From 7d06a0c95640937196c60126e3a1984988d50d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Fri, 22 Nov 2024 16:11:58 +0100 Subject: [PATCH] return amount and recipient when listing Txs --- api/grpcserver/v2alpha1/transaction.go | 95 +++++++++++++-------- api/grpcserver/v2alpha1/transaction_test.go | 7 +- 2 files changed, 61 insertions(+), 41 deletions(-) diff --git a/api/grpcserver/v2alpha1/transaction.go b/api/grpcserver/v2alpha1/transaction.go index 2f306bdf72..4df18fff9f 100644 --- a/api/grpcserver/v2alpha1/transaction.go +++ b/api/grpcserver/v2alpha1/transaction.go @@ -377,7 +377,30 @@ func convertTxState(tx *types.MeshTransaction) *spacemeshv2alpha1.TransactionSta } } -func decodeTxArgs(decoder *scale.Decoder) (*athcon.MethodSelector, *core.Address, *signing.PublicKey, error) { +type spawnTx struct { + Pubkey [32]byte +} + +type spendTx struct { + To types.Address + Amount uint64 +} + +var spawnSelector, spendSelector athcon.MethodSelector + +func init() { + var err error + spawnSelector, err = athcon.FromString("athexp_spawn") + if err != nil { + panic(err.Error()) + } + spendSelector, err = athcon.FromString("athexp_spend") + if err != nil { + panic(err.Error()) + } +} + +func decodeTxArgs(decoder *scale.Decoder) (any, *core.Address, error) { reg := registry.New() wallet.Register(reg) // multisig.Register(reg) @@ -386,45 +409,47 @@ func decodeTxArgs(decoder *scale.Decoder) (*athcon.MethodSelector, *core.Address _, _, err := scale.DecodeCompact8(decoder) if err != nil { - return nil, nil, nil, fmt.Errorf("%w: failed to decode version %w", core.ErrMalformed, err) + return nil, nil, fmt.Errorf("%w: failed to decode version %w", core.ErrMalformed, err) } var principal core.Address if _, err := principal.DecodeScale(decoder); err != nil { - return nil, nil, nil, fmt.Errorf("%w failed to decode principal: %w", core.ErrMalformed, err) + return nil, nil, fmt.Errorf("%w failed to decode principal: %w", core.ErrMalformed, err) } handler := reg.Get(wallet.TemplateAddress) if handler == nil { - return nil, nil, nil, fmt.Errorf("%w: wallet template not found", core.ErrMalformed) + return nil, nil, fmt.Errorf("%w: wallet template not found", core.ErrMalformed) } output, err := handler.Parse(decoder) if err != nil { - return nil, nil, nil, fmt.Errorf("%w: failed to parse transaction %w", core.ErrMalformed, err) + return nil, nil, fmt.Errorf("%w: failed to parse transaction %w", core.ErrMalformed, err) } - var unmarshaled struct { - *athcon.MethodSelector - signing.PublicKey + var payload athcon.Payload + err = gossamerScale.Unmarshal(output.Payload, &payload) + if err != nil { + return nil, nil, fmt.Errorf("%w: tx payload", core.ErrMalformed) + } + if payload.Selector == nil { + return nil, nil, fmt.Errorf("%w: nil method selector", core.ErrMalformed) } - err = gossamerScale.Unmarshal(output.Payload, &unmarshaled) + + var txArgs any + switch *payload.Selector { + case spawnSelector: + txArgs = new(spawnTx) + case spendSelector: + txArgs = new(spendTx) + default: + return nil, nil, fmt.Errorf("%w: unknown method selector %s", core.ErrMalformed, payload.Selector.String()) + } + err = gossamerScale.Unmarshal(payload.Input, txArgs) if err != nil { - return nil, nil, nil, fmt.Errorf("%w: malformed spawn payload", core.ErrMalformed) - } - // var p core.Payload - // if _, err = p.DecodeScale(decoder); err != nil { - // return 0, nil, nil, fmt.Errorf("%w: %w", core.ErrMalformed, err) - // } - - // args := handler.Args(method) - // if args == nil { - // return 0, nil, nil, fmt.Errorf("%w: unknown method %s %d", core.ErrMalformed, *templateAddress, method) - // } - // if _, err := args.DecodeScale(decoder); err != nil { - // return 0, nil, nil, fmt.Errorf("%w failed to decode method arguments %w", core.ErrMalformed, err) - // } - - return unmarshaled.MethodSelector, &wallet.TemplateAddress, &unmarshaled.PublicKey, nil + return nil, nil, fmt.Errorf("%w: malformed tx arguments payload", core.ErrMalformed) + } + + return txArgs, &wallet.TemplateAddress, nil } func toTxContents(rawTx []byte) (*spacemeshv2alpha1.TransactionContents, @@ -434,31 +459,29 @@ func toTxContents(rawTx []byte) (*spacemeshv2alpha1.TransactionContents, txType := spacemeshv2alpha1.Transaction_TRANSACTION_TYPE_UNSPECIFIED r := bytes.NewReader(rawTx) - method, _, pubkey, err := decodeTxArgs(scale.NewDecoder(r)) + txArgs, _, err := decodeTxArgs(scale.NewDecoder(r)) if err != nil { return res, txType, err } - if spawnSelector, err := athcon.FromString("athexp_spawn"); err != nil { - return res, txType, fmt.Errorf("%w: failed to create spawn selector: %w", core.ErrInternal, err) - } else if spendSelector, err := athcon.FromString("athexp_spend"); err != nil { - return res, txType, fmt.Errorf("%w: failed to create spend selector: %w", core.ErrInternal, err) - } else if *method == spawnSelector { + switch args := txArgs.(type) { + case *spawnTx: res.Contents = &spacemeshv2alpha1.TransactionContents_SingleSigSpawn{ SingleSigSpawn: &spacemeshv2alpha1.ContentsSingleSigSpawn{ - Pubkey: pubkey.String(), + Pubkey: signing.NewPublicKey(args.Pubkey[:]).String(), }, } txType = spacemeshv2alpha1.Transaction_TRANSACTION_TYPE_SINGLE_SIG_SPAWN - } else if *method == spendSelector { + case *spendTx: res.Contents = &spacemeshv2alpha1.TransactionContents_Send{ - // TODO(lane): we don't currently attempt to parse these from the payload Send: &spacemeshv2alpha1.ContentsSend{ - // Destination: args.Destination.String(), - // Amount: args.Amount, + Destination: args.To.String(), + Amount: args.Amount, }, } txType = spacemeshv2alpha1.Transaction_TRANSACTION_TYPE_SINGLE_SIG_SEND + default: + panic("txArgs is guaranteed to be spawn or spend at this point") } return res, txType, nil diff --git a/api/grpcserver/v2alpha1/transaction_test.go b/api/grpcserver/v2alpha1/transaction_test.go index 893e1d112d..4b52240f55 100644 --- a/api/grpcserver/v2alpha1/transaction_test.go +++ b/api/grpcserver/v2alpha1/transaction_test.go @@ -407,11 +407,8 @@ func TestTransactionService_ParseTransaction(t *testing.T) { }) require.NoError(t, err) - // TODO(lane): we don't currently parse tx amount for athena txs - require.Equal(t, uint64(0), resp.Tx.Contents.GetSend().Amount) - require.Equal(t, "", resp.Tx.Contents.GetSend().Destination) - // require.Equal(t, amount, resp.Tx.Contents.GetSend().Amount) - // require.Equal(t, addr.String(), resp.Tx.Contents.GetSend().Destination) + require.Equal(t, amount, resp.Tx.Contents.GetSend().Amount) + require.Equal(t, addr.String(), resp.Tx.Contents.GetSend().Destination) }) t.Run("transaction contents for spawn tx", func(t *testing.T) {