},
}
+ Btc2EthCancelTxs = []*types.Tx{
+ // Btc2EthOrders[0]
+ types.NewTx(types.TxData{
+ Inputs: []*types.TxInput{types.NewSpendInput([][]byte{{}, {}, vm.Int64Bytes(2)}, *Btc2EthOrders[0].Utxo.SourceID, *Btc2EthOrders[0].FromAssetID, Btc2EthOrders[0].Utxo.Amount, Btc2EthOrders[0].Utxo.SourcePos, Btc2EthOrders[0].Utxo.ControlProgram)},
+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*Btc2EthOrders[0].FromAssetID, Btc2EthOrders[0].Utxo.Amount, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251"))},
+ }),
+ }
+
Btc2EthMakerTxs = []*types.Tx{
// Btc2EthOrders[0]
types.NewTx(types.TxData{
},
}),
- // full matched transaction from Eos2Etc[0] Etc2Eos[0]
+ // full matched transaction from Eos2EtcMakerTxs[0] Etc2EosMakerTxs[0]
types.NewTx(types.TxData{
Inputs: []*types.TxInput{
types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *MustNewOrderFromOutput(Eos2EtcMakerTxs[0], 0).Utxo.SourceID, *Eos2EtcOrders[0].FromAssetID, Eos2EtcOrders[0].Utxo.Amount, Eos2EtcOrders[0].Utxo.SourcePos, Eos2EtcOrders[0].Utxo.ControlProgram),
types.NewIntraChainOutput(*Eth2BtcOrders[0].FromAssetID, 404, Eth2BtcOrders[0].Utxo.ControlProgram),
},
}),
+
+ // partial matched transaction from Btc2EthOrders[3], Eth2BtcOrders[2]
+ types.NewTx(types.TxData{
+ Inputs: []*types.TxInput{
+ types.NewSpendInput([][]byte{vm.Int64Bytes(810), vm.Int64Bytes(0), vm.Int64Bytes(0)}, *Btc2EthOrders[3].Utxo.SourceID, *Btc2EthOrders[3].FromAssetID, Btc2EthOrders[3].Utxo.Amount, Btc2EthOrders[3].Utxo.SourcePos, Btc2EthOrders[3].Utxo.ControlProgram),
+ types.NewSpendInput([][]byte{vm.Int64Bytes(2), vm.Int64Bytes(1)}, *Eth2BtcOrders[2].Utxo.SourceID, *Eth2BtcOrders[2].FromAssetID, Eth2BtcOrders[2].Utxo.Amount, Eth2BtcOrders[2].Utxo.SourcePos, Eth2BtcOrders[2].Utxo.ControlProgram),
+ },
+ Outputs: []*types.TxOutput{
+ types.NewIntraChainOutput(*Btc2EthOrders[3].ToAssetID, 810, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19252")),
+ // re-order
+ types.NewIntraChainOutput(*Btc2EthOrders[3].FromAssetID, 1, Btc2EthOrders[3].Utxo.ControlProgram),
+ types.NewIntraChainOutput(*Eth2BtcOrders[2].ToAssetID, 15, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19255")),
+ // fee
+ types.NewIntraChainOutput(*Btc2EthOrders[3].FromAssetID, 1, NodeProgram),
+ },
+ }),
+
+ // full matched transaction from Eos2EtcOrders[0] Etc2EosOrders[0]
+ types.NewTx(types.TxData{
+ Inputs: []*types.TxInput{
+ types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *Eos2EtcOrders[0].Utxo.SourceID, *Eos2EtcOrders[0].FromAssetID, Eos2EtcOrders[0].Utxo.Amount, Eos2EtcOrders[0].Utxo.SourcePos, Eos2EtcOrders[0].Utxo.ControlProgram),
+ types.NewSpendInput([][]byte{vm.Int64Bytes(1), vm.Int64Bytes(1)}, *Etc2EosOrders[0].Utxo.SourceID, *Etc2EosOrders[0].FromAssetID, Etc2EosOrders[0].Utxo.Amount, Etc2EosOrders[0].Utxo.SourcePos, Etc2EosOrders[0].Utxo.ControlProgram),
+ },
+ Outputs: []*types.TxOutput{
+ types.NewIntraChainOutput(*Eos2EtcOrders[0].ToAssetID, 50, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19255")),
+ types.NewIntraChainOutput(*Etc2EosOrders[0].ToAssetID, 100, testutil.MustDecodeHexString("0014df7a97e53bbe278e4e44810b0a760fb472daa9a3")),
+ },
+ }),
}
)
}
}
+func TestValidateMatchedTxSequence(t *testing.T) {
+ cases := []struct {
+ desc string
+ initOrders []*common.Order
+ transactions []*types.Tx
+ wantError error
+ }{
+ {
+ desc: "both db orders and transactions is empty",
+ initOrders: []*common.Order{},
+ transactions: []*types.Tx{},
+ wantError: nil,
+ },
+ {
+ desc: "existing matched orders in db, and transactions is empty",
+ initOrders: []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0]},
+ transactions: []*types.Tx{},
+ wantError: nil,
+ },
+ {
+ desc: "db orders is empty, but transactions has matched tx",
+ initOrders: []*common.Order{},
+ transactions: []*types.Tx{mock.MatchedTxs[1]},
+ wantError: errNotMatchedOrder,
+ },
+ {
+ desc: "existing matched orders in db, and corresponding matched tx in transactions",
+ initOrders: []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0]},
+ transactions: []*types.Tx{mock.MatchedTxs[1]},
+ wantError: nil,
+ },
+ {
+ desc: "existing two matched orders in db, and only one corresponding matched tx in transactions",
+ initOrders: []*common.Order{
+ mock.Btc2EthOrders[3], mock.Eth2BtcOrders[2],
+ mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0],
+ },
+ transactions: []*types.Tx{mock.MatchedTxs[8]},
+ wantError: nil,
+ },
+ {
+ desc: "existing two matched orders in db, and the sequence of match txs in incorrect",
+ initOrders: []*common.Order{
+ mock.Btc2EthOrders[3], mock.Eth2BtcOrders[2],
+ mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0],
+ },
+ transactions: []*types.Tx{mock.MatchedTxs[1], mock.MatchedTxs[8]},
+ wantError: errSpendOutputIDIsIncorrect,
+ },
+ {
+ desc: "package full matched tx from maker tx",
+ initOrders: []*common.Order{},
+ transactions: []*types.Tx{mock.Btc2EthMakerTxs[0], mock.Eth2BtcMakerTxs[1], mock.MatchedTxs[4]},
+ wantError: nil,
+ },
+ {
+ desc: "package the matched tx first, then package match orders",
+ initOrders: []*common.Order{},
+ transactions: []*types.Tx{mock.MatchedTxs[4], mock.Btc2EthMakerTxs[0], mock.Eth2BtcMakerTxs[1]},
+ wantError: errNotMatchedOrder,
+ },
+ {
+ desc: "cancel order in transactions",
+ initOrders: []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0]},
+ transactions: []*types.Tx{mock.Btc2EthCancelTxs[0], mock.MatchedTxs[1]},
+ wantError: errNotMatchedOrder,
+ },
+ {
+ desc: "package cancel order after match tx",
+ initOrders: []*common.Order{mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0]},
+ transactions: []*types.Tx{mock.MatchedTxs[1], mock.Btc2EthCancelTxs[0]},
+ wantError: nil,
+ },
+ {
+ desc: "package matched txs of different trade pairs",
+ initOrders: []*common.Order{
+ mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0],
+ mock.Eos2EtcOrders[0], mock.Etc2EosOrders[0],
+ },
+ transactions: []*types.Tx{mock.MatchedTxs[1], mock.MatchedTxs[9]},
+ wantError: nil,
+ },
+ {
+ desc: "package matched txs of different trade pairs in different sequence",
+ initOrders: []*common.Order{
+ mock.Btc2EthOrders[0], mock.Eth2BtcOrders[0],
+ mock.Eos2EtcOrders[0], mock.Etc2EosOrders[0],
+ },
+ transactions: []*types.Tx{mock.MatchedTxs[9], mock.MatchedTxs[1]},
+ wantError: nil,
+ },
+ {
+ desc: "package partial matched tx from db orders",
+ initOrders: []*common.Order{mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Eth2BtcOrders[2]},
+ transactions: []*types.Tx{mock.MatchedTxs[2], mock.MatchedTxs[3]},
+ wantError: nil,
+ },
+ }
+
+ 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 := movCore.validateMatchedTxSequence(c.transactions); err != c.wantError {
+ t.Errorf("#%d(%s):wanet error(%v), got error(%v)", i, c.desc, c.wantError, err)
+ }
+
+ testDB.Close()
+ os.RemoveAll("temp")
+ }
+}
+
type testFun func(movCore *MovCore, block *types.Block) error
func applyBlock(movCore *MovCore, block *types.Block) error {