OSDN Git Service

init for remove issue (#63)
[bytom/vapor.git] / blockchain / txbuilder / txbuilder_test.go
1 package txbuilder
2
3 import (
4         "context"
5         "encoding/hex"
6         "encoding/json"
7         "math"
8         "testing"
9         "time"
10
11         "github.com/davecgh/go-spew/spew"
12
13         "github.com/vapor/common"
14         "github.com/vapor/consensus"
15         "github.com/vapor/crypto"
16         "github.com/vapor/crypto/ed25519/chainkd"
17         chainjson "github.com/vapor/encoding/json"
18         "github.com/vapor/errors"
19         "github.com/vapor/protocol/bc"
20         "github.com/vapor/protocol/bc/types"
21         "github.com/vapor/protocol/vm/vmutil"
22         "github.com/vapor/testutil"
23 )
24
25 type testAction bc.AssetAmount
26
27 func (t testAction) Build(ctx context.Context, b *TemplateBuilder) error {
28         in := types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *t.AssetId, t.Amount, 0, nil)
29         tplIn := &SigningInstruction{}
30
31         err := b.AddInput(in, tplIn)
32         if err != nil {
33                 return err
34         }
35         return b.AddOutput(types.NewIntraChainOutput(*t.AssetId, t.Amount, []byte("change")))
36 }
37
38 func (t testAction) ActionType() string {
39         return "test-action"
40 }
41
42 func newControlProgramAction(assetAmt bc.AssetAmount, script []byte) *controlProgramAction {
43         return &controlProgramAction{
44                 AssetAmount: assetAmt,
45                 Program:     script,
46         }
47 }
48
49 func TestBuild(t *testing.T) {
50         ctx := context.Background()
51
52         assetID1 := bc.NewAssetID([32]byte{1})
53         assetID2 := bc.NewAssetID([32]byte{2})
54
55         actions := []Action{
56                 newControlProgramAction(bc.AssetAmount{AssetId: &assetID2, Amount: 6}, []byte("dest")),
57                 testAction(bc.AssetAmount{AssetId: &assetID1, Amount: 5}),
58         }
59         expiryTime := time.Now().Add(time.Minute)
60         got, err := Build(ctx, nil, actions, expiryTime, 0)
61         if err != nil {
62                 testutil.FatalErr(t, err)
63         }
64
65         want := &Template{
66                 Transaction: types.NewTx(types.TxData{
67                         Version: 1,
68                         Inputs: []*types.TxInput{
69                                 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), assetID1, 5, 0, nil),
70                         },
71                         Outputs: []*types.TxOutput{
72                                 types.NewIntraChainOutput(assetID2, 6, []byte("dest")),
73                                 types.NewIntraChainOutput(assetID1, 5, []byte("change")),
74                         },
75                 }),
76                 SigningInstructions: []*SigningInstruction{{
77                         WitnessComponents: []witnessComponent{},
78                 }},
79         }
80
81         if !testutil.DeepEqual(got.Transaction.TxData, want.Transaction.TxData) {
82                 t.Errorf("got tx:\n%s\nwant tx:\n%s", spew.Sdump(got.Transaction.TxData), spew.Sdump(want.Transaction.TxData))
83         }
84
85         if !testutil.DeepEqual(got.SigningInstructions, want.SigningInstructions) {
86                 t.Errorf("got signing instructions:\n\t%#v\nwant signing instructions:\n\t%#v", got.SigningInstructions, want.SigningInstructions)
87         }
88 }
89
90 func mustDecodeHex(str string) []byte {
91         data, err := hex.DecodeString(str)
92         if err != nil {
93                 panic(err)
94         }
95         return data
96 }
97
98 func TestCheckBlankCheck(t *testing.T) {
99         cases := []struct {
100                 tx   *types.TxData
101                 want error
102         }{{
103                 tx: &types.TxData{
104                         Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
105                 },
106                 want: ErrBlankCheck,
107         }, {
108                 tx: &types.TxData{
109                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
110                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 3, nil)},
111                 },
112                 want: ErrBlankCheck,
113         }, {
114                 tx: &types.TxData{
115                         Inputs: []*types.TxInput{
116                                 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil),
117                                 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.NewAssetID([32]byte{1}), 5, 0, nil),
118                         },
119                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 5, nil)},
120                 },
121                 want: ErrBlankCheck,
122         }, {
123                 tx: &types.TxData{
124                         Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
125                         Outputs: []*types.TxOutput{
126                                 types.NewIntraChainOutput(bc.AssetID{}, math.MaxInt64, nil),
127                                 types.NewIntraChainOutput(bc.AssetID{}, 7, nil),
128                         },
129                 },
130                 want: ErrBadAmount,
131         }, {
132                 tx: &types.TxData{
133                         Inputs: []*types.TxInput{
134                                 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil),
135                                 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, math.MaxInt64, 0, nil),
136                         },
137                 },
138                 want: ErrBadAmount,
139         }, {
140                 tx: &types.TxData{
141                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
142                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 5, nil)},
143                 },
144                 want: nil,
145         }, {
146                 tx: &types.TxData{
147                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 5, nil)},
148                 },
149                 want: nil,
150         }, {
151                 tx: &types.TxData{
152                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
153                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.NewAssetID([32]byte{1}), 5, nil)},
154                 },
155                 want: nil,
156         }}
157
158         for _, c := range cases {
159                 got := checkBlankCheck(c.tx)
160                 if errors.Root(got) != c.want {
161                         t.Errorf("checkUnsafe(%+v) err = %v want %v", c.tx, errors.Root(got), c.want)
162                 }
163         }
164 }
165
166 func TestCreateTxByUtxo(t *testing.T) {
167         xprv, xpub, err := chainkd.NewXKeys(nil)
168         if err != nil {
169                 t.Fatal(err)
170         }
171
172         pub := xpub.PublicKey()
173         pubHash := crypto.Ripemd160(pub)
174         program, err := vmutil.P2WPKHProgram([]byte(pubHash))
175         if err != nil {
176                 t.Fatal(err)
177         }
178
179         address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
180         if err != nil {
181                 t.Fatal(err)
182         }
183
184         muxID := testutil.MustDecodeHash("1e673900965623ec3305cead5a78dfb68a34599f8bc078460f3f202256c3dfa6")
185         utxo := struct {
186                 SourceID       bc.Hash
187                 AssetID        bc.AssetID
188                 Amount         uint64
189                 SourcePos      uint64
190                 ControlProgram []byte
191                 Address        string
192         }{
193                 SourceID:       muxID,
194                 AssetID:        *consensus.BTMAssetID,
195                 Amount:         20000000000,
196                 SourcePos:      1,
197                 ControlProgram: program,
198                 Address:        address.EncodeAddress(),
199         }
200
201         recvProg := mustDecodeHex("00145056532ecd3621c9ce8adde5505c058610b287cf")
202         tx := types.NewTx(types.TxData{
203                 Version: 1,
204                 Inputs: []*types.TxInput{
205                         types.NewSpendInput(nil, utxo.SourceID, utxo.AssetID, utxo.Amount, utxo.SourcePos, utxo.ControlProgram),
206                 },
207                 Outputs: []*types.TxOutput{
208                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, recvProg),
209                 },
210         })
211
212         tpl := &Template{
213                 Transaction:     tx,
214                 AllowAdditional: false,
215         }
216
217         h := tpl.Hash(0).Byte32()
218         sig := xprv.Sign(h[:])
219         data := []byte(pub)
220
221         // Test with more signatures than required, in correct order
222         tpl.SigningInstructions = []*SigningInstruction{{
223                 WitnessComponents: []witnessComponent{
224                         &RawTxSigWitness{
225                                 Quorum: 1,
226                                 Sigs:   []chainjson.HexBytes{sig},
227                         },
228                         DataWitness(data),
229                 },
230         }}
231
232         if err = materializeWitnesses(tpl); err != nil {
233                 t.Fatal(err)
234         }
235
236         if !testutil.DeepEqual(tx, tpl.Transaction) {
237                 t.Errorf("tx:%v result is equal to want:%v", tx, tpl.Transaction)
238         }
239 }
240
241 func TestAddContractArgs(t *testing.T) {
242         hexXpub, err := hex.DecodeString("ba76bb52574b3f40315f2c01f1818a9072ced56e9d4b68acbef56a4d0077d08e5e34837963e4cdc54eb251aa34aad01e6ae48b140f6a2743fbb0a0abd9cf8aac")
243         if err != nil {
244                 t.Fatal(err)
245         }
246
247         var xpub chainkd.XPub
248         copy(xpub[:], hexXpub)
249
250         rawTxSig := RawTxSigArgument{RootXPub: xpub, Path: []chainjson.HexBytes{{1, 1, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 0}}}
251         rawTxSigMsg, err := json.Marshal(rawTxSig)
252         if err != nil {
253                 t.Fatal(err)
254         }
255
256         value, err := hex.DecodeString("7468697320697320612074657374")
257         if err != nil {
258                 t.Fatal(err)
259         }
260         data := DataArgument{value}
261         dataMsg, err := json.Marshal(data)
262         if err != nil {
263                 t.Fatal(err)
264         }
265
266         strMsg, err := json.Marshal(StrArgument{"this is a test string"})
267         if err != nil {
268                 t.Fatal(err)
269         }
270
271         integerMsg, err := json.Marshal(IntegerArgument{100})
272         if err != nil {
273                 t.Fatal(err)
274         }
275
276         boolMsg, err := json.Marshal(BoolArgument{true})
277         if err != nil {
278                 t.Fatal(err)
279         }
280
281         cases := []struct {
282                 arguments  []ContractArgument
283                 wantResult error
284         }{
285                 {
286                         arguments: []ContractArgument{
287                                 {
288                                         Type:    "raw_tx_signature",
289                                         RawData: rawTxSigMsg,
290                                 },
291                         },
292                         wantResult: nil,
293                 },
294                 {
295                         arguments: []ContractArgument{
296                                 {
297                                         Type:    "data",
298                                         RawData: dataMsg,
299                                 },
300                         },
301                         wantResult: nil,
302                 },
303                 {
304                         arguments: []ContractArgument{
305                                 {
306                                         Type:    "string",
307                                         RawData: strMsg,
308                                 },
309                         },
310                         wantResult: nil,
311                 },
312                 {
313                         arguments: []ContractArgument{
314                                 {
315                                         Type:    "integer",
316                                         RawData: integerMsg,
317                                 },
318                         },
319                         wantResult: nil,
320                 },
321                 {
322                         arguments: []ContractArgument{
323                                 {
324                                         Type:    "boolean",
325                                         RawData: boolMsg,
326                                 },
327                         },
328                         wantResult: nil,
329                 },
330                 {
331                         arguments: []ContractArgument{
332                                 {
333                                         Type:    "raw_tx_signature",
334                                         RawData: rawTxSigMsg,
335                                 },
336                                 {
337                                         Type:    "data",
338                                         RawData: dataMsg,
339                                 },
340                         },
341                         wantResult: nil,
342                 },
343                 {
344                         arguments: []ContractArgument{
345                                 {
346                                         Type:    "data",
347                                         RawData: dataMsg,
348                                 },
349                                 {
350                                         Type:    "raw_tx_signature",
351                                         RawData: rawTxSigMsg,
352                                 },
353                         },
354                         wantResult: nil,
355                 },
356                 {
357                         arguments: []ContractArgument{
358                                 {
359                                         Type:    "raw_tx_signature",
360                                         RawData: rawTxSigMsg,
361                                 },
362                                 {
363                                         Type:    "data",
364                                         RawData: dataMsg,
365                                 },
366                                 {
367                                         Type:    "string",
368                                         RawData: strMsg,
369                                 },
370                                 {
371                                         Type:    "integer",
372                                         RawData: integerMsg,
373                                 },
374                                 {
375                                         Type:    "boolean",
376                                         RawData: boolMsg,
377                                 },
378                         },
379                         wantResult: nil,
380                 },
381                 {
382                         arguments: []ContractArgument{
383                                 {
384                                         Type:    "data",
385                                         RawData: dataMsg,
386                                 },
387                                 {
388                                         Type:    "err_data",
389                                         RawData: rawTxSigMsg,
390                                 },
391                         },
392                         wantResult: ErrBadContractArgType,
393                 },
394         }
395
396         sigInst := &SigningInstruction{}
397         for _, c := range cases {
398                 err := AddContractArgs(sigInst, c.arguments)
399                 if err != c.wantResult {
400                         t.Fatalf("got result=%v, want result=%v", err, c.wantResult)
401                 }
402         }
403 }