Skip to content

Commit

Permalink
delete recent price from db when delisting (#753)
Browse files Browse the repository at this point in the history
delete recent price from db when delisting
  • Loading branch information
EnderCrypto authored and unclezoro committed Jul 8, 2020
1 parent 9103d63 commit 1aa1e76
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 12 deletions.
7 changes: 6 additions & 1 deletion plugins/dex/order/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,7 @@ func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAlloc
}

delete(kp.engines, symbol)
delete(kp.recentPrices, symbol)
kp.deleteRecentPrices(ctx, symbol)
kp.mustGetOrderKeeper(symbol).deleteOrdersForPair(symbol)

baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol)
Expand All @@ -955,6 +955,11 @@ func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAlloc
}
}

func (kp *DexKeeper) deleteRecentPrices(ctx sdk.Context, symbol string) {
delete(kp.recentPrices, symbol)
kp.PairMapper.DeleteRecentPrices(ctx, symbol)
}

func (kp *DexKeeper) expireAllOrders(ctx sdk.Context, symbol string) []chan Transfer {
ordersOfSymbol := make(map[string]*OrderInfo)
if dexOrderKeeper, err := kp.getOrderKeeper(symbol); err == nil {
Expand Down
28 changes: 19 additions & 9 deletions plugins/dex/order/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func MakeCodec() *wire.Codec {

cdc.RegisterConcrete(OrderBookSnapshot{}, "dex/OrderBookSnapshot", nil)
cdc.RegisterConcrete(ActiveOrders{}, "dex/ActiveOrders", nil)
cdc.RegisterConcrete(store.RecentPrice{}, "dex/RecentPrice", nil)

return cdc
}
Expand Down Expand Up @@ -546,6 +547,8 @@ func setup() (ctx sdk.Context, mapper auth.AccountKeeper, keeper *DexKeeper) {
cdc := wire.NewCodec()
types.RegisterWire(cdc)
wire.RegisterCrypto(cdc)
cdc.RegisterConcrete(dextypes.TradingPair{}, "dex/TradingPair", nil)
cdc.RegisterConcrete(store.RecentPrice{}, "dex/RecentPrice", nil)
mapper = auth.NewAccountKeeper(cdc, capKey, types.ProtoAppAccount)
accountCache := getAccountCache(cdc, ms, capKey)
pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey)
Expand Down Expand Up @@ -852,6 +855,7 @@ func TestKeeper_DelistTradingPair(t *testing.T) {
keeper.FeeManager.UpdateConfig(NewTestFeeConfig())
_, acc := testutils.NewAccount(ctx, am, 0)
addr := acc.GetAddress()
ctx = ctx.WithBlockHeight(2000)

tradingPair := dextypes.NewTradingPair("XYZ-000", "BNB", 1e8)
keeper.PairMapper.AddTradingPair(ctx, tradingPair)
Expand All @@ -869,30 +873,36 @@ func TestKeeper_DelistTradingPair(t *testing.T) {
am.SetAccount(ctx, acc)

msg := NewNewOrderMsg(addr, "123456", Side.BUY, "XYZ-000_BNB", 1e6, 1e6)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)
msg = NewNewOrderMsg(addr, "1234562", Side.BUY, "XYZ-000_BNB", 1e6, 1e6)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)
msg = NewNewOrderMsg(addr, "123457", Side.BUY, "XYZ-000_BNB", 2e6, 1e6)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)
msg = NewNewOrderMsg(addr, "123458", Side.BUY, "XYZ-000_BNB", 3e6, 1e6)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)
msg = NewNewOrderMsg(addr, "123459", Side.SELL, "XYZ-000_BNB", 5e6, 1e4)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)
msg = NewNewOrderMsg(addr, "123460", Side.SELL, "XYZ-000_BNB", 6e6, 1e4)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)
msg = NewNewOrderMsg(addr, "1234602", Side.SELL, "XYZ-000_BNB", 6e6, 1e4)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)
msg = NewNewOrderMsg(addr, "123461", Side.SELL, "XYZ-000_BNB", 7e6, 1e4)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)
msg = NewNewOrderMsg(addr, "123462", Side.BUY, "XYZ-000_BNB", 4e6, 1e6)
keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false)
keeper.AddOrder(OrderInfo{msg, 2000, 84, 42, 84, 0, "", 0}, false)

lastTradePrices := make(map[string]int64, 1)
lastTradePrices["XYZ-000_BNB"] = 3e6
keeper.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices)
assert.Equal(1, len(keeper.GetAllOrders()))
assert.Equal(9, len(keeper.GetAllOrdersForPair("XYZ-000_BNB")))
assert.Equal(1, len(keeper.engines))
assert.Equal(1, len(keeper.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored)))

