OSDN Git Service

edht tx txoutput (#1966)
[bytom/bytom.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/bytom/consensus"
14         "github.com/bytom/bytom/errors"
15         "github.com/bytom/bytom/protocol/bc"
16         "github.com/bytom/bytom/testutil"
17 )
18
19 func TestTransaction(t *testing.T) {
20         cases := []struct {
21                 tx   *Tx
22                 hex  string
23                 hash bc.Hash
24         }{
25                 {
26                         tx: NewTx(TxData{
27                                 Version:        1,
28                                 SerializedSize: uint64(5),
29                                 Inputs:         nil,
30                                 Outputs:        nil,
31                         }),
32                         hex: strings.Join([]string{
33                                 "07", // serflags
34                                 "01", // transaction version
35                                 "00", // tx time range
36                                 "00", // inputs count
37                                 "00", // outputs count
38                         }, ""),
39                         hash: testutil.MustDecodeHash("8e88b9cb4615128c7209dff695f68b8de5b38648bf3d44d2d0e6a674848539c9"),
40                 },
41                 {
42                         tx: NewTx(TxData{
43                                 Version:        1,
44                                 SerializedSize: uint64(284),
45                                 TimeRange:      654,
46                                 Inputs: []*TxInput{
47                                         NewIssuanceInput([]byte("nonce"), 254354, []byte("issuanceProgram"), [][]byte{[]byte("arguments1"), []byte("arguments2")}, []byte("assetDefinition")),
48                                         NewSpendInput([][]byte{[]byte("arguments3"), []byte("arguments4")}, testutil.MustDecodeHash("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"), *consensus.BTMAssetID, 254354, 3, []byte("spendProgram"), [][]byte{[]byte("stateData")}),
49                                 },
50                                 Outputs: []*TxOutput{
51                                         NewOriginalTxOutput(testutil.MustDecodeAsset("a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf"), 254354, []byte("true"), [][]byte{[]byte("stateData")}),
52                                 },
53                         }),
54                         hex: strings.Join([]string{
55                                 "07",         // serflags
56                                 "01",         // transaction version
57                                 "8e05",       // tx time range
58                                 "02",         // inputs count
59                                 "01",         // input 0: asset version
60                                 "2a",         // input 0: serialization length
61                                 "00",         // input 0: issuance type flag
62                                 "05",         // input 0: nonce length
63                                 "6e6f6e6365", // input 0: nonce
64                                 "a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf", // input 0: assetID
65                                 "92c30f",                         // input 0: amount
66                                 "38",                             // input 0: input witness length
67                                 "0f",                             // input 0: asset definition length
68                                 "6173736574446566696e6974696f6e", // input 0: asset definition
69                                 "01",                             // input 0: vm version
70                                 "0f",                             // input 0: issuanceProgram length
71                                 "69737375616e636550726f6772616d", // input 0: issuance program
72                                 "02",                             // input 0: argument array length
73                                 "0a",                             // input 0: first argument length
74                                 "617267756d656e747331",           // input 0: first argument data
75                                 "0a",                             // input 0: second argument length
76                                 "617267756d656e747332",           // input 0: second argument data
77                                 "01",                             // input 1: asset version
78                                 "5f",                             // input 1: input commitment length
79                                 "01",                             // input 1: spend type flag
80                                 "5d",                             // input 1: spend commitment length
81                                 "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // input 1: source id
82                                 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // input 1: assetID
83                                 "92c30f",                   // input 1: amount
84                                 "03",                       // input 1: source position
85                                 "01",                       // input 1: vm version
86                                 "0c",                       // input 1: spend program length
87                                 "7370656e6450726f6772616d", // input 1: spend program
88                                 "0109",                     // input 1: state data length
89                                 "737461746544617461",       // input 1: state data
90                                 "17",                       // input 1: witness length
91                                 "02",                       // input 1: argument array length
92                                 "0a",                       // input 1: first argument length
93                                 "617267756d656e747333",     // input 1: first argument data
94                                 "0a",                       // input 1: second argument length
95                                 "617267756d656e747334",     // input 1: second argument data
96                                 "01",                       // outputs count
97                                 "01",                       // output 0: asset version
98                                 "00",
99                                 "34", // output 0: serialization length
100                                 "a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf", // output 0: assetID
101                                 "92c30f",             // output 0: amount
102                                 "01",                 // output 0: version
103                                 "04",                 // output 0: control program length
104                                 "74727565",           // output 0: control program
105                                 "0109",               // output 0: state data length
106                                 "737461746544617461", // output 0: state data
107                                 "00",                 // output 0: witness length
108                         }, ""),
109                         hash: testutil.MustDecodeHash("509632e139a418be372cd4b73c8de7b8aa5215c47848bf76ed2488d0a5c0c55e"),
110                 },
111                 {
112                         tx: NewTx(TxData{
113                                 Version:        1,
114                                 SerializedSize: uint64(132),
115                                 Inputs: []*TxInput{
116                                         NewCoinbaseInput([]byte("arbitrary")),
117                                 },
118                                 Outputs: []*TxOutput{
119                                         NewOriginalTxOutput(*consensus.BTMAssetID, 254354, []byte("true"), [][]byte{[]byte("stateData")}),
120                                         NewOriginalTxOutput(*consensus.BTMAssetID, 254354, []byte("false"), [][]byte{[]byte("stateData")}),
121                                 },
122                         }),
123                         hex: strings.Join([]string{
124                                 "07",                 // serflags
125                                 "01",                 // transaction version
126                                 "00",                 // tx time range
127                                 "01",                 // inputs count
128                                 "01",                 // input 0: asset version
129                                 "0b",                 // input 0: input commitment length
130                                 "02",                 // input 0: coinbase type flag
131                                 "09",                 // input 0: arbitrary length
132                                 "617262697472617279", // input 0: arbitrary data
133                                 "00",                 // input 0: witness length
134                                 "02",                 // outputs count
135                                 "01",                 // output 0: asset version
136                                 "00",
137                                 "34", // output 0: serialization length
138                                 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // output 0: assetID
139                                 "92c30f",             // output 0: amount
140                                 "01",                 // output 0: version
141                                 "04",                 // output 0: control program length
142                                 "74727565",           // output 0: control program
143                                 "0109",               // output 0: state data length
144                                 "737461746544617461", // output 0: state data
145                                 "00",                 // output 0: witness length
146                                 "01",                 // output 1: asset version
147                                 "00",
148                                 "35", // output 1: serialization length
149                                 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // output 1: assetID
150                                 "92c30f",             // output 1: amount
151                                 "01",                 // output 1: version
152                                 "05",                 // output 1: control program length
153                                 "66616c7365",         // output 1: control program
154                                 "0109",               // output 0: state data length
155                                 "737461746544617461", // output 0: state data
156                                 "00",                 // output 1: witness length
157                         }, ""),
158                         hash: testutil.MustDecodeHash("4243fc12f6e8704c5e4318a2addc648d29fd1c03a8fe1246badafa5efd8b5339"),
159                 },
160         }
161         for i, test := range cases {
162                 got := testutil.Serialize(t, test.tx)
163                 want, err := hex.DecodeString(test.hex)
164                 if err != nil {
165                         t.Fatal(err)
166                 }
167
168                 if !bytes.Equal(got, want) {
169                         t.Errorf("test %d: bytes = %x want %x", i, got, want)
170                 }
171                 if test.tx.ID != test.hash {
172                         t.Errorf("test %d: hash = %x want %x", i, test.tx.ID.Bytes(), test.hash.Bytes())
173                 }
174
175                 txJSON, err := json.Marshal(test.tx)
176                 if err != nil {
177                         t.Errorf("test %d: error marshaling tx to json: %s", i, err)
178                 }
179                 txFromJSON := Tx{}
180                 if err := json.Unmarshal(txJSON, &txFromJSON); err != nil {
181                         t.Errorf("test %d: error unmarshaling tx from json: %s", i, err)
182                 }
183                 if !testutil.DeepEqual(test.tx.TxData, txFromJSON.TxData) {
184                         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))
185                 }
186
187                 tx1 := new(TxData)
188                 if err := tx1.UnmarshalText([]byte(test.hex)); err != nil {
189                         t.Errorf("test %d: unexpected err %v", i, err)
190                 }
191                 if !testutil.DeepEqual(*tx1, test.tx.TxData) {
192                         t.Errorf("test %d: tx1 is:\n%swant:\n%s", i, spew.Sdump(*tx1), spew.Sdump(test.tx.TxData))
193                 }
194         }
195 }
196
197 func TestTransactionTrailingGarbage(t *testing.T) {
198         // validTxHex is a valid tx, we don't care what's inside as long as it's valid
199         validTxHex := `07010001012b00030a0908916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380a094a58d1d090001010101030102030101002a000000000000000000000000000000000000000000000000000000000000000080a094a58d1d0101010000`
200         validTx := Tx{}
201         if err := validTx.UnmarshalText([]byte(validTxHex)); err != nil {
202                 t.Fatal(err)
203         }
204
205         invalidTxHex := validTxHex + strings.Repeat("00", 10)
206         invalidTx := Tx{}
207         if err := invalidTx.UnmarshalText([]byte(invalidTxHex)); err == nil {
208                 t.Fatal("expected error with trailing garbage but got nil")
209         }
210 }
211
212 func TestInvalidIssuance(t *testing.T) {
213         hex := strings.Join([]string{
214                 "07",     // serflags
215                 "01",     // transaction version
216                 "00",     // tx maxtime
217                 "01",     // inputs count
218                 "01",     // input 0, asset version
219                 "2b",     // input 0, input commitment length prefix
220                 "00",     // input 0, input commitment, "issuance" type
221                 "03",     // input 0, input commitment, nonce length prefix
222                 "0a0908", // input 0, input commitment, nonce
223                 "0000000000000000000000000000000000000000000000000000000000000000", // input 0, input commitment, WRONG asset id
224                 "80a094a58d1d", // input 0, input commitment, amount
225                 "29",           // input 0, issuance input witness length prefix
226                 "03deff1d4319d67baa10a6d26c1fea9c3e8d30e33474efee1a610a9bb49d758d", // input 0, issuance input witness, initial block
227                 "00",     // input 0, issuance input witness, asset definition
228                 "01",     // input 0, issuance input witness, vm version
229                 "01",     // input 0, issuance input witness, issuance program length prefix
230                 "01",     // input 0, issuance input witness, issuance program
231                 "01",     // input 0, issuance input witness, arguments count
232                 "03",     // input 0, issuance input witness, argument 0 length prefix
233                 "010203", // input 0, issuance input witness, argument 0
234                 "01",     // outputs count
235                 "01",     // output 0, asset version
236                 "29",     // output 0, output commitment length
237                 "0000000000000000000000000000000000000000000000000000000000000000", // output 0, output commitment, asset id
238                 "80a094a58d1d",   // output 0, output commitment, amount
239                 "01",             // output 0, output commitment, vm version
240                 "0101",           // output 0, output commitment, control program
241                 "066f7574707574", // output 0, reference data
242                 "00",             // output 0, output witness
243                 "0869737375616e6365",
244         }, "")
245
246         tx := new(TxData)
247         if err := tx.UnmarshalText([]byte(hex)); errors.Root(err) != errBadAssetID {
248                 t.Errorf("want errBadAssetID, got %v", err)
249         }
250 }
251
252 func TestFuzzUnknownAssetVersion(t *testing.T) {
253         rawTx := `07010001012b00030a0908916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380a094a58d1d090001010101030102030101002a000000000000000000000000000000000000000000000000000000000000000080a094a58d1d0101010000`
254         /*
255                 07
256                 01
257                 00
258                 01
259                 01
260                 2b
261                 00
262                 03
263                 0a0908
264                 916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a263
265                 80a094a58d1d0900
266                 0101010103010203010100
267                 29
268                 0000000000000000000000000000000000000000000000000000000000000000
269                 80a094a58d1d
270                 01
271                 01
272                 01
273                 00
274         */
275         want := Tx{}
276         if err := want.UnmarshalText([]byte(rawTx)); err != nil {
277                 t.Fatal(err)
278         }
279
280         b, err := want.MarshalText()
281         if err != nil {
282                 t.Fatal(err)
283         }
284
285         got := Tx{}
286         if err = got.UnmarshalText(b); err != nil {
287                 t.Fatal(err)
288         }
289         if got.ID.String() != want.ID.String() {
290                 t.Errorf("tx id changed to %s", got.ID.String())
291         }
292 }
293
294 func BenchmarkTxWriteToTrue(b *testing.B) {
295         tx := &Tx{}
296         for i := 0; i < b.N; i++ {
297                 tx.writeTo(ioutil.Discard, 0)
298         }
299 }
300
301 func BenchmarkTxWriteToFalse(b *testing.B) {
302         tx := &Tx{}
303         for i := 0; i < b.N; i++ {
304                 tx.writeTo(ioutil.Discard, serRequired)
305         }
306 }
307
308 func BenchmarkTxWriteToTrue200(b *testing.B) {
309         tx := &Tx{}
310         for i := 0; i < 200; i++ {
311                 tx.Inputs = append(tx.Inputs, NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, nil))
312                 tx.Outputs = append(tx.Outputs, NewOriginalTxOutput(bc.AssetID{}, 0, nil, nil))
313         }
314         for i := 0; i < b.N; i++ {
315                 tx.writeTo(ioutil.Discard, 0)
316         }
317 }
318
319 func BenchmarkTxWriteToFalse200(b *testing.B) {
320         tx := &Tx{}
321         for i := 0; i < 200; i++ {
322                 tx.Inputs = append(tx.Inputs, NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, nil))
323                 tx.Outputs = append(tx.Outputs, NewOriginalTxOutput(bc.AssetID{}, 0, nil, nil))
324         }
325         for i := 0; i < b.N; i++ {
326                 tx.writeTo(ioutil.Discard, serRequired)
327         }
328 }
329
330 func BenchmarkTxInputWriteToTrue(b *testing.B) {
331         input := NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, nil)
332         ew := errors.NewWriter(ioutil.Discard)
333         for i := 0; i < b.N; i++ {
334                 input.writeTo(ew)
335         }
336 }
337
338 func BenchmarkTxInputWriteToFalse(b *testing.B) {
339         input := NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil, nil)
340         ew := errors.NewWriter(ioutil.Discard)
341         for i := 0; i < b.N; i++ {
342                 input.writeTo(ew)
343         }
344 }
345
346 func BenchmarkTxOutputWriteToTrue(b *testing.B) {
347         output := NewOriginalTxOutput(bc.AssetID{}, 0, nil, nil)
348         ew := errors.NewWriter(ioutil.Discard)
349         for i := 0; i < b.N; i++ {
350                 output.writeTo(ew)
351         }
352 }
353
354 func BenchmarkTxOutputWriteToFalse(b *testing.B) {
355         output := NewOriginalTxOutput(bc.AssetID{}, 0, nil, nil)
356         ew := errors.NewWriter(ioutil.Discard)
357         for i := 0; i < b.N; i++ {
358                 output.writeTo(ew)
359         }
360 }
361
362 func BenchmarkAssetAmountWriteTo(b *testing.B) {
363         aa := bc.AssetAmount{}
364         for i := 0; i < b.N; i++ {
365                 aa.WriteTo(ioutil.Discard)
366         }
367 }