Commit 5d8922a2 authored by harrylee's avatar harrylee Committed by vipwzw

add exchange_test.go

parent ef710316
...@@ -2,13 +2,466 @@ package executor ...@@ -2,13 +2,466 @@ package executor
import ( import (
"testing" "testing"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/queue"
et "github.com/33cn/plugin/plugin/dapp/exchange/types"
"github.com/stretchr/testify/assert"
)
type execEnv struct {
blockTime int64
blockHeight int64
difficulty uint64
}
var (
PrivKeyA = "0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" // 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
PrivKeyB = "0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4" // 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
PrivKeyC = "0x7a80a1f75d7360c6123c32a78ecf978c1ac55636f87892df38d8b85a9aeff115" // 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k
PrivKeyD = "0xcacb1f5d51700aea07fca2246ab43b0917d70405c65edea9b5063d72eb5c6b71" // 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs
Nodes = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"),
[]byte("1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"),
}
) )
func TestExchange(t *testing.T) {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
Init(et.ExchangeX, cfg, nil)
total := 100 * types.Coin
accountA := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[0]),
}
accountB := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[1]),
}
accountC := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[2]),
}
accountD := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[3]),
}
execAddr := address.ExecAddress(et.ExchangeX)
stateDB, _ := dbm.NewGoMemDB("1", "2", 1000)
_, _, kvdb := util.CreateTestDB()
accA, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accA.SaveExecAccount(execAddr, &accountA)
accB, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accB.SaveExecAccount(execAddr, &accountB)
accC, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accC.SaveExecAccount(execAddr, &accountC)
accD, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accD.SaveExecAccount(execAddr, &accountD)
accA1, _ := account.NewAccountDB(cfg, "token", "CCNY", stateDB)
accA1.SaveExecAccount(execAddr, &accountA)
accB1, _ := account.NewAccountDB(cfg, "paracross", "coins.bty", stateDB)
accB1.SaveExecAccount(execAddr, &accountB)
accC1, _ := account.NewAccountDB(cfg, "paracross", "token.CCNY", stateDB)
accC1.SaveExecAccount(execAddr, &accountC)
accD1, _ := account.NewAccountDB(cfg, "token", "para", stateDB)
accD1.SaveExecAccount(execAddr, &accountD)
env := execEnv{
10,
cfg.GetDappFork(et.ExchangeX, "Enable"),
1539918074,
}
// orderlimit bty:CCNY 买bty
ety := types.LoadExecutorType(et.ExchangeX)
tx, err := ety.Create("LimitOrder", &et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: 4, Amount: 10 * types.Coin, Op: et.OpBuy})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
exec := newExchange()
e := exec.(*exchange)
err = e.CheckTx(tx, 1)
assert.Nil(t, err)
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
env.blockHeight = env.blockHeight + 1
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err := exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptData, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
orderID1 := common.ToHex(tx.Hash())
//根据订单号,查询订单详情
msg, err := exec.Query(et.FuncNameQueryOrder, types.Encode(&et.QueryOrder{OrderID: orderID1}))
if err != nil {
t.Error(err)
}
reply := msg.(*et.Order)
t.Log(reply)
assert.Equal(t, int32(et.Ordered), reply.Status)
assert.Equal(t, 10*types.Coin, reply.GetBalance())
//查看账户余额
acc := accA1.LoadExecAccount(string(Nodes[0]), execAddr)
t.Log(acc)
//根据op查询市场深度
msg, err = exec.Query(et.FuncNameQueryMarketDepth, types.Encode(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Op: et.OpBuy}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply1 := msg.(*et.MarketDepthList)
assert.Equal(t, 10*types.Coin, reply1.List[0].GetAmount())
//根据状态和地址查询
msg, err = exec.Query(et.FuncNameQueryOrderList, types.Encode(&et.QueryOrderList{Status: et.Ordered, Address: string(Nodes[0])}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply2 := msg.(*et.OrderList)
assert.Equal(t, orderID1, reply2.List[0].OrderID)
// orderlimit bty:CCNY 卖bty
tx, err = ety.Create("LimitOrder", &et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Price: 4, Amount: 5 * types.Coin, Op: et.OpSell})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyB)
assert.Nil(t, err)
err = e.CheckTx(tx, 1)
assert.Nil(t, err)
env.blockHeight = env.blockHeight + 1
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(tx, receiptData, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
orderID2 := common.ToHex(tx.Hash())
//根据订单号,查询订单详情
msg, err = exec.Query(et.FuncNameQueryOrder, types.Encode(&et.QueryOrder{OrderID: orderID1}))
if err != nil {
t.Error(err)
}
//订单1的状态应该还是ordered
reply = msg.(*et.Order)
assert.Equal(t, int32(et.Ordered), reply.Status)
t.Log(reply)
msg, err = exec.Query(et.FuncNameQueryOrder, types.Encode(&et.QueryOrder{OrderID: orderID2}))
if err != nil {
t.Error(err)
}
reply = msg.(*et.Order)
assert.Equal(t, int32(et.Completed), reply.Status)
//根据op查询市场深度
msg, err = exec.Query(et.FuncNameQueryMarketDepth, types.Encode(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Op: et.OpBuy}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply1 = msg.(*et.MarketDepthList)
t.Log(reply1.List)
//市场深度应该改变
assert.Equal(t, 5*types.Coin, reply1.List[0].GetAmount())
//QueryCompletedOrderList
msg, err = exec.Query(et.FuncNameQueryCompletedOrderList, types.Encode(&et.QueryCompletedOrderList{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}}))
if err != nil {
t.Error(err)
}
reply2 = msg.(*et.OrderList)
assert.Equal(t, orderID2, reply2.List[0].OrderID)
//撤回之前的订单
// orderlimit bty:CCNY
tx, err = ety.Create("RevokeOrder", &et.RevokeOrder{OrderID: orderID1})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
err = e.CheckTx(tx, 1)
assert.Nil(t, err)
env.blockHeight = env.blockHeight + 1
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(tx, receiptData, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
//根据订单号,查询订单详情
msg, err = exec.Query(et.FuncNameQueryOrder, types.Encode(&et.QueryOrder{OrderID: orderID1}))
if err != nil {
t.Error(err)
}
reply = msg.(*et.Order)
assert.Equal(t, int32(et.Revoked), reply.Status)
t.Log(reply)
//根据op查询市场深度
msg, err = exec.Query(et.FuncNameQueryMarketDepth, types.Encode(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "token", Symbol: "CCNY"}, Op: et.OpBuy}))
if err != nil {
t.Error(err)
}
reply1 = msg.(*et.MarketDepthList)
t.Log(reply1.GetList())
t.Log(len(reply1.GetList()))
//反向测试
// orderlimit bty:CCNY 卖bty
tx, err = ety.Create("LimitOrder", &et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "paracross", Symbol: "coins.bty"}, Price: 0.5, Amount: 10 * types.Coin, Op: et.OpSell})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
err = e.CheckTx(tx, 1)
assert.Nil(t, err)
env.blockHeight = env.blockHeight + 1
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(tx, receiptData, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
orderID3 := common.ToHex(tx.Hash())
msg, err = exec.Query(et.FuncNameQueryOrder, types.Encode(&et.QueryOrder{OrderID: orderID3}))
if err != nil {
t.Error(err)
}
//订单1的状态应该还是ordered
reply = msg.(*et.Order)
assert.Equal(t, int32(et.Ordered), reply.Status)
t.Log(reply)
tx, err = ety.Create("LimitOrder", &et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "paracross", Symbol: "coins.bty"}, Price: 0.5, Amount: 10 * types.Coin, Op: et.OpSell})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
err = e.CheckTx(tx, 1)
assert.Nil(t, err)
env.blockHeight = env.blockHeight + 1
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(tx, receiptData, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
orderID4 := common.ToHex(tx.Hash())
//根据订单号,查询订单详情
msg, err = exec.Query(et.FuncNameQueryOrder, types.Encode(&et.QueryOrder{OrderID: orderID4}))
if err != nil {
t.Error(err)
}
//订单1的状态应该还是ordered
reply = msg.(*et.Order)
assert.Equal(t, int32(et.Ordered), reply.Status)
t.Log(reply)
//根据op查询市场深度
msg, err = exec.Query(et.FuncNameQueryMarketDepth, types.Encode(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "paracross", Symbol: "coins.bty"}, Op: et.OpSell}))
if err != nil {
t.Error(err)
}
reply1 = msg.(*et.MarketDepthList)
t.Log(reply1.List)
//市场深度应该改变
assert.Equal(t, 20*types.Coin, reply1.List[0].GetAmount())
//根据状态和地址查询
msg, err = exec.Query(et.FuncNameQueryOrderList, types.Encode(&et.QueryOrderList{Status: et.Ordered, Address: string(Nodes[0])}))
if err != nil {
t.Error(err)
}
reply2 = msg.(*et.OrderList)
t.Log(reply2)
//默认倒序查询
assert.Equal(t, orderID3, reply2.List[1].OrderID)
assert.Equal(t, orderID4, reply2.List[0].OrderID)
tx, err = ety.Create("LimitOrder", &et.LimitOrder{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "paracross", Symbol: "coins.bty"}, Price: 0.5, Amount: 20 * types.Coin, Op: et.OpBuy})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, et.ExchangeX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyB)
assert.Nil(t, err)
err = e.CheckTx(tx, 1)
assert.Nil(t, err)
env.blockHeight = env.blockHeight + 1
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(tx, receiptData, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
orderID5 := common.ToHex(tx.Hash())
//根据订单号,查询订单详情
msg, err = exec.Query(et.FuncNameQueryOrder, types.Encode(&et.QueryOrder{OrderID: orderID5}))
if err != nil {
t.Error(err)
}
//订单1的状态应该还是ordered
reply = msg.(*et.Order)
assert.Equal(t, int32(et.Completed), reply.Status)
//根据op查询市场深度
msg, err = exec.Query(et.FuncNameQueryMarketDepth, types.Encode(&et.QueryMarketDepth{LeftAsset: &et.Asset{Symbol: "bty", Execer: "coins"},
RightAsset: &et.Asset{Execer: "paracross", Symbol: "coins.bty"}, Op: et.OpSell}))
if err != nil {
t.Error(err)
}
reply1 = msg.(*et.MarketDepthList)
t.Log(reply1.List)
}
func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error) {
signType := types.SECP256K1
c, err := crypto.New(types.GetSignName("", signType))
if err != nil {
return tx, err
}
bytes, err := common.FromHex(hexPrivKey[:])
if err != nil {
return tx, err
}
privKey, err := c.PrivKeyFromBytes(bytes)
if err != nil {
return tx, err
}
tx.Sign(int32(signType), privKey)
return tx, nil
}
func TestTruncate(t *testing.T) { func TestTruncate(t *testing.T) {
a:=float32(1.00000212000000000001) a := float32(1.00000212000000000001)
b:=float32(0.34567) b := float32(0.34567)
c:=float32(1234) c := float32(1234)
t.Log(Truncate(a)) t.Log(Truncate(a))
t.Log(Truncate(b)) t.Log(Truncate(b))
t.Log(Truncate(c)) t.Log(Truncate(c))
} }
\ No newline at end of file
func TestCheckPrice(t *testing.T) {
t.Log(CheckPrice(0.25))
}
...@@ -35,7 +35,8 @@ func NewAction(e *exchange, tx *types.Transaction, index int) *Action { ...@@ -35,7 +35,8 @@ func NewAction(e *exchange, tx *types.Transaction, index int) *Action {
//GetIndex get index //GetIndex get index
func (a *Action) GetIndex() int64 { func (a *Action) GetIndex() int64 {
return a.height*types.MaxTxsPerBlock + int64(a.index) //扩容4个0,用于匹配多个matchorder索引时使用
return (a.height*types.MaxTxsPerBlock + int64(a.index)) * 1e4
} }
//GetKVSet get kv set //GetKVSet get kv set
...@@ -66,9 +67,9 @@ func (a *Action) calcActualCost(op int32, amount int64, price float32) int64 { ...@@ -66,9 +67,9 @@ func (a *Action) calcActualCost(op int32, amount int64, price float32) int64 {
return amount return amount
} }
//price 精度允许范围小数点后面7位数,整数是1e8 //price 精度允许范围小数点后面7位数,0<price<1e8
func CheckPrice(price float32) bool { func CheckPrice(price float32) bool {
if (Truncate(price) > 1e8) || (Truncate(price)*float32(1e8) <= 0) { if (Truncate(price) >= 1e8) || (Truncate(price)*float32(1e8) <= 0) {
return false return false
} }
return true return true
...@@ -122,7 +123,7 @@ func (a *Action) LimitOrder(payload *et.LimitOrder) (*types.Receipt, error) { ...@@ -122,7 +123,7 @@ func (a *Action) LimitOrder(payload *et.LimitOrder) (*types.Receipt, error) {
if !types.CheckAmount(payload.GetAmount()) { if !types.CheckAmount(payload.GetAmount()) {
return nil, et.ErrAssetAmount return nil, et.ErrAssetAmount
} }
if CheckPrice(payload.GetPrice()) { if !CheckPrice(payload.GetPrice()) {
return nil, et.ErrAssetPrice return nil, et.ErrAssetPrice
} }
if !CheckOp(payload.GetOp()) { if !CheckOp(payload.GetOp()) {
...@@ -188,7 +189,7 @@ func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) { ...@@ -188,7 +189,7 @@ func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
amount := int64(float32(balance) * price) amount := a.calcActualCost(et.OpBuy, balance, price)
rightAccount := rightAssetDB.LoadExecAccount(a.fromaddr, a.execaddr) rightAccount := rightAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if rightAccount.Frozen < amount { if rightAccount.Frozen < amount {
elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error()) elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
...@@ -207,7 +208,7 @@ func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) { ...@@ -207,7 +208,7 @@ func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
amount := balance amount := a.calcActualCost(et.OpBuy, balance, price)
leftAccount := leftAssetDB.LoadExecAccount(a.fromaddr, a.execaddr) leftAccount := leftAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if leftAccount.Frozen < amount { if leftAccount.Frozen < amount {
elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error()) elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
...@@ -281,25 +282,44 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc ...@@ -281,25 +282,44 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
} }
//TODO 这里得逻辑是否需要调整?当匹配的单数过多,会导致receipt日志数量激增,理论上存在日志存储攻击,需要加下最大匹配深度,防止这种攻击发生 //TODO 这里得逻辑是否需要调整?当匹配的单数过多,会导致receipt日志数量激增,理论上存在日志存储攻击,需要加下最大匹配深度,防止这种攻击发生
if matchorder.GetBalance() >= or.GetBalance() { if matchorder.GetBalance() >= or.GetBalance() {
//转移冻结资产 if payload.Op == et.OpSell {
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice())) //转移冻结资产
if err != nil { receipt, err := rightAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()))
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()), "err", err.Error()) if err != nil {
return nil, err elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//将达成交易的相应资产结算
receipt, err = leftAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, or.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, or.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
} }
logs = append(logs, receipt.Logs...) if payload.Op == et.OpBuy {
kvs = append(kvs, receipt.KV...) //转移冻结资产
//将达成交易的相应资产结算 receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()))
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, or.GetBalance(), payload.GetPrice())) if err != nil {
if err != nil { elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()), "err", err.Error())
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, or.GetBalance(), payload.GetPrice()), "err", err.Error()) return nil, err
return nil, err }
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//将达成交易的相应资产结算
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, or.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, or.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
} }
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...) // match receiptorder,涉及赋值先手顺序,代码顺序不可变
// match receiptorder
matchorder.Balance = matchorder.GetBalance() - or.GetBalance()
matchorder.Executed = matchorder.Executed + or.GetBalance()
matchorder.Status = func(a, b int64) int32 { matchorder.Status = func(a, b int64) int32 {
if a > b { if a > b {
return et.Ordered return et.Ordered
...@@ -307,12 +327,15 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc ...@@ -307,12 +327,15 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
return et.Completed return et.Completed
} }
}(matchorder.GetBalance(), or.GetBalance()) }(matchorder.GetBalance(), or.GetBalance())
matchorder.Balance = matchorder.GetBalance() - or.GetBalance()
matchorder.Executed = matchorder.Executed + or.GetBalance()
a.updateStateDBCache(matchorder) a.updateStateDBCache(matchorder)
kvs = append(kvs, a.GetKVSet(matchorder)...) kvs = append(kvs, a.GetKVSet(matchorder)...)
or.Balance = 0
or.Executed = or.Executed + or.GetBalance() or.Executed = or.Executed + or.GetBalance()
or.Status = et.Completed or.Status = et.Completed
or.Balance = 0
//update receipt order //update receipt order
re.Order = or re.Order = or
re.MatchOrders = append(re.MatchOrders, matchorder) re.MatchOrders = append(re.MatchOrders, matchorder)
...@@ -325,39 +348,58 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc ...@@ -325,39 +348,58 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
receipts := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs} receipts := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
return receipts, nil return receipts, nil
} else { } else {
//转移冻结资产 if payload.Op == et.OpSell {
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice())) //转移冻结资产
if err != nil { receipt, err := rightAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()))
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error()) if err != nil {
return nil, err elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//将达成交易的相应资产结算
receipt, err = leftAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
} }
logs = append(logs, receipt.Logs...) if payload.Op == et.OpBuy {
kvs = append(kvs, receipt.KV...) //转移冻结资产
//将达成交易的相应资产结算 receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()))
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.GetPrice())) if err != nil {
if err != nil { elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", matchorder.Addr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error())
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error()) return nil, err
return nil, err }
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//将达成交易的相应资产结算
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
} }
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...) //涉及赋值先后顺序,不可颠倒
or.Balance = or.Balance - matchorder.Balance
or.Executed = or.Executed + matchorder.Balance
or.Status = et.Ordered
a.updateStateDBCache(or)
// match receiptorder // match receiptorder
matchorder.Balance = 0
matchorder.Executed = matchorder.Executed + matchorder.GetBalance() matchorder.Executed = matchorder.Executed + matchorder.GetBalance()
matchorder.Status = et.Completed matchorder.Status = et.Completed
matchorder.Balance = 0
a.updateStateDBCache(matchorder) a.updateStateDBCache(matchorder)
kvs = append(kvs, a.GetKVSet(matchorder)...) kvs = append(kvs, a.GetKVSet(matchorder)...)
or.Balance = or.Balance - matchorder.Balance
or.Executed = or.Executed + matchorder.Balance
or.Status = et.Ordered
re.Order = or re.Order = or
re.MatchOrders = append(re.MatchOrders, matchorder) re.MatchOrders = append(re.MatchOrders, matchorder)
a.updateStateDBCache(or)
} }
} }
//查询数据不满足5条说明没有了,跳出循环 //查询数据不满足5条说明没有了,跳出循环
......
package executor package executor
import ( import (
"fmt"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
exchangetypes "github.com/33cn/plugin/plugin/dapp/exchange/types" exchangetypes "github.com/33cn/plugin/plugin/dapp/exchange/types"
) )
...@@ -11,19 +12,16 @@ import ( ...@@ -11,19 +12,16 @@ import (
*/ */
func (e *exchange) Exec_LimitOrder(payload *exchangetypes.LimitOrder, tx *types.Transaction, index int) (*types.Receipt, error) { func (e *exchange) Exec_LimitOrder(payload *exchangetypes.LimitOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt action := NewAction(e, tx, index)
//implement code return action.LimitOrder(payload)
return receipt, nil
} }
func (e *exchange) Exec_MarketOrder(payload *exchangetypes.MarketOrder, tx *types.Transaction, index int) (*types.Receipt, error) { func (e *exchange) Exec_MarketOrder(payload *exchangetypes.MarketOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt //TODO marketOrder
//implement code return nil, fmt.Errorf("%s", "not support MarketOrder..")
return receipt, nil
} }
func (e *exchange) Exec_RevokeOrder(payload *exchangetypes.RevokeOrder, tx *types.Transaction, index int) (*types.Receipt, error) { func (e *exchange) Exec_RevokeOrder(payload *exchangetypes.RevokeOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt action := NewAction(e, tx, index)
//implement code return action.RevokeOrder(payload)
return receipt, nil
} }
...@@ -30,13 +30,37 @@ func (e *exchange) ExecLocal_LimitOrder(payload *exchangetypes.LimitOrder, tx *t ...@@ -30,13 +30,37 @@ func (e *exchange) ExecLocal_LimitOrder(payload *exchangetypes.LimitOrder, tx *t
func (e *exchange) ExecLocal_MarketOrder(payload *exchangetypes.MarketOrder, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (e *exchange) ExecLocal_MarketOrder(payload *exchangetypes.MarketOrder, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{} dbSet := &types.LocalDBSet{}
//implement code if receiptData.Ty == types.ExecOk {
for _, log := range receiptData.Logs {
switch log.Ty {
case exchangetypes.TyMarketOrderLog:
receipt := &exchangetypes.ReceiptExchange{}
if err := types.Decode(log.Log, receipt); err != nil {
return nil, err
}
kv := e.updateIndex(receipt)
dbSet.KV = append(dbSet.KV, kv...)
}
}
}
return e.addAutoRollBack(tx, dbSet.KV), nil return e.addAutoRollBack(tx, dbSet.KV), nil
} }
func (e *exchange) ExecLocal_RevokeOrder(payload *exchangetypes.RevokeOrder, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (e *exchange) ExecLocal_RevokeOrder(payload *exchangetypes.RevokeOrder, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{} dbSet := &types.LocalDBSet{}
//implement code if receiptData.Ty == types.ExecOk {
for _, log := range receiptData.Logs {
switch log.Ty {
case exchangetypes.TyRevokeOrderLog:
receipt := &exchangetypes.ReceiptExchange{}
if err := types.Decode(log.Log, receipt); err != nil {
return nil, err
}
kv := e.updateIndex(receipt)
dbSet.KV = append(dbSet.KV, kv...)
}
}
}
return e.addAutoRollBack(tx, dbSet.KV), nil return e.addAutoRollBack(tx, dbSet.KV), nil
} }
...@@ -66,8 +90,10 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t ...@@ -66,8 +90,10 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
markDepth.RightAsset = right markDepth.RightAsset = right
markDepth.Op = op markDepth.Op = op
markDepth.Amount = receipt.Order.Balance markDepth.Amount = receipt.Order.Balance
} else {
markDepth.Amount = markDepth.Amount + receipt.Order.Balance
} }
markDepth.Amount = markDepth.Amount + receipt.Order.Balance
//marketDepth //marketDepth
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, op, price), Value: types.Encode(&markDepth)}) kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, op, price), Value: types.Encode(&markDepth)})
//orderID //orderID
...@@ -78,23 +104,23 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t ...@@ -78,23 +104,23 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
if len(receipt.MatchOrders) > 0 { if len(receipt.MatchOrders) > 0 {
//撮合交易更新 //撮合交易更新
var balance int64 var balance int64
for _, matchOrder := range receipt.MatchOrders { for i, matchOrder := range receipt.MatchOrders {
if matchOrder.Status == exchangetypes.Completed { if matchOrder.Status == exchangetypes.Completed {
// 删除原有状态orderID // 删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, matchOrder.GetLimitOrder().Op, price, matchOrder.Index), Value: nil}) kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, matchOrder.GetLimitOrder().Op, price, matchOrder.Index), Value: nil})
//删除原有状态orderID //删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, matchOrder.Addr, matchOrder.Index), Value: nil}) kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, matchOrder.Addr, matchOrder.Index), Value: nil})
//更新状态为已完成,索引index,改为当前的index //更新状态为已完成,索引index,改为当前的index
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, matchOrder.Addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index})}) kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, matchOrder.Addr, index+int64(i+1)), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index + int64(i+1)})})
//calcCompletedOrderKey //calcCompletedOrderKey
kvs = append(kvs, &types.KeyValue{Key: calcCompletedOrderKey(left, right, index), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index})}) kvs = append(kvs, &types.KeyValue{Key: calcCompletedOrderKey(left, right, index+int64(i+1)), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index + int64(i+1)})})
} }
if matchOrder.Status == exchangetypes.Ordered { if matchOrder.Status == exchangetypes.Ordered {
//只需统一更改市场深度状态,其他不需要处理 //只需统一更改市场深度状态,其他不需要处理
balance = balance + matchOrder.Balance balance = balance + matchOrder.Balance
} }
} }
//更改市场深度 //更改匹配市场深度
var matchDepth exchangetypes.MarketDepth var matchDepth exchangetypes.MarketDepth
err = findObject(e.GetLocalDB(), calcMarketDepthKey(left, right, OpSwap(op), price), &matchDepth) err = findObject(e.GetLocalDB(), calcMarketDepthKey(left, right, OpSwap(op), price), &matchDepth)
if err == types.ErrNotFound { if err == types.ErrNotFound {
...@@ -103,10 +129,15 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t ...@@ -103,10 +129,15 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
matchDepth.RightAsset = right matchDepth.RightAsset = right
matchDepth.Op = OpSwap(op) matchDepth.Op = OpSwap(op)
matchDepth.Amount = balance matchDepth.Amount = balance
} else {
matchDepth.Amount = matchDepth.Amount - receipt.Order.Executed
} }
matchDepth.Amount = matchDepth.Amount - receipt.Order.Executed
//marketDepth //marketDepth
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, OpSwap(op), price), Value: types.Encode(&matchDepth)}) kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, OpSwap(op), price), Value: types.Encode(&matchDepth)})
if matchDepth.Amount == 0 {
//删除
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, OpSwap(op), price), Value: nil})
}
} }
return return
case exchangetypes.Completed: case exchangetypes.Completed:
...@@ -121,19 +152,22 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t ...@@ -121,19 +152,22 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
//user orderID //user orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: oderID, Index: index})}) kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: oderID, Index: index})})
//calcCompletedOrderKey
kvs = append(kvs, &types.KeyValue{Key: calcCompletedOrderKey(left, right, index), Value: types.Encode(&exchangetypes.OrderID{ID: oderID, Index: index})})
if len(receipt.MatchOrders) > 0 { if len(receipt.MatchOrders) > 0 {
//撮合交易更新 //撮合交易更新
var balance int64 var balance int64
for _, matchOrder := range receipt.MatchOrders { for i, matchOrder := range receipt.MatchOrders {
if matchOrder.Status == exchangetypes.Completed { if matchOrder.Status == exchangetypes.Completed {
// 删除原有状态orderID // 删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, matchOrder.GetLimitOrder().Op, price, matchOrder.Index), Value: nil}) kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, matchOrder.GetLimitOrder().Op, price, matchOrder.Index), Value: nil})
//删除原有状态orderID //删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, matchOrder.Addr, matchOrder.Index), Value: nil}) kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, matchOrder.Addr, matchOrder.Index), Value: nil})
//更新状态为已完成,更新索引 //更新状态为已完成,更新索引
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, matchOrder.Addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index})}) kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, matchOrder.Addr, index+int64(i+1)), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index + int64(i+1)})})
//calcCompletedOrderKey //calcCompletedOrderKey
kvs = append(kvs, &types.KeyValue{Key: calcCompletedOrderKey(left, right, index), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index})}) kvs = append(kvs, &types.KeyValue{Key: calcCompletedOrderKey(left, right, index+int64(i+1)), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index + int64(i+1)})})
} }
if matchOrder.Status == exchangetypes.Ordered { if matchOrder.Status == exchangetypes.Ordered {
...@@ -150,10 +184,15 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t ...@@ -150,10 +184,15 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
matchDepth.RightAsset = right matchDepth.RightAsset = right
matchDepth.Op = OpSwap(op) matchDepth.Op = OpSwap(op)
matchDepth.Amount = balance matchDepth.Amount = balance
} else {
matchDepth.Amount = matchDepth.Amount - receipt.Order.Executed
} }
matchDepth.Amount = matchDepth.Amount - receipt.Order.Executed
//marketDepth //marketDepth
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, OpSwap(op), price), Value: types.Encode(&matchDepth)}) kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, OpSwap(op), price), Value: types.Encode(&matchDepth)})
if matchDepth.Amount == 0 {
//删除
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, OpSwap(op), price), Value: nil})
}
} }
return return
case exchangetypes.Revoked: case exchangetypes.Revoked:
...@@ -170,8 +209,14 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t ...@@ -170,8 +209,14 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
if err == nil { if err == nil {
//marketDepth //marketDepth
marketDepth.Amount = marketDepth.Amount - receipt.GetOrder().Balance marketDepth.Amount = marketDepth.Amount - receipt.GetOrder().Balance
elog.Error("revoked", "recept.order.balance", receipt.GetOrder().Balance)
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, op, price), Value: types.Encode(&marketDepth)}) kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, op, price), Value: types.Encode(&marketDepth)})
} }
elog.Error("revoked", "marketDepth.Amount", marketDepth.Amount)
if marketDepth.Amount == 0 {
//删除
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, op, price), Value: nil})
}
// 删除原有状态orderID // 删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, op, price, receipt.GetOrder().Index), Value: nil}) kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, op, price, receipt.GetOrder().Index), Value: nil})
//删除原有状态orderID //删除原有状态orderID
......
...@@ -45,14 +45,15 @@ func calcMarketDepthOrderPrefix(left, right *types.Asset, op int32, price float3 ...@@ -45,14 +45,15 @@ func calcMarketDepthOrderPrefix(left, right *types.Asset, op int32, price float3
// localdb中存储市场挂单ID // localdb中存储市场挂单ID
func calcMarketDepthOrderKey(left, right *types.Asset, op int32, price float32, index int64) []byte { func calcMarketDepthOrderKey(left, right *types.Asset, op int32, price float32, index int64) []byte {
// 设置精度为1e8 // 设置精度为1e8
key := fmt.Sprintf("%s"+"order-%s-%s-%d:%016d:%018d", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), op, int64(Truncate(price)*float32(1e8)), index) key := fmt.Sprintf("%s"+"order-%s-%s-%d:%016d:%022d", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), op, int64(Truncate(price)*float32(1e8)), index)
return []byte(key) return []byte(key)
} }
//最新已经成交的订单,这里状态固定都是完成状态,这个主要给外部使用,可以查询最新得成交信息 //最新已经成交的订单,这里状态固定都是完成状态,这个主要给外部使用,可以查询最新得成交信息,存在多个情况
//matchOrderIndex,是匹配order在数组中的index,这里预留4个0000,用来解决同一笔交易中存在key重复得情况,这样设计保证了key得唯一性
func calcCompletedOrderKey(left, right *types.Asset, index int64) []byte { func calcCompletedOrderKey(left, right *types.Asset, index int64) []byte {
// 设置精度为1e8 // 设置精度为1e8
key := fmt.Sprintf("%s"+"completed-%s-%s-%d:%018d", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), types.Completed, index) key := fmt.Sprintf("%s"+"completed-%s-%s-%d:%022d", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), types.Completed, index)
return []byte(key) return []byte(key)
} }
func calcCompletedOrderPrefix(left, right *types.Asset) []byte { func calcCompletedOrderPrefix(left, right *types.Asset) []byte {
...@@ -66,7 +67,8 @@ func calcUserOrderIDPrefix(status int32, addr string) []byte { ...@@ -66,7 +67,8 @@ func calcUserOrderIDPrefix(status int32, addr string) []byte {
key := fmt.Sprintf("%s"+"addr:%s:%d:", KeyPrefixLocalDB, addr, status) key := fmt.Sprintf("%s"+"addr:%s:%d:", KeyPrefixLocalDB, addr, status)
return []byte(key) return []byte(key)
} }
//matchOrderIndex,用来解决同一笔交易中存在key重复得情况,这样设计保证了key得唯一性
func calcUserOrderIDKey(status int32, addr string, index int64) []byte { func calcUserOrderIDKey(status int32, addr string, index int64) []byte {
key := fmt.Sprintf("%s"+"addr:%s:%d:%018d", KeyPrefixLocalDB, addr, status, index) key := fmt.Sprintf("%s"+"addr:%s:%d:%022d", KeyPrefixLocalDB, addr, status, index)
return []byte(key) return []byte(key)
} }
...@@ -16,9 +16,6 @@ func (s *exchange) Query_QueryMarketDepth(in *et.QueryMarketDepth) (types.Messag ...@@ -16,9 +16,6 @@ func (s *exchange) Query_QueryMarketDepth(in *et.QueryMarketDepth) (types.Messag
if !CheckExchangeAsset(in.LeftAsset, in.RightAsset) { if !CheckExchangeAsset(in.LeftAsset, in.RightAsset) {
return nil, et.ErrAsset return nil, et.ErrAsset
} }
if !CheckPrice(in.Price) {
return nil, et.ErrAssetPrice
}
if !CheckOp(in.Op) { if !CheckOp(in.Op) {
return nil, et.ErrAssetOp return nil, et.ErrAssetOp
......
...@@ -7,7 +7,7 @@ message Exchange { ...@@ -7,7 +7,7 @@ message Exchange {
message ExchangeAction { message ExchangeAction {
oneof value { oneof value {
LimitOrder limitOrder = 1; LimitOrder limitOrder = 1;
// MarketOrder marketOrder = 2; MarketOrder marketOrder = 2;
RevokeOrder revokeOrder = 3; RevokeOrder revokeOrder = 3;
} }
int32 ty = 6; int32 ty = 6;
......
...@@ -59,6 +59,7 @@ func (*Exchange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} ...@@ -59,6 +59,7 @@ func (*Exchange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0}
type ExchangeAction struct { type ExchangeAction struct {
// Types that are valid to be assigned to Value: // Types that are valid to be assigned to Value:
// *ExchangeAction_LimitOrder // *ExchangeAction_LimitOrder
// *ExchangeAction_MarketOrder
// *ExchangeAction_RevokeOrder // *ExchangeAction_RevokeOrder
Value isExchangeAction_Value `protobuf_oneof:"value"` Value isExchangeAction_Value `protobuf_oneof:"value"`
Ty int32 `protobuf:"varint,6,opt,name=ty" json:"ty,omitempty"` Ty int32 `protobuf:"varint,6,opt,name=ty" json:"ty,omitempty"`
...@@ -76,11 +77,15 @@ type isExchangeAction_Value interface { ...@@ -76,11 +77,15 @@ type isExchangeAction_Value interface {
type ExchangeAction_LimitOrder struct { type ExchangeAction_LimitOrder struct {
LimitOrder *LimitOrder `protobuf:"bytes,1,opt,name=limitOrder,oneof"` LimitOrder *LimitOrder `protobuf:"bytes,1,opt,name=limitOrder,oneof"`
} }
type ExchangeAction_MarketOrder struct {
MarketOrder *MarketOrder `protobuf:"bytes,2,opt,name=marketOrder,oneof"`
}
type ExchangeAction_RevokeOrder struct { type ExchangeAction_RevokeOrder struct {
RevokeOrder *RevokeOrder `protobuf:"bytes,3,opt,name=revokeOrder,oneof"` RevokeOrder *RevokeOrder `protobuf:"bytes,3,opt,name=revokeOrder,oneof"`
} }
func (*ExchangeAction_LimitOrder) isExchangeAction_Value() {} func (*ExchangeAction_LimitOrder) isExchangeAction_Value() {}
func (*ExchangeAction_MarketOrder) isExchangeAction_Value() {}
func (*ExchangeAction_RevokeOrder) isExchangeAction_Value() {} func (*ExchangeAction_RevokeOrder) isExchangeAction_Value() {}
func (m *ExchangeAction) GetValue() isExchangeAction_Value { func (m *ExchangeAction) GetValue() isExchangeAction_Value {
...@@ -97,6 +102,13 @@ func (m *ExchangeAction) GetLimitOrder() *LimitOrder { ...@@ -97,6 +102,13 @@ func (m *ExchangeAction) GetLimitOrder() *LimitOrder {
return nil return nil
} }
func (m *ExchangeAction) GetMarketOrder() *MarketOrder {
if x, ok := m.GetValue().(*ExchangeAction_MarketOrder); ok {
return x.MarketOrder
}
return nil
}
func (m *ExchangeAction) GetRevokeOrder() *RevokeOrder { func (m *ExchangeAction) GetRevokeOrder() *RevokeOrder {
if x, ok := m.GetValue().(*ExchangeAction_RevokeOrder); ok { if x, ok := m.GetValue().(*ExchangeAction_RevokeOrder); ok {
return x.RevokeOrder return x.RevokeOrder
...@@ -115,6 +127,7 @@ func (m *ExchangeAction) GetTy() int32 { ...@@ -115,6 +127,7 @@ func (m *ExchangeAction) GetTy() int32 {
func (*ExchangeAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { func (*ExchangeAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _ExchangeAction_OneofMarshaler, _ExchangeAction_OneofUnmarshaler, _ExchangeAction_OneofSizer, []interface{}{ return _ExchangeAction_OneofMarshaler, _ExchangeAction_OneofUnmarshaler, _ExchangeAction_OneofSizer, []interface{}{
(*ExchangeAction_LimitOrder)(nil), (*ExchangeAction_LimitOrder)(nil),
(*ExchangeAction_MarketOrder)(nil),
(*ExchangeAction_RevokeOrder)(nil), (*ExchangeAction_RevokeOrder)(nil),
} }
} }
...@@ -128,6 +141,11 @@ func _ExchangeAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { ...@@ -128,6 +141,11 @@ func _ExchangeAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
if err := b.EncodeMessage(x.LimitOrder); err != nil { if err := b.EncodeMessage(x.LimitOrder); err != nil {
return err return err
} }
case *ExchangeAction_MarketOrder:
b.EncodeVarint(2<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.MarketOrder); err != nil {
return err
}
case *ExchangeAction_RevokeOrder: case *ExchangeAction_RevokeOrder:
b.EncodeVarint(3<<3 | proto.WireBytes) b.EncodeVarint(3<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.RevokeOrder); err != nil { if err := b.EncodeMessage(x.RevokeOrder); err != nil {
...@@ -151,6 +169,14 @@ func _ExchangeAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto ...@@ -151,6 +169,14 @@ func _ExchangeAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto
err := b.DecodeMessage(msg) err := b.DecodeMessage(msg)
m.Value = &ExchangeAction_LimitOrder{msg} m.Value = &ExchangeAction_LimitOrder{msg}
return true, err return true, err
case 2: // value.marketOrder
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(MarketOrder)
err := b.DecodeMessage(msg)
m.Value = &ExchangeAction_MarketOrder{msg}
return true, err
case 3: // value.revokeOrder case 3: // value.revokeOrder
if wire != proto.WireBytes { if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType return true, proto.ErrInternalBadWireType
...@@ -173,6 +199,11 @@ func _ExchangeAction_OneofSizer(msg proto.Message) (n int) { ...@@ -173,6 +199,11 @@ func _ExchangeAction_OneofSizer(msg proto.Message) (n int) {
n += proto.SizeVarint(1<<3 | proto.WireBytes) n += proto.SizeVarint(1<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s)) n += proto.SizeVarint(uint64(s))
n += s n += s
case *ExchangeAction_MarketOrder:
s := proto.Size(x.MarketOrder)
n += proto.SizeVarint(2<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *ExchangeAction_RevokeOrder: case *ExchangeAction_RevokeOrder:
s := proto.Size(x.RevokeOrder) s := proto.Size(x.RevokeOrder)
n += proto.SizeVarint(3<<3 | proto.WireBytes) n += proto.SizeVarint(3<<3 | proto.WireBytes)
...@@ -931,46 +962,47 @@ var _Exchange_serviceDesc = grpc.ServiceDesc{ ...@@ -931,46 +962,47 @@ var _Exchange_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("exchange.proto", fileDescriptor0) } func init() { proto.RegisterFile("exchange.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 649 bytes of a gzipped FileDescriptorProto // 658 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xdd, 0x6a, 0xd4, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xed, 0x6a, 0xd4, 0x4c,
0x14, 0xee, 0xe4, 0xa7, 0xdb, 0x9c, 0x95, 0xad, 0x0e, 0xa2, 0x41, 0x44, 0x96, 0x5c, 0xd4, 0x22, 0x14, 0x6e, 0xbe, 0xba, 0xcd, 0xd9, 0x97, 0xed, 0xeb, 0x20, 0x1a, 0x44, 0x64, 0xc9, 0x8f, 0x5a,
0xba, 0x42, 0x0b, 0xfe, 0x5c, 0x56, 0x2b, 0xb4, 0x50, 0xa9, 0x0e, 0xbe, 0x40, 0x9a, 0x1c, 0xbb, 0x44, 0x57, 0x68, 0xc1, 0x8f, 0x9f, 0xd5, 0x0a, 0x2d, 0x54, 0xaa, 0x83, 0x37, 0x90, 0x26, 0xc7,
0xa1, 0xd9, 0x4d, 0x48, 0x26, 0xa5, 0x8b, 0xaf, 0x20, 0x78, 0xe7, 0x13, 0x28, 0xf8, 0x12, 0xe2, 0x6e, 0x68, 0x76, 0x13, 0x92, 0xd9, 0xd2, 0xc5, 0x5b, 0x10, 0xbc, 0x09, 0x05, 0x6f, 0x42, 0xbc,
0xab, 0xc9, 0x9c, 0x4c, 0x32, 0xd3, 0x1f, 0xa9, 0xa0, 0x7b, 0x97, 0x6f, 0xce, 0x4f, 0xbe, 0x73, 0x03, 0xaf, 0x49, 0xe6, 0xcc, 0x24, 0x33, 0xdb, 0xae, 0x54, 0xd4, 0xfd, 0x97, 0x67, 0xce, 0x47,
0xce, 0x77, 0x66, 0x60, 0x84, 0x67, 0xc9, 0x34, 0x9e, 0x1f, 0xe3, 0xa4, 0xac, 0x0a, 0x59, 0x70, 0x9e, 0x73, 0xce, 0x73, 0x66, 0x60, 0x80, 0x17, 0xe9, 0x38, 0x99, 0x9e, 0xe2, 0xa8, 0xaa, 0x4b,
0x5f, 0x2e, 0x4a, 0xac, 0x23, 0x80, 0xb5, 0x37, 0xda, 0x10, 0x7d, 0x65, 0x30, 0xea, 0xc0, 0x4e, 0x51, 0xb2, 0x40, 0xcc, 0x2b, 0x6c, 0x62, 0x80, 0x8d, 0x57, 0xda, 0x10, 0xff, 0x70, 0x60, 0xd0,
0x22, 0xb3, 0x62, 0xce, 0xb7, 0x01, 0xf2, 0x6c, 0x96, 0xc9, 0xc3, 0x2a, 0xc5, 0x2a, 0x64, 0x63, 0x82, 0xbd, 0x54, 0xe4, 0xe5, 0x94, 0xed, 0x02, 0x14, 0xf9, 0x24, 0x17, 0xc7, 0x75, 0x86, 0x75,
0xb6, 0x39, 0xdc, 0xba, 0x35, 0xa1, 0xd0, 0xc9, 0x41, 0x6f, 0xd8, 0x5b, 0x11, 0x96, 0x1b, 0x7f, 0xe4, 0x0c, 0x9d, 0xed, 0xfe, 0xce, 0x8d, 0x11, 0x85, 0x8e, 0x8e, 0x3a, 0xc3, 0xc1, 0x1a, 0xb7,
0x06, 0xc3, 0x0a, 0x4f, 0x8b, 0x13, 0x6c, 0xa3, 0x5c, 0x8a, 0xe2, 0x3a, 0x4a, 0x18, 0xcb, 0xde, 0xdc, 0xd8, 0x13, 0xe8, 0x4f, 0x92, 0xfa, 0x0c, 0x75, 0x94, 0x4b, 0x51, 0x4c, 0x47, 0xbd, 0x36,
0x8a, 0xb0, 0x1d, 0xf9, 0x08, 0x1c, 0xb9, 0x08, 0x57, 0xc7, 0x6c, 0xd3, 0x17, 0x8e, 0x5c, 0xbc, 0x96, 0x83, 0x35, 0x6e, 0x3b, 0xca, 0xb8, 0x1a, 0xcf, 0xcb, 0x33, 0x54, 0x71, 0xde, 0x42, 0x1c,
0x1a, 0x80, 0x7f, 0x1a, 0xe7, 0x0d, 0x46, 0xdf, 0x18, 0x80, 0xf9, 0x1b, 0x7f, 0x04, 0x41, 0x8e, 0x37, 0x16, 0x19, 0x67, 0x39, 0xb2, 0x01, 0xb8, 0x62, 0x1e, 0xad, 0x0f, 0x9d, 0xed, 0x80, 0xbb,
0x1f, 0xe5, 0x4e, 0x5d, 0xa3, 0xd4, 0x9c, 0x6e, 0xe8, 0xec, 0x74, 0x26, 0x8c, 0x99, 0x3f, 0x06, 0x62, 0xfe, 0xa2, 0x07, 0xc1, 0x79, 0x52, 0xcc, 0x30, 0xfe, 0xec, 0x00, 0x18, 0x96, 0xec, 0x01,
0xa8, 0xb2, 0xe3, 0xa9, 0x76, 0x76, 0xae, 0x70, 0xb6, 0xec, 0xfc, 0x36, 0xf8, 0x65, 0x95, 0x25, 0x84, 0x05, 0xbe, 0x17, 0x7b, 0x4d, 0x83, 0x42, 0xd7, 0xf2, 0x9f, 0xce, 0x4e, 0x67, 0xdc, 0x98,
0x48, 0x9c, 0x1d, 0xd1, 0x02, 0x7e, 0x07, 0x56, 0xe3, 0x59, 0xd1, 0xcc, 0x65, 0xe8, 0x8d, 0xd9, 0xd9, 0x43, 0x80, 0x3a, 0x3f, 0x1d, 0x6b, 0x67, 0x77, 0x89, 0xb3, 0x65, 0x67, 0x37, 0x21, 0xa8,
0xa6, 0x2b, 0x34, 0x52, 0x7c, 0x8b, 0x32, 0xf4, 0x5b, 0xbe, 0x45, 0x19, 0x7d, 0x61, 0x30, 0x7c, 0xea, 0x3c, 0x45, 0xe2, 0xec, 0x72, 0x05, 0xd8, 0x2d, 0x58, 0x4f, 0x26, 0xe5, 0x6c, 0x2a, 0x22,
0x1b, 0x57, 0x27, 0xb8, 0x74, 0x9e, 0x86, 0x91, 0x7b, 0x05, 0x23, 0xaf, 0x67, 0xf4, 0x10, 0x86, 0x7f, 0xe8, 0x6c, 0x7b, 0x5c, 0x23, 0xc9, 0xb7, 0xac, 0xa2, 0x40, 0xf1, 0x2d, 0xab, 0xf8, 0x93,
0x56, 0xbf, 0x79, 0x08, 0x83, 0x42, 0x7d, 0xec, 0xef, 0x12, 0x9d, 0x40, 0x74, 0x30, 0x7a, 0x0e, 0x03, 0x7d, 0xab, 0x2d, 0x2b, 0xe4, 0x69, 0x18, 0x79, 0x4b, 0x18, 0xf9, 0x1d, 0xa3, 0xfb, 0xd0,
0x7e, 0x9f, 0x19, 0xcf, 0x30, 0xd1, 0xc3, 0x0e, 0x84, 0x46, 0xea, 0xbc, 0x5e, 0xcc, 0x8e, 0x8a, 0xb7, 0xfa, 0xcd, 0x22, 0xe8, 0x95, 0xf2, 0xe3, 0x70, 0x9f, 0xe8, 0x84, 0xbc, 0x85, 0xf1, 0x53,
0x9c, 0xb8, 0x05, 0x42, 0xa3, 0xe8, 0x97, 0x03, 0xfe, 0x35, 0xc9, 0x2f, 0x88, 0xc8, 0xf9, 0x6b, 0x08, 0xba, 0xcc, 0x78, 0x81, 0xa9, 0x16, 0x49, 0xc8, 0x35, 0x92, 0xe7, 0xcd, 0x7c, 0x72, 0x52,
0x11, 0xcd, 0x4c, 0x2f, 0x2f, 0x88, 0xc8, 0xea, 0xb2, 0x12, 0x91, 0xe5, 0xa8, 0x45, 0xe4, 0x75, 0x16, 0xc4, 0x2d, 0xe4, 0x1a, 0xc5, 0xdf, 0x5d, 0x08, 0xae, 0x49, 0x7e, 0x49, 0x7c, 0xee, 0x1f,
0x22, 0xe2, 0xf7, 0x60, 0x4d, 0x95, 0xd0, 0x48, 0x4c, 0x69, 0x54, 0xae, 0xe8, 0xb1, 0xa2, 0x7c, 0x89, 0xcf, 0xfb, 0x5d, 0xf1, 0x29, 0x11, 0xf9, 0xad, 0x88, 0xd8, 0x1d, 0xd8, 0x90, 0x25, 0xcc,
0x14, 0xe7, 0xf1, 0x3c, 0x41, 0x52, 0x9d, 0x2b, 0x3a, 0x48, 0xe5, 0xca, 0x58, 0x36, 0x75, 0x38, 0x04, 0x66, 0x34, 0x2a, 0x8f, 0x77, 0x58, 0x52, 0x3e, 0x49, 0x8a, 0x64, 0x9a, 0x22, 0xa9, 0xce,
0xa0, 0x4c, 0x1a, 0x71, 0x0e, 0x5e, 0x9c, 0xa6, 0x55, 0xb8, 0x46, 0x15, 0xd2, 0x37, 0x7f, 0x00, 0xe3, 0x2d, 0xa4, 0x72, 0x45, 0x22, 0x66, 0x4d, 0xd4, 0xa3, 0x4c, 0x1a, 0x31, 0x06, 0x7e, 0x92,
0xd0, 0x94, 0x69, 0x2c, 0xf1, 0x43, 0x36, 0xc3, 0x30, 0xa0, 0x44, 0xd6, 0x89, 0x12, 0x55, 0x36, 0x65, 0x75, 0xb4, 0x41, 0x15, 0xd2, 0x37, 0xbb, 0x07, 0x30, 0xab, 0xb2, 0x44, 0xe0, 0xbb, 0x7c,
0x4f, 0xf1, 0x2c, 0x04, 0x32, 0xb5, 0xc0, 0x88, 0xfb, 0x05, 0x00, 0x31, 0x7f, 0x47, 0x5a, 0xeb, 0x82, 0x51, 0x48, 0x89, 0xac, 0x13, 0x29, 0xaa, 0x7c, 0x9a, 0xe1, 0x45, 0x04, 0x64, 0x52, 0xc0,
0x15, 0xc8, 0x6c, 0x05, 0xf6, 0x29, 0x1c, 0x2b, 0x45, 0xf4, 0x14, 0x06, 0x87, 0xba, 0xc5, 0x23, 0x88, 0xfb, 0x19, 0x00, 0x31, 0x7f, 0x43, 0x5a, 0xeb, 0x14, 0xe8, 0xd8, 0x0a, 0xec, 0x52, 0xb8,
0x70, 0xfa, 0xbe, 0x3b, 0xfb, 0xbb, 0x7f, 0x08, 0xf8, 0xc1, 0xe0, 0xe6, 0xfb, 0x06, 0xab, 0x45, 0x56, 0x8a, 0xf8, 0x31, 0xf4, 0x8e, 0x75, 0x8b, 0x07, 0xe0, 0x76, 0x7d, 0x77, 0x0f, 0xf7, 0x7f,
0xdb, 0xbf, 0x5d, 0x2c, 0xe5, 0x74, 0x89, 0x2a, 0x6d, 0xd5, 0xe8, 0x76, 0x6a, 0x34, 0xb5, 0x79, 0x11, 0xf0, 0xd5, 0x81, 0xff, 0xdf, 0xce, 0xb0, 0x9e, 0xab, 0xfe, 0xed, 0x63, 0x25, 0xc6, 0x2b,
0x17, 0x6a, 0x4b, 0x48, 0xca, 0xed, 0x22, 0xb5, 0x20, 0xfa, 0xde, 0xef, 0xd2, 0xb2, 0x59, 0xfe, 0x54, 0xa9, 0x52, 0xa3, 0xd7, 0xaa, 0xd1, 0xd4, 0xe6, 0x5f, 0xaa, 0x2d, 0x25, 0x29, 0xab, 0x45,
0xdb, 0xce, 0xbf, 0x84, 0x75, 0x8b, 0xe6, 0x41, 0x56, 0x4b, 0xbe, 0x01, 0x5e, 0x9e, 0xd5, 0x8a, 0x52, 0x20, 0xfe, 0xd2, 0xed, 0xd2, 0xaa, 0x59, 0xfe, 0xdd, 0xce, 0x3f, 0x87, 0x4d, 0x8b, 0xe6,
0xa5, 0x7b, 0x49, 0xb2, 0xe4, 0x25, 0xc8, 0x1e, 0xfd, 0x64, 0x70, 0x97, 0xa6, 0xf1, 0xba, 0x98, 0x51, 0xde, 0x08, 0xb6, 0x05, 0x7e, 0x91, 0x37, 0x92, 0xa5, 0x77, 0x45, 0xb2, 0xe4, 0xc5, 0xc9,
0x95, 0x39, 0x4a, 0x4c, 0x69, 0x9a, 0x94, 0x63, 0xa9, 0xe5, 0xb6, 0xca, 0x70, 0x2d, 0x65, 0x98, 0x1e, 0x7f, 0x73, 0xe0, 0x36, 0x4d, 0xe3, 0x65, 0x39, 0xa9, 0x0a, 0x14, 0x98, 0xd1, 0x34, 0x29,
0x21, 0x78, 0xd6, 0x10, 0xf8, 0x7d, 0x08, 0xd2, 0xac, 0x42, 0x7a, 0x0a, 0x74, 0xcd, 0xe6, 0x20, 0xc7, 0x4a, 0xcb, 0x55, 0xca, 0xf0, 0x2c, 0x65, 0x98, 0x21, 0xf8, 0xd6, 0x10, 0xd8, 0x5d, 0x08,
0xda, 0x00, 0x20, 0xfa, 0xd7, 0xdd, 0x2d, 0x9f, 0x19, 0x8c, 0x8c, 0x23, 0x95, 0x67, 0xd6, 0x8b, 0xb3, 0xbc, 0x46, 0x7a, 0x42, 0x74, 0xcd, 0xe6, 0x20, 0xde, 0x02, 0x20, 0xfa, 0xd7, 0xdd, 0x2d,
0x9d, 0x5b, 0xaf, 0x10, 0x06, 0x6a, 0xa5, 0xb0, 0xae, 0xf5, 0x35, 0xd3, 0xc1, 0xff, 0x48, 0xfb, 0x1f, 0x1d, 0x18, 0x18, 0x47, 0x2a, 0xcf, 0xac, 0x97, 0xb3, 0xb0, 0x5e, 0x11, 0xf4, 0xe4, 0x4a,
0x09, 0x04, 0x86, 0xc8, 0xf8, 0xdc, 0xac, 0xba, 0xae, 0x91, 0x5d, 0x4f, 0xe9, 0x13, 0xac, 0x0b, 0x61, 0xd3, 0xe8, 0x6b, 0xa6, 0x85, 0xff, 0x90, 0xf6, 0x23, 0x08, 0x0d, 0x91, 0xe1, 0xc2, 0xac,
0x4c, 0x30, 0x2b, 0x65, 0xf7, 0x34, 0xf2, 0x08, 0xfc, 0xc2, 0x7a, 0x0f, 0xcf, 0x47, 0xb5, 0x26, 0xda, 0xae, 0x91, 0x5d, 0x4f, 0xe9, 0x03, 0x6c, 0x72, 0x4c, 0x31, 0xaf, 0x44, 0xfb, 0xa4, 0xb2,
0x3e, 0x51, 0xd7, 0x97, 0x4c, 0xa6, 0x74, 0xa8, 0xaa, 0xb9, 0x9c, 0xdf, 0x76, 0xb8, 0xba, 0xbe, 0x18, 0x82, 0xd2, 0x7a, 0x47, 0x17, 0xa3, 0x94, 0x89, 0x8d, 0xe4, 0xf5, 0x25, 0xd2, 0x31, 0x1d,
0x2d, 0x50, 0x97, 0x57, 0xfb, 0xd7, 0xa3, 0x55, 0x7a, 0xb7, 0xb7, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xca, 0x6a, 0xae, 0xe6, 0xb7, 0x1d, 0x96, 0xd7, 0xb7, 0x03, 0xf2, 0xf2, 0x52, 0x7f, 0x3d, 0x59,
0xff, 0xe3, 0xe1, 0xf2, 0x06, 0xc9, 0x07, 0x00, 0x00, 0xa7, 0xf7, 0x7e, 0xf7, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb5, 0x7b, 0x52, 0x3b, 0x01, 0x08,
0x00, 0x00,
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment