OSDN Git Service

add mov core test
[bytom/vapor.git] / application / mov / mov_core_test.go
diff --git a/application/mov/mov_core_test.go b/application/mov/mov_core_test.go
new file mode 100644 (file)
index 0000000..64d10ce
--- /dev/null
@@ -0,0 +1,444 @@
+package mov
+
+import (
+       "math"
+       "os"
+       "testing"
+
+       "github.com/vapor/application/mov/common"
+       "github.com/vapor/application/mov/database"
+       "github.com/vapor/application/mov/mock"
+       "github.com/vapor/consensus"
+       dbm "github.com/vapor/database/leveldb"
+       "github.com/vapor/protocol/bc"
+       "github.com/vapor/protocol/bc/types"
+       "github.com/vapor/protocol/vm"
+       "github.com/vapor/testutil"
+)
+
+func TestApplyBlock(t *testing.T) {
+       initBlockHeader := &types.BlockHeader{Height: 1, PreviousBlockHash: bc.Hash{}}
+       cases := []struct {
+               desc        string
+               block       *types.Block
+               blockFunc   testFun
+               initOrders  []*common.Order
+               wantOrders  []*common.Order
+               wantDBState *common.MovDatabaseState
+               wantError   error
+       }{
+               {
+                       desc: "apply block has pending order transaction",
+                       block: &types.Block{
+                               BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
+                               Transactions: []*types.Tx{
+                                       mock.Btc2EthMakerTxs[0], mock.Eth2BtcMakerTxs[0],
+                               },
+                       },
+                       blockFunc:   applyBlock,
+                       wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.Btc2EthMakerTxs[0], 0), mock.MustNewOrderFromOutput(mock.Eth2BtcMakerTxs[0], 0)},
+                       wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
+               },
+               {
+                       desc: "apply block has full matched transaction",
+                       block: &types.Block{
+                               BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
+                               Transactions: []*types.Tx{
+                                       mock.MatchedTxs[1],
+                               },
+                       },
+                       blockFunc:   applyBlock,
+                       initOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[0]},
+                       wantOrders:  []*common.Order{mock.Btc2EthOrders[1]},
+                       wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
+               },
+               {
+                       desc: "apply block has partial matched transaction",
+                       block: &types.Block{
+                               BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
+                               Transactions: []*types.Tx{
+                                       mock.MatchedTxs[0],
+                               },
+                       },
+                       blockFunc:   applyBlock,
+                       initOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[1]},
+                       wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[0], 1)},
+                       wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
+               },
+               {
+                       desc: "apply block has two partial matched transaction",
+                       block: &types.Block{
+                               BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
+                               Transactions: []*types.Tx{
+                                       mock.MatchedTxs[2], mock.MatchedTxs[3],
+                               },
+                       },
+                       blockFunc:   applyBlock,
+                       initOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[2]},
+                       wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[3], 1)},
+                       wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
+               },
+               {
+                       desc: "apply block has partial matched transaction by pending orders from tx pool",
+                       block: &types.Block{
+                               BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
+                               Transactions: []*types.Tx{
+                                       mock.Btc2EthMakerTxs[0],
+                                       mock.Eth2BtcMakerTxs[1],
+                                       mock.MatchedTxs[4],
+                               },
+                       },
+                       blockFunc:   applyBlock,
+                       initOrders:  []*common.Order{},
+                       wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[4], 1)},
+                       wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
+               },
+               {
+                       desc: "detach block has pending order transaction",
+                       block: &types.Block{
+                               BlockHeader: *initBlockHeader,
+                               Transactions: []*types.Tx{
+                                       mock.Btc2EthMakerTxs[0], mock.Eth2BtcMakerTxs[1],
+                               },
+                       },
+                       blockFunc:   detachBlock,
+                       initOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.Btc2EthMakerTxs[0], 0), mock.MustNewOrderFromOutput(mock.Eth2BtcMakerTxs[1], 0)},
+                       wantOrders:  []*common.Order{},
+                       wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
+               },
+               {
+                       desc: "detach block has full matched transaction",
+                       block: &types.Block{
+                               BlockHeader: *initBlockHeader,
+                               Transactions: []*types.Tx{
+                                       mock.MatchedTxs[1],
+                               },
+                       },
+                       blockFunc:   detachBlock,
+                       initOrders:  []*common.Order{mock.Btc2EthOrders[1]},
+                       wantOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[0]},
+                       wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
+               },
+               {
+                       desc: "detach block has partial matched transaction",
+                       block: &types.Block{
+                               BlockHeader: *initBlockHeader,
+                               Transactions: []*types.Tx{
+                                       mock.MatchedTxs[0],
+                               },
+                       },
+                       blockFunc:   detachBlock,
+                       initOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[0], 1)},
+                       wantOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[1]},
+                       wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
+               },
+               {
+                       desc: "detach block has two partial matched transaction",
+                       block: &types.Block{
+                               BlockHeader: *initBlockHeader,
+                               Transactions: []*types.Tx{
+                                       mock.MatchedTxs[2], mock.MatchedTxs[3],
+                               },
+                       },
+                       blockFunc:   detachBlock,
+                       initOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[3], 1)},
+                       wantOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[2]},
+                       wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
+               },
+       }
+
+       defer os.RemoveAll("temp")
+       for i, c := range cases {
+               testDB := dbm.NewDB("testdb", "leveldb", "temp")
+               store := database.NewLevelDBMovStore(testDB)
+               if err := store.InitDBState(0, &bc.Hash{}); err != nil {
+                       t.Fatal(err)
+               }
+
+               if err := store.ProcessOrders(c.initOrders, nil, initBlockHeader); err != nil {
+                       t.Fatal(err)
+               }
+
+               movCore := &MovCore{movStore: store}
+               if err := c.blockFunc(movCore, c.block); err != c.wantError {
+                       t.Errorf("#%d(%s):apply block want error(%v), got error(%v)", i, c.desc, c.wantError, err)
+               }
+
+               gotOrders := queryAllOrders(store)
+               if !ordersEquals(c.wantOrders, gotOrders) {
+                       t.Errorf("#%d(%s):apply block want orders(%v), got orders(%v)", i, c.desc, c.wantOrders, gotOrders)
+               }
+
+               dbState, err := store.GetMovDatabaseState()
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               if !testutil.DeepEqual(c.wantDBState, dbState) {
+                       t.Errorf("#%d(%s):apply block want db state(%v), got db state(%v)", i, c.desc, c.wantDBState, dbState)
+               }
+
+               testDB.Close()
+               os.RemoveAll("temp")
+       }
+}
+
+func TestValidateBlock(t *testing.T) {
+       cases := []struct {
+               desc          string
+               block         *types.Block
+               verifyResults []*bc.TxVerifyResult
+               wantError     error
+       }{
+               {
+                       desc: "block only has maker tx",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       mock.Eth2BtcMakerTxs[0],
+                                       mock.Btc2EthMakerTxs[0],
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}},
+                       wantError: nil,
+               },
+               {
+                       desc: "block only has matched tx",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       mock.MatchedTxs[0],
+                                       mock.MatchedTxs[1],
+                                       mock.MatchedTxs[2],
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}, {StatusFail: false}},
+                       wantError: nil,
+               },
+               {
+                       desc: "block has maker tx and matched tx",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       mock.Eth2BtcMakerTxs[0],
+                                       mock.Btc2EthMakerTxs[0],
+                                       mock.MatchedTxs[0],
+                                       mock.MatchedTxs[1],
+                                       mock.MatchedTxs[2],
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}, {StatusFail: false}, {StatusFail: false}, {StatusFail: false}},
+                       wantError: nil,
+               },
+               {
+                       desc: "status fail of maker tx is true",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       mock.Eth2BtcMakerTxs[0],
+                                       mock.Btc2EthMakerTxs[0],
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: true}},
+                       wantError: errStatusFailMustFalse,
+               },
+               {
+                       desc: "status fail of matched tx is true",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       mock.MatchedTxs[1],
+                                       mock.MatchedTxs[2],
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: true}},
+                       wantError: errStatusFailMustFalse,
+               },
+               {
+                       desc: "asset id in matched tx is not unique",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       types.NewTx(types.TxData{
+                                               Inputs: []*types.TxInput{
+                                                       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),
+                                                       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),
+                                               },
+                                               Outputs: []*types.TxOutput{
+                                                       types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
+                                                       types.NewIntraChainOutput(*mock.Eth2BtcOrders[0].ToAssetID, 10, testutil.MustDecodeHexString("53")),
+                                                       types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 10, []byte{0x51}),
+                                               },
+                                       }),
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: true}},
+                       wantError: errAssetIDMustUniqueInMatchedTx,
+               },
+               {
+                       desc: "common input in the matched tx",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       types.NewTx(types.TxData{
+                                               Inputs: []*types.TxInput{
+                                                       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),
+                                                       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),
+                                                       types.NewSpendInput(nil, testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"), *consensus.BTMAssetID, 100, 0, []byte{0x51}),
+                                               },
+                                               Outputs: []*types.TxOutput{
+                                                       types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
+                                                       types.NewIntraChainOutput(*mock.Eth2BtcOrders[0].ToAssetID, 10, testutil.MustDecodeHexString("53")),
+                                                       types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 10, []byte{0x51}),
+                                                       types.NewIntraChainOutput(*consensus.BTMAssetID, 100, []byte{0x51}),
+                                               },
+                                       }),
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
+                       wantError: errInputProgramMustP2WMCScript,
+               },
+               {
+                       desc: "cancel order in the matched tx",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       types.NewTx(types.TxData{
+                                               Inputs: []*types.TxInput{
+                                                       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),
+                                                       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),
+                                                       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),
+                                               },
+                                               Outputs: []*types.TxOutput{
+                                                       types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
+                                                       types.NewIntraChainOutput(*mock.Eth2BtcOrders[0].ToAssetID, 10, testutil.MustDecodeHexString("53")),
+                                                       types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 10, []byte{0x51}),
+                                                       types.NewIntraChainOutput(*consensus.BTMAssetID, 100, []byte{0x51}),
+                                               },
+                                       }),
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
+                       wantError: errExistCancelOrderInMatchedTx,
+               },
+               {
+                       desc: "common input in the cancel order tx",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       types.NewTx(types.TxData{
+                                               Inputs: []*types.TxInput{
+                                                       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),
+                                                       types.NewSpendInput(nil, testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"), *consensus.BTMAssetID, 100, 0, []byte{0x51}),
+                                               },
+                                               Outputs: []*types.TxOutput{
+                                                       types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, 10, testutil.MustDecodeHexString("51")),
+                                                       types.NewIntraChainOutput(*consensus.BTMAssetID, 100, []byte{0x51}),
+                                               },
+                                       }),
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
+                       wantError: errInputProgramMustP2WMCScript,
+               },
+               {
+                       desc: "amount of fee greater than max fee amount",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       types.NewTx(types.TxData{
+                                               Inputs: []*types.TxInput{
+                                                       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),
+                                                       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),
+                                               },
+                                               Outputs: []*types.TxOutput{
+                                                       types.NewIntraChainOutput(*mock.Btc2EthOrders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
+                                                       types.NewIntraChainOutput(*mock.Eth2BtcOrders[2].ToAssetID, 10, testutil.MustDecodeHexString("55")),
+                                                       // re-order
+                                                       types.NewIntraChainOutput(*mock.Eth2BtcOrders[2].FromAssetID, 270, mock.Eth2BtcOrders[2].Utxo.ControlProgram),
+                                                       // fee
+                                                       types.NewIntraChainOutput(*mock.Eth2BtcOrders[2].FromAssetID, 40, []byte{0x59}),
+                                               },
+                                       }),
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
+                       wantError: errAmountOfFeeGreaterThanMaximum,
+               },
+               {
+                       desc: "ratio numerator is zero",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       types.NewTx(types.TxData{
+                                               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})},
+                                               Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("51"), 0, 1))},
+                                       }),
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
+                       wantError: errRatioOfTradeLessThanZero,
+               },
+               {
+                       desc: "ratio denominator is zero",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       types.NewTx(types.TxData{
+                                               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})},
+                                               Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("51"), 1, 0))},
+                                       }),
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
+                       wantError: errRatioOfTradeLessThanZero,
+               },
+               {
+                       desc: "ratio numerator product input amount is overflow",
+                       block: &types.Block{
+                               Transactions: []*types.Tx{
+                                       types.NewTx(types.TxData{
+                                               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})},
+                                               Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("51"), math.MaxInt64, 10))},
+                                       }),
+                               },
+                       },
+                       verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
+                       wantError: errNumeratorOfRatioIsOverflow,
+               },
+       }
+
+       for i, c := range cases {
+               movCore := &MovCore{}
+               if err := movCore.ValidateBlock(c.block, c.verifyResults); err != c.wantError {
+                       t.Errorf("#%d(%s):validate block want error(%v), got error(%v)", i, c.desc, c.wantError, err)
+               }
+       }
+}
+
+type testFun func(movCore *MovCore, block *types.Block) error
+
+func applyBlock(movCore *MovCore, block *types.Block) error {
+       return movCore.ApplyBlock(block)
+}
+
+func detachBlock(movCore *MovCore, block *types.Block) error {
+       return movCore.DetachBlock(block)
+}
+
+func queryAllOrders(store *database.LevelDBMovStore) []*common.Order {
+       var orders []*common.Order
+       tradePairIterator := database.NewTradePairIterator(store)
+       for tradePairIterator.HasNext() {
+               orderIterator := database.NewOrderIterator(store, tradePairIterator.Next())
+               for orderIterator.HasNext() {
+                       orders = append(orders, orderIterator.NextBatch()...)
+               }
+       }
+       return orders
+}
+
+func ordersEquals(orders1 []*common.Order, orders2 []*common.Order) bool {
+       orderMap1 := make(map[string]*common.Order)
+       for _, order := range orders1 {
+               orderMap1[order.Key()] = order
+       }
+
+       orderMap2 := make(map[string]*common.Order)
+       for _, order := range orders2 {
+               orderMap2[order.Key()] = order
+       }
+       return testutil.DeepEqual(orderMap1, orderMap2)
+}
+
+func hashPtr(hash bc.Hash) *bc.Hash {
+       return &hash
+}