OSDN Git Service

merge node_p2p and chain.
[bytom/bytom-spv.git] / protocol / bc / legacy / transaction_test.go
1 package legacy
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/blockchain/errors"
14         "github.com/blockchain/protocol/bc"
15         "github.com/blockchain/testutil"
16 )
17
18 func TestTransactionTrailingGarbage(t *testing.T) {
19         const validTxHex = `07010700d0929893b92b00000101270eac870dfde1e0feaa4fac6693dee38da2afe7f5cc83ce2b024f04a2400fd6e20a0104deadbeef027b7d0000`
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         initialBlockHashHex := "03deff1d4319d67baa10a6d26c1fea9c3e8d30e33474efee1a610a9bb49d758d"
38         initialBlockHash := mustDecodeHash(initialBlockHashHex)
39
40         assetID := bc.ComputeAssetID(issuanceScript, &initialBlockHash, 1, &bc.EmptyStringHash)
41
42         cases := []struct {
43                 tx   *Tx
44                 hex  string
45                 hash bc.Hash
46         }{
47                 {
48                         tx: NewTx(TxData{
49                                 Version:       1,
50                                 Inputs:        nil,
51                                 Outputs:       nil,
52                                 MinTime:       0,
53                                 MaxTime:       0,
54                                 ReferenceData: nil,
55                         }),
56                         hex: ("07" + // serflags
57                                 "01" + // transaction version
58                                 "02" + // common fields extensible string length
59                                 "00" + // common fields, mintime
60                                 "00" + // common fields, maxtime
61                                 "00" + // common witness extensible string length
62                                 "00" + // inputs count
63                                 "00" + // outputs count
64                                 "00"), // reference data
65                         hash: mustDecodeHash("7ae6eef6b02fe61d35cc185405aec5f690ccb0ac291ecd6214445a1dff8fc9fd"),
66                 },
67                 {
68                         tx: NewTx(TxData{
69                                 Version: 1,
70                                 Inputs: []*TxInput{
71                                         NewIssuanceInput([]byte{10, 9, 8}, 1000000000000, []byte("input"), initialBlockHash, issuanceScript, [][]byte{[]byte{1, 2, 3}}, nil),
72                                 },
73                                 Outputs: []*TxOutput{
74                                         NewTxOutput(bc.AssetID{}, 1000000000000, []byte{1}, []byte("output")),
75                                 },
76                                 MinTime:       0,
77                                 MaxTime:       0,
78                                 ReferenceData: []byte("issuance"),
79                         }),
80                         hex: ("07" + // serflags
81                                 "01" + // transaction version
82                                 "02" + // common fields extensible string length
83                                 "00" + // common fields, mintime
84                                 "00" + // common fields, maxtime
85                                 "00" + // common witness extensible string length
86                                 "01" + // inputs count
87                                 "01" + // input 0, asset version
88                                 "2b" + // input 0, input commitment length prefix
89                                 "00" + // input 0, input commitment, "issuance" type
90                                 "03" + // input 0, input commitment, nonce length prefix
91                                 "0a0908" + // input 0, input commitment, nonce
92                                 assetID.String() + // input 0, input commitment, asset id
93                                 "80a094a58d1d" + // input 0, input commitment, amount
94                                 "05696e707574" + // input 0, reference data
95                                 "29" + // input 0, issuance input witness length prefix
96                                 initialBlockHashHex + // input 0, issuance input witness, initial block
97                                 "00" + // input 0, issuance input witness, asset definition
98                                 "01" + // input 0, issuance input witness, vm version
99                                 "01" + // input 0, issuance input witness, issuance program length prefix
100                                 "01" + // input 0, issuance input witness, issuance program
101                                 "01" + // input 0, issuance input witness, arguments count
102                                 "03" + // input 0, issuance input witness, argument 0 length prefix
103                                 "010203" + // input 0, issuance input witness, argument 0
104                                 "01" + // outputs count
105                                 "01" + // output 0, asset version
106                                 "29" + // output 0, output commitment length
107                                 "0000000000000000000000000000000000000000000000000000000000000000" + // output 0, output commitment, asset id
108                                 "80a094a58d1d" + // output 0, output commitment, amount
109                                 "01" + // output 0, output commitment, vm version
110                                 "0101" + // output 0, output commitment, control program
111                                 "066f7574707574" + // output 0, reference data
112                                 "00" + // output 0, output witness
113                                 "0869737375616e6365"), // reference data
114                         hash: mustDecodeHash("cd4669d5363374f8661621273501c23e613fc98b0fab9d5d858f30e16ccd24ce"),
115                 },
116                 {
117                         tx: NewTx(TxData{
118                                 Version: 1,
119                                 Inputs: []*TxInput{
120                                         NewSpendInput(nil, mustDecodeHash("dd385f6fe25d91d8c1bd0fa58951ad56b0c5229dcc01f61d9f9e8b9eb92d3292"), bc.AssetID{}, 1000000000000, 1, []byte{1}, bc.Hash{}, []byte("input")),
121                                 },
122                                 Outputs: []*TxOutput{
123                                         NewTxOutput(assetID, 600000000000, []byte{1}, nil),
124                                         NewTxOutput(assetID, 400000000000, []byte{2}, nil),
125                                 },
126                                 MinTime:       1492590000,
127                                 MaxTime:       1492590591,
128                                 ReferenceData: []byte("distribution"),
129                         }),
130                         hex: ("07" + // serflags
131                                 "01" + // transaction version
132                                 "0a" + // common fields extensible string length
133
134                                 "b0bbdcc705" + // common fields, mintime
135                                 "ffbfdcc705" + // common fields, maxtime
136                                 "00" + // common witness extensible string length
137                                 "01" + // inputs count
138                                 "01" + // input 0, asset version
139                                 "6c" + // input 0, input commitment length prefix
140                                 "01" + // input 0, input commitment, "spend" type+
141                                 "6a" + // input 0, spend input commitment, spend commitment length prefix
142                                 "dd385f6fe25d91d8c1bd0fa58951ad56b0c5229dcc01f61d9f9e8b9eb92d3292" + // input 0, spend input commitment, spend commitment, source ID
143                                 "0000000000000000000000000000000000000000000000000000000000000000" + // input 0, spend input commitment, spend commitment, asset id
144                                 "80a094a58d1d" + // input 0, spend input commitment, spend commitment, amount
145                                 "01" + // input 0, spend input commitment, spend commitment, source position
146                                 "01" + // input 0, spend input commitment, spend commitment, vm version
147                                 "0101" + // input 0, spend input commitment, spend commitment, control program
148                                 "0000000000000000000000000000000000000000000000000000000000000000" + // input 0, spend input commitment, spend commitment, reference data hash
149                                 "05696e707574" + // input 0, reference data
150                                 "01" + // input 0, input witness length prefix
151                                 "00" + // input 0, input witness, number of args
152                                 "02" + // outputs count
153                                 "01" + // output 0, asset version
154                                 "29" + // output 0, output commitment length
155                                 "a9b2b6c5394888ab5396f583ae484b8459486b14268e2bef1b637440335eb6c1" + // output 0, output commitment, asset id
156                                 "80e0a596bb11" + // output 0, output commitment, amount
157                                 "01" + // output 0, output commitment, vm version
158                                 "0101" + // output 0, output commitment, control program
159                                 "00" + // output 0, reference data
160                                 "00" + // output 0, output witness
161                                 "01" + // output 1, asset version
162                                 "29" + // output 1, output commitment length
163                                 "a9b2b6c5394888ab5396f583ae484b8459486b14268e2bef1b637440335eb6c1" + // output 1, output commitment, asset id
164                                 "80c0ee8ed20b" + // output 1, output commitment, amount
165                                 "01" + // output 1, vm version
166                                 "0102" + // output 1, output commitment, control program
167                                 "00" + // output 1, reference data
168                                 "00" + // output 1, output witness
169                                 "0c646973747269627574696f6e"), // reference data
170                         hash: mustDecodeHash("c328ad4278045b4c50e8af7e7d0df198e7d9436d2b5de35df1339f13a1192331"),
171                 },
172
173                 //07
174                 //01
175                 //0a
176                 //b0bbdcc705
177                 //ffbfdcc705
178                 //00
179                 //01
180                 //01
181                 //4b
182                 //01
183                 //dd385f6fe25d91d8c1bd0fa58951ad56b0c5229dcc01f61d9f9e8b9eb92d3292
184                 //29
185                 //0000000000000000000000000000000000000000000000000000000000000000
186                 //80a094a58d1d
187                 //01
188                 //0101
189                 //05696e707574
190                 //01
191                 //00
192                 //02
193                 //01
194                 //29
195                 //a9b2b6c5394888ab5396f583ae484b8459486b14268e2bef1b637440335eb6c1
196                 //80e0a596bb11
197                 //01
198                 //0101
199                 //00
200                 //00
201                 //01
202                 //29
203                 //a9b2b6c5394888ab5396f583ae484b8459486b14268e2bef1b637440335eb6c1
204                 //80c0ee8ed20b
205                 //01
206                 //0102
207                 //00
208                 //00
209                 //0c646973747269627574696f6e
210
211         }
212         for i, test := range cases {
213                 got := serialize(t, test.tx)
214                 want, _ := hex.DecodeString(test.hex)
215                 if !bytes.Equal(got, want) {
216                         t.Errorf("test %d: bytes = %x want %x", i, got, want)
217                 }
218                 if test.tx.ID != test.hash {
219                         t.Errorf("test %d: hash = %x want %x", i, test.tx.ID.Bytes(), test.hash.Bytes())
220                 }
221
222                 txJSON, err := json.Marshal(test.tx)
223                 if err != nil {
224                         t.Errorf("test %d: error marshaling tx to json: %s", i, err)
225                 }
226                 var txFromJSON Tx
227                 if err := json.Unmarshal(txJSON, &txFromJSON); err != nil {
228                         t.Errorf("test %d: error unmarshaling tx from json: %s", i, err)
229                 }
230                 if !testutil.DeepEqual(test.tx.TxData, txFromJSON.TxData) {
231                         t.Errorf("test %d: legacy.TxData -> json -> legacy.TxData: got:\n%s\nwant:\n%s", i, spew.Sdump(txFromJSON.TxData), spew.Sdump(test.tx.TxData))
232                 }
233
234                 tx1 := new(TxData)
235                 if err := tx1.UnmarshalText([]byte(test.hex)); err != nil {
236                         t.Errorf("test %d: unexpected err %v", i, err)
237                 }
238                 if !testutil.DeepEqual(*tx1, test.tx.TxData) {
239                         t.Errorf("test %d: tx1 is:\n%swant:\n%s", i, spew.Sdump(*tx1), spew.Sdump(test.tx.TxData))
240                 }
241         }
242 }
243
244 func TestHasIssuance(t *testing.T) {
245         cases := []struct {
246                 tx   *TxData
247                 want bool
248         }{{
249                 tx: &TxData{
250                         Inputs: []*TxInput{NewIssuanceInput(nil, 0, nil, bc.Hash{}, nil, nil, nil)},
251                 },
252                 want: true,
253         }, {
254                 tx: &TxData{
255                         Inputs: []*TxInput{
256                                 NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, bc.Hash{}, nil),
257                                 NewIssuanceInput(nil, 0, nil, bc.Hash{}, nil, nil, nil),
258                         },
259                 },
260                 want: true,
261         }, {
262                 tx: &TxData{
263                         Inputs: []*TxInput{
264                                 NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, bc.Hash{}, nil),
265                         },
266                 },
267                 want: false,
268         }, {
269                 tx:   &TxData{},
270                 want: false,
271         }}
272
273         for _, c := range cases {
274                 got := c.tx.HasIssuance()
275                 if got != c.want {
276                         t.Errorf("HasIssuance(%+v) = %v want %v", c.tx, got, c.want)
277                 }
278         }
279 }
280
281 func TestInvalidIssuance(t *testing.T) {
282         hex := ("07" + // serflags
283                 "01" + // transaction version
284                 "02" + // common fields extensible string length
285                 "00" + // common fields, mintime
286                 "00" + // common fields, maxtime
287                 "00" + // common witness extensible string length
288                 "01" + // inputs count
289                 "01" + // input 0, asset version
290                 "2b" + // input 0, input commitment length prefix
291                 "00" + // input 0, input commitment, "issuance" type
292                 "03" + // input 0, input commitment, nonce length prefix
293                 "0a0908" + // input 0, input commitment, nonce
294                 "0000000000000000000000000000000000000000000000000000000000000000" + // input 0, input commitment, WRONG asset id
295                 "80a094a58d1d" + // input 0, input commitment, amount
296                 "05696e707574" + // input 0, reference data
297                 "29" + // input 0, issuance input witness length prefix
298                 "03deff1d4319d67baa10a6d26c1fea9c3e8d30e33474efee1a610a9bb49d758d" + // input 0, issuance input witness, initial block
299                 "00" + // input 0, issuance input witness, asset definition
300                 "01" + // input 0, issuance input witness, vm version
301                 "01" + // input 0, issuance input witness, issuance program length prefix
302                 "01" + // input 0, issuance input witness, issuance program
303                 "01" + // input 0, issuance input witness, arguments count
304                 "03" + // input 0, issuance input witness, argument 0 length prefix
305                 "010203" + // input 0, issuance input witness, argument 0
306                 "01" + // outputs count
307                 "01" + // output 0, asset version
308                 "29" + // output 0, output commitment length
309                 "0000000000000000000000000000000000000000000000000000000000000000" + // output 0, output commitment, asset id
310                 "80a094a58d1d" + // output 0, output commitment, amount
311                 "01" + // output 0, output commitment, vm version
312                 "0101" + // output 0, output commitment, control program
313                 "066f7574707574" + // output 0, reference data
314                 "00" + // output 0, output witness
315                 "0869737375616e6365")
316         tx := new(TxData)
317         err := tx.UnmarshalText([]byte(hex))
318         if errors.Root(err) != errBadAssetID {
319                 t.Errorf("want errBadAssetID, got %v", err)
320         }
321 }
322
323 func BenchmarkTxWriteToTrue(b *testing.B) {
324         tx := &Tx{}
325         for i := 0; i < b.N; i++ {
326                 tx.writeTo(ioutil.Discard, 0)
327         }
328 }
329
330 func BenchmarkTxWriteToFalse(b *testing.B) {
331         tx := &Tx{}
332         for i := 0; i < b.N; i++ {
333                 tx.writeTo(ioutil.Discard, serRequired)
334         }
335 }
336
337 func BenchmarkTxWriteToTrue200(b *testing.B) {
338         tx := &Tx{}
339         for i := 0; i < 200; i++ {
340                 tx.Inputs = append(tx.Inputs, NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, bc.Hash{}, nil))
341                 tx.Outputs = append(tx.Outputs, NewTxOutput(bc.AssetID{}, 0, nil, nil))
342         }
343         for i := 0; i < b.N; i++ {
344                 tx.writeTo(ioutil.Discard, 0)
345         }
346 }
347
348 func BenchmarkTxWriteToFalse200(b *testing.B) {
349         tx := &Tx{}
350         for i := 0; i < 200; i++ {
351                 tx.Inputs = append(tx.Inputs, NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, bc.Hash{}, nil))
352                 tx.Outputs = append(tx.Outputs, NewTxOutput(bc.AssetID{}, 0, nil, nil))
353         }
354         for i := 0; i < b.N; i++ {
355                 tx.writeTo(ioutil.Discard, serRequired)
356         }
357 }
358
359 func BenchmarkTxInputWriteToTrue(b *testing.B) {
360         input := NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, bc.Hash{}, nil)
361         ew := errors.NewWriter(ioutil.Discard)
362         for i := 0; i < b.N; i++ {
363                 input.writeTo(ew, 0)
364         }
365 }
366
367 func BenchmarkTxInputWriteToFalse(b *testing.B) {
368         input := NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, bc.Hash{}, nil)
369         ew := errors.NewWriter(ioutil.Discard)
370         for i := 0; i < b.N; i++ {
371                 input.writeTo(ew, serRequired)
372         }
373 }
374
375 func BenchmarkTxOutputWriteToTrue(b *testing.B) {
376         output := NewTxOutput(bc.AssetID{}, 0, nil, nil)
377         ew := errors.NewWriter(ioutil.Discard)
378         for i := 0; i < b.N; i++ {
379                 output.writeTo(ew, 0)
380         }
381 }
382
383 func BenchmarkTxOutputWriteToFalse(b *testing.B) {
384         output := NewTxOutput(bc.AssetID{}, 0, nil, nil)
385         ew := errors.NewWriter(ioutil.Discard)
386         for i := 0; i < b.N; i++ {
387                 output.writeTo(ew, serRequired)
388         }
389 }
390
391 func BenchmarkAssetAmountWriteTo(b *testing.B) {
392         aa := bc.AssetAmount{}
393         for i := 0; i < b.N; i++ {
394                 aa.WriteTo(ioutil.Discard)
395         }
396 }