OSDN Git Service

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