OSDN Git Service

opt mov validate match tx (#470)
[bytom/vapor.git] / application / mov / match / match.go
index f506cf7..4c0234f 100644 (file)
@@ -34,12 +34,12 @@ func (e *Engine) HasMatchedTx(tradePairs ...*common.TradePair) bool {
                return false
        }
 
-       orders := e.peekOrders(tradePairs)
+       orders := e.orderBook.PeekOrders(tradePairs)
        if len(orders) == 0 {
                return false
        }
 
-       return isMatched(orders)
+       return IsMatched(orders)
 }
 
 // NextMatchedTx return the next matchable transaction by the specified trade pairs
@@ -50,7 +50,7 @@ func (e *Engine) NextMatchedTx(tradePairs ...*common.TradePair) (*types.Tx, erro
                return nil, errors.New("the specified trade pairs can not be matched")
        }
 
-       tx, err := e.buildMatchTx(e.peekOrders(tradePairs))
+       tx, err := e.buildMatchTx(sortOrders(e.orderBook.PeekOrders(tradePairs)))
        if err != nil {
                return nil, err
        }
@@ -145,19 +145,6 @@ func (e *Engine) buildMatchTx(orders []*common.Order) (*types.Tx, error) {
        return types.NewTx(*txData), nil
 }
 
-func (e *Engine) peekOrders(tradePairs []*common.TradePair) []*common.Order {
-       var orders []*common.Order
-       for _, tradePair := range tradePairs {
-               order := e.orderBook.PeekOrder(tradePair)
-               if order == nil {
-                       return nil
-               }
-
-               orders = append(orders, order)
-       }
-       return orders
-}
-
 // MatchedTxFee is object to record the mov tx's fee information
 type MatchedTxFee struct {
        MaxFeeAmount int64
@@ -247,13 +234,26 @@ func calcOppositeIndex(size int, selfIdx int) int {
        return (selfIdx + 1) % size
 }
 
-func isMatched(orders []*common.Order) bool {
-       rate := orders[0].Rate
-       oppositeRate := 1.0
-       for i := 1; i < len(orders); i++ {
-               oppositeRate *= orders[i].Rate
+func IsMatched(orders []*common.Order) bool {
+       sortedOrders := sortOrders(orders)
+       if len(sortedOrders) == 0 {
+               return false
+       }
+
+       rate := orderRatio(sortedOrders[0])
+       oppositeRate := big.NewFloat(0).SetInt64(1)
+       for i := 1; i < len(sortedOrders); i++ {
+               oppositeRate.Mul(oppositeRate, orderRatio(sortedOrders[i]))
        }
-       return 1/rate >= oppositeRate
+
+       one := big.NewFloat(0).SetInt64(1)
+       return one.Quo(one, rate).Cmp(oppositeRate) >= 0
+}
+
+func orderRatio(order *common.Order) *big.Float {
+       ratio := big.NewFloat(0).SetInt64(order.RatioNumerator)
+       ratio.Quo(ratio, big.NewFloat(0).SetInt64(order.RatioDenominator))
+       return ratio
 }
 
 func setMatchTxArguments(txInput *types.TxInput, isPartialTrade bool, position int, receiveAmounts uint64) {
@@ -271,15 +271,40 @@ func validateTradePairs(tradePairs []*common.TradePair) error {
                return errors.New("size of trade pairs at least 2")
        }
 
-       for i, tradePair := range tradePairs {
+       assetMap := make(map[string]bool)
+       for _, tradePair := range tradePairs {
+               assetMap[tradePair.FromAssetID.String()] = true
                if *tradePair.FromAssetID == *tradePair.ToAssetID {
                        return errors.New("from asset id can't equal to asset id")
                }
+       }
 
-               oppositeTradePair := tradePairs[calcOppositeIndex(len(tradePairs), i)]
-               if *tradePair.ToAssetID != *oppositeTradePair.FromAssetID {
-                       return errors.New("specified trade pairs is invalid")
+       for _, tradePair := range tradePairs {
+               key := tradePair.ToAssetID.String()
+               if _, ok := assetMap[key]; !ok {
+                       return errors.New("invalid trade pairs")
                }
+               delete(assetMap, key)
        }
        return nil
 }
+
+func sortOrders(orders []*common.Order) []*common.Order {
+       orderMap := make(map[bc.AssetID]*common.Order)
+       firstOrder := orders[0]
+       for i := 1; i < len(orders); i++ {
+               orderMap[*orders[i].FromAssetID] = orders[i]
+       }
+
+       sortedOrders := []*common.Order{firstOrder}
+       for order := firstOrder; *order.ToAssetID != *firstOrder.FromAssetID; {
+               nextOrder, ok := orderMap[*order.ToAssetID]
+               if !ok {
+                       return nil
+               }
+
+               sortedOrders = append(sortedOrders, nextOrder)
+               order = nextOrder
+       }
+       return sortedOrders
+}