OSDN Git Service

fix mov infinite loop (#461)
[bytom/vapor.git] / application / mov / mov_core_test.go
1 package mov
2
3 import (
4         "math"
5         "os"
6         "testing"
7
8         "github.com/vapor/application/mov/common"
9         "github.com/vapor/application/mov/database"
10         "github.com/vapor/application/mov/mock"
11         "github.com/vapor/consensus"
12         dbm "github.com/vapor/database/leveldb"
13         "github.com/vapor/protocol/bc"
14         "github.com/vapor/protocol/bc/types"
15         "github.com/vapor/protocol/vm"
16         "github.com/vapor/testutil"
17 )
18
19 /*
20         @addTest:BeforeProposalBlock: will gas affect generate tx? will be packed tx affect generate tx?
21         @addTest:TestApplyBlock: one block has two different trade pairs & different trade pair won't affect each order(attach & detach)
22         @addTest:TestApplyBlock: node packed maker tx and match transaction in random order(attach & detach)
23         @addTest:TestValidateBlock: one tx has trade input and cancel input mixed
24         @addTest:TestValidateBlock: regular match transaction's seller program is also a P2WMCProgram
25 */
26 func TestApplyBlock(t *testing.T) {
27         initBlockHeader := &types.BlockHeader{Height: 1, PreviousBlockHash: bc.Hash{}}
28         cases := []struct {
29                 desc        string
30                 block       *types.Block
31                 blockFunc   testFun
32                 initOrders  []*common.Order
33                 wantOrders  []*common.Order
34                 wantDBState *common.MovDatabaseState
35                 wantError   error
36         }{
37                 {
38                         desc: "apply block has pending order transaction",
39                         block: &types.Block{
40                                 BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
41                                 Transactions: []*types.Tx{
42                                         mock.Btc2EthMakerTxs[0], mock.Eth2BtcMakerTxs[0],
43                                 },
44                         },
45                         blockFunc:   applyBlock,
46                         wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.Btc2EthMakerTxs[0], 0), mock.MustNewOrderFromOutput(mock.Eth2BtcMakerTxs[0], 0)},
47                         wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
48                 },
49                 {
50                         desc: "apply block has full matched transaction",
51                         block: &types.Block{
52                                 BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
53                                 Transactions: []*types.Tx{
54                                         mock.MatchedTxs[1],
55                                 },
56                         },
57                         blockFunc:   applyBlock,
58                         initOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[0]},
59                         wantOrders:  []*common.Order{mock.Btc2EthOrders[1]},
60                         wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
61                 },
62                 {
63                         desc: "apply block has partial matched transaction",
64                         block: &types.Block{
65                                 BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
66                                 Transactions: []*types.Tx{
67                                         mock.MatchedTxs[0],
68                                 },
69                         },
70                         blockFunc:   applyBlock,
71                         initOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[1]},
72                         wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[0], 1)},
73                         wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
74                 },
75                 {
76                         desc: "apply block has two partial matched transaction",
77                         block: &types.Block{
78                                 BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
79                                 Transactions: []*types.Tx{
80                                         mock.MatchedTxs[2], mock.MatchedTxs[3],
81                                 },
82                         },
83                         blockFunc:   applyBlock,
84                         initOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[2]},
85                         wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[3], 1)},
86                         wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
87                 },
88                 {
89                         desc: "apply block has partial matched transaction by pending orders from tx pool",
90                         block: &types.Block{
91                                 BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
92                                 Transactions: []*types.Tx{
93                                         mock.Btc2EthMakerTxs[0],
94                                         mock.Eth2BtcMakerTxs[1],
95                                         mock.MatchedTxs[4],
96                                 },
97                         },
98                         blockFunc:   applyBlock,
99                         initOrders:  []*common.Order{},
100                         wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[4], 1)},
101                         wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
102                 },
103                 {
104                         desc: "detach block has pending order transaction",
105                         block: &types.Block{
106                                 BlockHeader: *initBlockHeader,
107                                 Transactions: []*types.Tx{
108                                         mock.Btc2EthMakerTxs[0], mock.Eth2BtcMakerTxs[1],
109                                 },
110                         },
111                         blockFunc:   detachBlock,
112                         initOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.Btc2EthMakerTxs[0], 0), mock.MustNewOrderFromOutput(mock.Eth2BtcMakerTxs[1], 0)},
113                         wantOrders:  []*common.Order{},
114                         wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
115                 },
116                 {
117                         desc: "detach block has full matched transaction",
118                         block: &types.Block{
119                                 BlockHeader: *initBlockHeader,
120                                 Transactions: []*types.Tx{
121                                         mock.MatchedTxs[1],
122                                 },
123                         },
124                         blockFunc:   detachBlock,
125                         initOrders:  []*common.Order{mock.Btc2EthOrders[1]},
126                         wantOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[0]},
127                         wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
128                 },
129                 {
130                         desc: "detach block has partial matched transaction",
131                         block: &types.Block{
132                                 BlockHeader: *initBlockHeader,
133                                 Transactions: []*types.Tx{
134                                         mock.MatchedTxs[0],
135                                 },
136                         },
137                         blockFunc:   detachBlock,
138                         initOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[0], 1)},
139                         wantOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[1]},
140                         wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
141                 },
142                 {
143                         desc: "detach block has two partial matched transaction",
144                         block: &types.Block{
145                                 BlockHeader: *initBlockHeader,
146                                 Transactions: []*types.Tx{
147                                         mock.MatchedTxs[2], mock.MatchedTxs[3],
148                                 },
149                         },
150                         blockFunc:   detachBlock,
151                         initOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[3], 1)},
152                         wantOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[2]},
153                         wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
154                 },
155         }
156
157         defer os.RemoveAll("temp")
158         for i, c := range cases {
159                 testDB := dbm.NewDB("testdb", "leveldb", "temp")
160                 store := database.NewLevelDBMovStore(testDB)
161                 if err := store.InitDBState(0, &bc.Hash{}); err != nil {
162                         t.Fatal(err)
163                 }
164
165                 if err := store.ProcessOrders(c.initOrders, nil, initBlockHeader); err != nil {
166                         t.Fatal(err)
167                 }
168
169                 movCore := &MovCore{movStore: store}
170                 if err := c.blockFunc(movCore, c.block); err != c.wantError {
171                         t.Errorf("#%d(%s):apply block want error(%v), got error(%v)", i, c.desc, c.wantError, err)
172                 }
173
174                 gotOrders := queryAllOrders(store)
175                 if !ordersEquals(c.wantOrders, gotOrders) {
176                         t.Errorf("#%d(%s):apply block want orders(%v), got orders(%v)", i, c.desc, c.wantOrders, gotOrders)
177                 }
178
179                 dbState, err := store.GetMovDatabaseState()
180                 if err != nil {
181                         t.Fatal(err)
182                 }
183
184                 if !testutil.DeepEqual(c.wantDBState, dbState) {
185                         t.Errorf("#%d(%s):apply block want db state(%v), got db state(%v)", i, c.desc, c.wantDBState, dbState)
186                 }
187
188                 testDB.Close()
189                 os.RemoveAll("temp")
190         }
191 }
192
193 func TestValidateBlock(t *testing.T) {
194         cases := []struct {
195                 desc          string
196                 block         *types.Block
197                 verifyResults []*bc.TxVerifyResult
198                 wantError     error
199         }{
200                 {
201                         desc: "block only has maker tx",
202                         block: &types.Block{
203                                 Transactions: []*types.Tx{
204                                         mock.Eth2BtcMakerTxs[0],
205                                         mock.Btc2EthMakerTxs[0],
206                                 },
207                         },
208                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}},
209                         wantError:     nil,
210                 },
211                 {
212                         desc: "block only has matched tx",
213                         block: &types.Block{
214                                 Transactions: []*types.Tx{
215                                         mock.MatchedTxs[0],
216                                         mock.MatchedTxs[1],
217                                         mock.MatchedTxs[2],
218                                 },
219                         },
220                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}, {StatusFail: false}},
221                         wantError:     nil,
222                 },
223                 {
224                         desc: "block has maker tx and matched tx",
225                         block: &types.Block{
226                                 Transactions: []*types.Tx{
227                                         mock.Eth2BtcMakerTxs[0],
228                                         mock.Btc2EthMakerTxs[0],
229                                         mock.MatchedTxs[0],
230                                         mock.MatchedTxs[1],
231                                         mock.MatchedTxs[2],
232                                 },
233                         },
234                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}, {StatusFail: false}, {StatusFail: false}, {StatusFail: false}},
235                         wantError:     nil,
236                 },
237                 {
238                         desc: "status fail of maker tx is true",
239                         block: &types.Block{
240                                 Transactions: []*types.Tx{
241                                         mock.Eth2BtcMakerTxs[0],
242                                         mock.Btc2EthMakerTxs[0],
243                                 },
244                         },
245                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: true}},
246                         wantError:     errStatusFailMustFalse,
247                 },
248                 {
249                         desc: "status fail of matched tx is true",
250                         block: &types.Block{
251                                 Transactions: []*types.Tx{
252                                         mock.MatchedTxs[1],
253                                         mock.MatchedTxs[2],
254                                 },
255                         },
256                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: true}},
257                         wantError:     errStatusFailMustFalse,
258                 },
259                 {
260                         desc: "asset id in matched tx is not unique",
261                         block: &types.Block{
262                                 Transactions: []*types.Tx{
263                                         types.NewTx(types.TxData{
264                                                 Inputs: []*types.TxInput{
265                                                         types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, mock.Btc2EthOrders[0].Utxo.ControlProgram),
266                                                         types.NewSpendInput([][]byte{vm.Int64Bytes(1), vm.Int64Bytes(1)}, *mock.Eth2BtcOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Eth2BtcOrders[0].Utxo.Amount, mock.Eth2BtcOrders[0].Utxo.SourcePos, mock.Eth2BtcOrders[0].Utxo.ControlProgram),
267                                                 },
268                                                 Outputs: []*types.TxOutput{
269                                                         types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
270                                                         types.NewIntraChainOutput(*mock.Eth2BtcOrders[0].ToAssetID, 10, testutil.MustDecodeHexString("53")),
271                                                         types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 10, []byte{0x51}),
272                                                 },
273                                         }),
274                                 },
275                         },
276                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: true}},
277                         wantError:     errAssetIDMustUniqueInMatchedTx,
278                 },
279                 {
280                         desc: "common input in the matched tx",
281                         block: &types.Block{
282                                 Transactions: []*types.Tx{
283                                         types.NewTx(types.TxData{
284                                                 Inputs: []*types.TxInput{
285                                                         types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, mock.Btc2EthOrders[0].Utxo.ControlProgram),
286                                                         types.NewSpendInput([][]byte{vm.Int64Bytes(1), vm.Int64Bytes(1)}, *mock.Eth2BtcOrders[0].Utxo.SourceID, *mock.Eth2BtcOrders[0].FromAssetID, mock.Eth2BtcOrders[0].Utxo.Amount, mock.Eth2BtcOrders[0].Utxo.SourcePos, mock.Eth2BtcOrders[0].Utxo.ControlProgram),
287                                                         types.NewSpendInput(nil, testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"), *consensus.BTMAssetID, 100, 0, []byte{0x51}),
288                                                 },
289                                                 Outputs: []*types.TxOutput{
290                                                         types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
291                                                         types.NewIntraChainOutput(*mock.Eth2BtcOrders[0].ToAssetID, 10, testutil.MustDecodeHexString("53")),
292                                                         types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 10, []byte{0x51}),
293                                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 100, []byte{0x51}),
294                                                 },
295                                         }),
296                                 },
297                         },
298                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
299                         wantError:     errInputProgramMustP2WMCScript,
300                 },
301                 {
302                         desc: "cancel order in the matched tx",
303                         block: &types.Block{
304                                 Transactions: []*types.Tx{
305                                         types.NewTx(types.TxData{
306                                                 Inputs: []*types.TxInput{
307                                                         types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, mock.Btc2EthOrders[0].Utxo.ControlProgram),
308                                                         types.NewSpendInput([][]byte{vm.Int64Bytes(1), vm.Int64Bytes(1)}, *mock.Eth2BtcOrders[0].Utxo.SourceID, *mock.Eth2BtcOrders[0].FromAssetID, mock.Eth2BtcOrders[0].Utxo.Amount, mock.Eth2BtcOrders[0].Utxo.SourcePos, mock.Eth2BtcOrders[0].Utxo.ControlProgram),
309                                                         types.NewSpendInput([][]byte{{}, {}, vm.Int64Bytes(2)}, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, mock.Btc2EthOrders[0].Utxo.ControlProgram),
310                                                 },
311                                                 Outputs: []*types.TxOutput{
312                                                         types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
313                                                         types.NewIntraChainOutput(*mock.Eth2BtcOrders[0].ToAssetID, 10, testutil.MustDecodeHexString("53")),
314                                                         types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 10, []byte{0x51}),
315                                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 100, []byte{0x51}),
316                                                 },
317                                         }),
318                                 },
319                         },
320                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
321                         wantError:     errExistCancelOrderInMatchedTx,
322                 },
323                 {
324                         desc: "common input in the cancel order tx",
325                         block: &types.Block{
326                                 Transactions: []*types.Tx{
327                                         types.NewTx(types.TxData{
328                                                 Inputs: []*types.TxInput{
329                                                         types.NewSpendInput([][]byte{{}, {}, vm.Int64Bytes(2)}, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, mock.Btc2EthOrders[0].Utxo.ControlProgram),
330                                                         types.NewSpendInput(nil, testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"), *consensus.BTMAssetID, 100, 0, []byte{0x51}),
331                                                 },
332                                                 Outputs: []*types.TxOutput{
333                                                         types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, 10, testutil.MustDecodeHexString("51")),
334                                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 100, []byte{0x51}),
335                                                 },
336                                         }),
337                                 },
338                         },
339                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
340                         wantError:     errInputProgramMustP2WMCScript,
341                 },
342                 {
343                         desc: "amount of fee greater than max fee amount",
344                         block: &types.Block{
345                                 Transactions: []*types.Tx{
346                                         types.NewTx(types.TxData{
347                                                 Inputs: []*types.TxInput{
348                                                         types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, mock.Btc2EthOrders[0].Utxo.ControlProgram),
349                                                         types.NewSpendInput([][]byte{vm.Int64Bytes(10), vm.Int64Bytes(1), vm.Int64Bytes(0)}, *mock.Eth2BtcOrders[2].Utxo.SourceID, *mock.Eth2BtcOrders[2].FromAssetID, mock.Eth2BtcOrders[2].Utxo.Amount, mock.Eth2BtcOrders[2].Utxo.SourcePos, mock.Eth2BtcOrders[2].Utxo.ControlProgram),
350                                                 },
351                                                 Outputs: []*types.TxOutput{
352                                                         types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
353                                                         types.NewIntraChainOutput(*mock.Eth2BtcOrders[2].ToAssetID, 10, testutil.MustDecodeHexString("55")),
354                                                         // re-order
355                                                         types.NewIntraChainOutput(*mock.Eth2BtcOrders[2].FromAssetID, 270, mock.Eth2BtcOrders[2].Utxo.ControlProgram),
356                                                         // fee
357                                                         types.NewIntraChainOutput(*mock.Eth2BtcOrders[2].FromAssetID, 40, []byte{0x59}),
358                                                 },
359                                         }),
360                                 },
361                         },
362                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
363                         wantError:     errAmountOfFeeGreaterThanMaximum,
364                 },
365                 {
366                         desc: "ratio numerator is zero",
367                         block: &types.Block{
368                                 Transactions: []*types.Tx{
369                                         types.NewTx(types.TxData{
370                                                 Inputs:  []*types.TxInput{types.NewSpendInput(nil, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, []byte{0x51})},
371                                                 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251"), 0, 1))},
372                                         }),
373                                 },
374                         },
375                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
376                         wantError:     errRatioOfTradeLessThanZero,
377                 },
378                 {
379                         desc: "ratio denominator is zero",
380                         block: &types.Block{
381                                 Transactions: []*types.Tx{
382                                         types.NewTx(types.TxData{
383                                                 Inputs:  []*types.TxInput{types.NewSpendInput(nil, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, []byte{0x51})},
384                                                 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251"), 1, 0))},
385                                         }),
386                                 },
387                         },
388                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
389                         wantError:     errRatioOfTradeLessThanZero,
390                 },
391                 {
392                         desc: "want amount is overflow",
393                         block: &types.Block{
394                                 Transactions: []*types.Tx{
395                                         types.NewTx(types.TxData{
396                                                 Inputs:  []*types.TxInput{types.NewSpendInput(nil, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, []byte{0x51})},
397                                                 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251"), math.MaxInt64, 1))},
398                                         }),
399                                 },
400                         },
401                         verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
402                         wantError:     errRequestAmountMath,
403                 },
404         }
405
406         for i, c := range cases {
407                 movCore := &MovCore{}
408                 if err := movCore.ValidateBlock(c.block, c.verifyResults); err != c.wantError {
409                         t.Errorf("#%d(%s):validate block want error(%v), got error(%v)", i, c.desc, c.wantError, err)
410                 }
411         }
412 }
413
414 type testFun func(movCore *MovCore, block *types.Block) error
415
416 func applyBlock(movCore *MovCore, block *types.Block) error {
417         return movCore.ApplyBlock(block)
418 }
419
420 func detachBlock(movCore *MovCore, block *types.Block) error {
421         return movCore.DetachBlock(block)
422 }
423
424 func queryAllOrders(store *database.LevelDBMovStore) []*common.Order {
425         var orders []*common.Order
426         tradePairIterator := database.NewTradePairIterator(store)
427         for tradePairIterator.HasNext() {
428                 orderIterator := database.NewOrderIterator(store, tradePairIterator.Next())
429                 for orderIterator.HasNext() {
430                         orders = append(orders, orderIterator.NextBatch()...)
431                 }
432         }
433         return orders
434 }
435
436 func ordersEquals(orders1 []*common.Order, orders2 []*common.Order) bool {
437         orderMap1 := make(map[string]*common.Order)
438         for _, order := range orders1 {
439                 orderMap1[order.Key()] = order
440         }
441
442         orderMap2 := make(map[string]*common.Order)
443         for _, order := range orders2 {
444                 orderMap2[order.Key()] = order
445         }
446         return testutil.DeepEqual(orderMap1, orderMap2)
447 }
448
449 func hashPtr(hash bc.Hash) *bc.Hash {
450         return &hash
451 }