OSDN Git Service

mov core (#421)
[bytom/vapor.git] / application / mov / match / match_test.go
1 package match
2
3 import (
4         "testing"
5
6         "github.com/vapor/protocol/vm"
7         "github.com/vapor/testutil"
8
9         "github.com/vapor/application/mov/common"
10         "github.com/vapor/application/mov/database"
11         "github.com/vapor/protocol/bc"
12         "github.com/vapor/protocol/bc/types"
13         "github.com/vapor/protocol/vm/vmutil"
14 )
15
16 var (
17         btc = bc.NewAssetID([32]byte{1})
18         eth = bc.NewAssetID([32]byte{2})
19
20         orders = []*common.Order{
21                 // btc -> eth
22                 {
23                         FromAssetID: &btc,
24                         ToAssetID:   &eth,
25                         Rate:        50,
26                         Utxo: &common.MovUtxo{
27                                 SourceID:       hashPtr(testutil.MustDecodeHash("37b8edf656e45a7addf47f5626e114a8c394d918a36f61b5a2905675a09b40ae")),
28                                 SourcePos:      0,
29                                 Amount:         10,
30                                 ControlProgram: mustCreateP2WMCProgram(eth, testutil.MustDecodeHexString("51"), 50, 1),
31                         },
32                 },
33                 {
34                         FromAssetID: &btc,
35                         ToAssetID:   &eth,
36                         Rate:        53,
37                         Utxo: &common.MovUtxo{
38                                 SourceID:       hashPtr(testutil.MustDecodeHash("3ec2bbfb499a8736d377b547eee5392bcddf7ec2b287e9ed20b5938c3d84e7cd")),
39                                 SourcePos:      0,
40                                 Amount:         20,
41                                 ControlProgram: mustCreateP2WMCProgram(eth, testutil.MustDecodeHexString("52"), 53, 1),
42                         },
43                 },
44
45                 // eth -> btc
46                 {
47                         FromAssetID: &eth,
48                         ToAssetID:   &btc,
49                         Rate:        1 / 51.0,
50                         Utxo: &common.MovUtxo{
51                                 SourceID:       hashPtr(testutil.MustDecodeHash("fba43ff5155209cb1769e2ec0e1d4a33accf899c740865edfc6d1de39b873b29")),
52                                 SourcePos:      0,
53                                 Amount:         510,
54                                 ControlProgram: mustCreateP2WMCProgram(btc, testutil.MustDecodeHexString("53"), 1, 51.0),
55                         },
56                 },
57                 {
58                         FromAssetID: &eth,
59                         ToAssetID:   &btc,
60                         Rate:        1 / 52.0,
61                         Utxo: &common.MovUtxo{
62                                 SourceID:       hashPtr(testutil.MustDecodeHash("05f24bb847db823075d81786aa270748e02602199cd009c0284f928503846a5a")),
63                                 SourcePos:      0,
64                                 Amount:         416,
65                                 ControlProgram: mustCreateP2WMCProgram(btc, testutil.MustDecodeHexString("54"), 1, 52.0),
66                         },
67                 },
68                 {
69                         FromAssetID: &eth,
70                         ToAssetID:   &btc,
71                         Rate:        1 / 54.0,
72                         Utxo: &common.MovUtxo{
73                                 SourceID:       hashPtr(testutil.MustDecodeHash("119a02980796dc352cf6475457463aef5666f66622088de3551fa73a65f0d201")),
74                                 SourcePos:      0,
75                                 Amount:         810,
76                                 ControlProgram: mustCreateP2WMCProgram(btc, testutil.MustDecodeHexString("55"), 1, 54.0),
77                         },
78                 },
79         }
80 )
81
82 func TestGenerateMatchedTxs(t *testing.T) {
83         btc2eth := &common.TradePair{FromAssetID: &btc, ToAssetID: &eth}
84         eth2btc := &common.TradePair{FromAssetID: &eth, ToAssetID: &btc}
85
86         cases := []struct {
87                 desc           string
88                 tradePair      *common.TradePair
89                 storeOrderMap  map[string][]*common.Order
90                 wantMatchedTxs []*types.TxData
91         }{
92                 {
93                         desc:      "full matched",
94                         tradePair: &common.TradePair{FromAssetID: &btc, ToAssetID: &eth},
95                         storeOrderMap: map[string][]*common.Order{
96                                 btc2eth.Key(): {orders[0], orders[1]},
97                                 eth2btc.Key(): {orders[2], orders[3]},
98                         },
99                         wantMatchedTxs: []*types.TxData{
100                                 {
101                                         Inputs: []*types.TxInput{
102                                                 types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *orders[0].Utxo.SourceID, *orders[0].FromAssetID, orders[0].Utxo.Amount, orders[0].Utxo.SourcePos, orders[0].Utxo.ControlProgram),
103                                                 types.NewSpendInput([][]byte{vm.Int64Bytes(1), vm.Int64Bytes(1)}, *orders[2].Utxo.SourceID, *orders[2].FromAssetID, orders[2].Utxo.Amount, orders[2].Utxo.SourcePos, orders[2].Utxo.ControlProgram),
104                                         },
105                                         Outputs: []*types.TxOutput{
106                                                 types.NewIntraChainOutput(*orders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
107                                                 types.NewIntraChainOutput(*orders[2].ToAssetID, 10, testutil.MustDecodeHexString("53")),
108                                                 types.NewIntraChainOutput(*orders[0].ToAssetID, 10, []byte{0x51}),
109                                         },
110                                 },
111                         },
112                 },
113                 {
114                         desc:      "partial matched",
115                         tradePair: &common.TradePair{FromAssetID: &btc, ToAssetID: &eth},
116                         storeOrderMap: map[string][]*common.Order{
117                                 btc2eth.Key(): {orders[0], orders[1]},
118                                 eth2btc.Key(): {orders[3]},
119                         },
120                         wantMatchedTxs: []*types.TxData{
121                                 {
122                                         Inputs: []*types.TxInput{
123                                                 types.NewSpendInput([][]byte{vm.Int64Bytes(416), vm.Int64Bytes(0), vm.Int64Bytes(0)}, *orders[0].Utxo.SourceID, *orders[0].FromAssetID, orders[0].Utxo.Amount, orders[0].Utxo.SourcePos, orders[0].Utxo.ControlProgram),
124                                                 types.NewSpendInput([][]byte{vm.Int64Bytes(2), vm.Int64Bytes(1)}, *orders[3].Utxo.SourceID, *orders[3].FromAssetID, orders[3].Utxo.Amount, orders[3].Utxo.SourcePos, orders[3].Utxo.ControlProgram),
125                                         },
126                                         Outputs: []*types.TxOutput{
127                                                 types.NewIntraChainOutput(*orders[0].ToAssetID, 416, testutil.MustDecodeHexString("51")),
128                                                 // re-order
129                                                 types.NewIntraChainOutput(*orders[0].FromAssetID, 1, orders[0].Utxo.ControlProgram),
130                                                 types.NewIntraChainOutput(*orders[3].ToAssetID, 8, testutil.MustDecodeHexString("54")),
131                                                 // fee
132                                                 types.NewIntraChainOutput(*orders[3].ToAssetID, 1, []byte{0x51}),
133                                         },
134                                 },
135                         },
136                 },
137                 {
138                         desc:      "partial matched and continue to match",
139                         tradePair: &common.TradePair{FromAssetID: &btc, ToAssetID: &eth},
140                         storeOrderMap: map[string][]*common.Order{
141                                 btc2eth.Key(): {orders[0], orders[1]},
142                                 eth2btc.Key(): {orders[4]},
143                         },
144                         wantMatchedTxs: []*types.TxData{
145                                 {
146                                         Inputs: []*types.TxInput{
147                                                 types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *orders[0].Utxo.SourceID, *orders[0].FromAssetID, orders[0].Utxo.Amount, orders[0].Utxo.SourcePos, orders[0].Utxo.ControlProgram),
148                                                 types.NewSpendInput([][]byte{vm.Int64Bytes(10), vm.Int64Bytes(1), vm.Int64Bytes(0)}, *orders[4].Utxo.SourceID, *orders[4].FromAssetID, orders[4].Utxo.Amount, orders[4].Utxo.SourcePos, orders[4].Utxo.ControlProgram),
149                                         },
150                                         Outputs: []*types.TxOutput{
151                                                 types.NewIntraChainOutput(*orders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
152                                                 types.NewIntraChainOutput(*orders[4].ToAssetID, 10, testutil.MustDecodeHexString("55")),
153                                                 // re-order
154                                                 types.NewIntraChainOutput(*orders[4].FromAssetID, 270, orders[4].Utxo.ControlProgram),
155                                                 // fee
156                                                 types.NewIntraChainOutput(*orders[4].FromAssetID, 27, []byte{0x51}),
157                                                 // refund
158                                                 types.NewIntraChainOutput(*orders[4].FromAssetID, 6, testutil.MustDecodeHexString("51")),
159                                                 types.NewIntraChainOutput(*orders[4].FromAssetID, 7, testutil.MustDecodeHexString("55")),
160                                         },
161                                 },
162                                 {
163                                         Inputs: []*types.TxInput{
164                                                 types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(0)}, *orders[1].Utxo.SourceID, *orders[1].FromAssetID, orders[1].Utxo.Amount, orders[1].Utxo.SourcePos, orders[1].Utxo.ControlProgram),
165                                                 types.NewSpendInput([][]byte{vm.Int64Bytes(2), vm.Int64Bytes(1)}, testutil.MustDecodeHash("f47177c12d25f5316eb377ea006e77bf07e4f9646860e4641e313e004f9aa989"), *orders[4].FromAssetID, 270, 2, orders[4].Utxo.ControlProgram),
166                                         },
167                                         Outputs: []*types.TxOutput{
168                                                 types.NewIntraChainOutput(*orders[1].ToAssetID, 270, testutil.MustDecodeHexString("52")),
169                                                 // re-order
170                                                 types.NewIntraChainOutput(*orders[1].FromAssetID, 14, orders[1].Utxo.ControlProgram),
171                                                 types.NewIntraChainOutput(*orders[4].ToAssetID, 5, testutil.MustDecodeHexString("55")),
172                                                 types.NewIntraChainOutput(*orders[1].FromAssetID, 1, []byte{0x51}),
173                                         },
174                                 },
175                         },
176                 },
177         }
178
179         for i, c := range cases {
180                 movStore := &database.MockMovStore{OrderMap: c.storeOrderMap}
181                 matchEngine := NewEngine(movStore, 0.05, []byte{0x51})
182                 var gotMatchedTxs []*types.Tx
183                 for matchEngine.HasMatchedTx(c.tradePair, c.tradePair.Reverse()) {
184                         matchedTx, err := matchEngine.NextMatchedTx(c.tradePair, c.tradePair.Reverse())
185                         if err != nil {
186                                 t.Fatal(err)
187                         }
188
189                         gotMatchedTxs = append(gotMatchedTxs, matchedTx)
190                 }
191
192                 if len(c.wantMatchedTxs) != len(gotMatchedTxs) {
193                         t.Errorf("#%d(%s) the length of got matched tx is not equals want matched tx", i, c.desc)
194                         continue
195                 }
196
197                 for i, gotMatchedTx := range gotMatchedTxs {
198                         c.wantMatchedTxs[i].Version = 1
199                         byteData, err := c.wantMatchedTxs[i].MarshalText()
200                         if err != nil {
201                                 t.Fatal(err)
202                         }
203
204                         c.wantMatchedTxs[i].SerializedSize = uint64(len(byteData))
205                         wantMatchedTx := types.NewTx(*c.wantMatchedTxs[i])
206                         if gotMatchedTx.ID != wantMatchedTx.ID {
207                                 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())
208                         }
209                 }
210         }
211 }
212
213 func mustCreateP2WMCProgram(requestAsset bc.AssetID, sellerProgram []byte, ratioMolecule, ratioDenominator int64) []byte {
214         contractArgs := vmutil.MagneticContractArgs{
215                 RequestedAsset:   requestAsset,
216                 RatioNumerator:   ratioMolecule,
217                 RatioDenominator: ratioDenominator,
218                 SellerProgram:    sellerProgram,
219                 SellerKey:        testutil.MustDecodeHexString("ad79ec6bd3a6d6dbe4d0ee902afc99a12b9702fb63edce5f651db3081d868b75"),
220         }
221         program, err := vmutil.P2WMCProgram(contractArgs)
222         if err != nil {
223                 panic(err)
224         }
225         return program
226 }
227
228 func hashPtr(hash bc.Hash) *bc.Hash {
229         return &hash
230 }