OSDN Git Service

Merge pull request #473 from Bytom/master
[bytom/vapor.git] / application / mov / match / match_test.go
1 package match
2
3 import (
4         "testing"
5
6         "github.com/bytom/vapor/application/mov/common"
7         "github.com/bytom/vapor/application/mov/mock"
8         "github.com/bytom/vapor/protocol/bc"
9         "github.com/bytom/vapor/protocol/bc/types"
10         "github.com/bytom/vapor/protocol/validation"
11         "github.com/bytom/vapor/testutil"
12 )
13
14 func TestGenerateMatchedTxs(t *testing.T) {
15         btc2eth := &common.TradePair{FromAssetID: &mock.BTC, ToAssetID: &mock.ETH}
16         eth2btc := &common.TradePair{FromAssetID: &mock.ETH, ToAssetID: &mock.BTC}
17         eth2eos := &common.TradePair{FromAssetID: &mock.ETH, ToAssetID: &mock.EOS}
18         eos2btc := &common.TradePair{FromAssetID: &mock.EOS, ToAssetID: &mock.BTC}
19
20         cases := []struct {
21                 desc            string
22                 tradePairs      []*common.TradePair
23                 initStoreOrders []*common.Order
24                 wantMatchedTxs  []*types.Tx
25         }{
26                 {
27                         desc:       "full matched",
28                         tradePairs: []*common.TradePair{btc2eth, eth2btc},
29                         initStoreOrders: []*common.Order{
30                                 mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
31                                 mock.Eth2BtcOrders[0],
32                         },
33                         wantMatchedTxs: []*types.Tx{
34                                 mock.MatchedTxs[1],
35                         },
36                 },
37                 {
38                         desc:       "partial matched",
39                         tradePairs: []*common.TradePair{btc2eth, eth2btc},
40                         initStoreOrders: []*common.Order{
41                                 mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
42                                 mock.Eth2BtcOrders[1],
43                         },
44                         wantMatchedTxs: []*types.Tx{
45                                 mock.MatchedTxs[0],
46                         },
47                 },
48                 {
49                         desc:       "partial matched and continue to match",
50                         tradePairs: []*common.TradePair{btc2eth, eth2btc},
51                         initStoreOrders: []*common.Order{
52                                 mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
53                                 mock.Eth2BtcOrders[2],
54                         },
55                         wantMatchedTxs: []*types.Tx{
56                                 mock.MatchedTxs[2],
57                                 mock.MatchedTxs[3],
58                         },
59                 },
60                 {
61                         desc:       "unable to match",
62                         tradePairs: []*common.TradePair{btc2eth, eth2btc},
63                         initStoreOrders: []*common.Order{
64                                 mock.Btc2EthOrders[1],
65                                 mock.Eth2BtcOrders[0],
66                         },
67                         wantMatchedTxs: []*types.Tx{},
68                 },
69                 {
70                         desc:       "cycle match",
71                         tradePairs: []*common.TradePair{btc2eth, eth2eos, eos2btc},
72                         initStoreOrders: []*common.Order{
73                                 mock.Btc2EthOrders[0], mock.Eth2EosOrders[0], mock.Eos2BtcOrders[0],
74                         },
75                         wantMatchedTxs: []*types.Tx{
76                                 mock.MatchedTxs[6],
77                         },
78                 },
79         }
80
81         for i, c := range cases {
82                 movStore := mock.NewMovStore([]*common.TradePair{btc2eth, eth2btc}, c.initStoreOrders)
83                 matchEngine := NewEngine(NewOrderBook(movStore, nil, nil), 0.05, mock.NodeProgram)
84                 var gotMatchedTxs []*types.Tx
85                 for matchEngine.HasMatchedTx(c.tradePairs...) {
86                         matchedTx, err := matchEngine.NextMatchedTx(c.tradePairs...)
87                         if err != nil {
88                                 t.Fatal(err)
89                         }
90
91                         gotMatchedTxs = append(gotMatchedTxs, matchedTx)
92                 }
93
94                 if len(c.wantMatchedTxs) != len(gotMatchedTxs) {
95                         t.Errorf("#%d(%s) the length of got matched tx is not equals want matched tx", i, c.desc)
96                         continue
97                 }
98
99                 for i, gotMatchedTx := range gotMatchedTxs {
100                         if _, err := validation.ValidateTx(gotMatchedTx.Tx, &bc.Block{BlockHeader: &bc.BlockHeader{Version: 1}}); err != nil {
101                                 t.Fatal(err)
102                         }
103
104                         c.wantMatchedTxs[i].Version = 1
105                         byteData, err := c.wantMatchedTxs[i].MarshalText()
106                         if err != nil {
107                                 t.Fatal(err)
108                         }
109
110                         c.wantMatchedTxs[i].SerializedSize = uint64(len(byteData))
111                         wantMatchedTx := types.NewTx(c.wantMatchedTxs[i].TxData)
112                         if gotMatchedTx.ID != wantMatchedTx.ID {
113                                 t.Errorf("#%d(%s) the tx hash of got matched tx: %s is not equals want matched tx: %s", i, c.desc, gotMatchedTx.ID.String(), wantMatchedTx.ID.String())
114                         }
115                 }
116         }
117 }
118
119 func TestCalcMatchedTxFee(t *testing.T) {
120         cases := []struct {
121                 desc             string
122                 tx               *types.TxData
123                 maxFeeRate       float64
124                 wantMatchedTxFee map[bc.AssetID]*MatchedTxFee
125         }{
126                 {
127                         desc:             "fee less than max fee",
128                         maxFeeRate:       0.05,
129                         wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{mock.ETH: {FeeAmount: 10, MaxFeeAmount: 26}},
130                         tx:               &mock.MatchedTxs[1].TxData,
131                 },
132                 {
133                         desc:             "fee refund in tx",
134                         maxFeeRate:       0.05,
135                         wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{mock.ETH: {FeeAmount: 27, MaxFeeAmount: 27}},
136                         tx:               &mock.MatchedTxs[2].TxData,
137                 },
138                 {
139                         desc:             "fee is zero",
140                         maxFeeRate:       0.05,
141                         wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{},
142                         tx:               &mock.MatchedTxs[0].TxData,
143                 },
144         }
145
146         for i, c := range cases {
147                 gotMatchedTxFee, err := CalcMatchedTxFee(c.tx, c.maxFeeRate)
148                 if err != nil {
149                         t.Fatal(err)
150                 }
151
152                 if !testutil.DeepEqual(gotMatchedTxFee, c.wantMatchedTxFee) {
153                         t.Errorf("#%d(%s):fail to caculate matched tx fee, got (%v), want (%v)", i, c.desc, gotMatchedTxFee, c.wantMatchedTxFee)
154                 }
155         }
156 }
157
158 func TestValidateTradePairs(t *testing.T) {
159         cases := []struct {
160                 desc       string
161                 tradePairs []*common.TradePair
162                 wantError  bool
163         }{
164                 {
165                         desc: "valid case of two trade pairs",
166                         tradePairs: []*common.TradePair{
167                                 {
168                                         FromAssetID: &mock.BTC,
169                                         ToAssetID:   &mock.ETH,
170                                 },
171                                 {
172                                         FromAssetID: &mock.ETH,
173                                         ToAssetID:   &mock.BTC,
174                                 },
175                         },
176                         wantError: false,
177                 },
178                 {
179                         desc: "invalid case of two trade pairs",
180                         tradePairs: []*common.TradePair{
181                                 {
182                                         FromAssetID: &mock.BTC,
183                                         ToAssetID:   &mock.ETH,
184                                 },
185                                 {
186                                         FromAssetID: &mock.ETH,
187                                         ToAssetID:   &mock.EOS,
188                                 },
189                         },
190                         wantError: true,
191                 },
192                 {
193                         desc: "valid case of three trade pairs",
194                         tradePairs: []*common.TradePair{
195                                 {
196                                         FromAssetID: &mock.BTC,
197                                         ToAssetID:   &mock.ETH,
198                                 },
199                                 {
200                                         FromAssetID: &mock.ETH,
201                                         ToAssetID:   &mock.EOS,
202                                 },
203                                 {
204                                         FromAssetID: &mock.EOS,
205                                         ToAssetID:   &mock.BTC,
206                                 },
207                         },
208                         wantError: false,
209                 },
210                 {
211                         desc: "invalid case of three trade pairs",
212                         tradePairs: []*common.TradePair{
213                                 {
214                                         FromAssetID: &mock.BTC,
215                                         ToAssetID:   &mock.ETH,
216                                 },
217                                 {
218                                         FromAssetID: &mock.ETH,
219                                         ToAssetID:   &mock.BTC,
220                                 },
221                                 {
222                                         FromAssetID: &mock.BTC,
223                                         ToAssetID:   &mock.BTC,
224                                 },
225                         },
226                         wantError: true,
227                 },
228                 {
229                         desc: "valid case 2 of three trade pairs",
230                         tradePairs: []*common.TradePair{
231                                 {
232                                         FromAssetID: &mock.BTC,
233                                         ToAssetID:   &mock.ETH,
234                                 },
235                                 {
236                                         FromAssetID: &mock.EOS,
237                                         ToAssetID:   &mock.BTC,
238                                 },
239                                 {
240                                         FromAssetID: &mock.ETH,
241                                         ToAssetID:   &mock.EOS,
242                                 },
243                         },
244                         wantError: false,
245                 },
246         }
247
248         for i, c := range cases {
249                 err := validateTradePairs(c.tradePairs)
250                 if c.wantError && err == nil {
251                         t.Errorf("#%d(%s): want error, got no error", i, c.desc)
252                 }
253
254                 if !c.wantError && err != nil {
255                         t.Errorf("#%d(%s): want no error, got error (%v)", i, c.desc, err)
256                 }
257         }
258 }