keeper.DelistTradingPair(ctx, "XYZ-000_BNB", nil)
assert.Equal(0, len(keeper.GetAllOrders()))
assert.Equal(0, len(keeper.engines))
assert.Equal(0, len(keeper.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored)))

expectFees := sdk.NewFee(sdk.Coins{
sdk.NewCoin("BNB", 10e4),
Expand Down
19 changes: 17 additions & 2 deletions plugins/dex/store/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type TradingPairMapper interface {
ListAllTradingPairs(ctx sdk.Context) []types.TradingPair
UpdateRecentPrices(ctx sdk.Context, pricesStoreEvery, numPricesStored int64, lastTradePrices map[string]int64)
GetRecentPrices(ctx sdk.Context, pricesStoreEvery, numPricesStored int64) map[string]*utils.FixedSizeRing
DeleteRecentPrices(ctx sdk.Context, symbol string)
}

var _ TradingPairMapper = mapper{}
Expand Down Expand Up @@ -157,7 +158,7 @@ func (m mapper) GetRecentPrices(ctx sdk.Context, pricesStoreEvery, numPricesStor
} else {
recordStarted = true
}
prices := m.decodeRecentPrices(bz, numPricesStored)
prices := m.decodeRecentPrices(bz)
numSymbol := len(prices.Pair)
for i := 0; i < numSymbol; i++ {
symbol := prices.Pair[i]
Expand All @@ -172,6 +173,20 @@ func (m mapper) GetRecentPrices(ctx sdk.Context, pricesStoreEvery, numPricesStor
return recentPrices
}

func (m mapper) DeleteRecentPrices(ctx sdk.Context, symbol string) {
store := ctx.KVStore(m.key)
iter := sdk.KVStorePrefixIterator(store, []byte(recentPricesKeyPrefix))
defer iter.Close()

for ; iter.Valid(); iter.Next() {
bz := iter.Value()
prices := m.decodeRecentPrices(bz)
prices.removePair(symbol)
bz = m.cdc.MustMarshalBinaryBare(prices)
store.Set(iter.Key(), bz)
}
}

func (m mapper) encodeRecentPrices(recentPrices map[string]int64) []byte {
value := RecentPrice{}
numSymbol := len(recentPrices)
Expand All @@ -195,7 +210,7 @@ func (m mapper) encodeRecentPrices(recentPrices map[string]int64) []byte {
return bz
}

func (m mapper) decodeRecentPrices(bz []byte, numPricesStored int64) *RecentPrice {
func (m mapper) decodeRecentPrices(bz []byte) *RecentPrice {
value := RecentPrice{}
m.cdc.MustUnmarshalBinaryBare(bz, &value)
return &value
Expand Down
114 changes: 114 additions & 0 deletions plugins/dex/store/mapper_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package store

import (
"path"
"path/filepath"
"runtime"
"testing"

"github.com/stretchr/testify/require"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/db"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"

Expand Down Expand Up @@ -123,3 +127,113 @@ func TestMapper_UpdateRecentPrices(t *testing.T) {
require.Equal(t, int64(5), allRecentPrices["ABC"].Count())
require.Equal(t, []interface{}{int64(10), int64(10), int64(10), int64(10), int64(10)}, allRecentPrices["ABC"].Elements())
}

func TestMapper_DeleteRecentPrices(t *testing.T) {
const numPricesStored = 5
const pairNum = 3
const priceStoreEvery = 2
pairMapper, ctx := setup()
for i := 0; i < 30; i++ {
lastPrices := make(map[string]int64, pairNum)
lastPrices["ABC_BNB"] = 10
lastPrices["ABC_EFG"] = 3
lastPrices["EFG_BNB"] = 3
ctx = ctx.WithBlockHeight(int64(priceStoreEvery * (i + 1)))
pairMapper.UpdateRecentPrices(ctx, priceStoreEvery, numPricesStored, lastPrices)
}

allRecentPrices := pairMapper.GetRecentPrices(ctx, priceStoreEvery, numPricesStored)
require.Equal(t, 3, len(allRecentPrices))
require.Equal(t, int64(5), allRecentPrices["ABC_BNB"].Count())
require.Equal(t, []interface{}{int64(10), int64(10), int64(10), int64(10), int64(10)}, allRecentPrices["ABC_BNB"].Elements())
require.Equal(t, int64(5), allRecentPrices["ABC_EFG"].Count())
require.Equal(t, []interface{}{int64(3), int64(3), int64(3), int64(3), int64(3)}, allRecentPrices["ABC_EFG"].Elements())
require.Equal(t, int64(5), allRecentPrices["ABC_EFG"].Count())
require.Equal(t, []interface{}{int64(3), int64(3), int64(3), int64(3), int64(3)}, allRecentPrices["EFG_BNB"].Elements())

pairMapper.DeleteRecentPrices(ctx, "ABC_EFG")
allRecentPrices = pairMapper.GetRecentPrices(ctx, priceStoreEvery, numPricesStored)
require.Equal(t, 2, len(allRecentPrices))
require.Equal(t, int64(5), allRecentPrices["ABC_BNB"].Count())
require.Equal(t, []interface{}{int64(10), int64(10), int64(10), int64(10), int64(10)}, allRecentPrices["ABC_BNB"].Elements())
require.Equal(t, int64(5), allRecentPrices["EFG_BNB"].Count())
require.Equal(t, []interface{}{int64(3), int64(3), int64(3), int64(3), int64(3)}, allRecentPrices["EFG_BNB"].Elements())
}

func TestMapper_DeleteOneRecentPrices(t *testing.T) {
const numPricesStored = 10
const pairNum = 1
const priceStoreEvery = 2
pairMapper, ctx := setup()
for i := 0; i < numPricesStored; i++ {
lastPrices := make(map[string]int64, pairNum)
if i < 5 {
lastPrices["ABC_BNB"] = 10
}
ctx = ctx.WithBlockHeight(int64(2 * (i + 1)))
pairMapper.UpdateRecentPrices(ctx, priceStoreEvery, numPricesStored, lastPrices)
}
allRecentPrices := pairMapper.GetRecentPrices(ctx, priceStoreEvery, numPricesStored)
require.Equal(t, 1, len(allRecentPrices))
require.Equal(t, int64(5), allRecentPrices["ABC_BNB"].Count())
require.Equal(t, []interface{}{int64(10), int64(10), int64(10), int64(10), int64(10)}, allRecentPrices["ABC_BNB"].Elements())

pairMapper.DeleteRecentPrices(ctx, "ABC_BNB")
allRecentPrices = pairMapper.GetRecentPrices(ctx, priceStoreEvery, numPricesStored)
require.Equal(t, 0, len(allRecentPrices))

//allowed to delete again
pairMapper.DeleteRecentPrices(ctx, "ABC_BNB")
allRecentPrices = pairMapper.GetRecentPrices(ctx, priceStoreEvery, numPricesStored)
require.Equal(t, 0, len(allRecentPrices))
}

func BenchmarkMapper_DeleteRecentPrices(b *testing.B) {
db, pairMapper, ctx := setupForBenchTest()
defer db.Close()
b.ResetTimer()
for i := 0; i < b.N; i++ {
pairMapper.DeleteRecentPrices(ctx, string(i)+"_"+string(i))
}
}

func setupForBenchTest() (dbm.DB, TradingPairMapper, sdk.Context) {
const numPricesStored = 2000
const pairNum = 500
const priceStoreEvery = 1000
db, ms, key := setupLevelDbMultiStore()
ctx := sdk.NewContext(ms, abci.Header{Height: 1}, sdk.RunTxModeDeliver, log.NewNopLogger())
var cdc = wire.NewCodec()
cdc.RegisterConcrete(dextypes.TradingPair{}, "dex/TradingPair", nil)
cdc.RegisterConcrete(RecentPrice{}, "dex/RecentPrice", nil)
pairMapper := NewTradingPairMapper(cdc, key)
for i := 0; i < pairNum; i++ {
tradingPair := dextypes.NewTradingPair(string(i), string(i), 102000)
pairMapper.AddTradingPair(ctx, tradingPair)
}

for i := 0; i < numPricesStored; i++ {
lastPrices := make(map[string]int64, pairNum)
for j := 0; j < pairNum; j++ {
lastPrices[string(j)+"_"+string(j)] = 8
}
ctx = ctx.WithBlockHeight(int64(priceStoreEvery * (i + 1)))
pairMapper.UpdateRecentPrices(ctx, priceStoreEvery, numPricesStored, lastPrices)
}

return db, pairMapper, ctx
}

func setupLevelDbMultiStore() (dbm.DB, sdk.MultiStore, *sdk.KVStoreKey) {
_, b, _, _ := runtime.Caller(0)
basePath := filepath.Dir(b)
db, err := db.NewGoLevelDB("test", path.Join(basePath, "data"))
if err != nil {
panic(err)
}
key := sdk.NewKVStoreKey("pair")
ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
ms.LoadLatestVersion()
return db, ms, key
}
12 changes: 12 additions & 0 deletions plugins/dex/store/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,15 @@ type RecentPrice struct {
Pair []string
Price []int64
}

func (prices *RecentPrice) removePair(symbolToDelete string) {
numSymbol := len(prices.Pair)
for i := 0; i < numSymbol; i++ {
symbol := prices.Pair[i]
if symbol == symbolToDelete {
prices.Pair = append(prices.Pair[:i], prices.Pair[i+1:]...)
prices.Price = append(prices.Price[:i], prices.Price[i+1:]...)
break
}
}
}

0 comments on commit 1aa1e76

Please sign in to comment.