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

add exchange_test.go

parent ef710316
......@@ -35,7 +35,8 @@ func NewAction(e *exchange, tx *types.Transaction, index int) *Action {
//GetIndex get index
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
......@@ -66,9 +67,9 @@ func (a *Action) calcActualCost(op int32, amount int64, price float32) int64 {
return amount
}
//price 精度允许范围小数点后面7位数,整数是1e8
//price 精度允许范围小数点后面7位数,0<price<1e8
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 true
......@@ -122,7 +123,7 @@ func (a *Action) LimitOrder(payload *et.LimitOrder) (*types.Receipt, error) {
if !types.CheckAmount(payload.GetAmount()) {
return nil, et.ErrAssetAmount
}
if CheckPrice(payload.GetPrice()) {
if !CheckPrice(payload.GetPrice()) {
return nil, et.ErrAssetPrice
}
if !CheckOp(payload.GetOp()) {
......@@ -188,7 +189,7 @@ func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) {
if err != nil {
return nil, err
}
amount := int64(float32(balance) * price)
amount := a.calcActualCost(et.OpBuy, balance, price)
rightAccount := rightAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if rightAccount.Frozen < amount {
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) {
if err != nil {
return nil, err
}
amount := balance
amount := a.calcActualCost(et.OpBuy, balance, price)
leftAccount := leftAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if leftAccount.Frozen < amount {
elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
......@@ -281,10 +282,29 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
}
//TODO 这里得逻辑是否需要调整?当匹配的单数过多,会导致receipt日志数量激增,理论上存在日志存储攻击,需要加下最大匹配深度,防止这种攻击发生
if matchorder.GetBalance() >= or.GetBalance() {
if payload.Op == et.OpSell {
//转移冻结资产
receipt, err := rightAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()))
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())
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...)
}
if payload.Op == et.OpBuy {
//转移冻结资产
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()), "err", err.Error())
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...)
......@@ -297,9 +317,9 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
// match receiptorder
matchorder.Balance = matchorder.GetBalance() - or.GetBalance()
matchorder.Executed = matchorder.Executed + or.GetBalance()
}
// match receiptorder,涉及赋值先手顺序,代码顺序不可变
matchorder.Status = func(a, b int64) int32 {
if a > b {
return et.Ordered
......@@ -307,12 +327,15 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
return et.Completed
}
}(matchorder.GetBalance(), or.GetBalance())
matchorder.Balance = matchorder.GetBalance() - or.GetBalance()
matchorder.Executed = matchorder.Executed + or.GetBalance()
a.updateStateDBCache(matchorder)
kvs = append(kvs, a.GetKVSet(matchorder)...)
or.Balance = 0
or.Executed = or.Executed + or.GetBalance()
or.Status = et.Completed
or.Balance = 0
//update receipt order
re.Order = or
re.MatchOrders = append(re.MatchOrders, matchorder)
......@@ -325,10 +348,29 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
receipts := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
return receipts, nil
} else {
if payload.Op == et.OpSell {
//转移冻结资产
receipt, err := rightAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()))
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())
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...)
}
if payload.Op == et.OpBuy {
//转移冻结资产
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error())
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...)
......@@ -341,23 +383,23 @@ func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAcc
}
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
matchorder.Balance = 0
matchorder.Executed = matchorder.Executed + matchorder.GetBalance()
matchorder.Status = et.Completed
matchorder.Balance = 0
a.updateStateDBCache(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.MatchOrders = append(re.MatchOrders, matchorder)
a.updateStateDBCache(or)
}
}
//查询数据不满足5条说明没有了,跳出循环
......
package executor
import (
"fmt"
"github.com/33cn/chain33/types"
exchangetypes "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
......@@ -11,19 +12,16 @@ import (
*/
func (e *exchange) Exec_LimitOrder(payload *exchangetypes.LimitOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
action := NewAction(e, tx, index)
return action.LimitOrder(payload)
}
func (e *exchange) Exec_MarketOrder(payload *exchangetypes.MarketOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
//TODO marketOrder
return nil, fmt.Errorf("%s", "not support MarketOrder..")
}
func (e *exchange) Exec_RevokeOrder(payload *exchangetypes.RevokeOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
action := NewAction(e, tx, index)
return action.RevokeOrder(payload)
}
......@@ -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) {
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
}
func (e *exchange) ExecLocal_RevokeOrder(payload *exchangetypes.RevokeOrder, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
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
}
......@@ -66,8 +90,10 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
markDepth.RightAsset = right
markDepth.Op = op
markDepth.Amount = receipt.Order.Balance
}
} else {
markDepth.Amount = markDepth.Amount + receipt.Order.Balance
}
//marketDepth
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, op, price), Value: types.Encode(&markDepth)})
//orderID
......@@ -78,23 +104,23 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
if len(receipt.MatchOrders) > 0 {
//撮合交易更新
var balance int64
for _, matchOrder := range receipt.MatchOrders {
for i, matchOrder := range receipt.MatchOrders {
if matchOrder.Status == exchangetypes.Completed {
// 删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, matchOrder.GetLimitOrder().Op, price, matchOrder.Index), Value: nil})
//删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, matchOrder.Addr, matchOrder.Index), Value: nil})
//更新状态为已完成,索引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
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 {
//只需统一更改市场深度状态,其他不需要处理
balance = balance + matchOrder.Balance
}
}
//更改市场深度
//更改匹配市场深度
var matchDepth exchangetypes.MarketDepth
err = findObject(e.GetLocalDB(), calcMarketDepthKey(left, right, OpSwap(op), price), &matchDepth)
if err == types.ErrNotFound {
......@@ -103,10 +129,15 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
matchDepth.RightAsset = right
matchDepth.Op = OpSwap(op)
matchDepth.Amount = balance
}
} else {
matchDepth.Amount = matchDepth.Amount - receipt.Order.Executed
}
//marketDepth
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
case exchangetypes.Completed:
......@@ -121,19 +152,22 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
//user orderID
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 {
//撮合交易更新
var balance int64
for _, matchOrder := range receipt.MatchOrders {
for i, matchOrder := range receipt.MatchOrders {
if matchOrder.Status == exchangetypes.Completed {
// 删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, matchOrder.GetLimitOrder().Op, price, matchOrder.Index), Value: nil})
//删除原有状态orderID
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
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 {
......@@ -150,10 +184,15 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
matchDepth.RightAsset = right
matchDepth.Op = OpSwap(op)
matchDepth.Amount = balance
}
} else {
matchDepth.Amount = matchDepth.Amount - receipt.Order.Executed
}
//marketDepth
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
case exchangetypes.Revoked:
......@@ -170,8 +209,14 @@ func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*t
if err == nil {
//marketDepth
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)})
}
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
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, op, price, receipt.GetOrder().Index), Value: nil})
//删除原有状态orderID
......
......@@ -45,14 +45,15 @@ func calcMarketDepthOrderPrefix(left, right *types.Asset, op int32, price float3
// localdb中存储市场挂单ID
func calcMarketDepthOrderKey(left, right *types.Asset, op int32, price float32, index int64) []byte {
// 设置精度为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)
}
//最新已经成交的订单,这里状态固定都是完成状态,这个主要给外部使用,可以查询最新得成交信息
//最新已经成交的订单,这里状态固定都是完成状态,这个主要给外部使用,可以查询最新得成交信息,存在多个情况
//matchOrderIndex,是匹配order在数组中的index,这里预留4个0000,用来解决同一笔交易中存在key重复得情况,这样设计保证了key得唯一性
func calcCompletedOrderKey(left, right *types.Asset, index int64) []byte {
// 设置精度为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)
}
func calcCompletedOrderPrefix(left, right *types.Asset) []byte {
......@@ -66,7 +67,8 @@ func calcUserOrderIDPrefix(status int32, addr string) []byte {
key := fmt.Sprintf("%s"+"addr:%s:%d:", KeyPrefixLocalDB, addr, status)
return []byte(key)
}
//matchOrderIndex,用来解决同一笔交易中存在key重复得情况,这样设计保证了key得唯一性
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)
}
......@@ -16,9 +16,6 @@ func (s *exchange) Query_QueryMarketDepth(in *et.QueryMarketDepth) (types.Messag
if !CheckExchangeAsset(in.LeftAsset, in.RightAsset) {
return nil, et.ErrAsset
}
if !CheckPrice(in.Price) {
return nil, et.ErrAssetPrice
}
if !CheckOp(in.Op) {
return nil, et.ErrAssetOp
......
......@@ -7,7 +7,7 @@ message Exchange {
message ExchangeAction {
oneof value {
LimitOrder limitOrder = 1;
// MarketOrder marketOrder = 2;
MarketOrder marketOrder = 2;
RevokeOrder revokeOrder = 3;
}
int32 ty = 6;
......
This diff is collapsed.
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