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"
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}
22 tradePairs []*common.TradePair
23 initStoreOrders []*common.Order
24 wantMatchedTxs []*types.Tx
28 tradePairs: []*common.TradePair{btc2eth, eth2btc},
29 initStoreOrders: []*common.Order{
30 mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
31 mock.Eth2BtcOrders[0],
33 wantMatchedTxs: []*types.Tx{
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],
44 wantMatchedTxs: []*types.Tx{
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],
55 wantMatchedTxs: []*types.Tx{
61 desc: "unable to match",
62 tradePairs: []*common.TradePair{btc2eth, eth2btc},
63 initStoreOrders: []*common.Order{
64 mock.Btc2EthOrders[1],
65 mock.Eth2BtcOrders[0],
67 wantMatchedTxs: []*types.Tx{},
71 tradePairs: []*common.TradePair{btc2eth, eth2eos, eos2btc},
72 initStoreOrders: []*common.Order{
73 mock.Btc2EthOrders[0], mock.Eth2EosOrders[0], mock.Eos2BtcOrders[0],
75 wantMatchedTxs: []*types.Tx{
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...)
91 gotMatchedTxs = append(gotMatchedTxs, matchedTx)
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)
99 for i, gotMatchedTx := range gotMatchedTxs {
100 if _, err := validation.ValidateTx(gotMatchedTx.Tx, &bc.Block{BlockHeader: &bc.BlockHeader{Version: 1}}); err != nil {
104 c.wantMatchedTxs[i].Version = 1
105 byteData, err := c.wantMatchedTxs[i].MarshalText()
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())
119 func TestCalcMatchedTxFee(t *testing.T) {
124 wantMatchedTxFee map[bc.AssetID]*MatchedTxFee
127 desc: "fee less than max fee",
129 wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{mock.ETH: {FeeAmount: 10, MaxFeeAmount: 26}},
130 tx: &mock.MatchedTxs[1].TxData,
133 desc: "fee refund in tx",
135 wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{mock.ETH: {FeeAmount: 27, MaxFeeAmount: 27}},
136 tx: &mock.MatchedTxs[2].TxData,
141 wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{},
142 tx: &mock.MatchedTxs[0].TxData,
146 for i, c := range cases {
147 gotMatchedTxFee, err := CalcMatchedTxFee(c.tx, c.maxFeeRate)
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)
158 func TestValidateTradePairs(t *testing.T) {
161 tradePairs []*common.TradePair
165 desc: "valid case of two trade pairs",
166 tradePairs: []*common.TradePair{
168 FromAssetID: &mock.BTC,
169 ToAssetID: &mock.ETH,
172 FromAssetID: &mock.ETH,
173 ToAssetID: &mock.BTC,
179 desc: "invalid case of two trade pairs",
180 tradePairs: []*common.TradePair{
182 FromAssetID: &mock.BTC,
183 ToAssetID: &mock.ETH,
186 FromAssetID: &mock.ETH,
187 ToAssetID: &mock.EOS,
193 desc: "valid case of three trade pairs",
194 tradePairs: []*common.TradePair{
196 FromAssetID: &mock.BTC,
197 ToAssetID: &mock.ETH,
200 FromAssetID: &mock.ETH,
201 ToAssetID: &mock.EOS,
204 FromAssetID: &mock.EOS,
205 ToAssetID: &mock.BTC,
211 desc: "invalid case of three trade pairs",
212 tradePairs: []*common.TradePair{
214 FromAssetID: &mock.BTC,
215 ToAssetID: &mock.ETH,
218 FromAssetID: &mock.ETH,
219 ToAssetID: &mock.BTC,
222 FromAssetID: &mock.BTC,
223 ToAssetID: &mock.BTC,
229 desc: "valid case 2 of three trade pairs",
230 tradePairs: []*common.TradePair{
232 FromAssetID: &mock.BTC,
233 ToAssetID: &mock.ETH,
236 FromAssetID: &mock.EOS,
237 ToAssetID: &mock.BTC,
240 FromAssetID: &mock.ETH,
241 ToAssetID: &mock.EOS,
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)
254 if !c.wantError && err != nil {
255 t.Errorf("#%d(%s): want no error, got error (%v)", i, c.desc, err)
260 func TestIsMatched(t *testing.T) {
263 orders []*common.Order
267 desc: "ratio is equals",
268 orders: []*common.Order{
270 FromAssetID: &mock.BTC,
271 ToAssetID: &mock.ETH,
272 RatioNumerator: 6250,
276 FromAssetID: &mock.ETH,
277 ToAssetID: &mock.BTC,
279 RatioDenominator: 6250,
285 desc: "ratio is equals, and numerator and denominator are multiples of the opposite",
286 orders: []*common.Order{
288 FromAssetID: &mock.BTC,
289 ToAssetID: &mock.ETH,
290 RatioNumerator: 6250,
294 FromAssetID: &mock.ETH,
295 ToAssetID: &mock.BTC,
297 RatioDenominator: 18750,
303 desc: "matched with a slight diff",
304 orders: []*common.Order{
306 FromAssetID: &mock.BTC,
307 ToAssetID: &mock.ETH,
308 RatioNumerator: 62500000000000000,
309 RatioDenominator: 30000000000001,
312 FromAssetID: &mock.ETH,
313 ToAssetID: &mock.BTC,
315 RatioDenominator: 6250,
321 desc: "not matched with a slight diff",
322 orders: []*common.Order{
324 FromAssetID: &mock.BTC,
325 ToAssetID: &mock.ETH,
326 RatioNumerator: 62500000000000001,
327 RatioDenominator: 30000000000000,
330 FromAssetID: &mock.ETH,
331 ToAssetID: &mock.BTC,
333 RatioDenominator: 6250,
339 desc: "ring matched",
340 orders: []*common.Order{
342 FromAssetID: &mock.BTC,
343 ToAssetID: &mock.ETH,
344 RatioNumerator: 2000000003,
345 RatioDenominator: 100000001,
348 FromAssetID: &mock.ETH,
349 ToAssetID: &mock.EOS,
350 RatioNumerator: 400000000001,
351 RatioDenominator: 2000000003,
354 FromAssetID: &mock.EOS,
355 ToAssetID: &mock.BTC,
356 RatioNumerator: 100000001,
357 RatioDenominator: 400000000001,
363 desc: "ring matched with a slight diff",
364 orders: []*common.Order{
366 FromAssetID: &mock.BTC,
367 ToAssetID: &mock.ETH,
368 RatioNumerator: 2000000003,
369 RatioDenominator: 100000001,
372 FromAssetID: &mock.ETH,
373 ToAssetID: &mock.EOS,
374 RatioNumerator: 400000000001,
375 RatioDenominator: 2000000003,
378 FromAssetID: &mock.EOS,
379 ToAssetID: &mock.BTC,
380 RatioNumerator: 100000000,
381 RatioDenominator: 400000000001,
387 desc: "ring fail matched with a slight diff",
388 orders: []*common.Order{
390 FromAssetID: &mock.BTC,
391 ToAssetID: &mock.ETH,
392 RatioNumerator: 2000000003,
393 RatioDenominator: 100000001,
396 FromAssetID: &mock.ETH,
397 ToAssetID: &mock.EOS,
398 RatioNumerator: 400000000001,
399 RatioDenominator: 2000000003,
402 FromAssetID: &mock.EOS,
403 ToAssetID: &mock.BTC,
404 RatioNumerator: 100000002,
405 RatioDenominator: 400000000001,
412 for i, c := range cases {
413 gotMatched := IsMatched(c.orders)
414 if gotMatched != c.wantMatched {
415 t.Errorf("#%d(%s) got matched:%v, want matched:%v", i, c.desc, gotMatched, c.wantMatched)