OSDN Git Service

final code review (#484)
authorPaladz <yzhu101@uottawa.ca>
Wed, 12 Feb 2020 02:55:49 +0000 (10:55 +0800)
committerGitHub <noreply@github.com>
Wed, 12 Feb 2020 02:55:49 +0000 (10:55 +0800)
* final code review

* edit for code review

Co-authored-by: Colt-Z <453256728@qq.com>
application/mov/common/type.go
application/mov/common/util.go
application/mov/database/mov_store.go
application/mov/match/match.go
application/mov/match/order_book.go
application/mov/match/order_book_test.go
application/mov/match_collector.go
application/mov/mock/mock.go
application/mov/mov_core.go
application/mov/mov_core_test.go
proposal/proposal.go

index 14b3f9e..d038902 100644 (file)
@@ -28,16 +28,17 @@ type Order struct {
        RatioDenominator int64
 }
 
+// Rate return the exchange represented by float64
 func (o *Order) Rate() float64 {
        if o.RatioDenominator == 0 {
                return 0
        }
-       rate := big.NewFloat(0).SetInt64(o.RatioNumerator)
-       rate.Quo(rate, big.NewFloat(0).SetInt64(o.RatioDenominator))
+       rate := big.NewRat(o.RatioNumerator, o.RatioDenominator)
        result, _ := rate.Float64()
        return result
 }
 
+// Cmp compares x and y and returns -1 if x <  y, 0 if x == y, +1 if x >  y
 func (o *Order) Cmp(other *Order) int {
        rate := big.NewRat(o.RatioNumerator, o.RatioDenominator)
        otherRate := big.NewRat(other.RatioNumerator, other.RatioDenominator)
index 09413c9..0077eab 100644 (file)
@@ -12,7 +12,7 @@ func IsMatchedTx(tx *types.Tx) bool {
                return false
        }
        for _, input := range tx.Inputs {
-               if input.InputType() == types.SpendInputType && contract.IsTradeClauseSelector(input) && segwit.IsP2WMCScript(input.ControlProgram()) {
+               if input.InputType() == types.SpendInputType && segwit.IsP2WMCScript(input.ControlProgram()) && contract.IsTradeClauseSelector(input) {
                        return true
                }
        }
@@ -22,7 +22,7 @@ func IsMatchedTx(tx *types.Tx) bool {
 // IsCancelOrderTx check if this transaction has cancel mov order input
 func IsCancelOrderTx(tx *types.Tx) bool {
        for _, input := range tx.Inputs {
-               if input.InputType() == types.SpendInputType && contract.IsCancelClauseSelector(input) && segwit.IsP2WMCScript(input.ControlProgram()) {
+               if input.InputType() == types.SpendInputType && segwit.IsP2WMCScript(input.ControlProgram()) && contract.IsCancelClauseSelector(input) {
                        return true
                }
        }
index e9b7183..20d3101 100644 (file)
@@ -121,7 +121,6 @@ func (m *LevelDBMovStore) ListOrders(orderAfter *common.Order) ([]*common.Order,
        orderPrefix = append(orderPrefix, orderAfter.ToAssetID.Bytes()...)
 
        var startKey []byte
-
        if orderAfter.Rate() > 0 {
                startKey = calcOrderKey(orderAfter.FromAssetID, orderAfter.ToAssetID, orderAfter.UTXOHash(), orderAfter.Rate())
        }
index 845c228..64ed4e8 100644 (file)
@@ -208,6 +208,7 @@ func addMatchTxOutput(txData *types.TxData, txInput *types.TxInput, order *commo
        return nil
 }
 
+// CalcRequestAmount is from amount * numerator / ratioDenominator
 func CalcRequestAmount(fromAmount uint64, contractArg *vmutil.MagneticContractArgs) uint64 {
        res := big.NewInt(0).SetUint64(fromAmount)
        res.Mul(res, big.NewInt(contractArg.RatioNumerator)).Quo(res, big.NewInt(contractArg.RatioDenominator))
@@ -234,6 +235,7 @@ func calcOppositeIndex(size int, selfIdx int) int {
        return (selfIdx + 1) % size
 }
 
+// IsMatched check does the orders can be exchange
 func IsMatched(orders []*common.Order) bool {
        sortedOrders := sortOrders(orders)
        if len(sortedOrders) == 0 {
@@ -283,6 +285,10 @@ func validateTradePairs(tradePairs []*common.TradePair) error {
 }
 
 func sortOrders(orders []*common.Order) []*common.Order {
+       if len(orders) == 0 {
+               return nil
+       }
+
        orderMap := make(map[bc.AssetID]*common.Order)
        firstOrder := orders[0]
        for i := 1; i < len(orders); i++ {
index ea49643..e779289 100644 (file)
@@ -23,6 +23,28 @@ type OrderBook struct {
        arrivalDelOrders *sync.Map
 }
 
+func arrangeArrivalAddOrders(orders []*common.Order) *sync.Map {
+       orderMap := make(map[string][]*common.Order)
+       for _, order := range orders {
+               orderMap[order.TradePair().Key()] = append(orderMap[order.TradePair().Key()], order)
+       }
+
+       arrivalOrderMap := &sync.Map{}
+       for key, orders := range orderMap {
+               sort.Sort(sort.Reverse(common.OrderSlice(orders)))
+               arrivalOrderMap.Store(key, orders)
+       }
+       return arrivalOrderMap
+}
+
+func arrangeArrivalDelOrders(orders []*common.Order) *sync.Map {
+       arrivalDelOrderMap := &sync.Map{}
+       for _, order := range orders {
+               arrivalDelOrderMap.Store(order.Key(), order)
+       }
+       return arrivalDelOrderMap
+}
+
 // NewOrderBook create a new OrderBook object
 func NewOrderBook(movStore database.MovStore, arrivalAddOrders, arrivalDelOrders []*common.Order) *OrderBook {
        return &OrderBook{
@@ -35,7 +57,8 @@ func NewOrderBook(movStore database.MovStore, arrivalAddOrders, arrivalDelOrders
        }
 }
 
-// AddOrder add the in memory temp order to order table
+// AddOrder add the in memory temp order to order table, because temp order is what left for the
+// partial trade order, so the price should be lowest.
 func (o *OrderBook) AddOrder(order *common.Order) error {
        tradePairKey := order.TradePair().Key()
        orders := o.getArrivalAddOrders(tradePairKey)
@@ -48,6 +71,11 @@ func (o *OrderBook) AddOrder(order *common.Order) error {
        return nil
 }
 
+// DelOrder mark the order has been deleted in order book
+func (o *OrderBook) DelOrder(order *common.Order) {
+       o.arrivalDelOrders.Store(order.Key(), order)
+}
+
 // PeekOrder return the next lowest order of given trade pair
 func (o *OrderBook) PeekOrder(tradePair *common.TradePair) *common.Order {
        if len(o.getDBOrders(tradePair.Key())) == 0 {
@@ -95,12 +123,13 @@ func (o *OrderBook) PopOrder(tradePair *common.TradePair) {
 
        orders := o.getDBOrders(tradePair.Key())
        if len(orders) != 0 && orders[len(orders)-1].Key() == order.Key() {
-               o.dbOrders.Store(tradePair.Key(), orders[0 : len(orders)-1])
+               o.dbOrders.Store(tradePair.Key(), orders[0:len(orders)-1])
+               return
        }
 
        arrivalOrders := o.getArrivalAddOrders(tradePair.Key())
        if len(arrivalOrders) != 0 && arrivalOrders[len(arrivalOrders)-1].Key() == order.Key() {
-               o.arrivalAddOrders.Store(tradePair.Key(), arrivalOrders[0 : len(arrivalOrders)-1])
+               o.arrivalAddOrders.Store(tradePair.Key(), arrivalOrders[0:len(arrivalOrders)-1])
        }
 }
 
@@ -134,29 +163,6 @@ func (o *OrderBook) getArrivalDelOrders(orderKey string) *common.Order {
        return nil
 }
 
-func arrangeArrivalAddOrders(orders []*common.Order) *sync.Map {
-       orderMap := make(map[string][]*common.Order)
-       for _, order := range orders {
-               orderMap[order.TradePair().Key()] = append(orderMap[order.TradePair().Key()], order)
-       }
-
-       arrivalOrderMap := &sync.Map{}
-       for key, orders := range orderMap {
-               sort.Sort(sort.Reverse(common.OrderSlice(orders)))
-               arrivalOrderMap.Store(key, orders)
-
-       }
-       return arrivalOrderMap
-}
-
-func arrangeArrivalDelOrders(orders []*common.Order) *sync.Map {
-       arrivalDelOrderMap := &sync.Map{}
-       for _, order := range orders {
-               arrivalDelOrderMap.Store(order.Key(), order)
-       }
-       return arrivalDelOrderMap
-}
-
 func (o *OrderBook) extendDBOrders(tradePair *common.TradePair) {
        iterator, ok := o.orderIterators.Load(tradePair.Key())
        if !ok {
@@ -173,8 +179,23 @@ func (o *OrderBook) extendDBOrders(tradePair *common.TradePair) {
 }
 
 func (o *OrderBook) peekArrivalOrder(tradePair *common.TradePair) *common.Order {
-       if arrivalAddOrders := o.getArrivalAddOrders(tradePair.Key()); len(arrivalAddOrders) > 0 {
-               return arrivalAddOrders[len(arrivalAddOrders)-1]
+       orders := o.getArrivalAddOrders(tradePair.Key())
+       delPos := len(orders)
+       for i := delPos - 1; i >= 0; i-- {
+               if o.getArrivalDelOrders(orders[i].Key()) != nil {
+                       delPos = i
+               } else {
+                       break
+               }
+       }
+
+       if delPos < len(orders) {
+               orders = orders[:delPos]
+               o.arrivalAddOrders.Store(tradePair.Key(), orders)
+       }
+
+       if size := len(orders); size > 0 {
+               return orders[size-1]
        }
        return nil
 }
index e401970..466a953 100644 (file)
@@ -6,6 +6,7 @@ import (
        "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/testutil"
 )
 
 var (
@@ -188,8 +189,114 @@ func TestOrderBook(t *testing.T) {
                        }
 
                        if gotOrder.Key() != wantOrder.Key() {
-                               t.Errorf("#%d(%s):the key of got order(%v) is not equals key of want order(%v)", i, c.desc, gotOrder, wantOrder)
+                               t.Fatalf("#%d(%s):the key of got order(%v) is not equals key of want order(%v)", i, c.desc, gotOrder, wantOrder)
                        }
                }
        }
 }
+
+func TestPeekArrivalOrder(t *testing.T) {
+       cases := []struct {
+               desc                 string
+               initArrivalAddOrders []*common.Order
+               initArrivalDelOrders []*common.Order
+               peekTradePair        *common.TradePair
+               wantArrivalAddOrders []*common.Order
+               wantOrder            *common.Order
+       }{
+               {
+                       desc:                 "empty peek",
+                       initArrivalAddOrders: []*common.Order{},
+                       initArrivalDelOrders: []*common.Order{},
+                       peekTradePair:        btc2eth,
+                       wantArrivalAddOrders: []*common.Order{},
+                       wantOrder:            nil,
+               },
+               {
+                       desc:                 "1 element regular peek",
+                       initArrivalAddOrders: []*common.Order{mock.Btc2EthOrders[0]},
+                       initArrivalDelOrders: []*common.Order{},
+                       peekTradePair:        btc2eth,
+                       wantArrivalAddOrders: []*common.Order{mock.Btc2EthOrders[0]},
+                       wantOrder:            mock.Btc2EthOrders[0],
+               },
+               {
+                       desc: "4 element regular peek with",
+                       initArrivalAddOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Btc2EthOrders[2], mock.Btc2EthOrders[3],
+                       },
+                       initArrivalDelOrders: []*common.Order{},
+                       peekTradePair:        btc2eth,
+                       wantArrivalAddOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Btc2EthOrders[2], mock.Btc2EthOrders[3],
+                       },
+                       wantOrder: mock.Btc2EthOrders[3],
+               },
+               {
+                       desc:                 "1 element peek with 1 unrelated deleted order",
+                       initArrivalAddOrders: []*common.Order{mock.Btc2EthOrders[0]},
+                       initArrivalDelOrders: []*common.Order{mock.Btc2EthOrders[1]},
+                       peekTradePair:        btc2eth,
+                       wantArrivalAddOrders: []*common.Order{mock.Btc2EthOrders[0]},
+                       wantOrder:            mock.Btc2EthOrders[0],
+               },
+               {
+                       desc:                 "1 element peek with 1 related deleted order",
+                       initArrivalAddOrders: []*common.Order{mock.Btc2EthOrders[0]},
+                       initArrivalDelOrders: []*common.Order{mock.Btc2EthOrders[0]},
+                       peekTradePair:        btc2eth,
+                       wantArrivalAddOrders: []*common.Order{},
+                       wantOrder:            nil,
+               },
+               {
+                       desc: "4 element peek with first 3 deleted order",
+                       initArrivalAddOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Btc2EthOrders[2], mock.Btc2EthOrders[3],
+                       },
+                       initArrivalDelOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[2], mock.Btc2EthOrders[3],
+                       },
+                       peekTradePair:        btc2eth,
+                       wantArrivalAddOrders: []*common.Order{mock.Btc2EthOrders[1]},
+                       wantOrder:            mock.Btc2EthOrders[1],
+               },
+               {
+                       desc: "4 element peek with first 1 deleted order",
+                       initArrivalAddOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Btc2EthOrders[2], mock.Btc2EthOrders[3],
+                       },
+                       initArrivalDelOrders: []*common.Order{mock.Btc2EthOrders[3]},
+                       peekTradePair:        btc2eth,
+                       wantArrivalAddOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Btc2EthOrders[2],
+                       },
+                       wantOrder: mock.Btc2EthOrders[0],
+               },
+               {
+                       desc: "4 element peek with first 2th deleted order",
+                       initArrivalAddOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Btc2EthOrders[2], mock.Btc2EthOrders[3],
+                       },
+                       initArrivalDelOrders: []*common.Order{mock.Btc2EthOrders[0]},
+                       peekTradePair:        btc2eth,
+                       wantArrivalAddOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1], mock.Btc2EthOrders[2], mock.Btc2EthOrders[3],
+                       },
+                       wantOrder: mock.Btc2EthOrders[3],
+               },
+       }
+
+       for i, c := range cases {
+               orderBook := NewOrderBook(mock.NewMovStore(nil, nil), c.initArrivalAddOrders, c.initArrivalDelOrders)
+               gotOrder := orderBook.PeekOrder(c.peekTradePair)
+               if !testutil.DeepEqual(gotOrder, c.wantOrder) {
+                       t.Fatalf("#%d(%s):the key of got order(%v) is not equals key of want order(%v)", i, c.desc, gotOrder, c.wantOrder)
+               }
+
+               wantAddOrders, _ := arrangeArrivalAddOrders(c.wantArrivalAddOrders).Load(c.peekTradePair.Key())
+               gotAddOrders := orderBook.getArrivalAddOrders(c.peekTradePair.Key())
+               if !testutil.DeepEqual(gotAddOrders, wantAddOrders) {
+                       t.Fatalf("#%d(%s): the got arrivalAddOrders(%v) is differnt than want arrivalAddOrders(%v)", i, c.desc, gotAddOrders, wantAddOrders)
+               }
+       }
+}
index e46dd50..1081be3 100644 (file)
@@ -16,11 +16,11 @@ type matchCollector struct {
        gasLeft           int64
        isTimeout         func() bool
 
-       workerNum   int
-       workerNumCh chan int
-       processCh   chan *matchTxResult
-       tradePairCh chan *common.TradePair
-       closeCh     chan struct{}
+       workerNum     int
+       endWorkCh     chan int
+       tradePairCh   chan *common.TradePair
+       matchResultCh chan *matchTxResult
+       closeCh       chan struct{}
 }
 
 type matchTxResult struct {
@@ -33,13 +33,13 @@ func newMatchTxCollector(engine *match.Engine, iterator *database.TradePairItera
        return &matchCollector{
                engine:            engine,
                tradePairIterator: iterator,
+               gasLeft:           gasLeft,
+               isTimeout:         isTimeout,
                workerNum:         workerNum,
-               workerNumCh:       make(chan int, workerNum),
-               processCh:         make(chan *matchTxResult),
+               endWorkCh:         make(chan int, workerNum),
                tradePairCh:       make(chan *common.TradePair, workerNum),
+               matchResultCh:     make(chan *matchTxResult),
                closeCh:           make(chan struct{}),
-               gasLeft:           gasLeft,
-               isTimeout:         isTimeout,
        }
 }
 
@@ -63,10 +63,9 @@ func (m *matchCollector) collect() ([]*types.Tx, error) {
        defer close(m.closeCh)
 
        var matchedTxs []*types.Tx
-       completed := 0
-       for !m.isTimeout() {
+       for completed := 0; !m.isTimeout(); {
                select {
-               case data := <-m.processCh:
+               case data := <-m.matchResultCh:
                        if data.err != nil {
                                return nil, data.err
                        }
@@ -77,7 +76,7 @@ func (m *matchCollector) collect() ([]*types.Tx, error) {
                        } else {
                                return matchedTxs, nil
                        }
-               case <-m.workerNumCh:
+               case <-m.endWorkCh:
                        if completed++; completed == m.workerNum {
                                return matchedTxs, nil
                        }
@@ -113,7 +112,7 @@ func (m *matchCollector) tradePairProducer(wg *sync.WaitGroup) {
 
 func (m *matchCollector) matchTxWorker(wg *sync.WaitGroup) {
        defer func() {
-               m.workerNumCh <- 1
+               m.endWorkCh <- 1
                wg.Done()
        }()
 
@@ -122,22 +121,26 @@ func (m *matchCollector) matchTxWorker(wg *sync.WaitGroup) {
                case <-m.closeCh:
                        return
                case tradePair := <-m.tradePairCh:
+                       // end worker due to all trade pair has been matched
                        if tradePair == nil {
                                return
                        }
+
                        for m.engine.HasMatchedTx(tradePair, tradePair.Reverse()) {
                                matchedTx, err := m.engine.NextMatchedTx(tradePair, tradePair.Reverse())
-                               data := &matchTxResult{matchedTx: matchedTx, err: err}
                                select {
                                case <-m.closeCh:
                                        return
-                               case m.processCh <- data:
-                                       if data.err != nil {
+                               case m.matchResultCh <- &matchTxResult{matchedTx: matchedTx, err: err}:
+                                       if err != nil {
                                                return
                                        }
                                }
                        }
                }
-
        }
 }
+
+func calcMatchedTxGasUsed(tx *types.Tx) int64 {
+       return int64(len(tx.Inputs))*150 + int64(tx.SerializedSize)
+}
index 4c6788c..835a7c9 100644 (file)
@@ -329,6 +329,20 @@ var (
                                types.NewIntraChainOutput(BTC, 10, testutil.MustDecodeHexString("00144d0dfc8a0c5ce41d31d4f61d99aff70588bff8bc")),
                        },
                }),
+
+               // partial matched transaction from MatchedTxs[4], Eth2BtcMakerTxs[0]
+               types.NewTx(types.TxData{
+                       Inputs: []*types.TxInput{
+                               types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, testutil.MustDecodeHash("ed810e1672c3b9de27a1db23e017e6b9cc23334b6e3dbd25dfe8857e289b7f06"), *Btc2EthOrders[0].FromAssetID, 2, 1, Btc2EthOrders[0].Utxo.ControlProgram),
+                               types.NewSpendInput([][]byte{vm.Int64Bytes(1), vm.Int64Bytes(1)}, *MustNewOrderFromOutput(Eth2BtcMakerTxs[0], 0).Utxo.SourceID, *Eth2BtcOrders[0].FromAssetID, Eth2BtcOrders[0].Utxo.Amount, 0, Eth2BtcOrders[0].Utxo.ControlProgram),
+                       },
+                       Outputs: []*types.TxOutput{
+                               types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 100, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251")),
+                               types.NewIntraChainOutput(*Eth2BtcOrders[0].ToAssetID, 2, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19253")),
+                               // re-order
+                               types.NewIntraChainOutput(*Eth2BtcOrders[0].FromAssetID, 404, Eth2BtcOrders[0].Utxo.ControlProgram),
+                       },
+               }),
        }
 )
 
index c80113f..f9b1292 100644 (file)
@@ -53,15 +53,13 @@ func (m *MovCore) ApplyBlock(block *types.Block) error {
                if err := m.movStore.InitDBState(block.Height, &blockHash); err != nil {
                        return err
                }
-
-               return nil
        }
 
        if err := m.validateMatchedTxSequence(block.Transactions); err != nil {
                return err
        }
 
-       addOrders, deleteOrders, err := applyTransactions(block.Transactions)
+       addOrders, deleteOrders, err := decodeTxsOrders(block.Transactions)
        if err != nil {
                return err
        }
@@ -99,11 +97,11 @@ func (m *MovCore) ChainStatus() (uint64, *bc.Hash, error) {
 // DetachBlock parse pending order and cancel from the the transactions of block
 // and add cancel order to the dex db, remove pending order from dex db.
 func (m *MovCore) DetachBlock(block *types.Block) error {
-       if block.Height <= m.startBlockHeight {
+       if block.Height < m.startBlockHeight {
                return nil
        }
 
-       deleteOrders, addOrders, err := applyTransactions(block.Transactions)
+       deleteOrders, addOrders, err := decodeTxsOrders(block.Transactions)
        if err != nil {
                return err
        }
@@ -147,15 +145,13 @@ func (m *MovCore) ValidateTxs(txs []*types.Tx, verifyResults []*bc.TxVerifyResul
        return nil
 }
 
-// ValidateTxs validate one transaction.
+// ValidateTx validate one transaction.
 func (m *MovCore) ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) error {
        if common.IsMatchedTx(tx) {
                if err := validateMatchedTx(tx, verifyResult); err != nil {
                        return err
                }
-       }
-
-       if common.IsCancelOrderTx(tx) {
+       } else if common.IsCancelOrderTx(tx) {
                if err := validateCancelOrderTx(tx, verifyResult); err != nil {
                        return err
                }
@@ -260,49 +256,37 @@ func validateMatchedTxFeeAmount(tx *types.Tx) error {
 }
 
 func (m *MovCore) validateMatchedTxSequence(txs []*types.Tx) error {
-       var matchedTxs []*types.Tx
+       orderBook := match.NewOrderBook(m.movStore, nil, nil)
        for _, tx := range txs {
                if common.IsMatchedTx(tx) {
-                       matchedTxs = append(matchedTxs, tx)
-               }
-       }
-
-       if len(matchedTxs) == 0 {
-               return nil
-       }
+                       tradePairs, err := getTradePairsFromMatchedTx(tx)
+                       if err != nil {
+                               return err
+                       }
 
-       orderBook, err := buildOrderBook(m.movStore, txs)
-       if err != nil {
-               return err
-       }
+                       orders := orderBook.PeekOrders(tradePairs)
+                       if err := validateSpendOrders(tx, orders); err != nil {
+                               return err
+                       }
 
-       for _, matchedTx := range matchedTxs {
-               tradePairs, err := getTradePairsFromMatchedTx(matchedTx)
-               if err != nil {
-                       return err
-               }
+                       orderBook.PopOrders(tradePairs)
+               } else if common.IsCancelOrderTx(tx) {
+                       orders, err := getDeleteOrdersFromTx(tx)
+                       if err != nil {
+                               return err
+                       }
 
-               orders := orderBook.PeekOrders(tradePairs)
-               if !match.IsMatched(orders) {
-                       return errNotMatchedOrder
+                       for _, order := range orders {
+                               orderBook.DelOrder(order)
+                       }
                }
 
-               if err := validateSpendOrders(matchedTx, orders); err != nil {
+               addOrders, err := getAddOrdersFromTx(tx)
+               if err != nil {
                        return err
                }
 
-               orderBook.PopOrders(tradePairs)
-
-               for i, output := range matchedTx.Outputs {
-                       if !segwit.IsP2WMCScript(output.ControlProgram()) {
-                               continue
-                       }
-
-                       order, err := common.NewOrderFromOutput(matchedTx, i)
-                       if err != nil {
-                               return err
-                       }
-
+               for _, order := range addOrders {
                        if err := orderBook.AddOrder(order); err != nil {
                                return err
                        }
@@ -311,9 +295,13 @@ func (m *MovCore) validateMatchedTxSequence(txs []*types.Tx) error {
        return nil
 }
 
-func validateSpendOrders(matchedTx *types.Tx, orders []*common.Order) error {
+func validateSpendOrders(tx *types.Tx, orders []*common.Order) error {
+       if len(tx.Inputs) != len(orders) {
+               return errNotMatchedOrder
+       }
+
        spendOutputIDs := make(map[string]bool)
-       for _, input := range matchedTx.Inputs {
+       for _, input := range tx.Inputs {
                spendOutputID, err := input.SpentOutputID()
                if err != nil {
                        return err
@@ -331,7 +319,7 @@ func validateSpendOrders(matchedTx *types.Tx, orders []*common.Order) error {
        return nil
 }
 
-func applyTransactions(txs []*types.Tx) ([]*common.Order, []*common.Order, error) {
+func decodeTxsOrders(txs []*types.Tx) ([]*common.Order, []*common.Order, error) {
        deleteOrderMap := make(map[string]*common.Order)
        addOrderMap := make(map[string]*common.Order)
        for _, tx := range txs {
@@ -385,10 +373,6 @@ func buildOrderBook(store database.MovStore, txs []*types.Tx) (*match.OrderBook,
        return match.NewOrderBook(store, arrivalAddOrders, arrivalDelOrders), nil
 }
 
-func calcMatchedTxGasUsed(tx *types.Tx) int64 {
-       return int64(len(tx.Inputs))*150 + int64(tx.SerializedSize)
-}
-
 func getAddOrdersFromTx(tx *types.Tx) ([]*common.Order, error) {
        var orders []*common.Order
        for i, output := range tx.Outputs {
index 54a6f7e..9c0b354 100644 (file)
@@ -121,11 +121,11 @@ func TestApplyBlock(t *testing.T) {
                                Transactions: []*types.Tx{
                                        mock.Eos2EtcMakerTxs[0],
                                        mock.Btc2EthMakerTxs[0],
+                                       mock.Eth2BtcMakerTxs[1],
                                        mock.MatchedTxs[4],
                                        mock.Eth2EosMakerTxs[0],
-                                       mock.Eth2BtcMakerTxs[1],
-                                       mock.MatchedTxs[5],
                                        mock.Etc2EosMakerTxs[0],
+                                       mock.MatchedTxs[5],
                                },
                        },
                        blockFunc:  applyBlock,
@@ -137,6 +137,23 @@ func TestApplyBlock(t *testing.T) {
                        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,
index 6a115a7..4a8273f 100644 (file)
@@ -94,6 +94,7 @@ func (b *blockBuilder) applyCoinbaseTransaction() error {
        b.gasLeft -= gasState.GasUsed
        return nil
 }
+
 func (b *blockBuilder) applyTransactions(txs []*types.Tx, timeoutStatus uint8) error {
        tempTxs := []*types.Tx{}
        for i := 0; i < len(txs); i++ {
@@ -258,6 +259,7 @@ func createCoinbaseTxByReward(accountManager *account.Manager, blockHeight uint6
        if err = builder.AddInput(types.NewCoinbaseInput(arbitrary), &txbuilder.SigningInstruction{}); err != nil {
                return nil, err
        }
+
        if err = builder.AddOutput(types.NewIntraChainOutput(*consensus.BTMAssetID, 0, script)); err != nil {
                return nil, err
        }
@@ -294,7 +296,6 @@ type validateTxResult struct {
 
 func preValidateTxs(txs []*types.Tx, chain *protocol.Chain, view *state.UtxoViewpoint, gasLeft int64) ([]*validateTxResult, int64) {
        var results []*validateTxResult
-
        bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: chain.BestBlockHeight() + 1}}
        bcTxs := make([]*bc.Tx, len(txs))
        for i, tx := range txs {