OSDN Git Service

final code review (#484)
[bytom/vapor.git] / application / mov / mov_core_test.go
index 8fb0be3..9c0b354 100644 (file)
@@ -5,26 +5,20 @@ import (
        "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"
+       "github.com/bytom/vapor/application/mov/common"
+       "github.com/bytom/vapor/application/mov/database"
+       "github.com/bytom/vapor/application/mov/mock"
+       "github.com/bytom/vapor/consensus"
+       dbm "github.com/bytom/vapor/database/leveldb"
+       "github.com/bytom/vapor/protocol/bc"
+       "github.com/bytom/vapor/protocol/bc/types"
+       "github.com/bytom/vapor/protocol/vm"
+       "github.com/bytom/vapor/testutil"
 )
 
-/*
-       @addTest:BeforeProposalBlock: will gas affect generate tx? will be packed tx affect generate tx?
-       @addTest:TestApplyBlock: one block has two different trade pairs & different trade pair won't affect each order(attach & detach)
-       @addTest:TestApplyBlock: node packed maker tx and match transaction in random order(attach & detach)
-       @addTest:TestValidateBlock: one tx has trade input and cancel input mixed
-       @addTest:TestValidateBlock: regular match transaction's seller program is also a P2WMCProgram
-*/
+var initBlockHeader = &types.BlockHeader{Height: 1, PreviousBlockHash: bc.Hash{}}
+
 func TestApplyBlock(t *testing.T) {
-       initBlockHeader := &types.BlockHeader{Height: 1, PreviousBlockHash: bc.Hash{}}
        cases := []struct {
                desc        string
                block       *types.Block
@@ -47,6 +41,26 @@ func TestApplyBlock(t *testing.T) {
                        wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
                },
                {
+                       desc: "apply block has two different trade pairs & different trade pair won't affect each order",
+                       block: &types.Block{
+                               BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
+                               Transactions: []*types.Tx{
+                                       mock.Btc2EthMakerTxs[0],
+                                       mock.Eth2BtcMakerTxs[0],
+                                       mock.Eos2EtcMakerTxs[0],
+                                       mock.Eth2EosMakerTxs[0],
+                               },
+                       },
+                       blockFunc: applyBlock,
+                       wantOrders: []*common.Order{
+                               mock.MustNewOrderFromOutput(mock.Btc2EthMakerTxs[0], 0),
+                               mock.MustNewOrderFromOutput(mock.Eth2BtcMakerTxs[0], 0),
+                               mock.MustNewOrderFromOutput(mock.Eos2EtcMakerTxs[0], 0),
+                               mock.MustNewOrderFromOutput(mock.Eth2EosMakerTxs[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()},
@@ -101,6 +115,45 @@ func TestApplyBlock(t *testing.T) {
                        wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
                },
                {
+                       desc: "apply block which node packed maker tx and match transaction in random orde",
+                       block: &types.Block{
+                               BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
+                               Transactions: []*types.Tx{
+                                       mock.Eos2EtcMakerTxs[0],
+                                       mock.Btc2EthMakerTxs[0],
+                                       mock.Eth2BtcMakerTxs[1],
+                                       mock.MatchedTxs[4],
+                                       mock.Eth2EosMakerTxs[0],
+                                       mock.Etc2EosMakerTxs[0],
+                                       mock.MatchedTxs[5],
+                               },
+                       },
+                       blockFunc:  applyBlock,
+                       initOrders: []*common.Order{},
+                       wantOrders: []*common.Order{
+                               mock.MustNewOrderFromOutput(mock.MatchedTxs[4], 1),
+                               mock.MustNewOrderFromOutput(mock.Eth2EosMakerTxs[0], 0),
+                       },
+                       wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
+               },
+               {
+                       desc: "apply block has partial matched transaction chain",
+                       block: &types.Block{
+                               BlockHeader: types.BlockHeader{Height: 2, PreviousBlockHash: initBlockHeader.Hash()},
+                               Transactions: []*types.Tx{
+                                       mock.Btc2EthMakerTxs[0],
+                                       mock.Eth2BtcMakerTxs[1],
+                                       mock.MatchedTxs[4],
+                                       mock.Eth2BtcMakerTxs[0],
+                                       mock.MatchedTxs[7],
+                               },
+                       },
+                       blockFunc:   applyBlock,
+                       initOrders:  []*common.Order{},
+                       wantOrders:  []*common.Order{mock.MustNewOrderFromOutput(mock.MatchedTxs[7], 2)},
+                       wantDBState: &common.MovDatabaseState{Height: 2, Hash: hashPtr(testutil.MustDecodeHash("88dbcde57bb2b53b107d7494f20f1f1a892307a019705980c3510890449c0020"))},
+               },
+               {
                        desc: "detach block has pending order transaction",
                        block: &types.Block{
                                BlockHeader: *initBlockHeader,
@@ -114,6 +167,27 @@ func TestApplyBlock(t *testing.T) {
                        wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
                },
                {
+                       desc: "detach block has two different trade pairs & different trade pair won't affect each order",
+                       block: &types.Block{
+                               BlockHeader: *initBlockHeader,
+                               Transactions: []*types.Tx{
+                                       mock.Btc2EthMakerTxs[0],
+                                       mock.Eth2BtcMakerTxs[0],
+                                       mock.Eos2EtcMakerTxs[0],
+                                       mock.Eth2EosMakerTxs[0],
+                               },
+                       },
+                       blockFunc: detachBlock,
+                       initOrders: []*common.Order{
+                               mock.MustNewOrderFromOutput(mock.Btc2EthMakerTxs[0], 0),
+                               mock.MustNewOrderFromOutput(mock.Eth2BtcMakerTxs[0], 0),
+                               mock.MustNewOrderFromOutput(mock.Eos2EtcMakerTxs[0], 0),
+                               mock.MustNewOrderFromOutput(mock.Eth2EosMakerTxs[0], 0),
+                       },
+                       wantOrders:  []*common.Order{},
+                       wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
+               },
+               {
                        desc: "detach block has full matched transaction",
                        block: &types.Block{
                                BlockHeader: *initBlockHeader,
@@ -152,6 +226,28 @@ func TestApplyBlock(t *testing.T) {
                        wantOrders:  []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[2]},
                        wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
                },
+               {
+                       desc: "detach block which node packed maker tx and match transaction in random orde",
+                       block: &types.Block{
+                               BlockHeader: *initBlockHeader,
+                               Transactions: []*types.Tx{
+                                       mock.Eos2EtcMakerTxs[0],
+                                       mock.Btc2EthMakerTxs[0],
+                                       mock.MatchedTxs[4],
+                                       mock.Eth2EosMakerTxs[0],
+                                       mock.Eth2BtcMakerTxs[1],
+                                       mock.MatchedTxs[5],
+                                       mock.Etc2EosMakerTxs[0],
+                               },
+                       },
+                       blockFunc: detachBlock,
+                       initOrders: []*common.Order{
+                               mock.MustNewOrderFromOutput(mock.MatchedTxs[4], 1),
+                               mock.MustNewOrderFromOutput(mock.Eth2EosMakerTxs[0], 0),
+                       },
+                       wantOrders:  []*common.Order{},
+                       wantDBState: &common.MovDatabaseState{Height: 0, Hash: &bc.Hash{}},
+               },
        }
 
        defer os.RemoveAll("temp")
@@ -368,7 +464,7 @@ func TestValidateBlock(t *testing.T) {
                                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))},
+                                               Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251"), 0, 1))},
                                        }),
                                },
                        },
@@ -381,7 +477,7 @@ func TestValidateBlock(t *testing.T) {
                                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))},
