OSDN Git Service

Merge pull request #375 from Bytom/dev
[bytom/bytom-spv.git] / protocol / bc / types / transaction_test.go
1 package types
2
3 import (
4         "bytes"
5         "encoding/hex"
6         "encoding/json"
7         "io/ioutil"
8         "strings"
9         "testing"
10
11         "github.com/davecgh/go-spew/spew"
12
13         "github.com/bytom/errors"
14         "github.com/bytom/protocol/bc"
15         "github.com/bytom/testutil"
16 )
17
18 func TestTransactionTrailingGarbage(t *testing.T) {
19         const validTxHex = `0701000001012b00030a0908916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380a094a58d1d09000101010103010203010129000000000000000000000000000000000000000000000000000000000000000080a094a58d1d01010100`
20
21         var validTx Tx
22         err := validTx.UnmarshalText([]byte(validTxHex))
23         if err != nil {
24                 t.Fatal(err)
25         }
26
27         invalidTxHex := validTxHex + strings.Repeat("beef", 10)
28         var invalidTx Tx
29         err = invalidTx.UnmarshalText([]byte(invalidTxHex))
30         if err == nil {
31                 t.Fatal("expected error with trailing garbage but got nil")
32         }
33 }
34
35 func TestTransaction(t *testing.T) {
36         issuanceScript := []byte{1}
37
38         assetID := bc.ComputeAssetID(issuanceScript, 1, &bc.EmptyStringHash)
39
40         cases := []struct {
41                 tx   *Tx
42                 hex  string
43                 hash bc.Hash
44         }{
45                 {
46                         tx: NewTx(TxData{
47                                 Version:        1,
48                                 SerializedSize: uint64(6),
49                                 Inputs:         nil,
50                                 Outputs:        nil,
51                         }),
52                         hex: ("07" + // serflags
53                                 "01" + // transaction version
54                                 "00" + // tx maxtime
55                                 "00" + // common witness extensible string length
56                                 "00" + // inputs count
57                                 "00"), // outputs count
58                         hash: mustDecodeHash("b28048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea7d60"),
59                 },
60                 {
61                         tx: NewTx(TxData{
62                                 Version:        1,
63                                 SerializedSize: uint64(105),
64                                 Inputs: []*TxInput{
65                                         NewIssuanceInput([]byte{10, 9, 8}, 1000000000000, issuanceScript, [][]byte{[]byte{1, 2, 3}}, nil),
66                                 },
67                                 Outputs: []*TxOutput{
68                                         NewTxOutput(bc.AssetID{}, 1000000000000, []byte{1}),
69                                 },
70                         }),
71                         hex: ("0701000001012b00030a0908916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380a094a58d1d09000101010103010203010129000000000000000000000000000000000000000000000000000000000000000080a094a58d1d01010100"), // reference data
72                         hash: mustDecodeHash("7e6928130bc91e115f6ebe1fb4238d51e4155a7f9f809a36a5ebea7342ad1f63"),
73                 },
74                 {
75                         tx: NewTx(TxData{
76                                 Version:        1,
77                                 SerializedSize: uint64(174),
78                                 Inputs: []*TxInput{
79                                         NewSpendInput(nil, mustDecodeHash("dd385f6fe25d91d8c1bd0fa58951ad56b0c5229dcc01f61d9f9e8b9eb92d3292"), bc.AssetID{}, 1000000000000, 1, []byte{1}),
80                                 },
81                                 Outputs: []*TxOutput{
82                                         NewTxOutput(assetID, 600000000000, []byte{1}),
83                                         NewTxOutput(assetID, 400000000000, []byte{2}),
84                                 },
85                         }),
86                         hex: ("0701000001014c014add385f6fe25d91d8c1bd0fa58951ad56b0c5229dcc01f61d9f9e8b9eb92d3292000000000000000000000000000000000000000000000000000000000000000080a094a58d1d010101010100020129916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380e0a596bb11010101000129916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380c0ee8ed20b01010200"), // output 1, output witness
87                         hash: mustDecodeHash("e89ea19ec8acb92d697c06ebf841020bb9f1d9ace983efcb47c09913cff99026"),
88                 },
89         }
90         for i, test := range cases {
91                 got := serialize(t, test.tx)
92                 want, _ := hex.DecodeString(test.hex)
93                 if !bytes.Equal(got, want) {
94                         t.Errorf("test %d: bytes = %x want %x", i, got, want)
95                 }
96                 if test.tx.ID != test.hash {
97                         t.Errorf("test %d: hash = %x want %x", i, test.tx.ID.Bytes(), test.hash.Bytes())
98                 }
99
100                 txJSON, err := json.Marshal(test.tx)
101                 if err != nil {
102                         t.Errorf("test %d: error marshaling tx to json: %s", i, err)
103                 }
104                 var txFromJSON Tx
105                 if err := json.Unmarshal(txJSON, &txFromJSON); err != nil {
106                         t.Errorf("test %d: error unmarshaling tx from json: %s", i, err)
107                 }
108                 if !testutil.DeepEqual(test.tx.TxData, txFromJSON.TxData) {
109                         t.Errorf("test %d: types.TxData -> json -> types.TxData: got:\n%s\nwant:\n%s", i, spew.Sdump(txFromJSON.TxData), spew.Sdump(test.tx.TxData))
110                 }
111
112                 tx1 := new(TxData)
113                 if err := tx1.UnmarshalText([]byte(test.hex)); err != nil {
114                         t.Errorf("test %d: unexpected err %v", i, err)
115                 }
116                 if !testutil.DeepEqual(*tx1, test.tx.TxData) {
117                         t.Errorf("test %d: tx1 is:\n%swant:\n%s", i, spew.Sdump(*tx1), spew.Sdump(test.tx.TxData))
118                 }
119         }
120 }
121
122 func TestHasIssuance(t *testing.T) {
123         cases := []struct {
124                 tx   *TxData
125                 want bool
126         }{{
127                 tx: &TxData{
128                         Inputs: []*TxInput{NewIssuanceInput(nil, 0, nil, nil, nil)},
129                 },
130                 want: true,
131         }, {
132                 tx: &TxData{
133                         Inputs: []*TxInput{
134                                 NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil),
135                                 NewIssuanceInput(nil, 0, nil, nil, nil),
136                         },
137                 },
138                 want: true,
139         }, {
140                 tx: &TxData{
141                         Inputs: []*TxInput{
142                                 NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil),
143                         },
144                 },
145                 want: false,
146         }, {
147                 tx:   &TxData{},
148                 want: false,
149         }}
150
151         for _, c := range cases {
152                 got := c.tx.HasIssuance()
153                 if got != c.want {
154                         t.Errorf("HasIssuance(%+v) = %v want %v", c.tx, got, c.want)
155                 }
156         }
157 }
158
159 func TestInvalidIssuance(t *testing.T) {
160         hex := ("07" + // serflags
161                 "01" + // transaction version
162                 "00" + // tx maxtime
163                 "00" + // common witness extensible string length
164                 "01" + // inputs count
165                 "01" + // input 0, asset version
166                 "2b" + // input 0, input commitment length prefix
167                 "00" + // input 0, input commitment, "issuance" type
168                 "03" + // input 0, input commitment, nonce length prefix
169                 "0a0908" + // input 0, input commitment, nonce
170                 "0000000000000000000000000000000000000000000000000000000000000000" + // input 0, input commitment, WRONG asset id
171                 "80a094a58d1d" + // input 0, input commitment, amount
172                 "29" + // input 0, issuance input witness length prefix
173                 "03deff1d4319d67baa10a6d26c1fea9c3e8d30e33474efee1a610a9bb49d758d" + // input 0, issuance input witness, initial block
174                 "00" + // input 0, issuance input witness, asset definition
175                 "01" + // input 0, issuance input witness, vm version
176                 "01" + // input 0, issuance input witness, issuance program length prefix
177                 "01" + // input 0, issuance input witness, issuance program
178                 "01" + // input 0, issuance input witness, arguments count
179                 "03" + // input 0, issuance input witness, argument 0 length prefix
180                 "010203" + // input 0, issuance input witness, argument 0
181                 "01" + // outputs count
182                 "01" + // output 0, asset version
183                 "29" + // output 0, output commitment length
184                 "0000000000000000000000000000000000000000000000000000000000000000" + // output 0, output commitment, asset id
185                 "80a094a58d1d" + // output 0, output commitment, amount
186                 "01" + // output 0, output commitment, vm version
187                 "0101" + // output 0, output commitment, control program
188                 "066f7574707574" + // output 0, reference data
189                 "00" + // output 0, output witness
190                 "0869737375616e6365")
191         tx := new(TxData)
192         err := tx.UnmarshalText([]byte(hex))
193         if errors.Root(err) != errBadAssetID {
194                 t.Errorf("want errBadAssetID, got %v", err)
195         }
196 }
197
198 func BenchmarkTxWriteToTrue(b *testing.B) {
199         tx := &Tx{}
200         for i := 0; i < b.N; i++ {
201                 tx.writeTo(ioutil.Discard, 0)
202         }
203 }
204
205 func BenchmarkTxWriteToFalse(b *testing.B) {
206         tx := &Tx{}
207         for i := 0; i < b.N; i++ {
208                 tx.writeTo(ioutil.Discard, serRequired)
209         }
210 }
211
212 func BenchmarkTxWriteToTrue200(b *testing.B) {
213         tx := &Tx{}
214         for i := 0; i < 200; i++ {
215                 tx.Inputs = append(tx.Inputs, NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil))
216                 tx.Outputs = append(tx.Outputs, NewTxOutput(bc.AssetID{}, 0, nil))
217         }
218         for i := 0; i < b.N; i++ {
219                 tx.writeTo(ioutil.Discard, 0)
220         }
221 }
222
223 func BenchmarkTxWriteToFalse200(b *testing.B) {
224         tx := &Tx{}
225         for i := 0; i < 200; i++ {
226                 tx.Inputs = append(tx.Inputs, NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil))
227                 tx.Outputs = append(tx.Outputs, NewTxOutput(bc.AssetID{}, 0, nil))
228         }
229         for i := 0; i < b.N; i++ {
230                 tx.writeTo(ioutil.Discard, serRequired)
231         }
232 }
233
234 func BenchmarkTxInputWriteToTrue(b *testing.B) {
235         input := NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil)
236         ew := errors.NewWriter(ioutil.Discard)
237         for i := 0; i < b.N; i++ {
238                 input.writeTo(ew, 0)
239         }
240 }
241
242 func BenchmarkTxInputWriteToFalse(b *testing.B) {
243         input := NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil)
244         ew := errors.NewWriter(ioutil.Discard)
245         for i := 0; i < b.N; i++ {
246                 input.writeTo(ew, serRequired)
247         }
248 }
249
250 func BenchmarkTxOutputWriteToTrue(b *testing.B) {
251         output := NewTxOutput(bc.AssetID{}, 0, nil)
252         ew := errors.NewWriter(ioutil.Discard)
253         for i := 0; i < b.N; i++ {
254                 output.writeTo(ew, 0)
255         }
256 }
257
258 func BenchmarkTxOutputWriteToFalse(b *testing.B) {
259         output := NewTxOutput(bc.AssetID{}, 0, nil)
260         ew := errors.NewWriter(ioutil.Discard)
261         for i := 0; i < b.N; i++ {
262                 output.writeTo(ew, serRequired)
263         }
264 }
265
266 func BenchmarkAssetAmountWriteTo(b *testing.B) {
267         aa := bc.AssetAmount{}
268         for i := 0; i < b.N; i++ {
269                 aa.WriteTo(ioutil.Discard)
270         }
271 }