From b5c381299ec84b272362afeea9acd056e9c85f5e Mon Sep 17 00:00:00 2001 From: Andrew Chiw Date: Fri, 2 Aug 2019 18:49:14 +0200 Subject: [PATCH] refactor: SpendTx struct deserialization --- aeternity/transactions.go | 52 ++++++++++++++++++++++++++ aeternity/transactions_test.go | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/aeternity/transactions.go b/aeternity/transactions.go index 686ecbdf..45dc9224 100644 --- a/aeternity/transactions.go +++ b/aeternity/transactions.go @@ -225,6 +225,20 @@ type SpendTx struct { Nonce uint64 } +// Equal compares the receiver to another struct of the same type. This is +// needed because several types in Golang are difficult to compare, especially +// using reflect.DeepEqual. +func (tx *SpendTx) Equal(other *SpendTx) (equal bool) { + equal = (tx.SenderID == other.SenderID && + tx.RecipientID == other.RecipientID && + tx.Amount.Cmp(&other.Amount) == 0 && + tx.Fee.Cmp(&other.Fee) == 0 && + bytes.Equal(tx.Payload, other.Payload) && + tx.TTL == other.TTL && + tx.Nonce == other.Nonce) + return +} + // EncodeRLP implements rlp.Encoder func (tx *SpendTx) EncodeRLP(w io.Writer) (err error) { // build id for the sender @@ -259,6 +273,44 @@ func (tx *SpendTx) EncodeRLP(w io.Writer) (err error) { return nil } +type spendtx struct { + ObjectTagSpendTransaction uint + RlpMessageVersion uint + SenderID []uint8 + ReceiverID []uint8 + Amount big.Int + Fee big.Int + TTL uint64 + Nonce uint64 + Payload []byte +} + +func (tx *SpendTx) DecodeRLP(s *rlp.Stream) (err error) { + stx := &spendtx{} + blob, err := s.Raw() + err = rlp.DecodeBytes(blob, stx) + if err != nil { + return err + } + + _, sID, err := readIDTag(stx.SenderID) + if err != nil { + return err + } + _, rID, err := readIDTag(stx.ReceiverID) + if err != nil { + return err + } + tx.SenderID = sID + tx.RecipientID = rID + tx.Amount = stx.Amount + tx.Fee = stx.Fee + tx.TTL = stx.TTL + tx.Nonce = stx.Nonce + tx.Payload = stx.Payload + return +} + // JSON representation of a Tx is useful for querying the node's debug endpoint func (tx *SpendTx) JSON() (string, error) { baseEncodedPayload := Encode(PrefixByteArray, tx.Payload) diff --git a/aeternity/transactions_test.go b/aeternity/transactions_test.go index af1bac16..f4316ab9 100644 --- a/aeternity/transactions_test.go +++ b/aeternity/transactions_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/aeternity/aepp-sdk-go/utils" + rlp "github.com/randomshinichi/rlpae" ) func getRLPSerialized(tx1 string, tx2 string) ([]interface{}, []interface{}) { @@ -76,6 +77,8 @@ func TestSpendTx_EncodeRLP(t *testing.T) { txJSON, err := tx.JSON() fmt.Println(txJSON) + fmt.Println(rlp.EncodeToBytes(&tx)) + gotTx, err := SerializeTx(&tx) if (err != nil) != tt.wantErr { t.Errorf("SpendTx.RLP() error = %v, wantErr %v", err, tt.wantErr) @@ -88,6 +91,71 @@ func TestSpendTx_EncodeRLP(t *testing.T) { }) } } + +func TestSpendTx_DecodeRLP(t *testing.T) { + type args struct { + rlpBytes []byte + } + tests := []struct { + name string + wantTx SpendTx + args args + wantErr bool + }{ + { + args: args{ + // tx_+FYMAaEBzqet5HDJ+Z2dTkAIgKhvHUm7REti8Rqeu2S7z+tz/vOhAR8To7CL8AFABmKmi2nYdfeAPOxMCGR/btXYTHiXvVCjCgoKAYtIZWxsbyBXb3JsZPSZjdM= + // [12] [1] [1 206 167 173 228 112 201 249 157 157 78 64 8 128 168 111 29 73 187 68 75 98 241 26 158 187 100 187 207 235 115 254 243] [1 31 19 163 176 139 240 1 64 6 98 166 139 105 216 117 247 128 60 236 76 8 100 127 110 213 216 76 120 151 189 80 163] [10] [10] [10] [1] [72 101 108 108 111 32 87 111 114 108 100]] + rlpBytes: []byte{248, 86, 12, 1, 161, 1, 206, 167, 173, 228, 112, 201, 249, 157, 157, 78, 64, 8, 128, 168, 111, 29, 73, 187, 68, 75, 98, 241, 26, 158, 187, 100, 187, 207, 235, 115, 254, 243, 161, 1, 31, 19, 163, 176, 139, 240, 1, 64, 6, 98, 166, 139, 105, 216, 117, 247, 128, 60, 236, 76, 8, 100, 127, 110, 213, 216, 76, 120, 151, 189, 80, 163, 10, 10, 10, 1, 139, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100}, + }, + name: "Spend 10, Fee 10, Hello World", + wantTx: SpendTx{ + SenderID: "ak_2a1j2Mk9YSmC1gioUq4PWRm3bsv887MbuRVwyv4KaUGoR1eiKi", + RecipientID: "ak_Egp9yVdpxmvAfQ7vsXGvpnyfNq71msbdUpkMNYGTeTe8kPL3v", + Amount: *utils.NewIntFromUint64(10), + Fee: *utils.NewIntFromUint64(10), + Payload: []byte("Hello World"), + TTL: uint64(10), + Nonce: uint64(1), + }, + wantErr: false, + }, + { + args: args{ + // tx_+FYMAaEBzqet5HDJ+Z2dTkAIgKhvHUm7REti8Rqeu2S7z+tz/vOhAR8To7CL8AFABmKmi2nYdfeAPOxMCGR/btXYTHiXvVCjAAoKAYtIZWxsbyBXb3JsZICI5/w= + // [[12] [1] [1 206 167 173 228 112 201 249 157 157 78 64 8 128 168 111 29 73 187 68 75 98 241 26 158 187 100 187 207 235 115 254 243] [1 31 19 163 176 139 240 1 64 6 98 166 139 105 216 117 247 128 60 236 76 8 100 127 110 213 216 76 120 151 189 80 163] [0] [10] [10] [1] [72 101 108 108 111 32 87 111 114 108 100]] + rlpBytes: []byte{248, 86, 12, 1, 161, 1, 206, 167, 173, 228, 112, 201, 249, 157, 157, 78, 64, 8, 128, 168, 111, 29, 73, 187, 68, 75, 98, 241, 26, 158, 187, 100, 187, 207, 235, 115, 254, 243, 161, 1, 31, 19, 163, 176, 139, 240, 1, 64, 6, 98, 166, 139, 105, 216, 117, 247, 128, 60, 236, 76, 8, 100, 127, 110, 213, 216, 76, 120, 151, 189, 80, 163, 0, 10, 10, 1, 139, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100}, + }, + name: "Spend 0, Fee 10, Hello World (check correct RLP deserialization of 0)", + wantTx: SpendTx{ + SenderID: "ak_2a1j2Mk9YSmC1gioUq4PWRm3bsv887MbuRVwyv4KaUGoR1eiKi", + RecipientID: "ak_Egp9yVdpxmvAfQ7vsXGvpnyfNq71msbdUpkMNYGTeTe8kPL3v", + Amount: *utils.NewIntFromUint64(0), + Fee: *utils.NewIntFromUint64(10), + Payload: []byte("Hello World"), + TTL: uint64(10), + Nonce: uint64(1), + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotTx := SpendTx{} + b := &bytes.Buffer{} + b.Write(tt.args.rlpBytes) + + err := rlp.Decode(b, &gotTx) + if err != nil { + t.Error(err) + } + if !(gotTx.Equal(&tt.wantTx)) { + t.Errorf("Deserialization resulted in different structs: got %+v, want %+v", gotTx, tt.wantTx) + } + }) + } +} + func TestNamePointer_EncodeRLP(t *testing.T) { type fields struct { ID string