OSDN Git Service

fix decimal (#479)
[bytom/vapor.git] / application / mov / match / match_test.go
index 52fc53a..7d013ec 100644 (file)
@@ -3,27 +3,29 @@ package match
 import (
        "testing"
 
-       "github.com/vapor/protocol/bc"
-       "github.com/vapor/testutil"
-
-       "github.com/vapor/application/mov/common"
-       "github.com/vapor/application/mov/mock"
-       "github.com/vapor/protocol/bc/types"
+       "github.com/bytom/vapor/application/mov/common"
+       "github.com/bytom/vapor/application/mov/mock"
+       "github.com/bytom/vapor/protocol/bc"
+       "github.com/bytom/vapor/protocol/bc/types"
+       "github.com/bytom/vapor/protocol/validation"
+       "github.com/bytom/vapor/testutil"
 )
 
 func TestGenerateMatchedTxs(t *testing.T) {
        btc2eth := &common.TradePair{FromAssetID: &mock.BTC, ToAssetID: &mock.ETH}
        eth2btc := &common.TradePair{FromAssetID: &mock.ETH, ToAssetID: &mock.BTC}
+       eth2eos := &common.TradePair{FromAssetID: &mock.ETH, ToAssetID: &mock.EOS}
+       eos2btc := &common.TradePair{FromAssetID: &mock.EOS, ToAssetID: &mock.BTC}
 
        cases := []struct {
                desc            string
-               tradePair       *common.TradePair
+               tradePairs      []*common.TradePair
                initStoreOrders []*common.Order
                wantMatchedTxs  []*types.Tx
        }{
                {
-                       desc:      "full matched",
-                       tradePair: &common.TradePair{FromAssetID: &mock.BTC, ToAssetID: &mock.ETH},
+                       desc:       "full matched",
+                       tradePairs: []*common.TradePair{btc2eth, eth2btc},
                        initStoreOrders: []*common.Order{
                                mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
                                mock.Eth2BtcOrders[0],
@@ -33,8 +35,8 @@ func TestGenerateMatchedTxs(t *testing.T) {
                        },
                },
                {
-                       desc:      "partial matched",
-                       tradePair: &common.TradePair{FromAssetID: &mock.BTC, ToAssetID: &mock.ETH},
+                       desc:       "partial matched",
+                       tradePairs: []*common.TradePair{btc2eth, eth2btc},
                        initStoreOrders: []*common.Order{
                                mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
                                mock.Eth2BtcOrders[1],
@@ -44,8 +46,8 @@ func TestGenerateMatchedTxs(t *testing.T) {
                        },
                },
                {
-                       desc:      "partial matched and continue to match",
-                       tradePair: &common.TradePair{FromAssetID: &mock.BTC, ToAssetID: &mock.ETH},
+                       desc:       "partial matched and continue to match",
+                       tradePairs: []*common.TradePair{btc2eth, eth2btc},
                        initStoreOrders: []*common.Order{
                                mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
                                mock.Eth2BtcOrders[2],
@@ -56,22 +58,32 @@ func TestGenerateMatchedTxs(t *testing.T) {
                        },
                },
                {
-                       desc:      "unable to match",
-                       tradePair: &common.TradePair{FromAssetID: &mock.BTC, ToAssetID: &mock.ETH},
+                       desc:       "unable to match",
+                       tradePairs: []*common.TradePair{btc2eth, eth2btc},
                        initStoreOrders: []*common.Order{
                                mock.Btc2EthOrders[1],
                                mock.Eth2BtcOrders[0],
                        },
                        wantMatchedTxs: []*types.Tx{},
                },
+               {
+                       desc:       "cycle match",
+                       tradePairs: []*common.TradePair{btc2eth, eth2eos, eos2btc},
+                       initStoreOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Eth2EosOrders[0], mock.Eos2BtcOrders[0],
+                       },
+                       wantMatchedTxs: []*types.Tx{
+                               mock.MatchedTxs[6],
+                       },
+               },
        }
 
        for i, c := range cases {
                movStore := mock.NewMovStore([]*common.TradePair{btc2eth, eth2btc}, c.initStoreOrders)
-               matchEngine := NewEngine(NewOrderTable(movStore, nil, nil), 0.05, mock.NodeProgram)
+               matchEngine := NewEngine(NewOrderBook(movStore, nil, nil), 0.05, mock.NodeProgram)
                var gotMatchedTxs []*types.Tx
-               for matchEngine.HasMatchedTx(c.tradePair, c.tradePair.Reverse()) {
-                       matchedTx, err := matchEngine.NextMatchedTx(c.tradePair, c.tradePair.Reverse())
+               for matchEngine.HasMatchedTx(c.tradePairs...) {
+                       matchedTx, err := matchEngine.NextMatchedTx(c.tradePairs...)
                        if err != nil {
                                t.Fatal(err)
                        }
@@ -85,6 +97,10 @@ func TestGenerateMatchedTxs(t *testing.T) {
                }
 
                for i, gotMatchedTx := range gotMatchedTxs {
+                       if _, err := validation.ValidateTx(gotMatchedTx.Tx, &bc.Block{BlockHeader: &bc.BlockHeader{Version: 1}}); err != nil {
+                               t.Fatal(err)
+                       }
+
                        c.wantMatchedTxs[i].Version = 1
                        byteData, err := c.wantMatchedTxs[i].MarshalText()
                        if err != nil {
@@ -108,22 +124,22 @@ func TestCalcMatchedTxFee(t *testing.T) {
                wantMatchedTxFee map[bc.AssetID]*MatchedTxFee
        }{
                {
-                       desc: "fee less than max fee",
-                       maxFeeRate: 0.05,
+                       desc:             "fee less than max fee",
+                       maxFeeRate:       0.05,
                        wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{mock.ETH: {FeeAmount: 10, MaxFeeAmount: 26}},
-                       tx: &mock.MatchedTxs[1].TxData,
+                       tx:               &mock.MatchedTxs[1].TxData,
                },
                {
-                       desc: "fee refund in tx",
-                       maxFeeRate: 0.05,
+                       desc:             "fee refund in tx",
+                       maxFeeRate:       0.05,
                        wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{mock.ETH: {FeeAmount: 27, MaxFeeAmount: 27}},
-                       tx: &mock.MatchedTxs[2].TxData,
+                       tx:               &mock.MatchedTxs[2].TxData,
                },
                {
-                       desc: "fee is zero",
-                       maxFeeRate: 0.05,
+                       desc:             "fee is zero",
+                       maxFeeRate:       0.05,
                        wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{},
-                       tx: &mock.MatchedTxs[0].TxData,
+                       tx:               &mock.MatchedTxs[0].TxData,
                },
        }
 
@@ -138,3 +154,265 @@ func TestCalcMatchedTxFee(t *testing.T) {
                }
        }
 }
+
+func TestValidateTradePairs(t *testing.T) {
+       cases := []struct {
+               desc       string
+               tradePairs []*common.TradePair
+               wantError  bool
+       }{
+               {
+                       desc: "valid case of two trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                       },
+                       wantError: false,
+               },
+               {
+                       desc: "invalid case of two trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.EOS,
+                               },
+                       },
+                       wantError: true,
+               },
+               {
+                       desc: "valid case of three trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.EOS,
+                               },
+                               {
+                                       FromAssetID: &mock.EOS,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                       },
+                       wantError: false,
+               },
+               {
+                       desc: "invalid case of three trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                       },
+                       wantError: true,
+               },
+               {
+                       desc: "valid case 2 of three trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.EOS,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.EOS,
+                               },
+                       },
+                       wantError: false,
+               },
+       }
+
+       for i, c := range cases {
+               err := validateTradePairs(c.tradePairs)
+               if c.wantError && err == nil {
+                       t.Errorf("#%d(%s): want error, got no error", i, c.desc)
+               }
+
+               if !c.wantError && err != nil {
+                       t.Errorf("#%d(%s): want no error, got error (%v)", i, c.desc, err)
+               }
+       }
+}
+
+func TestIsMatched(t *testing.T) {
+       cases := []struct {
+               desc        string
+               orders      []*common.Order
+               wantMatched bool
+       }{
+               {
+                       desc: "ratio is equals",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   6250,
+                                       RatioDenominator: 3,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ratio is equals, and numerator and denominator are multiples of the opposite",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   6250,
+                                       RatioDenominator: 3,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   9,
+                                       RatioDenominator: 18750,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   62500000000000000,
+                                       RatioDenominator: 30000000000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "not matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   62500000000000001,
+                                       RatioDenominator: 30000000000000,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: false,
+               },
+               {
+                       desc: "ring matched",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000001,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ring matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000000,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ring fail matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000002,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: false,
+               },
+       }
+
+       for i, c := range cases {
+               gotMatched := IsMatched(c.orders)
+               if gotMatched != c.wantMatched {
+                       t.Errorf("#%d(%s) got matched:%v, want matched:%v", i, c.desc, gotMatched, c.wantMatched)
+               }
+       }
+}