+                                               Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251"), 1, 0))},
                                        }),
                                },
                        },
@@ -389,17 +485,17 @@ func TestValidateBlock(t *testing.T) {
                        wantError:     errRatioOfTradeLessThanZero,
                },
                {
-                       desc: "ratio numerator product input amount is overflow",
+                       desc: "want 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))},
+                                               Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251"), math.MaxInt64, 1))},
                                        }),
                                },
                        },
                        verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
-                       wantError:     errNumeratorOfRatioIsOverflow,
+                       wantError:     errRequestAmountMath,
                },
        }
 
@@ -411,6 +507,95 @@ func TestValidateBlock(t *testing.T) {
        }
 }
 
+func TestBeforeProposalBlock(t *testing.T) {
+       cases := []struct {
+               desc           string
+               initOrders     []*common.Order
+               gasLeft        int64
+               wantMatchedTxs []*types.Tx
+       }{
+               {
+                       desc:           "has matched tx, but gas left is zero",
+                       initOrders:     []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0]},
+                       gasLeft:        0,
+                       wantMatchedTxs: []*types.Tx{},
+               },
+               {
+                       desc:           "has one matched tx, and gas is sufficient",
+                       initOrders:     []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0]},
+                       gasLeft:        2000,
+                       wantMatchedTxs: []*types.Tx{mock.MatchedTxs[1]},
+               },
+               {
+                       desc: "has two matched tx, but gas is only enough to pack a matched tx",
+                       initOrders: []*common.Order{
+                               mock.Btc2EthOrders[0],
+                               mock.Btc2EthOrders[1],
+                               mock.Eth2BtcOrders[2],
+                       },
+                       gasLeft:        2000,
+                       wantMatchedTxs: []*types.Tx{mock.MatchedTxs[2]},
+               },
+               {
+                       desc: "has two matched tx, and gas left is sufficient",
+                       initOrders: []*common.Order{
+                               mock.Btc2EthOrders[0],
+                               mock.Btc2EthOrders[1],
+                               mock.Eth2BtcOrders[2],
+                       },
+                       gasLeft:        4000,
+                       wantMatchedTxs: []*types.Tx{mock.MatchedTxs[2], mock.MatchedTxs[3]},
+               },
+               {
+                       desc: "has multiple trade pairs, and gas left is sufficient",
+                       initOrders: []*common.Order{
+                               mock.Btc2EthOrders[0],
+                               mock.Btc2EthOrders[1],
+                               mock.Eth2BtcOrders[2],
+                               mock.Eos2EtcOrders[0],
+                               mock.Etc2EosOrders[0],
+                       },
+                       gasLeft:        6000,
+                       wantMatchedTxs: []*types.Tx{mock.MatchedTxs[2], mock.MatchedTxs[3], mock.MatchedTxs[5]},
+               },
+       }
+
+       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}
+               gotMatchedTxs, err := movCore.BeforeProposalBlock(nil, []byte{0x51}, 2, c.gasLeft, func() bool { return false })
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               gotMatchedTxMap := make(map[string]interface{})
+               for _, matchedTx := range gotMatchedTxs {
+                       gotMatchedTxMap[matchedTx.ID.String()] = nil
+               }
+
+               wantMatchedTxMap := make(map[string]interface{})
+               for _, matchedTx := range c.wantMatchedTxs {
+                       wantMatchedTxMap[matchedTx.ID.String()] = nil
+               }
+
+               if !testutil.DeepEqual(gotMatchedTxMap, wantMatchedTxMap) {
+                       t.Errorf("#%d(%s):want matched tx(%v) is not equals got matched tx(%v)", i, c.desc, c.wantMatchedTxs, gotMatchedTxs)
+               }
+
+               testDB.Close()
+               os.RemoveAll("temp")
+       }
+}
+
 type testFun func(movCore *MovCore, block *types.Block) error
 
 func applyBlock(movCore *MovCore, block *types.Block) error {