From 3bafddec08e35904e9b1d5c90c029af1bf29fcca Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 23 Mar 2020 20:08:18 +0800 Subject: [PATCH 01/96] add mini_token type --- common/types/mini_token.go | 153 ++++++++++++++++++++++++++++ plugins/miniTokens/store/mapper.go | 155 +++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 common/types/mini_token.go create mode 100644 plugins/miniTokens/store/mapper.go diff --git a/common/types/mini_token.go b/common/types/mini_token.go new file mode 100644 index 000000000..1f9bda2de --- /dev/null +++ b/common/types/mini_token.go @@ -0,0 +1,153 @@ +package types + +import ( + "bytes" + "errors" + "fmt" + "regexp" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/utils" +) + +const ( + MiniTokenSymbolMaxLen = 8 + MiniTokenSymbolMinLen = 3 + MiniTokenSymbolSuffixLen = 4 // probably enough. if it collides (unlikely) the issuer can just use another tx. + MiniTokenSymbolMSuffix = "M" + + MiniTokenDecimals int8 = 8 + MiniTokenMaxTotalSupply int64 = 10000000000000 // 90 billions with 8 decimal digits + + MiniTokenSupplyRange1UpperBound int64 = 1000000000000 +) + +type MiniToken struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + OrigSymbol string `json:"original_symbol"` + MaxTotalSupply utils.Fixed8 `json:"max_total_supply"` + TotalSupply utils.Fixed8 `json:"total_supply"` + Owner sdk.AccAddress `json:"owner"` + Mintable bool `json:"mintable"` + TokenURI string `json:"token_uri"` //TODO set max length +} + +func NewMiniToken(name, symbol string, maxTotalSupply int64, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken, error) { + // double check that the symbol is suffixed + if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { + return nil, err + } + parts, err := splitSuffixedMiniTokenSymbol(symbol) + if err != nil { + return nil, err + } + return &MiniToken{ + Name: name, + Symbol: symbol, + OrigSymbol: parts[0], + MaxTotalSupply: utils.Fixed8(maxTotalSupply), + TotalSupply: utils.Fixed8(totalSupply), + Owner: owner, + Mintable: mintable, + TokenURI: tokenURI, + }, nil +} + +func (token *MiniToken) IsOwner(addr sdk.AccAddress) bool { return bytes.Equal(token.Owner, addr) } +func (token MiniToken) String() string { + return fmt.Sprintf("{Name: %v, Symbol: %v, MaxTotalSupply: %v, TotalSupply: %v, Owner: %X, Mintable: %v, TokenURI: %v}", + token.Name, token.Symbol, token.MaxTotalSupply, token.TotalSupply, token.Owner, token.Mintable, token.TokenURI) +} + +// Token Validation + +func ValidateMiniToken(token MiniToken) error { + if err := ValidateMapperMiniTokenSymbol(token.Symbol); err != nil { + return err + } + if err := ValidateIssueMsgMiniTokenSymbol(token.OrigSymbol); err != nil { + return err + } + return nil +} + +func ValidateIssueMsgMiniTokenSymbol(symbol string) error { + if len(symbol) == 0 { + return errors.New("token symbol cannot be empty") + } + + // check len without suffix + if symbolLen := len(symbol); symbolLen > MiniTokenSymbolMaxLen || symbolLen < MiniTokenSymbolMinLen { + return errors.New("length of token symbol is limited to 3~8") + } + + if !utils.IsAlphaNum(symbol) { + return errors.New("token symbol should be alphanumeric") + } + + return nil +} + +func ValidateMapperMiniTokenSymbol(symbol string) error { + if len(symbol) == 0 { + return errors.New("suffixed token symbol cannot be empty") + } + + parts, err := splitSuffixedMiniTokenSymbol(symbol) + if err != nil { + return err + } + + symbolPart := parts[0] + + // check len without suffix + if len(symbolPart) < MiniTokenSymbolMinLen { + return fmt.Errorf("mini token symbol part is too short, got %d chars", len(symbolPart)) + } + if len(symbolPart) > MiniTokenSymbolMaxLen { + return fmt.Errorf("mini token symbol part is too long, got %d chars", len(symbolPart)) + } + + if !utils.IsAlphaNum(symbolPart) { + return errors.New("mini token symbol part should be alphanumeric") + } + + suffixPart := parts[1] + + if len(suffixPart) != MiniTokenSymbolSuffixLen { + return fmt.Errorf("mini token symbol suffix must be %d chars in length, got %d", MiniTokenSymbolSuffixLen, len(suffixPart)) + } + + if suffixPart[len(suffixPart)-1:] != "M" { + return fmt.Errorf("mini token symbol suffix must end with M") + } + + // prohibit non-hexadecimal chars in the suffix part + isHex, err := regexp.MatchString(fmt.Sprintf("[0-9A-F]{%d}M", MiniTokenSymbolSuffixLen-1), suffixPart) + if err != nil { + return err + } + if !isHex { + return fmt.Errorf("mini token symbol tx hash suffix must be hex with a length of %d", MiniTokenSymbolSuffixLen-1) + } + + return nil +} + +func splitSuffixedMiniTokenSymbol(suffixed string) ([]string, error) { + + split := strings.SplitN(suffixed, "-", 2) + + if len(split) != 2 { + return nil, errors.New("suffixed mini token symbol must contain a hyphen ('-')") + } + + if strings.Contains(split[1], "-") { + return nil, errors.New("suffixed mini token symbol must contain just one hyphen ('-')") + } + + return split, nil +} diff --git a/plugins/miniTokens/store/mapper.go b/plugins/miniTokens/store/mapper.go new file mode 100644 index 000000000..d1c27ffcd --- /dev/null +++ b/plugins/miniTokens/store/mapper.go @@ -0,0 +1,155 @@ +package store + +import ( + "errors" + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/utils" + "github.com/binance-chain/node/wire" +) + +type Tokens []types.Token + +func (t Tokens) GetSymbols() *[]string { + var symbols []string + for _, token := range t { + symbols = append(symbols, token.Symbol) + } + return &symbols +} + +type Mapper interface { + NewToken(ctx sdk.Context, token types.Token) error + Exists(ctx sdk.Context, symbol string) bool + ExistsCC(ctx context.CLIContext, symbol string) bool + GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool) Tokens + GetToken(ctx sdk.Context, symbol string) (types.Token, error) + // we do not provide the updateToken method + UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) error +} + +var _ Mapper = mapper{} + +type mapper struct { + key sdk.StoreKey + cdc *wire.Codec +} + +func NewMapper(cdc *wire.Codec, key sdk.StoreKey) mapper { + return mapper{ + key: key, + cdc: cdc, + } +} + +func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.Token, error) { + store := ctx.KVStore(m.key) + key := []byte(strings.ToUpper(symbol)) + + bz := store.Get(key) + if bz != nil { + return m.decodeToken(bz), nil + } + + return types.Token{}, fmt.Errorf("token(%v) not found", symbol) +} + +func (m mapper) GetTokenCC(ctx context.CLIContext, symbol string) (types.Token, error) { + key := []byte(strings.ToUpper(symbol)) + bz, err := ctx.QueryStore(key, common.TokenStoreName) + if err != nil { + return types.Token{}, err + } + if bz != nil { + return m.decodeToken(bz), nil + } + return types.Token{}, fmt.Errorf("token(%v) not found", symbol) +} + +func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool) Tokens { + var res Tokens + store := ctx.KVStore(m.key) + iter := store.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + token := m.decodeToken(iter.Value()) + if !showZeroSupplyTokens && token.TotalSupply.ToInt64() == 0 { + continue + } + res = append(res, token) + } + return res +} + +func (m mapper) Exists(ctx sdk.Context, symbol string) bool { + store := ctx.KVStore(m.key) + key := []byte(strings.ToUpper(symbol)) + return store.Has(key) +} + +func (m mapper) ExistsCC(ctx context.CLIContext, symbol string) bool { + key := []byte(strings.ToUpper(symbol)) + bz, err := ctx.QueryStore(key, common.TokenStoreName) + if err != nil { + return false + } + if bz != nil { + return true + } + return false +} + +func (m mapper) NewToken(ctx sdk.Context, token types.Token) error { + symbol := token.Symbol + if err := types.ValidateToken(token); err != nil { + return err + } + key := []byte(strings.ToUpper(symbol)) + store := ctx.KVStore(m.key) + value := m.encodeToken(token) + store.Set(key, value) + return nil +} + +func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) error { + if len(symbol) == 0 { + return errors.New("symbol cannot be empty") + } + + key := []byte(strings.ToUpper(symbol)) + store := ctx.KVStore(m.key) + bz := store.Get(key) + if bz == nil { + return errors.New("token does not exist") + } + + toBeUpdated := m.decodeToken(bz) + + if toBeUpdated.TotalSupply.ToInt64() != supply { + toBeUpdated.TotalSupply = utils.Fixed8(supply) + store.Set(key, m.encodeToken(toBeUpdated)) + } + return nil +} + +func (m mapper) encodeToken(token types.Token) []byte { + bz, err := m.cdc.MarshalBinaryBare(token) + if err != nil { + panic(err) + } + return bz +} + +func (m mapper) decodeToken(bz []byte) (token types.Token) { + err := m.cdc.UnmarshalBinaryBare(bz, &token) + if err != nil { + panic(err) + } + return +} From c1cbdab15f3c38d248c7772768389133d0d1e1a8 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 25 Mar 2020 13:48:11 +0800 Subject: [PATCH 02/96] complete minitoken issue --- admin/tx.go | 2 + app/app.go | 6 + app/config/config.go | 5 + app/pub/helpers.go | 3 + cmd/bnbcli/main.go | 2 + common/stores.go | 5 + common/types/mini_token.go | 17 +- common/upgrade/upgrade.go | 1 + plugins/api/server.go | 6 +- plugins/miniTokens/abci.go | 118 ++++++++++++ plugins/miniTokens/client/cli/commands.go | 33 ++++ plugins/miniTokens/client/cli/helper.go | 62 +++++++ plugins/miniTokens/client/cli/issue.go | 140 +++++++++++++++ plugins/miniTokens/issue/handler.go | 208 ++++++++++++++++++++++ plugins/miniTokens/issue/handler_test.go | 112 ++++++++++++ plugins/miniTokens/issue/msg.go | 160 +++++++++++++++++ plugins/miniTokens/mini_tokens.go | 5 + plugins/miniTokens/plugin.go | 27 +++ plugins/miniTokens/route.go | 15 ++ plugins/miniTokens/store/mapper.go | 76 +++++--- plugins/miniTokens/wire.go | 12 ++ plugins/param/genesis.go | 5 + plugins/param/plugin.go | 12 ++ plugins/param/types/types.go | 4 + 24 files changed, 1009 insertions(+), 27 deletions(-) create mode 100644 plugins/miniTokens/abci.go create mode 100644 plugins/miniTokens/client/cli/commands.go create mode 100644 plugins/miniTokens/client/cli/helper.go create mode 100644 plugins/miniTokens/client/cli/issue.go create mode 100644 plugins/miniTokens/issue/handler.go create mode 100644 plugins/miniTokens/issue/handler_test.go create mode 100644 plugins/miniTokens/issue/msg.go create mode 100644 plugins/miniTokens/mini_tokens.go create mode 100644 plugins/miniTokens/plugin.go create mode 100644 plugins/miniTokens/route.go create mode 100644 plugins/miniTokens/wire.go diff --git a/admin/tx.go b/admin/tx.go index 49633a4de..42cefc741 100644 --- a/admin/tx.go +++ b/admin/tx.go @@ -12,6 +12,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" "github.com/binance-chain/node/plugins/tokens/timelock" + miniIssue "github.com/binance-chain/node/plugins/miniTokens/issue" ) var transferOnlyModeBlackList = []string{ @@ -25,6 +26,7 @@ var transferOnlyModeBlackList = []string{ timelock.TimeLockMsg{}.Type(), timelock.TimeUnlockMsg{}.Type(), timelock.TimeRelockMsg{}.Type(), + miniIssue.IssueMsg{}.Type(), } var TxBlackList = map[runtime.Mode][]string{ diff --git a/app/app.go b/app/app.go index d30578dcf..c0e2197e8 100644 --- a/app/app.go +++ b/app/app.go @@ -40,6 +40,8 @@ import ( "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/ico" + "github.com/binance-chain/node/plugins/miniTokens" + miniTkstore "github.com/binance-chain/node/plugins/miniTokens/store" "github.com/binance-chain/node/plugins/param" "github.com/binance-chain/node/plugins/param/paramhub" "github.com/binance-chain/node/plugins/tokens" @@ -81,6 +83,7 @@ type BinanceChain struct { DexKeeper *dex.DexKeeper AccountKeeper auth.AccountKeeper TokenMapper tkstore.Mapper + MiniTokenMapper miniTkstore.MiniTokenMapper ValAddrCache *ValAddrCache stakeKeeper stake.Keeper govKeeper gov.Keeper @@ -128,6 +131,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp // mappers app.AccountKeeper = auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) app.TokenMapper = tkstore.NewMapper(cdc, common.TokenStoreKey) + app.MiniTokenMapper = miniTkstore.NewMiniTokenMapper(cdc, common.MiniTokenStoreKey) app.CoinKeeper = bank.NewBaseKeeper(app.AccountKeeper) app.ParamHub = paramhub.NewKeeper(cdc, common.ParamsStoreKey, common.TParamsStoreKey) tradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.PairStoreKey) @@ -253,6 +257,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp // setUpgradeConfig will overwrite default upgrade config func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // register upgrade height + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP6, upgradeConfig.BEP69Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP6, upgradeConfig.BEP6Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP9, upgradeConfig.BEP9Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP10, upgradeConfig.BEP10Height) @@ -329,6 +334,7 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { func (app *BinanceChain) initPlugins() { tokens.InitPlugin(app, app.TokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) + miniTokens.InitPlugin(app, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper) dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.AccountKeeper, app.govKeeper) param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) diff --git a/app/config/config.go b/app/config/config.go index 581bae02b..d25c20100 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -47,6 +47,8 @@ orderKeeperConcurrency = {{ .BaseConfig.OrderKeeperConcurrency }} breatheBlockDaysCountBack = {{ .BaseConfig.BreatheBlockDaysCountBack }} [upgrade] +# Block height of BEP69 upgrade +BEP69Height = {{ .UpgradeConfig.BEP69Height }} # Block height of BEP6 upgrade BEP6Height = {{ .UpgradeConfig.BEP6Height }} # Block height of BEP9 upgrade @@ -350,6 +352,8 @@ func defaultBaseConfig() *BaseConfig { } type UpgradeConfig struct { + + BEP69Height int64 `mapstructure:"BEP69Height"` // Galileo Upgrade BEP6Height int64 `mapstructure:"BEP6Height"` BEP9Height int64 `mapstructure:"BEP9Height"` @@ -369,6 +373,7 @@ type UpgradeConfig struct { func defaultUpgradeConfig() *UpgradeConfig { // make the upgraded functions enabled by default return &UpgradeConfig{ + BEP69Height: 1, BEP6Height: 1, BEP9Height: 1, BEP10Height: 1, diff --git a/app/pub/helpers.go b/app/pub/helpers.go index dfd7ec216..74c19744b 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -17,6 +17,7 @@ import ( "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/types" orderPkg "github.com/binance-chain/node/plugins/dex/order" + miniIssue "github.com/binance-chain/node/plugins/miniTokens/issue" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" @@ -128,6 +129,8 @@ func GetBlockPublished(pool *sdk.Pool, header abci.Header, blockHash []byte) *Bl case freeze.UnfreezeMsg: txAsset = msg.Symbol // will not cover timelock, timeUnlock, timeRelock, atomic Swap + case miniIssue.IssueMsg: + txAsset = msg.Symbol } transactionsToPublish = append(transactionsToPublish, Transaction{ TxHash: txhash, diff --git a/cmd/bnbcli/main.go b/cmd/bnbcli/main.go index 7b4ba81b3..cc8727fe7 100644 --- a/cmd/bnbcli/main.go +++ b/cmd/bnbcli/main.go @@ -21,6 +21,7 @@ import ( accountcmd "github.com/binance-chain/node/plugins/account/client/cli" apiserv "github.com/binance-chain/node/plugins/api" dexcmd "github.com/binance-chain/node/plugins/dex/client/cli" + miniTokencmd "github.com/binance-chain/node/plugins/miniTokens/client/cli" paramcmd "github.com/binance-chain/node/plugins/param/client/cli" tokencmd "github.com/binance-chain/node/plugins/tokens/client/cli" "github.com/binance-chain/node/version" @@ -87,6 +88,7 @@ func main() { accountcmd.AddCommands(rootCmd, cdc) dexcmd.AddCommands(rootCmd, cdc) paramcmd.AddCommands(rootCmd, cdc) + miniTokencmd.AddCommands(rootCmd, cdc) // stake cmds rootCmd.AddCommand( diff --git a/common/stores.go b/common/stores.go index b39b69381..57ec9ec94 100644 --- a/common/stores.go +++ b/common/stores.go @@ -7,6 +7,7 @@ const ( AccountStoreName = "acc" ValAddrStoreName = "val" TokenStoreName = "tokens" + MiniTokenStoreName = "miniTokens" DexStoreName = "dex" PairStoreName = "pairs" StakeStoreName = "stake" @@ -36,6 +37,8 @@ var ( TStakeStoreKey = sdk.NewTransientStoreKey(StakeTransientStoreName) TParamsStoreKey = sdk.NewTransientStoreKey(ParamsTransientStoreName) + MiniTokenStoreKey = sdk.NewKVStoreKey(MiniTokenStoreName) + StoreKeyNameMap = map[string]sdk.StoreKey{ MainStoreName: MainStoreKey, AccountStoreName: AccountStoreKey, @@ -50,6 +53,7 @@ var ( AtomicSwapStoreName: AtomicSwapStoreKey, StakeTransientStoreName: TStakeStoreKey, ParamsTransientStoreName: TParamsStoreKey, + MiniTokenStoreName: MiniTokenStoreKey, } NonTransientStoreKeyNames = []string{ @@ -64,6 +68,7 @@ var ( GovStoreName, TimeLockStoreName, AtomicSwapStoreName, + MiniTokenStoreName, } ) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 1f9bda2de..3c52562fc 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -16,10 +16,12 @@ const ( MiniTokenSymbolMaxLen = 8 MiniTokenSymbolMinLen = 3 MiniTokenSymbolSuffixLen = 4 // probably enough. if it collides (unlikely) the issuer can just use another tx. + MiniTokenSymbolTxHashSuffixLen = 3 // probably enough. if it collides (unlikely) the issuer can just use another tx. MiniTokenSymbolMSuffix = "M" - MiniTokenDecimals int8 = 8 - MiniTokenMaxTotalSupply int64 = 10000000000000 // 90 billions with 8 decimal digits + MiniTokenDecimals int8 = 8 + MiniTokenMinTotalSupply int64 = 100000000 // 100k with 8 decimal digits + MiniTokenMaxTotalSupplyUpperBound int64 = 10000000000000 // 100k with 8 decimal digits MiniTokenSupplyRange1UpperBound int64 = 1000000000000 ) @@ -56,6 +58,13 @@ func NewMiniToken(name, symbol string, maxTotalSupply int64, totalSupply int64, }, nil } +func IsMiniTokenSymbol(symbol string) bool{ + if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { + return false + } + return true +} + func (token *MiniToken) IsOwner(addr sdk.AccAddress) bool { return bytes.Equal(token.Owner, addr) } func (token MiniToken) String() string { return fmt.Sprintf("{Name: %v, Symbol: %v, MaxTotalSupply: %v, TotalSupply: %v, Owner: %X, Mintable: %v, TokenURI: %v}", @@ -126,12 +135,12 @@ func ValidateMapperMiniTokenSymbol(symbol string) error { } // prohibit non-hexadecimal chars in the suffix part - isHex, err := regexp.MatchString(fmt.Sprintf("[0-9A-F]{%d}M", MiniTokenSymbolSuffixLen-1), suffixPart) + isHex, err := regexp.MatchString(fmt.Sprintf("[0-9A-F]{%d}M", MiniTokenSymbolTxHashSuffixLen), suffixPart) if err != nil { return err } if !isHex { - return fmt.Errorf("mini token symbol tx hash suffix must be hex with a length of %d", MiniTokenSymbolSuffixLen-1) + return fmt.Errorf("mini token symbol tx hash suffix must be hex with a length of %d", MiniTokenSymbolTxHashSuffixLen) } return nil diff --git a/common/upgrade/upgrade.go b/common/upgrade/upgrade.go index c1ecba7de..e8ce39018 100644 --- a/common/upgrade/upgrade.go +++ b/common/upgrade/upgrade.go @@ -8,6 +8,7 @@ var Mgr = sdk.UpgradeMgr // bugfix: fix // improvement: (maybe bep ?) const ( + BEP69 = "BEP69" //FIXME placeholder // Galileo Upgrade BEP6 = "BEP6" // https://github.com/binance-chain/BEPs/pull/6 BEP9 = "BEP9" // https://github.com/binance-chain/BEPs/pull/9 diff --git a/plugins/api/server.go b/plugins/api/server.go index a9f59876f..f03788b05 100644 --- a/plugins/api/server.go +++ b/plugins/api/server.go @@ -5,9 +5,10 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" keyscli "github.com/cosmos/cosmos-sdk/client/keys" - keys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/binance-chain/node/common" + miniTkstore "github.com/binance-chain/node/plugins/miniTokens/store" tkstore "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) @@ -30,6 +31,8 @@ type server struct { tokens tkstore.Mapper accStoreName string + + miniTokens miniTkstore.MiniTokenMapper } // NewServer provides a new server structure. @@ -47,5 +50,6 @@ func newServer(ctx context.CLIContext, cdc *wire.Codec) *server { keyBase: kb, tokens: tkstore.NewMapper(cdc, common.TokenStoreKey), accStoreName: common.AccountStoreName, + miniTokens: miniTkstore.NewMiniTokenMapper(cdc, common.MiniTokenStoreKey), } } diff --git a/plugins/miniTokens/abci.go b/plugins/miniTokens/abci.go new file mode 100644 index 000000000..5d45511e2 --- /dev/null +++ b/plugins/miniTokens/abci.go @@ -0,0 +1,118 @@ +package miniTokens + +import ( + "fmt" + "strconv" + "strings" + + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + + app "github.com/binance-chain/node/common/types" +) + +func createAbciQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { + return func(app app.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { + // expects at least two query path segments. + if path[0] != abciQueryPrefix || len(path) < 2 { + return nil + } + switch path[1] { + case "info": // args: ["tokens", "info", ] + if len(path) < 3 { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeUnknownRequest), + Log: fmt.Sprintf( + "%s %s query requires a symbol path arg", + abciQueryPrefix, path[1]), + } + } + ctx := app.GetContextForCheckState() + symbol := path[2] + if len(symbol) == 0 { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: "empty symbol not permitted", + } + } + token, err := mapper.GetToken(ctx, symbol) + if err != nil { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: err.Error(), + } + } + bz, err := app.GetCodec().MarshalBinaryLengthPrefixed(token) + if err != nil { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: err.Error(), + } + } + return &abci.ResponseQuery{ + Code: uint32(sdk.ABCICodeOK), + Value: bz, + } + case "list": // args: ["tokens", "list", , , ] + if len(path) < 4 { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeUnknownRequest), + Log: fmt.Sprintf( + "%s %s query requires offset and limit path segments", + abciQueryPrefix, path[1]), + } + } + showZeroSupplyTokens := false + if len(path) == 5 && strings.ToLower(path[4]) == "true" { + showZeroSupplyTokens = true + } + ctx := app.GetContextForCheckState() + tokens := mapper.GetTokenList(ctx, showZeroSupplyTokens) + offset, err := strconv.Atoi(path[2]) + if err != nil || offset < 0 || offset >= len(tokens) { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: "unable to parse offset", + } + } + limit, err := strconv.Atoi(path[3]) + if err != nil || limit <= 0 { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: "unable to parse limit", + } + } + end := offset + limit + if end > len(tokens) { + end = len(tokens) + } + if end <= 0 || end <= offset { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: "malformed range", + } + } + bz, err := app.GetCodec().MarshalBinaryLengthPrefixed( + tokens[offset:end], + ) + if err != nil { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: err.Error(), + } + } + return &abci.ResponseQuery{ + Code: uint32(sdk.ABCICodeOK), + Value: bz, + } + default: + return &abci.ResponseQuery{ + Code: uint32(sdk.ABCICodeOK), + Info: fmt.Sprintf( + "Unknown `%s` query path: %v", + abciQueryPrefix, path), + } + } + } +} diff --git a/plugins/miniTokens/client/cli/commands.go b/plugins/miniTokens/client/cli/commands.go new file mode 100644 index 000000000..c92bd68a0 --- /dev/null +++ b/plugins/miniTokens/client/cli/commands.go @@ -0,0 +1,33 @@ +package commands + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + + "github.com/binance-chain/node/wire" +) + +const ( + flagSymbol = "symbol" + flagAmount = "amount" +) + +func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { + + miniTokenCmd := &cobra.Command{ + Use: "miniToken", + Short: "issue or view mini tokens", + Long: ``, + } + + cmdr := Commander{Cdc: cdc} + miniTokenCmd.AddCommand( + client.PostCommands( + issueMiniTokenCmd(cmdr), + mintMiniTokenCmd(cmdr))...) + + miniTokenCmd.AddCommand(client.LineBreak) + + cmd.AddCommand(miniTokenCmd) +} diff --git a/plugins/miniTokens/client/cli/helper.go b/plugins/miniTokens/client/cli/helper.go new file mode 100644 index 000000000..36d36ee7c --- /dev/null +++ b/plugins/miniTokens/client/cli/helper.go @@ -0,0 +1,62 @@ +package commands + +import ( + "errors" + "strconv" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/client" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/wire" +) + +type Commander struct { + Cdc *wire.Codec +} + +type msgBuilder func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg + +func (c Commander) checkAndSendTx(cmd *cobra.Command, args []string, builder msgBuilder) error { + cliCtx, txBuilder := client.PrepareCtx(c.Cdc) + + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + symbol := viper.GetString(flagSymbol) + err = types.ValidateMapperMiniTokenSymbol(symbol) + if err != nil { + return err + } + + symbol = strings.ToUpper(symbol) + + amountStr := viper.GetString(flagAmount) + amount, err := parseAmount(amountStr) + if err != nil { + return err + } + + // build message + msg := builder(from, symbol, amount) + return client.SendOrPrintTx(cliCtx, txBuilder, msg) +} + +func parseAmount(amountStr string) (int64, error) { + amount, err := strconv.ParseInt(amountStr, 10, 64) + if err != nil { + return 0, err + } + + if amount <= 0 { + return amount, errors.New("the amount should be greater than 0") + } + + return amount, nil +} diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/miniTokens/client/cli/issue.go new file mode 100644 index 000000000..eb8ee30cc --- /dev/null +++ b/plugins/miniTokens/client/cli/issue.go @@ -0,0 +1,140 @@ +package commands + +import ( + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/binance-chain/node/common/client" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/miniTokens/issue" +) + +const ( + flagMaxTotalSupply = "max-total-supply" + flagTotalSupply = "total-supply" + flagTokenName = "token-name" + flagMintable = "mintable" + flagTokenUri = "token-uri" +) + +func issueMiniTokenCmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "issue", + Short: "issue a new mini token", + RunE: cmdr.issueToken, + } + + cmd.Flags().String(flagTokenName, "", "name of the new token") + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the new token") + cmd.Flags().Int64P(flagMaxTotalSupply, "n", 0, "max total supply of the new token") + cmd.Flags().Int64P(flagTotalSupply, "n", 0, "total supply of the new token") + cmd.Flags().Bool(flagMintable, false, "whether the token can be minted") + cmd.Flags().String(flagTokenUri, "", "uri of the token information") + cmd.MarkFlagRequired(flagMaxTotalSupply) + cmd.MarkFlagRequired(flagTotalSupply) + return cmd +} + +func mintMiniTokenCmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "mint", + Short: "mint mini tokens for an existing token", + RunE: cmdr.mintToken, + } + + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the token") + cmd.Flags().Int64P(flagAmount, "n", 0, "amount to mint") + cmd.MarkFlagRequired(flagAmount) + return cmd +} + +func (c Commander) issueToken(cmd *cobra.Command, args []string) error { + cliCtx, txBldr := client.PrepareCtx(c.Cdc) + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + name := viper.GetString(flagTokenName) + if len(name) == 0 { + return errors.New("you must provide the name of the token") + } + + symbol := viper.GetString(flagSymbol) + err = types.ValidateIssueMsgTokenSymbol(symbol) + if err != nil { + return err + } + + maxSupply := viper.GetInt64(flagMaxTotalSupply) + err = checkMaxSupplyAmount(maxSupply) + if err != nil { + return err + } + + supply := viper.GetInt64(flagTotalSupply) + err = checkSupplyAmount(supply, maxSupply) + if err != nil { + return err + } + + mintable := viper.GetBool(flagMintable) + + tokenURI := viper.GetString(flagTokenUri) + err = validateTokenURI(tokenURI) + if err != nil { + return err + } + + // build message + msg := issue.NewIssueMsg(from, name, symbol, maxSupply, supply, mintable, tokenURI) + return client.SendOrPrintTx(cliCtx, txBldr, msg) +} + +func (c Commander) mintToken(cmd *cobra.Command, args []string) error { + cliCtx, txBldr := client.PrepareCtx(c.Cdc) + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + symbol := viper.GetString(flagSymbol) + err = types.ValidateMapperTokenSymbol(symbol) + if err != nil { + return err + } + + amount := viper.GetInt64(flagAmount) + err = checkSupplyAmount(amount, 0) + if err != nil { + return err + } + + msg := issue.NewMintMsg(from, symbol, amount) + return client.SendOrPrintTx(cliCtx, txBldr, msg) +} + +func checkMaxSupplyAmount(amount int64) error { + if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenMaxTotalSupplyUpperBound { + return errors.New("invalid max supply amount") + } + return nil +} + +func checkSupplyAmount(amount, maxAmount int64) error { + if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenMaxTotalSupplyUpperBound { + return errors.New("invalid supply amount") + } + if maxAmount > 0 && amount > maxAmount { + return errors.New("supply amount cannot exceed max supply amount") + } + return nil +} + +func validateTokenURI(uri string) error { + if len(uri) > 2048 { + return errors.New("uri cannot be longer than 2048 characters") + } + return nil +} diff --git a/plugins/miniTokens/issue/handler.go b/plugins/miniTokens/issue/handler.go new file mode 100644 index 000000000..3e630a50a --- /dev/null +++ b/plugins/miniTokens/issue/handler.go @@ -0,0 +1,208 @@ +package issue + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" + "strings" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" + + "github.com/binance-chain/node/common/log" + "github.com/binance-chain/node/common/types" + common "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/miniTokens/store" +) + +// NewHandler creates a new token issue message handler +func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case IssueMsg: + return handleIssueToken(ctx, tokenMapper, keeper, msg) + case MintMsg: + return handleMintToken(ctx, tokenMapper, keeper, msg) + default: + errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKeeper bank.Keeper, msg IssueMsg) sdk.Result { + errLogMsg := "issue token failed" + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) + var suffix string + + // TxHashKey is set in BaseApp's runMsgs + txHash := ctx.Value(baseapp.TxHashKey) + if txHashStr, ok := txHash.(string); ok { + if len(txHashStr) >= types.MiniTokenSymbolTxHashSuffixLen { + suffix = txHashStr[:types.MiniTokenSymbolTxHashSuffixLen] + types.MiniTokenSymbolMSuffix + } else { + logger.Error(errLogMsg, + "reason", fmt.Sprintf("%s on Context had a length of %d, expected >= %d", + baseapp.TxHashKey, len(txHashStr), types.MiniTokenSymbolTxHashSuffixLen)) + return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() + } + } else { + logger.Error(errLogMsg, + "reason", fmt.Sprintf("%s on Context is not a string as expected", baseapp.TxHashKey)) + return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() + } + + if msg.MaxTotalSupply % types.MiniTokenMinTotalSupply !=0 { + logger.Info(errLogMsg, "reason", "max total supply is not integer") + return sdk.ErrInvalidCoins( + fmt.Sprintf("max total supply should be a multiple of %v", types.MiniTokenMinTotalSupply)).Result() + } + + if msg.TotalSupply % types.MiniTokenMinTotalSupply !=0 { + logger.Info(errLogMsg, "reason", "total supply is not integer") + return sdk.ErrInvalidCoins( + fmt.Sprintf("total supply should be a multiple of %v", types.MiniTokenMinTotalSupply)).Result() + } + + if msg.MaxTotalSupply < common.MiniTokenMinTotalSupply { + logger.Info(errLogMsg, "reason", "max total supply doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too small, the min amount is %ds", + common.MiniTokenMinTotalSupply)).Result() + } + if msg.MaxTotalSupply > common.MiniTokenMaxTotalSupplyUpperBound { + logger.Info(errLogMsg, "reason", "max total supply exceeds the max total supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too large, the max total supply upper bound is %ds", + common.MiniTokenMaxTotalSupplyUpperBound)).Result() + } + if msg.TotalSupply < common.MiniTokenMinTotalSupply { + logger.Info(errLogMsg, "reason", "total supply doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too small, the min amount is %ds", + common.MiniTokenMinTotalSupply)).Result() + } + if msg.TotalSupply > msg.MaxTotalSupply { + logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply is %ds", + common.MiniTokenMaxTotalSupplyUpperBound)).Result() + } + + if msg.TotalSupply > common.MiniTokenMaxTotalSupplyUpperBound { + logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply upperbound is %ds", + common.MiniTokenMaxTotalSupplyUpperBound)).Result() + } + // the symbol is suffixed with the first n bytes of the tx hash + symbol = fmt.Sprintf("%s-%s", symbol, suffix) + + if !types.IsMiniTokenSymbol(symbol) { + logger.Info(errLogMsg, "reason", "symbol not valid") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) is not valid for mini token", symbol)).Result() + } + + if exists := tokenMapper.Exists(ctx, symbol); exists { + logger.Info(errLogMsg, "reason", "already exists") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) already exists", msg.Symbol)).Result() + } + + token, err := common.NewMiniToken(msg.Name, symbol, msg.MaxTotalSupply, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) + if err != nil { + logger.Error(errLogMsg, "reason", "create token failed: "+err.Error()) + return sdk.ErrInternal(fmt.Sprintf("unable to create token struct: %s", err.Error())).Result() + } + + if err := tokenMapper.NewToken(ctx, *token); err != nil { + logger.Error(errLogMsg, "reason", "add token failed: "+err.Error()) + return sdk.ErrInvalidCoins(err.Error()).Result() + } + + if _, _, sdkError := bankKeeper.AddCoins(ctx, token.Owner, + sdk.Coins{{ + Denom: token.Symbol, + Amount: token.TotalSupply.ToInt64(), + }}); sdkError != nil { + logger.Error(errLogMsg, "reason", "update balance failed: "+sdkError.Error()) + return sdkError.Result() + } + + serialized, err := json.Marshal(token) + if err != nil { + logger.Error(errLogMsg, "reason", "fatal! unable to json serialize token: "+err.Error()) + panic(err) // fatal, the sky is falling in goland + } + + logger.Info("finished issuing token") + + return sdk.Result{ + Data: serialized, + Log: fmt.Sprintf("Issued %s", token.Symbol), + } +} + +func handleMintToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "token", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) + + errLogMsg := "mint token failed" + token, err := tokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info(errLogMsg, "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + if !token.Mintable { + logger.Info(errLogMsg, "reason", "token cannot be minted") + return sdk.ErrInvalidCoins(fmt.Sprintf("token(%s) cannot be minted", msg.Symbol)).Result() + } + + if !token.IsOwner(msg.From) { + logger.Info(errLogMsg, "reason", "not the token owner") + return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() + } + + if msg.Amount % types.MiniTokenMinTotalSupply !=0 { + logger.Info(errLogMsg, "reason", "mint amount is not integer") + return sdk.ErrInvalidCoins( + fmt.Sprintf("amount should be a multiple of %v", types.MiniTokenMinTotalSupply)).Result() + } + + if msg.Amount < common.MiniTokenMinTotalSupply { + logger.Info(errLogMsg, "reason", "mint amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %ds", + common.MiniTokenMinTotalSupply)).Result() + } + // use minus to prevent overflow + if msg.Amount > token.MaxTotalSupply.ToInt64() -token.TotalSupply.ToInt64() { + logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %ds", + token.MaxTotalSupply)).Result() + } + + if msg.Amount > common.MiniTokenMaxTotalSupplyUpperBound-token.TotalSupply.ToInt64() { + logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply upper bound") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %ds", + common.MiniTokenMaxTotalSupplyUpperBound)).Result() + } + newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount + err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) + if err != nil { + logger.Error(errLogMsg, "reason", "update total supply failed: "+err.Error()) + return sdk.ErrInternal(fmt.Sprintf("update total supply failed")).Result() + } + + _, _, sdkError := bankKeeper.AddCoins(ctx, token.Owner, + sdk.Coins{{ + Denom: token.Symbol, + Amount: msg.Amount, + }}) + if sdkError != nil { + logger.Error(errLogMsg, "reason", "update balance failed: "+sdkError.Error()) + return sdkError.Result() + } + + logger.Info("finished minting token") + return sdk.Result{ + Data: []byte(strconv.FormatInt(newTotalSupply, 10)), + } +} diff --git a/plugins/miniTokens/issue/handler_test.go b/plugins/miniTokens/issue/handler_test.go new file mode 100644 index 000000000..48ffef1e9 --- /dev/null +++ b/plugins/miniTokens/issue/handler_test.go @@ -0,0 +1,112 @@ +package issue + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/binance-chain/node/common/testutils" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/miniTokens/store" + "github.com/binance-chain/node/wire" +) + +func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.MiniTokenMapper) { + ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() + cdc := wire.NewCodec() + tokenMapper := store.NewMiniTokenMapper(cdc, capKey1) + accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) + bankKeeper := bank.NewBaseKeeper(accountKeeper) + handler := NewHandler(tokenMapper, bankKeeper) + + accountStore := ms.GetKVStore(capKey2) + accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, + sdk.RunTxModeDeliver, log.NewNopLogger()). + WithAccountCache(auth.NewAccountCache(accountStoreCache)) + return ctx, handler, accountKeeper, tokenMapper +} + +func TestHandleIssueToken(t *testing.T) { + ctx, handler, accountKeeper, tokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg := NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100001e8, 100000e8, false, "http://www.xyz.com/nnb.json") + sdkResult := handler(ctx, msg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "max total supply is too large") + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100001e8, 100000e8-100, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "total supply should be a multiple of 100000000") + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100000e8, 100000e8, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 100000e8, 100000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, token) + + sdkResult = handler(ctx, msg) + require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") +} + +func TestHandleMintToken(t *testing.T) { + ctx, handler, accountKeeper, tokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 10000e8) + sdkResult := handler(ctx, mintMsg) + require.Contains(t, sdkResult.Log, "symbol(NNB-000M) does not exist") + + issueMsg := NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100000e8, 90000e8, true, "http://www.xyz.com/nnb.json") + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + sdkResult = handler(ctx, issueMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + sdkResult = handler(ctx, mintMsg) + token, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 100000e8, 100000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, token) + + sdkResult = handler(ctx, mintMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "mint amount is too large") + + invalidMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", types.MiniTokenMaxTotalSupplyUpperBound) + sdkResult = handler(ctx, invalidMintMsg) + require.Contains(t, sdkResult.Log, "mint amount is too large") + + _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) + invalidMintMsg = NewMintMsg(acc2.GetAddress(), "NNB-000M", types.MiniTokenMaxTotalSupplyUpperBound) + sdkResult = handler(ctx, invalidMintMsg) + require.Contains(t, sdkResult.Log, "only the owner can mint token NNB") + + // issue a non-mintable token + issueMsg = NewIssueMsg(acc.GetAddress(), "New BNB2", "NNB2", 100000e8, 100000e8, false, "http://www.xyz.com/nnb.json") + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + sdkResult = handler(ctx, issueMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + mintMsg = NewMintMsg(acc.GetAddress(), "NNB2-000M", 10000e8) + sdkResult = handler(ctx, mintMsg) + require.Contains(t, sdkResult.Log, "token(NNB2-000M) cannot be minted") + + // mint native token + invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) + require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "suffixed mini token symbol must contain a hyphen") +} diff --git a/plugins/miniTokens/issue/msg.go b/plugins/miniTokens/issue/msg.go new file mode 100644 index 000000000..616782f50 --- /dev/null +++ b/plugins/miniTokens/issue/msg.go @@ -0,0 +1,160 @@ +package issue + +import ( + "encoding/json" + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" +) + +// TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash +// const Route = "tokens/issue" +const ( + Route = "miniTokensIssue" + IssueMsgType = "miniIssueMsg" + AdvIssueMsgType = "advMiniIssueMsg" //For max total supply in range 2 + MintMsgType = "miniMintMsg" + + maxTokenNameLength = 32 + maxTokenURILength = 2048 +) + +var _ sdk.Msg = IssueMsg{} + +type IssueMsg struct { + From sdk.AccAddress `json:"from"` + Name string `json:"name"` + Symbol string `json:"symbol"` + MaxTotalSupply int64 `json:"max_total_supply"` + TotalSupply int64 `json:"total_supply"` + Mintable bool `json:"mintable"` + TokenURI string `json:"token_uri"` +} + +func NewIssueMsg(from sdk.AccAddress, name, symbol string, maxTotalSupply, supply int64, mintable bool, tokenURI string) IssueMsg { + return IssueMsg{ + From: from, + Name: name, + Symbol: symbol, + MaxTotalSupply: maxTotalSupply, + TotalSupply: supply, + Mintable: mintable, + TokenURI: tokenURI, + } +} + +// ValidateBasic does a simple validation check that +// doesn't require access to any other information. +func (msg IssueMsg) ValidateBasic() sdk.Error { + if msg.From == nil { + return sdk.ErrInvalidAddress("sender address cannot be empty") + } + + if err := types.ValidateIssueMsgMiniTokenSymbol(msg.Symbol); err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + + if len(msg.Name) == 0 || len(msg.Name) > maxTokenNameLength { + return sdk.ErrInvalidCoins(fmt.Sprintf("token name should have 1 ~ %v characters", maxTokenNameLength)) + } + + if len(msg.TokenURI) > maxTokenURILength { + return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", maxTokenURILength)) + } + + if msg.MaxTotalSupply%types.MiniTokenMinTotalSupply != 0 { + return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply should be a multiple of %v", types.MiniTokenMinTotalSupply)) + } + + if msg.TotalSupply%types.MiniTokenMinTotalSupply != 0 { + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be a multiple of %v", types.MiniTokenMinTotalSupply)) + } + + if msg.MaxTotalSupply < types.MiniTokenMinTotalSupply || msg.MaxTotalSupply > types.MiniTokenMaxTotalSupplyUpperBound { + return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenMaxTotalSupplyUpperBound)) + } + + if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > msg.MaxTotalSupply { + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, msg.MaxTotalSupply)) + } + + return nil +} + +// Implements IssueMsg. +func (msg IssueMsg) Route() string { return Route } +func (msg IssueMsg) Type() string { + if msg.MaxTotalSupply > types.MiniTokenSupplyRange1UpperBound { + return AdvIssueMsgType + } else { + return IssueMsgType + } +} +func (msg IssueMsg) String() string { return fmt.Sprintf("IssueMsg{%#v}", msg) } +func (msg IssueMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } +func (msg IssueMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} +func (msg IssueMsg) GetInvolvedAddresses() []sdk.AccAddress { + return msg.GetSigners() +} + +type MintMsg struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + Amount int64 `json:"amount"` +} + +func NewMintMsg(from sdk.AccAddress, symbol string, amount int64) MintMsg { + return MintMsg{ + From: from, + Symbol: symbol, + Amount: amount, + } +} + +func (msg MintMsg) ValidateBasic() sdk.Error { + if msg.From == nil { + return sdk.ErrInvalidAddress("sender address cannot be empty") + } + + if err := types.ValidateMapperMiniTokenSymbol(msg.Symbol); err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + + if msg.Symbol == types.NativeTokenSymbol { + return sdk.ErrInvalidCoins(fmt.Sprintf("cannot mint native token")) + } + + if msg.Amount%types.MiniTokenMinTotalSupply != 0 { + return sdk.ErrInvalidCoins(fmt.Sprintf("amount should be a multiple of %v", types.MiniTokenMinTotalSupply)) + } + + // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply + if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenMaxTotalSupplyUpperBound { + return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenMaxTotalSupplyUpperBound)) + } + + return nil +} + +// Implements MintMsg. +func (msg MintMsg) Route() string { return Route } +func (msg MintMsg) Type() string { return MintMsgType } +func (msg MintMsg) String() string { return fmt.Sprintf("MintMsg{%#v}", msg) } +func (msg MintMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } +func (msg MintMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} +func (msg MintMsg) GetInvolvedAddresses() []sdk.AccAddress { + return msg.GetSigners() +} diff --git a/plugins/miniTokens/mini_tokens.go b/plugins/miniTokens/mini_tokens.go new file mode 100644 index 000000000..7fdb25e5f --- /dev/null +++ b/plugins/miniTokens/mini_tokens.go @@ -0,0 +1,5 @@ +package miniTokens + +import "github.com/binance-chain/node/plugins/miniTokens/store" + +type MiniTokenMapper = store.MiniTokenMapper diff --git a/plugins/miniTokens/plugin.go b/plugins/miniTokens/plugin.go new file mode 100644 index 000000000..04907833d --- /dev/null +++ b/plugins/miniTokens/plugin.go @@ -0,0 +1,27 @@ +package miniTokens + +import ( + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + + app "github.com/binance-chain/node/common/types" +) + +const abciQueryPrefix = "miniTokens" + +// InitPlugin initializes the plugin. +func InitPlugin( + appp app.ChainApp, mapper MiniTokenMapper, accKeeper auth.AccountKeeper, coinKeeper bank.Keeper) { + // add msg handlers + for route, handler := range Routes(mapper, accKeeper, coinKeeper) { + appp.GetRouter().AddRoute(route, handler) + } + + // add abci handlers + handler := createQueryHandler(mapper) + appp.RegisterQueryHandler(abciQueryPrefix, handler) +} + +func createQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { + return createAbciQueryHandler(mapper) +} diff --git a/plugins/miniTokens/route.go b/plugins/miniTokens/route.go new file mode 100644 index 000000000..f00a6f0d9 --- /dev/null +++ b/plugins/miniTokens/route.go @@ -0,0 +1,15 @@ +package miniTokens + +import ( + "github.com/binance-chain/node/plugins/miniTokens/issue" + "github.com/binance-chain/node/plugins/miniTokens/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" +) + +func Routes(tokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) map[string]sdk.Handler { + routes := make(map[string]sdk.Handler) + routes[issue.Route] = issue.NewHandler(tokenMapper, keeper) + return routes +} diff --git a/plugins/miniTokens/store/mapper.go b/plugins/miniTokens/store/mapper.go index d1c27ffcd..edd2af36f 100644 --- a/plugins/miniTokens/store/mapper.go +++ b/plugins/miniTokens/store/mapper.go @@ -14,9 +14,9 @@ import ( "github.com/binance-chain/node/wire" ) -type Tokens []types.Token +type MiniTokens []types.MiniToken -func (t Tokens) GetSymbols() *[]string { +func (t MiniTokens) GetSymbols() *[]string { var symbols []string for _, token := range t { symbols = append(symbols, token.Symbol) @@ -24,31 +24,32 @@ func (t Tokens) GetSymbols() *[]string { return &symbols } -type Mapper interface { - NewToken(ctx sdk.Context, token types.Token) error +type MiniTokenMapper interface { + NewToken(ctx sdk.Context, token types.MiniToken) error Exists(ctx sdk.Context, symbol string) bool ExistsCC(ctx context.CLIContext, symbol string) bool - GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool) Tokens - GetToken(ctx sdk.Context, symbol string) (types.Token, error) + GetTokenList(ctx sdk.Context, showZeroSupplyMiniTokens bool) MiniTokens + GetToken(ctx sdk.Context, symbol string) (types.MiniToken, error) // we do not provide the updateToken method UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) error + UpdateTokenURI(ctx sdk.Context, symbol string, uri string) error } -var _ Mapper = mapper{} +var _ MiniTokenMapper = mapper{} type mapper struct { key sdk.StoreKey cdc *wire.Codec } -func NewMapper(cdc *wire.Codec, key sdk.StoreKey) mapper { +func NewMiniTokenMapper(cdc *wire.Codec, key sdk.StoreKey) MiniTokenMapper { return mapper{ key: key, cdc: cdc, } } -func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.Token, error) { +func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.MiniToken, error) { store := ctx.KVStore(m.key) key := []byte(strings.ToUpper(symbol)) @@ -57,29 +58,29 @@ func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.Token, error) { return m.decodeToken(bz), nil } - return types.Token{}, fmt.Errorf("token(%v) not found", symbol) + return types.MiniToken{}, fmt.Errorf("token(%v) not found", symbol) } -func (m mapper) GetTokenCC(ctx context.CLIContext, symbol string) (types.Token, error) { +func (m mapper) GetTokenCC(ctx context.CLIContext, symbol string) (types.MiniToken, error) { key := []byte(strings.ToUpper(symbol)) - bz, err := ctx.QueryStore(key, common.TokenStoreName) + bz, err := ctx.QueryStore(key, common.MiniTokenStoreName) if err != nil { - return types.Token{}, err + return types.MiniToken{}, err } if bz != nil { return m.decodeToken(bz), nil } - return types.Token{}, fmt.Errorf("token(%v) not found", symbol) + return types.MiniToken{}, fmt.Errorf("token(%v) not found", symbol) } -func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool) Tokens { - var res Tokens +func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyMiniTokens bool) MiniTokens { + var res MiniTokens store := ctx.KVStore(m.key) iter := store.Iterator(nil, nil) defer iter.Close() for ; iter.Valid(); iter.Next() { token := m.decodeToken(iter.Value()) - if !showZeroSupplyTokens && token.TotalSupply.ToInt64() == 0 { + if !showZeroSupplyMiniTokens && token.TotalSupply.ToInt64() == 0 { continue } res = append(res, token) @@ -95,7 +96,7 @@ func (m mapper) Exists(ctx sdk.Context, symbol string) bool { func (m mapper) ExistsCC(ctx context.CLIContext, symbol string) bool { key := []byte(strings.ToUpper(symbol)) - bz, err := ctx.QueryStore(key, common.TokenStoreName) + bz, err := ctx.QueryStore(key, common.MiniTokenStoreName) if err != nil { return false } @@ -105,9 +106,9 @@ func (m mapper) ExistsCC(ctx context.CLIContext, symbol string) bool { return false } -func (m mapper) NewToken(ctx sdk.Context, token types.Token) error { +func (m mapper) NewToken(ctx sdk.Context, token types.MiniToken) error { symbol := token.Symbol - if err := types.ValidateToken(token); err != nil { + if err := types.ValidateMiniToken(token); err != nil { return err } key := []byte(strings.ToUpper(symbol)) @@ -138,7 +139,7 @@ func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) return nil } -func (m mapper) encodeToken(token types.Token) []byte { +func (m mapper) encodeToken(token types.MiniToken) []byte { bz, err := m.cdc.MarshalBinaryBare(token) if err != nil { panic(err) @@ -146,10 +147,41 @@ func (m mapper) encodeToken(token types.Token) []byte { return bz } -func (m mapper) decodeToken(bz []byte) (token types.Token) { +func (m mapper) decodeToken(bz []byte) (token types.MiniToken) { err := m.cdc.UnmarshalBinaryBare(bz, &token) if err != nil { panic(err) } return } + + +func (m mapper) UpdateTokenURI(ctx sdk.Context, symbol string, uri string) error { + if len(symbol) == 0 { + return errors.New("symbol cannot be empty") + } + + if len(uri) == 0 { + return errors.New("uri cannot be empty") + } + + if len(uri) > 2048 { + return errors.New("uri length cannot be larger than 2048") + } + + key := []byte(strings.ToUpper(symbol)) + store := ctx.KVStore(m.key) + bz := store.Get(key) + if bz == nil { + return errors.New("token does not exist") + } + + toBeUpdated := m.decodeToken(bz) + + if toBeUpdated.TokenURI != uri { + toBeUpdated.TokenURI = uri + store.Set(key, m.encodeToken(toBeUpdated)) + } + return nil +} + diff --git a/plugins/miniTokens/wire.go b/plugins/miniTokens/wire.go new file mode 100644 index 000000000..2b889c3d4 --- /dev/null +++ b/plugins/miniTokens/wire.go @@ -0,0 +1,12 @@ +package miniTokens + +import ( + "github.com/binance-chain/node/plugins/miniTokens/issue" + "github.com/binance-chain/node/wire" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterConcrete(issue.IssueMsg{}, "miniTokens/IssueMsg", nil) + cdc.RegisterConcrete(issue.MintMsg{}, "miniTokens/MintMsg", nil) +} diff --git a/plugins/param/genesis.go b/plugins/param/genesis.go index c8cde3b0c..cc2ac6b8e 100644 --- a/plugins/param/genesis.go +++ b/plugins/param/genesis.go @@ -52,6 +52,11 @@ const ( FeeRateNative = 400 IOCExpireFee = 25e3 IOCExpireFeeNative = 5e3 + + //MiniToken fee + MiniIssueFee = 10e8 + AdvMiniIssueFee = 20e8 + MiniMintFee = 2e8 ) var DefaultGenesisState = param.GenesisState{ diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index bc6e369d3..606101c58 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -13,6 +13,7 @@ import ( "github.com/binance-chain/node/plugins/account" "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" + miniIssue "github.com/binance-chain/node/plugins/miniTokens/issue" "github.com/binance-chain/node/plugins/param/paramhub" param "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/plugins/tokens" @@ -60,6 +61,14 @@ func RegisterUpgradeBeginBlocker(paramHub *ParamHub) { } paramHub.UpdateFeeParams(ctx, swapFeeParams) }) + upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP69, func(ctx sdk.Context) { + miniTokenFeeParams := []param.FeeParam{ + ¶m.FixedFeeParams{MsgType: miniIssue.IssueMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: miniIssue.AdvIssueMsgType, Fee: AdvMiniIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: miniIssue.MintMsg{}.Type(), Fee: MiniMintFee, FeeFor: types.FeeForProposer}, + } + paramHub.UpdateFeeParams(ctx, miniTokenFeeParams) + }) } func EndBreatheBlock(ctx sdk.Context, paramHub *ParamHub) { @@ -92,5 +101,8 @@ func init() { swap.DepositHTLT: fees.FixedFeeCalculatorGen, swap.ClaimHTLT: fees.FixedFeeCalculatorGen, swap.RefundHTLT: fees.FixedFeeCalculatorGen, + miniIssue.IssueMsgType: fees.FixedFeeCalculatorGen, + miniIssue.AdvIssueMsgType: fees.FixedFeeCalculatorGen, + miniIssue.MintMsgType: fees.FixedFeeCalculatorGen, } } diff --git a/plugins/param/types/types.go b/plugins/param/types/types.go index ce39679f3..9bf4d414a 100644 --- a/plugins/param/types/types.go +++ b/plugins/param/types/types.go @@ -40,6 +40,10 @@ var ( "depositHTLT": {}, "claimHTLT": {}, "refundHTLT": {}, + + "miniIssueMsg": {}, + "advMiniIssueMsg": {}, + "miniMintMsg": {}, } ValidTransferFeeMsgTypes = map[string]struct{}{ From 353d64c97a1dd400798bfbe3db998946d6d74106 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 26 Mar 2020 01:10:09 +0800 Subject: [PATCH 03/96] fix miniToken/issue --- app/app.go | 4 +- cmd/dexperf/main.go | 2 + networks/publisher/setup_mini.sh | 82 ++++++++++++++++++++++ networks/tools/snapshot_viewer/snapshot.go | 3 +- plugins/miniTokens/client/cli/issue.go | 6 +- plugins/miniTokens/issue/handler.go | 16 ++--- 6 files changed, 100 insertions(+), 13 deletions(-) create mode 100755 networks/publisher/setup_mini.sh diff --git a/app/app.go b/app/app.go index c0e2197e8..143bbe7f3 100644 --- a/app/app.go +++ b/app/app.go @@ -219,6 +219,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp common.GovStoreKey, common.TimeLockStoreKey, common.AtomicSwapStoreKey, + common.MiniTokenStoreKey, ) app.SetAnteHandler(tx.NewAnteHandler(app.AccountKeeper)) app.SetPreChecker(tx.NewTxPreChecker()) @@ -257,7 +258,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp // setUpgradeConfig will overwrite default upgrade config func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // register upgrade height - upgrade.Mgr.AddUpgradeHeight(upgrade.BEP6, upgradeConfig.BEP69Height) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP69, upgradeConfig.BEP69Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP6, upgradeConfig.BEP6Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP9, upgradeConfig.BEP9Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP10, upgradeConfig.BEP10Height) @@ -758,6 +759,7 @@ func MakeCodec() *wire.Codec { stake.RegisterCodec(cdc) gov.RegisterCodec(cdc) param.RegisterWire(cdc) + miniTokens.RegisterWire(cdc) return cdc } diff --git a/cmd/dexperf/main.go b/cmd/dexperf/main.go index 459e0abb0..5639b6cfc 100644 --- a/cmd/dexperf/main.go +++ b/cmd/dexperf/main.go @@ -7,6 +7,7 @@ import ( "encoding/json" "flag" "fmt" + "github.com/binance-chain/node/plugins/miniTokens" "io/ioutil" "math/rand" "os" @@ -544,6 +545,7 @@ func MakeCodec() *wire.Codec { tokens.RegisterWire(cdc) types.RegisterWire(cdc) tx.RegisterWire(cdc) + miniTokens.RegisterWire(cdc) return cdc } diff --git a/networks/publisher/setup_mini.sh b/networks/publisher/setup_mini.sh new file mode 100755 index 000000000..738451501 --- /dev/null +++ b/networks/publisher/setup_mini.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +# start a validator and witness on local machine +# later on db indexer and publisher can be setup and started by newIndexer.sh and newPublisher.sh +# later on order generation can be kicked off by ordergen.sh +# TODO: support two validator without docker in same machine + +########################### SETUP ######################### +src='/Users/luerheng/go/src/github.com/binance-chain/node' +home='/Users/luerheng' +deamonhome='/Users/luerheng/.bnbchaind' +witnesshome='/Users/luerheng/.bnbchaind_witness' +clihome='/Users/luerheng/.bnbcli' +chain_id='test-chain-n4b735' + +key_seed_path="${home}" +executable="${src}/build/bnbchaind" +clipath="${src}/build/bnbcli" +cli="${clipath} --home ${clihome}" +scripthome="${src}/networks/publisher" +############################ END ########################## + +# clean history data +rm -r ${deamonhome} +rm -r ${clihome} +rm -r ${home}/.bnbchaind_witness + +# build +cd ${src} +make build + +# init a validator and witness node +${executable} init --moniker xxx --chain-id ${chain_id} > ${key_seed_path}/key_seed.json # cannot save into ${deamonhome}/init.json +secret=$(cat ${key_seed_path}/key_seed.json | grep secret | grep -o ":.*" | grep -o "\".*" | sed "s/\"//g") +#echo ${secret} + +mkdir -p ${home}/.bnbchaind_witness/config + +#sed -i -e "s/skip_timeout_commit = false/skip_timeout_commit = true/g" ${deamonhome}/config/config.toml +sed -i -e "s/log_level = \"main:info,state:info,\*:error\"/log_level = \"debug\"/g" ${deamonhome}/config/config.toml +sed -i -e "s/allow_duplicate_ip = false/allow_duplicate_ip = true/g" ${deamonhome}/config/config.toml +sed -i -e "s/addr_book_strict = true/addr_book_strict = false/g" ${deamonhome}/config/config.toml + +sed -i -e 's/logToConsole = true/logToConsole = false/g' ${deamonhome}/config/app.toml +sed -i -e 's/breatheBlockInterval = 0/breatheBlockInterval = 100/g' ${deamonhome}/config/app.toml +sed -i -e "s/publishOrderUpdates = false/publishOrderUpdates = true/g" ${deamonhome}/config/app.toml +sed -i -e "s/publishAccountBalance = false/publishAccountBalance = true/g" ${deamonhome}/config/app.toml +sed -i -e "s/publishOrderBook = false/publishOrderBook = true/g" ${deamonhome}/config/app.toml +sed -i -e "s/publishBlockFee = false/publishBlockFee = true/g" ${deamonhome}/config/app.toml +sed -i -e "s/publishTransfer = false/publishTransfer = true/g" ${deamonhome}/config/app.toml +sed -i -e "s/publishLocal = false/publishLocal = true/g" ${deamonhome}/config/app.toml + +# config witness node +cp ${deamonhome}/config/genesis.json ${witnesshome}/config/ +cp ${deamonhome}/config/app.toml ${witnesshome}/config/ +cp ${deamonhome}/config/config.toml ${witnesshome}/config/ + +sed -i -e "s/26/27/g" ${witnesshome}/config/config.toml +sed -i -e "s/6060/7060/g" ${witnesshome}/config/config.toml +#sed -i -e "s/fastest_sync_height = -1/fastest_sync_height = 10/g" ${witnesshome}/config/config.toml + +# start validator +${executable} start --pruning breathe > ${deamonhome}/log.txt 2>&1 & +validator_pid=$! +echo ${validator_pid} +sleep 60 # sleep in case cli status call failed to get node id +validatorStatus=$(${cli} status) +validator_id=$(echo ${validatorStatus} | grep -o "\"id\":\"[a-zA-Z0-9]*\"" | sed "s/\"//g" | sed "s/id://g") +#echo ${validator_id} + +# set witness peer to validator and start witness +sed -i -e "s/persistent_peers = \"\"/persistent_peers = \"${validator_id}@127.0.0.1:26656\"/g" ${witnesshome}/config/config.toml +sed -i -e "s/state_sync_height = -1/state_sync_height = 0/g" ${witnesshome}/config/config.toml +${executable} start --pruning breathe --home ${witnesshome} > ${witnesshome}/log.txt 2>&1 & +witness_pid=$! +echo ${witness_pid} + +# init accounts +result=$(expect ${scripthome}/recover.exp "${secret}" "zc" "${clipath}" "${clihome}") +result=$(expect ${scripthome}/add_key.exp "zz" "${clipath}" "${clihome}") +zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") + diff --git a/networks/tools/snapshot_viewer/snapshot.go b/networks/tools/snapshot_viewer/snapshot.go index a79df3eb8..fbda70251 100644 --- a/networks/tools/snapshot_viewer/snapshot.go +++ b/networks/tools/snapshot_viewer/snapshot.go @@ -47,7 +47,8 @@ func prepareCms(root string, appDB *db.GoLevelDB) sdk.CommitMultiStore { keys := []store.StoreKey{ common.MainStoreKey, common.TokenStoreKey, common.DexStoreKey, common.PairStoreKey, common.GovStoreKey, common.StakeStoreKey, - common.ParamsStoreKey, common.ValAddrStoreKey, common.AccountStoreKey} + common.ParamsStoreKey, common.ValAddrStoreKey, common.AccountStoreKey, + common.MiniTokenStoreKey} cms := store.NewCommitMultiStore(appDB) for _, key := range keys { diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/miniTokens/client/cli/issue.go index eb8ee30cc..df8a81b8b 100644 --- a/plugins/miniTokens/client/cli/issue.go +++ b/plugins/miniTokens/client/cli/issue.go @@ -27,7 +27,7 @@ func issueMiniTokenCmd(cmdr Commander) *cobra.Command { cmd.Flags().String(flagTokenName, "", "name of the new token") cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the new token") - cmd.Flags().Int64P(flagMaxTotalSupply, "n", 0, "max total supply of the new token") + cmd.Flags().Int64P(flagMaxTotalSupply, "m", 0, "max total supply of the new token") cmd.Flags().Int64P(flagTotalSupply, "n", 0, "total supply of the new token") cmd.Flags().Bool(flagMintable, false, "whether the token can be minted") cmd.Flags().String(flagTokenUri, "", "uri of the token information") @@ -62,7 +62,7 @@ func (c Commander) issueToken(cmd *cobra.Command, args []string) error { } symbol := viper.GetString(flagSymbol) - err = types.ValidateIssueMsgTokenSymbol(symbol) + err = types.ValidateIssueMsgMiniTokenSymbol(symbol) if err != nil { return err } @@ -100,7 +100,7 @@ func (c Commander) mintToken(cmd *cobra.Command, args []string) error { } symbol := viper.GetString(flagSymbol) - err = types.ValidateMapperTokenSymbol(symbol) + err = types.ValidateMapperMiniTokenSymbol(symbol) if err != nil { return err } diff --git a/plugins/miniTokens/issue/handler.go b/plugins/miniTokens/issue/handler.go index 3e630a50a..42d54aacf 100644 --- a/plugins/miniTokens/issue/handler.go +++ b/plugins/miniTokens/issue/handler.go @@ -69,28 +69,28 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe if msg.MaxTotalSupply < common.MiniTokenMinTotalSupply { logger.Info(errLogMsg, "reason", "max total supply doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too small, the min amount is %ds", + return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too small, the min amount is %d", common.MiniTokenMinTotalSupply)).Result() } if msg.MaxTotalSupply > common.MiniTokenMaxTotalSupplyUpperBound { logger.Info(errLogMsg, "reason", "max total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too large, the max total supply upper bound is %ds", + return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too large, the max total supply upper bound is %d", common.MiniTokenMaxTotalSupplyUpperBound)).Result() } if msg.TotalSupply < common.MiniTokenMinTotalSupply { logger.Info(errLogMsg, "reason", "total supply doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too small, the min amount is %ds", + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too small, the min amount is %d", common.MiniTokenMinTotalSupply)).Result() } if msg.TotalSupply > msg.MaxTotalSupply { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply is %ds", + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply is %d", common.MiniTokenMaxTotalSupplyUpperBound)).Result() } if msg.TotalSupply > common.MiniTokenMaxTotalSupplyUpperBound { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply upperbound is %ds", + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply upperbound is %d", common.MiniTokenMaxTotalSupplyUpperBound)).Result() } // the symbol is suffixed with the first n bytes of the tx hash @@ -169,19 +169,19 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKee if msg.Amount < common.MiniTokenMinTotalSupply { logger.Info(errLogMsg, "reason", "mint amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %ds", + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %d", common.MiniTokenMinTotalSupply)).Result() } // use minus to prevent overflow if msg.Amount > token.MaxTotalSupply.ToInt64() -token.TotalSupply.ToInt64() { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %ds", + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %d", token.MaxTotalSupply)).Result() } if msg.Amount > common.MiniTokenMaxTotalSupplyUpperBound-token.TotalSupply.ToInt64() { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply upper bound") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %ds", + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %d", common.MiniTokenMaxTotalSupplyUpperBound)).Result() } newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount From 07eb5459679a57287f34c576ab63cb3ce4a9bdb7 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 30 Mar 2020 21:58:27 +0800 Subject: [PATCH 04/96] burn setTokens tx; cli --- common/types/mini_token.go | 17 ++-- common/types/token.go | 10 ++ go.mod | 2 +- plugins/miniTokens/abci.go | 2 +- plugins/miniTokens/burn/handler.go | 84 ++++++++++++++++ plugins/miniTokens/burn/msg.go | 61 ++++++++++++ plugins/miniTokens/client/cli/burn.go | 35 +++++++ plugins/miniTokens/client/cli/commands.go | 8 +- plugins/miniTokens/client/cli/freeze.go | 63 ++++++++++++ plugins/miniTokens/client/cli/helper.go | 7 ++ plugins/miniTokens/client/cli/info.go | 64 ++++++++++++ plugins/miniTokens/client/cli/issue.go | 9 +- plugins/miniTokens/client/cli/uri.go | 44 +++++++++ plugins/miniTokens/freeze/handler.go | 113 ++++++++++++++++++++++ plugins/miniTokens/freeze/msg.go | 100 +++++++++++++++++++ plugins/miniTokens/issue/handler.go | 40 ++++---- plugins/miniTokens/issue/handler_test.go | 2 +- plugins/miniTokens/issue/msg.go | 6 +- plugins/miniTokens/route.go | 7 ++ plugins/miniTokens/uri/handler.go | 59 +++++++++++ plugins/miniTokens/uri/msg.go | 54 +++++++++++ plugins/miniTokens/wire.go | 7 ++ plugins/param/genesis.go | 9 +- plugins/param/plugin.go | 9 ++ plugins/param/types/types.go | 9 +- plugins/tokens/freeze/handler.go | 7 ++ plugins/tokens/swap/handler.go | 9 ++ plugins/tokens/timelock/handler.go | 9 ++ 28 files changed, 798 insertions(+), 48 deletions(-) create mode 100644 plugins/miniTokens/burn/handler.go create mode 100644 plugins/miniTokens/burn/msg.go create mode 100644 plugins/miniTokens/client/cli/burn.go create mode 100644 plugins/miniTokens/client/cli/freeze.go create mode 100644 plugins/miniTokens/client/cli/info.go create mode 100644 plugins/miniTokens/client/cli/uri.go create mode 100644 plugins/miniTokens/freeze/handler.go create mode 100644 plugins/miniTokens/freeze/msg.go create mode 100644 plugins/miniTokens/uri/handler.go create mode 100644 plugins/miniTokens/uri/msg.go diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 3c52562fc..3ea810307 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -24,6 +24,7 @@ const ( MiniTokenMaxTotalSupplyUpperBound int64 = 10000000000000 // 100k with 8 decimal digits MiniTokenSupplyRange1UpperBound int64 = 1000000000000 + MaxTokenURILength = 2048 ) type MiniToken struct { @@ -114,24 +115,24 @@ func ValidateMapperMiniTokenSymbol(symbol string) error { // check len without suffix if len(symbolPart) < MiniTokenSymbolMinLen { - return fmt.Errorf("mini token symbol part is too short, got %d chars", len(symbolPart)) + return fmt.Errorf("mini-token symbol part is too short, got %d chars", len(symbolPart)) } if len(symbolPart) > MiniTokenSymbolMaxLen { - return fmt.Errorf("mini token symbol part is too long, got %d chars", len(symbolPart)) + return fmt.Errorf("mini-token symbol part is too long, got %d chars", len(symbolPart)) } if !utils.IsAlphaNum(symbolPart) { - return errors.New("mini token symbol part should be alphanumeric") + return errors.New("mini-token symbol part should be alphanumeric") } suffixPart := parts[1] if len(suffixPart) != MiniTokenSymbolSuffixLen { - return fmt.Errorf("mini token symbol suffix must be %d chars in length, got %d", MiniTokenSymbolSuffixLen, len(suffixPart)) + return fmt.Errorf("mini-token symbol suffix must be %d chars in length, got %d", MiniTokenSymbolSuffixLen, len(suffixPart)) } if suffixPart[len(suffixPart)-1:] != "M" { - return fmt.Errorf("mini token symbol suffix must end with M") + return fmt.Errorf("mini-token symbol suffix must end with M") } // prohibit non-hexadecimal chars in the suffix part @@ -140,7 +141,7 @@ func ValidateMapperMiniTokenSymbol(symbol string) error { return err } if !isHex { - return fmt.Errorf("mini token symbol tx hash suffix must be hex with a length of %d", MiniTokenSymbolTxHashSuffixLen) + return fmt.Errorf("mini-token symbol tx hash suffix must be hex with a length of %d", MiniTokenSymbolTxHashSuffixLen) } return nil @@ -151,11 +152,11 @@ func splitSuffixedMiniTokenSymbol(suffixed string) ([]string, error) { split := strings.SplitN(suffixed, "-", 2) if len(split) != 2 { - return nil, errors.New("suffixed mini token symbol must contain a hyphen ('-')") + return nil, errors.New("suffixed mini-token symbol must contain a hyphen ('-')") } if strings.Contains(split[1], "-") { - return nil, errors.New("suffixed mini token symbol must contain just one hyphen ('-')") + return nil, errors.New("suffixed mini-token symbol must contain just one hyphen ('-')") } return split, nil diff --git a/common/types/token.go b/common/types/token.go index fb7ab19e9..500260fd0 100644 --- a/common/types/token.go +++ b/common/types/token.go @@ -93,6 +93,16 @@ func ValidateIssueMsgTokenSymbol(symbol string) error { return nil } +func ValidateMapperTokenCoins(coins sdk.Coins) error { + for _, coin := range coins { + err := ValidateMapperTokenSymbol(coin.Denom) + if err != nil { + return err + } + } + return nil +} + func ValidateMapperTokenSymbol(symbol string) error { if len(symbol) == 0 { return errors.New("suffixed token symbol cannot be empty") diff --git a/go.mod b/go.mod index bf19909ad..8a994ef3a 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.20 + github.com/cosmos/cosmos-sdk => /Users/luerheng/go/src/github.com/binance-chain/bnc-cosmos-sdk/ github.com/tendermint/go-amino => github.com/binance-chain/bnc-go-amino v0.14.1-binance.2 github.com/tendermint/iavl => github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3 github.com/tendermint/tendermint => github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 diff --git a/plugins/miniTokens/abci.go b/plugins/miniTokens/abci.go index 5d45511e2..b98f77577 100644 --- a/plugins/miniTokens/abci.go +++ b/plugins/miniTokens/abci.go @@ -19,7 +19,7 @@ func createAbciQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { return nil } switch path[1] { - case "info": // args: ["tokens", "info", ] + case "info": // args: ["miniTokens", "info", ] if len(path) < 3 { return &abci.ResponseQuery{ Code: uint32(sdk.CodeUnknownRequest), diff --git a/plugins/miniTokens/burn/handler.go b/plugins/miniTokens/burn/handler.go new file mode 100644 index 000000000..980a9195a --- /dev/null +++ b/plugins/miniTokens/burn/handler.go @@ -0,0 +1,84 @@ +package burn + +import ( + "fmt" + "reflect" + "strings" + + common "github.com/binance-chain/node/common/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" + + "github.com/binance-chain/node/common/log" + "github.com/binance-chain/node/plugins/miniTokens/store" +) + +func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + if msg, ok := msg.(BurnMsg); ok { + return handleBurnToken(ctx, tokenMapper, keeper, msg) + } + + errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } +} + +func handleBurnToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, keeper bank.Keeper, msg BurnMsg) sdk.Result { + logger := log.With("module", "miniToken", "symbol", msg.Symbol, "amount", msg.Amount) + burnAmount := msg.Amount + symbol := strings.ToUpper(msg.Symbol) + token, err := tokenMapper.GetToken(ctx, symbol) + errLogMsg := "burn token failed" + if err != nil { + logger.Info("burn token failed", "reason", "invalid token symbol") + return sdk.ErrInvalidCoins(err.Error()).Result() + } + + if !token.IsOwner(msg.From) { + logger.Info("burn token failed", "reason", "not token's owner", "from", msg.From, "owner", token.Owner) + return sdk.ErrUnauthorized("only the owner of the token can burn the token").Result() + } + + coins := keeper.GetCoins(ctx, token.Owner) + + useAllBalance := coins.AmountOf(symbol) == burnAmount + + if !useAllBalance && (burnAmount % common.MiniTokenMinTotalSupply !=0) { + logger.Info(errLogMsg, "reason", "unfreeze amount is not integer") + return sdk.ErrInvalidCoins( + fmt.Sprintf("amount should be a multiple of %v or equals total frozen balance", common.MiniTokenMinTotalSupply)).Result() + } + + if burnAmount<=0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { + logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", + common.MiniTokenMinTotalSupply)).Result() + } + + + if coins.AmountOf(symbol) < burnAmount || + token.TotalSupply.ToInt64() < burnAmount { + logger.Info("burn token failed", "reason", "no enough tokens to burn") + return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() + } + + _, _, sdkError := keeper.SubtractCoins(ctx, token.Owner, sdk.Coins{{ + Denom: symbol, + Amount: burnAmount, + }}) + if sdkError != nil { + logger.Error("burn token failed", "reason", "subtract tokens failed: "+sdkError.Error()) + return sdkError.Result() + } + + newTotalSupply := token.TotalSupply.ToInt64() - burnAmount + err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) + if err != nil { + logger.Error("burn token failed", "reason", "update total supply failed: "+err.Error()) + return sdk.ErrInternal(err.Error()).Result() + } + + logger.Info("successfully burnt token", "NewTotalSupply", newTotalSupply) + return sdk.Result{} +} diff --git a/plugins/miniTokens/burn/msg.go b/plugins/miniTokens/burn/msg.go new file mode 100644 index 000000000..24ba028c3 --- /dev/null +++ b/plugins/miniTokens/burn/msg.go @@ -0,0 +1,61 @@ +package burn + +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" +) + +// TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash +// const BurnRoute = "tokens/burn" +const BurnRoute = "miniTokensBurn" + +var _ sdk.Msg = BurnMsg{} + +type BurnMsg struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + Amount int64 `json:"amount"` +} + +func NewMsg(from sdk.AccAddress, symbol string, amount int64) BurnMsg { + return BurnMsg{ + From: from, + Symbol: symbol, + Amount: amount, + } +} + +func (msg BurnMsg) Route() string { return BurnRoute } +func (msg BurnMsg) Type() string { return BurnRoute } +func (msg BurnMsg) String() string { + return fmt.Sprintf("BurnMsg{%v#%v%v}", msg.From, msg.Amount, msg.Symbol) +} +func (msg BurnMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } +func (msg BurnMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } + +// ValidateBasic does a simple validation check that +// doesn't require access to any other information. +func (msg BurnMsg) ValidateBasic() sdk.Error { + // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") + err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) + if err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + if msg.Amount <= 0 { + // TODO: maybe we need to define our own errors + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil +} + +func (msg BurnMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} diff --git a/plugins/miniTokens/client/cli/burn.go b/plugins/miniTokens/client/cli/burn.go new file mode 100644 index 000000000..85969622b --- /dev/null +++ b/plugins/miniTokens/client/cli/burn.go @@ -0,0 +1,35 @@ +package commands + +import ( + "github.com/binance-chain/node/common/types" + "github.com/spf13/cobra" + "github.com/spf13/viper" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/binance-chain/node/plugins/miniTokens/burn" +) + +func burnTokenCmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "burn", + Short: "burn some amount of mini-token", + RunE: cmdr.burnToken, + } + + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the token to be burnt") + cmd.Flags().StringP(flagAmount, "n", "", "amount of the token to be burnt") + + return cmd +} + +func (c Commander) burnToken(cmd *cobra.Command, args []string) error { + symbol := viper.GetString(flagSymbol) + err := types.ValidateMapperMiniTokenSymbol(symbol) + if err != nil { + return err + } + burnMsgBuilder := func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg { + return burn.NewMsg(from, symbol, amount) + } + + return c.checkAndSendTx(cmd, args, burnMsgBuilder) +} diff --git a/plugins/miniTokens/client/cli/commands.go b/plugins/miniTokens/client/cli/commands.go index c92bd68a0..84d9f0dcc 100644 --- a/plugins/miniTokens/client/cli/commands.go +++ b/plugins/miniTokens/client/cli/commands.go @@ -11,6 +11,7 @@ import ( const ( flagSymbol = "symbol" flagAmount = "amount" + flagURI = "uri" ) func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { @@ -24,8 +25,13 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { cmdr := Commander{Cdc: cdc} miniTokenCmd.AddCommand( client.PostCommands( + getTokenInfoCmd(cmdr), issueMiniTokenCmd(cmdr), - mintMiniTokenCmd(cmdr))...) + mintMiniTokenCmd(cmdr), + freezeMiniTokenCmd(cmdr), + unfreezeMiniTokenCmd(cmdr), + burnTokenCmd(cmdr), + setTokenURICmd(cmdr),)...) miniTokenCmd.AddCommand(client.LineBreak) diff --git a/plugins/miniTokens/client/cli/freeze.go b/plugins/miniTokens/client/cli/freeze.go new file mode 100644 index 000000000..dcf66d18e --- /dev/null +++ b/plugins/miniTokens/client/cli/freeze.go @@ -0,0 +1,63 @@ +package commands + +import ( + "github.com/binance-chain/node/common/types" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/plugins/miniTokens/freeze" +) + +func freezeMiniTokenCmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "freeze", + Short: "freeze some amount of mini-token", + RunE: cmdr.freezeToken, + } + + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the token to be frozen") + cmd.Flags().StringP(flagAmount, "n", "", "amount of the token to be frozen") + + return cmd +} + +func unfreezeMiniTokenCmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "unfreeze", + Short: "unfreeze some amount of mini-token", + RunE: cmdr.unfreeze, + } + + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the token to be frozen") + cmd.Flags().StringP(flagAmount, "n", "", "amount of the token to be frozen") + + return cmd +} + +func (c Commander) freezeToken(cmd *cobra.Command, args []string) error { + symbol := viper.GetString(flagSymbol) + err := types.ValidateMapperMiniTokenSymbol(symbol) + if err != nil { + return err + } + freezeMsgBuilder := func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg { + return freeze.NewFreezeMsg(from, symbol, amount) + } + + return c.checkAndSendTx(cmd, args, freezeMsgBuilder) +} + +func (c Commander) unfreeze(cmd *cobra.Command, args []string) error { + symbol := viper.GetString(flagSymbol) + err := types.ValidateMapperMiniTokenSymbol(symbol) + if err != nil { + return err + } + unfreezeMsgBuilder := func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg { + return freeze.NewUnfreezeMsg(from, symbol, amount) + } + + return c.checkAndSendTx(cmd, args, unfreezeMsgBuilder) +} diff --git a/plugins/miniTokens/client/cli/helper.go b/plugins/miniTokens/client/cli/helper.go index 36d36ee7c..735a0d7a7 100644 --- a/plugins/miniTokens/client/cli/helper.go +++ b/plugins/miniTokens/client/cli/helper.go @@ -60,3 +60,10 @@ func parseAmount(amountStr string) (int64, error) { return amount, nil } + +func validateTokenURI(uri string) error { + if len(uri) > 2048 { + return errors.New("uri cannot be longer than 2048 characters") + } + return nil +} diff --git a/plugins/miniTokens/client/cli/info.go b/plugins/miniTokens/client/cli/info.go new file mode 100644 index 000000000..5ce4d76a6 --- /dev/null +++ b/plugins/miniTokens/client/cli/info.go @@ -0,0 +1,64 @@ +package commands + +import ( + "fmt" + "strings" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + + "github.com/binance-chain/node/common" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/wire" +) + +func getTokenInfoCmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "info ", + Short: "Query mini-token info", + RunE: cmdr.runGetToken, + } + + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the mini-token") + return cmd +} + +func (c Commander) runGetToken(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(c.Cdc) + + symbol := viper.GetString(flagSymbol) + if len(symbol) == 0 { + return errors.New("you must provide the symbol") + } + + key := []byte(strings.ToUpper(symbol)) + + res, err := ctx.QueryStore(key, common.MiniTokenStoreName) + if err != nil { + return err + } + + if len(res) == 0 { + fmt.Printf("No such mini-token(%v) exists\n", symbol) + return nil + } + + // decode the value + token := new(types.MiniToken) + err = c.Cdc.UnmarshalBinaryBare(res, &token) + if err != nil { + return err + } + + // print out the toke info + output, err := wire.MarshalJSONIndent(c.Cdc, token) + if err != nil { + return err + } + + fmt.Println(string(output)) + return nil +} diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/miniTokens/client/cli/issue.go index df8a81b8b..2f78bb3fe 100644 --- a/plugins/miniTokens/client/cli/issue.go +++ b/plugins/miniTokens/client/cli/issue.go @@ -21,7 +21,7 @@ const ( func issueMiniTokenCmd(cmdr Commander) *cobra.Command { cmd := &cobra.Command{ Use: "issue", - Short: "issue a new mini token", + Short: "issue a new mini-token", RunE: cmdr.issueToken, } @@ -131,10 +131,3 @@ func checkSupplyAmount(amount, maxAmount int64) error { } return nil } - -func validateTokenURI(uri string) error { - if len(uri) > 2048 { - return errors.New("uri cannot be longer than 2048 characters") - } - return nil -} diff --git a/plugins/miniTokens/client/cli/uri.go b/plugins/miniTokens/client/cli/uri.go new file mode 100644 index 000000000..d4864fa1d --- /dev/null +++ b/plugins/miniTokens/client/cli/uri.go @@ -0,0 +1,44 @@ +package commands + +import ( + "github.com/binance-chain/node/common/client" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/miniTokens/uri" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func setTokenURICmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "set-uri --symbol {symbol} --uri {token uri} --from {token issuer address}", + Short: "set token URI of mini-token", + RunE: cmdr.setTokenURI, + } + + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the mini-token") + cmd.Flags().StringP(flagURI, "u", "", "a distinct uri for the mini-token") + cmd.Flags().String(flagTokenUri, "", "uri of the token information") + + return cmd +} + +func (c Commander) setTokenURI(cmd *cobra.Command, args []string) error { + cliCtx, txBldr := client.PrepareCtx(c.Cdc) + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + symbol := viper.GetString(flagSymbol) + err = types.ValidateMapperMiniTokenSymbol(symbol) + if err != nil { + return err + } + tokenURI := viper.GetString(flagTokenUri) + err = validateTokenURI(tokenURI) + if err != nil { + return err + } + + msg := uri.NewSetUriMsg(from, symbol, tokenURI) + return client.SendOrPrintTx(cliCtx, txBldr, msg) +} diff --git a/plugins/miniTokens/freeze/handler.go b/plugins/miniTokens/freeze/handler.go new file mode 100644 index 000000000..10c0744e7 --- /dev/null +++ b/plugins/miniTokens/freeze/handler.go @@ -0,0 +1,113 @@ +package freeze + +import ( + "fmt" + "reflect" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + + "github.com/binance-chain/node/common/log" + common "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/miniTokens/store" +) + +// NewHandler creates a new token freeze message handler +func NewHandler(tokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case FreezeMsg: + return handleFreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) + case UnfreezeMsg: + return handleUnfreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) + default: + errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleFreezeToken(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg FreezeMsg) sdk.Result { + freezeAmount := msg.Amount + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "miniToken", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) + errLogMsg := "freeze token failed" + _, err := miniTokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info(errLogMsg, "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + coins := keeper.GetCoins(ctx, msg.From) + if coins.AmountOf(symbol) < freezeAmount { + logger.Info(errLogMsg, "reason", "no enough free tokens to freeze") + return sdk.ErrInsufficientCoins("do not have enough token to freeze").Result() + } + + useAllBalance := coins.AmountOf(symbol) == freezeAmount + + if !useAllBalance && (msg.Amount % common.MiniTokenMinTotalSupply !=0) { + logger.Info(errLogMsg, "reason", "freeze amount is not integer") + return sdk.ErrInvalidCoins( + fmt.Sprintf("amount should be a multiple of %v or equals total account balance", common.MiniTokenMinTotalSupply)).Result() + } + + if msg.Amount<=0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinTotalSupply)){ + logger.Info(errLogMsg, "reason", "freeze amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", + common.MiniTokenMinTotalSupply)).Result() + } + + account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) + newFrozenTokens := account.GetFrozenCoins().Plus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) + newFreeTokens := account.GetCoins().Minus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) + account.SetFrozenCoins(newFrozenTokens) + account.SetCoins(newFreeTokens) + accKeeper.SetAccount(ctx, account) + logger.Info("finish freezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) + return sdk.Result{} +} + +func handleUnfreezeToken(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg UnfreezeMsg) sdk.Result { + unfreezeAmount := msg.Amount + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "miniToken", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) + account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) + frozenAmount := account.GetFrozenCoins().AmountOf(symbol) + useAllFrozenBalance := frozenAmount == unfreezeAmount + errLogMsg := "unfreeze token failed" + + _, err := miniTokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info(errLogMsg, "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + if !useAllFrozenBalance && (unfreezeAmount % common.MiniTokenMinTotalSupply !=0) { + logger.Info(errLogMsg, "reason", "unfreeze amount is not integer") + return sdk.ErrInvalidCoins( + fmt.Sprintf("amount should be a multiple of %v or equals total frozen balance", common.MiniTokenMinTotalSupply)).Result() + } + + if unfreezeAmount<=0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinTotalSupply)) { + logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", + common.MiniTokenMinTotalSupply)).Result() + } + + if frozenAmount < unfreezeAmount { + logger.Info(errLogMsg, "reason", "no enough frozen tokens to unfreeze") + return sdk.ErrInsufficientCoins("do not have enough token to unfreeze").Result() + } + + newFrozenTokens := account.GetFrozenCoins().Minus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) + newFreeTokens := account.GetCoins().Plus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) + + account.SetFrozenCoins(newFrozenTokens) + account.SetCoins(newFreeTokens) + accKeeper.SetAccount(ctx, account) + logger.Debug("finish unfreezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) + return sdk.Result{} +} diff --git a/plugins/miniTokens/freeze/msg.go b/plugins/miniTokens/freeze/msg.go new file mode 100644 index 000000000..4c9b9fdc1 --- /dev/null +++ b/plugins/miniTokens/freeze/msg.go @@ -0,0 +1,100 @@ +package freeze + +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" +) + +// TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash +const FreezeRoute = "miniTokensFreeze" + +var _ sdk.Msg = FreezeMsg{} + +type FreezeMsg struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + Amount int64 `json:"amount"` +} + +func NewFreezeMsg(from sdk.AccAddress, symbol string, amount int64) FreezeMsg { + return FreezeMsg{ + From: from, + Symbol: symbol, + Amount: amount, + } +} + +func (msg FreezeMsg) Route() string { return FreezeRoute } +func (msg FreezeMsg) Type() string { return FreezeRoute } +func (msg FreezeMsg) String() string { + return fmt.Sprintf("Freeze{%v#%v%v}", msg.From, msg.Amount, msg.Symbol) +} +func (msg FreezeMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } +func (msg FreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } + +// ValidateBasic does a simple validation check that +// doesn't require access to any other information. +func (msg FreezeMsg) ValidateBasic() sdk.Error { + // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") + err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) + if err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + if msg.Amount <= 0 { + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil +} + +func (msg FreezeMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} + +var _ sdk.Msg = UnfreezeMsg{} + +type UnfreezeMsg struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + Amount int64 `json:"amount"` +} + +func NewUnfreezeMsg(from sdk.AccAddress, symbol string, amount int64) UnfreezeMsg { + return UnfreezeMsg{ + From: from, Symbol: symbol, Amount: amount} +} + +func (msg UnfreezeMsg) Route() string { return FreezeRoute } +func (msg UnfreezeMsg) Type() string { return FreezeRoute } +func (msg UnfreezeMsg) String() string { + return fmt.Sprintf("Unfreeze{%v#%v%v}", msg.From, msg.Amount, msg.Symbol) +} +func (msg UnfreezeMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } +func (msg UnfreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } + +func (msg UnfreezeMsg) ValidateBasic() sdk.Error { + // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") + err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) + if err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + if msg.Amount <= 0 { + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil +} + +func (msg UnfreezeMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} diff --git a/plugins/miniTokens/issue/handler.go b/plugins/miniTokens/issue/handler.go index 42d54aacf..f96a1fe4e 100644 --- a/plugins/miniTokens/issue/handler.go +++ b/plugins/miniTokens/issue/handler.go @@ -3,6 +3,7 @@ package issue import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" "reflect" "strconv" "strings" @@ -12,7 +13,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/common/types" common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/miniTokens/store" ) @@ -33,20 +33,24 @@ func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handl } func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKeeper bank.Keeper, msg IssueMsg) sdk.Result { - errLogMsg := "issue token failed" + errLogMsg := "issue miniToken failed" symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) + logger := log.With("module", "miniToken", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) var suffix string + if !sdk.IsUpgrade(upgrade.BEP69) { + return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")).Result() + } + // TxHashKey is set in BaseApp's runMsgs txHash := ctx.Value(baseapp.TxHashKey) if txHashStr, ok := txHash.(string); ok { - if len(txHashStr) >= types.MiniTokenSymbolTxHashSuffixLen { - suffix = txHashStr[:types.MiniTokenSymbolTxHashSuffixLen] + types.MiniTokenSymbolMSuffix + if len(txHashStr) >= common.MiniTokenSymbolTxHashSuffixLen { + suffix = txHashStr[:common.MiniTokenSymbolTxHashSuffixLen] + common.MiniTokenSymbolMSuffix } else { logger.Error(errLogMsg, "reason", fmt.Sprintf("%s on Context had a length of %d, expected >= %d", - baseapp.TxHashKey, len(txHashStr), types.MiniTokenSymbolTxHashSuffixLen)) + baseapp.TxHashKey, len(txHashStr), common.MiniTokenSymbolTxHashSuffixLen)) return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() } } else { @@ -55,16 +59,16 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() } - if msg.MaxTotalSupply % types.MiniTokenMinTotalSupply !=0 { + if msg.MaxTotalSupply % common.MiniTokenMinTotalSupply !=0 { logger.Info(errLogMsg, "reason", "max total supply is not integer") return sdk.ErrInvalidCoins( - fmt.Sprintf("max total supply should be a multiple of %v", types.MiniTokenMinTotalSupply)).Result() + fmt.Sprintf("max total supply should be a multiple of %v", common.MiniTokenMinTotalSupply)).Result() } - if msg.TotalSupply % types.MiniTokenMinTotalSupply !=0 { + if msg.TotalSupply % common.MiniTokenMinTotalSupply !=0 { logger.Info(errLogMsg, "reason", "total supply is not integer") return sdk.ErrInvalidCoins( - fmt.Sprintf("total supply should be a multiple of %v", types.MiniTokenMinTotalSupply)).Result() + fmt.Sprintf("total supply should be a multiple of %v", common.MiniTokenMinTotalSupply)).Result() } if msg.MaxTotalSupply < common.MiniTokenMinTotalSupply { @@ -96,9 +100,9 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe // the symbol is suffixed with the first n bytes of the tx hash symbol = fmt.Sprintf("%s-%s", symbol, suffix) - if !types.IsMiniTokenSymbol(symbol) { + if !common.IsMiniTokenSymbol(symbol) { logger.Info(errLogMsg, "reason", "symbol not valid") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) is not valid for mini token", symbol)).Result() + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) is not valid for mini-token", symbol)).Result() } if exists := tokenMapper.Exists(ctx, symbol); exists { @@ -140,12 +144,12 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe } } -func handleMintToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { +func handleMintToken(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "token", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) + logger := log.With("module", "miniToken", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) errLogMsg := "mint token failed" - token, err := tokenMapper.GetToken(ctx, symbol) + token, err := miniTokenMapper.GetToken(ctx, symbol) if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() @@ -161,10 +165,10 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKee return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() } - if msg.Amount % types.MiniTokenMinTotalSupply !=0 { + if msg.Amount % common.MiniTokenMinTotalSupply !=0 { logger.Info(errLogMsg, "reason", "mint amount is not integer") return sdk.ErrInvalidCoins( - fmt.Sprintf("amount should be a multiple of %v", types.MiniTokenMinTotalSupply)).Result() + fmt.Sprintf("amount should be a multiple of %v", common.MiniTokenMinTotalSupply)).Result() } if msg.Amount < common.MiniTokenMinTotalSupply { @@ -185,7 +189,7 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKee common.MiniTokenMaxTotalSupplyUpperBound)).Result() } newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount - err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) + err = miniTokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) if err != nil { logger.Error(errLogMsg, "reason", "update total supply failed: "+err.Error()) return sdk.ErrInternal(fmt.Sprintf("update total supply failed")).Result() diff --git a/plugins/miniTokens/issue/handler_test.go b/plugins/miniTokens/issue/handler_test.go index 48ffef1e9..2a935f758 100644 --- a/plugins/miniTokens/issue/handler_test.go +++ b/plugins/miniTokens/issue/handler_test.go @@ -108,5 +108,5 @@ func TestHandleMintToken(t *testing.T) { // mint native token invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) - require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "suffixed mini token symbol must contain a hyphen") + require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "suffixed mini-token symbol must contain a hyphen") } diff --git a/plugins/miniTokens/issue/msg.go b/plugins/miniTokens/issue/msg.go index 616782f50..48d294f14 100644 --- a/plugins/miniTokens/issue/msg.go +++ b/plugins/miniTokens/issue/msg.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/binance-chain/node/common/types" ) @@ -17,7 +16,6 @@ const ( MintMsgType = "miniMintMsg" maxTokenNameLength = 32 - maxTokenURILength = 2048 ) var _ sdk.Msg = IssueMsg{} @@ -59,8 +57,8 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidCoins(fmt.Sprintf("token name should have 1 ~ %v characters", maxTokenNameLength)) } - if len(msg.TokenURI) > maxTokenURILength { - return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", maxTokenURILength)) + if len(msg.TokenURI) > types.MaxTokenURILength { + return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", types.MaxTokenURILength)) } if msg.MaxTotalSupply%types.MiniTokenMinTotalSupply != 0 { diff --git a/plugins/miniTokens/route.go b/plugins/miniTokens/route.go index f00a6f0d9..71cb6f8d0 100644 --- a/plugins/miniTokens/route.go +++ b/plugins/miniTokens/route.go @@ -1,8 +1,11 @@ package miniTokens import ( + "github.com/binance-chain/node/plugins/miniTokens/burn" + "github.com/binance-chain/node/plugins/miniTokens/freeze" "github.com/binance-chain/node/plugins/miniTokens/issue" "github.com/binance-chain/node/plugins/miniTokens/store" + "github.com/binance-chain/node/plugins/miniTokens/uri" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" @@ -11,5 +14,9 @@ import ( func Routes(tokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) routes[issue.Route] = issue.NewHandler(tokenMapper, keeper) + routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, accKeeper, keeper) + routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, accKeeper, keeper) + routes[burn.BurnRoute] = burn.NewHandler(tokenMapper,keeper) + routes[uri.SetURIRoute] = uri.NewHandler(tokenMapper) return routes } diff --git a/plugins/miniTokens/uri/handler.go b/plugins/miniTokens/uri/handler.go new file mode 100644 index 000000000..bc514f2f2 --- /dev/null +++ b/plugins/miniTokens/uri/handler.go @@ -0,0 +1,59 @@ +package uri + +import ( + "fmt" + "github.com/binance-chain/node/common/log" + common "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/miniTokens/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "reflect" + "strings" +) + +func NewHandler(tokenMapper store.MiniTokenMapper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case SetURIMsg: + return handleSetURI(ctx, tokenMapper, msg) + default: + errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleSetURI(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, msg SetURIMsg) sdk.Result { + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "miniToken", "symbol", symbol, "tokenURI", msg.TokenURI, "from", msg.From) + + errLogMsg := "set token URI failed" + token, err := miniTokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info(errLogMsg, "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + if !token.IsOwner(msg.From) { + logger.Info(errLogMsg, "reason", "not the token owner") + return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() + } + + if len(msg.TokenURI) < 1 { + return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", common.MaxTokenURILength)).Result() + } + + if len(msg.TokenURI) > common.MaxTokenURILength { + return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", common.MaxTokenURILength)).Result() + } + err = miniTokenMapper.UpdateTokenURI(ctx, symbol, msg.TokenURI) + if err != nil { + logger.Error(errLogMsg, "reason", "update token uri failed: "+err.Error()) + return sdk.ErrInternal(fmt.Sprintf("update token uri failed")).Result() + } + + + logger.Info("finished update token uri") + return sdk.Result{ + Data: []byte(msg.TokenURI), + } +} diff --git a/plugins/miniTokens/uri/msg.go b/plugins/miniTokens/uri/msg.go new file mode 100644 index 000000000..d8c6c6d5b --- /dev/null +++ b/plugins/miniTokens/uri/msg.go @@ -0,0 +1,54 @@ +package uri + +import ( + "encoding/json" + "fmt" + "github.com/binance-chain/node/common/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const SetURIRoute = "miniTokensSetURI" + +var _ sdk.Msg = SetURIMsg{} + +type SetURIMsg struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + TokenURI string `json:"token_uri"` +} + +func NewSetUriMsg(from sdk.AccAddress, symbol string, tokenURI string) SetURIMsg { + return SetURIMsg{ + From: from, + Symbol: symbol, + TokenURI: tokenURI, + } +} + +func (msg SetURIMsg) ValidateBasic() sdk.Error { + if msg.From == nil || len(msg.From) == 0{ + return sdk.ErrInvalidAddress("sender address cannot be empty") + } + + if err := types.ValidateMapperMiniTokenSymbol(msg.Symbol); err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + + return nil +} + +// Implements MintMsg. +func (msg SetURIMsg) Route() string { return SetURIRoute } +func (msg SetURIMsg) Type() string { return SetURIRoute } +func (msg SetURIMsg) String() string { return fmt.Sprintf("SetURI{%#v}", msg) } +func (msg SetURIMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } +func (msg SetURIMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} +func (msg SetURIMsg) GetInvolvedAddresses() []sdk.AccAddress { + return msg.GetSigners() +} diff --git a/plugins/miniTokens/wire.go b/plugins/miniTokens/wire.go index 2b889c3d4..4cc8a4a36 100644 --- a/plugins/miniTokens/wire.go +++ b/plugins/miniTokens/wire.go @@ -1,7 +1,10 @@ package miniTokens import ( + "github.com/binance-chain/node/plugins/miniTokens/burn" + "github.com/binance-chain/node/plugins/miniTokens/freeze" "github.com/binance-chain/node/plugins/miniTokens/issue" + "github.com/binance-chain/node/plugins/miniTokens/uri" "github.com/binance-chain/node/wire" ) @@ -9,4 +12,8 @@ import ( func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(issue.IssueMsg{}, "miniTokens/IssueMsg", nil) cdc.RegisterConcrete(issue.MintMsg{}, "miniTokens/MintMsg", nil) + cdc.RegisterConcrete(freeze.FreezeMsg{}, "miniTokens/FreezeMsg", nil) + cdc.RegisterConcrete(freeze.UnfreezeMsg{}, "miniTokens/UnFreezeMsg", nil) + cdc.RegisterConcrete(burn.BurnMsg{}, "miniTokens/BurnMsg", nil) + cdc.RegisterConcrete(uri.SetURIMsg{}, "miniTokens/SetURIMsg", nil) } diff --git a/plugins/param/genesis.go b/plugins/param/genesis.go index cc2ac6b8e..88076d1e3 100644 --- a/plugins/param/genesis.go +++ b/plugins/param/genesis.go @@ -54,9 +54,12 @@ const ( IOCExpireFeeNative = 5e3 //MiniToken fee - MiniIssueFee = 10e8 - AdvMiniIssueFee = 20e8 - MiniMintFee = 2e8 + MiniIssueFee = 10e8 + AdvMiniIssueFee = 20e8 + MiniMintFee = 2e8 + MiniFreezeFee = 1e6 + MiniBurnFee = 2e8 + MiniSetUriFee = 1e8 ) var DefaultGenesisState = param.GenesisState{ diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 606101c58..30d40634f 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -13,7 +13,10 @@ import ( "github.com/binance-chain/node/plugins/account" "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" + miniBurn "github.com/binance-chain/node/plugins/miniTokens/burn" + miniFreeze "github.com/binance-chain/node/plugins/miniTokens/freeze" miniIssue "github.com/binance-chain/node/plugins/miniTokens/issue" + miniURI "github.com/binance-chain/node/plugins/miniTokens/uri" "github.com/binance-chain/node/plugins/param/paramhub" param "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/plugins/tokens" @@ -66,6 +69,9 @@ func RegisterUpgradeBeginBlocker(paramHub *ParamHub) { ¶m.FixedFeeParams{MsgType: miniIssue.IssueMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: miniIssue.AdvIssueMsgType, Fee: AdvMiniIssueFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: miniIssue.MintMsg{}.Type(), Fee: MiniMintFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: miniFreeze.FreezeMsg{}.Type(), Fee: MiniFreezeFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: miniBurn.BurnMsg{}.Type(), Fee: MiniBurnFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: miniURI.SetURIMsg{}.Type(), Fee: MiniSetUriFee, FeeFor: types.FeeForProposer}, } paramHub.UpdateFeeParams(ctx, miniTokenFeeParams) }) @@ -104,5 +110,8 @@ func init() { miniIssue.IssueMsgType: fees.FixedFeeCalculatorGen, miniIssue.AdvIssueMsgType: fees.FixedFeeCalculatorGen, miniIssue.MintMsgType: fees.FixedFeeCalculatorGen, + miniFreeze.FreezeRoute: fees.FixedFeeCalculatorGen, + miniBurn.BurnRoute: fees.FixedFeeCalculatorGen, + miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, } } diff --git a/plugins/param/types/types.go b/plugins/param/types/types.go index 9bf4d414a..1fdbc471c 100644 --- a/plugins/param/types/types.go +++ b/plugins/param/types/types.go @@ -41,9 +41,12 @@ var ( "claimHTLT": {}, "refundHTLT": {}, - "miniIssueMsg": {}, - "advMiniIssueMsg": {}, - "miniMintMsg": {}, + "miniIssueMsg": {}, + "advMiniIssueMsg": {}, + "miniMintMsg": {}, + "miniTokensFreeze": {}, + "miniTokensBurn": {}, + "miniTokensSetURI": {}, } ValidTransferFeeMsgTypes = map[string]struct{}{ diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 50b41971e..786dbbe33 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -1,6 +1,7 @@ package freeze import ( + "fmt" "reflect" "strings" @@ -52,6 +53,12 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au unfreezeAmount := msg.Amount symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "token", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) + + _, err := tokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info("unfreeze token failed", "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) frozenAmount := account.GetFrozenCoins().AmountOf(symbol) if frozenAmount < unfreezeAmount { diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index 57562cb73..110f202d2 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "fmt" + "github.com/binance-chain/node/common/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -27,6 +28,10 @@ func NewHandler(kp Keeper) sdk.Handler { } func handleHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg HTLTMsg) sdk.Result { + symbolError := types.ValidateMapperTokenCoins(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()).Result() + } blockTime := ctx.BlockHeader().Time.Unix() if msg.Timestamp < blockTime-ThirtyMinutes || msg.Timestamp > blockTime+FifteenMinutes { return ErrInvalidTimestamp(fmt.Sprintf("Timestamp (%d) can neither be 15 minutes ahead of the current time (%d), nor 30 minutes later", msg.Timestamp, ctx.BlockHeader().Time.Unix())).Result() @@ -61,6 +66,10 @@ func handleHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg HTLTMsg) sdk. } func handleDepositHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg DepositHTLTMsg) sdk.Result { + symbolError := types.ValidateMapperTokenCoins(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()).Result() + } swap := kp.GetSwap(ctx, msg.SwapID) if swap == nil { return ErrNonExistSwapID(fmt.Sprintf("No matched swap with swapID %v", msg.SwapID)).Result() diff --git a/plugins/tokens/timelock/handler.go b/plugins/tokens/timelock/handler.go index 5be0fca45..aecb9d773 100644 --- a/plugins/tokens/timelock/handler.go +++ b/plugins/tokens/timelock/handler.go @@ -2,6 +2,7 @@ package timelock import ( "fmt" + "github.com/binance-chain/node/common/types" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,6 +25,10 @@ func NewHandler(keeper Keeper) sdk.Handler { } func handleTimeLock(ctx sdk.Context, keeper Keeper, msg TimeLockMsg) sdk.Result { + symbolError := types.ValidateMapperTokenCoins(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()).Result() + } record, err := keeper.TimeLock(ctx, msg.From, msg.Description, msg.Amount, time.Unix(msg.LockTime, 0)) if err != nil { return err.Result() @@ -36,6 +41,10 @@ func handleTimeLock(ctx sdk.Context, keeper Keeper, msg TimeLockMsg) sdk.Result } func handleTimeRelock(ctx sdk.Context, keeper Keeper, msg TimeRelockMsg) sdk.Result { + symbolError := types.ValidateMapperTokenCoins(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()).Result() + } newRecord := TimeLockRecord{ Description: msg.Description, Amount: msg.Amount, From b2541f0e213b02de4f9499402be3351acee64425 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 31 Mar 2020 21:25:33 +0800 Subject: [PATCH 05/96] init trading related change --- admin/tx.go | 2 +- app/app.go | 12 +-- app/apptest/ordertx_test.go | 4 +- app/pub/helpers.go | 8 +- app/pub/keeper_pub_test.go | 8 +- app_test/abci_open_orders_test.go | 2 +- cmd/bnbcli/main.go | 2 +- cmd/dexperf/main.go | 4 +- common/stores.go | 2 +- plugins/api/server.go | 2 +- plugins/dex/listmini/handler.go | 83 ++++++++++++++++ plugins/dex/listmini/msg.go | 62 ++++++++++++ plugins/dex/order/keeper.go | 121 ++++++++++++++++++++--- plugins/dex/order/keeper_recovery.go | 14 ++- plugins/dex/order/keeper_test.go | 2 +- plugins/dex/store/mapper.go | 31 ++++++ plugins/dex/utils/pair.go | 9 ++ plugins/miniTokens/abci.go | 4 +- plugins/miniTokens/burn/handler.go | 2 +- plugins/miniTokens/client/cli/burn.go | 2 +- plugins/miniTokens/client/cli/freeze.go | 2 +- plugins/miniTokens/client/cli/issue.go | 2 +- plugins/miniTokens/client/cli/uri.go | 2 +- plugins/miniTokens/freeze/handler.go | 2 +- plugins/miniTokens/issue/handler.go | 2 +- plugins/miniTokens/issue/handler_test.go | 2 +- plugins/miniTokens/mini_tokens.go | 4 +- plugins/miniTokens/plugin.go | 4 +- plugins/miniTokens/route.go | 12 +-- plugins/miniTokens/uri/handler.go | 2 +- plugins/miniTokens/wire.go | 22 ++--- plugins/param/plugin.go | 8 +- 32 files changed, 361 insertions(+), 79 deletions(-) create mode 100644 plugins/dex/listmini/handler.go create mode 100644 plugins/dex/listmini/msg.go diff --git a/admin/tx.go b/admin/tx.go index 42cefc741..74755273e 100644 --- a/admin/tx.go +++ b/admin/tx.go @@ -12,7 +12,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" "github.com/binance-chain/node/plugins/tokens/timelock" - miniIssue "github.com/binance-chain/node/plugins/miniTokens/issue" + miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" ) var transferOnlyModeBlackList = []string{ diff --git a/app/app.go b/app/app.go index 143bbe7f3..38db31575 100644 --- a/app/app.go +++ b/app/app.go @@ -40,8 +40,8 @@ import ( "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/ico" - "github.com/binance-chain/node/plugins/miniTokens" - miniTkstore "github.com/binance-chain/node/plugins/miniTokens/store" + "github.com/binance-chain/node/plugins/minitokens" + miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" "github.com/binance-chain/node/plugins/param" "github.com/binance-chain/node/plugins/param/paramhub" "github.com/binance-chain/node/plugins/tokens" @@ -335,7 +335,7 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { func (app *BinanceChain) initPlugins() { tokens.InitPlugin(app, app.TokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) - miniTokens.InitPlugin(app, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper) + minitokens.InitPlugin(app, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper) dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.AccountKeeper, app.govKeeper) param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) @@ -530,9 +530,9 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a if sdk.IsUpgrade(upgrade.BEP19) || !isBreatheBlock { if app.publicationConfig.ShouldPublishAny() && pub.IsLive { - tradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, ctx) + tradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, ctx, isBreatheBlock) } else { - app.DexKeeper.MatchAndAllocateAll(ctx, nil) + app.DexKeeper.MatchAndAllocateAll(ctx, nil, isBreatheBlock) } } @@ -759,7 +759,7 @@ func MakeCodec() *wire.Codec { stake.RegisterCodec(cdc) gov.RegisterCodec(cdc) param.RegisterWire(cdc) - miniTokens.RegisterWire(cdc) + minitokens.RegisterWire(cdc) return cdc } diff --git a/app/apptest/ordertx_test.go b/app/apptest/ordertx_test.go index 50314a450..337863528 100644 --- a/app/apptest/ordertx_test.go +++ b/app/apptest/ordertx_test.go @@ -199,7 +199,7 @@ func Test_Match(t *testing.T) { buys, sells := getOrderBook("BTC-000_BNB") assert.Equal(4, len(buys)) assert.Equal(3, len(sells)) - testApp.DexKeeper.MatchAndAllocateAll(ctx, nil) + testApp.DexKeeper.MatchAndAllocateAll(ctx, nil, false) buys, sells = getOrderBook("BTC-000_BNB") assert.Equal(0, len(buys)) assert.Equal(3, len(sells)) @@ -254,7 +254,7 @@ func Test_Match(t *testing.T) { assert.Equal(4, len(buys)) assert.Equal(3, len(sells)) - testApp.DexKeeper.MatchAndAllocateAll(ctx, nil) + testApp.DexKeeper.MatchAndAllocateAll(ctx, nil, false) buys, sells = getOrderBook("ETH-000_BNB") t.Logf("buys: %v", buys) t.Logf("sells: %v", sells) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 74c19744b..b3e9ba900 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -17,7 +17,7 @@ import ( "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/types" orderPkg "github.com/binance-chain/node/plugins/dex/order" - miniIssue "github.com/binance-chain/node/plugins/miniTokens/issue" + miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" @@ -262,9 +262,7 @@ func GetAccountBalances(mapper auth.AccountKeeper, ctx sdk.Context, accSlices .. return } -func MatchAndAllocateAllForPublish( - dexKeeper *orderPkg.Keeper, - ctx sdk.Context) []*Trade { +func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.Keeper, ctx sdk.Context, matchAllMiniSymbols bool) []*Trade { // This channels is used for protect not update `dexKeeper.OrderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) // while dexKeeper.OrderChanges are not separated by concurrent factor (users here) @@ -284,7 +282,7 @@ func MatchAndAllocateAllForPublish( } } - dexKeeper.MatchAndAllocateAll(ctx, postAlloTransHandler) + dexKeeper.MatchAndAllocateAll(ctx, postAlloTransHandler, matchAllMiniSymbols) close(iocExpireFeeHolderCh) tradeIdx := 0 diff --git a/app/pub/keeper_pub_test.go b/app/pub/keeper_pub_test.go index 12cf498c5..982661d00 100644 --- a/app/pub/keeper_pub_test.go +++ b/app/pub/keeper_pub_test.go @@ -120,7 +120,7 @@ func TestKeeper_IOCExpireWithFee(t *testing.T) { require.Len(keeper.OrderChanges, 1) require.Len(keeper.OrderInfosForPub, 1) - trades := MatchAndAllocateAllForPublish(keeper, ctx) + trades := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(keeper.OrderChanges, 2) require.Len(keeper.OrderInfosForPub, 1) @@ -206,7 +206,7 @@ func Test_IOCPartialExpire(t *testing.T) { assert.Equal("s-1", orderChange1.Id) assert.Equal(orderPkg.Ack, orderChange1.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, ctx) + trades := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(keeper.OrderChanges, 3) require.Len(keeper.OrderInfosForPub, 2) @@ -246,7 +246,7 @@ func Test_GTEPartialExpire(t *testing.T) { assert.Equal("s-1", orderChange1.Id) assert.Equal(orderPkg.Ack, orderChange1.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, ctx) + trades := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(trades, 1) trade0 := trades[0] assert.Equal("0-0", trade0.Id) @@ -297,7 +297,7 @@ func Test_OneBuyVsTwoSell(t *testing.T) { assert.Equal("s-2", orderChange2.Id) assert.Equal(orderPkg.Ack, orderChange2.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, ctx) + trades := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(trades, 2) trade0 := trades[0] assert.Equal("0-0", trade0.Id) diff --git a/app_test/abci_open_orders_test.go b/app_test/abci_open_orders_test.go index 1b94ad65b..709bf29a6 100644 --- a/app_test/abci_open_orders_test.go +++ b/app_test/abci_open_orders_test.go @@ -38,7 +38,7 @@ func Test_Success(t *testing.T) { ctx = ctx.WithBlockHeader(abci.Header{Height: 101, Time: time.Unix(1, 0)}) ctx = ctx.WithBlockHeight(101) - keeper.MatchAndAllocateAll(ctx, nil) + keeper.MatchAndAllocateAll(ctx, nil, false) openOrders = issueMustSuccessQuery(pair, buyer, assert) require.Len(openOrders, 1) diff --git a/cmd/bnbcli/main.go b/cmd/bnbcli/main.go index cc8727fe7..bd83e5ff3 100644 --- a/cmd/bnbcli/main.go +++ b/cmd/bnbcli/main.go @@ -21,7 +21,7 @@ import ( accountcmd "github.com/binance-chain/node/plugins/account/client/cli" apiserv "github.com/binance-chain/node/plugins/api" dexcmd "github.com/binance-chain/node/plugins/dex/client/cli" - miniTokencmd "github.com/binance-chain/node/plugins/miniTokens/client/cli" + miniTokencmd "github.com/binance-chain/node/plugins/minitokens/client/cli" paramcmd "github.com/binance-chain/node/plugins/param/client/cli" tokencmd "github.com/binance-chain/node/plugins/tokens/client/cli" "github.com/binance-chain/node/version" diff --git a/cmd/dexperf/main.go b/cmd/dexperf/main.go index 5639b6cfc..b4966982e 100644 --- a/cmd/dexperf/main.go +++ b/cmd/dexperf/main.go @@ -7,7 +7,7 @@ import ( "encoding/json" "flag" "fmt" - "github.com/binance-chain/node/plugins/miniTokens" + "github.com/binance-chain/node/plugins/minitokens" "io/ioutil" "math/rand" "os" @@ -545,7 +545,7 @@ func MakeCodec() *wire.Codec { tokens.RegisterWire(cdc) types.RegisterWire(cdc) tx.RegisterWire(cdc) - miniTokens.RegisterWire(cdc) + minitokens.RegisterWire(cdc) return cdc } diff --git a/common/stores.go b/common/stores.go index 57ec9ec94..693b6023c 100644 --- a/common/stores.go +++ b/common/stores.go @@ -7,7 +7,7 @@ const ( AccountStoreName = "acc" ValAddrStoreName = "val" TokenStoreName = "tokens" - MiniTokenStoreName = "miniTokens" + MiniTokenStoreName = "minitokens" DexStoreName = "dex" PairStoreName = "pairs" StakeStoreName = "stake" diff --git a/plugins/api/server.go b/plugins/api/server.go index f03788b05..77ab62a90 100644 --- a/plugins/api/server.go +++ b/plugins/api/server.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/binance-chain/node/common" - miniTkstore "github.com/binance-chain/node/plugins/miniTokens/store" + miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" tkstore "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) diff --git a/plugins/dex/listmini/handler.go b/plugins/dex/listmini/handler.go new file mode 100644 index 000000000..538e083f7 --- /dev/null +++ b/plugins/dex/listmini/handler.go @@ -0,0 +1,83 @@ +package list + +import ( + "fmt" + "reflect" + + "github.com/binance-chain/node/common/log" + common "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/plugins/dex/order" + "github.com/binance-chain/node/plugins/dex/types" + "github.com/binance-chain/node/plugins/dex/utils" + "github.com/binance-chain/node/plugins/minitokens" + "github.com/binance-chain/node/plugins/tokens" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov" +) + +// NewHandler initialises dex message handlers +func NewHandler(keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper,tokenMapper tokens.Mapper, govKeeper gov.Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case ListMiniMsg: + return handleList(ctx, keeper, miniTokenMapper, tokenMapper, govKeeper, msg) + default: + errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleList(ctx sdk.Context, keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper,govKeeper gov.Keeper, + msg ListMiniMsg) sdk.Result { + if !sdk.IsUpgrade(upgrade.BEP69) { + return sdk.ErrInternal(fmt.Sprint("list miniToken is not supported at current height")).Result() + } + + if err := keeper.CanListTradingPair(ctx, msg.BaseAssetSymbol, msg.QuoteAssetSymbol); err != nil { + return sdk.ErrInvalidCoins(err.Error()).Result() + } + + baseToken, err := miniTokenMapper.GetToken(ctx, msg.BaseAssetSymbol) + if err != nil { + return sdk.ErrInvalidCoins(err.Error()).Result() + } + + quoteToken, err := tokenMapper.GetToken(ctx, msg.QuoteAssetSymbol) + if err != nil { + return sdk.ErrInvalidCoins(err.Error()).Result() + } + + if !baseToken.IsOwner(msg.From) && !quoteToken.IsOwner(msg.From) { + return sdk.ErrUnauthorized("only the owner of the base asset or quote asset can list the trading pair").Result() + } + + if !tokenMapper.Exists(ctx, msg.QuoteAssetSymbol) { + return sdk.ErrInvalidCoins("quote token does not exist").Result() + } + + if common.NativeTokenSymbol != msg.QuoteAssetSymbol {//todo permit BUSD + return sdk.ErrInvalidCoins("quote token: " + err.Error()).Result() + } + + var lotSize int64 + if sdk.IsUpgrade(upgrade.LotSizeOptimization) { + lotSize = keeper.DetermineLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice) + } else { + lotSize = utils.CalcLotSize(msg.InitPrice) + } + pair := types.NewTradingPairWithLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice, lotSize) + err = keeper.PairMapper.AddTradingPair(ctx, pair) + if err != nil { + return sdk.ErrInternal(err.Error()).Result() + } + + // this is done in memory! we must not run this block in checktx or simulate! + if ctx.IsDeliverTx() { // only add engine during DeliverTx + keeper.AddEngine(pair) + log.With("module", "dex").Info("List new mini-token Pair and created new match engine", "pair", pair) + } + + return sdk.Result{} +} diff --git a/plugins/dex/listmini/msg.go b/plugins/dex/listmini/msg.go new file mode 100644 index 000000000..be1af7fd4 --- /dev/null +++ b/plugins/dex/listmini/msg.go @@ -0,0 +1,62 @@ +package list + +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" +) + +const ListMiniRoute = "dexListMini" + +var _ sdk.Msg = ListMiniMsg{} + +type ListMiniMsg struct { + From sdk.AccAddress `json:"from"` + BaseAssetSymbol string `json:"base_asset_symbol"` + QuoteAssetSymbol string `json:"quote_asset_symbol"` + InitPrice int64 `json:"init_price"` +} + +func NewMsg(from sdk.AccAddress, baseAssetSymbol string, quoteAssetSymbol string, initPrice int64) ListMiniMsg { + return ListMiniMsg{ + From: from, + BaseAssetSymbol: baseAssetSymbol, + QuoteAssetSymbol: quoteAssetSymbol, + InitPrice: initPrice, + } +} + +func (msg ListMiniMsg) Route() string { return ListMiniRoute } +func (msg ListMiniMsg) Type() string { return ListMiniRoute } +func (msg ListMiniMsg) String() string { return fmt.Sprintf("MsgListMini{%#v}", msg) } +func (msg ListMiniMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } + +func (msg ListMiniMsg) ValidateBasic() sdk.Error { + + err := types.ValidateMapperMiniTokenSymbol(msg.BaseAssetSymbol) + if err != nil { + return sdk.ErrInvalidCoins("base token: " + err.Error()) + } + if types.NativeTokenSymbol != msg.QuoteAssetSymbol {//todo permit BUSD + return sdk.ErrInvalidCoins("quote token: " + err.Error()) + } + if msg.InitPrice <= 0 { + return sdk.ErrInvalidCoins("price should be positive") + } + return nil +} + +func (msg ListMiniMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return b +} + +func (msg ListMiniMsg) GetInvolvedAddresses() []sdk.AccAddress { + return msg.GetSigners() +} diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index c50ecfba2..68d41b927 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -3,6 +3,7 @@ package order import ( "errors" "fmt" + "hash/crc32" "math" "strings" "sync" @@ -30,9 +31,11 @@ import ( ) const ( - numPricesStored = 2000 - pricesStoreEvery = 1000 - minimalNumPrices = 500 + numPricesStored = 2000 + pricesStoreEvery = 1000 + minimalNumPrices = 500 + defaultMiniBlockMatchInterval = 16 + defaultActiveMiniSymbolCount = 8 ) type FeeHandler func(map[string]*types.Fee) @@ -52,8 +55,12 @@ type Keeper struct { OrderInfosForPub OrderInfoForPublish // for publication usage roundOrders map[string][]string // limit to the total tx number in a block roundIOCOrders map[string][]string - RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee - poolSize uint // number of concurrent channels, counted in the pow of 2 + roundOrdersMini map[string][]string // round orders for mini token which could be kept for several blocks + roundIOCOrdersMini map[string][]string + matchedMiniSymbols []string //mini token pairs matched in this round + miniSymbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin + RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee + poolSize uint // number of concurrent channels, counted in the pow of 2 cdc *wire.Codec FeeManager *FeeManager CollectOrderInfoForPublish bool @@ -81,6 +88,10 @@ func NewKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store. OrderInfosForPub: make(OrderInfoForPublish), roundOrders: make(map[string][]string, 256), roundIOCOrders: make(map[string][]string, 256), + roundOrdersMini: make(map[string][]string, 256), + roundIOCOrdersMini: make(map[string][]string, 256), + matchedMiniSymbols: make([]string, 0, 256), + miniSymbolsHash: make(map[string]uint32, 256), RoundOrderFees: make(map[string]*types.Fee, 256), poolSize: concurrency, cdc: cdc, @@ -101,6 +112,12 @@ func (kp *Keeper) InitRecentPrices(ctx sdk.Context) { func (kp *Keeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { symbol := strings.ToUpper(pair.GetSymbol()) + if sdk.IsUpgrade(upgrade.BEP69) { + baseSymbol := strings.ToUpper(pair.BaseAssetSymbol) + if types.IsMiniTokenSymbol(baseSymbol) { + kp.miniSymbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) + } + } eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) kp.engines[symbol] = eng kp.allOrders[symbol] = map[string]*OrderInfo{} @@ -208,6 +225,17 @@ func (kp *Keeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { } kp.allOrders[symbol][info.Id] = &info + + if (!sdk.IsUpgrade(upgrade.BEP69)) || !dexUtils.IsMiniTokenTradingPair(symbol) { + kp.addBEP2RoundOrders(symbol, info) + } else { + kp.addMiniRoundOrders(symbol, info) + } + kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) + return nil +} + +func (kp *Keeper) addBEP2RoundOrders(symbol string, info OrderInfo) { if ids, ok := kp.roundOrders[symbol]; ok { kp.roundOrders[symbol] = append(ids, info.Id) } else { @@ -217,8 +245,18 @@ func (kp *Keeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { if info.TimeInForce == TimeInForce.IOC { kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], info.Id) } - kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) - return nil +} + +func (kp *Keeper) addMiniRoundOrders(symbol string, info OrderInfo) { + if ids, ok := kp.roundOrdersMini[symbol]; ok { + kp.roundOrdersMini[symbol] = append(ids, info.Id) + } else { + newIds := make([]string, 0, 16) + kp.roundOrdersMini[symbol] = append(newIds, info.Id) + } + if info.TimeInForce == TimeInForce.IOC { + kp.roundIOCOrdersMini[symbol] = append(kp.roundIOCOrdersMini[symbol], info.Id) + } } func orderNotFound(symbol, id string) error { @@ -339,7 +377,11 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times } return // no need to handle IOC } - iocIDs := kp.roundIOCOrders[symbol] + var iocIDs []string + iocIDs = kp.roundIOCOrders[symbol] + if sdk.IsUpgrade(upgrade.BEP69) && len(iocIDs) == 0 { + iocIDs = kp.roundIOCOrdersMini[symbol] + } for _, id := range iocIDs { if msg, ok := orders[id]; ok { delete(orders, id) @@ -402,7 +444,7 @@ func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { } // please note if distributeTrade this method will work in async mode, otherwise in sync mode. -func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64) []chan Transfer { +func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64, matchAllMiniSymbols bool) ([]chan Transfer) { size := len(kp.roundOrders) // size is the number of pairs that have new orders, i.e. it should call match() if size == 0 { @@ -412,11 +454,30 @@ func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timesta concurrency := 1 << kp.poolSize tradeOuts := make([]chan Transfer, concurrency) + + if sdk.IsUpgrade(upgrade.BEP69) { + if matchAllMiniSymbols { + for symbol := range kp.roundOrdersMini { + kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) + } + } else { + kp.selectMiniSymbolsToMatch(height, func(miniSymbols map[string]struct{}) { + for symbol := range miniSymbols { + kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) + } + }) + } + } if distributeTrade { ordNum := 0 for _, perSymbol := range kp.roundOrders { ordNum += len(perSymbol) } + if sdk.IsUpgrade(upgrade.BEP69) { + for _, symbol := range kp.matchedMiniSymbols { + ordNum += len(kp.roundOrdersMini[symbol]) + } + } for i := range tradeOuts { //assume every new order would have 2 trades and generate 4 transfer tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) @@ -428,6 +489,11 @@ func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timesta for symbol := range kp.roundOrders { symbolCh <- symbol } + if sdk.IsUpgrade(upgrade.BEP69) { + for _, symbol := range kp.matchedMiniSymbols { + symbolCh <- symbol + } + } close(symbolCh) } matchWorker := func() { @@ -578,6 +644,11 @@ func (kp *Keeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { func (kp *Keeper) clearAfterMatch() { kp.roundOrders = make(map[string][]string, 256) kp.roundIOCOrders = make(map[string][]string, 256) + for _, symbol := range kp.matchedMiniSymbols { + delete(kp.roundOrdersMini, symbol) + delete(kp.roundIOCOrdersMini, symbol) + } + kp.matchedMiniSymbols = make([]string, 0, 256) } func (kp *Keeper) StoreTradePrices(ctx sdk.Context) { @@ -789,7 +860,7 @@ func (kp *Keeper) allocateAndCalcFee( // MatchAll will only concurrently match but do not allocate into accounts func (kp *Keeper) MatchAll(height, timestamp int64) { - tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp) //only match + tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp, false) //only match if tradeOuts == nil { kp.logger.Info("No order comes in for the block") } @@ -799,13 +870,10 @@ func (kp *Keeper) MatchAll(height, timestamp int64) { // MatchAndAllocateAll() is concurrently matching and allocating across // all the symbols' order books, among all the clients // Return whether match has been done in this height -func (kp *Keeper) MatchAndAllocateAll( - ctx sdk.Context, - postAlloTransHandler TransferHandler, -) { +func (kp *Keeper) MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllMiniSymbols bool) { kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(kp.roundOrders)) timestamp := ctx.BlockHeader().Time.UnixNano() - tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp) + tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp, matchAllMiniSymbols) if tradeOuts == nil { kp.logger.Info("No order comes in for the block") } @@ -971,6 +1039,9 @@ func (kp *Keeper) ClearOrders() { kp.allOrders = make(map[string]map[string]*OrderInfo, 256) kp.roundOrders = make(map[string][]string, 256) kp.roundIOCOrders = make(map[string][]string, 256) + kp.roundOrdersMini = make(map[string][]string, 256) + kp.roundIOCOrdersMini = make(map[string][]string, 256) + kp.matchedMiniSymbols = make([]string, 0, 256) kp.OrderInfosForPub = make(OrderInfoForPublish) } @@ -1105,3 +1176,23 @@ func (kp *Keeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset st return nil } + +func (kp *Keeper) selectMiniSymbolsToMatch(height int64, postSelect func(map[string]struct{})) { + symbolsToMatch := make(map[string]struct{}, 256) + selectActiveMiniSymbols(&symbolsToMatch, &kp.roundOrdersMini, defaultActiveMiniSymbolCount) + selectMiniSymbolsRoundRobin(&symbolsToMatch, &kp.miniSymbolsHash, height) + postSelect(symbolsToMatch) +} + +func selectActiveMiniSymbols(symbolsToMatch *map[string]struct{}, roundOrdersMini *map[string][]string, topK int) { + //TODO use quick select to select top k symbols +} + +func selectMiniSymbolsRoundRobin(symbolsToMatch *map[string]struct{}, miniSymbolsHash *map[string]uint32, height int64) { + m := height % defaultMiniBlockMatchInterval + for symbol, symbolHash := range *miniSymbolsHash { + if int64(symbolHash%defaultMiniBlockMatchInterval) == m { + (*symbolsToMatch)[symbol] = struct{}{} + } + } +} diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index cd8ea2a29..bc605f03a 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -4,6 +4,7 @@ import ( "bytes" "compress/zlib" "fmt" + dexUtils "github.com/binance-chain/node/plugins/dex/utils" "io" "sort" "strings" @@ -170,9 +171,16 @@ func (kp *Keeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64 symbol := strings.ToUpper(m.Symbol) kp.allOrders[symbol][m.Id] = &orderHolder if m.CreatedHeight == height { - kp.roundOrders[symbol] = append(kp.roundOrders[symbol], m.Id) - if m.TimeInForce == TimeInForce.IOC { - kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], m.Id) + if dexUtils.IsMiniTokenTradingPair(symbol) { + kp.roundOrdersMini[symbol] = append(kp.roundOrdersMini[symbol], m.Id) + if m.TimeInForce == TimeInForce.IOC { + kp.roundIOCOrdersMini[symbol] = append(kp.roundIOCOrdersMini[symbol], m.Id) + } + } else { + kp.roundOrders[symbol] = append(kp.roundOrders[symbol], m.Id) + if m.TimeInForce == TimeInForce.IOC { + kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], m.Id) + } } } if kp.CollectOrderInfoForPublish { diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index a895fb669..ff4e0fe54 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -107,7 +107,7 @@ func TestKeeper_MatchFailure(t *testing.T) { msg = NewNewOrderMsg(accAdd, "123462", Side.BUY, "XYZ-000_BNB", 99000, 15000000) ord = OrderInfo{msg, 42, 0, 42, 0, 0, "", 0} keeper.AddOrder(ord, false) - tradeOuts := keeper.matchAndDistributeTrades(true, 42, 0) + tradeOuts := keeper.matchAndDistributeTrades(true, 42, 0, false) c := channelHash(accAdd, 4) i := 0 for tr := range tradeOuts[c] { diff --git a/plugins/dex/store/mapper.go b/plugins/dex/store/mapper.go index 2d799cc1e..35e3d3642 100644 --- a/plugins/dex/store/mapper.go +++ b/plugins/dex/store/mapper.go @@ -24,6 +24,8 @@ type TradingPairMapper interface { GetTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) (types.TradingPair, error) DeleteTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error ListAllTradingPairs(ctx sdk.Context) []types.TradingPair + ListAllBEP2TradingPairs(ctx sdk.Context) []types.TradingPair + ListAllMiniTradingPairs(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 } @@ -61,6 +63,25 @@ func (m mapper) AddTradingPair(ctx sdk.Context, pair types.TradingPair) error { return nil } +func (m mapper) AddMiniTokenTradingPair(ctx sdk.Context, pair types.TradingPair) error { + baseAsset := pair.BaseAssetSymbol + if err := cmn.ValidateMapperTokenSymbol(baseAsset); err != nil { + return err + } + quoteAsset := pair.QuoteAssetSymbol + if err := cmn.ValidateMapperTokenSymbol(quoteAsset); err != nil { + return err + } + + tradeSymbol := dexUtils.Assets2TradingPair(strings.ToUpper(baseAsset), strings.ToUpper(quoteAsset)) + key := []byte(tradeSymbol) + store := ctx.KVStore(m.key) + value := m.encodeTradingPair(pair) + store.Set(key, value) + ctx.Logger().Info("Added trading pair", "pair", tradeSymbol) + return nil +} + func (m mapper) DeleteTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { symbol := dexUtils.Assets2TradingPair(strings.ToUpper(baseAsset), strings.ToUpper(quoteAsset)) key := []byte(symbol) @@ -112,6 +133,16 @@ func (m mapper) ListAllTradingPairs(ctx sdk.Context) (res []types.TradingPair) { return res } +func (m mapper) ListAllBEP2TradingPairs(ctx sdk.Context) []types.TradingPair { + //todo "implement me" + return nil +} + +func (m mapper) ListAllMiniTradingPairs(ctx sdk.Context) []types.TradingPair { + //todo "implement me" + return nil +} + func (m mapper) getRecentPricesSeq(height, pricesStoreEvery, numPricesStored int64) int64 { return (height/pricesStoreEvery - 1) % numPricesStored } diff --git a/plugins/dex/utils/pair.go b/plugins/dex/utils/pair.go index ec106ce48..f5dd5050c 100644 --- a/plugins/dex/utils/pair.go +++ b/plugins/dex/utils/pair.go @@ -2,6 +2,7 @@ package utils import ( "fmt" + "github.com/binance-chain/node/common/types" "math" "math/big" "strings" @@ -83,3 +84,11 @@ func TradingPair2AssetsSafe(symbol string) (baseAsset, quoteAsset string) { func Assets2TradingPair(baseAsset, quoteAsset string) (symbol string) { return fmt.Sprintf("%s_%s", baseAsset, quoteAsset) } + +func IsMiniTokenTradingPair(symbol string) bool { + baseAsset, _, err := TradingPair2Assets(symbol) + if err != nil{ + return false + } + return types.IsMiniTokenSymbol(baseAsset) +} diff --git a/plugins/miniTokens/abci.go b/plugins/miniTokens/abci.go index b98f77577..168f25dfb 100644 --- a/plugins/miniTokens/abci.go +++ b/plugins/miniTokens/abci.go @@ -1,4 +1,4 @@ -package miniTokens +package minitokens import ( "fmt" @@ -19,7 +19,7 @@ func createAbciQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { return nil } switch path[1] { - case "info": // args: ["miniTokens", "info", ] + case "info": // args: ["minitokens", "info", ] if len(path) < 3 { return &abci.ResponseQuery{ Code: uint32(sdk.CodeUnknownRequest), diff --git a/plugins/miniTokens/burn/handler.go b/plugins/miniTokens/burn/handler.go index 980a9195a..444279583 100644 --- a/plugins/miniTokens/burn/handler.go +++ b/plugins/miniTokens/burn/handler.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/plugins/miniTokens/store" + "github.com/binance-chain/node/plugins/minitokens/store" ) func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { diff --git a/plugins/miniTokens/client/cli/burn.go b/plugins/miniTokens/client/cli/burn.go index 85969622b..c8268a398 100644 --- a/plugins/miniTokens/client/cli/burn.go +++ b/plugins/miniTokens/client/cli/burn.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/binance-chain/node/plugins/miniTokens/burn" + "github.com/binance-chain/node/plugins/minitokens/burn" ) func burnTokenCmd(cmdr Commander) *cobra.Command { diff --git a/plugins/miniTokens/client/cli/freeze.go b/plugins/miniTokens/client/cli/freeze.go index dcf66d18e..c94264a75 100644 --- a/plugins/miniTokens/client/cli/freeze.go +++ b/plugins/miniTokens/client/cli/freeze.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/binance-chain/node/plugins/miniTokens/freeze" + "github.com/binance-chain/node/plugins/minitokens/freeze" ) func freezeMiniTokenCmd(cmdr Commander) *cobra.Command { diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/miniTokens/client/cli/issue.go index 2f78bb3fe..b69c4771a 100644 --- a/plugins/miniTokens/client/cli/issue.go +++ b/plugins/miniTokens/client/cli/issue.go @@ -7,7 +7,7 @@ import ( "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/miniTokens/issue" + "github.com/binance-chain/node/plugins/minitokens/issue" ) const ( diff --git a/plugins/miniTokens/client/cli/uri.go b/plugins/miniTokens/client/cli/uri.go index d4864fa1d..946e9188e 100644 --- a/plugins/miniTokens/client/cli/uri.go +++ b/plugins/miniTokens/client/cli/uri.go @@ -3,7 +3,7 @@ package commands import ( "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/miniTokens/uri" + "github.com/binance-chain/node/plugins/minitokens/uri" "github.com/spf13/cobra" "github.com/spf13/viper" ) diff --git a/plugins/miniTokens/freeze/handler.go b/plugins/miniTokens/freeze/handler.go index 10c0744e7..fff2b79ec 100644 --- a/plugins/miniTokens/freeze/handler.go +++ b/plugins/miniTokens/freeze/handler.go @@ -11,7 +11,7 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/miniTokens/store" + "github.com/binance-chain/node/plugins/minitokens/store" ) // NewHandler creates a new token freeze message handler diff --git a/plugins/miniTokens/issue/handler.go b/plugins/miniTokens/issue/handler.go index f96a1fe4e..56290e22d 100644 --- a/plugins/miniTokens/issue/handler.go +++ b/plugins/miniTokens/issue/handler.go @@ -14,7 +14,7 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/miniTokens/store" + "github.com/binance-chain/node/plugins/minitokens/store" ) // NewHandler creates a new token issue message handler diff --git a/plugins/miniTokens/issue/handler_test.go b/plugins/miniTokens/issue/handler_test.go index 2a935f758..e95e2511b 100644 --- a/plugins/miniTokens/issue/handler_test.go +++ b/plugins/miniTokens/issue/handler_test.go @@ -15,7 +15,7 @@ import ( "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/miniTokens/store" + "github.com/binance-chain/node/plugins/minitokens/store" "github.com/binance-chain/node/wire" ) diff --git a/plugins/miniTokens/mini_tokens.go b/plugins/miniTokens/mini_tokens.go index 7fdb25e5f..a1cf6679f 100644 --- a/plugins/miniTokens/mini_tokens.go +++ b/plugins/miniTokens/mini_tokens.go @@ -1,5 +1,5 @@ -package miniTokens +package minitokens -import "github.com/binance-chain/node/plugins/miniTokens/store" +import "github.com/binance-chain/node/plugins/minitokens/store" type MiniTokenMapper = store.MiniTokenMapper diff --git a/plugins/miniTokens/plugin.go b/plugins/miniTokens/plugin.go index 04907833d..bb1920a5b 100644 --- a/plugins/miniTokens/plugin.go +++ b/plugins/miniTokens/plugin.go @@ -1,4 +1,4 @@ -package miniTokens +package minitokens import ( "github.com/cosmos/cosmos-sdk/x/auth" @@ -7,7 +7,7 @@ import ( app "github.com/binance-chain/node/common/types" ) -const abciQueryPrefix = "miniTokens" +const abciQueryPrefix = "minitokens" // InitPlugin initializes the plugin. func InitPlugin( diff --git a/plugins/miniTokens/route.go b/plugins/miniTokens/route.go index 71cb6f8d0..603724de7 100644 --- a/plugins/miniTokens/route.go +++ b/plugins/miniTokens/route.go @@ -1,11 +1,11 @@ -package miniTokens +package minitokens import ( - "github.com/binance-chain/node/plugins/miniTokens/burn" - "github.com/binance-chain/node/plugins/miniTokens/freeze" - "github.com/binance-chain/node/plugins/miniTokens/issue" - "github.com/binance-chain/node/plugins/miniTokens/store" - "github.com/binance-chain/node/plugins/miniTokens/uri" + "github.com/binance-chain/node/plugins/minitokens/burn" + "github.com/binance-chain/node/plugins/minitokens/freeze" + "github.com/binance-chain/node/plugins/minitokens/issue" + "github.com/binance-chain/node/plugins/minitokens/store" + "github.com/binance-chain/node/plugins/minitokens/uri" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" diff --git a/plugins/miniTokens/uri/handler.go b/plugins/miniTokens/uri/handler.go index bc514f2f2..3bd43cf82 100644 --- a/plugins/miniTokens/uri/handler.go +++ b/plugins/miniTokens/uri/handler.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/miniTokens/store" + "github.com/binance-chain/node/plugins/minitokens/store" sdk "github.com/cosmos/cosmos-sdk/types" "reflect" "strings" diff --git a/plugins/miniTokens/wire.go b/plugins/miniTokens/wire.go index 4cc8a4a36..8f92808fb 100644 --- a/plugins/miniTokens/wire.go +++ b/plugins/miniTokens/wire.go @@ -1,19 +1,19 @@ -package miniTokens +package minitokens import ( - "github.com/binance-chain/node/plugins/miniTokens/burn" - "github.com/binance-chain/node/plugins/miniTokens/freeze" - "github.com/binance-chain/node/plugins/miniTokens/issue" - "github.com/binance-chain/node/plugins/miniTokens/uri" + "github.com/binance-chain/node/plugins/minitokens/burn" + "github.com/binance-chain/node/plugins/minitokens/freeze" + "github.com/binance-chain/node/plugins/minitokens/issue" + "github.com/binance-chain/node/plugins/minitokens/uri" "github.com/binance-chain/node/wire" ) // Register concrete types on wire codec func RegisterWire(cdc *wire.Codec) { - cdc.RegisterConcrete(issue.IssueMsg{}, "miniTokens/IssueMsg", nil) - cdc.RegisterConcrete(issue.MintMsg{}, "miniTokens/MintMsg", nil) - cdc.RegisterConcrete(freeze.FreezeMsg{}, "miniTokens/FreezeMsg", nil) - cdc.RegisterConcrete(freeze.UnfreezeMsg{}, "miniTokens/UnFreezeMsg", nil) - cdc.RegisterConcrete(burn.BurnMsg{}, "miniTokens/BurnMsg", nil) - cdc.RegisterConcrete(uri.SetURIMsg{}, "miniTokens/SetURIMsg", nil) + cdc.RegisterConcrete(issue.IssueMsg{}, "minitokens/IssueMsg", nil) + cdc.RegisterConcrete(issue.MintMsg{}, "minitokens/MintMsg", nil) + cdc.RegisterConcrete(freeze.FreezeMsg{}, "minitokens/FreezeMsg", nil) + cdc.RegisterConcrete(freeze.UnfreezeMsg{}, "minitokens/UnFreezeMsg", nil) + cdc.RegisterConcrete(burn.BurnMsg{}, "minitokens/BurnMsg", nil) + cdc.RegisterConcrete(uri.SetURIMsg{}, "minitokens/SetURIMsg", nil) } diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 30d40634f..c9aab7741 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -13,10 +13,10 @@ import ( "github.com/binance-chain/node/plugins/account" "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" - miniBurn "github.com/binance-chain/node/plugins/miniTokens/burn" - miniFreeze "github.com/binance-chain/node/plugins/miniTokens/freeze" - miniIssue "github.com/binance-chain/node/plugins/miniTokens/issue" - miniURI "github.com/binance-chain/node/plugins/miniTokens/uri" + miniBurn "github.com/binance-chain/node/plugins/minitokens/burn" + miniFreeze "github.com/binance-chain/node/plugins/minitokens/freeze" + miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" + miniURI "github.com/binance-chain/node/plugins/minitokens/uri" "github.com/binance-chain/node/plugins/param/paramhub" param "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/plugins/tokens" From 8ea6289a3cfe2a79e77a0a7bde4f4df299ed0d3b Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 2 Apr 2020 00:48:36 +0800 Subject: [PATCH 06/96] select top K active symbols for match by quick select --- plugins/dex/order/keeper.go | 14 ++++++++++++-- plugins/dex/order/types.go | 5 +++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 68d41b927..3f22060fa 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -1184,8 +1184,18 @@ func (kp *Keeper) selectMiniSymbolsToMatch(height int64, postSelect func(map[str postSelect(symbolsToMatch) } -func selectActiveMiniSymbols(symbolsToMatch *map[string]struct{}, roundOrdersMini *map[string][]string, topK int) { - //TODO use quick select to select top k symbols +func selectActiveMiniSymbols(symbolsToMatch *map[string]struct{}, roundOrdersMini *map[string][]string, k int) { + //use quick select to select top k symbols + symbolOrderNumsSlice := make([]*SymbolWithOrderNumber, 0, len(*roundOrdersMini)) + i:=0 + for symbol, orders := range *roundOrdersMini { + symbolOrderNumsSlice[i] = &SymbolWithOrderNumber{symbol,len(orders)} + } + topKSymbolOrderNums := findTopKLargest(symbolOrderNumsSlice, k) + + for _, selected := range topKSymbolOrderNums{ + (*symbolsToMatch)[selected.symbol] = struct{}{} + } } func selectMiniSymbolsRoundRobin(symbolsToMatch *map[string]struct{}, miniSymbolsHash *map[string]uint32, height int64) { diff --git a/plugins/dex/order/types.go b/plugins/dex/order/types.go index a2317a633..56f70adb7 100644 --- a/plugins/dex/order/types.go +++ b/plugins/dex/order/types.go @@ -123,4 +123,9 @@ type ExpireHolder struct { Fee string } +type SymbolWithOrderNumber struct { + symbol string + numberOfOrders int +} + type FeeHolder map[string]*types.Fee From 2754f394e816ecda9799054b14318e97f08170e6 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 2 Apr 2020 10:23:37 +0800 Subject: [PATCH 07/96] decide maker by last match height intead of height --- plugins/dex/matcheng/engine_new.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/dex/matcheng/engine_new.go b/plugins/dex/matcheng/engine_new.go index 8070382b7..d481dc7af 100644 --- a/plugins/dex/matcheng/engine_new.go +++ b/plugins/dex/matcheng/engine_new.go @@ -32,7 +32,9 @@ func (me *MatchEng) Match(height int64) bool { me.logger.Error("dropRedundantQty failed", "error", err) return false } - takerSide, err := me.determineTakerSide(height, index) + //If order height >= the last Match height, then it's maker. + // Block Height cannot be used here since mini-token is not matched in every block + takerSide, err := me.determineTakerSide(me.LastMatchHeight, index) if err != nil { me.logger.Error("determineTakerSide failed", "error", err) return false @@ -115,10 +117,10 @@ func dropRedundantQty(orders []OrderPart, toDropQty, lotSize int64) error { return nil } -func findTakerStartIdx(height int64, orders []OrderPart) (idx int, makerTotal int64) { +func findTakerStartIdx(lastMatchHeight int64, orders []OrderPart) (idx int, makerTotal int64) { i, k := 0, len(orders) for ; i < k; i++ { - if orders[i].Time >= height { + if orders[i].Time >= lastMatchHeight { return i, makerTotal } else { makerTotal += orders[i].nxtTrade @@ -127,11 +129,11 @@ func findTakerStartIdx(height int64, orders []OrderPart) (idx int, makerTotal in return i, makerTotal } -func (me *MatchEng) determineTakerSide(height int64, tradePriceIdx int) (int8, error) { +func (me *MatchEng) determineTakerSide(lastMatchHeight int64, tradePriceIdx int) (int8, error) { makerSide := UNKNOWN for i := 0; i <= tradePriceIdx; i++ { l := &me.overLappedLevel[i] - l.BuyTakerStartIdx, l.BuyMakerTotal = findTakerStartIdx(height, l.BuyOrders) + l.BuyTakerStartIdx, l.BuyMakerTotal = findTakerStartIdx(lastMatchHeight, l.BuyOrders) if l.HasBuyMaker() { makerSide = BUYSIDE } @@ -139,7 +141,7 @@ func (me *MatchEng) determineTakerSide(height int64, tradePriceIdx int) (int8, e for i := len(me.overLappedLevel) - 1; i >= tradePriceIdx; i-- { l := &me.overLappedLevel[i] - l.SellTakerStartIdx, l.SellMakerTotal = findTakerStartIdx(height, l.SellOrders) + l.SellTakerStartIdx, l.SellMakerTotal = findTakerStartIdx(lastMatchHeight, l.SellOrders) if l.HasSellMaker() { if makerSide == BUYSIDE { return UNKNOWN, errors.New("both buy side and sell side have maker orders.") From b5b83eb59eeabf971722d4fc42e6e04e8760e92d Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 3 Apr 2020 22:52:48 +0800 Subject: [PATCH 08/96] reuse some BEP2 txs for mini token --- app/app.go | 6 +- app/config/config.go | 8 +- common/testutils/testutils.go | 13 ++- common/upgrade/upgrade.go | 2 +- plugins/dex/client/cli/commands.go | 1 + plugins/dex/client/cli/list.go | 51 ++++++++++ plugins/dex/listmini/handler.go | 14 +-- plugins/dex/listmini/msg.go | 8 +- plugins/dex/order/handler.go | 24 ++++- plugins/dex/order/keeper.go | 12 +-- plugins/dex/plugin.go | 5 +- plugins/dex/route.go | 5 +- plugins/dex/wire.go | 3 + plugins/miniTokens/abci.go | 2 +- plugins/miniTokens/burn/handler.go | 84 ---------------- plugins/miniTokens/burn/msg.go | 61 ------------ plugins/miniTokens/client/cli/burn.go | 35 ------- plugins/miniTokens/client/cli/commands.go | 4 - plugins/miniTokens/client/cli/freeze.go | 63 ------------ plugins/miniTokens/client/cli/issue.go | 38 +------- plugins/miniTokens/client/cli/uri.go | 44 --------- plugins/miniTokens/freeze/handler.go | 113 ---------------------- plugins/miniTokens/freeze/msg.go | 100 ------------------- plugins/miniTokens/issue/handler.go | 82 +--------------- plugins/miniTokens/issue/handler_test.go | 61 +++--------- plugins/miniTokens/issue/msg.go | 66 +------------ plugins/miniTokens/route.go | 9 +- plugins/miniTokens/uri/handler.go | 59 ----------- plugins/miniTokens/uri/msg.go | 54 ----------- plugins/miniTokens/wire.go | 10 +- plugins/param/genesis.go | 4 +- plugins/param/plugin.go | 14 +-- plugins/param/types/types.go | 4 +- plugins/tokens/burn/handler.go | 65 ++++++++++++- plugins/tokens/burn/msg.go | 15 +++ plugins/tokens/client/cli/issue.go | 31 ++++-- plugins/tokens/freeze/handler.go | 89 ++++++++++++++++- plugins/tokens/freeze/msg.go | 31 ++++++ plugins/tokens/issue/handler.go | 74 +++++++++++++- plugins/tokens/issue/handler_test.go | 80 +++++++++++++-- plugins/tokens/issue/msg.go | 23 +++++ plugins/tokens/plugin.go | 5 +- plugins/tokens/route.go | 9 +- 43 files changed, 540 insertions(+), 941 deletions(-) delete mode 100644 plugins/miniTokens/burn/handler.go delete mode 100644 plugins/miniTokens/burn/msg.go delete mode 100644 plugins/miniTokens/client/cli/burn.go delete mode 100644 plugins/miniTokens/client/cli/freeze.go delete mode 100644 plugins/miniTokens/client/cli/uri.go delete mode 100644 plugins/miniTokens/freeze/handler.go delete mode 100644 plugins/miniTokens/freeze/msg.go delete mode 100644 plugins/miniTokens/uri/handler.go delete mode 100644 plugins/miniTokens/uri/msg.go diff --git a/app/app.go b/app/app.go index 38db31575..cba3e05bc 100644 --- a/app/app.go +++ b/app/app.go @@ -258,7 +258,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp // setUpgradeConfig will overwrite default upgrade config func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // register upgrade height - upgrade.Mgr.AddUpgradeHeight(upgrade.BEP69, upgradeConfig.BEP69Height) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, upgradeConfig.BEP8Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP6, upgradeConfig.BEP6Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP9, upgradeConfig.BEP9Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP10, upgradeConfig.BEP10Height) @@ -334,9 +334,9 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { } func (app *BinanceChain) initPlugins() { - tokens.InitPlugin(app, app.TokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) + tokens.InitPlugin(app, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) minitokens.InitPlugin(app, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper) - dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.AccountKeeper, app.govKeeper) + dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.govKeeper) param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) } diff --git a/app/config/config.go b/app/config/config.go index d25c20100..cb2f8bea5 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -47,8 +47,8 @@ orderKeeperConcurrency = {{ .BaseConfig.OrderKeeperConcurrency }} breatheBlockDaysCountBack = {{ .BaseConfig.BreatheBlockDaysCountBack }} [upgrade] -# Block height of BEP69 upgrade -BEP69Height = {{ .UpgradeConfig.BEP69Height }} +# Block height of BEP8 upgrade +BEP8Height = {{ .UpgradeConfig.BEP8Height }} # Block height of BEP6 upgrade BEP6Height = {{ .UpgradeConfig.BEP6Height }} # Block height of BEP9 upgrade @@ -353,7 +353,7 @@ func defaultBaseConfig() *BaseConfig { type UpgradeConfig struct { - BEP69Height int64 `mapstructure:"BEP69Height"` + BEP8Height int64 `mapstructure:"BEP8Height"` // Galileo Upgrade BEP6Height int64 `mapstructure:"BEP6Height"` BEP9Height int64 `mapstructure:"BEP9Height"` @@ -373,7 +373,7 @@ type UpgradeConfig struct { func defaultUpgradeConfig() *UpgradeConfig { // make the upgraded functions enabled by default return &UpgradeConfig{ - BEP69Height: 1, + BEP8Height: 1, BEP6Height: 1, BEP9Height: 1, BEP10Height: 1, diff --git a/common/testutils/testutils.go b/common/testutils/testutils.go index 75587ecc5..09b9eaf2f 100644 --- a/common/testutils/testutils.go +++ b/common/testutils/testutils.go @@ -13,20 +13,27 @@ import ( ) func SetupMultiStoreForUnitTest() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) { - _, ms, capKey, capKey2 := SetupMultiStoreWithDBForUnitTest() + _, ms, capKey, capKey2, _ := SetupMultiStoreWithDBForUnitTest() return ms, capKey, capKey2 } -func SetupMultiStoreWithDBForUnitTest() (dbm.DB, sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) { +func SetupThreeMultiStoreForUnitTest() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey, *sdk.KVStoreKey) { + _, ms, capKey, capKey2, capKey3 := SetupMultiStoreWithDBForUnitTest() + return ms, capKey, capKey2, capKey3 +} + +func SetupMultiStoreWithDBForUnitTest() (dbm.DB, sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey, *sdk.KVStoreKey) { db := dbm.NewMemDB() capKey := sdk.NewKVStoreKey("capkey") capKey2 := sdk.NewKVStoreKey("capkey2") + capKey3 := sdk.NewKVStoreKey("capkey3") ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(capKey2, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(capKey3, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(common.PairStoreKey, sdk.StoreTypeIAVL, db) ms.LoadLatestVersion() - return db, ms, capKey, capKey2 + return db, ms, capKey, capKey2, capKey3 } // coins to more than cover the fee diff --git a/common/upgrade/upgrade.go b/common/upgrade/upgrade.go index e8ce39018..ed4a95168 100644 --- a/common/upgrade/upgrade.go +++ b/common/upgrade/upgrade.go @@ -8,7 +8,7 @@ var Mgr = sdk.UpgradeMgr // bugfix: fix // improvement: (maybe bep ?) const ( - BEP69 = "BEP69" //FIXME placeholder + BEP8 = "BEP8" //FIXME placeholder // Galileo Upgrade BEP6 = "BEP6" // https://github.com/binance-chain/BEPs/pull/6 BEP9 = "BEP9" // https://github.com/binance-chain/BEPs/pull/9 diff --git a/plugins/dex/client/cli/commands.go b/plugins/dex/client/cli/commands.go index 30c3b1f3c..3ff94a2bf 100644 --- a/plugins/dex/client/cli/commands.go +++ b/plugins/dex/client/cli/commands.go @@ -22,6 +22,7 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { dexCmd.AddCommand( client.PostCommands( listTradingPairCmd(cdc), + listMiniTradingPairCmd(cdc), client.LineBreak, newOrderCmd(cdc), cancelOrderCmd(cdc))...) diff --git a/plugins/dex/client/cli/list.go b/plugins/dex/client/cli/list.go index 864ebd668..4aa9c5413 100644 --- a/plugins/dex/client/cli/list.go +++ b/plugins/dex/client/cli/list.go @@ -11,6 +11,7 @@ import ( "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/utils" "github.com/binance-chain/node/plugins/dex/list" + "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/wire" ) @@ -74,3 +75,53 @@ func listTradingPairCmd(cdc *wire.Codec) *cobra.Command { return cmd } + +func listMiniTradingPairCmd(cdc *wire.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "list-mini", + Short: "", + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx, txbldr := client.PrepareCtx(cdc) + + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + baseAsset := viper.GetString(flagBaseAsset) + err = types.ValidateMapperMiniTokenSymbol(baseAsset) + if err != nil { + return err + } + + quoteAsset := viper.GetString(flagQuoteAsset) + if quoteAsset != types.NativeTokenSymbol { + // TODO BUSD + return errors.New("invalid quote asset") + } + + baseAsset = strings.ToUpper(baseAsset) + quoteAsset = strings.ToUpper(quoteAsset) + + initPriceStr := viper.GetString(flagInitPrice) + initPrice, err := utils.ParsePrice(initPriceStr) + if err != nil { + return err + } + + msg := listmini.NewMsg(from, baseAsset, quoteAsset, initPrice) + err = client.SendOrPrintTx(cliCtx, txbldr, msg) + if err != nil { + return err + } + + return nil + }, + } + + cmd.Flags().StringP(flagBaseAsset, "s", "", "symbol of the base asset") + cmd.Flags().String(flagQuoteAsset, "", "symbol of the quote currency") + cmd.Flags().String(flagInitPrice, "", "init price for this pair") + + return cmd +} diff --git a/plugins/dex/listmini/handler.go b/plugins/dex/listmini/handler.go index 538e083f7..47c6f3390 100644 --- a/plugins/dex/listmini/handler.go +++ b/plugins/dex/listmini/handler.go @@ -1,4 +1,4 @@ -package list +package listmini import ( "fmt" @@ -13,15 +13,14 @@ import ( "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/gov" ) // NewHandler initialises dex message handlers -func NewHandler(keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper,tokenMapper tokens.Mapper, govKeeper gov.Keeper) sdk.Handler { +func NewHandler(keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case ListMiniMsg: - return handleList(ctx, keeper, miniTokenMapper, tokenMapper, govKeeper, msg) + return handleList(ctx, keeper, miniTokenMapper, tokenMapper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -29,13 +28,14 @@ func NewHandler(keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper } } -func handleList(ctx sdk.Context, keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper,govKeeper gov.Keeper, +func handleList(ctx sdk.Context, keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper, msg ListMiniMsg) sdk.Result { - if !sdk.IsUpgrade(upgrade.BEP69) { + if !sdk.IsUpgrade(upgrade.BEP8) { return sdk.ErrInternal(fmt.Sprint("list miniToken is not supported at current height")).Result() } if err := keeper.CanListTradingPair(ctx, msg.BaseAssetSymbol, msg.QuoteAssetSymbol); err != nil { + //TODO use miniTradingPair return sdk.ErrInvalidCoins(err.Error()).Result() } @@ -57,7 +57,7 @@ func handleList(ctx sdk.Context, keeper *order.Keeper, miniTokenMapper minitoken return sdk.ErrInvalidCoins("quote token does not exist").Result() } - if common.NativeTokenSymbol != msg.QuoteAssetSymbol {//todo permit BUSD + if common.NativeTokenSymbol != msg.QuoteAssetSymbol { //todo permit BUSD return sdk.ErrInvalidCoins("quote token: " + err.Error()).Result() } diff --git a/plugins/dex/listmini/msg.go b/plugins/dex/listmini/msg.go index be1af7fd4..3fc4ab793 100644 --- a/plugins/dex/listmini/msg.go +++ b/plugins/dex/listmini/msg.go @@ -1,4 +1,4 @@ -package list +package listmini import ( "encoding/json" @@ -9,7 +9,7 @@ import ( "github.com/binance-chain/node/common/types" ) -const ListMiniRoute = "dexListMini" +const Route = "dexListMini" var _ sdk.Msg = ListMiniMsg{} @@ -29,8 +29,8 @@ func NewMsg(from sdk.AccAddress, baseAssetSymbol string, quoteAssetSymbol string } } -func (msg ListMiniMsg) Route() string { return ListMiniRoute } -func (msg ListMiniMsg) Type() string { return ListMiniRoute } +func (msg ListMiniMsg) Route() string { return Route } +func (msg ListMiniMsg) Type() string { return Route } func (msg ListMiniMsg) String() string { return fmt.Sprintf("MsgListMini{%#v}", msg) } func (msg ListMiniMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index fc9c09706..25f76f2a8 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -78,6 +78,20 @@ func validateOrder(ctx sdk.Context, pairMapper store.TradingPairMapper, acc sdk. return nil } +func validatorMiniTokenOrder(ctx sdk.Context, pairMapper store.TradingPairMapper, acc sdk.Account, msg NewOrderMsg) error{ + + //coins := acc.GetCoins() + // + //useAllBalance := coins.AmountOf(symbol) == burnAmount + // + //if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { + // logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") + // return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", + // common.MiniTokenMinTotalSupply)).Result() + //} + return nil +} + func validateQtyAndLockBalance(ctx sdk.Context, keeper *Keeper, acc common.NamedAccount, msg NewOrderMsg) error { symbol := strings.ToUpper(msg.Symbol) baseAssetSymbol, quoteAssetSymbol := utils.TradingPair2AssetsSafe(symbol) @@ -143,7 +157,15 @@ func handleNewOrder( // 3. trading pair is verified // 4. price/qty may have odd tick size/lot size, but it can be handled as // other existing orders. - err := validateOrder(ctx, keeper.PairMapper, acc, msg) + var err error + if utils.IsMiniTokenTradingPair(msg.Symbol) { + //FIXMe .. use different keeper + + err = validatorMiniTokenOrder(ctx, keeper.PairMapper, acc, msg) + + } else{ + err = validateOrder(ctx, keeper.PairMapper, acc, msg) + } if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeInvalidOrderParam, err.Error()).Result() } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 3f22060fa..181c1f77d 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -112,7 +112,7 @@ func (kp *Keeper) InitRecentPrices(ctx sdk.Context) { func (kp *Keeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { symbol := strings.ToUpper(pair.GetSymbol()) - if sdk.IsUpgrade(upgrade.BEP69) { + if sdk.IsUpgrade(upgrade.BEP8) { baseSymbol := strings.ToUpper(pair.BaseAssetSymbol) if types.IsMiniTokenSymbol(baseSymbol) { kp.miniSymbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) @@ -226,7 +226,7 @@ func (kp *Keeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { kp.allOrders[symbol][info.Id] = &info - if (!sdk.IsUpgrade(upgrade.BEP69)) || !dexUtils.IsMiniTokenTradingPair(symbol) { + if (!sdk.IsUpgrade(upgrade.BEP8)) || !dexUtils.IsMiniTokenTradingPair(symbol) { kp.addBEP2RoundOrders(symbol, info) } else { kp.addMiniRoundOrders(symbol, info) @@ -379,7 +379,7 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times } var iocIDs []string iocIDs = kp.roundIOCOrders[symbol] - if sdk.IsUpgrade(upgrade.BEP69) && len(iocIDs) == 0 { + if sdk.IsUpgrade(upgrade.BEP8) && len(iocIDs) == 0 { iocIDs = kp.roundIOCOrdersMini[symbol] } for _, id := range iocIDs { @@ -455,7 +455,7 @@ func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timesta concurrency := 1 << kp.poolSize tradeOuts := make([]chan Transfer, concurrency) - if sdk.IsUpgrade(upgrade.BEP69) { + if sdk.IsUpgrade(upgrade.BEP8) { if matchAllMiniSymbols { for symbol := range kp.roundOrdersMini { kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) @@ -473,7 +473,7 @@ func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timesta for _, perSymbol := range kp.roundOrders { ordNum += len(perSymbol) } - if sdk.IsUpgrade(upgrade.BEP69) { + if sdk.IsUpgrade(upgrade.BEP8) { for _, symbol := range kp.matchedMiniSymbols { ordNum += len(kp.roundOrdersMini[symbol]) } @@ -489,7 +489,7 @@ func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timesta for symbol := range kp.roundOrders { symbolCh <- symbol } - if sdk.IsUpgrade(upgrade.BEP69) { + if sdk.IsUpgrade(upgrade.BEP8) { for _, symbol := range kp.matchedMiniSymbols { symbolCh <- symbol } diff --git a/plugins/dex/plugin.go b/plugins/dex/plugin.go index 33e8c1238..e61f07e19 100644 --- a/plugins/dex/plugin.go +++ b/plugins/dex/plugin.go @@ -13,6 +13,7 @@ import ( bnclog "github.com/binance-chain/node/common/log" app "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/dex/utils" + miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" tkstore "github.com/binance-chain/node/plugins/tokens/store" ) @@ -21,12 +22,12 @@ const DelayedDaysForDelist = 3 // InitPlugin initializes the dex plugin. func InitPlugin( - appp app.ChainApp, keeper *DexKeeper, tokenMapper tkstore.Mapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, + appp app.ChainApp, keeper *DexKeeper, tokenMapper tkstore.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, ) { cdc := appp.GetCodec() // add msg handlers - for route, handler := range Routes(cdc, keeper, tokenMapper, accMapper, govKeeper) { + for route, handler := range Routes(cdc, keeper, tokenMapper, miniTokenMapper, accMapper, govKeeper) { appp.GetRouter().AddRoute(route, handler) } diff --git a/plugins/dex/route.go b/plugins/dex/route.go index 6153bb452..319856b59 100644 --- a/plugins/dex/route.go +++ b/plugins/dex/route.go @@ -1,23 +1,26 @@ package dex import ( + "github.com/binance-chain/node/plugins/dex/listmini" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" + miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/wire" ) // Routes exports dex message routes -func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, +func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accKeeper auth.AccountKeeper, govKeeper gov.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) orderHandler := order.NewHandler(cdc, dexKeeper, accKeeper) routes[order.RouteNewOrder] = orderHandler routes[order.RouteCancelOrder] = orderHandler routes[list.Route] = list.NewHandler(dexKeeper, tokenMapper, govKeeper) + routes[listmini.Route] = listmini.NewHandler(dexKeeper, miniTokenMapper, tokenMapper) return routes } diff --git a/plugins/dex/wire.go b/plugins/dex/wire.go index cf5c3f784..1c0169603 100644 --- a/plugins/dex/wire.go +++ b/plugins/dex/wire.go @@ -2,6 +2,7 @@ package dex import ( "github.com/binance-chain/node/plugins/dex/list" + "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/store" "github.com/binance-chain/node/plugins/dex/types" @@ -18,6 +19,8 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(list.ListMsg{}, "dex/ListMsg", nil) cdc.RegisterConcrete(types.TradingPair{}, "dex/TradingPair", nil) + cdc.RegisterConcrete(listmini.ListMiniMsg{}, "dex/ListMiniMsg", nil) + cdc.RegisterConcrete(order.FeeConfig{}, "dex/FeeConfig", nil) cdc.RegisterConcrete(order.OrderBookSnapshot{}, "dex/OrderBookSnapshot", nil) cdc.RegisterConcrete(order.ActiveOrders{}, "dex/ActiveOrders", nil) diff --git a/plugins/miniTokens/abci.go b/plugins/miniTokens/abci.go index 168f25dfb..3c8e25d4c 100644 --- a/plugins/miniTokens/abci.go +++ b/plugins/miniTokens/abci.go @@ -54,7 +54,7 @@ func createAbciQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { Code: uint32(sdk.ABCICodeOK), Value: bz, } - case "list": // args: ["tokens", "list", , , ] + case "list": // args: ["minitokens", "list", , , ] if len(path) < 4 { return &abci.ResponseQuery{ Code: uint32(sdk.CodeUnknownRequest), diff --git a/plugins/miniTokens/burn/handler.go b/plugins/miniTokens/burn/handler.go deleted file mode 100644 index 444279583..000000000 --- a/plugins/miniTokens/burn/handler.go +++ /dev/null @@ -1,84 +0,0 @@ -package burn - -import ( - "fmt" - "reflect" - "strings" - - common "github.com/binance-chain/node/common/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" - - "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/plugins/minitokens/store" -) - -func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - if msg, ok := msg.(BurnMsg); ok { - return handleBurnToken(ctx, tokenMapper, keeper, msg) - } - - errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() - } -} - -func handleBurnToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, keeper bank.Keeper, msg BurnMsg) sdk.Result { - logger := log.With("module", "miniToken", "symbol", msg.Symbol, "amount", msg.Amount) - burnAmount := msg.Amount - symbol := strings.ToUpper(msg.Symbol) - token, err := tokenMapper.GetToken(ctx, symbol) - errLogMsg := "burn token failed" - if err != nil { - logger.Info("burn token failed", "reason", "invalid token symbol") - return sdk.ErrInvalidCoins(err.Error()).Result() - } - - if !token.IsOwner(msg.From) { - logger.Info("burn token failed", "reason", "not token's owner", "from", msg.From, "owner", token.Owner) - return sdk.ErrUnauthorized("only the owner of the token can burn the token").Result() - } - - coins := keeper.GetCoins(ctx, token.Owner) - - useAllBalance := coins.AmountOf(symbol) == burnAmount - - if !useAllBalance && (burnAmount % common.MiniTokenMinTotalSupply !=0) { - logger.Info(errLogMsg, "reason", "unfreeze amount is not integer") - return sdk.ErrInvalidCoins( - fmt.Sprintf("amount should be a multiple of %v or equals total frozen balance", common.MiniTokenMinTotalSupply)).Result() - } - - if burnAmount<=0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { - logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", - common.MiniTokenMinTotalSupply)).Result() - } - - - if coins.AmountOf(symbol) < burnAmount || - token.TotalSupply.ToInt64() < burnAmount { - logger.Info("burn token failed", "reason", "no enough tokens to burn") - return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() - } - - _, _, sdkError := keeper.SubtractCoins(ctx, token.Owner, sdk.Coins{{ - Denom: symbol, - Amount: burnAmount, - }}) - if sdkError != nil { - logger.Error("burn token failed", "reason", "subtract tokens failed: "+sdkError.Error()) - return sdkError.Result() - } - - newTotalSupply := token.TotalSupply.ToInt64() - burnAmount - err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) - if err != nil { - logger.Error("burn token failed", "reason", "update total supply failed: "+err.Error()) - return sdk.ErrInternal(err.Error()).Result() - } - - logger.Info("successfully burnt token", "NewTotalSupply", newTotalSupply) - return sdk.Result{} -} diff --git a/plugins/miniTokens/burn/msg.go b/plugins/miniTokens/burn/msg.go deleted file mode 100644 index 24ba028c3..000000000 --- a/plugins/miniTokens/burn/msg.go +++ /dev/null @@ -1,61 +0,0 @@ -package burn - -import ( - "encoding/json" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/common/types" -) - -// TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash -// const BurnRoute = "tokens/burn" -const BurnRoute = "miniTokensBurn" - -var _ sdk.Msg = BurnMsg{} - -type BurnMsg struct { - From sdk.AccAddress `json:"from"` - Symbol string `json:"symbol"` - Amount int64 `json:"amount"` -} - -func NewMsg(from sdk.AccAddress, symbol string, amount int64) BurnMsg { - return BurnMsg{ - From: from, - Symbol: symbol, - Amount: amount, - } -} - -func (msg BurnMsg) Route() string { return BurnRoute } -func (msg BurnMsg) Type() string { return BurnRoute } -func (msg BurnMsg) String() string { - return fmt.Sprintf("BurnMsg{%v#%v%v}", msg.From, msg.Amount, msg.Symbol) -} -func (msg BurnMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } -func (msg BurnMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } - -// ValidateBasic does a simple validation check that -// doesn't require access to any other information. -func (msg BurnMsg) ValidateBasic() sdk.Error { - // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") - err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) - if err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } - if msg.Amount <= 0 { - // TODO: maybe we need to define our own errors - return sdk.ErrInsufficientFunds("amount should be more than 0") - } - return nil -} - -func (msg BurnMsg) GetSignBytes() []byte { - b, err := json.Marshal(msg) // XXX: ensure some canonical form - if err != nil { - panic(err) - } - return b -} diff --git a/plugins/miniTokens/client/cli/burn.go b/plugins/miniTokens/client/cli/burn.go deleted file mode 100644 index c8268a398..000000000 --- a/plugins/miniTokens/client/cli/burn.go +++ /dev/null @@ -1,35 +0,0 @@ -package commands - -import ( - "github.com/binance-chain/node/common/types" - "github.com/spf13/cobra" - "github.com/spf13/viper" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/binance-chain/node/plugins/minitokens/burn" -) - -func burnTokenCmd(cmdr Commander) *cobra.Command { - cmd := &cobra.Command{ - Use: "burn", - Short: "burn some amount of mini-token", - RunE: cmdr.burnToken, - } - - cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the token to be burnt") - cmd.Flags().StringP(flagAmount, "n", "", "amount of the token to be burnt") - - return cmd -} - -func (c Commander) burnToken(cmd *cobra.Command, args []string) error { - symbol := viper.GetString(flagSymbol) - err := types.ValidateMapperMiniTokenSymbol(symbol) - if err != nil { - return err - } - burnMsgBuilder := func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg { - return burn.NewMsg(from, symbol, amount) - } - - return c.checkAndSendTx(cmd, args, burnMsgBuilder) -} diff --git a/plugins/miniTokens/client/cli/commands.go b/plugins/miniTokens/client/cli/commands.go index 84d9f0dcc..ec497211c 100644 --- a/plugins/miniTokens/client/cli/commands.go +++ b/plugins/miniTokens/client/cli/commands.go @@ -27,10 +27,6 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { client.PostCommands( getTokenInfoCmd(cmdr), issueMiniTokenCmd(cmdr), - mintMiniTokenCmd(cmdr), - freezeMiniTokenCmd(cmdr), - unfreezeMiniTokenCmd(cmdr), - burnTokenCmd(cmdr), setTokenURICmd(cmdr),)...) miniTokenCmd.AddCommand(client.LineBreak) diff --git a/plugins/miniTokens/client/cli/freeze.go b/plugins/miniTokens/client/cli/freeze.go deleted file mode 100644 index c94264a75..000000000 --- a/plugins/miniTokens/client/cli/freeze.go +++ /dev/null @@ -1,63 +0,0 @@ -package commands - -import ( - "github.com/binance-chain/node/common/types" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/plugins/minitokens/freeze" -) - -func freezeMiniTokenCmd(cmdr Commander) *cobra.Command { - cmd := &cobra.Command{ - Use: "freeze", - Short: "freeze some amount of mini-token", - RunE: cmdr.freezeToken, - } - - cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the token to be frozen") - cmd.Flags().StringP(flagAmount, "n", "", "amount of the token to be frozen") - - return cmd -} - -func unfreezeMiniTokenCmd(cmdr Commander) *cobra.Command { - cmd := &cobra.Command{ - Use: "unfreeze", - Short: "unfreeze some amount of mini-token", - RunE: cmdr.unfreeze, - } - - cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the token to be frozen") - cmd.Flags().StringP(flagAmount, "n", "", "amount of the token to be frozen") - - return cmd -} - -func (c Commander) freezeToken(cmd *cobra.Command, args []string) error { - symbol := viper.GetString(flagSymbol) - err := types.ValidateMapperMiniTokenSymbol(symbol) - if err != nil { - return err - } - freezeMsgBuilder := func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg { - return freeze.NewFreezeMsg(from, symbol, amount) - } - - return c.checkAndSendTx(cmd, args, freezeMsgBuilder) -} - -func (c Commander) unfreeze(cmd *cobra.Command, args []string) error { - symbol := viper.GetString(flagSymbol) - err := types.ValidateMapperMiniTokenSymbol(symbol) - if err != nil { - return err - } - unfreezeMsgBuilder := func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg { - return freeze.NewUnfreezeMsg(from, symbol, amount) - } - - return c.checkAndSendTx(cmd, args, unfreezeMsgBuilder) -} diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/miniTokens/client/cli/issue.go index b69c4771a..7c38c1a81 100644 --- a/plugins/miniTokens/client/cli/issue.go +++ b/plugins/miniTokens/client/cli/issue.go @@ -36,19 +36,6 @@ func issueMiniTokenCmd(cmdr Commander) *cobra.Command { return cmd } -func mintMiniTokenCmd(cmdr Commander) *cobra.Command { - cmd := &cobra.Command{ - Use: "mint", - Short: "mint mini tokens for an existing token", - RunE: cmdr.mintToken, - } - - cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the token") - cmd.Flags().Int64P(flagAmount, "n", 0, "amount to mint") - cmd.MarkFlagRequired(flagAmount) - return cmd -} - func (c Commander) issueToken(cmd *cobra.Command, args []string) error { cliCtx, txBldr := client.PrepareCtx(c.Cdc) from, err := cliCtx.GetFromAddress() @@ -92,29 +79,6 @@ func (c Commander) issueToken(cmd *cobra.Command, args []string) error { return client.SendOrPrintTx(cliCtx, txBldr, msg) } -func (c Commander) mintToken(cmd *cobra.Command, args []string) error { - cliCtx, txBldr := client.PrepareCtx(c.Cdc) - from, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - - symbol := viper.GetString(flagSymbol) - err = types.ValidateMapperMiniTokenSymbol(symbol) - if err != nil { - return err - } - - amount := viper.GetInt64(flagAmount) - err = checkSupplyAmount(amount, 0) - if err != nil { - return err - } - - msg := issue.NewMintMsg(from, symbol, amount) - return client.SendOrPrintTx(cliCtx, txBldr, msg) -} - func checkMaxSupplyAmount(amount int64) error { if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenMaxTotalSupplyUpperBound { return errors.New("invalid max supply amount") @@ -126,7 +90,7 @@ func checkSupplyAmount(amount, maxAmount int64) error { if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenMaxTotalSupplyUpperBound { return errors.New("invalid supply amount") } - if maxAmount > 0 && amount > maxAmount { + if amount > maxAmount { return errors.New("supply amount cannot exceed max supply amount") } return nil diff --git a/plugins/miniTokens/client/cli/uri.go b/plugins/miniTokens/client/cli/uri.go deleted file mode 100644 index 946e9188e..000000000 --- a/plugins/miniTokens/client/cli/uri.go +++ /dev/null @@ -1,44 +0,0 @@ -package commands - -import ( - "github.com/binance-chain/node/common/client" - "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/minitokens/uri" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -func setTokenURICmd(cmdr Commander) *cobra.Command { - cmd := &cobra.Command{ - Use: "set-uri --symbol {symbol} --uri {token uri} --from {token issuer address}", - Short: "set token URI of mini-token", - RunE: cmdr.setTokenURI, - } - - cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the mini-token") - cmd.Flags().StringP(flagURI, "u", "", "a distinct uri for the mini-token") - cmd.Flags().String(flagTokenUri, "", "uri of the token information") - - return cmd -} - -func (c Commander) setTokenURI(cmd *cobra.Command, args []string) error { - cliCtx, txBldr := client.PrepareCtx(c.Cdc) - from, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - symbol := viper.GetString(flagSymbol) - err = types.ValidateMapperMiniTokenSymbol(symbol) - if err != nil { - return err - } - tokenURI := viper.GetString(flagTokenUri) - err = validateTokenURI(tokenURI) - if err != nil { - return err - } - - msg := uri.NewSetUriMsg(from, symbol, tokenURI) - return client.SendOrPrintTx(cliCtx, txBldr, msg) -} diff --git a/plugins/miniTokens/freeze/handler.go b/plugins/miniTokens/freeze/handler.go deleted file mode 100644 index fff2b79ec..000000000 --- a/plugins/miniTokens/freeze/handler.go +++ /dev/null @@ -1,113 +0,0 @@ -package freeze - -import ( - "fmt" - "reflect" - "strings" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - - "github.com/binance-chain/node/common/log" - common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/minitokens/store" -) - -// NewHandler creates a new token freeze message handler -func NewHandler(tokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case FreezeMsg: - return handleFreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) - case UnfreezeMsg: - return handleUnfreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) - default: - errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - -func handleFreezeToken(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg FreezeMsg) sdk.Result { - freezeAmount := msg.Amount - symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "miniToken", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) - errLogMsg := "freeze token failed" - _, err := miniTokenMapper.GetToken(ctx, symbol) - if err != nil { - logger.Info(errLogMsg, "reason", "symbol not exist") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() - } - - coins := keeper.GetCoins(ctx, msg.From) - if coins.AmountOf(symbol) < freezeAmount { - logger.Info(errLogMsg, "reason", "no enough free tokens to freeze") - return sdk.ErrInsufficientCoins("do not have enough token to freeze").Result() - } - - useAllBalance := coins.AmountOf(symbol) == freezeAmount - - if !useAllBalance && (msg.Amount % common.MiniTokenMinTotalSupply !=0) { - logger.Info(errLogMsg, "reason", "freeze amount is not integer") - return sdk.ErrInvalidCoins( - fmt.Sprintf("amount should be a multiple of %v or equals total account balance", common.MiniTokenMinTotalSupply)).Result() - } - - if msg.Amount<=0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinTotalSupply)){ - logger.Info(errLogMsg, "reason", "freeze amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", - common.MiniTokenMinTotalSupply)).Result() - } - - account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) - newFrozenTokens := account.GetFrozenCoins().Plus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) - newFreeTokens := account.GetCoins().Minus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) - account.SetFrozenCoins(newFrozenTokens) - account.SetCoins(newFreeTokens) - accKeeper.SetAccount(ctx, account) - logger.Info("finish freezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) - return sdk.Result{} -} - -func handleUnfreezeToken(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg UnfreezeMsg) sdk.Result { - unfreezeAmount := msg.Amount - symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "miniToken", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) - account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) - frozenAmount := account.GetFrozenCoins().AmountOf(symbol) - useAllFrozenBalance := frozenAmount == unfreezeAmount - errLogMsg := "unfreeze token failed" - - _, err := miniTokenMapper.GetToken(ctx, symbol) - if err != nil { - logger.Info(errLogMsg, "reason", "symbol not exist") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() - } - - if !useAllFrozenBalance && (unfreezeAmount % common.MiniTokenMinTotalSupply !=0) { - logger.Info(errLogMsg, "reason", "unfreeze amount is not integer") - return sdk.ErrInvalidCoins( - fmt.Sprintf("amount should be a multiple of %v or equals total frozen balance", common.MiniTokenMinTotalSupply)).Result() - } - - if unfreezeAmount<=0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinTotalSupply)) { - logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", - common.MiniTokenMinTotalSupply)).Result() - } - - if frozenAmount < unfreezeAmount { - logger.Info(errLogMsg, "reason", "no enough frozen tokens to unfreeze") - return sdk.ErrInsufficientCoins("do not have enough token to unfreeze").Result() - } - - newFrozenTokens := account.GetFrozenCoins().Minus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) - newFreeTokens := account.GetCoins().Plus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) - - account.SetFrozenCoins(newFrozenTokens) - account.SetCoins(newFreeTokens) - accKeeper.SetAccount(ctx, account) - logger.Debug("finish unfreezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) - return sdk.Result{} -} diff --git a/plugins/miniTokens/freeze/msg.go b/plugins/miniTokens/freeze/msg.go deleted file mode 100644 index 4c9b9fdc1..000000000 --- a/plugins/miniTokens/freeze/msg.go +++ /dev/null @@ -1,100 +0,0 @@ -package freeze - -import ( - "encoding/json" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/common/types" -) - -// TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash -const FreezeRoute = "miniTokensFreeze" - -var _ sdk.Msg = FreezeMsg{} - -type FreezeMsg struct { - From sdk.AccAddress `json:"from"` - Symbol string `json:"symbol"` - Amount int64 `json:"amount"` -} - -func NewFreezeMsg(from sdk.AccAddress, symbol string, amount int64) FreezeMsg { - return FreezeMsg{ - From: from, - Symbol: symbol, - Amount: amount, - } -} - -func (msg FreezeMsg) Route() string { return FreezeRoute } -func (msg FreezeMsg) Type() string { return FreezeRoute } -func (msg FreezeMsg) String() string { - return fmt.Sprintf("Freeze{%v#%v%v}", msg.From, msg.Amount, msg.Symbol) -} -func (msg FreezeMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } -func (msg FreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } - -// ValidateBasic does a simple validation check that -// doesn't require access to any other information. -func (msg FreezeMsg) ValidateBasic() sdk.Error { - // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") - err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) - if err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } - if msg.Amount <= 0 { - return sdk.ErrInsufficientFunds("amount should be more than 0") - } - return nil -} - -func (msg FreezeMsg) GetSignBytes() []byte { - b, err := json.Marshal(msg) // XXX: ensure some canonical form - if err != nil { - panic(err) - } - return b -} - -var _ sdk.Msg = UnfreezeMsg{} - -type UnfreezeMsg struct { - From sdk.AccAddress `json:"from"` - Symbol string `json:"symbol"` - Amount int64 `json:"amount"` -} - -func NewUnfreezeMsg(from sdk.AccAddress, symbol string, amount int64) UnfreezeMsg { - return UnfreezeMsg{ - From: from, Symbol: symbol, Amount: amount} -} - -func (msg UnfreezeMsg) Route() string { return FreezeRoute } -func (msg UnfreezeMsg) Type() string { return FreezeRoute } -func (msg UnfreezeMsg) String() string { - return fmt.Sprintf("Unfreeze{%v#%v%v}", msg.From, msg.Amount, msg.Symbol) -} -func (msg UnfreezeMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } -func (msg UnfreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } - -func (msg UnfreezeMsg) ValidateBasic() sdk.Error { - // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") - err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) - if err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } - if msg.Amount <= 0 { - return sdk.ErrInsufficientFunds("amount should be more than 0") - } - return nil -} - -func (msg UnfreezeMsg) GetSignBytes() []byte { - b, err := json.Marshal(msg) // XXX: ensure some canonical form - if err != nil { - panic(err) - } - return b -} diff --git a/plugins/miniTokens/issue/handler.go b/plugins/miniTokens/issue/handler.go index 56290e22d..d1c0941ae 100644 --- a/plugins/miniTokens/issue/handler.go +++ b/plugins/miniTokens/issue/handler.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/binance-chain/node/common/upgrade" "reflect" - "strconv" "strings" "github.com/cosmos/cosmos-sdk/baseapp" @@ -23,8 +22,6 @@ func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handl switch msg := msg.(type) { case IssueMsg: return handleIssueToken(ctx, tokenMapper, keeper, msg) - case MintMsg: - return handleMintToken(ctx, tokenMapper, keeper, msg) default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -38,7 +35,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe logger := log.With("module", "miniToken", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) var suffix string - if !sdk.IsUpgrade(upgrade.BEP69) { + if !sdk.IsUpgrade(upgrade.BEP8) { return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")).Result() } @@ -59,18 +56,6 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() } - if msg.MaxTotalSupply % common.MiniTokenMinTotalSupply !=0 { - logger.Info(errLogMsg, "reason", "max total supply is not integer") - return sdk.ErrInvalidCoins( - fmt.Sprintf("max total supply should be a multiple of %v", common.MiniTokenMinTotalSupply)).Result() - } - - if msg.TotalSupply % common.MiniTokenMinTotalSupply !=0 { - logger.Info(errLogMsg, "reason", "total supply is not integer") - return sdk.ErrInvalidCoins( - fmt.Sprintf("total supply should be a multiple of %v", common.MiniTokenMinTotalSupply)).Result() - } - if msg.MaxTotalSupply < common.MiniTokenMinTotalSupply { logger.Info(errLogMsg, "reason", "max total supply doesn't reach the min supply") return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too small, the min amount is %d", @@ -144,69 +129,4 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe } } -func handleMintToken(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { - symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "miniToken", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) - errLogMsg := "mint token failed" - token, err := miniTokenMapper.GetToken(ctx, symbol) - if err != nil { - logger.Info(errLogMsg, "reason", "symbol not exist") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() - } - - if !token.Mintable { - logger.Info(errLogMsg, "reason", "token cannot be minted") - return sdk.ErrInvalidCoins(fmt.Sprintf("token(%s) cannot be minted", msg.Symbol)).Result() - } - - if !token.IsOwner(msg.From) { - logger.Info(errLogMsg, "reason", "not the token owner") - return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() - } - - if msg.Amount % common.MiniTokenMinTotalSupply !=0 { - logger.Info(errLogMsg, "reason", "mint amount is not integer") - return sdk.ErrInvalidCoins( - fmt.Sprintf("amount should be a multiple of %v", common.MiniTokenMinTotalSupply)).Result() - } - - if msg.Amount < common.MiniTokenMinTotalSupply { - logger.Info(errLogMsg, "reason", "mint amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %d", - common.MiniTokenMinTotalSupply)).Result() - } - // use minus to prevent overflow - if msg.Amount > token.MaxTotalSupply.ToInt64() -token.TotalSupply.ToInt64() { - logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %d", - token.MaxTotalSupply)).Result() - } - - if msg.Amount > common.MiniTokenMaxTotalSupplyUpperBound-token.TotalSupply.ToInt64() { - logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply upper bound") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %d", - common.MiniTokenMaxTotalSupplyUpperBound)).Result() - } - newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount - err = miniTokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) - if err != nil { - logger.Error(errLogMsg, "reason", "update total supply failed: "+err.Error()) - return sdk.ErrInternal(fmt.Sprintf("update total supply failed")).Result() - } - - _, _, sdkError := bankKeeper.AddCoins(ctx, token.Owner, - sdk.Coins{{ - Denom: token.Symbol, - Amount: msg.Amount, - }}) - if sdkError != nil { - logger.Error(errLogMsg, "reason", "update balance failed: "+sdkError.Error()) - return sdkError.Result() - } - - logger.Info("finished minting token") - return sdk.Result{ - Data: []byte(strconv.FormatInt(newTotalSupply, 10)), - } -} diff --git a/plugins/miniTokens/issue/handler_test.go b/plugins/miniTokens/issue/handler_test.go index e95e2511b..853e5ba3f 100644 --- a/plugins/miniTokens/issue/handler_test.go +++ b/plugins/miniTokens/issue/handler_test.go @@ -1,6 +1,7 @@ package issue import ( + "github.com/binance-chain/node/common/upgrade" "testing" "github.com/stretchr/testify/require" @@ -35,7 +36,17 @@ func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.MiniTokenMappe return ctx, handler, accountKeeper, tokenMapper } +func setChainVersion() { + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) +} + +func resetChainVersion() { + upgrade.Mgr.Config.HeightMap = nil +} + func TestHandleIssueToken(t *testing.T) { + setChainVersion() + defer resetChainVersion() ctx, handler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) @@ -46,10 +57,10 @@ func TestHandleIssueToken(t *testing.T) { require.Contains(t, sdkResult.Log, "max total supply is too large") ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100001e8, 100000e8-100, false, "http://www.xyz.com/nnb.json") + msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, 10000e8+100, false, "http://www.xyz.com/nnb.json") sdkResult = handler(ctx, msg) require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "total supply should be a multiple of 100000000") + require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply is") ctx = ctx.WithValue(baseapp.TxHashKey, "000") msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100000e8, 100000e8, false, "http://www.xyz.com/nnb.json") @@ -64,49 +75,3 @@ func TestHandleIssueToken(t *testing.T) { sdkResult = handler(ctx, msg) require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") } - -func TestHandleMintToken(t *testing.T) { - ctx, handler, accountKeeper, tokenMapper := setup() - _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) - mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 10000e8) - sdkResult := handler(ctx, mintMsg) - require.Contains(t, sdkResult.Log, "symbol(NNB-000M) does not exist") - - issueMsg := NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100000e8, 90000e8, true, "http://www.xyz.com/nnb.json") - ctx = ctx.WithValue(baseapp.TxHashKey, "000") - sdkResult = handler(ctx, issueMsg) - require.Equal(t, true, sdkResult.Code.IsOK()) - - sdkResult = handler(ctx, mintMsg) - token, err := tokenMapper.GetToken(ctx, "NNB-000M") - require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 100000e8, 100000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, token) - - sdkResult = handler(ctx, mintMsg) - require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "mint amount is too large") - - invalidMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", types.MiniTokenMaxTotalSupplyUpperBound) - sdkResult = handler(ctx, invalidMintMsg) - require.Contains(t, sdkResult.Log, "mint amount is too large") - - _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) - invalidMintMsg = NewMintMsg(acc2.GetAddress(), "NNB-000M", types.MiniTokenMaxTotalSupplyUpperBound) - sdkResult = handler(ctx, invalidMintMsg) - require.Contains(t, sdkResult.Log, "only the owner can mint token NNB") - - // issue a non-mintable token - issueMsg = NewIssueMsg(acc.GetAddress(), "New BNB2", "NNB2", 100000e8, 100000e8, false, "http://www.xyz.com/nnb.json") - ctx = ctx.WithValue(baseapp.TxHashKey, "000") - sdkResult = handler(ctx, issueMsg) - require.Equal(t, true, sdkResult.Code.IsOK()) - - mintMsg = NewMintMsg(acc.GetAddress(), "NNB2-000M", 10000e8) - sdkResult = handler(ctx, mintMsg) - require.Contains(t, sdkResult.Log, "token(NNB2-000M) cannot be minted") - - // mint native token - invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) - require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "suffixed mini-token symbol must contain a hyphen") -} diff --git a/plugins/miniTokens/issue/msg.go b/plugins/miniTokens/issue/msg.go index 48d294f14..de91629f2 100644 --- a/plugins/miniTokens/issue/msg.go +++ b/plugins/miniTokens/issue/msg.go @@ -13,7 +13,6 @@ const ( Route = "miniTokensIssue" IssueMsgType = "miniIssueMsg" AdvIssueMsgType = "advMiniIssueMsg" //For max total supply in range 2 - MintMsgType = "miniMintMsg" maxTokenNameLength = 32 ) @@ -58,15 +57,7 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { } if len(msg.TokenURI) > types.MaxTokenURILength { - return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", types.MaxTokenURILength)) - } - - if msg.MaxTotalSupply%types.MiniTokenMinTotalSupply != 0 { - return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply should be a multiple of %v", types.MiniTokenMinTotalSupply)) - } - - if msg.TotalSupply%types.MiniTokenMinTotalSupply != 0 { - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be a multiple of %v", types.MiniTokenMinTotalSupply)) + return sdk.ErrInvalidCoins(fmt.Sprintf("token seturi should not exceed %v characters", types.MaxTokenURILength)) } if msg.MaxTotalSupply < types.MiniTokenMinTotalSupply || msg.MaxTotalSupply > types.MiniTokenMaxTotalSupplyUpperBound { @@ -101,58 +92,3 @@ func (msg IssueMsg) GetSignBytes() []byte { func (msg IssueMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } - -type MintMsg struct { - From sdk.AccAddress `json:"from"` - Symbol string `json:"symbol"` - Amount int64 `json:"amount"` -} - -func NewMintMsg(from sdk.AccAddress, symbol string, amount int64) MintMsg { - return MintMsg{ - From: from, - Symbol: symbol, - Amount: amount, - } -} - -func (msg MintMsg) ValidateBasic() sdk.Error { - if msg.From == nil { - return sdk.ErrInvalidAddress("sender address cannot be empty") - } - - if err := types.ValidateMapperMiniTokenSymbol(msg.Symbol); err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } - - if msg.Symbol == types.NativeTokenSymbol { - return sdk.ErrInvalidCoins(fmt.Sprintf("cannot mint native token")) - } - - if msg.Amount%types.MiniTokenMinTotalSupply != 0 { - return sdk.ErrInvalidCoins(fmt.Sprintf("amount should be a multiple of %v", types.MiniTokenMinTotalSupply)) - } - - // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply - if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenMaxTotalSupplyUpperBound { - return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenMaxTotalSupplyUpperBound)) - } - - return nil -} - -// Implements MintMsg. -func (msg MintMsg) Route() string { return Route } -func (msg MintMsg) Type() string { return MintMsgType } -func (msg MintMsg) String() string { return fmt.Sprintf("MintMsg{%#v}", msg) } -func (msg MintMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } -func (msg MintMsg) GetSignBytes() []byte { - b, err := json.Marshal(msg) // XXX: ensure some canonical form - if err != nil { - panic(err) - } - return b -} -func (msg MintMsg) GetInvolvedAddresses() []sdk.AccAddress { - return msg.GetSigners() -} diff --git a/plugins/miniTokens/route.go b/plugins/miniTokens/route.go index 603724de7..771c60e54 100644 --- a/plugins/miniTokens/route.go +++ b/plugins/miniTokens/route.go @@ -1,11 +1,9 @@ package minitokens import ( - "github.com/binance-chain/node/plugins/minitokens/burn" - "github.com/binance-chain/node/plugins/minitokens/freeze" "github.com/binance-chain/node/plugins/minitokens/issue" + "github.com/binance-chain/node/plugins/minitokens/seturi" "github.com/binance-chain/node/plugins/minitokens/store" - "github.com/binance-chain/node/plugins/minitokens/uri" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" @@ -14,9 +12,6 @@ import ( func Routes(tokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) routes[issue.Route] = issue.NewHandler(tokenMapper, keeper) - routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, accKeeper, keeper) - routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, accKeeper, keeper) - routes[burn.BurnRoute] = burn.NewHandler(tokenMapper,keeper) - routes[uri.SetURIRoute] = uri.NewHandler(tokenMapper) + routes[seturi.SetURIRoute] = seturi.NewHandler(tokenMapper) return routes } diff --git a/plugins/miniTokens/uri/handler.go b/plugins/miniTokens/uri/handler.go deleted file mode 100644 index 3bd43cf82..000000000 --- a/plugins/miniTokens/uri/handler.go +++ /dev/null @@ -1,59 +0,0 @@ -package uri - -import ( - "fmt" - "github.com/binance-chain/node/common/log" - common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/minitokens/store" - sdk "github.com/cosmos/cosmos-sdk/types" - "reflect" - "strings" -) - -func NewHandler(tokenMapper store.MiniTokenMapper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case SetURIMsg: - return handleSetURI(ctx, tokenMapper, msg) - default: - errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - -func handleSetURI(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, msg SetURIMsg) sdk.Result { - symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "miniToken", "symbol", symbol, "tokenURI", msg.TokenURI, "from", msg.From) - - errLogMsg := "set token URI failed" - token, err := miniTokenMapper.GetToken(ctx, symbol) - if err != nil { - logger.Info(errLogMsg, "reason", "symbol not exist") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() - } - - if !token.IsOwner(msg.From) { - logger.Info(errLogMsg, "reason", "not the token owner") - return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() - } - - if len(msg.TokenURI) < 1 { - return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", common.MaxTokenURILength)).Result() - } - - if len(msg.TokenURI) > common.MaxTokenURILength { - return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", common.MaxTokenURILength)).Result() - } - err = miniTokenMapper.UpdateTokenURI(ctx, symbol, msg.TokenURI) - if err != nil { - logger.Error(errLogMsg, "reason", "update token uri failed: "+err.Error()) - return sdk.ErrInternal(fmt.Sprintf("update token uri failed")).Result() - } - - - logger.Info("finished update token uri") - return sdk.Result{ - Data: []byte(msg.TokenURI), - } -} diff --git a/plugins/miniTokens/uri/msg.go b/plugins/miniTokens/uri/msg.go deleted file mode 100644 index d8c6c6d5b..000000000 --- a/plugins/miniTokens/uri/msg.go +++ /dev/null @@ -1,54 +0,0 @@ -package uri - -import ( - "encoding/json" - "fmt" - "github.com/binance-chain/node/common/types" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -const SetURIRoute = "miniTokensSetURI" - -var _ sdk.Msg = SetURIMsg{} - -type SetURIMsg struct { - From sdk.AccAddress `json:"from"` - Symbol string `json:"symbol"` - TokenURI string `json:"token_uri"` -} - -func NewSetUriMsg(from sdk.AccAddress, symbol string, tokenURI string) SetURIMsg { - return SetURIMsg{ - From: from, - Symbol: symbol, - TokenURI: tokenURI, - } -} - -func (msg SetURIMsg) ValidateBasic() sdk.Error { - if msg.From == nil || len(msg.From) == 0{ - return sdk.ErrInvalidAddress("sender address cannot be empty") - } - - if err := types.ValidateMapperMiniTokenSymbol(msg.Symbol); err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } - - return nil -} - -// Implements MintMsg. -func (msg SetURIMsg) Route() string { return SetURIRoute } -func (msg SetURIMsg) Type() string { return SetURIRoute } -func (msg SetURIMsg) String() string { return fmt.Sprintf("SetURI{%#v}", msg) } -func (msg SetURIMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } -func (msg SetURIMsg) GetSignBytes() []byte { - b, err := json.Marshal(msg) // XXX: ensure some canonical form - if err != nil { - panic(err) - } - return b -} -func (msg SetURIMsg) GetInvolvedAddresses() []sdk.AccAddress { - return msg.GetSigners() -} diff --git a/plugins/miniTokens/wire.go b/plugins/miniTokens/wire.go index 8f92808fb..aad97eb68 100644 --- a/plugins/miniTokens/wire.go +++ b/plugins/miniTokens/wire.go @@ -1,19 +1,13 @@ package minitokens import ( - "github.com/binance-chain/node/plugins/minitokens/burn" - "github.com/binance-chain/node/plugins/minitokens/freeze" "github.com/binance-chain/node/plugins/minitokens/issue" - "github.com/binance-chain/node/plugins/minitokens/uri" + "github.com/binance-chain/node/plugins/minitokens/seturi" "github.com/binance-chain/node/wire" ) // Register concrete types on wire codec func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(issue.IssueMsg{}, "minitokens/IssueMsg", nil) - cdc.RegisterConcrete(issue.MintMsg{}, "minitokens/MintMsg", nil) - cdc.RegisterConcrete(freeze.FreezeMsg{}, "minitokens/FreezeMsg", nil) - cdc.RegisterConcrete(freeze.UnfreezeMsg{}, "minitokens/UnFreezeMsg", nil) - cdc.RegisterConcrete(burn.BurnMsg{}, "minitokens/BurnMsg", nil) - cdc.RegisterConcrete(uri.SetURIMsg{}, "minitokens/SetURIMsg", nil) + cdc.RegisterConcrete(seturi.SetURIMsg{}, "minitokens/SetURIMsg", nil) } diff --git a/plugins/param/genesis.go b/plugins/param/genesis.go index 88076d1e3..1555586e8 100644 --- a/plugins/param/genesis.go +++ b/plugins/param/genesis.go @@ -56,10 +56,8 @@ const ( //MiniToken fee MiniIssueFee = 10e8 AdvMiniIssueFee = 20e8 - MiniMintFee = 2e8 - MiniFreezeFee = 1e6 - MiniBurnFee = 2e8 MiniSetUriFee = 1e8 + MiniListingFee = 100e8 ) var DefaultGenesisState = param.GenesisState{ diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index c9aab7741..b90052b5e 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -1,6 +1,7 @@ package param import ( + "github.com/binance-chain/node/plugins/dex/listmini" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/gov" @@ -13,10 +14,8 @@ import ( "github.com/binance-chain/node/plugins/account" "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" - miniBurn "github.com/binance-chain/node/plugins/minitokens/burn" - miniFreeze "github.com/binance-chain/node/plugins/minitokens/freeze" miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" - miniURI "github.com/binance-chain/node/plugins/minitokens/uri" + miniURI "github.com/binance-chain/node/plugins/minitokens/seturi" "github.com/binance-chain/node/plugins/param/paramhub" param "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/plugins/tokens" @@ -64,14 +63,12 @@ func RegisterUpgradeBeginBlocker(paramHub *ParamHub) { } paramHub.UpdateFeeParams(ctx, swapFeeParams) }) - upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP69, func(ctx sdk.Context) { + upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP8, func(ctx sdk.Context) { miniTokenFeeParams := []param.FeeParam{ ¶m.FixedFeeParams{MsgType: miniIssue.IssueMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: miniIssue.AdvIssueMsgType, Fee: AdvMiniIssueFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: miniIssue.MintMsg{}.Type(), Fee: MiniMintFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: miniFreeze.FreezeMsg{}.Type(), Fee: MiniFreezeFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: miniBurn.BurnMsg{}.Type(), Fee: MiniBurnFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: miniURI.SetURIMsg{}.Type(), Fee: MiniSetUriFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: listmini.ListMiniMsg{}.Type(), Fee: MiniListingFee, FeeFor: types.FeeForProposer}, } paramHub.UpdateFeeParams(ctx, miniTokenFeeParams) }) @@ -109,9 +106,6 @@ func init() { swap.RefundHTLT: fees.FixedFeeCalculatorGen, miniIssue.IssueMsgType: fees.FixedFeeCalculatorGen, miniIssue.AdvIssueMsgType: fees.FixedFeeCalculatorGen, - miniIssue.MintMsgType: fees.FixedFeeCalculatorGen, - miniFreeze.FreezeRoute: fees.FixedFeeCalculatorGen, - miniBurn.BurnRoute: fees.FixedFeeCalculatorGen, miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, } } diff --git a/plugins/param/types/types.go b/plugins/param/types/types.go index 1fdbc471c..eeb17b820 100644 --- a/plugins/param/types/types.go +++ b/plugins/param/types/types.go @@ -43,10 +43,8 @@ var ( "miniIssueMsg": {}, "advMiniIssueMsg": {}, - "miniMintMsg": {}, - "miniTokensFreeze": {}, - "miniTokensBurn": {}, "miniTokensSetURI": {}, + "dexListMini": {}, } ValidTransferFeeMsgTypes = map[string]struct{}{ diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 2bd715183..9cbcda0a7 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -1,6 +1,7 @@ package burn import ( + "fmt" "reflect" "strings" @@ -8,15 +9,21 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/binance-chain/node/common/log" + common "github.com/binance-chain/node/common/types" + miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/store" ) -func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { +func NewHandler(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { if msg, ok := msg.(BurnMsg); ok { - return handleBurnToken(ctx, tokenMapper, keeper, msg) + symbol := strings.ToUpper(msg.Symbol) + if common.IsMiniTokenSymbol(symbol) { + return handleBurnMiniToken(ctx, miniTokenMapper, keeper, msg) + } else { + return handleBurnToken(ctx, tokenMapper, keeper, msg) + } } - errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() } @@ -63,3 +70,55 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep logger.Info("successfully burnt token", "NewTotalSupply", newTotalSupply) return sdk.Result{} } + +func handleBurnMiniToken(ctx sdk.Context, tokenMapper miniToken.MiniTokenMapper, keeper bank.Keeper, msg BurnMsg) sdk.Result { + logger := log.With("module", "miniToken", "symbol", msg.Symbol, "amount", msg.Amount) + burnAmount := msg.Amount + symbol := strings.ToUpper(msg.Symbol) + token, err := tokenMapper.GetToken(ctx, symbol) + errLogMsg := "burn token failed" + if err != nil { + logger.Info("burn token failed", "reason", "invalid token symbol") + return sdk.ErrInvalidCoins(err.Error()).Result() + } + + if !token.IsOwner(msg.From) { + logger.Info("burn token failed", "reason", "not token's owner", "from", msg.From, "owner", token.Owner) + return sdk.ErrUnauthorized("only the owner of the token can burn the token").Result() + } + + coins := keeper.GetCoins(ctx, token.Owner) + + useAllBalance := coins.AmountOf(symbol) == burnAmount + + if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { + logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", + common.MiniTokenMinTotalSupply)).Result() + } + + if coins.AmountOf(symbol) < burnAmount || + token.TotalSupply.ToInt64() < burnAmount { + logger.Info("burn token failed", "reason", "no enough tokens to burn") + return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() + } + + _, _, sdkError := keeper.SubtractCoins(ctx, token.Owner, sdk.Coins{{ + Denom: symbol, + Amount: burnAmount, + }}) + if sdkError != nil { + logger.Error("burn token failed", "reason", "subtract tokens failed: "+sdkError.Error()) + return sdkError.Result() + } + + newTotalSupply := token.TotalSupply.ToInt64() - burnAmount + err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) + if err != nil { + logger.Error("burn token failed", "reason", "update total supply failed: "+err.Error()) + return sdk.ErrInternal(err.Error()).Result() + } + + logger.Info("successfully burnt token", "NewTotalSupply", newTotalSupply) + return sdk.Result{} +} diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index 176d12851..fcaafd1bc 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -40,6 +40,10 @@ func (msg BurnMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAdd // ValidateBasic does a simple validation check that // doesn't require access to any other information. func (msg BurnMsg) ValidateBasic() sdk.Error { + + if types.IsMiniTokenSymbol(msg.Symbol) { + return msg.validateMiniTokenBasic() + } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") err := types.ValidateMapperTokenSymbol(msg.Symbol) if err != nil { @@ -59,3 +63,14 @@ func (msg BurnMsg) GetSignBytes() []byte { } return b } + +func (msg BurnMsg) validateMiniTokenBasic() sdk.Error { + err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) + if err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + if msg.Amount <= 0 { + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil +} diff --git a/plugins/tokens/client/cli/issue.go b/plugins/tokens/client/cli/issue.go index a60c6f72f..3a4e7b040 100644 --- a/plugins/tokens/client/cli/issue.go +++ b/plugins/tokens/client/cli/issue.go @@ -4,6 +4,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" + "strings" "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" @@ -83,15 +84,22 @@ func (c Commander) mintToken(cmd *cobra.Command, args []string) error { } symbol := viper.GetString(flagSymbol) - err = types.ValidateMapperTokenSymbol(symbol) - if err != nil { - return err - } - amount := viper.GetInt64(flagAmount) - err = checkSupplyAmount(amount) - if err != nil { - return err + + if types.IsMiniTokenSymbol(strings.ToUpper(symbol)) { + err = checkMiniTokenSupplyAmount(amount) + if err != nil { + return err + } + }else { + err = types.ValidateMapperTokenSymbol(symbol) + if err != nil { + return err + } + err = checkSupplyAmount(amount) + if err != nil { + return err + } } msg := issue.NewMintMsg(from, symbol, amount) @@ -104,3 +112,10 @@ func checkSupplyAmount(amount int64) error { } return nil } +func checkMiniTokenSupplyAmount(amount int64) error { + if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenMaxTotalSupplyUpperBound { + return errors.New("invalid supply amount") + } + + return nil +} diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 786dbbe33..30b051d66 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -11,17 +11,28 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" + miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/store" ) // NewHandler creates a new token freeze message handler -func NewHandler(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) sdk.Handler { +func NewHandler(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case FreezeMsg: - return handleFreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) + symbol := strings.ToUpper(msg.Symbol) + if common.IsMiniTokenSymbol(symbol) { + return handleFreezeMiniToken(ctx, miniTokenMapper, accKeeper, keeper, msg) + } else { + return handleFreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) + } case UnfreezeMsg: - return handleUnfreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) + symbol := strings.ToUpper(msg.Symbol) + if common.IsMiniTokenSymbol(symbol) { + return handleUnfreezeMiniToken(ctx, miniTokenMapper, accKeeper, keeper, msg) + } else { + return handleUnfreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) + } default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -74,3 +85,75 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au logger.Debug("finish unfreezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) return sdk.Result{} } + +func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg FreezeMsg) sdk.Result { + freezeAmount := msg.Amount + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "miniToken", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) + errLogMsg := "freeze token failed" + _, err := miniTokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info(errLogMsg, "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + coins := keeper.GetCoins(ctx, msg.From) + if coins.AmountOf(symbol) < freezeAmount { + logger.Info(errLogMsg, "reason", "no enough free tokens to freeze") + return sdk.ErrInsufficientCoins("do not have enough token to freeze").Result() + } + + useAllBalance := coins.AmountOf(symbol) == freezeAmount + + if msg.Amount<=0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinTotalSupply)){ + logger.Info(errLogMsg, "reason", "freeze amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", + common.MiniTokenMinTotalSupply)).Result() + } + + account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) + newFrozenTokens := account.GetFrozenCoins().Plus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) + newFreeTokens := account.GetCoins().Minus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) + account.SetFrozenCoins(newFrozenTokens) + account.SetCoins(newFreeTokens) + accKeeper.SetAccount(ctx, account) + logger.Info("finish freezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) + return sdk.Result{} +} + +func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg UnfreezeMsg) sdk.Result { + unfreezeAmount := msg.Amount + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "miniToken", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) + account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) + frozenAmount := account.GetFrozenCoins().AmountOf(symbol) + useAllFrozenBalance := frozenAmount == unfreezeAmount + errLogMsg := "unfreeze token failed" + + _, err := miniTokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info(errLogMsg, "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + if unfreezeAmount<=0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinTotalSupply)) { + logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", + common.MiniTokenMinTotalSupply)).Result() + } + + if frozenAmount < unfreezeAmount { + logger.Info(errLogMsg, "reason", "no enough frozen tokens to unfreeze") + return sdk.ErrInsufficientCoins("do not have enough token to unfreeze").Result() + } + + newFrozenTokens := account.GetFrozenCoins().Minus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) + newFreeTokens := account.GetCoins().Plus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) + + account.SetFrozenCoins(newFrozenTokens) + account.SetCoins(newFreeTokens) + accKeeper.SetAccount(ctx, account) + logger.Debug("finish unfreezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) + return sdk.Result{} +} + diff --git a/plugins/tokens/freeze/msg.go b/plugins/tokens/freeze/msg.go index 4884af8cd..266e099b0 100644 --- a/plugins/tokens/freeze/msg.go +++ b/plugins/tokens/freeze/msg.go @@ -40,6 +40,10 @@ func (msg FreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccA // ValidateBasic does a simple validation check that // doesn't require access to any other information. func (msg FreezeMsg) ValidateBasic() sdk.Error { + + if types.IsMiniTokenSymbol(msg.Symbol) { + return msg.validateMiniTokenBasic() + } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") err := types.ValidateMapperTokenSymbol(msg.Symbol) if err != nil { @@ -60,6 +64,17 @@ func (msg FreezeMsg) GetSignBytes() []byte { return b } +func (msg FreezeMsg) validateMiniTokenBasic() sdk.Error { + err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) + if err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + if msg.Amount <= 0 { + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil +} + var _ sdk.Msg = UnfreezeMsg{} type UnfreezeMsg struct { @@ -82,6 +97,10 @@ func (msg UnfreezeMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetS func (msg UnfreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } func (msg UnfreezeMsg) ValidateBasic() sdk.Error { + + if types.IsMiniTokenSymbol(msg.Symbol) { + return msg.validateMiniTokenBasic() + } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") err := types.ValidateMapperTokenSymbol(msg.Symbol) if err != nil { @@ -101,3 +120,15 @@ func (msg UnfreezeMsg) GetSignBytes() []byte { } return b } + +func (msg UnfreezeMsg) validateMiniTokenBasic() sdk.Error { + // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") + err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) + if err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + if msg.Amount <= 0 { + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil +} diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 8b836880d..b506171cc 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -3,6 +3,7 @@ package issue import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" "reflect" "strconv" "strings" @@ -14,17 +15,23 @@ import ( "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" common "github.com/binance-chain/node/common/types" + miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/store" ) // NewHandler creates a new token issue message handler -func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { +func NewHandler(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case IssueMsg: return handleIssueToken(ctx, tokenMapper, keeper, msg) case MintMsg: - return handleMintToken(ctx, tokenMapper, keeper, msg) + symbol := strings.ToUpper(msg.Symbol) + if common.IsMiniTokenSymbol(symbol) { + return handleMintMiniToken(ctx, miniTokenMapper, keeper, msg) + } else { + return handleMintToken(ctx, tokenMapper, keeper, msg) + } default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -146,3 +153,66 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. Data: []byte(strconv.FormatInt(newTotalSupply, 10)), } } + +func handleMintMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "token", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) + if !sdk.IsUpgrade(upgrade.BEP8) { + return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")).Result() + } + errLogMsg := "mint token failed" + token, err := miniTokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info(errLogMsg, "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + if !token.Mintable { + logger.Info(errLogMsg, "reason", "token cannot be minted") + return sdk.ErrInvalidCoins(fmt.Sprintf("token(%s) cannot be minted", msg.Symbol)).Result() + } + + if !token.IsOwner(msg.From) { + logger.Info(errLogMsg, "reason", "not the token owner") + return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() + } + + if msg.Amount < common.MiniTokenMinTotalSupply { + logger.Info(errLogMsg, "reason", "mint amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %d", + common.MiniTokenMinTotalSupply)).Result() + } + // use minus to prevent overflow + if msg.Amount > token.MaxTotalSupply.ToInt64()-token.TotalSupply.ToInt64() { + logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %d", + token.MaxTotalSupply)).Result() + } + + if msg.Amount > common.MiniTokenMaxTotalSupplyUpperBound-token.TotalSupply.ToInt64() { + logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply upper bound") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %d", + common.MiniTokenMaxTotalSupplyUpperBound)).Result() + } + newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount + err = miniTokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) + if err != nil { + logger.Error(errLogMsg, "reason", "update total supply failed: "+err.Error()) + return sdk.ErrInternal(fmt.Sprintf("update total supply failed")).Result() + } + + _, _, sdkError := bankKeeper.AddCoins(ctx, token.Owner, + sdk.Coins{{ + Denom: token.Symbol, + Amount: msg.Amount, + }}) + if sdkError != nil { + logger.Error(errLogMsg, "reason", "update balance failed: "+sdkError.Error()) + return sdkError.Result() + } + + logger.Info("finished minting token") + return sdk.Result{ + Data: []byte(strconv.FormatInt(newTotalSupply, 10)), + } +} diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index e5a4cfc7b..29e805e2c 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -1,6 +1,7 @@ package issue import ( + "github.com/binance-chain/node/common/upgrade" "testing" "github.com/stretchr/testify/require" @@ -15,28 +16,39 @@ import ( "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" + miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" + miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) -func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { - ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() +func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper, miniTkstore.MiniTokenMapper) { + ms, capKey1, capKey2, capKey3 := testutils.SetupThreeMultiStoreForUnitTest() cdc := wire.NewCodec() tokenMapper := store.NewMapper(cdc, capKey1) accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) + miniTokenMapper := miniTkstore.NewMiniTokenMapper(cdc, capKey3) bankKeeper := bank.NewBaseKeeper(accountKeeper) - handler := NewHandler(tokenMapper, bankKeeper) - + handler := NewHandler(tokenMapper, miniTokenMapper, bankKeeper) + miniTokenHandler := miniIssue.NewHandler(miniTokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, sdk.RunTxModeDeliver, log.NewNopLogger()). WithAccountCache(auth.NewAccountCache(accountStoreCache)) - return ctx, handler, accountKeeper, tokenMapper + return ctx, handler, miniTokenHandler, accountKeeper, tokenMapper, miniTokenMapper +} + +func setChainVersion() { + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) +} + +func resetChainVersion() { + upgrade.Mgr.Config.HeightMap = nil } func TestHandleIssueToken(t *testing.T) { - ctx, handler, accountKeeper, tokenMapper := setup() + ctx, handler, _, accountKeeper, tokenMapper, _ := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") @@ -53,7 +65,7 @@ func TestHandleIssueToken(t *testing.T) { } func TestHandleMintToken(t *testing.T) { - ctx, handler, accountKeeper, tokenMapper := setup() + ctx, handler, _, accountKeeper, tokenMapper, _ := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000", 10000e8) sdkResult := handler(ctx, mintMsg) @@ -95,3 +107,57 @@ func TestHandleMintToken(t *testing.T) { invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "cannot mint native token") } + + +func TestHandleMintMiniToken(t *testing.T) { + setChainVersion() + defer resetChainVersion() + ctx, handler, miniTokenHandler, accountKeeper, tokenMapper, miniTokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 10000e8) + sdkResult := handler(ctx, mintMsg) + require.Contains(t, sdkResult.Log, "symbol(NNB-000M) does not exist") + + issueMsg := miniIssue.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100000e8, 90000e8, true, "http://www.xyz.com/nnb.json") + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + sdkResult = miniTokenHandler(ctx, issueMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + sdkResult = handler(ctx, mintMsg) + token, err := miniTokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 100000e8, 100000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, token) + + _, err = tokenMapper.GetToken(ctx, "NNB-000M") + require.NotNil(t,err) + require.Contains(t, err.Error(), "token(NNB-000M) not found") + + sdkResult = handler(ctx, mintMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "mint amount is too large") + + invalidMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", types.MiniTokenMaxTotalSupplyUpperBound) + sdkResult = handler(ctx, invalidMintMsg) + require.Contains(t, sdkResult.Log, "mint amount is too large") + + _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) + invalidMintMsg = NewMintMsg(acc2.GetAddress(), "NNB-000M", types.MiniTokenMaxTotalSupplyUpperBound) + sdkResult = handler(ctx, invalidMintMsg) + require.Contains(t, sdkResult.Log, "only the owner can mint token NNB") + + // issue a non-mintable token + issueMsg = miniIssue.NewIssueMsg(acc.GetAddress(), "New BNB2", "NNB2", 100000e8, 100000e8, false, "http://www.xyz.com/nnb.json") + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + sdkResult = miniTokenHandler(ctx, issueMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + mintMsg = NewMintMsg(acc.GetAddress(), "NNB2-000M", 10000e8) + sdkResult = handler(ctx, mintMsg) + require.Contains(t, sdkResult.Log, "token(NNB2-000M) cannot be minted") + + // mint native token + invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) + require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "cannot mint native token") +} + diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index 9a454c66f..4b6e42e89 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -92,6 +92,11 @@ func NewMintMsg(from sdk.AccAddress, symbol string, amount int64) MintMsg { } func (msg MintMsg) ValidateBasic() sdk.Error { + + if types.IsMiniTokenSymbol(msg.Symbol) { + return msg.validateMiniTokenBasic() + } + if msg.From == nil { return sdk.ErrInvalidAddress("sender address cannot be empty") } @@ -112,6 +117,24 @@ func (msg MintMsg) ValidateBasic() sdk.Error { return nil } +func (msg MintMsg) validateMiniTokenBasic() sdk.Error { + + if msg.From == nil { + return sdk.ErrInvalidAddress("sender address cannot be empty") + } + + if err := types.ValidateMapperMiniTokenSymbol(msg.Symbol); err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + + // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply + if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenMaxTotalSupplyUpperBound { + return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenMaxTotalSupplyUpperBound)) + } + + return nil +} + // Implements MintMsg. func (msg MintMsg) Route() string { return Route } func (msg MintMsg) Type() string { return MintMsgType } diff --git a/plugins/tokens/plugin.go b/plugins/tokens/plugin.go index b41bc6b32..cd7833abb 100644 --- a/plugins/tokens/plugin.go +++ b/plugins/tokens/plugin.go @@ -12,16 +12,17 @@ import ( app "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" + miniToken "github.com/binance-chain/node/plugins/minitokens" ) const abciQueryPrefix = "tokens" // InitPlugin initializes the plugin. func InitPlugin( - appp app.ChainApp, mapper Mapper, accKeeper auth.AccountKeeper, coinKeeper bank.Keeper, + appp app.ChainApp, mapper Mapper, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, coinKeeper bank.Keeper, timeLockKeeper timelock.Keeper, swapKeeper swap.Keeper) { // add msg handlers - for route, handler := range Routes(mapper, accKeeper, coinKeeper, timeLockKeeper, swapKeeper) { + for route, handler := range Routes(mapper, miniTokenMapper, accKeeper, coinKeeper, timeLockKeeper, swapKeeper) { appp.GetRouter().AddRoute(route, handler) } diff --git a/plugins/tokens/route.go b/plugins/tokens/route.go index a65c3ac70..506815dd0 100644 --- a/plugins/tokens/route.go +++ b/plugins/tokens/route.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" @@ -13,12 +14,12 @@ import ( "github.com/binance-chain/node/plugins/tokens/timelock" ) -func Routes(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, +func Routes(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, timeLockKeeper timelock.Keeper, swapKeeper swap.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) - routes[issue.Route] = issue.NewHandler(tokenMapper, keeper) - routes[burn.BurnRoute] = burn.NewHandler(tokenMapper, keeper) - routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, accKeeper, keeper) + routes[issue.Route] = issue.NewHandler(tokenMapper, miniTokenMapper, keeper) + routes[burn.BurnRoute] = burn.NewHandler(tokenMapper, miniTokenMapper, keeper) + routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, miniTokenMapper, accKeeper, keeper) routes[timelock.MsgRoute] = timelock.NewHandler(timeLockKeeper) routes[swap.AtomicSwapRoute] = swap.NewHandler(swapKeeper) return routes From 2a91ffc310531398660eb1c50be8129405350f34 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 7 Apr 2020 10:55:23 +0800 Subject: [PATCH 09/96] add files --- plugins/dex/order/quickselect.go | 52 ++++++ plugins/dex/order/quickselect_test.go | 208 ++++++++++++++++++++++++ plugins/dex/store/minitoken_mapper.go | 1 + plugins/miniTokens/client/cli/seturi.go | 44 +++++ plugins/miniTokens/seturi/handler.go | 59 +++++++ plugins/miniTokens/seturi/msg.go | 54 ++++++ 6 files changed, 418 insertions(+) create mode 100644 plugins/dex/order/quickselect.go create mode 100644 plugins/dex/order/quickselect_test.go create mode 100644 plugins/dex/store/minitoken_mapper.go create mode 100644 plugins/miniTokens/client/cli/seturi.go create mode 100644 plugins/miniTokens/seturi/handler.go create mode 100644 plugins/miniTokens/seturi/msg.go diff --git a/plugins/dex/order/quickselect.go b/plugins/dex/order/quickselect.go new file mode 100644 index 000000000..08ca407d0 --- /dev/null +++ b/plugins/dex/order/quickselect.go @@ -0,0 +1,52 @@ +package order + + +//Find and return top K symbols with largest number of order. +// The returned top K slice is not sorted. The input orderNums may be re-ordered in place. +// If more than one symbols have same order numbers, these symbol will be selected by ascending alphabetical sequence. +func findTopKLargest(orderNums []*SymbolWithOrderNumber, k int) []*SymbolWithOrderNumber { + if k>=len(orderNums) { + return orderNums + } + return quickselect(orderNums, 0, len(orderNums)-1, k) +} + + +func partition(orderNums []*SymbolWithOrderNumber, start, end, pivot int) int { + // move pivot to end + orderNums[end], orderNums[pivot] = orderNums[pivot], orderNums[end] + pivotValue := orderNums[end] + i := start + for j := start; j < end; j++ { + if compare(orderNums[j], pivotValue) { + orderNums[i], orderNums[j] = orderNums[j], orderNums[i] + i++ + } + } + // move pivot to its sorted position + orderNums[i], orderNums[end] = orderNums[end], orderNums[i] + // return pivot index + return i +} + +func compare(orderNumA *SymbolWithOrderNumber, orderNumB *SymbolWithOrderNumber) bool { + if orderNumA.numberOfOrders > orderNumB.numberOfOrders { + return true + }else if orderNumA.numberOfOrders == orderNumB.numberOfOrders { + return orderNumA.symbol < orderNumB.symbol + } + return false +} + +func quickselect(orderNums []*SymbolWithOrderNumber, start, end, n int) []*SymbolWithOrderNumber { + // use last element as pivot + pivotIndex := partition(orderNums, start, end, end) + + if n-1 == pivotIndex { + return orderNums[:pivotIndex+1] + } else if n-1 > pivotIndex { + return quickselect(orderNums, pivotIndex+1, end, n) + } else { + return quickselect(orderNums, start, pivotIndex-1, n) + } +} diff --git a/plugins/dex/order/quickselect_test.go b/plugins/dex/order/quickselect_test.go new file mode 100644 index 000000000..ec6eca55d --- /dev/null +++ b/plugins/dex/order/quickselect_test.go @@ -0,0 +1,208 @@ +package order + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_findKthLargest(t *testing.T) { + //A0 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 0} + A1 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 1} + A2 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 2} + A3 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 3} + A4 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 4} + A5 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 5} + A6 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 6} + //B2 := &SymbolWithOrderNumber{"b", 2} + B3 := &SymbolWithOrderNumber{"BAC-678M_BNB", 3} + B5 := &SymbolWithOrderNumber{"BAC-678M_BNB", 5} + //C3 := &SymbolWithOrderNumber{"c", 3} + C4 := &SymbolWithOrderNumber{"CUY-G42M_BNB", 4} + //D4 := &SymbolWithOrderNumber{"d", 4} + D3 := &SymbolWithOrderNumber{"DUY-765_BNB", 3} + //E5 := &SymbolWithOrderNumber{"e", 5} + E2 := &SymbolWithOrderNumber{"ETF-876_BNB", 2} + //F6 := &SymbolWithOrderNumber{"f", 6} + F1 := &SymbolWithOrderNumber{"FXM-987M_BNB", 1} + + assert := assert.New(t) + + expected := []*SymbolWithOrderNumber{A3, A4, A5} + result := findTopKLargest([]*SymbolWithOrderNumber{A1, A2, A3, A4, A5}, 3) + assert.Equal(3, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{A3, A4, A5} + result = findTopKLargest([]*SymbolWithOrderNumber{A5, A3, A3, A1, A4}, 3) + assert.Equal(3, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{A3, A4, A5} + result = findTopKLargest([]*SymbolWithOrderNumber{A5, B3, A3, A1, A4}, 3) + assert.Equal(3, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{A6, A5} + result = findTopKLargest([]*SymbolWithOrderNumber{A3, A2, A1, A5, A6, A4}, 2) + assert.Equal(2, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{A6, C4, B5} + result = findTopKLargest([]*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4}, 3) + assert.Equal(3, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4} + result = findTopKLargest([]*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4}, 6) + assert.Equal(6, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4} + result = findTopKLargest([]*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4}, 7) + assert.Equal(6, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } +} + +func Test_findKthLargest_SameNumber(t *testing.T) { + A0 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 0} + A1 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 1} + A2 := &SymbolWithOrderNumber{"ABC-9UEM_BNB", 2} + B2 := &SymbolWithOrderNumber{"BAC-678M_BNB", 2} + C1 := &SymbolWithOrderNumber{"CUY-G42M_BNB", 1} + C2 := &SymbolWithOrderNumber{"CUY-G42M_BNB", 2} + E2 := &SymbolWithOrderNumber{"ETF-876_BNB", 2} + F2 := &SymbolWithOrderNumber{"FXM-987M_BNB", 2} + + assert := assert.New(t) + + expected := []*SymbolWithOrderNumber{A2, B2, E2} + result := findTopKLargest([]*SymbolWithOrderNumber{F2, E2, A2, B2, C1}, 3) + assert.Equal(3, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{B2, A2, C2} + result = findTopKLargest([]*SymbolWithOrderNumber{A0, A1, A2, B2, C1, C2}, 3) + assert.Equal(3, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{A2} + result = findTopKLargest([]*SymbolWithOrderNumber{A0, A1, A2, B2, C1, C2}, 1) + assert.Equal(1, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{A1, A2, B2, C2} + result = findTopKLargest([]*SymbolWithOrderNumber{A0, A1, A2, B2, C1, C2}, 4) + assert.Equal(4, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } + + expected = []*SymbolWithOrderNumber{A1, A2, B2, C1, C2} + result = findTopKLargest([]*SymbolWithOrderNumber{A0, A1, A2, B2, C1, C2}, 5) + assert.Equal(5, len(result)) + for _, x := range result { + fmt.Printf("%v,", *x) + } + fmt.Println("") + for _, ele := range expected { + if !contains(result, ele) { + t.Fatalf("Expected contains %v, but doesn't exist", ele) + } + } +} + +func contains(s []*SymbolWithOrderNumber, e *SymbolWithOrderNumber) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/plugins/dex/store/minitoken_mapper.go b/plugins/dex/store/minitoken_mapper.go new file mode 100644 index 000000000..72440ea2a --- /dev/null +++ b/plugins/dex/store/minitoken_mapper.go @@ -0,0 +1 @@ +package store diff --git a/plugins/miniTokens/client/cli/seturi.go b/plugins/miniTokens/client/cli/seturi.go new file mode 100644 index 000000000..9f5082830 --- /dev/null +++ b/plugins/miniTokens/client/cli/seturi.go @@ -0,0 +1,44 @@ +package commands + +import ( + "github.com/binance-chain/node/common/client" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/minitokens/seturi" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func setTokenURICmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "set-uri --symbol {symbol} --uri {token uri} --from {token issuer address}", + Short: "set token URI of mini-token", + RunE: cmdr.setTokenURI, + } + + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the mini-token") + cmd.Flags().StringP(flagURI, "u", "", "a distinct uri for the mini-token") + cmd.Flags().String(flagTokenUri, "", "uri of the token information") + + return cmd +} + +func (c Commander) setTokenURI(cmd *cobra.Command, args []string) error { + cliCtx, txBldr := client.PrepareCtx(c.Cdc) + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + symbol := viper.GetString(flagSymbol) + err = types.ValidateMapperMiniTokenSymbol(symbol) + if err != nil { + return err + } + tokenURI := viper.GetString(flagTokenUri) + err = validateTokenURI(tokenURI) + if err != nil { + return err + } + + msg := seturi.NewSetUriMsg(from, symbol, tokenURI) + return client.SendOrPrintTx(cliCtx, txBldr, msg) +} diff --git a/plugins/miniTokens/seturi/handler.go b/plugins/miniTokens/seturi/handler.go new file mode 100644 index 000000000..31afe50da --- /dev/null +++ b/plugins/miniTokens/seturi/handler.go @@ -0,0 +1,59 @@ +package seturi + +import ( + "fmt" + "github.com/binance-chain/node/common/log" + common "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/minitokens/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "reflect" + "strings" +) + +func NewHandler(tokenMapper store.MiniTokenMapper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case SetURIMsg: + return handleSetURI(ctx, tokenMapper, msg) + default: + errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleSetURI(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, msg SetURIMsg) sdk.Result { + symbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "miniToken", "symbol", symbol, "tokenURI", msg.TokenURI, "from", msg.From) + + errLogMsg := "set token URI failed" + token, err := miniTokenMapper.GetToken(ctx, symbol) + if err != nil { + logger.Info(errLogMsg, "reason", "symbol not exist") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + if !token.IsOwner(msg.From) { + logger.Info(errLogMsg, "reason", "not the token owner") + return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() + } + + if len(msg.TokenURI) < 1 { + return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", common.MaxTokenURILength)).Result() + } + + if len(msg.TokenURI) > common.MaxTokenURILength { + return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", common.MaxTokenURILength)).Result() + } + err = miniTokenMapper.UpdateTokenURI(ctx, symbol, msg.TokenURI) + if err != nil { + logger.Error(errLogMsg, "reason", "update token uri failed: "+err.Error()) + return sdk.ErrInternal(fmt.Sprintf("update token uri failed")).Result() + } + + + logger.Info("finished update token uri") + return sdk.Result{ + Data: []byte(msg.TokenURI), + } +} diff --git a/plugins/miniTokens/seturi/msg.go b/plugins/miniTokens/seturi/msg.go new file mode 100644 index 000000000..06a86e8ba --- /dev/null +++ b/plugins/miniTokens/seturi/msg.go @@ -0,0 +1,54 @@ +package seturi + +import ( + "encoding/json" + "fmt" + "github.com/binance-chain/node/common/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const SetURIRoute = "miniTokensSetURI" + +var _ sdk.Msg = SetURIMsg{} + +type SetURIMsg struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + TokenURI string `json:"token_uri"` +} + +func NewSetUriMsg(from sdk.AccAddress, symbol string, tokenURI string) SetURIMsg { + return SetURIMsg{ + From: from, + Symbol: symbol, + TokenURI: tokenURI, + } +} + +func (msg SetURIMsg) ValidateBasic() sdk.Error { + if msg.From == nil || len(msg.From) == 0{ + return sdk.ErrInvalidAddress("sender address cannot be empty") + } + + if err := types.ValidateMapperMiniTokenSymbol(msg.Symbol); err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + + return nil +} + +// Implements MintMsg. +func (msg SetURIMsg) Route() string { return SetURIRoute } +func (msg SetURIMsg) Type() string { return SetURIRoute } +func (msg SetURIMsg) String() string { return fmt.Sprintf("SetURI{%#v}", msg) } +func (msg SetURIMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } +func (msg SetURIMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} +func (msg SetURIMsg) GetInvolvedAddresses() []sdk.AccAddress { + return msg.GetSigners() +} From 19f0b5967ca28944dc9198f7aa317eb90f9daae0 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 13 Apr 2020 19:24:01 +0800 Subject: [PATCH 10/96] add dex-mini keeper --- app/app.go | 76 ++- app/helpers.go | 8 + app/pub/helpers.go | 137 ++-- app/pub/keeper_pub_test.go | 10 +- app/pub/msgs.go | 24 +- app/pub/publisher.go | 60 +- app/pub/schemas.go | 74 +++ app/pub/schemas/executionResults1.avsc | 138 ++++ app/pub/types.go | 41 +- cmd/pressuremaker/utils/utils.go | 4 + common/stores.go | 32 +- common/types/mini_token.go | 4 +- networks/tools/snapshot_viewer/snapshot.go | 2 +- plugins/dex/aliases.go | 3 + plugins/dex/list/handler_test.go | 2 +- plugins/dex/listmini/handler.go | 22 +- plugins/dex/order/handler.go | 108 ++-- plugins/dex/order/handler_test.go | 2 +- plugins/dex/order/keeper.go | 224 ++++--- plugins/dex/order/keeper_recovery.go | 8 - plugins/dex/order/keeper_test.go | 4 +- plugins/dex/order/mini_keeper.go | 703 +++++++++++++++++++++ plugins/dex/plugin.go | 41 +- plugins/dex/route.go | 6 +- plugins/dex/store/mapper.go | 41 +- plugins/dex/store/mapper_test.go | 2 +- plugins/miniTokens/plugin.go | 2 +- plugins/tokens/burn/handler.go | 4 +- plugins/tokens/burn/msg.go | 4 - plugins/tokens/freeze/msg.go | 4 - 30 files changed, 1420 insertions(+), 370 deletions(-) create mode 100644 app/pub/schemas/executionResults1.avsc create mode 100644 plugins/dex/order/mini_keeper.go diff --git a/app/app.go b/app/app.go index cba3e05bc..08d5e91a6 100644 --- a/app/app.go +++ b/app/app.go @@ -79,16 +79,17 @@ type BinanceChain struct { queryHandlers map[string]types.AbciQueryHandler // keepers - CoinKeeper bank.Keeper - DexKeeper *dex.DexKeeper - AccountKeeper auth.AccountKeeper - TokenMapper tkstore.Mapper - MiniTokenMapper miniTkstore.MiniTokenMapper - ValAddrCache *ValAddrCache - stakeKeeper stake.Keeper - govKeeper gov.Keeper - timeLockKeeper timelock.Keeper - swapKeeper swap.Keeper + CoinKeeper bank.Keeper + DexKeeper *dex.DexKeeper + DexMiniTokenKeeper *dex.DexMiniTokenKeeper + AccountKeeper auth.AccountKeeper + TokenMapper tkstore.Mapper + MiniTokenMapper miniTkstore.MiniTokenMapper + ValAddrCache *ValAddrCache + stakeKeeper stake.Keeper + govKeeper gov.Keeper + timeLockKeeper timelock.Keeper + swapKeeper swap.Keeper // keeper to process param store and update ParamHub *param.ParamHub @@ -134,7 +135,8 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp app.MiniTokenMapper = miniTkstore.NewMiniTokenMapper(cdc, common.MiniTokenStoreKey) app.CoinKeeper = bank.NewBaseKeeper(app.AccountKeeper) app.ParamHub = paramhub.NewKeeper(cdc, common.ParamsStoreKey, common.TParamsStoreKey) - tradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.PairStoreKey) + tradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.PairStoreKey, false) + miniTokenTradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.MiniTokenPairStoreKey, true) app.stakeKeeper = stake.NewKeeper( cdc, @@ -243,7 +245,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp } // remaining plugin init - app.initDex(tradingPairMapper) + app.initDex(tradingPairMapper, miniTokenTradingPairMapper) app.initGovHooks() app.initPlugins() app.initParams() @@ -306,12 +308,17 @@ func (app *BinanceChain) initRunningMode() { } } -func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { +func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper, miniPairMapper dex.TradingPairMapper) { app.DexKeeper = dex.NewOrderKeeper(common.DexStoreKey, app.AccountKeeper, pairMapper, app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec, app.publicationConfig.ShouldPublishAny()) app.DexKeeper.SubscribeParamChange(app.ParamHub) + app.DexMiniTokenKeeper = dex.NewMiniKeeper(common.DexMiniStoreKey, app.AccountKeeper, miniPairMapper, + app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec, + app.publicationConfig.ShouldPublishAny()) + app.DexMiniTokenKeeper.SubscribeParamChange(app.ParamHub) + // do not proceed if we are in a unit test and `CheckState` is unset. if app.CheckState == nil { return @@ -331,12 +338,21 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { stateDB, app.LastBlockHeight(), app.TxDecoder) + + app.DexMiniTokenKeeper.Init( + app.CheckState.Ctx, + app.baseConfig.BreatheBlockInterval, + app.baseConfig.BreatheBlockDaysCountBack, + blockStore, + stateDB, + app.LastBlockHeight(), + app.TxDecoder) } func (app *BinanceChain) initPlugins() { tokens.InitPlugin(app, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) minitokens.InitPlugin(app, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper) - dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.govKeeper) + dex.InitPlugin(app, app.DexKeeper, app.DexMiniTokenKeeper, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.govKeeper) param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) } @@ -527,12 +543,16 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a isBreatheBlock := app.isBreatheBlock(height, lastBlockTime, blockTime) var tradesToPublish []*pub.Trade - + var miniTradesToPublish []*pub.Trade if sdk.IsUpgrade(upgrade.BEP19) || !isBreatheBlock { if app.publicationConfig.ShouldPublishAny() && pub.IsLive { + //todo parallel run, extract fees.Pool.AddAndCommitFee("MATCH", totalFee) tradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, ctx, isBreatheBlock) + miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexMiniTokenKeeper, ctx, isBreatheBlock) } else { + //todo parallel run, extract fees.Pool.AddAndCommitFee("MATCH", totalFee) app.DexKeeper.MatchAndAllocateAll(ctx, nil, isBreatheBlock) + app.DexMiniTokenKeeper.MatchAndAllocateAll(ctx, nil, isBreatheBlock) } } @@ -543,6 +563,7 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a app.takeSnapshotHeight = height icoDone := ico.EndBlockAsync(ctx) dex.EndBreatheBlock(ctx, app.DexKeeper, app.govKeeper, height, blockTime) + dex.EndBreatheBlock(ctx, app.DexMiniTokenKeeper, app.govKeeper, height, blockTime) param.EndBreatheBlock(ctx, app.ParamHub) tokens.EndBreatheBlock(ctx, app.swapKeeper) // other end blockers @@ -552,6 +573,7 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a } app.DexKeeper.StoreTradePrices(ctx) + app.DexMiniTokenKeeper.StoreTradePrices(ctx) blockFee := distributeFee(ctx, app.AccountKeeper, app.ValAddrCache, app.publicationConfig.PublishBlockFee) tags, passed, failed := gov.EndBlocker(ctx, app.govKeeper) @@ -576,12 +598,14 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a var stakeUpdates pub.StakeUpdates stakeUpdates = pub.CollectStakeUpdatesForPublish(completedUbd) if height >= app.publicationConfig.FromHeightInclusive { - app.publish(tradesToPublish, &proposals, &stakeUpdates, blockFee, ctx, height, blockTime.UnixNano()) + app.publish(tradesToPublish, miniTradesToPublish, &proposals, &stakeUpdates, blockFee, ctx, height, blockTime.UnixNano()) } // clean up intermediate cached data app.DexKeeper.ClearOrderChanges() app.DexKeeper.ClearRoundFee() + app.DexMiniTokenKeeper.ClearOrderChanges() + app.DexMiniTokenKeeper.ClearRoundFee() } fees.Pool.Clear() // just clean it, no matter use it or not. @@ -763,18 +787,21 @@ func MakeCodec() *wire.Codec { return cdc } -func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublish *pub.Proposals, stakeUpdates *pub.StakeUpdates, blockFee pub.BlockFee, ctx sdk.Context, height, blockTime int64) { +func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPublish []*pub.Trade, proposalsToPublish *pub.Proposals, stakeUpdates *pub.StakeUpdates, blockFee pub.BlockFee, ctx sdk.Context, height, blockTime int64) { pub.Logger.Info("start to collect publish information", "height", height) var accountsToPublish map[string]pub.Account var transferToPublish *pub.Transfers var blockToPublish *pub.Block var latestPriceLevels order.ChangedPriceLevelsMap + var miniLatestPriceLevels order.ChangedPriceLevelsMap duration := pub.Timer(app.Logger, fmt.Sprintf("collect publish information, height=%d", height), func() { if app.publicationConfig.PublishAccountBalance { txRelatedAccounts := app.Pool.TxRelatedAddrs() tradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, tradesToPublish) + miniTradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexMiniTokenKeeper, miniTradesToPublish) + tradeRelatedAccounts= append(tradeRelatedAccounts,miniTradeRelatedAccounts...) accountsToPublish = pub.GetAccountBalances( app.AccountKeeper, ctx, @@ -793,6 +820,7 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublis } if app.publicationConfig.PublishOrderBook { latestPriceLevels = app.DexKeeper.GetOrderBooks(pub.MaxOrderBookLevel) + miniLatestPriceLevels = app.DexMiniTokenKeeper.GetOrderBooks(pub.MaxOrderBookLevel) } }) @@ -804,6 +832,9 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublis "blockTime", blockTime, "numOfTrades", len(tradesToPublish), "numOfOrders", // the order num we collected here doesn't include trade related orders len(app.DexKeeper.OrderChanges), + "numOfMiniTrades", len(miniTradesToPublish), + "numOfMiniOrders", // the order num we collected here doesn't include trade related orders + len(app.DexMiniTokenKeeper.OrderChanges), "numOfProposals", proposalsToPublish.NumOfMsgs, "numOfStakeUpdates", @@ -811,16 +842,22 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublis "numOfAccounts", len(accountsToPublish)) pub.ToRemoveOrderIdCh = make(chan string, pub.ToRemoveOrderIdChannelSize) + pub.ToRemoveMiniOrderIdCh = make(chan string, pub.ToRemoveOrderIdChannelSize) + pub.ToPublishCh <- pub.NewBlockInfoToPublish( height, blockTime, tradesToPublish, + miniTradesToPublish, proposalsToPublish, stakeUpdates, app.DexKeeper.OrderChanges, // thread-safety is guarded by the signal from RemoveDoneCh + app.DexMiniTokenKeeper.OrderChanges, app.DexKeeper.OrderInfosForPub, // thread-safety is guarded by the signal from RemoveDoneCh + app.DexMiniTokenKeeper.OrderInfosForPub, accountsToPublish, latestPriceLevels, + miniLatestPriceLevels, blockFee, app.DexKeeper.RoundOrderFees, transferToPublish, @@ -830,6 +867,11 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublis for id := range pub.ToRemoveOrderIdCh { pub.Logger.Debug("delete order from order changes map", "orderId", id) delete(app.DexKeeper.OrderInfosForPub, id) + delete(app.DexMiniTokenKeeper.OrderInfosForPub, id) + } + for id := range pub.ToRemoveMiniOrderIdCh { + pub.Logger.Debug("delete mini order from order changes map", "orderId", id) + delete(app.DexMiniTokenKeeper.OrderInfosForPub, id) } pub.Logger.Debug("finish publish", "height", height) diff --git a/app/helpers.go b/app/helpers.go index ee640bc8e..6bf665846 100644 --- a/app/helpers.go +++ b/app/helpers.go @@ -195,6 +195,14 @@ func (app *BinanceChain) reInitChain() error { snapshot.Manager().GetStateDB(), app.LastBlockHeight(), app.TxDecoder) + app.DexMiniTokenKeeper.Init( + app.CheckState.Ctx, + app.baseConfig.BreatheBlockInterval, + app.baseConfig.BreatheBlockDaysCountBack, + snapshot.Manager().GetBlockStore(), + snapshot.Manager().GetStateDB(), + app.LastBlockHeight(), + app.TxDecoder) app.initParams() // init app cache diff --git a/app/pub/helpers.go b/app/pub/helpers.go index b3e9ba900..00e880f1f 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -24,24 +24,26 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) -func GetTradeAndOrdersRelatedAccounts(kp *orderPkg.Keeper, tradesToPublish []*Trade) []string { - res := make([]string, 0, len(tradesToPublish)*2+len(kp.OrderChanges)) +func GetTradeAndOrdersRelatedAccounts(kp orderPkg.DexOrderKeeper, tradesToPublish []*Trade) []string { + res := make([]string, 0, len(tradesToPublish)*2+len(kp.GetOrderChanges())) + OrderInfosForPub := kp.GetOrderInfosForPub() for _, t := range tradesToPublish { - if bo, ok := kp.OrderInfosForPub[t.Bid]; ok { + + if bo, ok := OrderInfosForPub[t.Bid]; ok { res = append(res, string(bo.Sender.Bytes())) } else { Logger.Error("failed to locate buy order in OrderChangesMap for trade account resolving", "bid", t.Bid) } - if so, ok := kp.OrderInfosForPub[t.Sid]; ok { + if so, ok := OrderInfosForPub[t.Sid]; ok { res = append(res, string(so.Sender.Bytes())) } else { Logger.Error("failed to locate sell order in OrderChangesMap for trade account resolving", "sid", t.Sid) } } - for _, orderChange := range kp.OrderChanges { - if orderInfo := kp.OrderInfosForPub[orderChange.Id]; orderInfo != nil { + for _, orderChange := range kp.GetOrderChanges() { + if orderInfo := OrderInfosForPub[orderChange.Id]; orderInfo != nil { res = append(res, string(orderInfo.Sender.Bytes())) } else { Logger.Error("failed to locate order change in OrderChangesMap", "orderChange", orderChange.String()) @@ -262,7 +264,7 @@ func GetAccountBalances(mapper auth.AccountKeeper, ctx sdk.Context, accSlices .. return } -func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.Keeper, ctx sdk.Context, matchAllMiniSymbols bool) []*Trade { +func MatchAndAllocateAllForPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, matchAllMiniSymbols bool) []*Trade { // This channels is used for protect not update `dexKeeper.OrderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) // while dexKeeper.OrderChanges are not separated by concurrent factor (users here) @@ -288,7 +290,7 @@ func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.Keeper, ctx sdk.Context, tradeIdx := 0 tradesToPublish := make([]*Trade, 0) tradeHeight := ctx.BlockHeight() - for _, pair := range dexKeeper.PairMapper.ListAllTradingPairs(ctx) { + for _, pair := range dexKeeper.GetPairMapper().ListAllTradingPairs(ctx) { symbol := pair.GetSymbol() matchEngTrades, _ := dexKeeper.GetLastTrades(tradeHeight, symbol) for _, trade := range matchEngTrades { @@ -324,7 +326,7 @@ func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.Keeper, ctx sdk.Context, } func ExpireOrdersForPublish( - dexKeeper *orderPkg.Keeper, + dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, blockTime time.Time) { expireHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize) @@ -342,7 +344,7 @@ func ExpireOrdersForPublish( return } -func DelistTradingPairForPublish(ctx sdk.Context, dexKeeper *orderPkg.Keeper, symbol string) { +func DelistTradingPairForPublish(ctx sdk.Context, dexKeeper orderPkg.DexOrderKeeper, symbol string) { expireHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize) wg := sync.WaitGroup{} wg.Add(1) @@ -381,22 +383,21 @@ func CollectStakeUpdatesForPublish(unbondingDelegations []stake.UnbondingDelegat } func updateExpireFeeForPublish( - dexKeeper *orderPkg.Keeper, + dexKeeper orderPkg.DexOrderKeeper, wg *sync.WaitGroup, expHolderCh <-chan orderPkg.ExpireHolder) { defer wg.Done() for expHolder := range expHolderCh { Logger.Debug("transfer collector for order", "orderId", expHolder.OrderId) change := orderPkg.OrderChange{expHolder.OrderId, expHolder.Reason, expHolder.Fee, nil} - dexKeeper.OrderChanges = append(dexKeeper.OrderChanges, change) + dexKeeper.UpdateOrderChange(change) } } // collect all changed books according to published order status func filterChangedOrderBooksByOrders( ordersToPublish []*Order, - latestPriceLevels orderPkg.ChangedPriceLevelsMap) orderPkg.ChangedPriceLevelsMap { - var res = make(orderPkg.ChangedPriceLevelsMap) + latestPriceLevels orderPkg.ChangedPriceLevelsMap, res orderPkg.ChangedPriceLevelsMap) orderPkg.ChangedPriceLevelsMap { // map from symbol -> price -> qty diff in this block var buyQtyDiff = make(map[string]map[int64]int64) var sellQtyDiff = make(map[string]map[int64]int64) @@ -507,9 +508,13 @@ func collectOrdersToPublish( orderChanges orderPkg.OrderChanges, orderInfos orderPkg.OrderInfoForPublish, feeHolder orderPkg.FeeHolder, - timestamp int64) (opensToPublish []*Order, closedToPublish []*Order, feeToPublish map[string]string) { + timestamp int64, miniTrades []*Trade, + miniOrderChanges orderPkg.OrderChanges, + miniOrderInfos orderPkg.OrderInfoForPublish) (opensToPublish []*Order, closedToPublish []*Order, miniOpensToPublish []*Order, miniClosedToPublish []*Order,feeToPublish map[string]string, ) { opensToPublish = make([]*Order, 0) closedToPublish = make([]*Order, 0) + miniOpensToPublish = make([]*Order, 0) + miniClosedToPublish = make([]*Order, 0) // serve as a cache to avoid fee's serialization several times for one address feeToPublish = make(map[string]string) @@ -520,43 +525,47 @@ func collectOrdersToPublish( chargedExpires := make(map[string]int) // collect orders (new, cancel, ioc-no-fill, expire, failed-blocking and failed-matching) from orderChanges - for _, o := range orderChanges { - if orderInfo := o.ResolveOrderInfo(orderInfos); orderInfo != nil { - orderToPublish := Order{ - orderInfo.Symbol, o.Tpe, o.Id, - "", orderInfo.Sender.String(), orderInfo.Side, - orderPkg.OrderType.LIMIT, orderInfo.Price, orderInfo.Quantity, - 0, 0, orderInfo.CumQty, "", - orderInfo.CreatedTimestamp, timestamp, orderInfo.TimeInForce, - orderPkg.NEW, orderInfo.TxHash, o.SingleFee, - } + opensToPublish, closedToPublish = collectOrders(orderChanges, orderInfos, timestamp, opensToPublish, closedToPublish, chargedCancels, chargedExpires) + miniOpensToPublish, miniClosedToPublish = collectOrders(miniOrderChanges, miniOrderInfos, timestamp, miniOpensToPublish, miniClosedToPublish, chargedCancels, chargedExpires) - if o.Tpe.IsOpen() { + // update C and E fields in serialized fee string + updateCancelExpireOrderNum(closedToPublish, orderInfos, feeToPublish, chargedCancels, chargedExpires, feeHolder) + updateCancelExpireOrderNum(miniClosedToPublish, miniOrderInfos, feeToPublish, chargedCancels, chargedExpires, feeHolder) + // update fee and collect orders from trades + opensToPublish, closedToPublish = convertTradesToOrders(trades, orderInfos, timestamp, feeHolder, feeToPublish, opensToPublish, closedToPublish) + miniOpensToPublish, miniClosedToPublish = convertTradesToOrders(miniTrades, miniOrderInfos, timestamp, feeHolder, feeToPublish, miniOpensToPublish, miniClosedToPublish) + + return opensToPublish, closedToPublish, miniOpensToPublish, miniClosedToPublish, feeToPublish +} + +func convertTradesToOrders(trades []*Trade, orderInfos orderPkg.OrderInfoForPublish, timestamp int64, feeHolder orderPkg.FeeHolder, feeToPublish map[string]string, opensToPublish []*Order, closedToPublish []*Order) ([]*Order, []*Order) { + for _, t := range trades { + if o, exists := orderInfos[t.Bid]; exists { + orderToPublish := tradeToOrder(t, o, timestamp, feeHolder, feeToPublish) + if orderToPublish.Status.IsOpen() { opensToPublish = append(opensToPublish, &orderToPublish) } else { closedToPublish = append(closedToPublish, &orderToPublish) } + } else { + Logger.Error("failed to resolve order information from orderInfos", "orderId", t.Bid) + } - // fee field handling - if orderToPublish.isChargedCancel() { - if _, ok := chargedCancels[string(orderInfo.Sender)]; ok { - chargedCancels[string(orderInfo.Sender)] += 1 - } else { - chargedCancels[string(orderInfo.Sender)] = 1 - } - } else if orderToPublish.isChargedExpire() { - if _, ok := chargedExpires[string(orderInfo.Sender)]; ok { - chargedExpires[string(orderInfo.Sender)] += 1 - } else { - chargedExpires[string(orderInfo.Sender)] = 1 - } + if o, exists := orderInfos[t.Sid]; exists { + orderToPublish := tradeToOrder(t, o, timestamp, feeHolder, feeToPublish) + if orderToPublish.Status.IsOpen() { + opensToPublish = append(opensToPublish, &orderToPublish) + } else { + closedToPublish = append(closedToPublish, &orderToPublish) } } else { - Logger.Error("failed to locate order change in OrderChangesMap", "orderChange", o.String()) + Logger.Error("failed to resolve order information from orderInfos", "orderId", t.Sid) } } + return opensToPublish, closedToPublish +} - // update C and E fields in serialized fee string +func updateCancelExpireOrderNum(closedToPublish []*Order, orderInfos orderPkg.OrderInfoForPublish, feeToPublish map[string]string, chargedCancels map[string]int, chargedExpires map[string]int, feeHolder orderPkg.FeeHolder) { for _, order := range closedToPublish { if orderInfo, ok := orderInfos[order.OrderId]; ok { senderBytesStr := string(orderInfo.Sender) @@ -575,33 +584,45 @@ func collectOrdersToPublish( Logger.Error("should not to locate order in OrderChangesMap", "oid", order.OrderId) } } +} - // update fee and collect orders from trades - for _, t := range trades { - if o, exists := orderInfos[t.Bid]; exists { - orderToPublish := tradeToOrder(t, o, timestamp, feeHolder, feeToPublish) - if orderToPublish.Status.IsOpen() { - opensToPublish = append(opensToPublish, &orderToPublish) - } else { - closedToPublish = append(closedToPublish, &orderToPublish) +func collectOrders(orderChanges orderPkg.OrderChanges, orderInfos orderPkg.OrderInfoForPublish, timestamp int64, opensToPublish []*Order, closedToPublish []*Order, chargedCancels map[string]int, chargedExpires map[string]int) ([]*Order, []*Order) { + for _, o := range orderChanges { + if orderInfo := o.ResolveOrderInfo(orderInfos); orderInfo != nil { + orderToPublish := Order{ + orderInfo.Symbol, o.Tpe, o.Id, + "", orderInfo.Sender.String(), orderInfo.Side, + orderPkg.OrderType.LIMIT, orderInfo.Price, orderInfo.Quantity, + 0, 0, orderInfo.CumQty, "", + orderInfo.CreatedTimestamp, timestamp, orderInfo.TimeInForce, + orderPkg.NEW, orderInfo.TxHash, o.SingleFee, } - } else { - Logger.Error("failed to resolve order information from orderInfos", "orderId", t.Bid) - } - if o, exists := orderInfos[t.Sid]; exists { - orderToPublish := tradeToOrder(t, o, timestamp, feeHolder, feeToPublish) - if orderToPublish.Status.IsOpen() { + if o.Tpe.IsOpen() { opensToPublish = append(opensToPublish, &orderToPublish) } else { closedToPublish = append(closedToPublish, &orderToPublish) } + + // fee field handling + if orderToPublish.isChargedCancel() { + if _, ok := chargedCancels[string(orderInfo.Sender)]; ok { + chargedCancels[string(orderInfo.Sender)] += 1 + } else { + chargedCancels[string(orderInfo.Sender)] = 1 + } + } else if orderToPublish.isChargedExpire() { + if _, ok := chargedExpires[string(orderInfo.Sender)]; ok { + chargedExpires[string(orderInfo.Sender)] += 1 + } else { + chargedExpires[string(orderInfo.Sender)] = 1 + } + } } else { - Logger.Error("failed to resolve order information from orderInfos", "orderId", t.Sid) + Logger.Error("failed to locate order change in OrderChangesMap", "orderChange", o.String()) } } - - return opensToPublish, closedToPublish, feeToPublish + return opensToPublish, closedToPublish } func getSerializedFeeForOrder(orderInfo *orderPkg.OrderInfo, status orderPkg.ChangeType, feeHolder orderPkg.FeeHolder, feeToPublish map[string]string) string { diff --git a/app/pub/keeper_pub_test.go b/app/pub/keeper_pub_test.go index 982661d00..ef6d0de72 100644 --- a/app/pub/keeper_pub_test.go +++ b/app/pub/keeper_pub_test.go @@ -60,7 +60,7 @@ func setupKeeperTest(t *testing.T) (*assert.Assertions, *require.Assertions) { accountCache := getAccountCache(cdc, ms, capKey) ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, logger).WithAccountCache(accountCache) - pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) + pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) keeper = orderPkg.NewKeeper(capKey2, am, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, true) tradingPair := dextypes.NewTradingPair("XYZ-000", types.NativeTokenSymbol, 1e8) keeper.PairMapper.AddTradingPair(ctx, tradingPair) @@ -120,7 +120,7 @@ func TestKeeper_IOCExpireWithFee(t *testing.T) { require.Len(keeper.OrderChanges, 1) require.Len(keeper.OrderInfosForPub, 1) - trades := MatchAndAllocateAllForPublish(keeper, ctx, false) + trades := MatchAndAllocateAllForPublish(keeper, nil, ctx, false) require.Len(keeper.OrderChanges, 2) require.Len(keeper.OrderInfosForPub, 1) @@ -206,7 +206,7 @@ func Test_IOCPartialExpire(t *testing.T) { assert.Equal("s-1", orderChange1.Id) assert.Equal(orderPkg.Ack, orderChange1.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, ctx, false) + trades := MatchAndAllocateAllForPublish(keeper, nil, ctx, false) require.Len(keeper.OrderChanges, 3) require.Len(keeper.OrderInfosForPub, 2) @@ -246,7 +246,7 @@ func Test_GTEPartialExpire(t *testing.T) { assert.Equal("s-1", orderChange1.Id) assert.Equal(orderPkg.Ack, orderChange1.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, ctx, false) + trades := MatchAndAllocateAllForPublish(keeper, nil, ctx, false) require.Len(trades, 1) trade0 := trades[0] assert.Equal("0-0", trade0.Id) @@ -297,7 +297,7 @@ func Test_OneBuyVsTwoSell(t *testing.T) { assert.Equal("s-2", orderChange2.Id) assert.Equal(orderPkg.Ack, orderChange2.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, ctx, false) + trades := MatchAndAllocateAllForPublish(keeper, nil, ctx, false) require.Len(trades, 2) trade0 := trades[0] assert.Equal("0-0", trade0.Id) diff --git a/app/pub/msgs.go b/app/pub/msgs.go index bf55031fb..d835f9ea0 100644 --- a/app/pub/msgs.go +++ b/app/pub/msgs.go @@ -55,7 +55,7 @@ func (this msgType) String() string { var latestSchemaVersions = map[msgType]int{ accountsTpe: 1, booksTpe: 0, - executionResultTpe: 1, + executionResultTpe: 2, blockFeeTpe: 0, transferTpe: 1, blockTpe: 0, @@ -98,6 +98,8 @@ type ExecutionResults struct { Orders Orders Proposals Proposals StakeUpdates StakeUpdates + miniTrades trades + miniOrders Orders } func (msg *ExecutionResults) String() string { @@ -121,13 +123,21 @@ func (msg *ExecutionResults) ToNativeMap() map[string]interface{} { if msg.StakeUpdates.NumOfMsgs > 0 { native["stakeUpdates"] = map[string]interface{}{"org.binance.dex.model.avro.StakeUpdates": msg.StakeUpdates.ToNativeMap()} } + if msg.miniTrades.NumOfMsgs > 0 { + native["miniTrades"] = map[string]interface{}{"org.binance.dex.model.avro.Trades": msg.miniTrades.ToNativeMap()} + } + if msg.miniOrders.NumOfMsgs > 0 { + native["miniOrders"] = map[string]interface{}{"org.binance.dex.model.avro.Orders": msg.miniOrders.ToNativeMap()} + } return native } func (msg *ExecutionResults) EssentialMsg() string { // mainly used to recover for large breathe block expiring message, there should be no trade on breathe block orders := msg.Orders.EssentialMsg() - return fmt.Sprintf("height:%d\ntime:%d\norders:\n%s\n", msg.Height, msg.Timestamp, orders) + miniOrders := msg.miniOrders.EssentialMsg() + //TODO output other fields: trades, stakeUpdate etc. + return fmt.Sprintf("height:%d\ntime:%d\norders:\n%s\nminiOrders:\n%s\n", msg.Height, msg.Timestamp, orders, miniOrders) } func (msg *ExecutionResults) EmptyCopy() AvroOrJsonMsg { @@ -137,15 +147,23 @@ func (msg *ExecutionResults) EmptyCopy() AvroOrJsonMsg { nonExpiredOrders = append(nonExpiredOrders, order) } } + var nonExpiredMiniOrders []*Order + for _, order := range msg.miniOrders.Orders { + if order.Status != orderPkg.Expired { + nonExpiredMiniOrders = append(nonExpiredMiniOrders, order) + } + } return &ExecutionResults{ msg.Height, msg.Timestamp, - msg.Proposals.NumOfMsgs + msg.StakeUpdates.NumOfMsgs + len(nonExpiredOrders), + msg.Proposals.NumOfMsgs + msg.StakeUpdates.NumOfMsgs + len(nonExpiredOrders) + len(nonExpiredMiniOrders), trades{}, // no trades on breathe block Orders{len(nonExpiredOrders), nonExpiredOrders}, msg.Proposals, msg.StakeUpdates, + trades{}, // no trades on breathe block + Orders{len(nonExpiredMiniOrders), nonExpiredMiniOrders}, } } diff --git a/app/pub/publisher.go b/app/pub/publisher.go index 33c6d0e6a..7afe8219c 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -23,6 +23,7 @@ var ( Cfg *config.PublicationConfig ToPublishCh chan BlockInfoToPublish ToRemoveOrderIdCh chan string // order ids to remove from keeper.OrderInfoForPublish + ToRemoveMiniOrderIdCh chan string // order ids to remove from keeper.miniOrderInfoForPublish IsLive bool ) @@ -50,22 +51,21 @@ func Publish( // they can assign buyer/seller address into trade before persist into DB var opensToPublish []*Order var closedToPublish []*Order + var miniOpensToPublish []*Order + var miniClosedToPublish []*Order var feeToPublish map[string]string if cfg.PublishOrderUpdates || cfg.PublishOrderBook { - opensToPublish, closedToPublish, feeToPublish = collectOrdersToPublish( + opensToPublish, closedToPublish, miniOpensToPublish, miniClosedToPublish, feeToPublish = collectOrdersToPublish( marketData.tradesToPublish, marketData.orderChanges, marketData.orderInfos, marketData.feeHolder, - marketData.timestamp) - for _, o := range closedToPublish { - if ToRemoveOrderIdCh != nil { - Logger.Debug( - "going to delete order from order changes map", - "orderId", o.OrderId, "status", o.Status) - ToRemoveOrderIdCh <- o.OrderId - } - } + marketData.timestamp, + marketData.miniTradesToPublish, + marketData.miniOrderChanges, + marketData.miniOrderInfos) + addClosedOrder(closedToPublish, ToRemoveOrderIdCh) + addClosedOrder(miniClosedToPublish, ToRemoveMiniOrderIdCh) } // ToRemoveOrderIdCh would be only used in production code @@ -73,8 +73,12 @@ func Publish( if ToRemoveOrderIdCh != nil { close(ToRemoveOrderIdCh) } + if ToRemoveMiniOrderIdCh != nil { + close(ToRemoveMiniOrderIdCh) + } ordersToPublish := append(opensToPublish, closedToPublish...) + miniOrdersToPublish := append(miniOpensToPublish, miniClosedToPublish...) if cfg.PublishOrderUpdates { duration := Timer(Logger, "publish all orders", func() { publishExecutionResult( @@ -84,7 +88,9 @@ func Publish( ordersToPublish, marketData.tradesToPublish, marketData.proposalsToPublish, - marketData.stakeUpdates) + marketData.stakeUpdates, + miniOrdersToPublish, + marketData.miniTradesToPublish, ) }) if metrics != nil { @@ -106,9 +112,10 @@ func Publish( } if cfg.PublishOrderBook { - var changedPrices orderPkg.ChangedPriceLevelsMap + var changedPrices = make(orderPkg.ChangedPriceLevelsMap) duration := Timer(Logger, "prepare order books to publish", func() { - changedPrices = filterChangedOrderBooksByOrders(ordersToPublish, marketData.latestPricesLevels) + filterChangedOrderBooksByOrders(ordersToPublish, marketData.latestPricesLevels, changedPrices) + filterChangedOrderBooksByOrders(miniOrdersToPublish, marketData.miniLatestPriceLevels, changedPrices) }) if metrics != nil { numOfChangedPrices := 0 @@ -172,6 +179,17 @@ func Publish( } } +func addClosedOrder(closedToPublish []*Order, toRemoveOrderIdCh chan string) { + for _, o := range closedToPublish { + if toRemoveOrderIdCh != nil { + Logger.Debug( + "going to delete order from order changes map", + "orderId", o.OrderId, "status", o.Status) + toRemoveOrderIdCh <- o.OrderId + } + } +} + func Stop(publisher MarketDataPublisher) { if IsLive == false { Logger.Error("publication module has already been stopped") @@ -184,16 +202,22 @@ func Stop(publisher MarketDataPublisher) { if ToRemoveOrderIdCh != nil { close(ToRemoveOrderIdCh) } + if ToRemoveMiniOrderIdCh != nil { + close(ToRemoveMiniOrderIdCh) + } publisher.Stop() } -func publishExecutionResult(publisher MarketDataPublisher, height int64, timestamp int64, os []*Order, tradesToPublish []*Trade, proposalsToPublish *Proposals, stakeUpdates *StakeUpdates) { +func publishExecutionResult(publisher MarketDataPublisher, height int64, timestamp int64, os []*Order, tradesToPublish []*Trade, proposalsToPublish *Proposals, stakeUpdates *StakeUpdates, + miniOrders []*Order, miniTrades []*Trade) { numOfOrders := len(os) numOfTrades := len(tradesToPublish) numOfProposals := proposalsToPublish.NumOfMsgs numOfStakeUpdatedAccounts := stakeUpdates.NumOfMsgs - executionResultsMsg := ExecutionResults{Height: height, Timestamp: timestamp, NumOfMsgs: numOfTrades + numOfOrders + numOfProposals + numOfStakeUpdatedAccounts} + numOfMiniOrders := len(miniOrders) + numOfMiniTrades := len(miniTrades) + executionResultsMsg := ExecutionResults{Height: height, Timestamp: timestamp, NumOfMsgs: numOfTrades + numOfOrders + numOfProposals + numOfStakeUpdatedAccounts + numOfMiniTrades + numOfMiniOrders } if numOfOrders > 0 { executionResultsMsg.Orders = Orders{numOfOrders, os} } @@ -206,6 +230,12 @@ func publishExecutionResult(publisher MarketDataPublisher, height int64, timesta if numOfStakeUpdatedAccounts > 0 { executionResultsMsg.StakeUpdates = *stakeUpdates } + if numOfMiniOrders > 0 { + executionResultsMsg.miniOrders = Orders{numOfOrders, miniOrders} + } + if numOfMiniTrades > 0 { + executionResultsMsg.miniTrades = trades{numOfTrades, miniTrades} + } publisher.publish(&executionResultsMsg, executionResultTpe, height, timestamp) } diff --git a/app/pub/schemas.go b/app/pub/schemas.go index 2165dcb1e..8e0d7cd78 100644 --- a/app/pub/schemas.go +++ b/app/pub/schemas.go @@ -146,6 +146,80 @@ const ( } } ] + }], "default": null }, + { "name": "miniTrades", "type": ["null", { + "type": "record", + "name": "Trades", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "numOfMsgs", "type": "int" }, + { "name": "trades", "type": { + "type": "array", + "items": + { + "type": "record", + "name": "Trade", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "symbol", "type": "string" }, + { "name": "id", "type": "string" }, + { "name": "price", "type": "long" }, + { "name": "qty", "type": "long" }, + { "name": "sid", "type": "string" }, + { "name": "bid", "type": "string" }, + { "name": "sfee", "type": "string" }, + { "name": "bfee", "type": "string" }, + { "name": "saddr", "type": "string" }, + { "name": "baddr", "type": "string" }, + { "name": "ssrc", "type": "long" }, + { "name": "bsrc", "type": "long" }, + { "name": "ssinglefee", "type": "string" }, + { "name": "bsinglefee", "type": "string" }, + { "name": "tickType", "type": "int" } + ] + } + } + } + ] + }], "default": null }, + { "name": "miniOrders", "type": ["null", { + "type": "record", + "name": "Orders", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "numOfMsgs", "type": "int" }, + { "name": "orders", "type": { + "type": "array", + "items": + { + "type": "record", + "name": "Order", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "symbol", "type": "string" }, + { "name": "status", "type": "string" }, + { "name": "orderId", "type": "string" }, + { "name": "tradeId", "type": "string" }, + { "name": "owner", "type": "string" }, + { "name": "side", "type": "int" }, + { "name": "orderType", "type": "int" }, + { "name": "price", "type": "long" }, + { "name": "qty", "type": "long" }, + { "name": "lastExecutedPrice", "type": "long" }, + { "name": "lastExecutedQty", "type": "long" }, + { "name": "cumQty", "type": "long" }, + { "name": "fee", "type": "string" }, + { "name": "orderCreationTime", "type": "long" }, + { "name": "transactionTime", "type": "long" }, + { "name": "timeInForce", "type": "int" }, + { "name": "currentExecutionType", "type": "string" }, + { "name": "txHash", "type": "string" }, + { "name": "singlefee", "type": "string" } + ] + } + } + } + ] }], "default": null } ] } diff --git a/app/pub/schemas/executionResults1.avsc b/app/pub/schemas/executionResults1.avsc new file mode 100644 index 000000000..6739f1b0c --- /dev/null +++ b/app/pub/schemas/executionResults1.avsc @@ -0,0 +1,138 @@ +{ + "type": "record", + "name": "ExecutionResults", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "height", "type": "long" }, + { "name": "timestamp", "type": "long" }, + { "name": "numOfMsgs", "type": "int" }, + { "name": "trades", "type": ["null", { + "type": "record", + "name": "Trades", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "numOfMsgs", "type": "int" }, + { "name": "trades", "type": { + "type": "array", + "items": + { + "type": "record", + "name": "Trade", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "symbol", "type": "string" }, + { "name": "id", "type": "string" }, + { "name": "price", "type": "long" }, + { "name": "qty", "type": "long" }, + { "name": "sid", "type": "string" }, + { "name": "bid", "type": "string" }, + { "name": "sfee", "type": "string" }, + { "name": "bfee", "type": "string" }, + { "name": "saddr", "type": "string" }, + { "name": "baddr", "type": "string" }, + { "name": "ssrc", "type": "long" , "default": 0}, + { "name": "bsrc", "type": "long" , "default": 0}, + { "name": "ssinglefee", "type": "string", "default": "null"}, + { "name": "bsinglefee", "type": "string" , "default": "null"}, + { "name": "tickType", "type": "int" , "default": 0} + ] + } + } + } + ] + }], "default": null }, + { "name": "orders", "type": ["null", { + "type": "record", + "name": "Orders", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "numOfMsgs", "type": "int" }, + { "name": "orders", "type": { + "type": "array", + "items": + { + "type": "record", + "name": "Order", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "symbol", "type": "string" }, + { "name": "status", "type": "string" }, + { "name": "orderId", "type": "string" }, + { "name": "tradeId", "type": "string" }, + { "name": "owner", "type": "string" }, + { "name": "side", "type": "int" }, + { "name": "orderType", "type": "int" }, + { "name": "price", "type": "long" }, + { "name": "qty", "type": "long" }, + { "name": "lastExecutedPrice", "type": "long" }, + { "name": "lastExecutedQty", "type": "long" }, + { "name": "cumQty", "type": "long" }, + { "name": "fee", "type": "string" }, + { "name": "orderCreationTime", "type": "long" }, + { "name": "transactionTime", "type": "long" }, + { "name": "timeInForce", "type": "int" }, + { "name": "currentExecutionType", "type": "string" }, + { "name": "txHash", "type": "string" }, + { "name": "singlefee", "type": "string", "default": "null" } + ] + } + } + } + ] + }], "default": null }, + { "name": "proposals", "type": ["null", { + "type": "record", + "name": "Proposals", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "numOfMsgs", "type": "int" }, + { "name": "proposals", "type": { + "type": "array", + "items": + { + "type": "record", + "name": "Proposal", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "id", "type": "long" }, + { "name": "status", "type": "string" } + ] + } + } + } + ] + }], "default": null }, + { "name": "stakeUpdates", "type": ["null", { + "type": "record", + "name": "StakeUpdates", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "numOfMsgs", "type": "int" }, + { "name": "completedUnbondingDelegations", "type": { + "type": "array", + "items": + { + "type": "record", + "name": "CompletedUnbondingDelegation", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "validator", "type": "string" }, + { "name": "delegator", "type": "string" }, + { "name": "amount", "type": { + "type": "record", + "name": "Coin", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "denom", "type": "string" }, + { "name": "amount", "type": "long" } + ] + } + } + ] + } + } + } + ] + }], "default": null } + ] +} \ No newline at end of file diff --git a/app/pub/types.go b/app/pub/types.go index cec82935e..2af819c2f 100644 --- a/app/pub/types.go +++ b/app/pub/types.go @@ -6,31 +6,39 @@ import ( // intermediate data structures to deal with concurrent publication between main thread and publisher thread type BlockInfoToPublish struct { - height int64 - timestamp int64 - tradesToPublish []*Trade - proposalsToPublish *Proposals - stakeUpdates *StakeUpdates - orderChanges orderPkg.OrderChanges - orderInfos orderPkg.OrderInfoForPublish - accounts map[string]Account - latestPricesLevels orderPkg.ChangedPriceLevelsMap - blockFee BlockFee - feeHolder orderPkg.FeeHolder - transfers *Transfers - block *Block + height int64 + timestamp int64 + tradesToPublish []*Trade + proposalsToPublish *Proposals + stakeUpdates *StakeUpdates + orderChanges orderPkg.OrderChanges + orderInfos orderPkg.OrderInfoForPublish + accounts map[string]Account + latestPricesLevels orderPkg.ChangedPriceLevelsMap + miniLatestPriceLevels orderPkg.ChangedPriceLevelsMap + blockFee BlockFee + feeHolder orderPkg.FeeHolder + transfers *Transfers + block *Block + miniTradesToPublish []*Trade + miniOrderChanges orderPkg.OrderChanges + miniOrderInfos orderPkg.OrderInfoForPublish } func NewBlockInfoToPublish( height int64, timestamp int64, tradesToPublish []*Trade, + miniTradesToPublish []*Trade, proposalsToPublish *Proposals, stakeUpdates *StakeUpdates, orderChanges orderPkg.OrderChanges, + miniOrderChanges orderPkg.OrderChanges, orderInfos orderPkg.OrderInfoForPublish, + miniOrderInfos orderPkg.OrderInfoForPublish, accounts map[string]Account, latestPriceLevels orderPkg.ChangedPriceLevelsMap, + miniLatestPriceLevels orderPkg.ChangedPriceLevelsMap, blockFee BlockFee, feeHolder orderPkg.FeeHolder, transfers *Transfers, block *Block) BlockInfoToPublish { return BlockInfoToPublish{ @@ -43,8 +51,13 @@ func NewBlockInfoToPublish( orderInfos, accounts, latestPriceLevels, + miniLatestPriceLevels, blockFee, feeHolder, transfers, - block} + block, + miniTradesToPublish, + miniOrderChanges, + miniOrderInfos, + } } diff --git a/cmd/pressuremaker/utils/utils.go b/cmd/pressuremaker/utils/utils.go index a35b71358..ddd7f0b65 100644 --- a/cmd/pressuremaker/utils/utils.go +++ b/cmd/pressuremaker/utils/utils.go @@ -148,12 +148,16 @@ func (mg MessageGenerator) Publish(height, timePub int64, tradesToPublish []*pub height, timePub, tradesToPublish, + nil, new(pub.Proposals), new(pub.StakeUpdates), orderChanges, + nil, orderChangesCopy, + nil, accounts, nil, + nil, pub.BlockFee{}, nil, transfers, diff --git a/common/stores.go b/common/stores.go index 693b6023c..0e1f005f7 100644 --- a/common/stores.go +++ b/common/stores.go @@ -3,18 +3,20 @@ package common import sdk "github.com/cosmos/cosmos-sdk/types" const ( - MainStoreName = "main" - AccountStoreName = "acc" - ValAddrStoreName = "val" - TokenStoreName = "tokens" - MiniTokenStoreName = "minitokens" - DexStoreName = "dex" - PairStoreName = "pairs" - StakeStoreName = "stake" - ParamsStoreName = "params" - GovStoreName = "gov" - TimeLockStoreName = "time_lock" - AtomicSwapStoreName = "atomic_swap" + MainStoreName = "main" + AccountStoreName = "acc" + ValAddrStoreName = "val" + TokenStoreName = "tokens" + MiniTokenStoreName = "minitokens" + DexStoreName = "dex" + DexMiniStoreName = "dex_mini" + PairStoreName = "pairs" + MiniTokenPairStoreName = "mini_pairs" + StakeStoreName = "stake" + ParamsStoreName = "params" + GovStoreName = "gov" + TimeLockStoreName = "time_lock" + AtomicSwapStoreName = "atomic_swap" StakeTransientStoreName = "transient_stake" ParamsTransientStoreName = "transient_params" @@ -27,6 +29,7 @@ var ( ValAddrStoreKey = sdk.NewKVStoreKey(ValAddrStoreName) TokenStoreKey = sdk.NewKVStoreKey(TokenStoreName) DexStoreKey = sdk.NewKVStoreKey(DexStoreName) + DexMiniStoreKey = sdk.NewKVStoreKey(DexMiniStoreName) PairStoreKey = sdk.NewKVStoreKey(PairStoreName) StakeStoreKey = sdk.NewKVStoreKey(StakeStoreName) ParamsStoreKey = sdk.NewKVStoreKey(ParamsStoreName) @@ -37,7 +40,8 @@ var ( TStakeStoreKey = sdk.NewTransientStoreKey(StakeTransientStoreName) TParamsStoreKey = sdk.NewTransientStoreKey(ParamsTransientStoreName) - MiniTokenStoreKey = sdk.NewKVStoreKey(MiniTokenStoreName) + MiniTokenStoreKey = sdk.NewKVStoreKey(MiniTokenStoreName) + MiniTokenPairStoreKey = sdk.NewKVStoreKey(MiniTokenPairStoreName) StoreKeyNameMap = map[string]sdk.StoreKey{ MainStoreName: MainStoreKey, @@ -45,6 +49,7 @@ var ( ValAddrStoreName: ValAddrStoreKey, TokenStoreName: TokenStoreKey, DexStoreName: DexStoreKey, + DexMiniStoreName: DexMiniStoreKey, PairStoreName: PairStoreKey, StakeStoreName: StakeStoreKey, ParamsStoreName: ParamsStoreKey, @@ -62,6 +67,7 @@ var ( ValAddrStoreName, TokenStoreName, DexStoreName, + DexMiniStoreName, PairStoreName, StakeStoreName, ParamsStoreName, diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 3ea810307..5546f8531 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -20,7 +20,7 @@ const ( MiniTokenSymbolMSuffix = "M" MiniTokenDecimals int8 = 8 - MiniTokenMinTotalSupply int64 = 100000000 // 100k with 8 decimal digits + MiniTokenMinTotalSupply int64 = 100000000 // 1 with 8 decimal digits MiniTokenMaxTotalSupplyUpperBound int64 = 10000000000000 // 100k with 8 decimal digits MiniTokenSupplyRange1UpperBound int64 = 1000000000000 @@ -131,7 +131,7 @@ func ValidateMapperMiniTokenSymbol(symbol string) error { return fmt.Errorf("mini-token symbol suffix must be %d chars in length, got %d", MiniTokenSymbolSuffixLen, len(suffixPart)) } - if suffixPart[len(suffixPart)-1:] != "M" { + if suffixPart[len(suffixPart)-1:] != MiniTokenSymbolMSuffix { return fmt.Errorf("mini-token symbol suffix must end with M") } diff --git a/networks/tools/snapshot_viewer/snapshot.go b/networks/tools/snapshot_viewer/snapshot.go index fbda70251..5a3e24054 100644 --- a/networks/tools/snapshot_viewer/snapshot.go +++ b/networks/tools/snapshot_viewer/snapshot.go @@ -45,7 +45,7 @@ func openAppDB(root string) *db.GoLevelDB { func prepareCms(root string, appDB *db.GoLevelDB) sdk.CommitMultiStore { keys := []store.StoreKey{ - common.MainStoreKey, common.TokenStoreKey, common.DexStoreKey, + common.MainStoreKey, common.TokenStoreKey, common.DexStoreKey, common.DexMiniStoreKey, common.PairStoreKey, common.GovStoreKey, common.StakeStoreKey, common.ParamsStoreKey, common.ValAddrStoreKey, common.AccountStoreKey, common.MiniTokenStoreKey} diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index 1c0bff943..f09b9c0db 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -11,8 +11,11 @@ import ( type TradingPairMapper = store.TradingPairMapper type DexKeeper = order.Keeper +type DexMiniTokenKeeper = order.MiniKeeper +type DexOrderKeeper = order.DexOrderKeeper var NewTradingPairMapper = store.NewTradingPairMapper var NewOrderKeeper = order.NewKeeper +var NewMiniKeeper = order.NewMiniKeeper const DefaultCodespace = types.DefaultCodespace diff --git a/plugins/dex/list/handler_test.go b/plugins/dex/list/handler_test.go index e161fa56d..d4107ba18 100644 --- a/plugins/dex/list/handler_test.go +++ b/plugins/dex/list/handler_test.go @@ -64,7 +64,7 @@ func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, orderKeeper *o accKeeper := auth.NewAccountKeeper(cdc, accKey, types.ProtoAppAccount) codespacer := sdk.NewCodespacer() - pairMapper := store.NewTradingPairMapper(cdc, pairKey) + pairMapper := store.NewTradingPairMapper(cdc, pairKey, false) orderKeeper = order.NewKeeper(common.DexStoreKey, accKeeper, pairMapper, codespacer.RegisterNext(dexTypes.DefaultCodespace), 2, cdc, false) diff --git a/plugins/dex/listmini/handler.go b/plugins/dex/listmini/handler.go index 47c6f3390..bb7bf35d8 100644 --- a/plugins/dex/listmini/handler.go +++ b/plugins/dex/listmini/handler.go @@ -5,7 +5,6 @@ import ( "reflect" "github.com/binance-chain/node/common/log" - common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/types" @@ -16,11 +15,11 @@ import ( ) // NewHandler initialises dex message handlers -func NewHandler(keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper) sdk.Handler { +func NewHandler(miniKeeper *order.MiniKeeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case ListMiniMsg: - return handleList(ctx, keeper, miniTokenMapper, tokenMapper, msg) + return handleList(ctx, miniKeeper, miniTokenMapper, tokenMapper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -28,14 +27,13 @@ func NewHandler(keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper } } -func handleList(ctx sdk.Context, keeper *order.Keeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper, +func handleList(ctx sdk.Context, miniKeeper *order.MiniKeeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper, msg ListMiniMsg) sdk.Result { if !sdk.IsUpgrade(upgrade.BEP8) { - return sdk.ErrInternal(fmt.Sprint("list miniToken is not supported at current height")).Result() + return sdk.ErrInternal(fmt.Sprint("list mini-token is not supported at current height")).Result() } - if err := keeper.CanListTradingPair(ctx, msg.BaseAssetSymbol, msg.QuoteAssetSymbol); err != nil { - //TODO use miniTradingPair + if err := miniKeeper.CanListTradingPair(ctx, msg.BaseAssetSymbol, msg.QuoteAssetSymbol); err != nil { return sdk.ErrInvalidCoins(err.Error()).Result() } @@ -57,25 +55,21 @@ func handleList(ctx sdk.Context, keeper *order.Keeper, miniTokenMapper minitoken return sdk.ErrInvalidCoins("quote token does not exist").Result() } - if common.NativeTokenSymbol != msg.QuoteAssetSymbol { //todo permit BUSD - return sdk.ErrInvalidCoins("quote token: " + err.Error()).Result() - } - var lotSize int64 if sdk.IsUpgrade(upgrade.LotSizeOptimization) { - lotSize = keeper.DetermineLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice) + lotSize = miniKeeper.DetermineLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice) } else { lotSize = utils.CalcLotSize(msg.InitPrice) } pair := types.NewTradingPairWithLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice, lotSize) - err = keeper.PairMapper.AddTradingPair(ctx, pair) + err = miniKeeper.PairMapper.AddTradingPair(ctx, pair) if err != nil { return sdk.ErrInternal(err.Error()).Result() } // this is done in memory! we must not run this block in checktx or simulate! if ctx.IsDeliverTx() { // only add engine during DeliverTx - keeper.AddEngine(pair) + miniKeeper.AddEngine(pair) log.With("module", "dex").Info("List new mini-token Pair and created new match engine", "pair", pair) } diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index 25f76f2a8..ccb4a3b2a 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -15,7 +15,6 @@ import ( common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" me "github.com/binance-chain/node/plugins/dex/matcheng" - "github.com/binance-chain/node/plugins/dex/store" "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/wire" @@ -26,13 +25,15 @@ type NewOrderResponse struct { } // NewHandler - returns a handler for dex type messages. -func NewHandler(cdc *wire.Codec, k *Keeper, accKeeper auth.AccountKeeper) sdk.Handler { +func NewHandler(cdc *wire.Codec, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, accKeeper auth.AccountKeeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case NewOrderMsg: - return handleNewOrder(ctx, cdc, k, msg) + orderKeeper, _ := selectKeeper(msg, dexKeeper, dexMiniKeeper) + return handleNewOrder(ctx, cdc, orderKeeper, msg) case CancelOrderMsg: - return handleCancelOrder(ctx, k, msg) + orderKeeper, _ := selectKeeper(msg, dexKeeper, dexMiniKeeper) + return handleCancelOrder(ctx, orderKeeper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -40,59 +41,27 @@ func NewHandler(cdc *wire.Codec, k *Keeper, accKeeper auth.AccountKeeper) sdk.Ha } } -func validateOrder(ctx sdk.Context, pairMapper store.TradingPairMapper, acc sdk.Account, msg NewOrderMsg) error { - baseAsset, quoteAsset, err := utils.TradingPair2Assets(msg.Symbol) - if err != nil { - return err - } - - seq := acc.GetSequence() - expectedID := GenerateOrderID(seq, msg.Sender) - if expectedID != msg.Id { - return fmt.Errorf("the order ID(%s) given did not match the expected one: `%s`", msg.Id, expectedID) - } - - pair, err := pairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) - if err != nil { - return err - } - - if msg.Quantity <= 0 || msg.Quantity%pair.LotSize.ToInt64() != 0 { - return fmt.Errorf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()) - } - - if msg.Price <= 0 || msg.Price%pair.TickSize.ToInt64() != 0 { - return fmt.Errorf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()) - } - - if sdk.IsUpgrade(upgrade.LotSizeOptimization) { - if utils.IsUnderMinNotional(msg.Price, msg.Quantity) { - return errors.New("notional value of the order is too small") - } - } - - if utils.IsExceedMaxNotional(msg.Price, msg.Quantity) { - return errors.New("notional value of the order is too large(cannot fit in int64)") +func selectKeeper(msg sdk.Msg, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper) (DexOrderKeeper, error) { + var orderKeeper DexOrderKeeper + var symbol string + switch v := msg.(type) { + case NewOrderMsg: + symbol = strings.ToUpper(v.Symbol) + case CancelOrderMsg: + symbol = strings.ToUpper(v.Symbol) + default: + err := fmt.Errorf("unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) + return nil, err + } + if (!sdk.IsUpgrade(upgrade.BEP8)) || !utils.IsMiniTokenTradingPair(symbol) { + orderKeeper = dexKeeper + } else { + orderKeeper = dexMiniKeeper } - - return nil + return orderKeeper, nil } -func validatorMiniTokenOrder(ctx sdk.Context, pairMapper store.TradingPairMapper, acc sdk.Account, msg NewOrderMsg) error{ - - //coins := acc.GetCoins() - // - //useAllBalance := coins.AmountOf(symbol) == burnAmount - // - //if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { - // logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") - // return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", - // common.MiniTokenMinTotalSupply)).Result() - //} - return nil -} - -func validateQtyAndLockBalance(ctx sdk.Context, keeper *Keeper, acc common.NamedAccount, msg NewOrderMsg) error { +func validateQtyAndLockBalance(ctx sdk.Context, keeper DexOrderKeeper, acc common.NamedAccount, msg NewOrderMsg) error { symbol := strings.ToUpper(msg.Symbol) baseAssetSymbol, quoteAssetSymbol := utils.TradingPair2AssetsSafe(symbol) notional := utils.CalBigNotionalInt64(msg.Price, msg.Quantity) @@ -135,12 +104,12 @@ func validateQtyAndLockBalance(ctx sdk.Context, keeper *Keeper, acc common.Named acc.SetCoins(freeBalance.Minus(toLockCoins)) acc.SetLockedCoins(acc.GetLockedCoins().Plus(toLockCoins)) - keeper.am.SetAccount(ctx, acc) + keeper.getAccountKeeper().SetAccount(ctx, acc) return nil } func handleNewOrder( - ctx sdk.Context, cdc *wire.Codec, keeper *Keeper, msg NewOrderMsg, + ctx sdk.Context, cdc *wire.Codec, keeper DexOrderKeeper, msg NewOrderMsg, ) sdk.Result { // TODO: the below is mostly copied from FreezeToken. It should be rewritten once "locked" becomes a field on account // this check costs least. @@ -149,7 +118,7 @@ func handleNewOrder( return sdk.NewError(types.DefaultCodespace, types.CodeDuplicatedOrder, errString).Result() } - acc := keeper.am.GetAccount(ctx, msg.Sender).(common.NamedAccount) + acc := keeper.getAccountKeeper().GetAccount(ctx, msg.Sender).(common.NamedAccount) if !ctx.IsReCheckTx() { //for recheck: // 1. sequence is verified in anteHandler @@ -157,15 +126,8 @@ func handleNewOrder( // 3. trading pair is verified // 4. price/qty may have odd tick size/lot size, but it can be handled as // other existing orders. - var err error - if utils.IsMiniTokenTradingPair(msg.Symbol) { - //FIXMe .. use different keeper - - err = validatorMiniTokenOrder(ctx, keeper.PairMapper, acc, msg) + err := keeper.validateOrder(ctx, acc, msg) - } else{ - err = validateOrder(ctx, keeper.PairMapper, acc, msg) - } if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeInvalidOrderParam, err.Error()).Result() } @@ -190,7 +152,7 @@ func handleNewOrder( if txSrc, ok := ctx.Value(baseapp.TxSourceKey).(int64); ok { txSource = txSrc } else { - keeper.logger.Error("cannot get txSource from ctx") + keeper.getLogger().Error("cannot get txSource from ctx") } }) msg := OrderInfo{ @@ -198,7 +160,9 @@ func handleNewOrder( height, timestamp, height, timestamp, 0, txHash, txSource} + err := keeper.AddOrder(msg, false) + if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeFailInsertOrder, err.Error()).Result() } @@ -222,7 +186,7 @@ func handleNewOrder( // Handle CancelOffer - func handleCancelOrder( - ctx sdk.Context, keeper *Keeper, msg CancelOrderMsg, + ctx sdk.Context, keeper DexOrderKeeper, msg CancelOrderMsg, ) sdk.Result { origOrd, ok := keeper.OrderExists(msg.Symbol, msg.RefId) @@ -249,10 +213,10 @@ func handleCancelOrder( } fee := common.Fee{} if !transfer.FeeFree() { - acc := keeper.am.GetAccount(ctx, msg.Sender) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), transfer.eventType, transfer.inAsset, keeper.engines) + acc := keeper.getAccountKeeper().GetAccount(ctx, msg.Sender) + fee = keeper.getFeeManager().CalcFixedFee(acc.GetCoins(), transfer.eventType, transfer.inAsset, keeper.getEngines()) acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - keeper.am.SetAccount(ctx, acc) + keeper.getAccountKeeper().SetAccount(ctx, acc) } // this is done in memory! we must not run this block in checktx or simulate! @@ -265,9 +229,9 @@ func handleCancelOrder( } //remove order from cache and order book err := keeper.RemoveOrder(origOrd.Id, origOrd.Symbol, func(ord me.OrderPart) { - if keeper.CollectOrderInfoForPublish { + if keeper.ShouldPublishOrder() { change := OrderChange{msg.RefId, Canceled, fee.String(), nil} - keeper.OrderChanges = append(keeper.OrderChanges, change) + keeper.UpdateOrderChange(change) keeper.updateRoundOrderFee(string(msg.Sender), fee) } }) diff --git a/plugins/dex/order/handler_test.go b/plugins/dex/order/handler_test.go index f64935567..d81703204 100644 --- a/plugins/dex/order/handler_test.go +++ b/plugins/dex/order/handler_test.go @@ -35,7 +35,7 @@ func setupMappers() (store.TradingPairMapper, auth.AccountKeeper, sdk.Context) { var cdc = wire.NewCodec() auth.RegisterBaseAccount(cdc) cdc.RegisterConcrete(types.TradingPair{}, "dex/TradingPair", nil) - pairMapper := store.NewTradingPairMapper(cdc, key) + pairMapper := store.NewTradingPairMapper(cdc, key, false) accMapper := auth.NewAccountKeeper(cdc, key2, auth.ProtoBaseAccount) accountCache := getAccountCache(cdc, ms, key2) ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 181c1f77d..d6e6ac950 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -3,7 +3,6 @@ package order import ( "errors" "fmt" - "hash/crc32" "math" "strings" "sync" @@ -31,16 +30,65 @@ import ( ) const ( - numPricesStored = 2000 - pricesStoreEvery = 1000 - minimalNumPrices = 500 - defaultMiniBlockMatchInterval = 16 - defaultActiveMiniSymbolCount = 8 + numPricesStored = 2000 + pricesStoreEvery = 1000 + minimalNumPrices = 500 ) type FeeHandler func(map[string]*types.Fee) type TransferHandler func(Transfer) +type DexOrderKeeper interface { + Init(ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) + InitRecentPrices(ctx sdk.Context) + AddEngine(pair dexTypes.TradingPair) *me.MatchEng + UpdateTickSizeAndLotSize(ctx sdk.Context) + DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) + UpdateLotSize(symbol string, lotSize int64) + AddOrder(info OrderInfo, isRecovery bool) (err error) + RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) + GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) + OrderExists(symbol, id string) (OrderInfo, bool) + SubscribeParamChange(hub *paramhub.Keeper) + GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel + GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder + GetOrderBooks(maxLevels int) ChangedPriceLevelsMap + GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel + GetLastTrades(height int64, pair string) ([]me.Trade, int64) + GetLastTradesForPair(pair string) ([]me.Trade, int64) + ClearOrderBook(pair string) + ClearOrderChanges() + StoreTradePrices(ctx sdk.Context) + MatchAll(height, timestamp int64) + MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) + ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) + MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) + GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) + GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 + ClearRoundFee() + ClearOrders() + DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) + CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error + CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error + SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) + LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) + ReplayOrdersFromBlock(ctx sdk.Context, bc *tmstore.BlockStore, stateDb dbm.DB, lastHeight, breatheHeight int64, + txDecoder sdk.TxDecoder) error + GetPairMapper() store.TradingPairMapper + GetOrderChanges() OrderChanges + GetOrderInfosForPub() OrderInfoForPublish + getAccountKeeper() *auth.AccountKeeper + getLogger() tmlog.Logger + getFeeManager() *FeeManager + getEngines() map[string]*me.MatchEng + ShouldPublishOrder() bool + doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error + updateRoundOrderFee(addr string, fee types.Fee) + UpdateOrderChange(change OrderChange) + validateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error +} + +var _ DexOrderKeeper = &Keeper{} // in the future, this may be distributed via Sharding type Keeper struct { PairMapper store.TradingPairMapper @@ -55,12 +103,8 @@ type Keeper struct { OrderInfosForPub OrderInfoForPublish // for publication usage roundOrders map[string][]string // limit to the total tx number in a block roundIOCOrders map[string][]string - roundOrdersMini map[string][]string // round orders for mini token which could be kept for several blocks - roundIOCOrdersMini map[string][]string - matchedMiniSymbols []string //mini token pairs matched in this round - miniSymbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin - RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee - poolSize uint // number of concurrent channels, counted in the pow of 2 + RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee + poolSize uint // number of concurrent channels, counted in the pow of 2 cdc *wire.Codec FeeManager *FeeManager CollectOrderInfoForPublish bool @@ -88,10 +132,6 @@ func NewKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store. OrderInfosForPub: make(OrderInfoForPublish), roundOrders: make(map[string][]string, 256), roundIOCOrders: make(map[string][]string, 256), - roundOrdersMini: make(map[string][]string, 256), - roundIOCOrdersMini: make(map[string][]string, 256), - matchedMiniSymbols: make([]string, 0, 256), - miniSymbolsHash: make(map[string]uint32, 256), RoundOrderFees: make(map[string]*types.Fee, 256), poolSize: concurrency, cdc: cdc, @@ -112,12 +152,6 @@ func (kp *Keeper) InitRecentPrices(ctx sdk.Context) { func (kp *Keeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { symbol := strings.ToUpper(pair.GetSymbol()) - if sdk.IsUpgrade(upgrade.BEP8) { - baseSymbol := strings.ToUpper(pair.BaseAssetSymbol) - if types.IsMiniTokenSymbol(baseSymbol) { - kp.miniSymbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) - } - } eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) kp.engines[symbol] = eng kp.allOrders[symbol] = map[string]*OrderInfo{} @@ -225,17 +259,13 @@ func (kp *Keeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { } kp.allOrders[symbol][info.Id] = &info + kp.addRoundOrders(symbol, info) - if (!sdk.IsUpgrade(upgrade.BEP8)) || !dexUtils.IsMiniTokenTradingPair(symbol) { - kp.addBEP2RoundOrders(symbol, info) - } else { - kp.addMiniRoundOrders(symbol, info) - } kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) return nil } -func (kp *Keeper) addBEP2RoundOrders(symbol string, info OrderInfo) { +func (kp *Keeper) addRoundOrders(symbol string, info OrderInfo) { if ids, ok := kp.roundOrders[symbol]; ok { kp.roundOrders[symbol] = append(ids, info.Id) } else { @@ -247,18 +277,6 @@ func (kp *Keeper) addBEP2RoundOrders(symbol string, info OrderInfo) { } } -func (kp *Keeper) addMiniRoundOrders(symbol string, info OrderInfo) { - if ids, ok := kp.roundOrdersMini[symbol]; ok { - kp.roundOrdersMini[symbol] = append(ids, info.Id) - } else { - newIds := make([]string, 0, 16) - kp.roundOrdersMini[symbol] = append(newIds, info.Id) - } - if info.TimeInForce == TimeInForce.IOC { - kp.roundIOCOrdersMini[symbol] = append(kp.roundIOCOrdersMini[symbol], info.Id) - } -} - func orderNotFound(symbol, id string) error { return fmt.Errorf("Failed to find order [%v] on symbol [%v]", id, symbol) } @@ -379,9 +397,6 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times } var iocIDs []string iocIDs = kp.roundIOCOrders[symbol] - if sdk.IsUpgrade(upgrade.BEP8) && len(iocIDs) == 0 { - iocIDs = kp.roundIOCOrdersMini[symbol] - } for _, id := range iocIDs { if msg, ok := orders[id]; ok { delete(orders, id) @@ -444,7 +459,7 @@ func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { } // please note if distributeTrade this method will work in async mode, otherwise in sync mode. -func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64, matchAllMiniSymbols bool) ([]chan Transfer) { +func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64) ([]chan Transfer) { size := len(kp.roundOrders) // size is the number of pairs that have new orders, i.e. it should call match() if size == 0 { @@ -455,29 +470,11 @@ func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timesta concurrency := 1 << kp.poolSize tradeOuts := make([]chan Transfer, concurrency) - if sdk.IsUpgrade(upgrade.BEP8) { - if matchAllMiniSymbols { - for symbol := range kp.roundOrdersMini { - kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) - } - } else { - kp.selectMiniSymbolsToMatch(height, func(miniSymbols map[string]struct{}) { - for symbol := range miniSymbols { - kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) - } - }) - } - } if distributeTrade { ordNum := 0 for _, perSymbol := range kp.roundOrders { ordNum += len(perSymbol) } - if sdk.IsUpgrade(upgrade.BEP8) { - for _, symbol := range kp.matchedMiniSymbols { - ordNum += len(kp.roundOrdersMini[symbol]) - } - } for i := range tradeOuts { //assume every new order would have 2 trades and generate 4 transfer tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) @@ -489,11 +486,6 @@ func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timesta for symbol := range kp.roundOrders { symbolCh <- symbol } - if sdk.IsUpgrade(upgrade.BEP8) { - for _, symbol := range kp.matchedMiniSymbols { - symbolCh <- symbol - } - } close(symbolCh) } matchWorker := func() { @@ -644,11 +636,6 @@ func (kp *Keeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { func (kp *Keeper) clearAfterMatch() { kp.roundOrders = make(map[string][]string, 256) kp.roundIOCOrders = make(map[string][]string, 256) - for _, symbol := range kp.matchedMiniSymbols { - delete(kp.roundOrdersMini, symbol) - delete(kp.roundIOCOrdersMini, symbol) - } - kp.matchedMiniSymbols = make([]string, 0, 256) } func (kp *Keeper) StoreTradePrices(ctx sdk.Context) { @@ -860,7 +847,7 @@ func (kp *Keeper) allocateAndCalcFee( // MatchAll will only concurrently match but do not allocate into accounts func (kp *Keeper) MatchAll(height, timestamp int64) { - tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp, false) //only match + tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp) //only match if tradeOuts == nil { kp.logger.Info("No order comes in for the block") } @@ -870,10 +857,10 @@ func (kp *Keeper) MatchAll(height, timestamp int64) { // MatchAndAllocateAll() is concurrently matching and allocating across // all the symbols' order books, among all the clients // Return whether match has been done in this height -func (kp *Keeper) MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllMiniSymbols bool) { +func (kp *Keeper) MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(kp.roundOrders)) timestamp := ctx.BlockHeader().Time.UnixNano() - tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp, matchAllMiniSymbols) + tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp) if tradeOuts == nil { kp.logger.Info("No order comes in for the block") } @@ -1039,9 +1026,6 @@ func (kp *Keeper) ClearOrders() { kp.allOrders = make(map[string]map[string]*OrderInfo, 256) kp.roundOrders = make(map[string][]string, 256) kp.roundIOCOrders = make(map[string][]string, 256) - kp.roundOrdersMini = make(map[string][]string, 256) - kp.roundIOCOrdersMini = make(map[string][]string, 256) - kp.matchedMiniSymbols = make([]string, 0, 256) kp.OrderInfosForPub = make(OrderInfoForPublish) } @@ -1177,32 +1161,76 @@ func (kp *Keeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset st return nil } -func (kp *Keeper) selectMiniSymbolsToMatch(height int64, postSelect func(map[string]struct{})) { - symbolsToMatch := make(map[string]struct{}, 256) - selectActiveMiniSymbols(&symbolsToMatch, &kp.roundOrdersMini, defaultActiveMiniSymbolCount) - selectMiniSymbolsRoundRobin(&symbolsToMatch, &kp.miniSymbolsHash, height) - postSelect(symbolsToMatch) +func (kp *Keeper) GetPairMapper() store.TradingPairMapper { + return kp.PairMapper } -func selectActiveMiniSymbols(symbolsToMatch *map[string]struct{}, roundOrdersMini *map[string][]string, k int) { - //use quick select to select top k symbols - symbolOrderNumsSlice := make([]*SymbolWithOrderNumber, 0, len(*roundOrdersMini)) - i:=0 - for symbol, orders := range *roundOrdersMini { - symbolOrderNumsSlice[i] = &SymbolWithOrderNumber{symbol,len(orders)} +func (kp *Keeper) GetOrderChanges() OrderChanges { + return kp.OrderChanges +} + +func (kp *Keeper) GetOrderInfosForPub() OrderInfoForPublish { + return kp.OrderInfosForPub +} + +func (kp *Keeper) getAccountKeeper() *auth.AccountKeeper { + return &kp.am +} + +func (kp *Keeper) getLogger() tmlog.Logger { + return kp.logger +} + +func (kp *Keeper) getFeeManager() *FeeManager { + return kp.FeeManager +} + +func (kp *Keeper) ShouldPublishOrder() bool { + return kp.CollectOrderInfoForPublish +} + +func (kp *Keeper) getEngines() map[string]*me.MatchEng { + return kp.engines +} + +func (kp *Keeper) UpdateOrderChange(change OrderChange) { + kp.OrderChanges = append(kp.OrderChanges, change) +} + +func (kp *Keeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { + baseAsset, quoteAsset, err := dexUtils.TradingPair2Assets(msg.Symbol) + if err != nil { + return err } - topKSymbolOrderNums := findTopKLargest(symbolOrderNumsSlice, k) - for _, selected := range topKSymbolOrderNums{ - (*symbolsToMatch)[selected.symbol] = struct{}{} + seq := acc.GetSequence() + expectedID := GenerateOrderID(seq, msg.Sender) + if expectedID != msg.Id { + return fmt.Errorf("the order ID(%s) given did not match the expected one: `%s`", msg.Id, expectedID) + } + + pair, err := kp.PairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) + if err != nil { + return err + } + + if msg.Quantity <= 0 || msg.Quantity%pair.LotSize.ToInt64() != 0 { + return fmt.Errorf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()) + } + + if msg.Price <= 0 || msg.Price%pair.TickSize.ToInt64() != 0 { + return fmt.Errorf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()) } -} -func selectMiniSymbolsRoundRobin(symbolsToMatch *map[string]struct{}, miniSymbolsHash *map[string]uint32, height int64) { - m := height % defaultMiniBlockMatchInterval - for symbol, symbolHash := range *miniSymbolsHash { - if int64(symbolHash%defaultMiniBlockMatchInterval) == m { - (*symbolsToMatch)[symbol] = struct{}{} + if sdk.IsUpgrade(upgrade.LotSizeOptimization) { + if dexUtils.IsUnderMinNotional(msg.Price, msg.Quantity) { + return errors.New("notional value of the order is too small") } } + + if dexUtils.IsExceedMaxNotional(msg.Price, msg.Quantity) { + return errors.New("notional value of the order is too large(cannot fit in int64)") + } + + return nil } diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index bc605f03a..22f299e86 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -4,7 +4,6 @@ import ( "bytes" "compress/zlib" "fmt" - dexUtils "github.com/binance-chain/node/plugins/dex/utils" "io" "sort" "strings" @@ -171,17 +170,10 @@ func (kp *Keeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64 symbol := strings.ToUpper(m.Symbol) kp.allOrders[symbol][m.Id] = &orderHolder if m.CreatedHeight == height { - if dexUtils.IsMiniTokenTradingPair(symbol) { - kp.roundOrdersMini[symbol] = append(kp.roundOrdersMini[symbol], m.Id) - if m.TimeInForce == TimeInForce.IOC { - kp.roundIOCOrdersMini[symbol] = append(kp.roundIOCOrdersMini[symbol], m.Id) - } - } else { kp.roundOrders[symbol] = append(kp.roundOrders[symbol], m.Id) if m.TimeInForce == TimeInForce.IOC { kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], m.Id) } - } } if kp.CollectOrderInfoForPublish { if _, exists := kp.OrderInfosForPub[m.Id]; !exists { diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index ff4e0fe54..dd1db6f0c 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -55,7 +55,7 @@ func MakeCodec() *wire.Codec { func MakeKeeper(cdc *wire.Codec) *Keeper { accKeeper := auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) codespacer := sdk.NewCodespacer() - pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) + pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) keeper := NewKeeper(common.DexStoreKey, accKeeper, pairMapper, codespacer.RegisterNext(dextypes.DefaultCodespace), 2, cdc, true) return keeper @@ -545,7 +545,7 @@ func setup() (ctx sdk.Context, mapper auth.AccountKeeper, keeper *Keeper) { wire.RegisterCrypto(cdc) mapper = auth.NewAccountKeeper(cdc, capKey, types.ProtoAppAccount) accountCache := getAccountCache(cdc, ms, capKey) - pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) + pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) keeper = NewKeeper(capKey2, mapper, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, false) return diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go new file mode 100644 index 000000000..0259404ca --- /dev/null +++ b/plugins/dex/order/mini_keeper.go @@ -0,0 +1,703 @@ +package order + +import ( + "errors" + "fmt" + "hash/crc32" + "strings" + "sync" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + + "github.com/binance-chain/node/common/fees" + bnclog "github.com/binance-chain/node/common/log" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/common/utils" + me "github.com/binance-chain/node/plugins/dex/matcheng" + "github.com/binance-chain/node/plugins/dex/store" + dexTypes "github.com/binance-chain/node/plugins/dex/types" + dexUtils "github.com/binance-chain/node/plugins/dex/utils" + "github.com/binance-chain/node/wire" +) + +const ( + defaultMiniBlockMatchInterval = 16 + defaultActiveMiniSymbolCount = 8 +) + +//order keeper for mini-token +type MiniKeeper struct { + Keeper //use dex order keeper as base keeper + matchedMiniSymbols []string //mini token pairs matched in this round + miniSymbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin +} + +var _ DexOrderKeeper = &MiniKeeper{} + +// NewKeeper - Returns the MiniToken Keeper +func NewMiniKeeper(dexMiniKey sdk.StoreKey, am auth.AccountKeeper, miniPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, + concurrency uint, cdc *wire.Codec, collectOrderInfoForPublish bool) *MiniKeeper { + logger := bnclog.With("module", "dexkeeper") + return &MiniKeeper{ + Keeper{PairMapper: miniPairMapper, + am: am, + storeKey: dexMiniKey, + codespace: codespace, + engines: make(map[string]*me.MatchEng), + recentPrices: make(map[string]*utils.FixedSizeRing, 256), + allOrders: make(map[string]map[string]*OrderInfo, 256), // need to init the nested map when a new symbol added. + OrderChangesMtx: &sync.Mutex{}, + OrderChanges: make(OrderChanges, 0), + OrderInfosForPub: make(OrderInfoForPublish), + roundOrders: make(map[string][]string, 256), + roundIOCOrders: make(map[string][]string, 256), + RoundOrderFees: make(map[string]*types.Fee, 256), + poolSize: concurrency, + cdc: cdc, + FeeManager: NewFeeManager(cdc, dexMiniKey, logger), + CollectOrderInfoForPublish: collectOrderInfoForPublish, + logger: logger}, + make([]string, 0, 256), + make(map[string]uint32, 256), + } +} + +// override +func (kp *MiniKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { + eng := kp.Keeper.AddEngine(pair) + symbol := strings.ToUpper(pair.GetSymbol()) + kp.miniSymbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) + return eng +} + +// override +// please note if distributeTrade this method will work in async mode, otherwise in sync mode. +func (kp *MiniKeeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64, matchAllMiniSymbols bool) ([]chan Transfer) { + size := len(kp.roundOrders) + // size is the number of pairs that have new orders, i.e. it should call match() + if size == 0 { + kp.logger.Info("No new orders for any pair, give up matching") + return nil + } + + concurrency := 1 << kp.poolSize + tradeOuts := make([]chan Transfer, concurrency) + + if matchAllMiniSymbols { + for symbol := range kp.roundOrders { + kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) + } + } else { + kp.selectMiniSymbolsToMatch(height, func(miniSymbols map[string]struct{}) { + for symbol := range miniSymbols { + kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) + } + }) + } + + if distributeTrade { + ordNum := 0 + for _, perSymbol := range kp.roundOrders { + ordNum += len(perSymbol) + } + for i := range tradeOuts { + //assume every new order would have 2 trades and generate 4 transfer + tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) + } + } + + symbolCh := make(chan string, concurrency) + producer := func() { + for symbol := range kp.roundOrders { + symbolCh <- symbol + } + close(symbolCh) + } + matchWorker := func() { + i := 0 + for symbol := range symbolCh { + i++ + kp.matchAndDistributeTradesForSymbol(symbol, height, timestamp, kp.allOrders[symbol], distributeTrade, tradeOuts) + } + } + + if distributeTrade { + utils.ConcurrentExecuteAsync(concurrency, producer, matchWorker, func() { + for _, tradeOut := range tradeOuts { + close(tradeOut) + } + }) + } else { + utils.ConcurrentExecuteSync(concurrency, producer, matchWorker) + } + return tradeOuts +} + +func (kp *MiniKeeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { + orderbook := make([]store.OrderBookLevel, maxLevels) + + i, j := 0, 0 + + if eng, ok := kp.engines[pair]; ok { + // TODO: check considered bucket splitting? + eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { + orderbook[i].BuyPrice = utils.Fixed8(p.Price) + orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) + i++ + }, + func(p *me.PriceLevel) { + orderbook[j].SellPrice = utils.Fixed8(p.Price) + orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) + j++ + }) + } + return orderbook +} + +func (kp *MiniKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { + openOrders := make([]store.OpenOrder, 0) + + for _, order := range kp.allOrders[pair] { + if string(order.Sender.Bytes()) == string(addr.Bytes()) { + openOrders = append( + openOrders, + store.OpenOrder{ + order.Id, + pair, + utils.Fixed8(order.Price), + utils.Fixed8(order.Quantity), + utils.Fixed8(order.CumQty), + order.CreatedHeight, + order.CreatedTimestamp, + order.LastUpdatedHeight, + order.LastUpdatedTimestamp, + }) + } + } + + return openOrders +} + +func (kp *MiniKeeper) GetOrderBooks(maxLevels int) ChangedPriceLevelsMap { + var res = make(ChangedPriceLevelsMap) + for pair, eng := range kp.engines { + buys := make(map[int64]int64) + sells := make(map[int64]int64) + res[pair] = ChangedPriceLevelsPerSymbol{buys, sells} + + // TODO: check considered bucket splitting? + eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { + buys[p.Price] = p.TotalLeavesQty() + }, func(p *me.PriceLevel) { + sells[p.Price] = p.TotalLeavesQty() + }) + } + + return res +} + +func (kp *MiniKeeper) GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel { + if eng, ok := kp.engines[pair]; ok { + return eng.Book.GetPriceLevel(price, side) + } else { + return nil + } +} + +func (kp *MiniKeeper) GetLastTrades(height int64, pair string) ([]me.Trade, int64) { + if eng, ok := kp.engines[pair]; ok { + if eng.LastMatchHeight == height { + return eng.Trades, eng.LastTradePrice + } + } + return nil, 0 +} + +// !!! FOR TEST USE ONLY +func (kp *MiniKeeper) GetLastTradesForPair(pair string) ([]me.Trade, int64) { + if eng, ok := kp.engines[pair]; ok { + return eng.Trades, eng.LastTradePrice + } + return nil, 0 +} + +func (kp *MiniKeeper) ClearOrderBook(pair string) { + if eng, ok := kp.engines[pair]; ok { + eng.Book.Clear() + } +} + +func (kp *MiniKeeper) ClearOrderChanges() { + kp.OrderChanges = kp.OrderChanges[:0] +} + +func (kp *MiniKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { + account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) + newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) + // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. + // they should never happen, there would be a severe bug if happen and we have to cancel all orders when app restarts. + if !newLocked.IsNotNegative() { + panic(fmt.Errorf( + "no enough locked tokens to unlock, oid: %s, newLocked: %s, unlock: %d", + tran.Oid, + newLocked.String(), + tran.unlock)) + } + if tran.unlock < tran.out { + panic(errors.New("unlocked tokens cannot cover the expense")) + } + account.SetLockedCoins(newLocked) + accountCoin := account.GetCoins(). + Plus(sdk.Coins{sdk.NewCoin(tran.inAsset, tran.in)}) + if remain := tran.unlock - tran.out; remain > 0 || !sdk.IsUpgrade(upgrade.FixZeroBalance) { + accountCoin = accountCoin.Plus(sdk.Coins{sdk.NewCoin(tran.outAsset, remain)}) + } + account.SetCoins(accountCoin) + + kp.am.SetAccount(ctx, account) + return nil +} + +// override +func (kp *MiniKeeper) clearAfterMatch() { + for _, symbol := range kp.matchedMiniSymbols { + delete(kp.roundOrders, symbol) + delete(kp.roundIOCOrders, symbol) + } + kp.matchedMiniSymbols = make([]string, 0, 256) +} + +func (kp *MiniKeeper) StoreTradePrices(ctx sdk.Context) { + // TODO: check block height != 0 + if ctx.BlockHeight()%pricesStoreEvery == 0 { + lastTradePrices := make(map[string]int64, len(kp.engines)) + for symbol, engine := range kp.engines { + lastTradePrices[symbol] = engine.LastTradePrice + if _, ok := kp.recentPrices[symbol]; !ok { + kp.recentPrices[symbol] = utils.NewFixedSizedRing(numPricesStored) + } + kp.recentPrices[symbol].Push(engine.LastTradePrice) + } + if len(lastTradePrices) != 0 { + kp.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices) + } + } +} + +func (kp *MiniKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( + types.Fee, map[string]*types.Fee) { + if !sdk.IsUpgrade(upgrade.BEP19) { + return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler) + } + + // use string of the addr as the key since map makes a fast path for string key. + // Also, making the key have same length is also an optimization. + tradeTransfers := make(map[string]TradeTransfers) + // expire fee is fixed, so we count by numbers. + expireTransfers := make(map[string]ExpireTransfers) + // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. + var expireEventType transferEventType + var totalFee types.Fee + for tran := range tranCh { + kp.doTransfer(ctx, &tran) + if !tran.FeeFree() { + addrStr := string(tran.accAddress.Bytes()) + // need a copy of tran as it is reused + tranCp := tran + if tran.IsExpiredWithFee() { + expireEventType = tran.eventType + if _, ok := expireTransfers[addrStr]; !ok { + expireTransfers[addrStr] = ExpireTransfers{&tranCp} + } else { + expireTransfers[addrStr] = append(expireTransfers[addrStr], &tranCp) + } + } else if tran.eventType == eventFilled { + if _, ok := tradeTransfers[addrStr]; !ok { + tradeTransfers[addrStr] = TradeTransfers{&tranCp} + } else { + tradeTransfers[addrStr] = append(tradeTransfers[addrStr], &tranCp) + } + } + } else if tran.IsExpire() { + if postAllocateHandler != nil { + postAllocateHandler(tran) + } + } + } + + feesPerAcc := make(map[string]*types.Fee) + for addrStr, trans := range tradeTransfers { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, kp.engines) + if !fees.IsEmpty() { + feesPerAcc[addrStr] = &fees + acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) + kp.am.SetAccount(ctx, acc) + totalFee.AddFee(fees) + } + } + + for addrStr, trans := range expireTransfers { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + + fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, kp.engines, postAllocateHandler) + if !fees.IsEmpty() { + if _, ok := feesPerAcc[addrStr]; ok { + feesPerAcc[addrStr].AddFee(fees) + } else { + feesPerAcc[addrStr] = &fees + } + acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) + kp.am.SetAccount(ctx, acc) + totalFee.AddFee(fees) + } + } + return totalFee, feesPerAcc +} + +// DEPRECATED +func (kp *MiniKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( + types.Fee, map[string]*types.Fee) { + // use string of the addr as the key since map makes a fast path for string key. + // Also, making the key have same length is also an optimization. + tradeInAsset := make(map[string]*sortedAsset) + // expire fee is fixed, so we count by numbers. + expireInAsset := make(map[string]*sortedAsset) + // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. + var expireEventType transferEventType + var totalFee types.Fee + for tran := range tranCh { + kp.doTransfer(ctx, &tran) + if !tran.FeeFree() { + addrStr := string(tran.accAddress.Bytes()) + if tran.IsExpiredWithFee() { + expireEventType = tran.eventType + fees, ok := expireInAsset[addrStr] + if !ok { + fees = &sortedAsset{} + expireInAsset[addrStr] = fees + } + fees.addAsset(tran.inAsset, 1) + } else if tran.eventType == eventFilled { + fees, ok := tradeInAsset[addrStr] + if !ok { + fees = &sortedAsset{} + tradeInAsset[addrStr] = fees + } + // no possible to overflow, for tran.in == otherSide.tran.out <= TotalSupply(otherSide.tran.outAsset) + fees.addAsset(tran.inAsset, tran.in) + } + } + if postAllocateHandler != nil { + postAllocateHandler(tran) + } + } + + feesPerAcc := make(map[string]*types.Fee) + collectFee := func(assetsMap map[string]*sortedAsset, calcFeeAndDeduct func(acc sdk.Account, in sdk.Coin) types.Fee) { + for addrStr, assets := range assetsMap { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + + var fees types.Fee + if exists, ok := feesPerAcc[addrStr]; ok { + fees = *exists + } + if assets.native != 0 { + fee := calcFeeAndDeduct(acc, sdk.NewCoin(types.NativeTokenSymbol, assets.native)) + fees.AddFee(fee) + totalFee.AddFee(fee) + } + for _, asset := range assets.tokens { + fee := calcFeeAndDeduct(acc, asset) + fees.AddFee(fee) + totalFee.AddFee(fee) + } + if !fees.IsEmpty() { + feesPerAcc[addrStr] = &fees + kp.am.SetAccount(ctx, acc) + } + } + } + collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { + fee := kp.FeeManager.CalcTradeFee(acc.GetCoins(), in, kp.engines) + acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) + return fee + }) + collectFee(expireInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { + var i int64 = 0 + var fees types.Fee + for ; i < in.Amount; i++ { + fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, kp.engines) + acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) + fees.AddFee(fee) + } + return fees + }) + return totalFee, feesPerAcc +} + +func (kp *MiniKeeper) allocateAndCalcFee( + ctx sdk.Context, + tradeOuts []chan Transfer, + postAlloTransHandler TransferHandler, +) types.Fee { + concurrency := len(tradeOuts) + var wg sync.WaitGroup + wg.Add(concurrency) + feesPerCh := make([]types.Fee, concurrency) + feesPerAcc := make([]map[string]*types.Fee, concurrency) + allocatePerCh := func(index int, tranCh <-chan Transfer) { + defer wg.Done() + fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) + feesPerCh[index].AddFee(fee) + feesPerAcc[index] = feeByAcc + } + + for i, tradeTranCh := range tradeOuts { + go allocatePerCh(i, tradeTranCh) + } + wg.Wait() + totalFee := types.Fee{} + for i := 0; i < concurrency; i++ { + totalFee.AddFee(feesPerCh[i]) + } + if kp.CollectOrderInfoForPublish { + for _, m := range feesPerAcc { + for k, v := range m { + kp.updateRoundOrderFee(k, *v) + } + } + } + return totalFee +} + +// MatchAll will only concurrently match but do not allocate into accounts +func (kp *MiniKeeper) MatchAll(height, timestamp int64) { + tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp, false) //only match + if tradeOuts == nil { + kp.logger.Info("No order comes in for the block") + } + kp.clearAfterMatch() +} + +// MatchAndAllocateAll() is concurrently matching and allocating across +// all the symbols' order books, among all the clients +// Return whether match has been done in this height +func (kp *MiniKeeper) MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { + kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(kp.roundOrders)) + timestamp := ctx.BlockHeader().Time.UnixNano() + tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp, matchAllSymbols) + if tradeOuts == nil { + kp.logger.Info("No order comes in for the block") + } + + totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) + fees.Pool.AddAndCommitFee("MATCH", totalFee) + kp.clearAfterMatch() +} + +func (kp *MiniKeeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { + size := len(kp.allOrders) + if size == 0 { + kp.logger.Info("No orders to expire") + return nil + } + + // TODO: make effectiveDays configurable + const effectiveDays = 3 + expireHeight, err := kp.GetBreatheBlockHeight(ctx, blockTime, effectiveDays) + if err != nil { + // breathe block not found, that should only happens in in the first three days, just log it and ignore. + kp.logger.Info(err.Error()) + return nil + } + + channelSize := size >> kp.poolSize + concurrency := 1 << kp.poolSize + if size%concurrency != 0 { + channelSize += 1 + } + + transferChs := make([]chan Transfer, concurrency) + for i := range transferChs { + // TODO: channelSize is enough for buffer to facilitate ? + transferChs[i] = make(chan Transfer, channelSize*2) + } + + expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { + engine.Book.RemoveOrders(expireHeight, side, func(ord me.OrderPart) { + // gen transfer + if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { + h := channelHash(ordMsg.Sender, concurrency) + transferChs[h] <- TransferFromExpired(ord, *ordMsg) + // delete from allOrders + delete(orders, ord.Id) + } else { + kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) + } + }) + } + + symbolCh := make(chan string, concurrency) + utils.ConcurrentExecuteAsync(concurrency, + func() { + for symbol := range kp.allOrders { + symbolCh <- symbol + } + close(symbolCh) + }, func() { + for symbol := range symbolCh { + engine := kp.engines[symbol] + orders := kp.allOrders[symbol] + expire(orders, engine, me.BUYSIDE) + expire(orders, engine, me.SELLSIDE) + } + }, func() { + for _, transferCh := range transferChs { + close(transferCh) + } + }) + + return transferChs +} + +func (kp *MiniKeeper) ExpireOrders( + ctx sdk.Context, + blockTime time.Time, + postAlloTransHandler TransferHandler, +) { + transferChs := kp.expireOrders(ctx, blockTime) + if transferChs == nil { + return + } + + totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAlloTransHandler) + fees.Pool.AddAndCommitFee("EXPIRE", totalFee) +} + +// used by state sync to clear memory order book after we synced latest breathe block +//TODO check usage +func (kp *MiniKeeper) ClearOrders() { + kp.Keeper.ClearOrders() + kp.matchedMiniSymbols = make([]string, 0, 256) +} + +func (kp *MiniKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) { + _, ok := kp.engines[symbol] + if !ok { + kp.logger.Error("delist symbol does not exist", "symbol", symbol) + return + } + + transferChs := kp.expireAllOrders(ctx, symbol) + if transferChs != nil { + totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAllocTransHandler) + fees.Pool.AddAndCommitFee(fmt.Sprintf("DELIST_%s", symbol), totalFee) + } + + delete(kp.engines, symbol) + delete(kp.allOrders, symbol) + delete(kp.recentPrices, symbol) + + baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol) + err := kp.PairMapper.DeleteTradingPair(ctx, baseAsset, quoteAsset) + if err != nil { + kp.logger.Error("delete trading pair error", "err", err.Error()) + } +} + +//override +func (kp *MiniKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { + // trading pair against native token should exist if quote token is not native token + baseAsset = strings.ToUpper(baseAsset) + quoteAsset = strings.ToUpper(quoteAsset) + + if baseAsset == quoteAsset { + return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") + } + + if kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) || kp.PairMapper.Exists(ctx, quoteAsset, baseAsset) { + return errors.New("trading pair exists") + } + + if types.NativeTokenSymbol != quoteAsset { //todo permit BUSD + return errors.New("quote token is not valid: " + quoteAsset) + } + + return nil +} + +//override TODO check +func (kp *MiniKeeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { + // trading pair against native token should not be delisted if there is any other trading pair exist + baseAsset = strings.ToUpper(baseAsset) + quoteAsset = strings.ToUpper(quoteAsset) + + if baseAsset == quoteAsset { + return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") + } + + if !kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) { + return fmt.Errorf("trading pair %s_%s does not exist", baseAsset, quoteAsset) + } + + return nil +} + +func (kp *MiniKeeper) selectMiniSymbolsToMatch(height int64, postSelect func(map[string]struct{})) { + symbolsToMatch := make(map[string]struct{}, 256) + selectActiveMiniSymbols(&symbolsToMatch, &kp.roundOrders, defaultActiveMiniSymbolCount) + selectMiniSymbolsRoundRobin(&symbolsToMatch, &kp.miniSymbolsHash, height) + postSelect(symbolsToMatch) +} + +func selectActiveMiniSymbols(symbolsToMatch *map[string]struct{}, roundOrdersMini *map[string][]string, k int) { + //use quick select to select top k symbols + symbolOrderNumsSlice := make([]*SymbolWithOrderNumber, 0, len(*roundOrdersMini)) + i := 0 + for symbol, orders := range *roundOrdersMini { + symbolOrderNumsSlice[i] = &SymbolWithOrderNumber{symbol, len(orders)} + } + topKSymbolOrderNums := findTopKLargest(symbolOrderNumsSlice, k) + + for _, selected := range topKSymbolOrderNums { + (*symbolsToMatch)[selected.symbol] = struct{}{} + } +} + +func selectMiniSymbolsRoundRobin(symbolsToMatch *map[string]struct{}, miniSymbolsHash *map[string]uint32, height int64) { + m := height % defaultMiniBlockMatchInterval + for symbol, symbolHash := range *miniSymbolsHash { + if int64(symbolHash%defaultMiniBlockMatchInterval) == m { + (*symbolsToMatch)[symbol] = struct{}{} + } + } +} + +// override +func (kp *MiniKeeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { + + err := kp.Keeper.validateOrder(ctx, acc, msg) + if err != nil { + return err + } + coins := acc.GetCoins() + symbol := strings.ToUpper(msg.Symbol) + var quantityBigEnough bool + if msg.Side == Side.BUY { + quantityBigEnough = msg.Quantity >= types.MiniTokenMinTotalSupply + } else if msg.Side == Side.SELL { + quantityBigEnough = (msg.Quantity >= types.MiniTokenMinTotalSupply) || coins.AmountOf(symbol) == msg.Quantity + } + if !quantityBigEnough { + return fmt.Errorf("quantity is too small, the min quantity is %d or total free balance of the mini token", + types.MiniTokenMinTotalSupply) + } + return nil +} diff --git a/plugins/dex/plugin.go b/plugins/dex/plugin.go index e61f07e19..0fcbcd130 100644 --- a/plugins/dex/plugin.go +++ b/plugins/dex/plugin.go @@ -2,6 +2,7 @@ package dex import ( "encoding/json" + "reflect" "strings" "time" @@ -20,20 +21,28 @@ import ( const AbciQueryPrefix = "dex" const DelayedDaysForDelist = 3 +type DexKeeperType int8 + +const ( + KeeperType DexKeeperType = 0 + MiniTokenKeeperType DexKeeperType = 1 +) + // InitPlugin initializes the dex plugin. func InitPlugin( - appp app.ChainApp, keeper *DexKeeper, tokenMapper tkstore.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, + appp app.ChainApp, dexKeeper *DexKeeper, dexMiniKeeper *DexMiniTokenKeeper, tokenMapper tkstore.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, ) { cdc := appp.GetCodec() // add msg handlers - for route, handler := range Routes(cdc, keeper, tokenMapper, miniTokenMapper, accMapper, govKeeper) { + for route, handler := range Routes(cdc, dexKeeper, dexMiniKeeper, tokenMapper, miniTokenMapper, accMapper, govKeeper) { appp.GetRouter().AddRoute(route, handler) } // add abci handlers - handler := createQueryHandler(keeper) + handler := createQueryHandler(dexKeeper) appp.RegisterQueryHandler(AbciQueryPrefix, handler) + //TODO dex mini handler } func createQueryHandler(keeper *DexKeeper) app.AbciQueryHandler { @@ -41,7 +50,7 @@ func createQueryHandler(keeper *DexKeeper) app.AbciQueryHandler { } // EndBreatheBlock processes the breathe block lifecycle event. -func EndBreatheBlock(ctx sdk.Context, dexKeeper *DexKeeper, govKeeper gov.Keeper, height int64, blockTime time.Time) { +func EndBreatheBlock(ctx sdk.Context, dexKeeper DexOrderKeeper, govKeeper gov.Keeper, height int64, blockTime time.Time) { logger := bnclog.With("module", "dex") logger.Info("Delist trading pairs", "blockHeight", height) @@ -51,7 +60,7 @@ func EndBreatheBlock(ctx sdk.Context, dexKeeper *DexKeeper, govKeeper gov.Keeper dexKeeper.UpdateTickSizeAndLotSize(ctx) logger.Info("Expire stale orders") - if dexKeeper.CollectOrderInfoForPublish { + if dexKeeper.ShouldPublishOrder() { pub.ExpireOrdersForPublish(dexKeeper, ctx, blockTime) } else { dexKeeper.ExpireOrders(ctx, blockTime, nil) @@ -66,9 +75,19 @@ func EndBreatheBlock(ctx sdk.Context, dexKeeper *DexKeeper, govKeeper gov.Keeper return } -func delistTradingPairs(ctx sdk.Context, govKeeper gov.Keeper, dexKeeper *DexKeeper, blockTime time.Time) { +func delistTradingPairs(ctx sdk.Context, govKeeper gov.Keeper, dexKeeper DexOrderKeeper, blockTime time.Time) { logger := bnclog.With("module", "dex") - symbolsToDelist := getSymbolsToDelist(ctx, govKeeper, blockTime) + var dexKeeperType DexKeeperType + switch dexKeeper.(type) { + case *DexKeeper: + dexKeeperType = KeeperType + case *DexMiniTokenKeeper: + dexKeeperType = MiniTokenKeeperType + default: + logger.Error("unknown dexKeeper type", "dexKeeper", reflect.TypeOf(dexKeeper)) + return + } + symbolsToDelist := getSymbolsToDelist(ctx, govKeeper, blockTime, dexKeeperType) for _, symbol := range symbolsToDelist { logger.Info("Delist trading pair", "symbol", symbol) @@ -79,7 +98,7 @@ func delistTradingPairs(ctx sdk.Context, govKeeper gov.Keeper, dexKeeper *DexKee continue } - if dexKeeper.CollectOrderInfoForPublish { + if dexKeeper.ShouldPublishOrder() { pub.DelistTradingPairForPublish(ctx, dexKeeper, symbol) } else { dexKeeper.DelistTradingPair(ctx, symbol, nil) @@ -87,7 +106,7 @@ func delistTradingPairs(ctx sdk.Context, govKeeper gov.Keeper, dexKeeper *DexKee } } -func getSymbolsToDelist(ctx sdk.Context, govKeeper gov.Keeper, blockTime time.Time) []string { +func getSymbolsToDelist(ctx sdk.Context, govKeeper gov.Keeper, blockTime time.Time, dexKeeperType DexKeeperType) []string { logger := bnclog.With("module", "dex") symbols := make([]string, 0) @@ -115,8 +134,10 @@ func getSymbolsToDelist(ctx sdk.Context, govKeeper gov.Keeper, blockTime time.Ti timeToDelist := passedTime.Add(DelayedDaysForDelist * 24 * time.Hour) if timeToDelist.Before(blockTime) { symbol := utils.Assets2TradingPair(strings.ToUpper(delistParam.BaseAssetSymbol), strings.ToUpper(delistParam.QuoteAssetSymbol)) + if (dexKeeperType == MiniTokenKeeperType) != utils.IsMiniTokenTradingPair(symbol) { + return false + } symbols = append(symbols, symbol) - // update proposal delisted status delistParam.IsExecuted = true bz, err := json.Marshal(delistParam) diff --git a/plugins/dex/route.go b/plugins/dex/route.go index 319856b59..bc42931fe 100644 --- a/plugins/dex/route.go +++ b/plugins/dex/route.go @@ -14,13 +14,13 @@ import ( ) // Routes exports dex message routes -func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, +func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, dexMiniKeeper *DexMiniTokenKeeper, tokenMapper tokens.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accKeeper auth.AccountKeeper, govKeeper gov.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) - orderHandler := order.NewHandler(cdc, dexKeeper, accKeeper) + orderHandler := order.NewHandler(cdc, dexKeeper, dexMiniKeeper, accKeeper) routes[order.RouteNewOrder] = orderHandler routes[order.RouteCancelOrder] = orderHandler routes[list.Route] = list.NewHandler(dexKeeper, tokenMapper, govKeeper) - routes[listmini.Route] = listmini.NewHandler(dexKeeper, miniTokenMapper, tokenMapper) + routes[listmini.Route] = listmini.NewHandler(dexMiniKeeper, miniTokenMapper, tokenMapper) return routes } diff --git a/plugins/dex/store/mapper.go b/plugins/dex/store/mapper.go index 35e3d3642..2392b21b9 100644 --- a/plugins/dex/store/mapper.go +++ b/plugins/dex/store/mapper.go @@ -10,6 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" cmn "github.com/binance-chain/node/common/types" + common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/utils" "github.com/binance-chain/node/plugins/dex/types" dexUtils "github.com/binance-chain/node/plugins/dex/utils" @@ -24,8 +25,6 @@ type TradingPairMapper interface { GetTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) (types.TradingPair, error) DeleteTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error ListAllTradingPairs(ctx sdk.Context) []types.TradingPair - ListAllBEP2TradingPairs(ctx sdk.Context) []types.TradingPair - ListAllMiniTradingPairs(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 } @@ -35,23 +34,33 @@ var _ TradingPairMapper = mapper{} type mapper struct { key sdk.StoreKey cdc *wire.Codec + forMiniPair bool } -func NewTradingPairMapper(cdc *wire.Codec, key sdk.StoreKey) TradingPairMapper { +func NewTradingPairMapper(cdc *wire.Codec, key sdk.StoreKey, forMiniPair bool) TradingPairMapper { return mapper{ key: key, cdc: cdc, - } + forMiniPair: forMiniPair} } func (m mapper) AddTradingPair(ctx sdk.Context, pair types.TradingPair) error { baseAsset := pair.BaseAssetSymbol - if err := cmn.ValidateMapperTokenSymbol(baseAsset); err != nil { - return err - } quoteAsset := pair.QuoteAssetSymbol - if err := cmn.ValidateMapperTokenSymbol(quoteAsset); err != nil { - return err + if m.forMiniPair{ + if err := cmn.ValidateMapperMiniTokenSymbol(baseAsset); err != nil { + return err + } + if quoteAsset!= common.NativeTokenSymbol{ //todo permit BUSD + return errors.New("quote token is not valid") + } + }else { + if err := cmn.ValidateMapperTokenSymbol(baseAsset); err != nil { + return err + } + if err := cmn.ValidateMapperTokenSymbol(quoteAsset); err != nil { + return err + } } tradeSymbol := dexUtils.Assets2TradingPair(strings.ToUpper(baseAsset), strings.ToUpper(quoteAsset)) @@ -65,7 +74,7 @@ func (m mapper) AddTradingPair(ctx sdk.Context, pair types.TradingPair) error { func (m mapper) AddMiniTokenTradingPair(ctx sdk.Context, pair types.TradingPair) error { baseAsset := pair.BaseAssetSymbol - if err := cmn.ValidateMapperTokenSymbol(baseAsset); err != nil { + if err := cmn.ValidateMapperMiniTokenSymbol(baseAsset); err != nil { return err } quoteAsset := pair.QuoteAssetSymbol @@ -78,7 +87,7 @@ func (m mapper) AddMiniTokenTradingPair(ctx sdk.Context, pair types.TradingPair) store := ctx.KVStore(m.key) value := m.encodeTradingPair(pair) store.Set(key, value) - ctx.Logger().Info("Added trading pair", "pair", tradeSymbol) + ctx.Logger().Info("Added mini-token trading pair", "pair", tradeSymbol) return nil } @@ -133,16 +142,6 @@ func (m mapper) ListAllTradingPairs(ctx sdk.Context) (res []types.TradingPair) { return res } -func (m mapper) ListAllBEP2TradingPairs(ctx sdk.Context) []types.TradingPair { - //todo "implement me" - return nil -} - -func (m mapper) ListAllMiniTradingPairs(ctx sdk.Context) []types.TradingPair { - //todo "implement me" - return nil -} - func (m mapper) getRecentPricesSeq(height, pricesStoreEvery, numPricesStored int64) int64 { return (height/pricesStoreEvery - 1) % numPricesStored } diff --git a/plugins/dex/store/mapper_test.go b/plugins/dex/store/mapper_test.go index 3bef25063..56ebe1cdc 100644 --- a/plugins/dex/store/mapper_test.go +++ b/plugins/dex/store/mapper_test.go @@ -24,7 +24,7 @@ func setup() (TradingPairMapper, sdk.Context) { var cdc = wire.NewCodec() cdc.RegisterConcrete(dextypes.TradingPair{}, "dex/TradingPair", nil) cdc.RegisterConcrete(RecentPrice{}, "dex/RecentPrice", nil) - return NewTradingPairMapper(cdc, key), ctx + return NewTradingPairMapper(cdc, key, false), ctx } func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) { diff --git a/plugins/miniTokens/plugin.go b/plugins/miniTokens/plugin.go index bb1920a5b..4214e8bb9 100644 --- a/plugins/miniTokens/plugin.go +++ b/plugins/miniTokens/plugin.go @@ -7,7 +7,7 @@ import ( app "github.com/binance-chain/node/common/types" ) -const abciQueryPrefix = "minitokens" +const abciQueryPrefix = "mini-tokens" // InitPlugin initializes the plugin. func InitPlugin( diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 9cbcda0a7..3d7a31ad7 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -92,8 +92,8 @@ func handleBurnMiniToken(ctx sdk.Context, tokenMapper miniToken.MiniTokenMapper, useAllBalance := coins.AmountOf(symbol) == burnAmount if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { - logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", + logger.Info(errLogMsg, "reason", "burn amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("burn amount is too small, the min amount is %d or total free balance", common.MiniTokenMinTotalSupply)).Result() } diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index fcaafd1bc..febca9f6a 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -65,10 +65,6 @@ func (msg BurnMsg) GetSignBytes() []byte { } func (msg BurnMsg) validateMiniTokenBasic() sdk.Error { - err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) - if err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } if msg.Amount <= 0 { return sdk.ErrInsufficientFunds("amount should be more than 0") } diff --git a/plugins/tokens/freeze/msg.go b/plugins/tokens/freeze/msg.go index 266e099b0..e02a9d351 100644 --- a/plugins/tokens/freeze/msg.go +++ b/plugins/tokens/freeze/msg.go @@ -65,10 +65,6 @@ func (msg FreezeMsg) GetSignBytes() []byte { } func (msg FreezeMsg) validateMiniTokenBasic() sdk.Error { - err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) - if err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } if msg.Amount <= 0 { return sdk.ErrInsufficientFunds("amount should be more than 0") } From 5747530ed3a96a561ad5c57574b09c5ed27a63d7 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 14 Apr 2020 17:20:55 +0800 Subject: [PATCH 11/96] clean code; fix avro schema --- app/app.go | 17 +- app/config/config.go | 11 +- app/pub/schemas.go | 76 +---- cmd/dexperf/main.go | 2 +- common/upgrade/upgrade.go | 3 +- plugins/dex/order/mini_keeper.go | 456 +-------------------------- plugins/dex/utils/pair.go | 2 +- plugins/miniTokens/issue/handler.go | 2 +- plugins/miniTokens/issue/msg.go | 2 + plugins/miniTokens/route.go | 7 +- plugins/miniTokens/seturi/handler.go | 8 +- plugins/miniTokens/seturi/msg.go | 4 +- plugins/param/plugin.go | 2 +- plugins/tokens/client/cli/issue.go | 3 +- plugins/tokens/swap/handler.go | 2 +- plugins/tokens/timelock/handler.go | 3 +- 16 files changed, 50 insertions(+), 550 deletions(-) diff --git a/app/app.go b/app/app.go index 08d5e91a6..6c9860f1c 100644 --- a/app/app.go +++ b/app/app.go @@ -41,6 +41,8 @@ import ( "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/ico" "github.com/binance-chain/node/plugins/minitokens" + miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" + "github.com/binance-chain/node/plugins/minitokens/seturi" miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" "github.com/binance-chain/node/plugins/param" "github.com/binance-chain/node/plugins/param/paramhub" @@ -260,7 +262,6 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp // setUpgradeConfig will overwrite default upgrade config func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // register upgrade height - upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, upgradeConfig.BEP8Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP6, upgradeConfig.BEP6Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP9, upgradeConfig.BEP9Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP10, upgradeConfig.BEP10Height) @@ -271,11 +272,14 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { upgrade.Mgr.AddUpgradeHeight(upgrade.LotSizeOptimization, upgradeConfig.LotSizeUpgradeHeight) upgrade.Mgr.AddUpgradeHeight(upgrade.ListingRuleUpgrade, upgradeConfig.ListingRuleUpgradeHeight) upgrade.Mgr.AddUpgradeHeight(upgrade.FixZeroBalance, upgradeConfig.FixZeroBalanceHeight) - + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, upgradeConfig.BEP8Height) // register store keys of upgrade upgrade.Mgr.RegisterStoreKeys(upgrade.BEP9, common.TimeLockStoreKey.Name()) upgrade.Mgr.RegisterStoreKeys(upgrade.BEP3, common.AtomicSwapStoreKey.Name()) + upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.MiniTokenStoreKey.Name()) + upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.MiniTokenPairStoreKey.Name()) + // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP9, timelock.TimeLockMsg{}.Type(), @@ -291,6 +295,11 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { swap.ClaimHTLTMsg{}.Type(), swap.RefundHTLTMsg{}.Type(), ) + // register msg types of upgrade + upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, + miniIssue.IssueMsg{}.Type(), + seturi.SetURIMsg{}.Type(), + ) } func getABCIQueryBlackList(queryConfig *config.QueryConfig) map[string]bool { @@ -801,7 +810,7 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli txRelatedAccounts := app.Pool.TxRelatedAddrs() tradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, tradesToPublish) miniTradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexMiniTokenKeeper, miniTradesToPublish) - tradeRelatedAccounts= append(tradeRelatedAccounts,miniTradeRelatedAccounts...) + tradeRelatedAccounts = append(tradeRelatedAccounts, miniTradeRelatedAccounts...) accountsToPublish = pub.GetAccountBalances( app.AccountKeeper, ctx, @@ -851,7 +860,7 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli miniTradesToPublish, proposalsToPublish, stakeUpdates, - app.DexKeeper.OrderChanges, // thread-safety is guarded by the signal from RemoveDoneCh + app.DexKeeper.OrderChanges, // thread-safety is guarded by the signal from RemoveDoneCh app.DexMiniTokenKeeper.OrderChanges, app.DexKeeper.OrderInfosForPub, // thread-safety is guarded by the signal from RemoveDoneCh app.DexMiniTokenKeeper.OrderInfosForPub, diff --git a/app/config/config.go b/app/config/config.go index cb2f8bea5..a5e23b11a 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -47,8 +47,6 @@ orderKeeperConcurrency = {{ .BaseConfig.OrderKeeperConcurrency }} breatheBlockDaysCountBack = {{ .BaseConfig.BreatheBlockDaysCountBack }} [upgrade] -# Block height of BEP8 upgrade -BEP8Height = {{ .UpgradeConfig.BEP8Height }} # Block height of BEP6 upgrade BEP6Height = {{ .UpgradeConfig.BEP6Height }} # Block height of BEP9 upgrade @@ -69,7 +67,8 @@ LotSizeUpgradeHeight = {{ .UpgradeConfig.LotSizeUpgradeHeight }} ListingRuleUpgradeHeight = {{ .UpgradeConfig.ListingRuleUpgradeHeight }} # Block height of FixZeroBalanceHeight upgrade FixZeroBalanceHeight = {{ .UpgradeConfig.FixZeroBalanceHeight }} - +# Block height of BEP8 upgrade +BEP8Height = {{ .UpgradeConfig.BEP8Height }} [query] # ABCI query interface black list, suggested value: ["custom/gov/proposals", "custom/timelock/timelocks", "custom/atomicSwap/swapcreator", "custom/atomicSwap/swaprecipient"] ABCIQueryBlackList = {{ .QueryConfig.ABCIQueryBlackList }} @@ -353,7 +352,6 @@ func defaultBaseConfig() *BaseConfig { type UpgradeConfig struct { - BEP8Height int64 `mapstructure:"BEP8Height"` // Galileo Upgrade BEP6Height int64 `mapstructure:"BEP6Height"` BEP9Height int64 `mapstructure:"BEP9Height"` @@ -368,12 +366,14 @@ type UpgradeConfig struct { LotSizeUpgradeHeight int64 `mapstructure:"LotSizeUpgradeHeight"` ListingRuleUpgradeHeight int64 `mapstructure:"ListingRuleUpgradeHeight"` FixZeroBalanceHeight int64 `mapstructure:"FixZeroBalanceHeight"` + + // TODO: add upgrade name + BEP8Height int64 `mapstructure:"BEP8Height"` } func defaultUpgradeConfig() *UpgradeConfig { // make the upgraded functions enabled by default return &UpgradeConfig{ - BEP8Height: 1, BEP6Height: 1, BEP9Height: 1, BEP10Height: 1, @@ -384,6 +384,7 @@ func defaultUpgradeConfig() *UpgradeConfig { LotSizeUpgradeHeight: math.MaxInt64, ListingRuleUpgradeHeight: math.MaxInt64, FixZeroBalanceHeight: math.MaxInt64, + BEP8Height: 1, } } diff --git a/app/pub/schemas.go b/app/pub/schemas.go index 8e0d7cd78..bc6ec41af 100644 --- a/app/pub/schemas.go +++ b/app/pub/schemas.go @@ -147,80 +147,8 @@ const ( } ] }], "default": null }, - { "name": "miniTrades", "type": ["null", { - "type": "record", - "name": "Trades", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "numOfMsgs", "type": "int" }, - { "name": "trades", "type": { - "type": "array", - "items": - { - "type": "record", - "name": "Trade", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "symbol", "type": "string" }, - { "name": "id", "type": "string" }, - { "name": "price", "type": "long" }, - { "name": "qty", "type": "long" }, - { "name": "sid", "type": "string" }, - { "name": "bid", "type": "string" }, - { "name": "sfee", "type": "string" }, - { "name": "bfee", "type": "string" }, - { "name": "saddr", "type": "string" }, - { "name": "baddr", "type": "string" }, - { "name": "ssrc", "type": "long" }, - { "name": "bsrc", "type": "long" }, - { "name": "ssinglefee", "type": "string" }, - { "name": "bsinglefee", "type": "string" }, - { "name": "tickType", "type": "int" } - ] - } - } - } - ] - }], "default": null }, - { "name": "miniOrders", "type": ["null", { - "type": "record", - "name": "Orders", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "numOfMsgs", "type": "int" }, - { "name": "orders", "type": { - "type": "array", - "items": - { - "type": "record", - "name": "Order", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "symbol", "type": "string" }, - { "name": "status", "type": "string" }, - { "name": "orderId", "type": "string" }, - { "name": "tradeId", "type": "string" }, - { "name": "owner", "type": "string" }, - { "name": "side", "type": "int" }, - { "name": "orderType", "type": "int" }, - { "name": "price", "type": "long" }, - { "name": "qty", "type": "long" }, - { "name": "lastExecutedPrice", "type": "long" }, - { "name": "lastExecutedQty", "type": "long" }, - { "name": "cumQty", "type": "long" }, - { "name": "fee", "type": "string" }, - { "name": "orderCreationTime", "type": "long" }, - { "name": "transactionTime", "type": "long" }, - { "name": "timeInForce", "type": "int" }, - { "name": "currentExecutionType", "type": "string" }, - { "name": "txHash", "type": "string" }, - { "name": "singlefee", "type": "string" } - ] - } - } - } - ] - }], "default": null } + { "name": "miniTrades", "type": ["null", "org.binance.dex.model.avro.Trades"], "default": null }, + { "name": "miniOrders", "type": ["null", "org.binance.dex.model.avro.Orders"], "default": null } ] } ` diff --git a/cmd/dexperf/main.go b/cmd/dexperf/main.go index b4966982e..0fec019a8 100644 --- a/cmd/dexperf/main.go +++ b/cmd/dexperf/main.go @@ -7,7 +7,6 @@ import ( "encoding/json" "flag" "fmt" - "github.com/binance-chain/node/plugins/minitokens" "io/ioutil" "math/rand" "os" @@ -38,6 +37,7 @@ import ( "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/dex" "github.com/binance-chain/node/plugins/dex/order" + "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/wire" ) diff --git a/common/upgrade/upgrade.go b/common/upgrade/upgrade.go index ed4a95168..13405f593 100644 --- a/common/upgrade/upgrade.go +++ b/common/upgrade/upgrade.go @@ -8,7 +8,6 @@ var Mgr = sdk.UpgradeMgr // bugfix: fix // improvement: (maybe bep ?) const ( - BEP8 = "BEP8" //FIXME placeholder // Galileo Upgrade BEP6 = "BEP6" // https://github.com/binance-chain/BEPs/pull/6 BEP9 = "BEP9" // https://github.com/binance-chain/BEPs/pull/9 @@ -23,6 +22,8 @@ const ( LotSizeOptimization = "LotSizeOptimization" ListingRuleUpgrade = "ListingRuleUpgrade" // Remove restriction that only the owner of base asset can list trading pair FixZeroBalance = "FixZeroBalance" + //FIXME upgrade version placeholder + BEP8 = "BEP8" ) func UpgradeBEP10(before func(), after func()) { diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 0259404ca..68aa73d97 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -3,23 +3,19 @@ package order import ( "errors" "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" "hash/crc32" "strings" "sync" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/binance-chain/node/common/fees" bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/common/utils" me "github.com/binance-chain/node/plugins/dex/matcheng" "github.com/binance-chain/node/plugins/dex/store" dexTypes "github.com/binance-chain/node/plugins/dex/types" - dexUtils "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/wire" ) @@ -100,7 +96,7 @@ func (kp *MiniKeeper) matchAndDistributeTrades(distributeTrade bool, height, tim if distributeTrade { ordNum := 0 - for _, perSymbol := range kp.roundOrders { + for _, perSymbol := range kp.matchedMiniSymbols { ordNum += len(perSymbol) } for i := range tradeOuts { @@ -111,7 +107,7 @@ func (kp *MiniKeeper) matchAndDistributeTrades(distributeTrade bool, height, tim symbolCh := make(chan string, concurrency) producer := func() { - for symbol := range kp.roundOrders { + for _, symbol := range kp.matchedMiniSymbols { symbolCh <- symbol } close(symbolCh) @@ -136,131 +132,6 @@ func (kp *MiniKeeper) matchAndDistributeTrades(distributeTrade bool, height, tim return tradeOuts } -func (kp *MiniKeeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { - orderbook := make([]store.OrderBookLevel, maxLevels) - - i, j := 0, 0 - - if eng, ok := kp.engines[pair]; ok { - // TODO: check considered bucket splitting? - eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { - orderbook[i].BuyPrice = utils.Fixed8(p.Price) - orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) - i++ - }, - func(p *me.PriceLevel) { - orderbook[j].SellPrice = utils.Fixed8(p.Price) - orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) - j++ - }) - } - return orderbook -} - -func (kp *MiniKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { - openOrders := make([]store.OpenOrder, 0) - - for _, order := range kp.allOrders[pair] { - if string(order.Sender.Bytes()) == string(addr.Bytes()) { - openOrders = append( - openOrders, - store.OpenOrder{ - order.Id, - pair, - utils.Fixed8(order.Price), - utils.Fixed8(order.Quantity), - utils.Fixed8(order.CumQty), - order.CreatedHeight, - order.CreatedTimestamp, - order.LastUpdatedHeight, - order.LastUpdatedTimestamp, - }) - } - } - - return openOrders -} - -func (kp *MiniKeeper) GetOrderBooks(maxLevels int) ChangedPriceLevelsMap { - var res = make(ChangedPriceLevelsMap) - for pair, eng := range kp.engines { - buys := make(map[int64]int64) - sells := make(map[int64]int64) - res[pair] = ChangedPriceLevelsPerSymbol{buys, sells} - - // TODO: check considered bucket splitting? - eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { - buys[p.Price] = p.TotalLeavesQty() - }, func(p *me.PriceLevel) { - sells[p.Price] = p.TotalLeavesQty() - }) - } - - return res -} - -func (kp *MiniKeeper) GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel { - if eng, ok := kp.engines[pair]; ok { - return eng.Book.GetPriceLevel(price, side) - } else { - return nil - } -} - -func (kp *MiniKeeper) GetLastTrades(height int64, pair string) ([]me.Trade, int64) { - if eng, ok := kp.engines[pair]; ok { - if eng.LastMatchHeight == height { - return eng.Trades, eng.LastTradePrice - } - } - return nil, 0 -} - -// !!! FOR TEST USE ONLY -func (kp *MiniKeeper) GetLastTradesForPair(pair string) ([]me.Trade, int64) { - if eng, ok := kp.engines[pair]; ok { - return eng.Trades, eng.LastTradePrice - } - return nil, 0 -} - -func (kp *MiniKeeper) ClearOrderBook(pair string) { - if eng, ok := kp.engines[pair]; ok { - eng.Book.Clear() - } -} - -func (kp *MiniKeeper) ClearOrderChanges() { - kp.OrderChanges = kp.OrderChanges[:0] -} - -func (kp *MiniKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { - account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) - newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) - // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. - // they should never happen, there would be a severe bug if happen and we have to cancel all orders when app restarts. - if !newLocked.IsNotNegative() { - panic(fmt.Errorf( - "no enough locked tokens to unlock, oid: %s, newLocked: %s, unlock: %d", - tran.Oid, - newLocked.String(), - tran.unlock)) - } - if tran.unlock < tran.out { - panic(errors.New("unlocked tokens cannot cover the expense")) - } - account.SetLockedCoins(newLocked) - accountCoin := account.GetCoins(). - Plus(sdk.Coins{sdk.NewCoin(tran.inAsset, tran.in)}) - if remain := tran.unlock - tran.out; remain > 0 || !sdk.IsUpgrade(upgrade.FixZeroBalance) { - accountCoin = accountCoin.Plus(sdk.Coins{sdk.NewCoin(tran.outAsset, remain)}) - } - account.SetCoins(accountCoin) - - kp.am.SetAccount(ctx, account) - return nil -} - // override func (kp *MiniKeeper) clearAfterMatch() { for _, symbol := range kp.matchedMiniSymbols { @@ -270,222 +141,6 @@ func (kp *MiniKeeper) clearAfterMatch() { kp.matchedMiniSymbols = make([]string, 0, 256) } -func (kp *MiniKeeper) StoreTradePrices(ctx sdk.Context) { - // TODO: check block height != 0 - if ctx.BlockHeight()%pricesStoreEvery == 0 { - lastTradePrices := make(map[string]int64, len(kp.engines)) - for symbol, engine := range kp.engines { - lastTradePrices[symbol] = engine.LastTradePrice - if _, ok := kp.recentPrices[symbol]; !ok { - kp.recentPrices[symbol] = utils.NewFixedSizedRing(numPricesStored) - } - kp.recentPrices[symbol].Push(engine.LastTradePrice) - } - if len(lastTradePrices) != 0 { - kp.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices) - } - } -} - -func (kp *MiniKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( - types.Fee, map[string]*types.Fee) { - if !sdk.IsUpgrade(upgrade.BEP19) { - return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler) - } - - // use string of the addr as the key since map makes a fast path for string key. - // Also, making the key have same length is also an optimization. - tradeTransfers := make(map[string]TradeTransfers) - // expire fee is fixed, so we count by numbers. - expireTransfers := make(map[string]ExpireTransfers) - // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. - var expireEventType transferEventType - var totalFee types.Fee - for tran := range tranCh { - kp.doTransfer(ctx, &tran) - if !tran.FeeFree() { - addrStr := string(tran.accAddress.Bytes()) - // need a copy of tran as it is reused - tranCp := tran - if tran.IsExpiredWithFee() { - expireEventType = tran.eventType - if _, ok := expireTransfers[addrStr]; !ok { - expireTransfers[addrStr] = ExpireTransfers{&tranCp} - } else { - expireTransfers[addrStr] = append(expireTransfers[addrStr], &tranCp) - } - } else if tran.eventType == eventFilled { - if _, ok := tradeTransfers[addrStr]; !ok { - tradeTransfers[addrStr] = TradeTransfers{&tranCp} - } else { - tradeTransfers[addrStr] = append(tradeTransfers[addrStr], &tranCp) - } - } - } else if tran.IsExpire() { - if postAllocateHandler != nil { - postAllocateHandler(tran) - } - } - } - - feesPerAcc := make(map[string]*types.Fee) - for addrStr, trans := range tradeTransfers { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, kp.engines) - if !fees.IsEmpty() { - feesPerAcc[addrStr] = &fees - acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) - kp.am.SetAccount(ctx, acc) - totalFee.AddFee(fees) - } - } - - for addrStr, trans := range expireTransfers { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - - fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, kp.engines, postAllocateHandler) - if !fees.IsEmpty() { - if _, ok := feesPerAcc[addrStr]; ok { - feesPerAcc[addrStr].AddFee(fees) - } else { - feesPerAcc[addrStr] = &fees - } - acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) - kp.am.SetAccount(ctx, acc) - totalFee.AddFee(fees) - } - } - return totalFee, feesPerAcc -} - -// DEPRECATED -func (kp *MiniKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( - types.Fee, map[string]*types.Fee) { - // use string of the addr as the key since map makes a fast path for string key. - // Also, making the key have same length is also an optimization. - tradeInAsset := make(map[string]*sortedAsset) - // expire fee is fixed, so we count by numbers. - expireInAsset := make(map[string]*sortedAsset) - // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. - var expireEventType transferEventType - var totalFee types.Fee - for tran := range tranCh { - kp.doTransfer(ctx, &tran) - if !tran.FeeFree() { - addrStr := string(tran.accAddress.Bytes()) - if tran.IsExpiredWithFee() { - expireEventType = tran.eventType - fees, ok := expireInAsset[addrStr] - if !ok { - fees = &sortedAsset{} - expireInAsset[addrStr] = fees - } - fees.addAsset(tran.inAsset, 1) - } else if tran.eventType == eventFilled { - fees, ok := tradeInAsset[addrStr] - if !ok { - fees = &sortedAsset{} - tradeInAsset[addrStr] = fees - } - // no possible to overflow, for tran.in == otherSide.tran.out <= TotalSupply(otherSide.tran.outAsset) - fees.addAsset(tran.inAsset, tran.in) - } - } - if postAllocateHandler != nil { - postAllocateHandler(tran) - } - } - - feesPerAcc := make(map[string]*types.Fee) - collectFee := func(assetsMap map[string]*sortedAsset, calcFeeAndDeduct func(acc sdk.Account, in sdk.Coin) types.Fee) { - for addrStr, assets := range assetsMap { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - - var fees types.Fee - if exists, ok := feesPerAcc[addrStr]; ok { - fees = *exists - } - if assets.native != 0 { - fee := calcFeeAndDeduct(acc, sdk.NewCoin(types.NativeTokenSymbol, assets.native)) - fees.AddFee(fee) - totalFee.AddFee(fee) - } - for _, asset := range assets.tokens { - fee := calcFeeAndDeduct(acc, asset) - fees.AddFee(fee) - totalFee.AddFee(fee) - } - if !fees.IsEmpty() { - feesPerAcc[addrStr] = &fees - kp.am.SetAccount(ctx, acc) - } - } - } - collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { - fee := kp.FeeManager.CalcTradeFee(acc.GetCoins(), in, kp.engines) - acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - return fee - }) - collectFee(expireInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { - var i int64 = 0 - var fees types.Fee - for ; i < in.Amount; i++ { - fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, kp.engines) - acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - fees.AddFee(fee) - } - return fees - }) - return totalFee, feesPerAcc -} - -func (kp *MiniKeeper) allocateAndCalcFee( - ctx sdk.Context, - tradeOuts []chan Transfer, - postAlloTransHandler TransferHandler, -) types.Fee { - concurrency := len(tradeOuts) - var wg sync.WaitGroup - wg.Add(concurrency) - feesPerCh := make([]types.Fee, concurrency) - feesPerAcc := make([]map[string]*types.Fee, concurrency) - allocatePerCh := func(index int, tranCh <-chan Transfer) { - defer wg.Done() - fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) - feesPerCh[index].AddFee(fee) - feesPerAcc[index] = feeByAcc - } - - for i, tradeTranCh := range tradeOuts { - go allocatePerCh(i, tradeTranCh) - } - wg.Wait() - totalFee := types.Fee{} - for i := 0; i < concurrency; i++ { - totalFee.AddFee(feesPerCh[i]) - } - if kp.CollectOrderInfoForPublish { - for _, m := range feesPerAcc { - for k, v := range m { - kp.updateRoundOrderFee(k, *v) - } - } - } - return totalFee -} - -// MatchAll will only concurrently match but do not allocate into accounts -func (kp *MiniKeeper) MatchAll(height, timestamp int64) { - tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp, false) //only match - if tradeOuts == nil { - kp.logger.Info("No order comes in for the block") - } - kp.clearAfterMatch() -} - // MatchAndAllocateAll() is concurrently matching and allocating across // all the symbols' order books, among all the clients // Return whether match has been done in this height @@ -502,85 +157,6 @@ func (kp *MiniKeeper) MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler kp.clearAfterMatch() } -func (kp *MiniKeeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { - size := len(kp.allOrders) - if size == 0 { - kp.logger.Info("No orders to expire") - return nil - } - - // TODO: make effectiveDays configurable - const effectiveDays = 3 - expireHeight, err := kp.GetBreatheBlockHeight(ctx, blockTime, effectiveDays) - if err != nil { - // breathe block not found, that should only happens in in the first three days, just log it and ignore. - kp.logger.Info(err.Error()) - return nil - } - - channelSize := size >> kp.poolSize - concurrency := 1 << kp.poolSize - if size%concurrency != 0 { - channelSize += 1 - } - - transferChs := make([]chan Transfer, concurrency) - for i := range transferChs { - // TODO: channelSize is enough for buffer to facilitate ? - transferChs[i] = make(chan Transfer, channelSize*2) - } - - expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { - engine.Book.RemoveOrders(expireHeight, side, func(ord me.OrderPart) { - // gen transfer - if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { - h := channelHash(ordMsg.Sender, concurrency) - transferChs[h] <- TransferFromExpired(ord, *ordMsg) - // delete from allOrders - delete(orders, ord.Id) - } else { - kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) - } - }) - } - - symbolCh := make(chan string, concurrency) - utils.ConcurrentExecuteAsync(concurrency, - func() { - for symbol := range kp.allOrders { - symbolCh <- symbol - } - close(symbolCh) - }, func() { - for symbol := range symbolCh { - engine := kp.engines[symbol] - orders := kp.allOrders[symbol] - expire(orders, engine, me.BUYSIDE) - expire(orders, engine, me.SELLSIDE) - } - }, func() { - for _, transferCh := range transferChs { - close(transferCh) - } - }) - - return transferChs -} - -func (kp *MiniKeeper) ExpireOrders( - ctx sdk.Context, - blockTime time.Time, - postAlloTransHandler TransferHandler, -) { - transferChs := kp.expireOrders(ctx, blockTime) - if transferChs == nil { - return - } - - totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAlloTransHandler) - fees.Pool.AddAndCommitFee("EXPIRE", totalFee) -} - // used by state sync to clear memory order book after we synced latest breathe block //TODO check usage func (kp *MiniKeeper) ClearOrders() { @@ -588,30 +164,6 @@ func (kp *MiniKeeper) ClearOrders() { kp.matchedMiniSymbols = make([]string, 0, 256) } -func (kp *MiniKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) { - _, ok := kp.engines[symbol] - if !ok { - kp.logger.Error("delist symbol does not exist", "symbol", symbol) - return - } - - transferChs := kp.expireAllOrders(ctx, symbol) - if transferChs != nil { - totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAllocTransHandler) - fees.Pool.AddAndCommitFee(fmt.Sprintf("DELIST_%s", symbol), totalFee) - } - - delete(kp.engines, symbol) - delete(kp.allOrders, symbol) - delete(kp.recentPrices, symbol) - - baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol) - err := kp.PairMapper.DeleteTradingPair(ctx, baseAsset, quoteAsset) - if err != nil { - kp.logger.Error("delete trading pair error", "err", err.Error()) - } -} - //override func (kp *MiniKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { // trading pair against native token should exist if quote token is not native token diff --git a/plugins/dex/utils/pair.go b/plugins/dex/utils/pair.go index f5dd5050c..58dd11b1b 100644 --- a/plugins/dex/utils/pair.go +++ b/plugins/dex/utils/pair.go @@ -2,11 +2,11 @@ package utils import ( "fmt" - "github.com/binance-chain/node/common/types" "math" "math/big" "strings" + "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/utils" ) diff --git a/plugins/miniTokens/issue/handler.go b/plugins/miniTokens/issue/handler.go index d1c0941ae..5e145de52 100644 --- a/plugins/miniTokens/issue/handler.go +++ b/plugins/miniTokens/issue/handler.go @@ -3,7 +3,6 @@ package issue import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" "reflect" "strings" @@ -13,6 +12,7 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/minitokens/store" ) diff --git a/plugins/miniTokens/issue/msg.go b/plugins/miniTokens/issue/msg.go index de91629f2..c9631725e 100644 --- a/plugins/miniTokens/issue/msg.go +++ b/plugins/miniTokens/issue/msg.go @@ -3,7 +3,9 @@ package issue import ( "encoding/json" "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/binance-chain/node/common/types" ) diff --git a/plugins/miniTokens/route.go b/plugins/miniTokens/route.go index 771c60e54..972d50886 100644 --- a/plugins/miniTokens/route.go +++ b/plugins/miniTokens/route.go @@ -1,12 +1,13 @@ package minitokens import ( - "github.com/binance-chain/node/plugins/minitokens/issue" - "github.com/binance-chain/node/plugins/minitokens/seturi" - "github.com/binance-chain/node/plugins/minitokens/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + + "github.com/binance-chain/node/plugins/minitokens/issue" + "github.com/binance-chain/node/plugins/minitokens/seturi" + "github.com/binance-chain/node/plugins/minitokens/store" ) func Routes(tokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) map[string]sdk.Handler { diff --git a/plugins/miniTokens/seturi/handler.go b/plugins/miniTokens/seturi/handler.go index 31afe50da..d35927bea 100644 --- a/plugins/miniTokens/seturi/handler.go +++ b/plugins/miniTokens/seturi/handler.go @@ -2,12 +2,14 @@ package seturi import ( "fmt" + "reflect" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/minitokens/store" - sdk "github.com/cosmos/cosmos-sdk/types" - "reflect" - "strings" ) func NewHandler(tokenMapper store.MiniTokenMapper) sdk.Handler { diff --git a/plugins/miniTokens/seturi/msg.go b/plugins/miniTokens/seturi/msg.go index 06a86e8ba..ab8229b96 100644 --- a/plugins/miniTokens/seturi/msg.go +++ b/plugins/miniTokens/seturi/msg.go @@ -3,8 +3,10 @@ package seturi import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" ) const SetURIRoute = "miniTokensSetURI" diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index b90052b5e..589749e14 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -1,7 +1,6 @@ package param import ( - "github.com/binance-chain/node/plugins/dex/listmini" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/gov" @@ -13,6 +12,7 @@ import ( "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/account" "github.com/binance-chain/node/plugins/dex/list" + "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/plugins/dex/order" miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" miniURI "github.com/binance-chain/node/plugins/minitokens/seturi" diff --git a/plugins/tokens/client/cli/issue.go b/plugins/tokens/client/cli/issue.go index 3a4e7b040..e8db3fb92 100644 --- a/plugins/tokens/client/cli/issue.go +++ b/plugins/tokens/client/cli/issue.go @@ -1,10 +1,11 @@ package commands import ( + "strings" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" - "strings" "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index 110f202d2..505a60c61 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -4,9 +4,9 @@ import ( "bytes" "encoding/hex" "fmt" - "github.com/binance-chain/node/common/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/binance-chain/node/common/types" ) func NewHandler(kp Keeper) sdk.Handler { diff --git a/plugins/tokens/timelock/handler.go b/plugins/tokens/timelock/handler.go index aecb9d773..2231e318b 100644 --- a/plugins/tokens/timelock/handler.go +++ b/plugins/tokens/timelock/handler.go @@ -2,10 +2,11 @@ package timelock import ( "fmt" - "github.com/binance-chain/node/common/types" "time" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" ) func NewHandler(keeper Keeper) sdk.Handler { From b153299a5fbb2ef2b741cec60dc44995274d5602 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 15 Apr 2020 16:18:49 +0800 Subject: [PATCH 12/96] refactor mini_keeper --- app/app.go | 4 +- app/apptest/ordertx_test.go | 4 +- app/pub/helpers.go | 2 +- app_test/abci_open_orders_test.go | 2 +- common/fees/pool.go | 4 + plugins/dex/order/keeper.go | 48 +++++---- plugins/dex/order/keeper_recovery.go | 2 +- plugins/dex/order/keeper_test.go | 6 +- plugins/dex/order/mini_keeper.go | 145 ++++----------------------- plugins/dex/order/symbol_selector.go | 112 +++++++++++++++++++++ 10 files changed, 169 insertions(+), 160 deletions(-) create mode 100644 plugins/dex/order/symbol_selector.go diff --git a/app/app.go b/app/app.go index 6c9860f1c..95649e3eb 100644 --- a/app/app.go +++ b/app/app.go @@ -560,8 +560,8 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexMiniTokenKeeper, ctx, isBreatheBlock) } else { //todo parallel run, extract fees.Pool.AddAndCommitFee("MATCH", totalFee) - app.DexKeeper.MatchAndAllocateAll(ctx, nil, isBreatheBlock) - app.DexMiniTokenKeeper.MatchAndAllocateAll(ctx, nil, isBreatheBlock) + app.DexKeeper.MatchAndAllocateSymbols(ctx, nil, isBreatheBlock) + app.DexMiniTokenKeeper.MatchAndAllocateSymbols(ctx, nil, isBreatheBlock) } } diff --git a/app/apptest/ordertx_test.go b/app/apptest/ordertx_test.go index 337863528..04caa6149 100644 --- a/app/apptest/ordertx_test.go +++ b/app/apptest/ordertx_test.go @@ -199,7 +199,7 @@ func Test_Match(t *testing.T) { buys, sells := getOrderBook("BTC-000_BNB") assert.Equal(4, len(buys)) assert.Equal(3, len(sells)) - testApp.DexKeeper.MatchAndAllocateAll(ctx, nil, false) + testApp.DexKeeper.MatchAndAllocateSymbols(ctx, nil, false) buys, sells = getOrderBook("BTC-000_BNB") assert.Equal(0, len(buys)) assert.Equal(3, len(sells)) @@ -254,7 +254,7 @@ func Test_Match(t *testing.T) { assert.Equal(4, len(buys)) assert.Equal(3, len(sells)) - testApp.DexKeeper.MatchAndAllocateAll(ctx, nil, false) + testApp.DexKeeper.MatchAndAllocateSymbols(ctx, nil, false) buys, sells = getOrderBook("ETH-000_BNB") t.Logf("buys: %v", buys) t.Logf("sells: %v", sells) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 00e880f1f..5a2f9d69e 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -284,7 +284,7 @@ func MatchAndAllocateAllForPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Co } } - dexKeeper.MatchAndAllocateAll(ctx, postAlloTransHandler, matchAllMiniSymbols) + dexKeeper.MatchAndAllocateSymbols(ctx, postAlloTransHandler, matchAllMiniSymbols) close(iocExpireFeeHolderCh) tradeIdx := 0 diff --git a/app_test/abci_open_orders_test.go b/app_test/abci_open_orders_test.go index 709bf29a6..098251f80 100644 --- a/app_test/abci_open_orders_test.go +++ b/app_test/abci_open_orders_test.go @@ -38,7 +38,7 @@ func Test_Success(t *testing.T) { ctx = ctx.WithBlockHeader(abci.Header{Height: 101, Time: time.Unix(1, 0)}) ctx = ctx.WithBlockHeight(101) - keeper.MatchAndAllocateAll(ctx, nil, false) + keeper.MatchAndAllocateSymbols(ctx, nil, false) openOrders = issueMustSuccessQuery(pair, buyer, assert) require.Len(openOrders, 1) diff --git a/common/fees/pool.go b/common/fees/pool.go index 5192af6a9..baec4555b 100644 --- a/common/fees/pool.go +++ b/common/fees/pool.go @@ -2,6 +2,7 @@ package fees import ( "fmt" + "sync" "github.com/binance-chain/node/common/types" ) @@ -12,6 +13,7 @@ var Pool pool = newPool() type pool struct { fees map[string]types.Fee // TxHash -> fee committedFees types.Fee + sync.Mutex } func newPool() pool { @@ -26,6 +28,8 @@ func (p *pool) AddFee(txHash string, fee types.Fee) { } func (p *pool) AddAndCommitFee(txHash string, fee types.Fee) { + p.Lock() + defer p.Unlock() p.fees[txHash] = fee p.committedFees.AddFee(fee) } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index d6e6ac950..dde6cb5f1 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -59,8 +59,8 @@ type DexOrderKeeper interface { ClearOrderBook(pair string) ClearOrderChanges() StoreTradePrices(ctx sdk.Context) - MatchAll(height, timestamp int64) - MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) + MatchSymbols(height, timestamp int64) + MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) @@ -109,6 +109,8 @@ type Keeper struct { FeeManager *FeeManager CollectOrderInfoForPublish bool logger tmlog.Logger + symbolSelector SymbolSelector + clearAfterMatch func(*Keeper) } func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { @@ -138,6 +140,8 @@ func NewKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store. FeeManager: NewFeeManager(cdc, key, logger), CollectOrderInfoForPublish: collectOrderInfoForPublish, logger: logger, + symbolSelector: &BEP2SymbolSelector{}, + clearAfterMatch: clearAfterMatchBEP2, } } @@ -459,21 +463,18 @@ func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { } // please note if distributeTrade this method will work in async mode, otherwise in sync mode. -func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64) ([]chan Transfer) { - size := len(kp.roundOrders) - // size is the number of pairs that have new orders, i.e. it should call match() - if size == 0 { - kp.logger.Info("No new orders for any pair, give up matching") +func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64, symbolsToMatch []string) []chan Transfer { + if len(symbolsToMatch) == 0 { + kp.logger.Info("No symbols to match in the block") return nil } - concurrency := 1 << kp.poolSize tradeOuts := make([]chan Transfer, concurrency) if distributeTrade { ordNum := 0 - for _, perSymbol := range kp.roundOrders { - ordNum += len(perSymbol) + for _, symbol := range symbolsToMatch { + ordNum += len(kp.roundOrders[symbol]) } for i := range tradeOuts { //assume every new order would have 2 trades and generate 4 transfer @@ -483,7 +484,7 @@ func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timesta symbolCh := make(chan string, concurrency) producer := func() { - for symbol := range kp.roundOrders { + for _, symbol := range symbolsToMatch { symbolCh <- symbol } close(symbolCh) @@ -633,7 +634,8 @@ func (kp *Keeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { return nil } -func (kp *Keeper) clearAfterMatch() { +func clearAfterMatchBEP2(kp *Keeper) { + kp.logger.Debug("clearAfterMatchBEP2...") kp.roundOrders = make(map[string][]string, 256) kp.roundIOCOrders = make(map[string][]string, 256) } @@ -845,29 +847,31 @@ func (kp *Keeper) allocateAndCalcFee( return totalFee } -// MatchAll will only concurrently match but do not allocate into accounts -func (kp *Keeper) MatchAll(height, timestamp int64) { - tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp) //only match +func (kp *Keeper) MatchSymbols(height, timestamp int64) { + symbolsToMatch := kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, timestamp, false) + kp.logger.Debug("symbols to match", "symbols", symbolsToMatch) + tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp, symbolsToMatch) //only match if tradeOuts == nil { kp.logger.Info("No order comes in for the block") } - kp.clearAfterMatch() + kp.clearAfterMatch(kp) } -// MatchAndAllocateAll() is concurrently matching and allocating across +// MatchAndAllocateSymbols() is concurrently matching and allocating across // all the symbols' order books, among all the clients // Return whether match has been done in this height -func (kp *Keeper) MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { +func (kp *Keeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(kp.roundOrders)) timestamp := ctx.BlockHeader().Time.UnixNano() - tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp) + + symbolsToMatch := kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, ctx.BlockHeader().Height, timestamp, false) + tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp, symbolsToMatch) if tradeOuts == nil { kp.logger.Info("No order comes in for the block") } - totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) - fees.Pool.AddAndCommitFee("MATCH", totalFee) - kp.clearAfterMatch() + fees.Pool.AddAndCommitFee("MATCH_MINI", totalFee) + kp.clearAfterMatch(kp) } func (kp *Keeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 22f299e86..7ebfeef49 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -245,7 +245,7 @@ func (kp *Keeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, state } } logger.Info("replayed all tx. Starting match", "height", height) - kp.MatchAll(height, t) //no need to check result + kp.MatchSymbols(height, t) //no need to check result } func (kp *Keeper) ReplayOrdersFromBlock(ctx sdk.Context, bc *tmstore.BlockStore, stateDb dbm.DB, lastHeight, breatheHeight int64, diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index dd1db6f0c..dda2c32e7 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -275,7 +275,7 @@ func TestKeeper_SnapShotAndLoadAfterMatch(t *testing.T) { assert.Equal(3, len(keeper.allOrders["XYZ-000_BNB"])) assert.Equal(1, len(keeper.engines)) - keeper.MatchAll(42, 0) + keeper.MatchSymbols(42, 0) _, err := keeper.SnapShotOrderBook(ctx, 43) assert.Nil(err) keeper.MarkBreatheBlock(ctx, 43, time.Now()) @@ -716,7 +716,7 @@ func TestOpenOrders_AfterMatch(t *testing.T) { assert.Equal(1, len(res)) // match existing two orders - keeper.MatchAll(43, 86) + keeper.MatchSymbols(43, 86) // after match, the original buy order's cumQty and latest updated fields should be updated res = keeper.GetOpenOrders("NNB_BNB", zc) @@ -750,7 +750,7 @@ func TestOpenOrders_AfterMatch(t *testing.T) { assert.Equal(int64(88), res[0].LastUpdatedTimestamp) // match existing two orders - keeper.MatchAll(44, 88) + keeper.MatchSymbols(44, 88) // after match, all orders should be closed res = keeper.GetOpenOrders("NNB_BNB", zc) diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 68aa73d97..6bd5f2a7c 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -3,13 +3,6 @@ package order import ( "errors" "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "hash/crc32" - "strings" - "sync" - - "github.com/binance-chain/node/common/fees" bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/utils" @@ -17,6 +10,10 @@ import ( "github.com/binance-chain/node/plugins/dex/store" dexTypes "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/wire" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "strings" + "sync" ) const ( @@ -26,9 +23,7 @@ const ( //order keeper for mini-token type MiniKeeper struct { - Keeper //use dex order keeper as base keeper - matchedMiniSymbols []string //mini token pairs matched in this round - miniSymbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin + Keeper //use dex order keeper as base keeper } var _ DexOrderKeeper = &MiniKeeper{} @@ -55,9 +50,10 @@ func NewMiniKeeper(dexMiniKey sdk.StoreKey, am auth.AccountKeeper, miniPairMappe cdc: cdc, FeeManager: NewFeeManager(cdc, dexMiniKey, logger), CollectOrderInfoForPublish: collectOrderInfoForPublish, - logger: logger}, - make([]string, 0, 256), - make(map[string]uint32, 256), + logger: logger, + symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}, + clearAfterMatch: clearAfterMatchMini}, + } } @@ -65,103 +61,26 @@ func NewMiniKeeper(dexMiniKey sdk.StoreKey, am auth.AccountKeeper, miniPairMappe func (kp *MiniKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { eng := kp.Keeper.AddEngine(pair) symbol := strings.ToUpper(pair.GetSymbol()) - kp.miniSymbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) + kp.symbolSelector.AddSymbolHash(symbol) return eng } -// override -// please note if distributeTrade this method will work in async mode, otherwise in sync mode. -func (kp *MiniKeeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64, matchAllMiniSymbols bool) ([]chan Transfer) { - size := len(kp.roundOrders) - // size is the number of pairs that have new orders, i.e. it should call match() - if size == 0 { - kp.logger.Info("No new orders for any pair, give up matching") - return nil - } - - concurrency := 1 << kp.poolSize - tradeOuts := make([]chan Transfer, concurrency) - - if matchAllMiniSymbols { - for symbol := range kp.roundOrders { - kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) - } - } else { - kp.selectMiniSymbolsToMatch(height, func(miniSymbols map[string]struct{}) { - for symbol := range miniSymbols { - kp.matchedMiniSymbols = append(kp.matchedMiniSymbols, symbol) - } - }) - } - - if distributeTrade { - ordNum := 0 - for _, perSymbol := range kp.matchedMiniSymbols { - ordNum += len(perSymbol) - } - for i := range tradeOuts { - //assume every new order would have 2 trades and generate 4 transfer - tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) - } - } - - symbolCh := make(chan string, concurrency) - producer := func() { - for _, symbol := range kp.matchedMiniSymbols { - symbolCh <- symbol - } - close(symbolCh) - } - matchWorker := func() { - i := 0 - for symbol := range symbolCh { - i++ - kp.matchAndDistributeTradesForSymbol(symbol, height, timestamp, kp.allOrders[symbol], distributeTrade, tradeOuts) - } - } - - if distributeTrade { - utils.ConcurrentExecuteAsync(concurrency, producer, matchWorker, func() { - for _, tradeOut := range tradeOuts { - close(tradeOut) - } - }) - } else { - utils.ConcurrentExecuteSync(concurrency, producer, matchWorker) - } - return tradeOuts -} - -// override -func (kp *MiniKeeper) clearAfterMatch() { - for _, symbol := range kp.matchedMiniSymbols { +func clearAfterMatchMini(kp *Keeper) { + kp.logger.Debug("clearAfterMatchMini...") + for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { delete(kp.roundOrders, symbol) delete(kp.roundIOCOrders, symbol) } - kp.matchedMiniSymbols = make([]string, 0, 256) -} - -// MatchAndAllocateAll() is concurrently matching and allocating across -// all the symbols' order books, among all the clients -// Return whether match has been done in this height -func (kp *MiniKeeper) MatchAndAllocateAll(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { - kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(kp.roundOrders)) - timestamp := ctx.BlockHeader().Time.UnixNano() - tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp, matchAllSymbols) - if tradeOuts == nil { - kp.logger.Info("No order comes in for the block") - } - - totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) - fees.Pool.AddAndCommitFee("MATCH", totalFee) - kp.clearAfterMatch() + emptyRoundMatchSymbols := make([]string, 0, 256) + kp.symbolSelector.SetRoundMatchSymbol(emptyRoundMatchSymbols) } // used by state sync to clear memory order book after we synced latest breathe block //TODO check usage func (kp *MiniKeeper) ClearOrders() { kp.Keeper.ClearOrders() - kp.matchedMiniSymbols = make([]string, 0, 256) + emptyRoundMatchSymbols := make([]string, 0, 256) + kp.symbolSelector.SetRoundMatchSymbol(emptyRoundMatchSymbols) } //override @@ -202,36 +121,6 @@ func (kp *MiniKeeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsse return nil } -func (kp *MiniKeeper) selectMiniSymbolsToMatch(height int64, postSelect func(map[string]struct{})) { - symbolsToMatch := make(map[string]struct{}, 256) - selectActiveMiniSymbols(&symbolsToMatch, &kp.roundOrders, defaultActiveMiniSymbolCount) - selectMiniSymbolsRoundRobin(&symbolsToMatch, &kp.miniSymbolsHash, height) - postSelect(symbolsToMatch) -} - -func selectActiveMiniSymbols(symbolsToMatch *map[string]struct{}, roundOrdersMini *map[string][]string, k int) { - //use quick select to select top k symbols - symbolOrderNumsSlice := make([]*SymbolWithOrderNumber, 0, len(*roundOrdersMini)) - i := 0 - for symbol, orders := range *roundOrdersMini { - symbolOrderNumsSlice[i] = &SymbolWithOrderNumber{symbol, len(orders)} - } - topKSymbolOrderNums := findTopKLargest(symbolOrderNumsSlice, k) - - for _, selected := range topKSymbolOrderNums { - (*symbolsToMatch)[selected.symbol] = struct{}{} - } -} - -func selectMiniSymbolsRoundRobin(symbolsToMatch *map[string]struct{}, miniSymbolsHash *map[string]uint32, height int64) { - m := height % defaultMiniBlockMatchInterval - for symbol, symbolHash := range *miniSymbolsHash { - if int64(symbolHash%defaultMiniBlockMatchInterval) == m { - (*symbolsToMatch)[symbol] = struct{}{} - } - } -} - // override func (kp *MiniKeeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { diff --git a/plugins/dex/order/symbol_selector.go b/plugins/dex/order/symbol_selector.go new file mode 100644 index 000000000..9504fa020 --- /dev/null +++ b/plugins/dex/order/symbol_selector.go @@ -0,0 +1,112 @@ +package order + +import ( + "hash/crc32" +) + +type SymbolSelector interface { + SelectSymbolsToMatch(roundOrders map[string][]string, height, timestamp int64, matchAllSymbols bool) []string + AddSymbolHash(symbol string) + GetRoundMatchSymbol() *[]string + SetRoundMatchSymbol([]string) +} + +type BEP2SymbolSelector struct { +} + +var _ SymbolSelector = &BEP2SymbolSelector{} + +func (bss *BEP2SymbolSelector) AddSymbolHash(symbol string) { + panic("unsupported method") +} + +func (bss *BEP2SymbolSelector) SetRoundMatchSymbol([]string) { + panic("unsupported method") +} + +func (bss *BEP2SymbolSelector) GetRoundMatchSymbol() *[]string { + panic("unsupported method") +} + +func (bss *BEP2SymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]string, height, timestamp int64, matchAllSymbols bool) []string { + size := len(roundOrders) + if size == 0 { + return make([]string, 0) + } + symbolsToMatch := make([]string, 0, 256) + for symbol := range roundOrders { + symbolsToMatch = append(symbolsToMatch, symbol) + } + return symbolsToMatch +} + +type MiniSymbolSelector struct { + miniSymbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin + matchedMiniSymbols []string //mini token pairs matched in this round +} + +var _ SymbolSelector = &MiniSymbolSelector{} + + +func (mss *MiniSymbolSelector) GetRoundMatchSymbol() *[]string { + return &mss.matchedMiniSymbols +} + +func (mss *MiniSymbolSelector) AddSymbolHash(symbol string) { + mss.miniSymbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) +} + +func (mss *MiniSymbolSelector) SetRoundMatchSymbol(symbols []string) { + mss.matchedMiniSymbols = symbols +} + +func (mss *MiniSymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]string, height, timestamp int64, matchAllSymbols bool) []string { + size := len(roundOrders) + if size == 0 { + return make([]string, 0) + } + symbolsToMatch := make([]string, 0, 256) + if matchAllSymbols { + for symbol := range roundOrders { + symbolsToMatch = append(symbolsToMatch, symbol) + } + } else { + selectMiniSymbolsToMatch(roundOrders, mss.miniSymbolsHash, height, func(miniSymbols map[string]struct{}) { + for symbol := range miniSymbols { + symbolsToMatch = append(symbolsToMatch, symbol) + } + }) + } + mss.matchedMiniSymbols = symbolsToMatch + return symbolsToMatch +} + +func selectMiniSymbolsToMatch(roundOrders map[string][]string, miniSymbolsHash map[string]uint32, height int64, postSelect func(map[string]struct{})) { + symbolsToMatch := make(map[string]struct{}, 256) + selectActiveMiniSymbols(&symbolsToMatch, &roundOrders, defaultActiveMiniSymbolCount) + selectMiniSymbolsRoundRobin(&symbolsToMatch, &miniSymbolsHash, height) + postSelect(symbolsToMatch) +} + +func selectActiveMiniSymbols(symbolsToMatch *map[string]struct{}, roundOrdersMini *map[string][]string, k int) { + //use quick select to select top k symbols + symbolOrderNumsSlice := make([]*SymbolWithOrderNumber, 0, len(*roundOrdersMini)) + i := 0 + for symbol, orders := range *roundOrdersMini { + symbolOrderNumsSlice[i] = &SymbolWithOrderNumber{symbol, len(orders)} + } + topKSymbolOrderNums := findTopKLargest(symbolOrderNumsSlice, k) + + for _, selected := range topKSymbolOrderNums { + (*symbolsToMatch)[selected.symbol] = struct{}{} + } +} + +func selectMiniSymbolsRoundRobin(symbolsToMatch *map[string]struct{}, miniSymbolsHash *map[string]uint32, height int64) { + m := height % defaultMiniBlockMatchInterval + for symbol, symbolHash := range *miniSymbolsHash { + if int64(symbolHash%defaultMiniBlockMatchInterval) == m { + (*symbolsToMatch)[symbol] = struct{}{} + } + } +} From abae60ccb27a02c875417eff2d7c56d636c89bda Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sun, 26 Apr 2020 17:17:57 +0800 Subject: [PATCH 13/96] change maxTotalSupply to tokenType for mini token --- common/types/mini_token.go | 88 +++++++++++++++++--------- plugins/dex/order/keeper.go | 6 +- plugins/dex/order/mini_keeper.go | 5 +- plugins/miniTokens/client/cli/issue.go | 29 +++++---- plugins/miniTokens/issue/handler.go | 21 +----- plugins/miniTokens/issue/msg.go | 56 ++++++++-------- plugins/param/plugin.go | 26 ++++---- plugins/param/types/types.go | 4 +- plugins/tokens/client/cli/issue.go | 2 +- plugins/tokens/issue/handler.go | 8 +-- plugins/tokens/issue/handler_test.go | 4 +- plugins/tokens/issue/msg.go | 4 +- 12 files changed, 135 insertions(+), 118 deletions(-) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 5546f8531..e4877cc7a 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -13,32 +13,62 @@ import ( ) const ( - MiniTokenSymbolMaxLen = 8 - MiniTokenSymbolMinLen = 3 - MiniTokenSymbolSuffixLen = 4 // probably enough. if it collides (unlikely) the issuer can just use another tx. + MiniTokenSymbolMaxLen = 8 + MiniTokenSymbolMinLen = 3 + MiniTokenSymbolSuffixLen = 4 // probably enough. if it collides (unlikely) the issuer can just use another tx. MiniTokenSymbolTxHashSuffixLen = 3 // probably enough. if it collides (unlikely) the issuer can just use another tx. - MiniTokenSymbolMSuffix = "M" + MiniTokenSymbolMSuffix = "M" - MiniTokenDecimals int8 = 8 - MiniTokenMinTotalSupply int64 = 100000000 // 1 with 8 decimal digits - MiniTokenMaxTotalSupplyUpperBound int64 = 10000000000000 // 100k with 8 decimal digits + MiniTokenMinTotalSupply int64 = 100000000 // 1 with 8 decimal digits + MiniTokenSupplyUpperBound int64 = 10000000000000 // 100k with 8 decimal digits + TinyTokenSupplyUpperBound int64 = 1000000000000 + MaxTokenURILength = 2048 - MiniTokenSupplyRange1UpperBound int64 = 1000000000000 - MaxTokenURILength = 2048 + TinyRangeType SupplyRangeType = 1 + MiniRangeType SupplyRangeType = 2 ) +type SupplyRangeType int8 + +func (t SupplyRangeType) UpperBound() int64 { + switch t { + case TinyRangeType: + return TinyTokenSupplyUpperBound + case MiniRangeType: + return MiniTokenSupplyUpperBound + default: + return -1 + } +} + +func (t SupplyRangeType) String() string { + switch t { + case TinyRangeType: + return "Tiny" + case MiniRangeType: + return "Mini" + default: + return "Unknown" + } +} + +var SupplyRange = struct { + TINY SupplyRangeType + MINI SupplyRangeType +}{MiniRangeType, TinyRangeType} + type MiniToken struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - OrigSymbol string `json:"original_symbol"` - MaxTotalSupply utils.Fixed8 `json:"max_total_supply"` - TotalSupply utils.Fixed8 `json:"total_supply"` - Owner sdk.AccAddress `json:"owner"` - Mintable bool `json:"mintable"` - TokenURI string `json:"token_uri"` //TODO set max length + Name string `json:"name"` + Symbol string `json:"symbol"` + OrigSymbol string `json:"original_symbol"` + TokenType SupplyRangeType `json:"token_type"` + TotalSupply utils.Fixed8 `json:"total_supply"` + Owner sdk.AccAddress `json:"owner"` + Mintable bool `json:"mintable"` + TokenURI string `json:"token_uri"` //TODO set max length } -func NewMiniToken(name, symbol string, maxTotalSupply int64, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken, error) { +func NewMiniToken(name, symbol string, supplyRangeType int8, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken, error) { // double check that the symbol is suffixed if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { return nil, err @@ -48,18 +78,18 @@ func NewMiniToken(name, symbol string, maxTotalSupply int64, totalSupply int64, return nil, err } return &MiniToken{ - Name: name, - Symbol: symbol, - OrigSymbol: parts[0], - MaxTotalSupply: utils.Fixed8(maxTotalSupply), - TotalSupply: utils.Fixed8(totalSupply), - Owner: owner, - Mintable: mintable, - TokenURI: tokenURI, + Name: name, + Symbol: symbol, + OrigSymbol: parts[0], + TokenType: SupplyRangeType(supplyRangeType), + TotalSupply: utils.Fixed8(totalSupply), + Owner: owner, + Mintable: mintable, + TokenURI: tokenURI, }, nil } -func IsMiniTokenSymbol(symbol string) bool{ +func IsMiniTokenSymbol(symbol string) bool { if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { return false } @@ -68,8 +98,8 @@ func IsMiniTokenSymbol(symbol string) bool{ func (token *MiniToken) IsOwner(addr sdk.AccAddress) bool { return bytes.Equal(token.Owner, addr) } func (token MiniToken) String() string { - return fmt.Sprintf("{Name: %v, Symbol: %v, MaxTotalSupply: %v, TotalSupply: %v, Owner: %X, Mintable: %v, TokenURI: %v}", - token.Name, token.Symbol, token.MaxTotalSupply, token.TotalSupply, token.Owner, token.Mintable, token.TokenURI) + return fmt.Sprintf("{Name: %v, Symbol: %v, TokenType: %v, TotalSupply: %v, Owner: %X, Mintable: %v, TokenURI: %v}", + token.Name, token.Symbol, token.TokenType, token.TotalSupply, token.Owner, token.Mintable, token.TokenURI) } // Token Validation diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index dde6cb5f1..29ac8096d 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -110,7 +110,7 @@ type Keeper struct { CollectOrderInfoForPublish bool logger tmlog.Logger symbolSelector SymbolSelector - clearAfterMatch func(*Keeper) + clearAfterMatch func(*Keeper) } func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { @@ -141,7 +141,7 @@ func NewKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store. CollectOrderInfoForPublish: collectOrderInfoForPublish, logger: logger, symbolSelector: &BEP2SymbolSelector{}, - clearAfterMatch: clearAfterMatchBEP2, + clearAfterMatch: clearAfterMatchBEP2, } } @@ -634,7 +634,7 @@ func (kp *Keeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { return nil } -func clearAfterMatchBEP2(kp *Keeper) { +func clearAfterMatchBEP2(kp *Keeper) { kp.logger.Debug("clearAfterMatchBEP2...") kp.roundOrders = make(map[string][]string, 256) kp.roundIOCOrders = make(map[string][]string, 256) diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 6bd5f2a7c..8127ea456 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -52,8 +52,7 @@ func NewMiniKeeper(dexMiniKey sdk.StoreKey, am auth.AccountKeeper, miniPairMappe CollectOrderInfoForPublish: collectOrderInfoForPublish, logger: logger, symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}, - clearAfterMatch: clearAfterMatchMini}, - + clearAfterMatch: clearAfterMatchMini}, } } @@ -65,7 +64,7 @@ func (kp *MiniKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { return eng } -func clearAfterMatchMini(kp *Keeper) { +func clearAfterMatchMini(kp *Keeper) { kp.logger.Debug("clearAfterMatchMini...") for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { delete(kp.roundOrders, symbol) diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/miniTokens/client/cli/issue.go index 7c38c1a81..be361c1fd 100644 --- a/plugins/miniTokens/client/cli/issue.go +++ b/plugins/miniTokens/client/cli/issue.go @@ -1,6 +1,7 @@ package commands import ( + "fmt" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -11,7 +12,7 @@ import ( ) const ( - flagMaxTotalSupply = "max-total-supply" + flagTokenType = "token-type" flagTotalSupply = "total-supply" flagTokenName = "token-name" flagMintable = "mintable" @@ -27,11 +28,11 @@ func issueMiniTokenCmd(cmdr Commander) *cobra.Command { cmd.Flags().String(flagTokenName, "", "name of the new token") cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the new token") - cmd.Flags().Int64P(flagMaxTotalSupply, "m", 0, "max total supply of the new token") + cmd.Flags().Int8P(flagTokenType, "t", 0, "token type - 1 = tiny token, of which max supply is 10k; - 2 = mini token, of which max supply is 100k") cmd.Flags().Int64P(flagTotalSupply, "n", 0, "total supply of the new token") cmd.Flags().Bool(flagMintable, false, "whether the token can be minted") cmd.Flags().String(flagTokenUri, "", "uri of the token information") - cmd.MarkFlagRequired(flagMaxTotalSupply) + cmd.MarkFlagRequired(flagTokenType) cmd.MarkFlagRequired(flagTotalSupply) return cmd } @@ -54,14 +55,14 @@ func (c Commander) issueToken(cmd *cobra.Command, args []string) error { return err } - maxSupply := viper.GetInt64(flagMaxTotalSupply) - err = checkMaxSupplyAmount(maxSupply) + tokenType := viper.GetInt(flagTokenType) + err = checkTokenType(tokenType) if err != nil { return err } supply := viper.GetInt64(flagTotalSupply) - err = checkSupplyAmount(supply, maxSupply) + err = checkSupplyAmount(supply, int8(tokenType)) if err != nil { return err } @@ -75,23 +76,23 @@ func (c Commander) issueToken(cmd *cobra.Command, args []string) error { } // build message - msg := issue.NewIssueMsg(from, name, symbol, maxSupply, supply, mintable, tokenURI) + msg := issue.NewIssueMsg(from, name, symbol, int8(tokenType), supply, mintable, tokenURI) return client.SendOrPrintTx(cliCtx, txBldr, msg) } -func checkMaxSupplyAmount(amount int64) error { - if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenMaxTotalSupplyUpperBound { - return errors.New("invalid max supply amount") +func checkTokenType(tokenType int) error { + if tokenType != int(types.SupplyRange.TINY) || tokenType != int(types.SupplyRange.MINI) { + return errors.New("invalid token type") } return nil } -func checkSupplyAmount(amount, maxAmount int64) error { - if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenMaxTotalSupplyUpperBound { +func checkSupplyAmount(amount int64, tokenType int8) error { + if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenSupplyUpperBound { return errors.New("invalid supply amount") } - if amount > maxAmount { - return errors.New("supply amount cannot exceed max supply amount") + if amount > types.SupplyRangeType(tokenType).UpperBound() { + return errors.New(fmt.Sprintf("supply amount cannot exceed max supply amount of %s - %d",types.SupplyRangeType(tokenType).String(),types.SupplyRangeType(tokenType).UpperBound())) } return nil } diff --git a/plugins/miniTokens/issue/handler.go b/plugins/miniTokens/issue/handler.go index 5e145de52..35150435b 100644 --- a/plugins/miniTokens/issue/handler.go +++ b/plugins/miniTokens/issue/handler.go @@ -56,31 +56,16 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() } - if msg.MaxTotalSupply < common.MiniTokenMinTotalSupply { - logger.Info(errLogMsg, "reason", "max total supply doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too small, the min amount is %d", - common.MiniTokenMinTotalSupply)).Result() - } - if msg.MaxTotalSupply > common.MiniTokenMaxTotalSupplyUpperBound { - logger.Info(errLogMsg, "reason", "max total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply is too large, the max total supply upper bound is %d", - common.MiniTokenMaxTotalSupplyUpperBound)).Result() - } if msg.TotalSupply < common.MiniTokenMinTotalSupply { logger.Info(errLogMsg, "reason", "total supply doesn't reach the min supply") return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too small, the min amount is %d", common.MiniTokenMinTotalSupply)).Result() } - if msg.TotalSupply > msg.MaxTotalSupply { - logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply is %d", - common.MiniTokenMaxTotalSupplyUpperBound)).Result() - } - if msg.TotalSupply > common.MiniTokenMaxTotalSupplyUpperBound { + if msg.TotalSupply > common.MiniTokenSupplyUpperBound { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply upperbound is %d", - common.MiniTokenMaxTotalSupplyUpperBound)).Result() + common.MiniTokenSupplyUpperBound)).Result() } // the symbol is suffixed with the first n bytes of the tx hash symbol = fmt.Sprintf("%s-%s", symbol, suffix) @@ -95,7 +80,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) already exists", msg.Symbol)).Result() } - token, err := common.NewMiniToken(msg.Name, symbol, msg.MaxTotalSupply, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) + token, err := common.NewMiniToken(msg.Name, symbol, msg.TokenType, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) if err != nil { logger.Error(errLogMsg, "reason", "create token failed: "+err.Error()) return sdk.ErrInternal(fmt.Sprintf("unable to create token struct: %s", err.Error())).Result() diff --git a/plugins/miniTokens/issue/msg.go b/plugins/miniTokens/issue/msg.go index c9631725e..4dc6a1269 100644 --- a/plugins/miniTokens/issue/msg.go +++ b/plugins/miniTokens/issue/msg.go @@ -12,34 +12,33 @@ import ( // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash // const Route = "tokens/issue" const ( - Route = "miniTokensIssue" - IssueMsgType = "miniIssueMsg" - AdvIssueMsgType = "advMiniIssueMsg" //For max total supply in range 2 - + Route = "miniTokensIssue" + IssueTinyMsgType = "tinyIssueMsg" + IssueMiniMsgType = "miniIssueMsg" //For max total supply in range 2 maxTokenNameLength = 32 ) var _ sdk.Msg = IssueMsg{} type IssueMsg struct { - From sdk.AccAddress `json:"from"` - Name string `json:"name"` - Symbol string `json:"symbol"` - MaxTotalSupply int64 `json:"max_total_supply"` - TotalSupply int64 `json:"total_supply"` - Mintable bool `json:"mintable"` - TokenURI string `json:"token_uri"` + From sdk.AccAddress `json:"from"` + Name string `json:"name"` + Symbol string `json:"symbol"` + TokenType int8 `json:"token_type"` + TotalSupply int64 `json:"total_supply"` + Mintable bool `json:"mintable"` + TokenURI string `json:"token_uri"` } -func NewIssueMsg(from sdk.AccAddress, name, symbol string, maxTotalSupply, supply int64, mintable bool, tokenURI string) IssueMsg { +func NewIssueMsg(from sdk.AccAddress, name, symbol string, tokenType int8, supply int64, mintable bool, tokenURI string) IssueMsg { return IssueMsg{ - From: from, - Name: name, - Symbol: symbol, - MaxTotalSupply: maxTotalSupply, - TotalSupply: supply, - Mintable: mintable, - TokenURI: tokenURI, + From: from, + Name: name, + Symbol: symbol, + TokenType: tokenType, + TotalSupply: supply, + Mintable: mintable, + TokenURI: tokenURI, } } @@ -62,12 +61,12 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidCoins(fmt.Sprintf("token seturi should not exceed %v characters", types.MaxTokenURILength)) } - if msg.MaxTotalSupply < types.MiniTokenMinTotalSupply || msg.MaxTotalSupply > types.MiniTokenMaxTotalSupplyUpperBound { - return sdk.ErrInvalidCoins(fmt.Sprintf("max total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenMaxTotalSupplyUpperBound)) + if msg.TokenType != int8(types.SupplyRange.MINI) || msg.TokenType != int8(types.SupplyRange.TINY) { + return sdk.ErrInvalidCoins(fmt.Sprintf("token type should be %d or %d", int8(types.SupplyRange.MINI), int8(types.SupplyRange.TINY))) } - if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > msg.MaxTotalSupply { - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, msg.MaxTotalSupply)) + if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.SupplyRangeType(msg.TokenType).UpperBound() { + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.SupplyRangeType(msg.TokenType).UpperBound())) } return nil @@ -76,10 +75,13 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { // Implements IssueMsg. func (msg IssueMsg) Route() string { return Route } func (msg IssueMsg) Type() string { - if msg.MaxTotalSupply > types.MiniTokenSupplyRange1UpperBound { - return AdvIssueMsgType - } else { - return IssueMsgType + switch types.SupplyRangeType(msg.TokenType) { + case types.SupplyRange.TINY: + return IssueTinyMsgType + case types.SupplyRange.MINI: + return IssueMiniMsgType + default: + return IssueMiniMsgType } } func (msg IssueMsg) String() string { return fmt.Sprintf("IssueMsg{%#v}", msg) } diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 589749e14..87944d522 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -65,8 +65,8 @@ func RegisterUpgradeBeginBlocker(paramHub *ParamHub) { }) upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP8, func(ctx sdk.Context) { miniTokenFeeParams := []param.FeeParam{ - ¶m.FixedFeeParams{MsgType: miniIssue.IssueMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: miniIssue.AdvIssueMsgType, Fee: AdvMiniIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: miniIssue.IssueTinyMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: miniIssue.IssueMiniMsgType, Fee: AdvMiniIssueFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: miniURI.SetURIMsg{}.Type(), Fee: MiniSetUriFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: listmini.ListMiniMsg{}.Type(), Fee: MiniListingFee, FeeFor: types.FeeForProposer}, } @@ -96,16 +96,16 @@ func init() { burn.BurnRoute: fees.FixedFeeCalculatorGen, account.SetAccountFlagsMsgType: fees.FixedFeeCalculatorGen, freeze.FreezeRoute: fees.FixedFeeCalculatorGen, - timelock.TimeLockMsg{}.Type(): fees.FixedFeeCalculatorGen, - timelock.TimeUnlockMsg{}.Type(): fees.FixedFeeCalculatorGen, - timelock.TimeRelockMsg{}.Type(): fees.FixedFeeCalculatorGen, - bank.MsgSend{}.Type(): tokens.TransferFeeCalculatorGen, - swap.HTLT: fees.FixedFeeCalculatorGen, - swap.DepositHTLT: fees.FixedFeeCalculatorGen, - swap.ClaimHTLT: fees.FixedFeeCalculatorGen, - swap.RefundHTLT: fees.FixedFeeCalculatorGen, - miniIssue.IssueMsgType: fees.FixedFeeCalculatorGen, - miniIssue.AdvIssueMsgType: fees.FixedFeeCalculatorGen, - miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, + timelock.TimeLockMsg{}.Type(): fees.FixedFeeCalculatorGen, + timelock.TimeUnlockMsg{}.Type(): fees.FixedFeeCalculatorGen, + timelock.TimeRelockMsg{}.Type(): fees.FixedFeeCalculatorGen, + bank.MsgSend{}.Type(): tokens.TransferFeeCalculatorGen, + swap.HTLT: fees.FixedFeeCalculatorGen, + swap.DepositHTLT: fees.FixedFeeCalculatorGen, + swap.ClaimHTLT: fees.FixedFeeCalculatorGen, + swap.RefundHTLT: fees.FixedFeeCalculatorGen, + miniIssue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, + miniIssue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, + miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, } } diff --git a/plugins/param/types/types.go b/plugins/param/types/types.go index eeb17b820..94e60f696 100644 --- a/plugins/param/types/types.go +++ b/plugins/param/types/types.go @@ -41,8 +41,8 @@ var ( "claimHTLT": {}, "refundHTLT": {}, - "miniIssueMsg": {}, - "advMiniIssueMsg": {}, + "tinyIssueMsg": {}, + "miniIssueMsg": {}, "miniTokensSetURI": {}, "dexListMini": {}, } diff --git a/plugins/tokens/client/cli/issue.go b/plugins/tokens/client/cli/issue.go index e8db3fb92..14096a60f 100644 --- a/plugins/tokens/client/cli/issue.go +++ b/plugins/tokens/client/cli/issue.go @@ -114,7 +114,7 @@ func checkSupplyAmount(amount int64) error { return nil } func checkMiniTokenSupplyAmount(amount int64) error { - if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenMaxTotalSupplyUpperBound { + if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenSupplyUpperBound { return errors.New("invalid supply amount") } diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index b506171cc..ae3c0aac8 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -183,16 +183,16 @@ func handleMintMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMap common.MiniTokenMinTotalSupply)).Result() } // use minus to prevent overflow - if msg.Amount > token.MaxTotalSupply.ToInt64()-token.TotalSupply.ToInt64() { + if msg.Amount > token.TokenType.UpperBound()-token.TotalSupply.ToInt64() { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %d", - token.MaxTotalSupply)).Result() + token.TokenType.UpperBound())).Result() } - if msg.Amount > common.MiniTokenMaxTotalSupplyUpperBound-token.TotalSupply.ToInt64() { + if msg.Amount > common.MiniTokenSupplyUpperBound-token.TotalSupply.ToInt64() { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply upper bound") return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %d", - common.MiniTokenMaxTotalSupplyUpperBound)).Result() + common.MiniTokenSupplyUpperBound)).Result() } newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount err = miniTokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 29e805e2c..ecd5a95bb 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -137,12 +137,12 @@ func TestHandleMintMiniToken(t *testing.T) { require.Equal(t, false, sdkResult.Code.IsOK()) require.Contains(t, sdkResult.Log, "mint amount is too large") - invalidMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", types.MiniTokenMaxTotalSupplyUpperBound) + invalidMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", types.MiniTokenSupplyUpperBound) sdkResult = handler(ctx, invalidMintMsg) require.Contains(t, sdkResult.Log, "mint amount is too large") _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) - invalidMintMsg = NewMintMsg(acc2.GetAddress(), "NNB-000M", types.MiniTokenMaxTotalSupplyUpperBound) + invalidMintMsg = NewMintMsg(acc2.GetAddress(), "NNB-000M", types.MiniTokenSupplyUpperBound) sdkResult = handler(ctx, invalidMintMsg) require.Contains(t, sdkResult.Log, "only the owner can mint token NNB") diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index 4b6e42e89..f5e27cb2d 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -128,8 +128,8 @@ func (msg MintMsg) validateMiniTokenBasic() sdk.Error { } // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply - if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenMaxTotalSupplyUpperBound { - return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenMaxTotalSupplyUpperBound)) + if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenSupplyUpperBound { + return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenSupplyUpperBound)) } return nil From 0e5963566148bafb0a4623da528ea4c11a1d3b9d Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 29 Apr 2020 12:22:44 +0800 Subject: [PATCH 14/96] refactor WIP --- app/app.go | 4 +- app/pub/helpers.go | 22 ++- plugins/dex/order/keeper.go | 163 ------------------ plugins/dex/order/keeper_match.go | 247 +++++++++++++++++++++++++++ plugins/dex/order/keeper_recovery.go | 12 +- plugins/dex/order/mini_keeper.go | 14 +- plugins/dex/utils/numbers.go | 12 ++ 7 files changed, 288 insertions(+), 186 deletions(-) create mode 100644 plugins/dex/order/keeper_match.go diff --git a/app/app.go b/app/app.go index 95649e3eb..a8a1ca21d 100644 --- a/app/app.go +++ b/app/app.go @@ -556,8 +556,8 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a if sdk.IsUpgrade(upgrade.BEP19) || !isBreatheBlock { if app.publicationConfig.ShouldPublishAny() && pub.IsLive { //todo parallel run, extract fees.Pool.AddAndCommitFee("MATCH", totalFee) - tradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, ctx, isBreatheBlock) - miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexMiniTokenKeeper, ctx, isBreatheBlock) + tradesToPublish, miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, app.DexMiniTokenKeeper, ctx, isBreatheBlock) + //miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexMiniTokenKeeper, ctx, isBreatheBlock) } else { //todo parallel run, extract fees.Pool.AddAndCommitFee("MATCH", totalFee) app.DexKeeper.MatchAndAllocateSymbols(ctx, nil, isBreatheBlock) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 5a2f9d69e..ffe0a0e30 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "github.com/binance-chain/node/plugins/dex" "strconv" "sync" "time" @@ -264,15 +265,16 @@ func GetAccountBalances(mapper auth.AccountKeeper, ctx sdk.Context, accSlices .. return } -func MatchAndAllocateAllForPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, matchAllMiniSymbols bool) []*Trade { +func MatchAndAllocateAllForPublish(dexKeeper *dex.DexKeeper, dexMiniKeeper *dex.DexMiniTokenKeeper, ctx sdk.Context, matchAllMiniSymbols bool) ([]*Trade,[]*Trade) { // This channels is used for protect not update `dexKeeper.OrderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) // while dexKeeper.OrderChanges are not separated by concurrent factor (users here) iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize) wg := sync.WaitGroup{} - wg.Add(1) + wg.Add(2) go updateExpireFeeForPublish(dexKeeper, &wg, iocExpireFeeHolderCh) + go updateExpireFeeForPublish(dexMiniKeeper, &wg, iocExpireFeeHolderCh) var postAlloTransHandler = func(tran orderPkg.Transfer) { if tran.IsExpire() { if tran.IsExpiredWithFee() { @@ -284,12 +286,20 @@ func MatchAndAllocateAllForPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Co } } - dexKeeper.MatchAndAllocateSymbols(ctx, postAlloTransHandler, matchAllMiniSymbols) + orderPkg.MatchAndAllocateSymbols(dexKeeper, dexMiniKeeper, ctx, postAlloTransHandler, matchAllMiniSymbols, Logger) close(iocExpireFeeHolderCh) tradeIdx := 0 - tradesToPublish := make([]*Trade, 0) + tradeHeight := ctx.BlockHeight() + tradesToPublish := extractTradesToPublish(dexKeeper, ctx, tradeHeight, &tradeIdx) + miniTradesToPublish := extractTradesToPublish(dexMiniKeeper, ctx, tradeHeight, &tradeIdx) + wg.Wait() + return tradesToPublish, miniTradesToPublish +} + +func extractTradesToPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, tradeHeight int64, tradeIdx *int) []*Trade { + tradesToPublish := make([]*Trade, 0) for _, pair := range dexKeeper.GetPairMapper().ListAllTradingPairs(ctx) { symbol := pair.GetSymbol() matchEngTrades, _ := dexKeeper.GetLastTrades(tradeHeight, symbol) @@ -316,12 +326,10 @@ func MatchAndAllocateAllForPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Co BSingleFee: bsinglefee, TickType: int(trade.TickType), } - tradeIdx += 1 + *tradeIdx += 1 tradesToPublish = append(tradesToPublish, t) } } - - wg.Wait() return tradesToPublish } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 29ac8096d..88e18d122 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -39,7 +39,6 @@ type FeeHandler func(map[string]*types.Fee) type TransferHandler func(Transfer) type DexOrderKeeper interface { - Init(ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) InitRecentPrices(ctx sdk.Context) AddEngine(pair dexTypes.TradingPair) *me.MatchEng UpdateTickSizeAndLotSize(ctx sdk.Context) @@ -60,7 +59,6 @@ type DexOrderKeeper interface { ClearOrderChanges() StoreTradePrices(ctx sdk.Context) MatchSymbols(height, timestamp int64) - MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) @@ -110,7 +108,6 @@ type Keeper struct { CollectOrderInfoForPublish bool logger tmlog.Logger symbolSelector SymbolSelector - clearAfterMatch func(*Keeper) } func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { @@ -141,15 +138,9 @@ func NewKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store. CollectOrderInfoForPublish: collectOrderInfoForPublish, logger: logger, symbolSelector: &BEP2SymbolSelector{}, - clearAfterMatch: clearAfterMatchBEP2, } } -func (kp *Keeper) Init(ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { - kp.initOrderBook(ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) - kp.InitRecentPrices(ctx) -} - func (kp *Keeper) InitRecentPrices(ctx sdk.Context) { kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) } @@ -342,81 +333,6 @@ func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { return sum % bucketNumber } -func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, timestamp int64, orders map[string]*OrderInfo, - distributeTrade bool, tradeOuts []chan Transfer) { - engine := kp.engines[symbol] - concurrency := len(tradeOuts) - // please note there is no logging in matching, expecting to see the order book details - // from the exchange's order book stream. - if engine.Match(height) { - kp.logger.Debug("Match finish:", "symbol", symbol, "lastTradePrice", engine.LastTradePrice) - for i := range engine.Trades { - t := &engine.Trades[i] - updateOrderMsg(orders[t.Bid], t.BuyCumQty, height, timestamp) - updateOrderMsg(orders[t.Sid], t.SellCumQty, height, timestamp) - if distributeTrade { - t1, t2 := TransferFromTrade(t, symbol, kp.allOrders[symbol]) - c := channelHash(t1.accAddress, concurrency) - tradeOuts[c] <- t1 - c = channelHash(t2.accAddress, concurrency) - tradeOuts[c] <- t2 - } - } - droppedIds := engine.DropFilledOrder() //delete from order books - for _, id := range droppedIds { - delete(orders, id) //delete from order cache - } - kp.logger.Debug("Drop filled orders", "total", droppedIds) - } else { - // FUTURE-TODO: - // when Match() failed, have to unsolicited cancel all the new orders - // in this block. Ideally the order IDs would be stored in the EndBlock response, - // but this is not implemented yet, pending Tendermint to better handle EndBlock - // for index service. - kp.logger.Error("Fatal error occurred in matching, cancel all incoming new orders", - "symbol", symbol) - thisRoundIds := kp.roundOrders[symbol] - for _, id := range thisRoundIds { - msg := orders[id] - delete(orders, id) - if ord, err := engine.Book.RemoveOrder(id, msg.Side, msg.Price); err == nil { - kp.logger.Info("Removed due to match failure", "ordID", msg.Id) - if distributeTrade { - c := channelHash(msg.Sender, concurrency) - tradeOuts[c] <- TransferFromCanceled(ord, *msg, true) - } - } else { - kp.logger.Error("Failed to remove order, may be fatal!", "orderID", id) - } - - // let the order status publisher publish these abnormal - // order status change outs. - if kp.CollectOrderInfoForPublish { - kp.OrderChangesMtx.Lock() - kp.OrderChanges = append(kp.OrderChanges, OrderChange{id, FailedMatching, "", nil}) - kp.OrderChangesMtx.Unlock() - } - } - return // no need to handle IOC - } - var iocIDs []string - iocIDs = kp.roundIOCOrders[symbol] - for _, id := range iocIDs { - if msg, ok := orders[id]; ok { - delete(orders, id) - if ord, err := engine.Book.RemoveOrder(id, msg.Side, msg.Price); err == nil { - kp.logger.Debug("Removed unclosed IOC order", "ordID", msg.Id) - if distributeTrade { - c := channelHash(msg.Sender, concurrency) - tradeOuts[c] <- TransferFromExpired(ord, *msg) - } - } else { - kp.logger.Error("Failed to remove IOC order, may be fatal!", "orderID", id) - } - } - } -} - func (kp *Keeper) SubscribeParamChange(hub *paramhub.Keeper) { hub.SubscribeParamChange( func(ctx sdk.Context, changes []interface{}) { @@ -462,52 +378,6 @@ func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { order.LastUpdatedTimestamp = timestamp } -// please note if distributeTrade this method will work in async mode, otherwise in sync mode. -func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64, symbolsToMatch []string) []chan Transfer { - if len(symbolsToMatch) == 0 { - kp.logger.Info("No symbols to match in the block") - return nil - } - concurrency := 1 << kp.poolSize - tradeOuts := make([]chan Transfer, concurrency) - - if distributeTrade { - ordNum := 0 - for _, symbol := range symbolsToMatch { - ordNum += len(kp.roundOrders[symbol]) - } - for i := range tradeOuts { - //assume every new order would have 2 trades and generate 4 transfer - tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) - } - } - - symbolCh := make(chan string, concurrency) - producer := func() { - for _, symbol := range symbolsToMatch { - symbolCh <- symbol - } - close(symbolCh) - } - matchWorker := func() { - i := 0 - for symbol := range symbolCh { - i++ - kp.matchAndDistributeTradesForSymbol(symbol, height, timestamp, kp.allOrders[symbol], distributeTrade, tradeOuts) - } - } - - if distributeTrade { - utils.ConcurrentExecuteAsync(concurrency, producer, matchWorker, func() { - for _, tradeOut := range tradeOuts { - close(tradeOut) - } - }) - } else { - utils.ConcurrentExecuteSync(concurrency, producer, matchWorker) - } - return tradeOuts -} func (kp *Keeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { orderbook := make([]store.OrderBookLevel, maxLevels) @@ -634,12 +504,6 @@ func (kp *Keeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { return nil } -func clearAfterMatchBEP2(kp *Keeper) { - kp.logger.Debug("clearAfterMatchBEP2...") - kp.roundOrders = make(map[string][]string, 256) - kp.roundIOCOrders = make(map[string][]string, 256) -} - func (kp *Keeper) StoreTradePrices(ctx sdk.Context) { // TODO: check block height != 0 if ctx.BlockHeight()%pricesStoreEvery == 0 { @@ -847,33 +711,6 @@ func (kp *Keeper) allocateAndCalcFee( return totalFee } -func (kp *Keeper) MatchSymbols(height, timestamp int64) { - symbolsToMatch := kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, timestamp, false) - kp.logger.Debug("symbols to match", "symbols", symbolsToMatch) - tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp, symbolsToMatch) //only match - if tradeOuts == nil { - kp.logger.Info("No order comes in for the block") - } - kp.clearAfterMatch(kp) -} - -// MatchAndAllocateSymbols() is concurrently matching and allocating across -// all the symbols' order books, among all the clients -// Return whether match has been done in this height -func (kp *Keeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { - kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(kp.roundOrders)) - timestamp := ctx.BlockHeader().Time.UnixNano() - - symbolsToMatch := kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, ctx.BlockHeader().Height, timestamp, false) - tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp, symbolsToMatch) - if tradeOuts == nil { - kp.logger.Info("No order comes in for the block") - } - totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) - fees.Pool.AddAndCommitFee("MATCH_MINI", totalFee) - kp.clearAfterMatch(kp) -} - func (kp *Keeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { size := len(kp.allOrders) if size == 0 { diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go new file mode 100644 index 000000000..0c5f60506 --- /dev/null +++ b/plugins/dex/order/keeper_match.go @@ -0,0 +1,247 @@ +package order + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + tmlog "github.com/tendermint/tendermint/libs/log" + + "github.com/binance-chain/node/common/fees" + "github.com/binance-chain/node/common/utils" + dexUtils "github.com/binance-chain/node/plugins/dex/utils" +) + +func MatchAndAllocateSymbols(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool, logger tmlog.Logger) { + logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(dexKeeper.roundOrders)) + timestamp := ctx.BlockHeader().Time.UnixNano() + + symbolsToMatch := dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols) + symbolsToMatch = append(symbolsToMatch, dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols)...) + tradeOuts := matchAndDistributeTrades(dexKeeper, dexMiniKeeper, true, ctx.BlockHeader().Height, timestamp, symbolsToMatch, logger) + if tradeOuts == nil { + logger.Info("No order comes in for the block") + } + totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) + fees.Pool.AddAndCommitFee("MATCH", totalFee) + clearAfterMatchBEP2(dexKeeper) + clearAfterMatchMini(dexMiniKeeper) +} + +func clearAfterMatchBEP2(kp *Keeper) { + kp.logger.Debug("clearAfterMatchBEP2...") + kp.roundOrders = make(map[string][]string, 256) + kp.roundIOCOrders = make(map[string][]string, 256) +} + +func clearAfterMatchMini(kp *MiniKeeper) { + kp.logger.Debug("clearAfterMatchMini...") + for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { + delete(kp.roundOrders, symbol) + delete(kp.roundIOCOrders, symbol) + } + emptyRoundMatchSymbols := make([]string, 0, 256) + kp.symbolSelector.SetRoundMatchSymbol(emptyRoundMatchSymbols) +} + +// please note if distributeTrade this method will work in async mode, otherwise in sync mode. +func matchAndDistributeTrades(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, distributeTrade bool, height, timestamp int64, symbolsToMatch []string, logger tmlog.Logger) []chan Transfer { + if len(symbolsToMatch) == 0 { + logger.Info("No symbols to match in the block") + return nil + } + concurrency := 1 << dexUtils.MaxOf(dexKeeper.poolSize, dexMiniKeeper.poolSize) + tradeOuts := make([]chan Transfer, concurrency) + + if distributeTrade { + ordNum := 0 + for _, symbol := range symbolsToMatch { + if dexUtils.IsMiniTokenTradingPair(symbol) { + ordNum += len(dexMiniKeeper.roundOrders[symbol]) + } else { + ordNum += len(dexKeeper.roundOrders[symbol]) + } + } + for i := range tradeOuts { + //assume every new order would have 2 trades and generate 4 transfer + tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) + } + } + + symbolCh := make(chan string, concurrency) + producer := func() { + for _, symbol := range symbolsToMatch { + symbolCh <- symbol + } + close(symbolCh) + } + matchWorker := func() { + for symbol := range symbolCh { + if dexUtils.IsMiniTokenTradingPair(symbol) { + dexMiniKeeper.matchAndDistributeTradesForSymbol(symbol, height, timestamp, dexMiniKeeper.allOrders[symbol], distributeTrade, tradeOuts) + } else { + dexKeeper.matchAndDistributeTradesForSymbol(symbol, height, timestamp, dexKeeper.allOrders[symbol], distributeTrade, tradeOuts) + } + } + + } + + if distributeTrade { + utils.ConcurrentExecuteAsync(concurrency, producer, matchWorker, func() { + for _, tradeOut := range tradeOuts { + close(tradeOut) + } + }) + } else { + utils.ConcurrentExecuteSync(concurrency, producer, matchWorker) + } + return tradeOuts +} + +func (kp *Keeper) MatchSymbols(height, timestamp int64) { + symbolsToMatch := kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, timestamp, false) + kp.logger.Debug("symbols to match", "symbols", symbolsToMatch) + tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp, symbolsToMatch) //only match + if tradeOuts == nil { + kp.logger.Info("No order comes in for the block") + } + clearAfterMatchBEP2(dexKeeper) + clearAfterMatchMini(dexMiniKeeper) +} + +// MatchAndAllocateSymbols() is concurrently matching and allocating across +// all the symbols' order books, among all the clients +// Return whether match has been done in this height +//func (kp *Keeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { +// kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(kp.roundOrders)) +// timestamp := ctx.BlockHeader().Time.UnixNano() +// +// symbolsToMatch := kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols) +// tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp, symbolsToMatch) +// if tradeOuts == nil { +// kp.logger.Info("No order comes in for the block") +// } +// totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) +// fees.Pool.AddAndCommitFee("MATCH", totalFee) +// kp.clearAfterMatch(kp) +//} + +//// please note if distributeTrade this method will work in async mode, otherwise in sync mode. +//func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64, symbolsToMatch []string) []chan Transfer { +// if len(symbolsToMatch) == 0 { +// kp.logger.Info("No symbols to match in the block") +// return nil +// } +// concurrency := 1 << kp.poolSize +// tradeOuts := make([]chan Transfer, concurrency) +// +// if distributeTrade { +// ordNum := 0 +// for _, symbol := range symbolsToMatch { +// ordNum += len(kp.roundOrders[symbol]) +// } +// for i := range tradeOuts { +// //assume every new order would have 2 trades and generate 4 transfer +// tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) +// } +// } +// +// symbolCh := make(chan string, concurrency) +// producer := func() { +// for _, symbol := range symbolsToMatch { +// symbolCh <- symbol +// } +// close(symbolCh) +// } +// matchWorker := func() { +// i := 0 +// for symbol := range symbolCh { +// i++ +// kp.matchAndDistributeTradesForSymbol(symbol, height, timestamp, kp.allOrders[symbol], distributeTrade, tradeOuts) +// } +// } +// +// if distributeTrade { +// utils.ConcurrentExecuteAsync(concurrency, producer, matchWorker, func() { +// for _, tradeOut := range tradeOuts { +// close(tradeOut) +// } +// }) +// } else { +// utils.ConcurrentExecuteSync(concurrency, producer, matchWorker) +// } +// return tradeOuts +//} + +func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, timestamp int64, orders map[string]*OrderInfo, + distributeTrade bool, tradeOuts []chan Transfer) { + engine := kp.engines[symbol] + concurrency := len(tradeOuts) + // please note there is no logging in matching, expecting to see the order book details + // from the exchange's order book stream. + if engine.Match(height) { + kp.logger.Debug("Match finish:", "symbol", symbol, "lastTradePrice", engine.LastTradePrice) + for i := range engine.Trades { + t := &engine.Trades[i] + updateOrderMsg(orders[t.Bid], t.BuyCumQty, height, timestamp) + updateOrderMsg(orders[t.Sid], t.SellCumQty, height, timestamp) + if distributeTrade { + t1, t2 := TransferFromTrade(t, symbol, kp.allOrders[symbol]) + c := channelHash(t1.accAddress, concurrency) + tradeOuts[c] <- t1 + c = channelHash(t2.accAddress, concurrency) + tradeOuts[c] <- t2 + } + } + droppedIds := engine.DropFilledOrder() //delete from order books + for _, id := range droppedIds { + delete(orders, id) //delete from order cache + } + kp.logger.Debug("Drop filled orders", "total", droppedIds) + } else { + // FUTURE-TODO: + // when Match() failed, have to unsolicited cancel all the new orders + // in this block. Ideally the order IDs would be stored in the EndBlock response, + // but this is not implemented yet, pending Tendermint to better handle EndBlock + // for index service. + kp.logger.Error("Fatal error occurred in matching, cancel all incoming new orders", + "symbol", symbol) + thisRoundIds := kp.roundOrders[symbol] + for _, id := range thisRoundIds { + msg := orders[id] + delete(orders, id) + if ord, err := engine.Book.RemoveOrder(id, msg.Side, msg.Price); err == nil { + kp.logger.Info("Removed due to match failure", "ordID", msg.Id) + if distributeTrade { + c := channelHash(msg.Sender, concurrency) + tradeOuts[c] <- TransferFromCanceled(ord, *msg, true) + } + } else { + kp.logger.Error("Failed to remove order, may be fatal!", "orderID", id) + } + + // let the order status publisher publish these abnormal + // order status change outs. + if kp.CollectOrderInfoForPublish { + kp.OrderChangesMtx.Lock() + kp.OrderChanges = append(kp.OrderChanges, OrderChange{id, FailedMatching, "", nil}) + kp.OrderChangesMtx.Unlock() + } + } + return // no need to handle IOC + } + var iocIDs []string + iocIDs = kp.roundIOCOrders[symbol] + for _, id := range iocIDs { + if msg, ok := orders[id]; ok { + delete(orders, id) + if ord, err := engine.Book.RemoveOrder(id, msg.Side, msg.Price); err == nil { + kp.logger.Debug("Removed unclosed IOC order", "ordID", msg.Id) + if distributeTrade { + c := channelHash(msg.Sender, concurrency) + tradeOuts[c] <- TransferFromExpired(ord, *msg) + } + } else { + kp.logger.Error("Failed to remove IOC order, may be fatal!", "orderID", id) + } + } + } +} diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 7ebfeef49..7e9a2844a 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -59,6 +59,13 @@ func compressAndSave(snapshot interface{}, cdc *wire.Codec, key string, kv sdk.K return nil } + +func Init(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { + initOrderBook(dexKeeper, dexMiniKeeper, ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) + dexKeeper.InitRecentPrices(ctx) + dexMiniKeeper.InitRecentPrices(ctx) +} + func (kp *Keeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) { kvstore := ctx.KVStore(kp.storeKey) effectedStoreKeys = make([]string, 0) @@ -259,7 +266,7 @@ func (kp *Keeper) ReplayOrdersFromBlock(ctx sdk.Context, bc *tmstore.BlockStore, return nil } -func (kp *Keeper) initOrderBook(ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { +func initOrderBook(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { var timeOfLatestBlock time.Time if lastHeight == 0 { timeOfLatestBlock = utils.Now() @@ -267,7 +274,8 @@ func (kp *Keeper) initOrderBook(ctx sdk.Context, blockInterval, daysBack int, bl block := blockStore.LoadBlock(lastHeight) timeOfLatestBlock = block.Time } - height, err := kp.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) + height, err := dexKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) + height, err = dexMiniKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) if err != nil { panic(err) } diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 8127ea456..a883be983 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -52,28 +52,18 @@ func NewMiniKeeper(dexMiniKey sdk.StoreKey, am auth.AccountKeeper, miniPairMappe CollectOrderInfoForPublish: collectOrderInfoForPublish, logger: logger, symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}, - clearAfterMatch: clearAfterMatchMini}, + }, } } // override func (kp *MiniKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { - eng := kp.Keeper.AddEngine(pair) + eng := kp.AddEngine(pair) symbol := strings.ToUpper(pair.GetSymbol()) kp.symbolSelector.AddSymbolHash(symbol) return eng } -func clearAfterMatchMini(kp *Keeper) { - kp.logger.Debug("clearAfterMatchMini...") - for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { - delete(kp.roundOrders, symbol) - delete(kp.roundIOCOrders, symbol) - } - emptyRoundMatchSymbols := make([]string, 0, 256) - kp.symbolSelector.SetRoundMatchSymbol(emptyRoundMatchSymbols) -} - // used by state sync to clear memory order book after we synced latest breathe block //TODO check usage func (kp *MiniKeeper) ClearOrders() { diff --git a/plugins/dex/utils/numbers.go b/plugins/dex/utils/numbers.go index 2b6c881ff..26e0534f7 100644 --- a/plugins/dex/utils/numbers.go +++ b/plugins/dex/utils/numbers.go @@ -53,3 +53,15 @@ func IsUnderMinNotional(price, qty int64) bool { return p < 1e8 } } + +func MaxOf(vars ...uint) uint { + max := vars[0] + + for _, i := range vars { + if max < i { + max = i + } + } + + return max +} From 9c93f4176b95835c16aaed8424af8681114e3beb Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 30 Apr 2020 12:34:56 +0800 Subject: [PATCH 15/96] parallel match --- app/app.go | 55 ++--- app/app_pub_test.go | 2 +- app/helpers.go | 13 +- app/pub/helpers.go | 28 ++- app/pub/publisher.go | 19 +- common/stores.go | 2 + common/types/mini_token.go | 2 +- networks/publisher/newPublisher.sh | 10 +- networks/publisher/ordergen.sh | 8 +- networks/publisher/setup_mini.sh | 26 ++ plugins/dex/aliases.go | 3 + plugins/dex/order/fee.go | 2 +- plugins/dex/order/global_keeper.go | 308 ++++++++++++++++++++++++ plugins/dex/order/handler.go | 10 +- plugins/dex/order/keeper.go | 316 ++----------------------- plugins/dex/order/keeper_match.go | 95 ++------ plugins/dex/order/keeper_recovery.go | 47 ++-- plugins/dex/order/mini_keeper.go | 59 +++-- plugins/dex/plugin.go | 4 +- plugins/dex/route.go | 4 +- plugins/miniTokens/client/cli/issue.go | 2 +- plugins/miniTokens/issue/msg.go | 6 +- 22 files changed, 533 insertions(+), 488 deletions(-) create mode 100644 plugins/dex/order/global_keeper.go diff --git a/app/app.go b/app/app.go index a8a1ca21d..d7fe8b735 100644 --- a/app/app.go +++ b/app/app.go @@ -84,6 +84,7 @@ type BinanceChain struct { CoinKeeper bank.Keeper DexKeeper *dex.DexKeeper DexMiniTokenKeeper *dex.DexMiniTokenKeeper + DexGlobalKeeper *dex.DexGlobalKeeper AccountKeeper auth.AccountKeeper TokenMapper tkstore.Mapper MiniTokenMapper miniTkstore.MiniTokenMapper @@ -223,7 +224,9 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp common.GovStoreKey, common.TimeLockStoreKey, common.AtomicSwapStoreKey, + common.DexMiniStoreKey, common.MiniTokenStoreKey, + common.MiniTokenPairStoreKey, ) app.SetAnteHandler(tx.NewAnteHandler(app.AccountKeeper)) app.SetPreChecker(tx.NewTxPreChecker()) @@ -277,6 +280,7 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { upgrade.Mgr.RegisterStoreKeys(upgrade.BEP9, common.TimeLockStoreKey.Name()) upgrade.Mgr.RegisterStoreKeys(upgrade.BEP3, common.AtomicSwapStoreKey.Name()) + upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.DexMiniStoreKey.Name()) upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.MiniTokenStoreKey.Name()) upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.MiniTokenPairStoreKey.Name()) @@ -318,15 +322,17 @@ func (app *BinanceChain) initRunningMode() { } func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper, miniPairMapper dex.TradingPairMapper) { - app.DexKeeper = dex.NewOrderKeeper(common.DexStoreKey, app.AccountKeeper, pairMapper, + + app.DexGlobalKeeper = dex.NewGlobalKeeper(app.Codec, app.AccountKeeper, app.publicationConfig.ShouldPublishAny()) + app.DexGlobalKeeper.SubscribeParamChange(app.ParamHub) + + app.DexKeeper = dex.NewOrderKeeper(common.DexStoreKey, pairMapper, app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec, - app.publicationConfig.ShouldPublishAny()) - app.DexKeeper.SubscribeParamChange(app.ParamHub) + app.DexGlobalKeeper) - app.DexMiniTokenKeeper = dex.NewMiniKeeper(common.DexMiniStoreKey, app.AccountKeeper, miniPairMapper, + app.DexMiniTokenKeeper = dex.NewMiniKeeper(common.DexMiniStoreKey, miniPairMapper, app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec, - app.publicationConfig.ShouldPublishAny()) - app.DexMiniTokenKeeper.SubscribeParamChange(app.ParamHub) + app.DexGlobalKeeper) // do not proceed if we are in a unit test and `CheckState` is unset. if app.CheckState == nil { @@ -339,7 +345,9 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper, miniPairMappe stateDB := baseapp.LoadStateDB() defer stateDB.Close() - app.DexKeeper.Init( + order.Init( + app.DexKeeper, + app.DexMiniTokenKeeper, app.CheckState.Ctx, app.baseConfig.BreatheBlockInterval, app.baseConfig.BreatheBlockDaysCountBack, @@ -348,20 +356,12 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper, miniPairMappe app.LastBlockHeight(), app.TxDecoder) - app.DexMiniTokenKeeper.Init( - app.CheckState.Ctx, - app.baseConfig.BreatheBlockInterval, - app.baseConfig.BreatheBlockDaysCountBack, - blockStore, - stateDB, - app.LastBlockHeight(), - app.TxDecoder) } func (app *BinanceChain) initPlugins() { tokens.InitPlugin(app, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) minitokens.InitPlugin(app, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper) - dex.InitPlugin(app, app.DexKeeper, app.DexMiniTokenKeeper, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.govKeeper) + dex.InitPlugin(app, app.DexKeeper, app.DexMiniTokenKeeper, app.DexGlobalKeeper, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.govKeeper) param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) } @@ -555,13 +555,9 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a var miniTradesToPublish []*pub.Trade if sdk.IsUpgrade(upgrade.BEP19) || !isBreatheBlock { if app.publicationConfig.ShouldPublishAny() && pub.IsLive { - //todo parallel run, extract fees.Pool.AddAndCommitFee("MATCH", totalFee) tradesToPublish, miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, app.DexMiniTokenKeeper, ctx, isBreatheBlock) - //miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexMiniTokenKeeper, ctx, isBreatheBlock) } else { - //todo parallel run, extract fees.Pool.AddAndCommitFee("MATCH", totalFee) - app.DexKeeper.MatchAndAllocateSymbols(ctx, nil, isBreatheBlock) - app.DexMiniTokenKeeper.MatchAndAllocateSymbols(ctx, nil, isBreatheBlock) + order.MatchAndAllocateSymbols(app.DexKeeper, app.DexMiniTokenKeeper, ctx, nil, isBreatheBlock, app.Logger) } } @@ -572,7 +568,9 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a app.takeSnapshotHeight = height icoDone := ico.EndBlockAsync(ctx) dex.EndBreatheBlock(ctx, app.DexKeeper, app.govKeeper, height, blockTime) - dex.EndBreatheBlock(ctx, app.DexMiniTokenKeeper, app.govKeeper, height, blockTime) + if sdk.IsUpgrade(upgrade.BEP8) { + dex.EndBreatheBlock(ctx, app.DexMiniTokenKeeper, app.govKeeper, height, blockTime) + } param.EndBreatheBlock(ctx, app.ParamHub) tokens.EndBreatheBlock(ctx, app.swapKeeper) // other end blockers @@ -582,7 +580,9 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a } app.DexKeeper.StoreTradePrices(ctx) - app.DexMiniTokenKeeper.StoreTradePrices(ctx) + if sdk.IsUpgrade(upgrade.BEP8) { + app.DexMiniTokenKeeper.StoreTradePrices(ctx) + } blockFee := distributeFee(ctx, app.AccountKeeper, app.ValAddrCache, app.publicationConfig.PublishBlockFee) tags, passed, failed := gov.EndBlocker(ctx, app.govKeeper) @@ -612,9 +612,10 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a // clean up intermediate cached data app.DexKeeper.ClearOrderChanges() - app.DexKeeper.ClearRoundFee() - app.DexMiniTokenKeeper.ClearOrderChanges() - app.DexMiniTokenKeeper.ClearRoundFee() + if sdk.IsUpgrade(upgrade.BEP8) { + app.DexMiniTokenKeeper.ClearOrderChanges() + } + app.DexGlobalKeeper.ClearRoundFee() } fees.Pool.Clear() // just clean it, no matter use it or not. @@ -868,7 +869,7 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli latestPriceLevels, miniLatestPriceLevels, blockFee, - app.DexKeeper.RoundOrderFees, + app.DexGlobalKeeper.RoundOrderFees, //only use DexKeeper RoundOrderFees transferToPublish, blockToPublish) diff --git a/app/app_pub_test.go b/app/app_pub_test.go index 8c36807d3..b8e66fb76 100644 --- a/app/app_pub_test.go +++ b/app/app_pub_test.go @@ -214,7 +214,7 @@ func TestAppPub_MatchOrder(t *testing.T) { func TestAppPub_MatchAndCancelFee(t *testing.T) { assert, require, app, buyerAcc, sellerAcc := setupAppTest(t) - handler := orderPkg.NewHandler(app.GetCodec(), app.DexKeeper, app.AccountKeeper) + handler := orderPkg.NewHandler(app.GetCodec(), app.DexKeeper, app.AccountKeeper, app.DexGlobalKeeper) ctx := app.DeliverState.Ctx // ==== Place a to-be-matched sell order and a to-be-cancelled buy order (in different symbol) diff --git a/app/helpers.go b/app/helpers.go index 6bf665846..8519d2ff3 100644 --- a/app/helpers.go +++ b/app/helpers.go @@ -187,15 +187,9 @@ func (app *BinanceChain) getLastBreatheBlockHeight() int64 { } func (app *BinanceChain) reInitChain() error { - app.DexKeeper.Init( - app.CheckState.Ctx, - app.baseConfig.BreatheBlockInterval, - app.baseConfig.BreatheBlockDaysCountBack, - snapshot.Manager().GetBlockStore(), - snapshot.Manager().GetStateDB(), - app.LastBlockHeight(), - app.TxDecoder) - app.DexMiniTokenKeeper.Init( + order.Init( + app.DexKeeper, + app.DexMiniTokenKeeper, app.CheckState.Ctx, app.baseConfig.BreatheBlockInterval, app.baseConfig.BreatheBlockDaysCountBack, @@ -203,6 +197,7 @@ func (app *BinanceChain) reInitChain() error { snapshot.Manager().GetStateDB(), app.LastBlockHeight(), app.TxDecoder) + app.initParams() // init app cache diff --git a/app/pub/helpers.go b/app/pub/helpers.go index ffe0a0e30..87c5ce69e 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -4,7 +4,8 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/binance-chain/node/plugins/dex" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/plugins/dex/utils" "strconv" "sync" "time" @@ -265,35 +266,48 @@ func GetAccountBalances(mapper auth.AccountKeeper, ctx sdk.Context, accSlices .. return } -func MatchAndAllocateAllForPublish(dexKeeper *dex.DexKeeper, dexMiniKeeper *dex.DexMiniTokenKeeper, ctx sdk.Context, matchAllMiniSymbols bool) ([]*Trade,[]*Trade) { +func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.Keeper, dexMiniKeeper *orderPkg.MiniKeeper, ctx sdk.Context, matchAllMiniSymbols bool) ([]*Trade, []*Trade) { // This channels is used for protect not update `dexKeeper.OrderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) // while dexKeeper.OrderChanges are not separated by concurrent factor (users here) iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize) + miniIocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, MiniTransferCollectionChannelSize) wg := sync.WaitGroup{} wg.Add(2) go updateExpireFeeForPublish(dexKeeper, &wg, iocExpireFeeHolderCh) - go updateExpireFeeForPublish(dexMiniKeeper, &wg, iocExpireFeeHolderCh) + go updateExpireFeeForPublish(dexMiniKeeper, &wg, miniIocExpireFeeHolderCh) var postAlloTransHandler = func(tran orderPkg.Transfer) { + var receiver chan orderPkg.ExpireHolder + if utils.IsMiniTokenTradingPair(tran.Symbol) { + receiver = miniIocExpireFeeHolderCh + } else { + receiver = iocExpireFeeHolderCh + } if tran.IsExpire() { if tran.IsExpiredWithFee() { // we only got expire of Ioc here, gte orders expire is handled in breathe block - iocExpireFeeHolderCh <- orderPkg.ExpireHolder{tran.Oid, orderPkg.IocNoFill, tran.Fee.String()} + receiver <- orderPkg.ExpireHolder{tran.Oid, orderPkg.IocNoFill, tran.Fee.String()} } else { - iocExpireFeeHolderCh <- orderPkg.ExpireHolder{tran.Oid, orderPkg.IocExpire, tran.Fee.String()} + receiver <- orderPkg.ExpireHolder{tran.Oid, orderPkg.IocExpire, tran.Fee.String()} } } } orderPkg.MatchAndAllocateSymbols(dexKeeper, dexMiniKeeper, ctx, postAlloTransHandler, matchAllMiniSymbols, Logger) close(iocExpireFeeHolderCh) + close(miniIocExpireFeeHolderCh) tradeIdx := 0 tradeHeight := ctx.BlockHeight() tradesToPublish := extractTradesToPublish(dexKeeper, ctx, tradeHeight, &tradeIdx) - miniTradesToPublish := extractTradesToPublish(dexMiniKeeper, ctx, tradeHeight, &tradeIdx) + var miniTradesToPublish []*Trade + if !sdk.IsUpgrade(upgrade.BEP8) { + miniTradesToPublish = make([]*Trade, 0) + } else { + miniTradesToPublish = extractTradesToPublish(dexMiniKeeper, ctx, tradeHeight, &tradeIdx) + } wg.Wait() return tradesToPublish, miniTradesToPublish } @@ -518,7 +532,7 @@ func collectOrdersToPublish( feeHolder orderPkg.FeeHolder, timestamp int64, miniTrades []*Trade, miniOrderChanges orderPkg.OrderChanges, - miniOrderInfos orderPkg.OrderInfoForPublish) (opensToPublish []*Order, closedToPublish []*Order, miniOpensToPublish []*Order, miniClosedToPublish []*Order,feeToPublish map[string]string, ) { + miniOrderInfos orderPkg.OrderInfoForPublish) (opensToPublish []*Order, closedToPublish []*Order, miniOpensToPublish []*Order, miniClosedToPublish []*Order, feeToPublish map[string]string, ) { opensToPublish = make([]*Order, 0) closedToPublish = make([]*Order, 0) miniOpensToPublish = make([]*Order, 0) diff --git a/app/pub/publisher.go b/app/pub/publisher.go index 7afe8219c..3bdfef938 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -13,18 +13,19 @@ import ( const ( // TODO(#66): revisit the setting / whole thread model here, // do we need better way to make main thread less possibility to block - TransferCollectionChannelSize = 4000 - ToRemoveOrderIdChannelSize = 1000 - MaxOrderBookLevel = 100 + TransferCollectionChannelSize = 4000 + MiniTransferCollectionChannelSize = 1000 + ToRemoveOrderIdChannelSize = 1000 + MaxOrderBookLevel = 100 ) var ( - Logger tmlog.Logger - Cfg *config.PublicationConfig - ToPublishCh chan BlockInfoToPublish - ToRemoveOrderIdCh chan string // order ids to remove from keeper.OrderInfoForPublish + Logger tmlog.Logger + Cfg *config.PublicationConfig + ToPublishCh chan BlockInfoToPublish + ToRemoveOrderIdCh chan string // order ids to remove from keeper.OrderInfoForPublish ToRemoveMiniOrderIdCh chan string // order ids to remove from keeper.miniOrderInfoForPublish - IsLive bool + IsLive bool ) type MarketDataPublisher interface { @@ -217,7 +218,7 @@ func publishExecutionResult(publisher MarketDataPublisher, height int64, timesta numOfStakeUpdatedAccounts := stakeUpdates.NumOfMsgs numOfMiniOrders := len(miniOrders) numOfMiniTrades := len(miniTrades) - executionResultsMsg := ExecutionResults{Height: height, Timestamp: timestamp, NumOfMsgs: numOfTrades + numOfOrders + numOfProposals + numOfStakeUpdatedAccounts + numOfMiniTrades + numOfMiniOrders } + executionResultsMsg := ExecutionResults{Height: height, Timestamp: timestamp, NumOfMsgs: numOfTrades + numOfOrders + numOfProposals + numOfStakeUpdatedAccounts + numOfMiniTrades + numOfMiniOrders} if numOfOrders > 0 { executionResultsMsg.Orders = Orders{numOfOrders, os} } diff --git a/common/stores.go b/common/stores.go index 0e1f005f7..854d53400 100644 --- a/common/stores.go +++ b/common/stores.go @@ -59,6 +59,7 @@ var ( StakeTransientStoreName: TStakeStoreKey, ParamsTransientStoreName: TParamsStoreKey, MiniTokenStoreName: MiniTokenStoreKey, + MiniTokenPairStoreName: MiniTokenPairStoreKey, } NonTransientStoreKeyNames = []string{ @@ -75,6 +76,7 @@ var ( TimeLockStoreName, AtomicSwapStoreName, MiniTokenStoreName, + MiniTokenPairStoreName, } ) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index e4877cc7a..cc868cb74 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -55,7 +55,7 @@ func (t SupplyRangeType) String() string { var SupplyRange = struct { TINY SupplyRangeType MINI SupplyRangeType -}{MiniRangeType, TinyRangeType} +}{TinyRangeType, MiniRangeType } type MiniToken struct { Name string `json:"name"` diff --git a/networks/publisher/newPublisher.sh b/networks/publisher/newPublisher.sh index 951bfa248..d0ff359f6 100755 --- a/networks/publisher/newPublisher.sh +++ b/networks/publisher/newPublisher.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash ########################### SETUP ######################### -src='/Users/zhaocong/go/src/github.com/binance-chain/node' -home='/Users/zhaocong' -deamonhome='/Users/zhaocong/.bnbchaind' -witnesshome='/Users/zhaocong/.bnbchaind_publisher' -clihome='/Users/zhaocong/.bnbcli' +src='/Users/luerheng/go/src/github.com/binance-chain/node' +home='/Users/luerheng' +deamonhome='/Users/luerheng/.bnbchaind' +witnesshome='/Users/luerheng/.bnbchaind_publisher' +clihome='/Users/luerheng/.bnbcli' chain_id='test-chain-n4b735' key_seed_path="${home}" diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index ea9ffb8bc..ecbf53e5f 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -1,11 +1,11 @@ #!/bin/bash ########################### SETUP ######################### -clipath='/Users/zhaocong/go/src/github.com/binance-chain/node/build/bnbcli' -home='/Users/zhaocong' -clihome='/Users/zhaocong/.bnbcli' +clipath='/Users/luerheng/go/src/github.com/binance-chain/node/build/bnbcli' +home='/Users/luerheng' +clihome='/Users/luerheng/.bnbcli' chainId='test-chain-n4b735' # should be same with publisher/setup.sh or testnet/deploy.sh -src='/Users/zhaocong/go/src/github.com/binance-chain/node' +src='/Users/luerheng/go/src/github.com/binance-chain/node' cli="${clipath} --home ${clihome}" scripthome="${src}/networks/publisher" diff --git a/networks/publisher/setup_mini.sh b/networks/publisher/setup_mini.sh index 738451501..187045e56 100755 --- a/networks/publisher/setup_mini.sh +++ b/networks/publisher/setup_mini.sh @@ -80,3 +80,29 @@ result=$(expect ${scripthome}/recover.exp "${secret}" "zc" "${clipath}" "${cliho result=$(expect ${scripthome}/add_key.exp "zz" "${clipath}" "${clihome}") zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") + +# issue&list NNB and ZCB for ordergen +result=$(${cli} token issue --from=zc --token-name="New BNB Coin" --symbol=NNB --total-supply=2000000000000000 --chain-id ${chain_id}) +nnb_symbol=$(echo "${result}" | tail -n 1 | grep -o "NNB-[0-9A-Z]*") +echo ${nnb_symbol} +sleep 5 +((expire_time=$(date '+%s')+1000)) +${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${nnb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 5 --json +sleep 2 +${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 1 --option Yes --json +sleep 6 +${cli} dex list -s=${nnb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 1 +sleep 1 +result=$(${cli} token issue --from=zc --token-name="ZC Coin" --symbol=ZCB --total-supply=2000000000000000 --chain-id ${chain_id}) +zcb_symbol=$(echo "${result}" | tail -n 1 | grep -o "ZCB-[0-9A-Z]*") +echo ${zcb_symbol} +sleep 5 +((expire_time=$(date '+%s')+1000)) +${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${zcb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 5 --json +sleep 2 +${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 2 --option Yes --json +sleep 6 +${cli} dex list -s=${zcb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 2 +sleep 1 +${cli} send --from=zc --to=${zz_addr} --amount=1000000000000000:BNB --chain-id ${chain_id} +sleep 5 diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index f09b9c0db..fa6b5084f 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -13,9 +13,12 @@ type TradingPairMapper = store.TradingPairMapper type DexKeeper = order.Keeper type DexMiniTokenKeeper = order.MiniKeeper type DexOrderKeeper = order.DexOrderKeeper +type DexGlobalKeeper = order.GlobalKeeper + var NewTradingPairMapper = store.NewTradingPairMapper var NewOrderKeeper = order.NewKeeper var NewMiniKeeper = order.NewMiniKeeper +var NewGlobalKeeper = order.NewGlobalKeeper const DefaultCodespace = types.DefaultCodespace diff --git a/plugins/dex/order/fee.go b/plugins/dex/order/fee.go index 807363a65..5dab9fb71 100644 --- a/plugins/dex/order/fee.go +++ b/plugins/dex/order/fee.go @@ -47,7 +47,7 @@ type FeeManager struct { FeeConfig FeeConfig } -func NewFeeManager(cdc *wire.Codec, storeKey sdk.StoreKey, logger tmlog.Logger) *FeeManager { +func NewFeeManager(cdc *wire.Codec, logger tmlog.Logger) *FeeManager { return &FeeManager{ cdc: cdc, logger: logger, diff --git a/plugins/dex/order/global_keeper.go b/plugins/dex/order/global_keeper.go new file mode 100644 index 000000000..ed72ef113 --- /dev/null +++ b/plugins/dex/order/global_keeper.go @@ -0,0 +1,308 @@ +package order + +import ( + "errors" + "fmt" + "sync" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + + tmlog "github.com/tendermint/tendermint/libs/log" + + bnclog "github.com/binance-chain/node/common/log" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/plugins/dex/matcheng" + "github.com/binance-chain/node/plugins/param/paramhub" + paramTypes "github.com/binance-chain/node/plugins/param/types" + "github.com/binance-chain/node/wire" +) + +type GlobalKeeper struct { + am auth.AccountKeeper + FeeManager *FeeManager + RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee + CollectOrderInfoForPublish bool + logger tmlog.Logger +} + +func NewGlobalKeeper(cdc *wire.Codec, am auth.AccountKeeper, collectOrderInfoForPublish bool) *GlobalKeeper { + logger := bnclog.With("module", "dex_global_keeper") + return &GlobalKeeper{ + am: am, + RoundOrderFees: make(map[string]*types.Fee, 256), + FeeManager: NewFeeManager(cdc, logger), + CollectOrderInfoForPublish: collectOrderInfoForPublish, + logger: logger, + } +} + +// deliberately make `fee` parameter not a pointer +// in case we modify the original fee (which will be referenced when distribute to validator) +func (kp *GlobalKeeper) updateRoundOrderFee(addr string, fee types.Fee) { + if existingFee, ok := kp.RoundOrderFees[addr]; ok { + existingFee.AddFee(fee) + } else { + kp.RoundOrderFees[addr] = &fee + } +} + +func (kp *GlobalKeeper) ClearRoundFee() { + kp.RoundOrderFees = make(map[string]*types.Fee, 256) +} + +func (kp *GlobalKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer), engines map[string]*matcheng.MatchEng) ( + types.Fee, map[string]*types.Fee) { + if !sdk.IsUpgrade(upgrade.BEP19) { + return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler, engines) + } + + // use string of the addr as the key since map makes a fast path for string key. + // Also, making the key have same length is also an optimization. + tradeTransfers := make(map[string]TradeTransfers) + // expire fee is fixed, so we count by numbers. + expireTransfers := make(map[string]ExpireTransfers) + // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. + var expireEventType transferEventType + var totalFee types.Fee + for tran := range tranCh { + kp.doTransfer(ctx, &tran) + if !tran.FeeFree() { + addrStr := string(tran.accAddress.Bytes()) + // need a copy of tran as it is reused + tranCp := tran + if tran.IsExpiredWithFee() { + expireEventType = tran.eventType + if _, ok := expireTransfers[addrStr]; !ok { + expireTransfers[addrStr] = ExpireTransfers{&tranCp} + } else { + expireTransfers[addrStr] = append(expireTransfers[addrStr], &tranCp) + } + } else if tran.eventType == eventFilled { + if _, ok := tradeTransfers[addrStr]; !ok { + tradeTransfers[addrStr] = TradeTransfers{&tranCp} + } else { + tradeTransfers[addrStr] = append(tradeTransfers[addrStr], &tranCp) + } + } + } else if tran.IsExpire() { + if postAllocateHandler != nil { + postAllocateHandler(tran) + } + } + } + + feesPerAcc := make(map[string]*types.Fee) + for addrStr, trans := range tradeTransfers { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, engines) + if !fees.IsEmpty() { + feesPerAcc[addrStr] = &fees + acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) + kp.am.SetAccount(ctx, acc) + totalFee.AddFee(fees) + } + } + + for addrStr, trans := range expireTransfers { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + + fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, engines, postAllocateHandler) + if !fees.IsEmpty() { + if _, ok := feesPerAcc[addrStr]; ok { + feesPerAcc[addrStr].AddFee(fees) + } else { + feesPerAcc[addrStr] = &fees + } + acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) + kp.am.SetAccount(ctx, acc) + totalFee.AddFee(fees) + } + } + return totalFee, feesPerAcc +} + +func (kp *GlobalKeeper) allocateAndCalcFee( + ctx sdk.Context, + tradeOuts []chan Transfer, + postAlloTransHandler TransferHandler, + engines map[string]*matcheng.MatchEng) types.Fee { + concurrency := len(tradeOuts) + var wg sync.WaitGroup + wg.Add(concurrency) + feesPerCh := make([]types.Fee, concurrency) + feesPerAcc := make([]map[string]*types.Fee, concurrency) + allocatePerCh := func(index int, tranCh <-chan Transfer) { + defer wg.Done() + fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler, engines) + feesPerCh[index].AddFee(fee) + feesPerAcc[index] = feeByAcc + } + + for i, tradeTranCh := range tradeOuts { + go allocatePerCh(i, tradeTranCh) + } + wg.Wait() + totalFee := types.Fee{} + for i := 0; i < concurrency; i++ { + totalFee.AddFee(feesPerCh[i]) + } + if kp.CollectOrderInfoForPublish { + for _, m := range feesPerAcc { + for k, v := range m { + kp.updateRoundOrderFee(k, *v) + } + } + } + return totalFee +} + +// DEPRECATED +func (kp *GlobalKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer), engines map[string]*matcheng.MatchEng) ( + types.Fee, map[string]*types.Fee) { + // use string of the addr as the key since map makes a fast path for string key. + // Also, making the key have same length is also an optimization. + tradeInAsset := make(map[string]*sortedAsset) + // expire fee is fixed, so we count by numbers. + expireInAsset := make(map[string]*sortedAsset) + // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. + var expireEventType transferEventType + var totalFee types.Fee + for tran := range tranCh { + kp.doTransfer(ctx, &tran) + if !tran.FeeFree() { + addrStr := string(tran.accAddress.Bytes()) + if tran.IsExpiredWithFee() { + expireEventType = tran.eventType + fees, ok := expireInAsset[addrStr] + if !ok { + fees = &sortedAsset{} + expireInAsset[addrStr] = fees + } + fees.addAsset(tran.inAsset, 1) + } else if tran.eventType == eventFilled { + fees, ok := tradeInAsset[addrStr] + if !ok { + fees = &sortedAsset{} + tradeInAsset[addrStr] = fees + } + // no possible to overflow, for tran.in == otherSide.tran.out <= TotalSupply(otherSide.tran.outAsset) + fees.addAsset(tran.inAsset, tran.in) + } + } + if postAllocateHandler != nil { + postAllocateHandler(tran) + } + } + + feesPerAcc := make(map[string]*types.Fee) + collectFee := func(assetsMap map[string]*sortedAsset, calcFeeAndDeduct func(acc sdk.Account, in sdk.Coin) types.Fee) { + for addrStr, assets := range assetsMap { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + + var fees types.Fee + if exists, ok := feesPerAcc[addrStr]; ok { + fees = *exists + } + if assets.native != 0 { + fee := calcFeeAndDeduct(acc, sdk.NewCoin(types.NativeTokenSymbol, assets.native)) + fees.AddFee(fee) + totalFee.AddFee(fee) + } + for _, asset := range assets.tokens { + fee := calcFeeAndDeduct(acc, asset) + fees.AddFee(fee) + totalFee.AddFee(fee) + } + if !fees.IsEmpty() { + feesPerAcc[addrStr] = &fees + kp.am.SetAccount(ctx, acc) + } + } + } + collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { + fee := kp.FeeManager.CalcTradeFee(acc.GetCoins(), in, engines) + acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) + return fee + }) + collectFee(expireInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { + var i int64 = 0 + var fees types.Fee + for ; i < in.Amount; i++ { + fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, engines) + acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) + fees.AddFee(fee) + } + return fees + }) + return totalFee, feesPerAcc +} + +func (kp *GlobalKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { + account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) + newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) + // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. + // they should never happen, there would be a severe bug if happen and we have to cancel all orders when app restarts. + if !newLocked.IsNotNegative() { + panic(fmt.Errorf( + "no enough locked tokens to unlock, oid: %s, newLocked: %s, unlock: %d", + tran.Oid, + newLocked.String(), + tran.unlock)) + } + if tran.unlock < tran.out { + panic(errors.New("unlocked tokens cannot cover the expense")) + } + account.SetLockedCoins(newLocked) + accountCoin := account.GetCoins(). + Plus(sdk.Coins{sdk.NewCoin(tran.inAsset, tran.in)}) + if remain := tran.unlock - tran.out; remain > 0 || !sdk.IsUpgrade(upgrade.FixZeroBalance) { + accountCoin = accountCoin.Plus(sdk.Coins{sdk.NewCoin(tran.outAsset, remain)}) + } + account.SetCoins(accountCoin) + + kp.am.SetAccount(ctx, account) + return nil +} + +func (kp *GlobalKeeper) SubscribeParamChange(hub *paramhub.Keeper) { + hub.SubscribeParamChange( + func(ctx sdk.Context, changes []interface{}) { + for _, c := range changes { + switch change := c.(type) { + case []paramTypes.FeeParam: + feeConfig := ParamToFeeConfig(change) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } + default: + kp.logger.Debug("Receive param changes that not interested.") + } + } + }, + func(context sdk.Context, state paramTypes.GenesisState) { + feeConfig := ParamToFeeConfig(state.FeeGenesis) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } else { + panic("Genesis with no dex fee config ") + } + }, + func(context sdk.Context, iLoad interface{}) { + switch load := iLoad.(type) { + case []paramTypes.FeeParam: + feeConfig := ParamToFeeConfig(load) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } else { + panic("Load with no dex fee config ") + } + default: + kp.logger.Debug("Receive param load that not interested.") + } + }) +} diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index ccb4a3b2a..3bcb84375 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -25,7 +25,7 @@ type NewOrderResponse struct { } // NewHandler - returns a handler for dex type messages. -func NewHandler(cdc *wire.Codec, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, accKeeper auth.AccountKeeper) sdk.Handler { +func NewHandler(cdc *wire.Codec, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, dexGlobalKeeper *GlobalKeeper, accKeeper auth.AccountKeeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case NewOrderMsg: @@ -33,7 +33,7 @@ func NewHandler(cdc *wire.Codec, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, a return handleNewOrder(ctx, cdc, orderKeeper, msg) case CancelOrderMsg: orderKeeper, _ := selectKeeper(msg, dexKeeper, dexMiniKeeper) - return handleCancelOrder(ctx, orderKeeper, msg) + return handleCancelOrder(ctx, orderKeeper, dexGlobalKeeper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -186,7 +186,7 @@ func handleNewOrder( // Handle CancelOffer - func handleCancelOrder( - ctx sdk.Context, keeper DexOrderKeeper, msg CancelOrderMsg, + ctx sdk.Context, keeper DexOrderKeeper, dexGlobalKeeper *GlobalKeeper, msg CancelOrderMsg, ) sdk.Result { origOrd, ok := keeper.OrderExists(msg.Symbol, msg.RefId) @@ -207,7 +207,7 @@ func handleCancelOrder( return sdk.NewError(types.DefaultCodespace, types.CodeFailLocateOrderToCancel, err.Error()).Result() } transfer := TransferFromCanceled(ord, origOrd, false) - sdkError := keeper.doTransfer(ctx, &transfer) + sdkError := dexGlobalKeeper.doTransfer(ctx, &transfer) if sdkError != nil { return sdkError.Result() } @@ -232,7 +232,7 @@ func handleCancelOrder( if keeper.ShouldPublishOrder() { change := OrderChange{msg.RefId, Canceled, fee.String(), nil} keeper.UpdateOrderChange(change) - keeper.updateRoundOrderFee(string(msg.Sender), fee) + dexGlobalKeeper.updateRoundOrderFee(string(msg.Sender), fee) } }) if err != nil { diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 88e18d122..6796fccbc 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -8,12 +8,9 @@ import ( "sync" "time" - dbm "github.com/tendermint/tendermint/libs/db" - tmlog "github.com/tendermint/tendermint/libs/log" - tmstore "github.com/tendermint/tendermint/store" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + tmlog "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/common/fees" bnclog "github.com/binance-chain/node/common/log" @@ -24,8 +21,6 @@ import ( "github.com/binance-chain/node/plugins/dex/store" dexTypes "github.com/binance-chain/node/plugins/dex/types" dexUtils "github.com/binance-chain/node/plugins/dex/utils" - "github.com/binance-chain/node/plugins/param/paramhub" - paramTypes "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/wire" ) @@ -48,7 +43,6 @@ type DexOrderKeeper interface { RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) OrderExists(symbol, id string) (OrderInfo, bool) - SubscribeParamChange(hub *paramhub.Keeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder GetOrderBooks(maxLevels int) ChangedPriceLevelsMap @@ -58,30 +52,25 @@ type DexOrderKeeper interface { ClearOrderBook(pair string) ClearOrderChanges() StoreTradePrices(ctx sdk.Context) - MatchSymbols(height, timestamp int64) ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 - ClearRoundFee() ClearOrders() DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) - ReplayOrdersFromBlock(ctx sdk.Context, bc *tmstore.BlockStore, stateDb dbm.DB, lastHeight, breatheHeight int64, - txDecoder sdk.TxDecoder) error GetPairMapper() store.TradingPairMapper GetOrderChanges() OrderChanges GetOrderInfosForPub() OrderInfoForPublish + GetGlobalKeeper() *GlobalKeeper getAccountKeeper() *auth.AccountKeeper getLogger() tmlog.Logger getFeeManager() *FeeManager getEngines() map[string]*me.MatchEng ShouldPublishOrder() bool - doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error - updateRoundOrderFee(addr string, fee types.Fee) UpdateOrderChange(change OrderChange) validateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error } @@ -90,7 +79,6 @@ var _ DexOrderKeeper = &Keeper{} // in the future, this may be distributed via Sharding type Keeper struct { PairMapper store.TradingPairMapper - am auth.AccountKeeper storeKey sdk.StoreKey // The key used to access the store from the Context. codespace sdk.CodespaceType engines map[string]*me.MatchEng @@ -101,13 +89,11 @@ type Keeper struct { OrderInfosForPub OrderInfoForPublish // for publication usage roundOrders map[string][]string // limit to the total tx number in a block roundIOCOrders map[string][]string - RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee - poolSize uint // number of concurrent channels, counted in the pow of 2 + poolSize uint // number of concurrent channels, counted in the pow of 2 cdc *wire.Codec - FeeManager *FeeManager - CollectOrderInfoForPublish bool logger tmlog.Logger symbolSelector SymbolSelector + GlobalKeeper *GlobalKeeper } func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { @@ -115,12 +101,11 @@ func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { } // NewKeeper - Returns the Keeper -func NewKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, - concurrency uint, cdc *wire.Codec, collectOrderInfoForPublish bool) *Keeper { +func NewKeeper(key sdk.StoreKey, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, + concurrency uint, cdc *wire.Codec, globalKeeper *GlobalKeeper) *Keeper { logger := bnclog.With("module", "dexkeeper") return &Keeper{ PairMapper: tradingPairMapper, - am: am, storeKey: key, codespace: codespace, engines: make(map[string]*me.MatchEng), @@ -131,13 +116,11 @@ func NewKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store. OrderInfosForPub: make(OrderInfoForPublish), roundOrders: make(map[string][]string, 256), roundIOCOrders: make(map[string][]string, 256), - RoundOrderFees: make(map[string]*types.Fee, 256), poolSize: concurrency, cdc: cdc, - FeeManager: NewFeeManager(cdc, key, logger), - CollectOrderInfoForPublish: collectOrderInfoForPublish, logger: logger, symbolSelector: &BEP2SymbolSelector{}, + GlobalKeeper: globalKeeper, } } @@ -243,7 +226,7 @@ func (kp *Keeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { return err } - if kp.CollectOrderInfoForPublish { + if kp.GlobalKeeper.CollectOrderInfoForPublish { change := OrderChange{info.Id, Ack, "", nil} // deliberately not add this message to orderChanges if !isRecovery { @@ -333,44 +316,6 @@ func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { return sum % bucketNumber } -func (kp *Keeper) SubscribeParamChange(hub *paramhub.Keeper) { - hub.SubscribeParamChange( - func(ctx sdk.Context, changes []interface{}) { - for _, c := range changes { - switch change := c.(type) { - case []paramTypes.FeeParam: - feeConfig := ParamToFeeConfig(change) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } - default: - kp.logger.Debug("Receive param changes that not interested.") - } - } - }, - func(context sdk.Context, state paramTypes.GenesisState) { - feeConfig := ParamToFeeConfig(state.FeeGenesis) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } else { - panic("Genesis with no dex fee config ") - } - }, - func(context sdk.Context, iLoad interface{}) { - switch load := iLoad.(type) { - case []paramTypes.FeeParam: - feeConfig := ParamToFeeConfig(load) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } else { - panic("Load with no dex fee config ") - } - default: - kp.logger.Debug("Receive param load that not interested.") - } - }) -} - // Run as postConsume procedure of async, no concurrent updates of orders map func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { order.CumQty = cumQty @@ -378,7 +323,6 @@ func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { order.LastUpdatedTimestamp = timestamp } - func (kp *Keeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { orderbook := make([]store.OrderBookLevel, maxLevels) @@ -477,33 +421,6 @@ func (kp *Keeper) ClearOrderChanges() { kp.OrderChanges = kp.OrderChanges[:0] } -func (kp *Keeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { - account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) - newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) - // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. - // they should never happen, there would be a severe bug if happen and we have to cancel all orders when app restarts. - if !newLocked.IsNotNegative() { - panic(fmt.Errorf( - "no enough locked tokens to unlock, oid: %s, newLocked: %s, unlock: %d", - tran.Oid, - newLocked.String(), - tran.unlock)) - } - if tran.unlock < tran.out { - panic(errors.New("unlocked tokens cannot cover the expense")) - } - account.SetLockedCoins(newLocked) - accountCoin := account.GetCoins(). - Plus(sdk.Coins{sdk.NewCoin(tran.inAsset, tran.in)}) - if remain := tran.unlock - tran.out; remain > 0 || !sdk.IsUpgrade(upgrade.FixZeroBalance) { - accountCoin = accountCoin.Plus(sdk.Coins{sdk.NewCoin(tran.outAsset, remain)}) - } - account.SetCoins(accountCoin) - - kp.am.SetAccount(ctx, account) - return nil -} - func (kp *Keeper) StoreTradePrices(ctx sdk.Context) { // TODO: check block height != 0 if ctx.BlockHeight()%pricesStoreEvery == 0 { @@ -521,195 +438,6 @@ func (kp *Keeper) StoreTradePrices(ctx sdk.Context) { } } -func (kp *Keeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( - types.Fee, map[string]*types.Fee) { - if !sdk.IsUpgrade(upgrade.BEP19) { - return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler) - } - - // use string of the addr as the key since map makes a fast path for string key. - // Also, making the key have same length is also an optimization. - tradeTransfers := make(map[string]TradeTransfers) - // expire fee is fixed, so we count by numbers. - expireTransfers := make(map[string]ExpireTransfers) - // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. - var expireEventType transferEventType - var totalFee types.Fee - for tran := range tranCh { - kp.doTransfer(ctx, &tran) - if !tran.FeeFree() { - addrStr := string(tran.accAddress.Bytes()) - // need a copy of tran as it is reused - tranCp := tran - if tran.IsExpiredWithFee() { - expireEventType = tran.eventType - if _, ok := expireTransfers[addrStr]; !ok { - expireTransfers[addrStr] = ExpireTransfers{&tranCp} - } else { - expireTransfers[addrStr] = append(expireTransfers[addrStr], &tranCp) - } - } else if tran.eventType == eventFilled { - if _, ok := tradeTransfers[addrStr]; !ok { - tradeTransfers[addrStr] = TradeTransfers{&tranCp} - } else { - tradeTransfers[addrStr] = append(tradeTransfers[addrStr], &tranCp) - } - } - } else if tran.IsExpire() { - if postAllocateHandler != nil { - postAllocateHandler(tran) - } - } - } - - feesPerAcc := make(map[string]*types.Fee) - for addrStr, trans := range tradeTransfers { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, kp.engines) - if !fees.IsEmpty() { - feesPerAcc[addrStr] = &fees - acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) - kp.am.SetAccount(ctx, acc) - totalFee.AddFee(fees) - } - } - - for addrStr, trans := range expireTransfers { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - - fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, kp.engines, postAllocateHandler) - if !fees.IsEmpty() { - if _, ok := feesPerAcc[addrStr]; ok { - feesPerAcc[addrStr].AddFee(fees) - } else { - feesPerAcc[addrStr] = &fees - } - acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) - kp.am.SetAccount(ctx, acc) - totalFee.AddFee(fees) - } - } - return totalFee, feesPerAcc -} - -// DEPRECATED -func (kp *Keeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( - types.Fee, map[string]*types.Fee) { - // use string of the addr as the key since map makes a fast path for string key. - // Also, making the key have same length is also an optimization. - tradeInAsset := make(map[string]*sortedAsset) - // expire fee is fixed, so we count by numbers. - expireInAsset := make(map[string]*sortedAsset) - // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. - var expireEventType transferEventType - var totalFee types.Fee - for tran := range tranCh { - kp.doTransfer(ctx, &tran) - if !tran.FeeFree() { - addrStr := string(tran.accAddress.Bytes()) - if tran.IsExpiredWithFee() { - expireEventType = tran.eventType - fees, ok := expireInAsset[addrStr] - if !ok { - fees = &sortedAsset{} - expireInAsset[addrStr] = fees - } - fees.addAsset(tran.inAsset, 1) - } else if tran.eventType == eventFilled { - fees, ok := tradeInAsset[addrStr] - if !ok { - fees = &sortedAsset{} - tradeInAsset[addrStr] = fees - } - // no possible to overflow, for tran.in == otherSide.tran.out <= TotalSupply(otherSide.tran.outAsset) - fees.addAsset(tran.inAsset, tran.in) - } - } - if postAllocateHandler != nil { - postAllocateHandler(tran) - } - } - - feesPerAcc := make(map[string]*types.Fee) - collectFee := func(assetsMap map[string]*sortedAsset, calcFeeAndDeduct func(acc sdk.Account, in sdk.Coin) types.Fee) { - for addrStr, assets := range assetsMap { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - - var fees types.Fee - if exists, ok := feesPerAcc[addrStr]; ok { - fees = *exists - } - if assets.native != 0 { - fee := calcFeeAndDeduct(acc, sdk.NewCoin(types.NativeTokenSymbol, assets.native)) - fees.AddFee(fee) - totalFee.AddFee(fee) - } - for _, asset := range assets.tokens { - fee := calcFeeAndDeduct(acc, asset) - fees.AddFee(fee) - totalFee.AddFee(fee) - } - if !fees.IsEmpty() { - feesPerAcc[addrStr] = &fees - kp.am.SetAccount(ctx, acc) - } - } - } - collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { - fee := kp.FeeManager.CalcTradeFee(acc.GetCoins(), in, kp.engines) - acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - return fee - }) - collectFee(expireInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { - var i int64 = 0 - var fees types.Fee - for ; i < in.Amount; i++ { - fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, kp.engines) - acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - fees.AddFee(fee) - } - return fees - }) - return totalFee, feesPerAcc -} - -func (kp *Keeper) allocateAndCalcFee( - ctx sdk.Context, - tradeOuts []chan Transfer, - postAlloTransHandler TransferHandler, -) types.Fee { - concurrency := len(tradeOuts) - var wg sync.WaitGroup - wg.Add(concurrency) - feesPerCh := make([]types.Fee, concurrency) - feesPerAcc := make([]map[string]*types.Fee, concurrency) - allocatePerCh := func(index int, tranCh <-chan Transfer) { - defer wg.Done() - fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) - feesPerCh[index].AddFee(fee) - feesPerAcc[index] = feeByAcc - } - - for i, tradeTranCh := range tradeOuts { - go allocatePerCh(i, tradeTranCh) - } - wg.Wait() - totalFee := types.Fee{} - for i := 0; i < concurrency; i++ { - totalFee.AddFee(feesPerCh[i]) - } - if kp.CollectOrderInfoForPublish { - for _, m := range feesPerAcc { - for k, v := range m { - kp.updateRoundOrderFee(k, *v) - } - } - } - return totalFee -} func (kp *Keeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { size := len(kp.allOrders) @@ -786,7 +514,7 @@ func (kp *Keeper) ExpireOrders( return } - totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAlloTransHandler) + totalFee := kp.GlobalKeeper.allocateAndCalcFee(ctx, transferChs, postAlloTransHandler, kp.engines) fees.Pool.AddAndCommitFee("EXPIRE", totalFee) } @@ -847,20 +575,6 @@ func (kp *Keeper) GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight i } } -// deliberately make `fee` parameter not a pointer -// in case we modify the original fee (which will be referenced when distribute to validator) -func (kp *Keeper) updateRoundOrderFee(addr string, fee types.Fee) { - if existingFee, ok := kp.RoundOrderFees[addr]; ok { - existingFee.AddFee(fee) - } else { - kp.RoundOrderFees[addr] = &fee - } -} - -func (kp *Keeper) ClearRoundFee() { - kp.RoundOrderFees = make(map[string]*types.Fee, 256) -} - // used by state sync to clear memory order book after we synced latest breathe block func (kp *Keeper) ClearOrders() { kp.engines = make(map[string]*me.MatchEng) @@ -879,7 +593,7 @@ func (kp *Keeper) DelistTradingPair(ctx sdk.Context, symbol string, postAllocTra transferChs := kp.expireAllOrders(ctx, symbol) if transferChs != nil { - totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAllocTransHandler) + totalFee := kp.GlobalKeeper.allocateAndCalcFee(ctx, transferChs, postAllocTransHandler, kp.engines) fees.Pool.AddAndCommitFee(fmt.Sprintf("DELIST_%s", symbol), totalFee) } @@ -1015,7 +729,7 @@ func (kp *Keeper) GetOrderInfosForPub() OrderInfoForPublish { } func (kp *Keeper) getAccountKeeper() *auth.AccountKeeper { - return &kp.am + return &kp.GlobalKeeper.am } func (kp *Keeper) getLogger() tmlog.Logger { @@ -1023,11 +737,11 @@ func (kp *Keeper) getLogger() tmlog.Logger { } func (kp *Keeper) getFeeManager() *FeeManager { - return kp.FeeManager + return kp.GlobalKeeper.FeeManager } func (kp *Keeper) ShouldPublishOrder() bool { - return kp.CollectOrderInfoForPublish + return kp.GlobalKeeper.CollectOrderInfoForPublish } func (kp *Keeper) getEngines() map[string]*me.MatchEng { @@ -1075,3 +789,7 @@ func (kp *Keeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrderMs return nil } + +func (kp *Keeper) GetGlobalKeeper() *GlobalKeeper { + return kp.GlobalKeeper +} diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 0c5f60506..8fc5dc1a7 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -1,6 +1,7 @@ package order import ( + "github.com/binance-chain/node/plugins/dex/matcheng" sdk "github.com/cosmos/cosmos-sdk/types" tmlog "github.com/tendermint/tendermint/libs/log" @@ -16,16 +17,29 @@ func MatchAndAllocateSymbols(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx s symbolsToMatch := dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols) symbolsToMatch = append(symbolsToMatch, dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols)...) + logger.Debug("symbols to match", "symbols", symbolsToMatch) + tradeOuts := matchAndDistributeTrades(dexKeeper, dexMiniKeeper, true, ctx.BlockHeader().Height, timestamp, symbolsToMatch, logger) if tradeOuts == nil { logger.Info("No order comes in for the block") } - totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) + globalKeeper := dexKeeper.GlobalKeeper + totalFee := globalKeeper.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler, mergeMatchEngineMap(dexKeeper.engines, dexMiniKeeper.engines)) fees.Pool.AddAndCommitFee("MATCH", totalFee) clearAfterMatchBEP2(dexKeeper) clearAfterMatchMini(dexMiniKeeper) } +func mergeMatchEngineMap(ms ...map[string]*matcheng.MatchEng) map[string]*matcheng.MatchEng { + res := make(map[string]*matcheng.MatchEng) + for _, m := range ms { + for k, v := range m { + res[k] = v + } + } + return res +} + func clearAfterMatchBEP2(kp *Keeper) { kp.logger.Debug("clearAfterMatchBEP2...") kp.roundOrders = make(map[string][]string, 256) @@ -96,81 +110,20 @@ func matchAndDistributeTrades(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, dist return tradeOuts } -func (kp *Keeper) MatchSymbols(height, timestamp int64) { - symbolsToMatch := kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, timestamp, false) - kp.logger.Debug("symbols to match", "symbols", symbolsToMatch) - tradeOuts := kp.matchAndDistributeTrades(false, height, timestamp, symbolsToMatch) //only match +func MatchSymbols(height, timestamp int64, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, matchAllSymbols bool, logger tmlog.Logger) { + symbolsToMatch := dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, height, timestamp, matchAllSymbols) + symbolsToMatch = append(symbolsToMatch, dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, height, timestamp, matchAllSymbols)...) + logger.Debug("symbols to match", "symbols", symbolsToMatch) + + tradeOuts := matchAndDistributeTrades(dexKeeper, dexMiniKeeper, true, height, timestamp, symbolsToMatch, logger) + if tradeOuts == nil { - kp.logger.Info("No order comes in for the block") + logger.Info("No order comes in for the block") } clearAfterMatchBEP2(dexKeeper) clearAfterMatchMini(dexMiniKeeper) } -// MatchAndAllocateSymbols() is concurrently matching and allocating across -// all the symbols' order books, among all the clients -// Return whether match has been done in this height -//func (kp *Keeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { -// kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(kp.roundOrders)) -// timestamp := ctx.BlockHeader().Time.UnixNano() -// -// symbolsToMatch := kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols) -// tradeOuts := kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp, symbolsToMatch) -// if tradeOuts == nil { -// kp.logger.Info("No order comes in for the block") -// } -// totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) -// fees.Pool.AddAndCommitFee("MATCH", totalFee) -// kp.clearAfterMatch(kp) -//} - -//// please note if distributeTrade this method will work in async mode, otherwise in sync mode. -//func (kp *Keeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64, symbolsToMatch []string) []chan Transfer { -// if len(symbolsToMatch) == 0 { -// kp.logger.Info("No symbols to match in the block") -// return nil -// } -// concurrency := 1 << kp.poolSize -// tradeOuts := make([]chan Transfer, concurrency) -// -// if distributeTrade { -// ordNum := 0 -// for _, symbol := range symbolsToMatch { -// ordNum += len(kp.roundOrders[symbol]) -// } -// for i := range tradeOuts { -// //assume every new order would have 2 trades and generate 4 transfer -// tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) -// } -// } -// -// symbolCh := make(chan string, concurrency) -// producer := func() { -// for _, symbol := range symbolsToMatch { -// symbolCh <- symbol -// } -// close(symbolCh) -// } -// matchWorker := func() { -// i := 0 -// for symbol := range symbolCh { -// i++ -// kp.matchAndDistributeTradesForSymbol(symbol, height, timestamp, kp.allOrders[symbol], distributeTrade, tradeOuts) -// } -// } -// -// if distributeTrade { -// utils.ConcurrentExecuteAsync(concurrency, producer, matchWorker, func() { -// for _, tradeOut := range tradeOuts { -// close(tradeOut) -// } -// }) -// } else { -// utils.ConcurrentExecuteSync(concurrency, producer, matchWorker) -// } -// return tradeOuts -//} - func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, timestamp int64, orders map[string]*OrderInfo, distributeTrade bool, tradeOuts []chan Transfer) { engine := kp.engines[symbol] @@ -220,7 +173,7 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times // let the order status publisher publish these abnormal // order status change outs. - if kp.CollectOrderInfoForPublish { + if kp.GlobalKeeper.CollectOrderInfoForPublish { kp.OrderChangesMtx.Lock() kp.OrderChanges = append(kp.OrderChanges, OrderChange{id, FailedMatching, "", nil}) kp.OrderChangesMtx.Unlock() diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 7e9a2844a..6f43d1cd3 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -24,6 +24,7 @@ import ( "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/common/utils" me "github.com/binance-chain/node/plugins/dex/matcheng" + dexUtils "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/wire" ) @@ -59,7 +60,6 @@ func compressAndSave(snapshot interface{}, cdc *wire.Codec, key string, kv sdk.K return nil } - func Init(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { initOrderBook(dexKeeper, dexMiniKeeper, ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) dexKeeper.InitRecentPrices(ctx) @@ -177,12 +177,12 @@ func (kp *Keeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64 symbol := strings.ToUpper(m.Symbol) kp.allOrders[symbol][m.Id] = &orderHolder if m.CreatedHeight == height { - kp.roundOrders[symbol] = append(kp.roundOrders[symbol], m.Id) - if m.TimeInForce == TimeInForce.IOC { - kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], m.Id) - } + kp.roundOrders[symbol] = append(kp.roundOrders[symbol], m.Id) + if m.TimeInForce == TimeInForce.IOC { + kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], m.Id) + } } - if kp.CollectOrderInfoForPublish { + if kp.GlobalKeeper.CollectOrderInfoForPublish { if _, exists := kp.OrderInfosForPub[m.Id]; !exists { bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", m.Id) kp.OrderInfosForPub[m.Id] = &orderHolder @@ -193,7 +193,7 @@ func (kp *Keeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64 return height, nil } -func (kp *Keeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, stateDB dbm.DB, txDecoder sdk.TxDecoder, +func replayOneBlocks(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, logger log.Logger, block *tmtypes.Block, stateDB dbm.DB, txDecoder sdk.TxDecoder, height int64, timestamp time.Time) { if block == nil { logger.Error("No block is loaded. Ignore replay for orderbook") @@ -208,6 +208,7 @@ func (kp *Keeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, state } // the time we replay should be consistent with ctx.BlockHeader().Time t := timestamp.UnixNano() + var orderKeeper DexOrderKeeper for idx, txBytes := range block.Txs { if abciRes.DeliverTx[idx].IsErr() { logger.Info("Skip tx when replay", "height", height, "idx", idx) @@ -235,13 +236,23 @@ func (kp *Keeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, state height, t, height, t, 0, txHash.String(), txSource} - kp.AddOrder(orderInfo, true) + if (!sdk.IsUpgrade(upgrade.BEP8)) || !dexUtils.IsMiniTokenTradingPair(msg.Symbol) { + orderKeeper = dexKeeper + } else { + orderKeeper = dexMiniKeeper + } + orderKeeper.AddOrder(orderInfo, true) logger.Info("Added Order", "order", msg) case CancelOrderMsg: - err := kp.RemoveOrder(msg.RefId, msg.Symbol, func(ord me.OrderPart) { - if kp.CollectOrderInfoForPublish { + if (!sdk.IsUpgrade(upgrade.BEP8)) || !dexUtils.IsMiniTokenTradingPair(msg.Symbol) { + orderKeeper = dexKeeper + } else { + orderKeeper = dexMiniKeeper + } + err := orderKeeper.RemoveOrder(msg.RefId, msg.Symbol, func(ord me.OrderPart) { + if orderKeeper.GetGlobalKeeper().CollectOrderInfoForPublish { bnclog.Debug("deleted order from order changes map", "orderId", msg.RefId, "isRecovery", true) - delete(kp.OrderInfosForPub, msg.RefId) + delete(orderKeeper.GetOrderInfosForPub(), msg.RefId) } }) if err != nil { @@ -252,16 +263,16 @@ func (kp *Keeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, state } } logger.Info("replayed all tx. Starting match", "height", height) - kp.MatchSymbols(height, t) //no need to check result + MatchSymbols(height, t, dexKeeper, dexMiniKeeper, false, logger) //no need to check result } -func (kp *Keeper) ReplayOrdersFromBlock(ctx sdk.Context, bc *tmstore.BlockStore, stateDb dbm.DB, lastHeight, breatheHeight int64, +func ReplayOrdersFromBlock(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, bc *tmstore.BlockStore, stateDb dbm.DB, lastHeight, breatheHeight int64, txDecoder sdk.TxDecoder) error { for i := breatheHeight + 1; i <= lastHeight; i++ { block := bc.LoadBlock(i) ctx.Logger().Info("Relaying block for order book", "height", i) upgrade.Mgr.SetHeight(i) - kp.replayOneBlocks(ctx.Logger(), block, stateDb, txDecoder, i, block.Time) + replayOneBlocks(dexKeeper, dexMiniKeeper, ctx.Logger(), block, stateDb, txDecoder, i, block.Time) } return nil } @@ -275,13 +286,15 @@ func initOrderBook(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context timeOfLatestBlock = block.Time } height, err := dexKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) - height, err = dexMiniKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) + if sdk.IsUpgrade(upgrade.BEP8) { + _, err = dexMiniKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) + } if err != nil { panic(err) } logger := ctx.Logger().With("module", "dex") - logger.Info("Initialized Block Store for replay", "toHeight", lastHeight) - err = kp.ReplayOrdersFromBlock(ctx.WithLogger(logger), blockStore, stateDB, lastHeight, height, txDecoder) + logger.Info("Initialized Block Store for replay", "fromHeight", height, "toHeight", lastHeight) + err = ReplayOrdersFromBlock(dexKeeper, dexMiniKeeper, ctx.WithLogger(logger), blockStore, stateDB, lastHeight, height, txDecoder) if err != nil { panic(err) } diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index a883be983..210a07ca4 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -3,6 +3,11 @@ package order import ( "errors" "fmt" + "github.com/binance-chain/node/common/upgrade" + "strings" + "sync" + "time" + bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/utils" @@ -11,9 +16,6 @@ import ( dexTypes "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/wire" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "strings" - "sync" ) const ( @@ -29,30 +31,27 @@ type MiniKeeper struct { var _ DexOrderKeeper = &MiniKeeper{} // NewKeeper - Returns the MiniToken Keeper -func NewMiniKeeper(dexMiniKey sdk.StoreKey, am auth.AccountKeeper, miniPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, - concurrency uint, cdc *wire.Codec, collectOrderInfoForPublish bool) *MiniKeeper { +func NewMiniKeeper(dexMiniKey sdk.StoreKey, miniPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, + concurrency uint, cdc *wire.Codec, globalKeeper *GlobalKeeper) *MiniKeeper { logger := bnclog.With("module", "dexkeeper") return &MiniKeeper{ Keeper{PairMapper: miniPairMapper, - am: am, - storeKey: dexMiniKey, - codespace: codespace, - engines: make(map[string]*me.MatchEng), - recentPrices: make(map[string]*utils.FixedSizeRing, 256), - allOrders: make(map[string]map[string]*OrderInfo, 256), // need to init the nested map when a new symbol added. - OrderChangesMtx: &sync.Mutex{}, - OrderChanges: make(OrderChanges, 0), - OrderInfosForPub: make(OrderInfoForPublish), - roundOrders: make(map[string][]string, 256), - roundIOCOrders: make(map[string][]string, 256), - RoundOrderFees: make(map[string]*types.Fee, 256), - poolSize: concurrency, - cdc: cdc, - FeeManager: NewFeeManager(cdc, dexMiniKey, logger), - CollectOrderInfoForPublish: collectOrderInfoForPublish, - logger: logger, - symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}, - }, + storeKey: dexMiniKey, + codespace: codespace, + engines: make(map[string]*me.MatchEng), + recentPrices: make(map[string]*utils.FixedSizeRing, 256), + allOrders: make(map[string]map[string]*OrderInfo, 256), // need to init the nested map when a new symbol added. + OrderChangesMtx: &sync.Mutex{}, + OrderChanges: make(OrderChanges, 0), + OrderInfosForPub: make(OrderInfoForPublish), + roundOrders: make(map[string][]string, 256), + roundIOCOrders: make(map[string][]string, 256), + poolSize: concurrency, + cdc: cdc, + logger: logger, + symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}, + GlobalKeeper: globalKeeper, + }, } } @@ -131,3 +130,15 @@ func (kp *MiniKeeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrd } return nil } + +// override +func (kp *MiniKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) { + lastBreatheBlockHeight := kp.GetLastBreatheBlockHeight(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) + upgradeHeight := sdk.UpgradeMgr.GetUpgradeHeight(upgrade.BEP8) + kp.logger.Info("Loaded MiniKeeper orderbook ", "lastBreatheBlockHeight", lastBreatheBlockHeight, "upgradeHeight", upgradeHeight) + if lastBreatheBlockHeight < upgradeHeight { + return lastBreatheBlockHeight, nil + } else { + return kp.Keeper.LoadOrderBookSnapshot(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) + } +} diff --git a/plugins/dex/plugin.go b/plugins/dex/plugin.go index 0fcbcd130..c25ef5305 100644 --- a/plugins/dex/plugin.go +++ b/plugins/dex/plugin.go @@ -30,12 +30,12 @@ const ( // InitPlugin initializes the dex plugin. func InitPlugin( - appp app.ChainApp, dexKeeper *DexKeeper, dexMiniKeeper *DexMiniTokenKeeper, tokenMapper tkstore.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, + appp app.ChainApp, dexKeeper *DexKeeper, dexMiniKeeper *DexMiniTokenKeeper, dexGlobalKeeper *DexGlobalKeeper, tokenMapper tkstore.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, ) { cdc := appp.GetCodec() // add msg handlers - for route, handler := range Routes(cdc, dexKeeper, dexMiniKeeper, tokenMapper, miniTokenMapper, accMapper, govKeeper) { + for route, handler := range Routes(cdc, dexKeeper, dexMiniKeeper, dexGlobalKeeper, tokenMapper, miniTokenMapper, accMapper, govKeeper) { appp.GetRouter().AddRoute(route, handler) } diff --git a/plugins/dex/route.go b/plugins/dex/route.go index bc42931fe..1507c35f5 100644 --- a/plugins/dex/route.go +++ b/plugins/dex/route.go @@ -14,10 +14,10 @@ import ( ) // Routes exports dex message routes -func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, dexMiniKeeper *DexMiniTokenKeeper, tokenMapper tokens.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, +func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, dexMiniKeeper *DexMiniTokenKeeper, dexGlobalKeeper *DexGlobalKeeper, tokenMapper tokens.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accKeeper auth.AccountKeeper, govKeeper gov.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) - orderHandler := order.NewHandler(cdc, dexKeeper, dexMiniKeeper, accKeeper) + orderHandler := order.NewHandler(cdc, dexKeeper, dexMiniKeeper, dexGlobalKeeper, accKeeper) routes[order.RouteNewOrder] = orderHandler routes[order.RouteCancelOrder] = orderHandler routes[list.Route] = list.NewHandler(dexKeeper, tokenMapper, govKeeper) diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/miniTokens/client/cli/issue.go index be361c1fd..829af40e9 100644 --- a/plugins/miniTokens/client/cli/issue.go +++ b/plugins/miniTokens/client/cli/issue.go @@ -81,7 +81,7 @@ func (c Commander) issueToken(cmd *cobra.Command, args []string) error { } func checkTokenType(tokenType int) error { - if tokenType != int(types.SupplyRange.TINY) || tokenType != int(types.SupplyRange.MINI) { + if tokenType != int(types.SupplyRange.TINY) && tokenType != int(types.SupplyRange.MINI) { return errors.New("invalid token type") } return nil diff --git a/plugins/miniTokens/issue/msg.go b/plugins/miniTokens/issue/msg.go index 4dc6a1269..6df2b4f69 100644 --- a/plugins/miniTokens/issue/msg.go +++ b/plugins/miniTokens/issue/msg.go @@ -61,12 +61,12 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidCoins(fmt.Sprintf("token seturi should not exceed %v characters", types.MaxTokenURILength)) } - if msg.TokenType != int8(types.SupplyRange.MINI) || msg.TokenType != int8(types.SupplyRange.TINY) { - return sdk.ErrInvalidCoins(fmt.Sprintf("token type should be %d or %d", int8(types.SupplyRange.MINI), int8(types.SupplyRange.TINY))) + if msg.TokenType != int8(types.SupplyRange.MINI) && msg.TokenType != int8(types.SupplyRange.TINY) { + return sdk.ErrInvalidCoins(fmt.Sprintf("token type should be %d or %d, got %d", int8(types.SupplyRange.MINI), int8(types.SupplyRange.TINY), msg.TokenType)) } if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.SupplyRangeType(msg.TokenType).UpperBound() { - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.SupplyRangeType(msg.TokenType).UpperBound())) + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.SupplyRangeType(msg.TokenType).UpperBound())) } return nil From 6878065dc3de9dba8234ebffd0d649daa1a7abe1 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sat, 2 May 2020 17:52:48 +0800 Subject: [PATCH 16/96] fix wrong symbol --- networks/publisher/ordergen.sh | 10 +++++----- plugins/dex/order/keeper_match.go | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index ecbf53e5f..bcfd9d4f7 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -43,10 +43,10 @@ do pause=$(random 5 7) symbolNum=$(random 1 10) - symbol="NNB-FCA_BNB" + symbol="NNB-FE4_BNB" if [ $symbolNum -lt 4 ] then - symbol="NNB-FCA_BNB" + symbol="NNB-FE4_BNB" fi from="zc" @@ -60,8 +60,8 @@ do ${cli} dex order --symbol=${symbol} --side=${side} --price=${price}00000000 --qty=${qty}00000000 --tif="GTE" --from=${from} --chain-id=${chainId} # -d is used for get response of expect script. TODO: better log redirection -# result=$(expect -d ${scripthome}/ordergen.exp "${clipath}" "${clihome}" "${symbol}" "${side}" "${price}00000000" "${qty}00000000" "${from}" "${chainId}") + result=$(expect -d ${scripthome}/ordergen.exp "${clipath}" "${clihome}" "${symbol}" "${side}" "${price}00000000" "${qty}00000000" "${from}" "${chainId}") -# printf "\nsleep ${pause} seconds...\n" -# sleep ${pause} + printf "\nsleep ${pause} seconds...\n" + sleep ${pause} done \ No newline at end of file diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 8fc5dc1a7..eddfcdf1d 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -16,8 +16,8 @@ func MatchAndAllocateSymbols(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx s timestamp := ctx.BlockHeader().Time.UnixNano() symbolsToMatch := dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols) - symbolsToMatch = append(symbolsToMatch, dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols)...) - logger.Debug("symbols to match", "symbols", symbolsToMatch) + symbolsToMatch = append(symbolsToMatch, dexMiniKeeper.symbolSelector.SelectSymbolsToMatch(dexMiniKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols)...) + logger.Info("symbols to match", "symbols", symbolsToMatch) //todo debug tradeOuts := matchAndDistributeTrades(dexKeeper, dexMiniKeeper, true, ctx.BlockHeader().Height, timestamp, symbolsToMatch, logger) if tradeOuts == nil { From 3de38cacd8274d251764d872d943f1f7729277f7 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sun, 3 May 2020 15:57:17 +0800 Subject: [PATCH 17/96] fix abci handler for mini --- app/app.go | 2 + app_test/abci_open_orders_test.go | 2 +- networks/publisher/list_mini.sh | 32 ++++++++++++++ networks/publisher/ordergen.sh | 20 +++++---- plugins/dex/abci.go | 9 ++-- plugins/dex/order/fee_test.go | 64 ++++++++++++++-------------- plugins/dex/order/keeper_recovery.go | 4 +- plugins/dex/order/mini_keeper.go | 24 ++++++----- plugins/dex/order/symbol_selector.go | 3 +- plugins/dex/plugin.go | 15 ++++--- plugins/dex/store/codec.go | 15 ++++++- plugins/dex/store/mapper.go | 19 --------- plugins/dex/store/utils.go | 3 ++ plugins/param/plugin.go | 23 +++++----- 14 files changed, 136 insertions(+), 99 deletions(-) create mode 100755 networks/publisher/list_mini.sh diff --git a/app/app.go b/app/app.go index d7fe8b735..b84fc388d 100644 --- a/app/app.go +++ b/app/app.go @@ -38,6 +38,7 @@ import ( "github.com/binance-chain/node/plugins/account" "github.com/binance-chain/node/plugins/dex" "github.com/binance-chain/node/plugins/dex/list" + "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/ico" "github.com/binance-chain/node/plugins/minitokens" @@ -303,6 +304,7 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, miniIssue.IssueMsg{}.Type(), seturi.SetURIMsg{}.Type(), + listmini.ListMiniMsg{}.Type(), ) } diff --git a/app_test/abci_open_orders_test.go b/app_test/abci_open_orders_test.go index 098251f80..472352c70 100644 --- a/app_test/abci_open_orders_test.go +++ b/app_test/abci_open_orders_test.go @@ -101,7 +101,7 @@ func issueMustSuccessQuery(pair string, address sdk.AccAddress, assert *assert.A } func issueQuery(pair string, address string) abci.ResponseQuery { - path := fmt.Sprintf("/%s/openorders/%s/%s", dex.AbciQueryPrefix, pair, address) + path := fmt.Sprintf("/%s/openorders/%s/%s", dex.DexAbciQueryPrefix, pair, address) query := abci.RequestQuery{ Path: path, Data: []byte(""), diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh new file mode 100755 index 000000000..603ccd03a --- /dev/null +++ b/networks/publisher/list_mini.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# start a validator and witness on local machine +# later on db indexer and publisher can be setup and started by newIndexer.sh and newPublisher.sh +# later on order generation can be kicked off by ordergen.sh +# TODO: support two validator without docker in same machine + +########################### SETUP ######################### +src='/Users/luerheng/go/src/github.com/binance-chain/node' +home='/Users/luerheng' +deamonhome='/Users/luerheng/.bnbchaind' +witnesshome='/Users/luerheng/.bnbchaind_witness' +clihome='/Users/luerheng/.bnbcli' +chain_id='test-chain-n4b735' + +key_seed_path="${home}" +executable="${src}/build/bnbchaind" +clipath="${src}/build/bnbcli" +cli="${clipath} --home ${clihome}" +scripthome="${src}/networks/publisher" +############################ END ########################## + +#x1mini_symbol="x1mini-ED3" +result=$(${cli} miniToken issue --from=zc --token-name="X1MINI Coin" --symbol=X1M --total-supply=80000000000000 --token-type=2 --chain-id ${chain_id}) +x1mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "x1mini-[0-9A-Z]*") +echo ${x1mini_symbol} +sleep 2 +echo 1234qwerasdf|${cli} dex list-mini -s=${x1mini_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} +sleep 1 +zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") +echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=20000000000000:${x1mini_symbol} --chain-id ${chain_id} +sleep 5 diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index bcfd9d4f7..316aa5bc3 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -38,17 +38,21 @@ function random() while : do side=$(random 1 2) - price=$(random 1 20) - qty=$(random 10 20) + price=$(random 1 2) + qty=$(random 1 2) pause=$(random 5 7) symbolNum=$(random 1 10) - symbol="NNB-FE4_BNB" + symbol="NNB-BF1_BNB" if [ $symbolNum -lt 4 ] then - symbol="NNB-FE4_BNB" + symbol="ZCB-ED3_BNB" + elif [ $symbolNum -lt 6 ] + then + symbol="TEST1-8B2M_BNB" + else [ $symbolNum -lt 8 ] + symbol="ZIP-BECM_BNB" fi - from="zc" if [ $side == 1 ] then @@ -57,11 +61,11 @@ do printf "\n${cli} dex order --symbol=${symbol} --side=${side} --price=${price}00000000 --qty=${qty}00000000 --tif="GTE" --from=${from} --chain-id=${chainId}\n" - ${cli} dex order --symbol=${symbol} --side=${side} --price=${price}00000000 --qty=${qty}00000000 --tif="GTE" --from=${from} --chain-id=${chainId} + echo 1234qwerasdf|${cli} dex order --symbol=${symbol} --side=${side} --price=${price}00000000 --qty=${qty}00000000 --tif="GTE" --from=${from} --chain-id=${chainId} # -d is used for get response of expect script. TODO: better log redirection - result=$(expect -d ${scripthome}/ordergen.exp "${clipath}" "${clihome}" "${symbol}" "${side}" "${price}00000000" "${qty}00000000" "${from}" "${chainId}") + #result=$(expect -d ${scripthome}/ordergen.exp "${clipath}" "${clihome}" "${symbol}" "${side}" "${price}00000000" "${qty}00000000" "${from}" "${chainId}") - printf "\nsleep ${pause} seconds...\n" + #printf "\nsleep ${pause} seconds...\n" sleep ${pause} done \ No newline at end of file diff --git a/plugins/dex/abci.go b/plugins/dex/abci.go index 00616c057..1ddd28686 100644 --- a/plugins/dex/abci.go +++ b/plugins/dex/abci.go @@ -18,10 +18,11 @@ import ( const MaxDepthLevels = 1000 // matches UI requirement const DefaultDepthLevels = 100 // matches UI requirement -func createAbciQueryHandler(keeper *DexKeeper) app.AbciQueryHandler { +func createAbciQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQueryHandler { + queryPrefix := abciQueryPrefix return func(app app.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { // expects at least two query path segments. - if path[0] != AbciQueryPrefix || len(path) < 2 { + if path[0] != queryPrefix || len(path) < 2 { return nil } switch path[1] { @@ -31,7 +32,7 @@ func createAbciQueryHandler(keeper *DexKeeper) app.AbciQueryHandler { Code: uint32(sdk.CodeUnknownRequest), Log: fmt.Sprintf( "%s %s query requires offset and limit in the path", - AbciQueryPrefix, path[1]), + queryPrefix, path[1]), } } ctx := app.GetContextForCheckState() @@ -173,7 +174,7 @@ func createAbciQueryHandler(keeper *DexKeeper) app.AbciQueryHandler { Code: uint32(sdk.ABCICodeOK), Info: fmt.Sprintf( "Unknown `%s` query path: %v", - AbciQueryPrefix, path), + queryPrefix, path), } } } diff --git a/plugins/dex/order/fee_test.go b/plugins/dex/order/fee_test.go index dd6f3eea6..2fa99222f 100644 --- a/plugins/dex/order/fee_test.go +++ b/plugins/dex/order/fee_test.go @@ -28,7 +28,7 @@ func NewTestFeeConfig() FeeConfig { func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { ctx, am, keeper := setup() - keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("BNB", "XYZ-111", 1e7)) _, acc := testutils.NewAccount(ctx, am, 0) @@ -39,10 +39,10 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 100, } // no enough bnb or native fee rounding to 0 - fee := keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee := keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"ABC-000", 1}}, fee.Tokens) _, acc = testutils.NewAccount(ctx, am, 100) - fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"ABC-000", 1}}, fee.Tokens) tran = Transfer{ @@ -52,10 +52,10 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 10000, } _, acc = testutils.NewAccount(ctx, am, 1) - fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"ABC-000", 1000}}, fee.Tokens) _, acc = testutils.NewAccount(ctx, am, 100) - fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) tran = Transfer{ @@ -65,7 +65,7 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 1000, } _, acc = testutils.NewAccount(ctx, am, 100) - fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 0}}, fee.Tokens) tran = Transfer{ @@ -74,7 +74,7 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { outAsset: "ABC-000", out: 100000, } - fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) tran = Transfer{ @@ -84,7 +84,7 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 100000, } acc.SetCoins(sdk.Coins{{"ABC-000", 1000000}, {"BNB", 100}}) - fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) tran = Transfer{ inAsset: "XYZ-111", @@ -93,13 +93,13 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 100000, } acc.SetCoins(sdk.Coins{{"XYZ-111", 1000000}, {"BNB", 1000}}) - fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 500}}, fee.Tokens) } func TestFeeManager_CalcTradesFee(t *testing.T) { ctx, am, keeper := setup() - keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("XYZ-111", "BNB", 2e7)) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BTC", 1e4)) @@ -126,7 +126,7 @@ func TestFeeManager_CalcTradesFee(t *testing.T) { {"BTC", 10e8}, {"XYZ-000", 100e8}, }) - fees := keeper.FeeManager.CalcTradesFee(acc.GetCoins(), tradeTransfers, keeper.engines) + fees := keeper.GlobalKeeper.FeeManager.CalcTradesFee(acc.GetCoins(), tradeTransfers, keeper.engines) require.Equal(t, "ABC-000:8000;BNB:15251305;BTC:100000;XYZ-111:2000", fees.String()) require.Equal(t, "BNB:250000", tradeTransfers[0].Fee.String()) require.Equal(t, "BNB:15000000", tradeTransfers[1].Fee.String()) @@ -148,7 +148,7 @@ func TestFeeManager_CalcTradesFee(t *testing.T) { func TestFeeManager_CalcExpiresFee(t *testing.T) { ctx, am, keeper := setup() - keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("XYZ-111", "BNB", 2e7)) keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC", 5e5)) @@ -173,7 +173,7 @@ func TestFeeManager_CalcExpiresFee(t *testing.T) { {"BTC", 10e8}, {"XYZ-111", 800000}, }) - fees := keeper.FeeManager.CalcExpiresFee(acc.GetCoins(), eventFullyExpire, expireTransfers, keeper.engines, nil) + fees := keeper.GlobalKeeper.FeeManager.CalcExpiresFee(acc.GetCoins(), eventFullyExpire, expireTransfers, keeper.engines, nil) require.Equal(t, "ABC-000:1000000;BNB:120000;BTC:500;XYZ-111:800000", fees.String()) require.Equal(t, "BNB:20000", expireTransfers[0].Fee.String()) require.Equal(t, "BNB:20000", expireTransfers[1].Fee.String()) @@ -195,17 +195,17 @@ func TestFeeManager_CalcExpiresFee(t *testing.T) { func TestFeeManager_CalcTradeFee(t *testing.T) { ctx, am, keeper := setup() - keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) // BNB _, acc := testutils.NewAccount(ctx, am, 0) // the tradeIn amount is large enough to make the fee > 0 tradeIn := sdk.NewCoin(types.NativeTokenSymbol, 100e8) - fee := keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee := keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 5e6)}, fee.Tokens) // small tradeIn amount tradeIn = sdk.NewCoin(types.NativeTokenSymbol, 100) - fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 0)}, fee.Tokens) // !BNB @@ -213,11 +213,11 @@ func TestFeeManager_CalcTradeFee(t *testing.T) { // has enough bnb tradeIn = sdk.NewCoin("ABC-000", 1000e8) acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e8)}) - fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 5e6)}, fee.Tokens) // no enough bnb acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e6)}) - fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e8)}, fee.Tokens) // very high price to produce int64 overflow @@ -225,64 +225,64 @@ func TestFeeManager_CalcTradeFee(t *testing.T) { // has enough bnb tradeIn = sdk.NewCoin("ABC-000", 1000e8) acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e16)}) - fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 5e15)}, fee.Tokens) // no enough bnb, fee is within int64 acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e15)}) - fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e8)}, fee.Tokens) // no enough bnb, even the fee overflows tradeIn = sdk.NewCoin("ABC-000", 1e16) - fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e13)}, fee.Tokens) } func TestFeeManager_CalcFixedFee(t *testing.T) { ctx, am, keeper := setup() - keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) _, acc := testutils.NewAccount(ctx, am, 1e4) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC-000", 1e5)) // in BNB // no enough BNB, but inAsset == BNB - fee := keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) + fee := keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e4)}, fee.Tokens) // enough BNB acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 3e4)}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2e4)}, fee.Tokens) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventIOCFullyExpire, types.NativeTokenSymbol, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventIOCFullyExpire, types.NativeTokenSymbol, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e4)}, fee.Tokens) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyCancel, types.NativeTokenSymbol, keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyCancel, types.NativeTokenSymbol, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2e4)}, fee.Tokens) // ABC-000_BNB, sell ABC-000 - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2e4)}, fee.Tokens) // No enough native token, but enough ABC-000 acc.SetCoins(sdk.Coins{{Denom: types.NativeTokenSymbol, Amount: 1e4}, {Denom: "ABC-000", Amount: 1e8}}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e6)}, fee.Tokens) // No enough native token and ABC-000 acc.SetCoins(sdk.Coins{{Denom: types.NativeTokenSymbol, Amount: 1e4}, {Denom: "ABC-000", Amount: 1e5}}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e5)}, fee.Tokens) // BNB_BTC-000, sell BTC-000 acc.SetCoins(sdk.Coins{{Denom: "BTC-000", Amount: 1e4}}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("BTC-000", 1e2)}, fee.Tokens) // extreme prices keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1)) keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC-000", 1e16)) acc.SetCoins(sdk.Coins{{Denom: "ABC-000", Amount: 1e16}, {Denom: "BTC-000", Amount: 1e16}}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e13)}, fee.Tokens) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) + fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("BTC-000", 1e13)}, fee.Tokens) } diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 6f43d1cd3..a1c70b416 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -286,9 +286,7 @@ func initOrderBook(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context timeOfLatestBlock = block.Time } height, err := dexKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) - if sdk.IsUpgrade(upgrade.BEP8) { - _, err = dexMiniKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) - } + _, err = dexMiniKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) if err != nil { panic(err) } diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 210a07ca4..1a01456f8 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -3,7 +3,6 @@ package order import ( "errors" "fmt" - "github.com/binance-chain/node/common/upgrade" "strings" "sync" "time" @@ -33,7 +32,7 @@ var _ DexOrderKeeper = &MiniKeeper{} // NewKeeper - Returns the MiniToken Keeper func NewMiniKeeper(dexMiniKey sdk.StoreKey, miniPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, concurrency uint, cdc *wire.Codec, globalKeeper *GlobalKeeper) *MiniKeeper { - logger := bnclog.With("module", "dexkeeper") + logger := bnclog.With("module", "dexMiniKeeper") return &MiniKeeper{ Keeper{PairMapper: miniPairMapper, storeKey: dexMiniKey, @@ -57,7 +56,7 @@ func NewMiniKeeper(dexMiniKey sdk.StoreKey, miniPairMapper store.TradingPairMapp // override func (kp *MiniKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { - eng := kp.AddEngine(pair) + eng := kp.Keeper.AddEngine(pair) symbol := strings.ToUpper(pair.GetSymbol()) kp.symbolSelector.AddSymbolHash(symbol) return eng @@ -133,12 +132,15 @@ func (kp *MiniKeeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrd // override func (kp *MiniKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) { - lastBreatheBlockHeight := kp.GetLastBreatheBlockHeight(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) - upgradeHeight := sdk.UpgradeMgr.GetUpgradeHeight(upgrade.BEP8) - kp.logger.Info("Loaded MiniKeeper orderbook ", "lastBreatheBlockHeight", lastBreatheBlockHeight, "upgradeHeight", upgradeHeight) - if lastBreatheBlockHeight < upgradeHeight { - return lastBreatheBlockHeight, nil - } else { - return kp.Keeper.LoadOrderBookSnapshot(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) - } + //TODO review + //lastBreatheBlockHeight := kp.GetLastBreatheBlockHeight(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) + //upgradeHeight := sdk.UpgradeMgr.GetUpgradeHeight(upgrade.BEP8) + //kp.logger.Info("Loaded MiniKeeper orderbook ", "lastBreatheBlockHeight", lastBreatheBlockHeight, "upgradeHeight", upgradeHeight) + //if lastBreatheBlockHeight < upgradeHeight { + // return lastBreatheBlockHeight, nil + //} else { + // return kp.Keeper.LoadOrderBookSnapshot(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) + //} + + return kp.Keeper.LoadOrderBookSnapshot(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) } diff --git a/plugins/dex/order/symbol_selector.go b/plugins/dex/order/symbol_selector.go index 9504fa020..d81436b20 100644 --- a/plugins/dex/order/symbol_selector.go +++ b/plugins/dex/order/symbol_selector.go @@ -91,9 +91,8 @@ func selectMiniSymbolsToMatch(roundOrders map[string][]string, miniSymbolsHash m func selectActiveMiniSymbols(symbolsToMatch *map[string]struct{}, roundOrdersMini *map[string][]string, k int) { //use quick select to select top k symbols symbolOrderNumsSlice := make([]*SymbolWithOrderNumber, 0, len(*roundOrdersMini)) - i := 0 for symbol, orders := range *roundOrdersMini { - symbolOrderNumsSlice[i] = &SymbolWithOrderNumber{symbol, len(orders)} + symbolOrderNumsSlice = append(symbolOrderNumsSlice, &SymbolWithOrderNumber{symbol, len(orders)}) } topKSymbolOrderNums := findTopKLargest(symbolOrderNumsSlice, k) diff --git a/plugins/dex/plugin.go b/plugins/dex/plugin.go index c25ef5305..b59bf856d 100644 --- a/plugins/dex/plugin.go +++ b/plugins/dex/plugin.go @@ -18,7 +18,8 @@ import ( tkstore "github.com/binance-chain/node/plugins/tokens/store" ) -const AbciQueryPrefix = "dex" +const DexAbciQueryPrefix = "dex" +const DexMiniAbciQueryPrefix = "dex_mini" const DelayedDaysForDelist = 3 type DexKeeperType int8 @@ -40,13 +41,15 @@ func InitPlugin( } // add abci handlers - handler := createQueryHandler(dexKeeper) - appp.RegisterQueryHandler(AbciQueryPrefix, handler) - //TODO dex mini handler + dexHandler := createQueryHandler(dexKeeper, DexAbciQueryPrefix) + appp.RegisterQueryHandler(DexAbciQueryPrefix, dexHandler) + //dex mini handler + dexMiniHandler := createQueryHandler(dexKeeper, DexMiniAbciQueryPrefix) + appp.RegisterQueryHandler(DexMiniAbciQueryPrefix, dexMiniHandler) } -func createQueryHandler(keeper *DexKeeper) app.AbciQueryHandler { - return createAbciQueryHandler(keeper) +func createQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQueryHandler { + return createAbciQueryHandler(keeper, abciQueryPrefix) } // EndBreatheBlock processes the breathe block lifecycle event. diff --git a/plugins/dex/store/codec.go b/plugins/dex/store/codec.go index 301cf7aca..572dd17f8 100644 --- a/plugins/dex/store/codec.go +++ b/plugins/dex/store/codec.go @@ -2,6 +2,7 @@ package store import ( "fmt" + "github.com/binance-chain/node/plugins/dex/utils" "github.com/cosmos/cosmos-sdk/client/context" @@ -10,7 +11,12 @@ import ( // queryOrderBook queries the store for the serialized order book for a given pair. func queryOrderBook(cdc *wire.Codec, ctx context.CLIContext, pair string, levels int) (*[]byte, error) { - bz, err := ctx.Query(fmt.Sprintf("dex/orderbook/%s/%d", pair, levels), nil) + var path string + if utils.IsMiniTokenTradingPair(pair){ + path = fmt.Sprintf("dex_mini/orderbook/%s/%d", pair, levels) + } + path =fmt.Sprintf("dex/orderbook/%s/%d", pair, levels) + bz, err := ctx.Query(path, nil) if err != nil { return nil, err } @@ -41,7 +47,12 @@ func GetOrderBook(cdc *wire.Codec, ctx context.CLIContext, pair string, levels i } func queryOpenOrders(cdc *wire.Codec, ctx context.CLIContext, pair string, addr string) (*[]byte, error) { - if bz, err := ctx.Query(fmt.Sprintf("dex/openorders/%s/%s", pair, addr), nil); err != nil { + var path string + if utils.IsMiniTokenTradingPair(pair){ + path = fmt.Sprintf("dex/openorders/%s/%s", pair, addr) + } + path =fmt.Sprintf("dex/openorders/%s/%s", pair, addr) + if bz, err := ctx.Query(path, nil); err != nil { return nil, err } else { return &bz, nil diff --git a/plugins/dex/store/mapper.go b/plugins/dex/store/mapper.go index 2392b21b9..dd3d21e09 100644 --- a/plugins/dex/store/mapper.go +++ b/plugins/dex/store/mapper.go @@ -72,25 +72,6 @@ func (m mapper) AddTradingPair(ctx sdk.Context, pair types.TradingPair) error { return nil } -func (m mapper) AddMiniTokenTradingPair(ctx sdk.Context, pair types.TradingPair) error { - baseAsset := pair.BaseAssetSymbol - if err := cmn.ValidateMapperMiniTokenSymbol(baseAsset); err != nil { - return err - } - quoteAsset := pair.QuoteAssetSymbol - if err := cmn.ValidateMapperTokenSymbol(quoteAsset); err != nil { - return err - } - - tradeSymbol := dexUtils.Assets2TradingPair(strings.ToUpper(baseAsset), strings.ToUpper(quoteAsset)) - key := []byte(tradeSymbol) - store := ctx.KVStore(m.key) - value := m.encodeTradingPair(pair) - store.Set(key, value) - ctx.Logger().Info("Added mini-token trading pair", "pair", tradeSymbol) - return nil -} - func (m mapper) DeleteTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { symbol := dexUtils.Assets2TradingPair(strings.ToUpper(baseAsset), strings.ToUpper(quoteAsset)) key := []byte(symbol) diff --git a/plugins/dex/store/utils.go b/plugins/dex/store/utils.go index 221b258ca..294ce7068 100644 --- a/plugins/dex/store/utils.go +++ b/plugins/dex/store/utils.go @@ -25,6 +25,9 @@ func ValidatePairSymbol(symbol string) error { return errors.New("invalid symbol: trading pair must contain an underscore ('_')") } for _, tokenSymbol := range tokenSymbols { + if types.IsMiniTokenSymbol(tokenSymbol){ + continue + } if err := types.ValidateMapperTokenSymbol(tokenSymbol); err != nil { return err } diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 87944d522..2edd2a5a5 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -96,16 +96,17 @@ func init() { burn.BurnRoute: fees.FixedFeeCalculatorGen, account.SetAccountFlagsMsgType: fees.FixedFeeCalculatorGen, freeze.FreezeRoute: fees.FixedFeeCalculatorGen, - timelock.TimeLockMsg{}.Type(): fees.FixedFeeCalculatorGen, - timelock.TimeUnlockMsg{}.Type(): fees.FixedFeeCalculatorGen, - timelock.TimeRelockMsg{}.Type(): fees.FixedFeeCalculatorGen, - bank.MsgSend{}.Type(): tokens.TransferFeeCalculatorGen, - swap.HTLT: fees.FixedFeeCalculatorGen, - swap.DepositHTLT: fees.FixedFeeCalculatorGen, - swap.ClaimHTLT: fees.FixedFeeCalculatorGen, - swap.RefundHTLT: fees.FixedFeeCalculatorGen, - miniIssue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, - miniIssue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, - miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, + timelock.TimeLockMsg{}.Type(): fees.FixedFeeCalculatorGen, + timelock.TimeUnlockMsg{}.Type(): fees.FixedFeeCalculatorGen, + timelock.TimeRelockMsg{}.Type(): fees.FixedFeeCalculatorGen, + bank.MsgSend{}.Type(): tokens.TransferFeeCalculatorGen, + swap.HTLT: fees.FixedFeeCalculatorGen, + swap.DepositHTLT: fees.FixedFeeCalculatorGen, + swap.ClaimHTLT: fees.FixedFeeCalculatorGen, + swap.RefundHTLT: fees.FixedFeeCalculatorGen, + miniIssue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, + miniIssue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, + miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, + listmini.Route: fees.FixedFeeCalculatorGen, } } From d92a2ca0ef196fe940bc86f9ee351e27bbc34128 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 5 May 2020 01:13:17 +0800 Subject: [PATCH 18/96] fix test --- app/pub/helpers.go | 3 +- plugins/dex/matcheng/engine_new.go | 18 ++++++++---- plugins/dex/matcheng/match_new_test.go | 4 +-- plugins/dex/order/handler_test.go | 38 ++++++++++++++------------ plugins/dex/order/keeper.go | 2 +- plugins/dex/order/keeper_match.go | 4 +-- plugins/dex/order/keeper_recovery.go | 1 + plugins/dex/order/keeper_test.go | 26 ++++++++++++++---- plugins/dex/order/mini_keeper.go | 10 ------- 9 files changed, 62 insertions(+), 44 deletions(-) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 87c5ce69e..6f44729d7 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -314,6 +314,7 @@ func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.Keeper, dexMiniKeeper *or func extractTradesToPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, tradeHeight int64, tradeIdx *int) []*Trade { tradesToPublish := make([]*Trade, 0) + //TODO reduce call of ListAllTradingPairs for _, pair := range dexKeeper.GetPairMapper().ListAllTradingPairs(ctx) { symbol := pair.GetSymbol() matchEngTrades, _ := dexKeeper.GetLastTrades(tradeHeight, symbol) @@ -330,7 +331,7 @@ func extractTradesToPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, } t := &Trade{ - Id: fmt.Sprintf("%d-%d", tradeHeight, tradeIdx), + Id: fmt.Sprintf("%d-%d", tradeHeight, *tradeIdx), Symbol: symbol, Sid: trade.Sid, Bid: trade.Bid, diff --git a/plugins/dex/matcheng/engine_new.go b/plugins/dex/matcheng/engine_new.go index d481dc7af..6231ef881 100644 --- a/plugins/dex/matcheng/engine_new.go +++ b/plugins/dex/matcheng/engine_new.go @@ -12,7 +12,7 @@ import ( "github.com/binance-chain/node/common/utils" ) -func (me *MatchEng) Match(height int64) bool { +func (me *MatchEng) Match(height int64, isMini bool) bool { if !sdk.IsUpgrade(upgrade.BEP19) { return me.MatchBeforeGalileo(height) } @@ -32,9 +32,15 @@ func (me *MatchEng) Match(height int64) bool { me.logger.Error("dropRedundantQty failed", "error", err) return false } - //If order height >= the last Match height, then it's maker. + //If order height > the last Match height, then it's maker. // Block Height cannot be used here since mini-token is not matched in every block - takerSide, err := me.determineTakerSide(me.LastMatchHeight, index) + var lastMatchHeight int64 + if isMini { + lastMatchHeight = me.LastMatchHeight + }else{ + lastMatchHeight = height -1 //Every block is deemed as performed matching for all BEP2 symbols + } + takerSide, err := me.determineTakerSide(lastMatchHeight, index) if err != nil { me.logger.Error("determineTakerSide failed", "error", err) return false @@ -120,10 +126,10 @@ func dropRedundantQty(orders []OrderPart, toDropQty, lotSize int64) error { func findTakerStartIdx(lastMatchHeight int64, orders []OrderPart) (idx int, makerTotal int64) { i, k := 0, len(orders) for ; i < k; i++ { - if orders[i].Time >= lastMatchHeight { - return i, makerTotal - } else { + if orders[i].Time <= lastMatchHeight { makerTotal += orders[i].nxtTrade + } else { + return i, makerTotal } } return i, makerTotal diff --git a/plugins/dex/matcheng/match_new_test.go b/plugins/dex/matcheng/match_new_test.go index 82b849cd8..7973dbe7e 100644 --- a/plugins/dex/matcheng/match_new_test.go +++ b/plugins/dex/matcheng/match_new_test.go @@ -923,7 +923,7 @@ func TestMatchEng_Match(t *testing.T) { me.Book.InsertOrder("16", BUYSIDE, 100, 100, 20) upgrade.Mgr.SetHeight(100) - assert.True(me.Match(100)) + assert.True(me.Match(100, false)) assert.Equal(4, len(me.overLappedLevel)) assert.Equal(int64(100), me.LastTradePrice) assert.Equal([]Trade{ @@ -979,7 +979,7 @@ func TestMatchEng_Match(t *testing.T) { me.Book.InsertOrder("6", BUYSIDE, 100, 110, 40) me.Book.InsertOrder("8", BUYSIDE, 100, 110, 100) - assert.True(me.Match(100)) + assert.True(me.Match(100, false)) assert.Equal(4, len(me.overLappedLevel)) assert.Equal(int64(104), me.LastTradePrice) assert.Equal([]Trade{ diff --git a/plugins/dex/order/handler_test.go b/plugins/dex/order/handler_test.go index d81703204..24364c50d 100644 --- a/plugins/dex/order/handler_test.go +++ b/plugins/dex/order/handler_test.go @@ -16,22 +16,24 @@ import ( "github.com/binance-chain/node/common" "github.com/binance-chain/node/plugins/dex/store" "github.com/binance-chain/node/plugins/dex/types" + dextypes "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/wire" ) -func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) { +func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey, *sdk.KVStoreKey) { db := dbm.NewMemDB() key := sdk.NewKVStoreKey("pair") // TODO: can this be "pairs" as in the constant? key2 := sdk.NewKVStoreKey(common.AccountStoreName) + key3 := sdk.NewKVStoreKey(common.DexStoreName) ms := cstore.NewCommitMultiStore(db) ms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(key2, sdk.StoreTypeIAVL, db) ms.LoadLatestVersion() - return ms, key, key2 + return ms, key, key2, key3 } -func setupMappers() (store.TradingPairMapper, auth.AccountKeeper, sdk.Context) { - ms, key, key2 := setupMultiStore() +func setupMappers() (store.TradingPairMapper, auth.AccountKeeper, sdk.Context, DexOrderKeeper) { + ms, key, key2, key3 := setupMultiStore() var cdc = wire.NewCodec() auth.RegisterBaseAccount(cdc) cdc.RegisterConcrete(types.TradingPair{}, "dex/TradingPair", nil) @@ -39,7 +41,9 @@ func setupMappers() (store.TradingPairMapper, auth.AccountKeeper, sdk.Context) { accMapper := auth.NewAccountKeeper(cdc, key2, auth.ProtoBaseAccount) accountCache := getAccountCache(cdc, ms, key2) ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) - return pairMapper, accMapper, ctx + globalKeeper := NewGlobalKeeper(cdc, accMapper, false) + keeper := NewKeeper(key3, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, globalKeeper) + return pairMapper, accMapper, ctx, keeper } func setupAccount(ctx sdk.Context, accMapper auth.AccountKeeper) (sdk.Account, sdk.AccAddress) { @@ -61,7 +65,7 @@ func setupAccount(ctx sdk.Context, accMapper auth.AccountKeeper) (sdk.Account, s } func TestHandler_ValidateOrder_OrderNotExist(t *testing.T) { - pairMapper, accMapper, ctx := setupMappers() + pairMapper, accMapper, ctx, keeper := setupMappers() pair := types.NewTradingPair("AAA-000", "BNB", 1e8) err := pairMapper.AddTradingPair(ctx, pair) require.NoError(t, err) @@ -76,13 +80,13 @@ func TestHandler_ValidateOrder_OrderNotExist(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = validateOrder(ctx, pairMapper, acc, msg) + err = keeper.validateOrder(ctx, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("trading pair not found: %s", msg.Symbol), err.Error()) } func TestHandler_ValidateOrder_WrongSymbol(t *testing.T) { - pairMapper, _, ctx := setupMappers() + pairMapper, _, ctx, keeper := setupMappers() msgs := []NewOrderMsg{ { @@ -103,14 +107,14 @@ func TestHandler_ValidateOrder_WrongSymbol(t *testing.T) { } for _, msg := range msgs { - err := validateOrder(ctx, pairMapper, nil, msg) + err := keeper.validateOrder(ctx, pairMapper, nil, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("Failed to parse trading pair symbol:%s into assets", msg.Symbol), err.Error()) } } func TestHandler_ValidateOrder_WrongPrice(t *testing.T) { - pairMapper, accMapper, ctx := setupMappers() + pairMapper, accMapper, ctx, keeper := setupMappers() pair := types.NewTradingPair("AAA-000", "BNB", 1e8) err := pairMapper.AddTradingPair(ctx, pair) require.NoError(t, err) @@ -125,13 +129,13 @@ func TestHandler_ValidateOrder_WrongPrice(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = validateOrder(ctx, pairMapper, acc, msg) + err = keeper.validateOrder(ctx, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()), err.Error()) } func TestHandler_ValidateOrder_WrongQuantity(t *testing.T) { - pairMapper, accMapper, ctx := setupMappers() + pairMapper, accMapper, ctx, keeper := setupMappers() pair := types.NewTradingPair("AAA-000", "BNB", 1e8) err := pairMapper.AddTradingPair(ctx, pair) require.NoError(t, err) @@ -146,13 +150,13 @@ func TestHandler_ValidateOrder_WrongQuantity(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = validateOrder(ctx, pairMapper, acc, msg) + err = keeper.validateOrder(ctx, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()), err.Error()) } func TestHandler_ValidateOrder_Normal(t *testing.T) { - pairMapper, accMapper, ctx := setupMappers() + pairMapper, accMapper, ctx, keeper:= setupMappers() err := pairMapper.AddTradingPair(ctx, types.NewTradingPair("AAA-000", "BNB", 1e8)) require.NoError(t, err) @@ -166,12 +170,12 @@ func TestHandler_ValidateOrder_Normal(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = validateOrder(ctx, pairMapper, acc, msg) + err = keeper.validateOrder(ctx, acc, msg) require.NoError(t, err) } func TestHandler_ValidateOrder_MaxNotional(t *testing.T) { - pairMapper, accMapper, ctx := setupMappers() + pairMapper, accMapper, ctx, keeper := setupMappers() err := pairMapper.AddTradingPair(ctx, types.NewTradingPair("AAA-000", "BNB", 1e8)) require.NoError(t, err) @@ -185,7 +189,7 @@ func TestHandler_ValidateOrder_MaxNotional(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = validateOrder(ctx, pairMapper, acc, msg) + err = keeper.validateOrder(ctx, acc, msg) require.Error(t, err) require.Equal(t, "notional value of the order is too large(cannot fit in int64)", err.Error()) } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 6796fccbc..894613156 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -705,7 +705,7 @@ func (kp *Keeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset st } tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) - for _, pair := range tradingPairs { + for _, pair := range tradingPairs { //TODO if (pair.BaseAssetSymbol == symbolToCheck && pair.QuoteAssetSymbol != types.NativeTokenSymbol) || (pair.QuoteAssetSymbol == symbolToCheck && pair.BaseAssetSymbol != types.NativeTokenSymbol) { return fmt.Errorf("trading pair %s_%s should not exist before delisting %s_%s", diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index eddfcdf1d..3bfc6e42c 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -112,7 +112,7 @@ func matchAndDistributeTrades(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, dist func MatchSymbols(height, timestamp int64, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, matchAllSymbols bool, logger tmlog.Logger) { symbolsToMatch := dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, height, timestamp, matchAllSymbols) - symbolsToMatch = append(symbolsToMatch, dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, height, timestamp, matchAllSymbols)...) + symbolsToMatch = append(symbolsToMatch, dexMiniKeeper.symbolSelector.SelectSymbolsToMatch(dexMiniKeeper.roundOrders, height, timestamp, matchAllSymbols)...) logger.Debug("symbols to match", "symbols", symbolsToMatch) tradeOuts := matchAndDistributeTrades(dexKeeper, dexMiniKeeper, true, height, timestamp, symbolsToMatch, logger) @@ -130,7 +130,7 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times concurrency := len(tradeOuts) // please note there is no logging in matching, expecting to see the order book details // from the exchange's order book stream. - if engine.Match(height) { + if engine.Match(height, dexUtils.IsMiniTokenTradingPair(symbol)) { kp.logger.Debug("Match finish:", "symbol", symbol, "lastTradePrice", engine.LastTradePrice) for i := range engine.Trades { t := &engine.Trades[i] diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index a1c70b416..fe5e13521 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -152,6 +152,7 @@ func (kp *Keeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64 eng.Book.InsertPriceLevel(&pl, me.SELLSIDE) } eng.LastTradePrice = ob.LastTradePrice + eng.LastMatchHeight = height ctx.Logger().Info("Successfully Loaded order snapshot", "pair", pair) } key := genActiveOrdersSnapshotKey(height) diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index dda2c32e7..395496a96 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -56,8 +56,19 @@ func MakeKeeper(cdc *wire.Codec) *Keeper { accKeeper := auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) codespacer := sdk.NewCodespacer() pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) - keeper := NewKeeper(common.DexStoreKey, accKeeper, pairMapper, - codespacer.RegisterNext(dextypes.DefaultCodespace), 2, cdc, true) + globalKeeper := NewGlobalKeeper(cdc, accKeeper, true) + keeper := NewKeeper(common.DexStoreKey, pairMapper, + codespacer.RegisterNext(dextypes.DefaultCodespace), 2, cdc, globalKeeper) + return keeper +} + +func MakeMiniKeeper(cdc *wire.Codec) *MiniKeeper { + accKeeper := auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) + codespacer := sdk.NewCodespacer() + pairMapper := store.NewTradingPairMapper(cdc, common.MiniTokenPairStoreKey, true) + globalKeeper := NewGlobalKeeper(cdc, accKeeper, true) + keeper := NewMiniKeeper(common.DexMiniStoreKey, pairMapper, + codespacer.RegisterNext(dextypes.DefaultCodespace), 2, cdc, globalKeeper) return keeper } @@ -77,6 +88,7 @@ func TestKeeper_MatchFailure(t *testing.T) { assert := assert.New(t) cdc := MakeCodec() keeper := MakeKeeper(cdc) + miniKeeper := MakeMiniKeeper(cdc) cms := MakeCMS(nil) logger := log.NewTMLogger(os.Stdout) ctx := sdk.NewContext(cms, abci.Header{}, sdk.RunTxModeCheck, logger) @@ -107,7 +119,8 @@ func TestKeeper_MatchFailure(t *testing.T) { msg = NewNewOrderMsg(accAdd, "123462", Side.BUY, "XYZ-000_BNB", 99000, 15000000) ord = OrderInfo{msg, 42, 0, 42, 0, 0, "", 0} keeper.AddOrder(ord, false) - tradeOuts := keeper.matchAndDistributeTrades(true, 42, 0, false) + symbolsToMatch := keeper.symbolSelector.SelectSymbolsToMatch(keeper.roundOrders, ctx.BlockHeader().Height, 0, false) + tradeOuts := matchAndDistributeTrades(keeper, miniKeeper, true, 42, 0, symbolsToMatch, logger) c := channelHash(accAdd, 4) i := 0 for tr := range tradeOuts[c] { @@ -255,6 +268,7 @@ func TestKeeper_SnapShotAndLoadAfterMatch(t *testing.T) { assert := assert.New(t) cdc := MakeCodec() keeper := MakeKeeper(cdc) + miniKeeper := MakeMiniKeeper(cdc) cms := MakeCMS(nil) logger := log.NewTMLogger(os.Stdout) ctx := sdk.NewContext(cms, abci.Header{}, sdk.RunTxModeCheck, logger) @@ -275,7 +289,7 @@ func TestKeeper_SnapShotAndLoadAfterMatch(t *testing.T) { assert.Equal(3, len(keeper.allOrders["XYZ-000_BNB"])) assert.Equal(1, len(keeper.engines)) - keeper.MatchSymbols(42, 0) + MatchSymbols(42, 0, keeper, miniKeeper,false,logger) _, err := keeper.SnapShotOrderBook(ctx, 43) assert.Nil(err) keeper.MarkBreatheBlock(ctx, 43, time.Now()) @@ -547,7 +561,9 @@ func setup() (ctx sdk.Context, mapper auth.AccountKeeper, keeper *Keeper) { accountCache := getAccountCache(cdc, ms, capKey) pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) - keeper = NewKeeper(capKey2, mapper, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, false) + + globalKeeper := NewGlobalKeeper(cdc, mapper, false) + keeper = NewKeeper(capKey2, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, globalKeeper) return } diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 1a01456f8..d87b2c92b 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -132,15 +132,5 @@ func (kp *MiniKeeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrd // override func (kp *MiniKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) { - //TODO review - //lastBreatheBlockHeight := kp.GetLastBreatheBlockHeight(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) - //upgradeHeight := sdk.UpgradeMgr.GetUpgradeHeight(upgrade.BEP8) - //kp.logger.Info("Loaded MiniKeeper orderbook ", "lastBreatheBlockHeight", lastBreatheBlockHeight, "upgradeHeight", upgradeHeight) - //if lastBreatheBlockHeight < upgradeHeight { - // return lastBreatheBlockHeight, nil - //} else { - // return kp.Keeper.LoadOrderBookSnapshot(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) - //} - return kp.Keeper.LoadOrderBookSnapshot(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) } From da397b1bbdd820226256cfa349e80ba86964a62b Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 8 May 2020 14:24:16 +0800 Subject: [PATCH 19/96] refactor dex keeper --- app/app.go | 71 +- app/app_pub_test.go | 4 +- app/helpers.go | 9 +- app/pub/helpers.go | 73 +- app/pub/keeper_pub_test.go | 4 +- app_test/utils_test.go | 2 +- common/stores.go | 8 - networks/publisher/ordergen.sh | 8 +- networks/publisher/setup_mini.sh | 6 +- networks/tools/snapshot_viewer/snapshot.go | 2 +- plugins/dex/aliases.go | 17 +- plugins/dex/list/handler.go | 4 +- plugins/dex/list/handler_test.go | 4 +- plugins/dex/list/hooks.go | 8 +- plugins/dex/listmini/handler.go | 14 +- plugins/dex/matcheng/engine_new.go | 3 + plugins/dex/matcheng/match_new_test.go | 12 +- plugins/dex/order/fee_test.go | 64 +- plugins/dex/order/global_keeper.go | 815 ++++++++++++++++++++- plugins/dex/order/handler.go | 67 +- plugins/dex/order/handler_test.go | 21 +- plugins/dex/order/keeper.go | 804 +++++--------------- plugins/dex/order/keeper_match.go | 145 ++-- plugins/dex/order/keeper_recovery.go | 92 ++- plugins/dex/order/keeper_test.go | 84 +-- plugins/dex/order/mini_keeper.go | 144 ++-- plugins/dex/order/openOrders_test.go | 2 +- plugins/dex/order/symbol_selector.go | 15 +- plugins/dex/order/types.go | 1 + plugins/dex/plugin.go | 33 +- plugins/dex/route.go | 6 +- plugins/dex/store/mapper.go | 18 +- plugins/dex/utils/pair.go | 4 +- 33 files changed, 1371 insertions(+), 1193 deletions(-) diff --git a/app/app.go b/app/app.go index b84fc388d..1c4f298d8 100644 --- a/app/app.go +++ b/app/app.go @@ -84,8 +84,6 @@ type BinanceChain struct { // keepers CoinKeeper bank.Keeper DexKeeper *dex.DexKeeper - DexMiniTokenKeeper *dex.DexMiniTokenKeeper - DexGlobalKeeper *dex.DexGlobalKeeper AccountKeeper auth.AccountKeeper TokenMapper tkstore.Mapper MiniTokenMapper miniTkstore.MiniTokenMapper @@ -139,8 +137,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp app.MiniTokenMapper = miniTkstore.NewMiniTokenMapper(cdc, common.MiniTokenStoreKey) app.CoinKeeper = bank.NewBaseKeeper(app.AccountKeeper) app.ParamHub = paramhub.NewKeeper(cdc, common.ParamsStoreKey, common.TParamsStoreKey) - tradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.PairStoreKey, false) - miniTokenTradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.MiniTokenPairStoreKey, true) + tradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.PairStoreKey) app.stakeKeeper = stake.NewKeeper( cdc, @@ -225,9 +222,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp common.GovStoreKey, common.TimeLockStoreKey, common.AtomicSwapStoreKey, - common.DexMiniStoreKey, common.MiniTokenStoreKey, - common.MiniTokenPairStoreKey, ) app.SetAnteHandler(tx.NewAnteHandler(app.AccountKeeper)) app.SetPreChecker(tx.NewTxPreChecker()) @@ -251,7 +246,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp } // remaining plugin init - app.initDex(tradingPairMapper, miniTokenTradingPairMapper) + app.initDex(tradingPairMapper) app.initGovHooks() app.initPlugins() app.initParams() @@ -281,9 +276,7 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { upgrade.Mgr.RegisterStoreKeys(upgrade.BEP9, common.TimeLockStoreKey.Name()) upgrade.Mgr.RegisterStoreKeys(upgrade.BEP3, common.AtomicSwapStoreKey.Name()) - upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.DexMiniStoreKey.Name()) upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.MiniTokenStoreKey.Name()) - upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.MiniTokenPairStoreKey.Name()) // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP9, @@ -323,18 +316,10 @@ func (app *BinanceChain) initRunningMode() { } } -func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper, miniPairMapper dex.TradingPairMapper) { +func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { - app.DexGlobalKeeper = dex.NewGlobalKeeper(app.Codec, app.AccountKeeper, app.publicationConfig.ShouldPublishAny()) - app.DexGlobalKeeper.SubscribeParamChange(app.ParamHub) - - app.DexKeeper = dex.NewOrderKeeper(common.DexStoreKey, pairMapper, - app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec, - app.DexGlobalKeeper) - - app.DexMiniTokenKeeper = dex.NewMiniKeeper(common.DexMiniStoreKey, miniPairMapper, - app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec, - app.DexGlobalKeeper) + app.DexKeeper = dex.NewDexKeeper(common.DexStoreKey, pairMapper, app.RegisterCodespace(dex.DefaultCodespace), app.Codec, app.AccountKeeper, app.publicationConfig.ShouldPublishAny(), app.baseConfig.OrderKeeperConcurrency) + app.DexKeeper.SubscribeParamChange(app.ParamHub) // do not proceed if we are in a unit test and `CheckState` is unset. if app.CheckState == nil { @@ -349,7 +334,6 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper, miniPairMappe order.Init( app.DexKeeper, - app.DexMiniTokenKeeper, app.CheckState.Ctx, app.baseConfig.BreatheBlockInterval, app.baseConfig.BreatheBlockDaysCountBack, @@ -363,7 +347,7 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper, miniPairMappe func (app *BinanceChain) initPlugins() { tokens.InitPlugin(app, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) minitokens.InitPlugin(app, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper) - dex.InitPlugin(app, app.DexKeeper, app.DexMiniTokenKeeper, app.DexGlobalKeeper, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.govKeeper) + dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.govKeeper) param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) } @@ -557,9 +541,9 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a var miniTradesToPublish []*pub.Trade if sdk.IsUpgrade(upgrade.BEP19) || !isBreatheBlock { if app.publicationConfig.ShouldPublishAny() && pub.IsLive { - tradesToPublish, miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, app.DexMiniTokenKeeper, ctx, isBreatheBlock) + tradesToPublish, miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, ctx, isBreatheBlock) } else { - order.MatchAndAllocateSymbols(app.DexKeeper, app.DexMiniTokenKeeper, ctx, nil, isBreatheBlock, app.Logger) + app.DexKeeper.MatchAndAllocateSymbols(ctx, nil, isBreatheBlock) } } @@ -570,9 +554,6 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a app.takeSnapshotHeight = height icoDone := ico.EndBlockAsync(ctx) dex.EndBreatheBlock(ctx, app.DexKeeper, app.govKeeper, height, blockTime) - if sdk.IsUpgrade(upgrade.BEP8) { - dex.EndBreatheBlock(ctx, app.DexMiniTokenKeeper, app.govKeeper, height, blockTime) - } param.EndBreatheBlock(ctx, app.ParamHub) tokens.EndBreatheBlock(ctx, app.swapKeeper) // other end blockers @@ -582,9 +563,7 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a } app.DexKeeper.StoreTradePrices(ctx) - if sdk.IsUpgrade(upgrade.BEP8) { - app.DexMiniTokenKeeper.StoreTradePrices(ctx) - } + blockFee := distributeFee(ctx, app.AccountKeeper, app.ValAddrCache, app.publicationConfig.PublishBlockFee) tags, passed, failed := gov.EndBlocker(ctx, app.govKeeper) @@ -614,10 +593,7 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a // clean up intermediate cached data app.DexKeeper.ClearOrderChanges() - if sdk.IsUpgrade(upgrade.BEP8) { - app.DexMiniTokenKeeper.ClearOrderChanges() - } - app.DexGlobalKeeper.ClearRoundFee() + app.DexKeeper.ClearRoundFee() } fees.Pool.Clear() // just clean it, no matter use it or not. @@ -811,8 +787,8 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli duration := pub.Timer(app.Logger, fmt.Sprintf("collect publish information, height=%d", height), func() { if app.publicationConfig.PublishAccountBalance { txRelatedAccounts := app.Pool.TxRelatedAddrs() - tradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, tradesToPublish) - miniTradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexMiniTokenKeeper, miniTradesToPublish) + tradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, tradesToPublish, dex.PairType.BEP2) + miniTradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, miniTradesToPublish, dex.PairType.MINI) tradeRelatedAccounts = append(tradeRelatedAccounts, miniTradeRelatedAccounts...) accountsToPublish = pub.GetAccountBalances( app.AccountKeeper, @@ -831,8 +807,8 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli blockToPublish = pub.GetBlockPublished(app.Pool, header, blockHash) } if app.publicationConfig.PublishOrderBook { - latestPriceLevels = app.DexKeeper.GetOrderBooks(pub.MaxOrderBookLevel) - miniLatestPriceLevels = app.DexMiniTokenKeeper.GetOrderBooks(pub.MaxOrderBookLevel) + latestPriceLevels = app.DexKeeper.GetOrderBooks(pub.MaxOrderBookLevel, dex.PairType.BEP2) + miniLatestPriceLevels = app.DexKeeper.GetOrderBooks(pub.MaxOrderBookLevel, dex.PairType.MINI) } }) @@ -843,10 +819,10 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli pub.Logger.Info("start to publish", "height", height, "blockTime", blockTime, "numOfTrades", len(tradesToPublish), "numOfOrders", // the order num we collected here doesn't include trade related orders - len(app.DexKeeper.OrderChanges), + len(app.DexKeeper.GetOrderChanges(dex.PairType.BEP2)), "numOfMiniTrades", len(miniTradesToPublish), "numOfMiniOrders", // the order num we collected here doesn't include trade related orders - len(app.DexMiniTokenKeeper.OrderChanges), + len(app.DexKeeper.GetOrderChanges(dex.PairType.MINI)), "numOfProposals", proposalsToPublish.NumOfMsgs, "numOfStakeUpdates", @@ -863,27 +839,26 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli miniTradesToPublish, proposalsToPublish, stakeUpdates, - app.DexKeeper.OrderChanges, // thread-safety is guarded by the signal from RemoveDoneCh - app.DexMiniTokenKeeper.OrderChanges, - app.DexKeeper.OrderInfosForPub, // thread-safety is guarded by the signal from RemoveDoneCh - app.DexMiniTokenKeeper.OrderInfosForPub, + app.DexKeeper.GetOrderChanges(dex.PairType.BEP2), // thread-safety is guarded by the signal from RemoveDoneCh + app.DexKeeper.GetOrderChanges(dex.PairType.MINI), + app.DexKeeper.GetOrderInfosForPub(dex.PairType.BEP2), // thread-safety is guarded by the signal from RemoveDoneCh + app.DexKeeper.GetOrderInfosForPub(dex.PairType.MINI), accountsToPublish, latestPriceLevels, miniLatestPriceLevels, blockFee, - app.DexGlobalKeeper.RoundOrderFees, //only use DexKeeper RoundOrderFees + app.DexKeeper.RoundOrderFees, //only use DexKeeper RoundOrderFees transferToPublish, blockToPublish) // remove item from OrderInfoForPublish when we published removed order (cancel, iocnofill, fullyfilled, expired) for id := range pub.ToRemoveOrderIdCh { pub.Logger.Debug("delete order from order changes map", "orderId", id) - delete(app.DexKeeper.OrderInfosForPub, id) - delete(app.DexMiniTokenKeeper.OrderInfosForPub, id) + delete(app.DexKeeper.GetOrderInfosForPub(dex.PairType.BEP2), id) //TODO change to removeOrderInfosForPub method } for id := range pub.ToRemoveMiniOrderIdCh { pub.Logger.Debug("delete mini order from order changes map", "orderId", id) - delete(app.DexMiniTokenKeeper.OrderInfosForPub, id) + delete(app.DexKeeper.GetOrderInfosForPub(dex.PairType.MINI), id) } pub.Logger.Debug("finish publish", "height", height) diff --git a/app/app_pub_test.go b/app/app_pub_test.go index b8e66fb76..786296a85 100644 --- a/app/app_pub_test.go +++ b/app/app_pub_test.go @@ -140,7 +140,7 @@ func TestAppPub_MatchOrder(t *testing.T) { ctx := app.DeliverState.Ctx msg := orderPkg.NewNewOrderMsg(buyerAcc.GetAddress(), orderPkg.GenerateOrderID(1, buyerAcc.GetAddress()), orderPkg.Side.BUY, "XYZ-000_BNB", 102000, 300000000) - handler := orderPkg.NewHandler(app.GetCodec(), app.DexKeeper, app.AccountKeeper) + handler := orderPkg.NewHandler(app.GetCodec(), app.DexKeeper) app.DeliverState.Ctx = app.DeliverState.Ctx.WithBlockHeight(41).WithBlockTime(time.Unix(0, 100)) buyerAcc.SetSequence(1) app.AccountKeeper.SetAccount(ctx, buyerAcc) @@ -214,7 +214,7 @@ func TestAppPub_MatchOrder(t *testing.T) { func TestAppPub_MatchAndCancelFee(t *testing.T) { assert, require, app, buyerAcc, sellerAcc := setupAppTest(t) - handler := orderPkg.NewHandler(app.GetCodec(), app.DexKeeper, app.AccountKeeper, app.DexGlobalKeeper) + handler := orderPkg.NewHandler(app.GetCodec(), app.DexKeeper) ctx := app.DeliverState.Ctx // ==== Place a to-be-matched sell order and a to-be-cancelled buy order (in different symbol) diff --git a/app/helpers.go b/app/helpers.go index 8519d2ff3..34c4ce70f 100644 --- a/app/helpers.go +++ b/app/helpers.go @@ -144,16 +144,12 @@ func (app *BinanceChain) processErrAbciResponseForPub(txBytes []byte) { case order.NewOrderMsg: app.Logger.Info("failed to process NewOrderMsg", "oid", msg.Id) // The error on deliver should be rare and only impact witness publisher's performance - app.DexKeeper.OrderChangesMtx.Lock() - app.DexKeeper.OrderChanges = append(app.DexKeeper.OrderChanges, order.OrderChange{msg.Id, order.FailedBlocking, "", msg}) - app.DexKeeper.OrderChangesMtx.Unlock() + app.DexKeeper.UpdateOrderChangeSync(order.OrderChange{msg.Id, order.FailedBlocking, "", msg}, msg.Symbol) case order.CancelOrderMsg: app.Logger.Info("failed to process CancelOrderMsg", "oid", msg.RefId) // The error on deliver should be rare and only impact witness publisher's performance - app.DexKeeper.OrderChangesMtx.Lock() // OrderInfo must has been in keeper.OrderInfosForPub - app.DexKeeper.OrderChanges = append(app.DexKeeper.OrderChanges, order.OrderChange{msg.RefId, order.FailedBlocking, "", msg}) - app.DexKeeper.OrderChangesMtx.Unlock() + app.DexKeeper.UpdateOrderChangeSync(order.OrderChange{msg.RefId, order.FailedBlocking, "", msg}, msg.Symbol) default: // deliberately do nothing for message other than NewOrderMsg // in future, we may publish fail status of send msg @@ -189,7 +185,6 @@ func (app *BinanceChain) getLastBreatheBlockHeight() int64 { func (app *BinanceChain) reInitChain() error { order.Init( app.DexKeeper, - app.DexMiniTokenKeeper, app.CheckState.Ctx, app.baseConfig.BreatheBlockInterval, app.baseConfig.BreatheBlockDaysCountBack, diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 6f44729d7..0d27dc3ef 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -4,8 +4,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" - "github.com/binance-chain/node/plugins/dex/utils" "strconv" "sync" "time" @@ -26,9 +24,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) -func GetTradeAndOrdersRelatedAccounts(kp orderPkg.DexOrderKeeper, tradesToPublish []*Trade) []string { - res := make([]string, 0, len(tradesToPublish)*2+len(kp.GetOrderChanges())) - OrderInfosForPub := kp.GetOrderInfosForPub() +func GetTradeAndOrdersRelatedAccounts(kp *orderPkg.DexKeeper, tradesToPublish []*Trade, pairType orderPkg.SymbolPairType) []string { + res := make([]string, 0, len(tradesToPublish)*2+len(kp.GetOrderChanges(pairType))) + OrderInfosForPub := kp.GetOrderInfosForPub(pairType) for _, t := range tradesToPublish { @@ -44,7 +42,7 @@ func GetTradeAndOrdersRelatedAccounts(kp orderPkg.DexOrderKeeper, tradesToPublis } } - for _, orderChange := range kp.GetOrderChanges() { + for _, orderChange := range kp.GetOrderChanges(pairType) { if orderInfo := OrderInfosForPub[orderChange.Id]; orderInfo != nil { res = append(res, string(orderInfo.Sender.Bytes())) } else { @@ -266,57 +264,41 @@ func GetAccountBalances(mapper auth.AccountKeeper, ctx sdk.Context, accSlices .. return } -func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.Keeper, dexMiniKeeper *orderPkg.MiniKeeper, ctx sdk.Context, matchAllMiniSymbols bool) ([]*Trade, []*Trade) { +func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, matchAllMiniSymbols bool) ([]*Trade, []*Trade) { // This channels is used for protect not update `dexKeeper.OrderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) // while dexKeeper.OrderChanges are not separated by concurrent factor (users here) - iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize) - miniIocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, MiniTransferCollectionChannelSize) + iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize + MiniTransferCollectionChannelSize) wg := sync.WaitGroup{} - wg.Add(2) + wg.Add(1) go updateExpireFeeForPublish(dexKeeper, &wg, iocExpireFeeHolderCh) - go updateExpireFeeForPublish(dexMiniKeeper, &wg, miniIocExpireFeeHolderCh) var postAlloTransHandler = func(tran orderPkg.Transfer) { - var receiver chan orderPkg.ExpireHolder - if utils.IsMiniTokenTradingPair(tran.Symbol) { - receiver = miniIocExpireFeeHolderCh - } else { - receiver = iocExpireFeeHolderCh - } if tran.IsExpire() { if tran.IsExpiredWithFee() { // we only got expire of Ioc here, gte orders expire is handled in breathe block - receiver <- orderPkg.ExpireHolder{tran.Oid, orderPkg.IocNoFill, tran.Fee.String()} + iocExpireFeeHolderCh <- orderPkg.ExpireHolder{tran.Oid, orderPkg.IocNoFill, tran.Fee.String(), tran.Symbol} } else { - receiver <- orderPkg.ExpireHolder{tran.Oid, orderPkg.IocExpire, tran.Fee.String()} + iocExpireFeeHolderCh <- orderPkg.ExpireHolder{tran.Oid, orderPkg.IocExpire, tran.Fee.String(), tran.Symbol} } } } - orderPkg.MatchAndAllocateSymbols(dexKeeper, dexMiniKeeper, ctx, postAlloTransHandler, matchAllMiniSymbols, Logger) + dexKeeper.MatchAndAllocateSymbols(ctx, postAlloTransHandler, matchAllMiniSymbols) close(iocExpireFeeHolderCh) - close(miniIocExpireFeeHolderCh) - - tradeIdx := 0 tradeHeight := ctx.BlockHeight() - tradesToPublish := extractTradesToPublish(dexKeeper, ctx, tradeHeight, &tradeIdx) - var miniTradesToPublish []*Trade - if !sdk.IsUpgrade(upgrade.BEP8) { - miniTradesToPublish = make([]*Trade, 0) - } else { - miniTradesToPublish = extractTradesToPublish(dexMiniKeeper, ctx, tradeHeight, &tradeIdx) - } + tradesToPublish, miniTradesToPublish := extractTradesToPublish(dexKeeper, ctx, tradeHeight) wg.Wait() return tradesToPublish, miniTradesToPublish } -func extractTradesToPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, tradeHeight int64, tradeIdx *int) []*Trade { - tradesToPublish := make([]*Trade, 0) - //TODO reduce call of ListAllTradingPairs - for _, pair := range dexKeeper.GetPairMapper().ListAllTradingPairs(ctx) { - symbol := pair.GetSymbol() +func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, tradeHeight int64) (tradesToPublish []*Trade, miniTradesToPublish []*Trade) { + tradesToPublish = make([]*Trade, 0, 32) + miniTradesToPublish = make([]*Trade, 0, 32) + tradeIdx := 0 + + for symbol := range dexKeeper.GetEngines() { matchEngTrades, _ := dexKeeper.GetLastTrades(tradeHeight, symbol) for _, trade := range matchEngTrades { var ssinglefee string @@ -331,7 +313,7 @@ func extractTradesToPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, } t := &Trade{ - Id: fmt.Sprintf("%d-%d", tradeHeight, *tradeIdx), + Id: fmt.Sprintf("%d-%d", tradeHeight, tradeIdx), Symbol: symbol, Sid: trade.Sid, Bid: trade.Bid, @@ -341,15 +323,18 @@ func extractTradesToPublish(dexKeeper orderPkg.DexOrderKeeper, ctx sdk.Context, BSingleFee: bsinglefee, TickType: int(trade.TickType), } - *tradeIdx += 1 + tradeIdx += 1 + if types.IsMiniTokenSymbol(symbol){ + miniTradesToPublish = append(miniTradesToPublish, t) + } tradesToPublish = append(tradesToPublish, t) } } - return tradesToPublish + return tradesToPublish, miniTradesToPublish } func ExpireOrdersForPublish( - dexKeeper orderPkg.DexOrderKeeper, + dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, blockTime time.Time) { expireHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize) @@ -358,7 +343,7 @@ func ExpireOrdersForPublish( go updateExpireFeeForPublish(dexKeeper, &wg, expireHolderCh) var collectorForExpires = func(tran orderPkg.Transfer) { if tran.IsExpire() { - expireHolderCh <- orderPkg.ExpireHolder{tran.Oid, orderPkg.Expired, tran.Fee.String()} + expireHolderCh <- orderPkg.ExpireHolder{tran.Oid, orderPkg.Expired, tran.Fee.String(), tran.Symbol} } } dexKeeper.ExpireOrders(ctx, blockTime, collectorForExpires) @@ -367,14 +352,14 @@ func ExpireOrdersForPublish( return } -func DelistTradingPairForPublish(ctx sdk.Context, dexKeeper orderPkg.DexOrderKeeper, symbol string) { +func DelistTradingPairForPublish(ctx sdk.Context, dexKeeper *orderPkg.DexKeeper, symbol string) { expireHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize) wg := sync.WaitGroup{} wg.Add(1) go updateExpireFeeForPublish(dexKeeper, &wg, expireHolderCh) var collectorForExpires = func(tran orderPkg.Transfer) { if tran.IsExpire() { - expireHolderCh <- orderPkg.ExpireHolder{tran.Oid, orderPkg.Expired, tran.Fee.String()} + expireHolderCh <- orderPkg.ExpireHolder{tran.Oid, orderPkg.Expired, tran.Fee.String(), tran.Symbol} } } dexKeeper.DelistTradingPair(ctx, symbol, collectorForExpires) @@ -406,14 +391,14 @@ func CollectStakeUpdatesForPublish(unbondingDelegations []stake.UnbondingDelegat } func updateExpireFeeForPublish( - dexKeeper orderPkg.DexOrderKeeper, + dexKeeper *orderPkg.DexKeeper, wg *sync.WaitGroup, expHolderCh <-chan orderPkg.ExpireHolder) { defer wg.Done() for expHolder := range expHolderCh { Logger.Debug("transfer collector for order", "orderId", expHolder.OrderId) change := orderPkg.OrderChange{expHolder.OrderId, expHolder.Reason, expHolder.Fee, nil} - dexKeeper.UpdateOrderChange(change) + dexKeeper.UpdateOrderChangeSync(change, expHolder.Symbol) } } diff --git a/app/pub/keeper_pub_test.go b/app/pub/keeper_pub_test.go index ef6d0de72..e268073be 100644 --- a/app/pub/keeper_pub_test.go +++ b/app/pub/keeper_pub_test.go @@ -39,7 +39,7 @@ func newTestFeeConfig() orderPkg.FeeConfig { return feeConfig } -var keeper *orderPkg.Keeper +var keeper *orderPkg.BEP2OrderKeeper var buyer sdk.AccAddress var seller sdk.AccAddress var am auth.AccountKeeper @@ -61,7 +61,7 @@ func setupKeeperTest(t *testing.T) (*assert.Assertions, *require.Assertions) { ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, logger).WithAccountCache(accountCache) pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) - keeper = orderPkg.NewKeeper(capKey2, am, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, true) + keeper = orderPkg.NewBEP2OrderKeeper(capKey2, am, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, true) tradingPair := dextypes.NewTradingPair("XYZ-000", types.NativeTokenSymbol, 1e8) keeper.PairMapper.AddTradingPair(ctx, tradingPair) keeper.AddEngine(tradingPair) diff --git a/app_test/utils_test.go b/app_test/utils_test.go index 2af12b401..20269c754 100644 --- a/app_test/utils_test.go +++ b/app_test/utils_test.go @@ -24,7 +24,7 @@ import ( // this file has to named with suffix _test, this is a golang bug: https://github.com/golang/go/issues/24895 var ( - keeper *orderPkg.Keeper + keeper *orderPkg.BEP2OrderKeeper buyer sdk.AccAddress seller sdk.AccAddress am auth.AccountKeeper diff --git a/common/stores.go b/common/stores.go index 854d53400..775a3d38e 100644 --- a/common/stores.go +++ b/common/stores.go @@ -9,9 +9,7 @@ const ( TokenStoreName = "tokens" MiniTokenStoreName = "minitokens" DexStoreName = "dex" - DexMiniStoreName = "dex_mini" PairStoreName = "pairs" - MiniTokenPairStoreName = "mini_pairs" StakeStoreName = "stake" ParamsStoreName = "params" GovStoreName = "gov" @@ -29,7 +27,6 @@ var ( ValAddrStoreKey = sdk.NewKVStoreKey(ValAddrStoreName) TokenStoreKey = sdk.NewKVStoreKey(TokenStoreName) DexStoreKey = sdk.NewKVStoreKey(DexStoreName) - DexMiniStoreKey = sdk.NewKVStoreKey(DexMiniStoreName) PairStoreKey = sdk.NewKVStoreKey(PairStoreName) StakeStoreKey = sdk.NewKVStoreKey(StakeStoreName) ParamsStoreKey = sdk.NewKVStoreKey(ParamsStoreName) @@ -41,7 +38,6 @@ var ( TParamsStoreKey = sdk.NewTransientStoreKey(ParamsTransientStoreName) MiniTokenStoreKey = sdk.NewKVStoreKey(MiniTokenStoreName) - MiniTokenPairStoreKey = sdk.NewKVStoreKey(MiniTokenPairStoreName) StoreKeyNameMap = map[string]sdk.StoreKey{ MainStoreName: MainStoreKey, @@ -49,7 +45,6 @@ var ( ValAddrStoreName: ValAddrStoreKey, TokenStoreName: TokenStoreKey, DexStoreName: DexStoreKey, - DexMiniStoreName: DexMiniStoreKey, PairStoreName: PairStoreKey, StakeStoreName: StakeStoreKey, ParamsStoreName: ParamsStoreKey, @@ -59,7 +54,6 @@ var ( StakeTransientStoreName: TStakeStoreKey, ParamsTransientStoreName: TParamsStoreKey, MiniTokenStoreName: MiniTokenStoreKey, - MiniTokenPairStoreName: MiniTokenPairStoreKey, } NonTransientStoreKeyNames = []string{ @@ -68,7 +62,6 @@ var ( ValAddrStoreName, TokenStoreName, DexStoreName, - DexMiniStoreName, PairStoreName, StakeStoreName, ParamsStoreName, @@ -76,7 +69,6 @@ var ( TimeLockStoreName, AtomicSwapStoreName, MiniTokenStoreName, - MiniTokenPairStoreName, } ) diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index 316aa5bc3..ca9c610df 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -43,15 +43,15 @@ do pause=$(random 5 7) symbolNum=$(random 1 10) - symbol="NNB-BF1_BNB" + symbol="ZCB-51A_BNB" if [ $symbolNum -lt 4 ] then - symbol="ZCB-ED3_BNB" + symbol="ZCB-51A_BNB" elif [ $symbolNum -lt 6 ] then - symbol="TEST1-8B2M_BNB" + symbol="ZCB-51A_BNB" else [ $symbolNum -lt 8 ] - symbol="ZIP-BECM_BNB" + symbol="ZCB-51A_BNB" fi from="zc" if [ $side == 1 ] diff --git a/networks/publisher/setup_mini.sh b/networks/publisher/setup_mini.sh index 187045e56..876620868 100755 --- a/networks/publisher/setup_mini.sh +++ b/networks/publisher/setup_mini.sh @@ -80,17 +80,17 @@ result=$(expect ${scripthome}/recover.exp "${secret}" "zc" "${clipath}" "${cliho result=$(expect ${scripthome}/add_key.exp "zz" "${clipath}" "${clihome}") zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") - +sleep 5 # issue&list NNB and ZCB for ordergen result=$(${cli} token issue --from=zc --token-name="New BNB Coin" --symbol=NNB --total-supply=2000000000000000 --chain-id ${chain_id}) nnb_symbol=$(echo "${result}" | tail -n 1 | grep -o "NNB-[0-9A-Z]*") echo ${nnb_symbol} sleep 5 ((expire_time=$(date '+%s')+1000)) -${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${nnb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 5 --json +${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${nnb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 8 --json sleep 2 ${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 1 --option Yes --json -sleep 6 +sleep 7 ${cli} dex list -s=${nnb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 1 sleep 1 result=$(${cli} token issue --from=zc --token-name="ZC Coin" --symbol=ZCB --total-supply=2000000000000000 --chain-id ${chain_id}) diff --git a/networks/tools/snapshot_viewer/snapshot.go b/networks/tools/snapshot_viewer/snapshot.go index 5a3e24054..fbda70251 100644 --- a/networks/tools/snapshot_viewer/snapshot.go +++ b/networks/tools/snapshot_viewer/snapshot.go @@ -45,7 +45,7 @@ func openAppDB(root string) *db.GoLevelDB { func prepareCms(root string, appDB *db.GoLevelDB) sdk.CommitMultiStore { keys := []store.StoreKey{ - common.MainStoreKey, common.TokenStoreKey, common.DexStoreKey, common.DexMiniStoreKey, + common.MainStoreKey, common.TokenStoreKey, common.DexStoreKey, common.PairStoreKey, common.GovStoreKey, common.StakeStoreKey, common.ParamsStoreKey, common.ValAddrStoreKey, common.AccountStoreKey, common.MiniTokenStoreKey} diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index fa6b5084f..330647e0f 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -10,15 +10,16 @@ import ( // type TradingPair = types.TradingPair type TradingPairMapper = store.TradingPairMapper -type DexKeeper = order.Keeper -type DexMiniTokenKeeper = order.MiniKeeper -type DexOrderKeeper = order.DexOrderKeeper -type DexGlobalKeeper = order.GlobalKeeper - +type BEP2OrderKeeper = order.BEP2OrderKeeper +type MiniOrderKeeper = order.MiniOrderKeeper +type IDexOrderKeeper = order.IDexOrderKeeper +type DexKeeper = order.DexKeeper +type SymbolPairType = order.SymbolPairType var NewTradingPairMapper = store.NewTradingPairMapper -var NewOrderKeeper = order.NewKeeper -var NewMiniKeeper = order.NewMiniKeeper -var NewGlobalKeeper = order.NewGlobalKeeper +var NewOrderKeeper = order.NewBEP2OrderKeeper +var NewMiniOrderKeeper = order.NewMiniOrderKeeper +var NewDexKeeper = order.NewDexKeeper +var PairType = order.PairType const DefaultCodespace = types.DefaultCodespace diff --git a/plugins/dex/list/handler.go b/plugins/dex/list/handler.go index 88e3bf896..463e23b08 100644 --- a/plugins/dex/list/handler.go +++ b/plugins/dex/list/handler.go @@ -18,7 +18,7 @@ import ( ) // NewHandler initialises dex message handlers -func NewHandler(keeper *order.Keeper, tokenMapper tokens.Mapper, govKeeper gov.Keeper) sdk.Handler { +func NewHandler(keeper *order.DexKeeper, tokenMapper tokens.Mapper, govKeeper gov.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case ListMsg: @@ -74,7 +74,7 @@ func checkListProposal(ctx sdk.Context, govKeeper gov.Keeper, msg ListMsg) error return nil } -func handleList(ctx sdk.Context, keeper *order.Keeper, tokenMapper tokens.Mapper, govKeeper gov.Keeper, +func handleList(ctx sdk.Context, keeper *order.DexKeeper, tokenMapper tokens.Mapper, govKeeper gov.Keeper, msg ListMsg) sdk.Result { if err := checkListProposal(ctx, govKeeper, msg); err != nil { return types.ErrInvalidProposal(err.Error()).Result() diff --git a/plugins/dex/list/handler_test.go b/plugins/dex/list/handler_test.go index d4107ba18..401d3a24a 100644 --- a/plugins/dex/list/handler_test.go +++ b/plugins/dex/list/handler_test.go @@ -42,7 +42,7 @@ func MakeCodec() *codec.Codec { return cdc } -func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, orderKeeper *order.Keeper, tokenMapper tokenStore.Mapper, govKeeper gov.Keeper) { +func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, orderKeeper *order.BEP2OrderKeeper, tokenMapper tokenStore.Mapper, govKeeper gov.Keeper) { accKey := sdk.NewKVStoreKey("acc") pairKey := sdk.NewKVStoreKey("pair") tokenKey := sdk.NewKVStoreKey("token") @@ -65,7 +65,7 @@ func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, orderKeeper *o accKeeper := auth.NewAccountKeeper(cdc, accKey, types.ProtoAppAccount) codespacer := sdk.NewCodespacer() pairMapper := store.NewTradingPairMapper(cdc, pairKey, false) - orderKeeper = order.NewKeeper(common.DexStoreKey, accKeeper, pairMapper, + orderKeeper = order.NewBEP2OrderKeeper(common.DexStoreKey, accKeeper, pairMapper, codespacer.RegisterNext(dexTypes.DefaultCodespace), 2, cdc, false) tokenMapper = tokenStore.NewMapper(cdc, tokenKey) diff --git a/plugins/dex/list/hooks.go b/plugins/dex/list/hooks.go index 89fd5302e..180d60fb8 100644 --- a/plugins/dex/list/hooks.go +++ b/plugins/dex/list/hooks.go @@ -14,11 +14,11 @@ import ( ) type ListHooks struct { - orderKeeper *order.Keeper + orderKeeper *order.DexKeeper tokenMapper tokens.Mapper } -func NewListHooks(orderKeeper *order.Keeper, tokenMapper tokens.Mapper) ListHooks { +func NewListHooks(orderKeeper *order.DexKeeper, tokenMapper tokens.Mapper) ListHooks { return ListHooks{ orderKeeper: orderKeeper, tokenMapper: tokenMapper, @@ -74,10 +74,10 @@ func (hooks ListHooks) OnProposalSubmitted(ctx sdk.Context, proposal gov.Proposa } type DelistHooks struct { - orderKeeper *order.Keeper + orderKeeper *order.DexKeeper } -func NewDelistHooks(orderKeeper *order.Keeper) DelistHooks { +func NewDelistHooks(orderKeeper *order.DexKeeper) DelistHooks { return DelistHooks{ orderKeeper: orderKeeper, } diff --git a/plugins/dex/listmini/handler.go b/plugins/dex/listmini/handler.go index bb7bf35d8..6540eaa81 100644 --- a/plugins/dex/listmini/handler.go +++ b/plugins/dex/listmini/handler.go @@ -15,11 +15,11 @@ import ( ) // NewHandler initialises dex message handlers -func NewHandler(miniKeeper *order.MiniKeeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper) sdk.Handler { +func NewHandler(dexKeeper *order.DexKeeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case ListMiniMsg: - return handleList(ctx, miniKeeper, miniTokenMapper, tokenMapper, msg) + return handleList(ctx, dexKeeper, miniTokenMapper, tokenMapper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -27,13 +27,13 @@ func NewHandler(miniKeeper *order.MiniKeeper, miniTokenMapper minitokens.MiniTok } } -func handleList(ctx sdk.Context, miniKeeper *order.MiniKeeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper, +func handleList(ctx sdk.Context, dexKeeper *order.DexKeeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper, msg ListMiniMsg) sdk.Result { if !sdk.IsUpgrade(upgrade.BEP8) { return sdk.ErrInternal(fmt.Sprint("list mini-token is not supported at current height")).Result() } - if err := miniKeeper.CanListTradingPair(ctx, msg.BaseAssetSymbol, msg.QuoteAssetSymbol); err != nil { + if err := dexKeeper.CanListTradingPair(ctx, msg.BaseAssetSymbol, msg.QuoteAssetSymbol); err != nil { return sdk.ErrInvalidCoins(err.Error()).Result() } @@ -57,19 +57,19 @@ func handleList(ctx sdk.Context, miniKeeper *order.MiniKeeper, miniTokenMapper m var lotSize int64 if sdk.IsUpgrade(upgrade.LotSizeOptimization) { - lotSize = miniKeeper.DetermineLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice) + lotSize = dexKeeper.DetermineLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice) } else { lotSize = utils.CalcLotSize(msg.InitPrice) } pair := types.NewTradingPairWithLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice, lotSize) - err = miniKeeper.PairMapper.AddTradingPair(ctx, pair) + err = dexKeeper.PairMapper.AddTradingPair(ctx, pair) if err != nil { return sdk.ErrInternal(err.Error()).Result() } // this is done in memory! we must not run this block in checktx or simulate! if ctx.IsDeliverTx() { // only add engine during DeliverTx - miniKeeper.AddEngine(pair) + dexKeeper.AddEngine(pair) log.With("module", "dex").Info("List new mini-token Pair and created new match engine", "pair", pair) } diff --git a/plugins/dex/matcheng/engine_new.go b/plugins/dex/matcheng/engine_new.go index 6231ef881..bf56c0582 100644 --- a/plugins/dex/matcheng/engine_new.go +++ b/plugins/dex/matcheng/engine_new.go @@ -20,16 +20,19 @@ func (me *MatchEng) Match(height int64, isMini bool) bool { me.Trades = me.Trades[:0] r := me.Book.GetOverlappedRange(&me.overLappedLevel, &me.buyBuf, &me.sellBuf) if r <= 0 { + me.LastMatchHeight = height return true } prepareMatch(&me.overLappedLevel) tradePrice, index := getTradePrice(&me.overLappedLevel, &me.maxExec, &me.leastSurplus, me.LastTradePrice, me.PriceLimitPct) if index < 0 { + me.LastMatchHeight = height return false } if err := me.dropRedundantQty(index); err != nil { me.logger.Error("dropRedundantQty failed", "error", err) + me.LastMatchHeight = height return false } //If order height > the last Match height, then it's maker. diff --git a/plugins/dex/matcheng/match_new_test.go b/plugins/dex/matcheng/match_new_test.go index 7973dbe7e..be27e6d3e 100644 --- a/plugins/dex/matcheng/match_new_test.go +++ b/plugins/dex/matcheng/match_new_test.go @@ -486,7 +486,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { l.BuyTakerStartIdx, l.BuyMakerTotal, l.SellTakerStartIdx, l.SellMakerTotal = 0, 0, 0, 0 } - takerSide, err := me.determineTakerSide(100, 0) + takerSide, err := me.determineTakerSide(99, 0) assert.NoError(err) assert.Equal(BUYSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 2, 200) @@ -494,7 +494,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { checkAndClear(&me.overLappedLevel[2], 0, 0, 0, 0) checkAndClear(&me.overLappedLevel[3], 0, 0, 0, 0) - takerSide, err = me.determineTakerSide(100, 1) + takerSide, err = me.determineTakerSide(99, 1) assert.NoError(err) assert.Equal(BUYSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 0, 0) @@ -502,7 +502,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { checkAndClear(&me.overLappedLevel[2], 0, 0, 0, 0) checkAndClear(&me.overLappedLevel[3], 0, 0, 0, 0) - takerSide, err = me.determineTakerSide(100, 2) + takerSide, err = me.determineTakerSide(99, 2) assert.NoError(err) assert.Equal(SELLSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 0, 0) @@ -510,7 +510,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { checkAndClear(&me.overLappedLevel[2], 2, 200, 0, 0) checkAndClear(&me.overLappedLevel[3], 0, 0, 0, 0) - takerSide, err = me.determineTakerSide(100, 3) + takerSide, err = me.determineTakerSide(99, 3) assert.NoError(err) assert.Equal(SELLSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 0, 0) @@ -527,7 +527,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { {"2", 100, 100, 0, 100}, }, }} - takerSide, err = me.determineTakerSide(100, 0) + takerSide, err = me.determineTakerSide(99, 0) assert.NoError(err) assert.Equal(BUYSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 0, 0) @@ -541,7 +541,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { {"2", 99, 100, 0, 100}, }, }} - takerSide, err = me.determineTakerSide(100, 0) + takerSide, err = me.determineTakerSide(99, 0) assert.EqualError(err, "both buy side and sell side have maker orders.") assert.Equal(UNKNOWN, takerSide) } diff --git a/plugins/dex/order/fee_test.go b/plugins/dex/order/fee_test.go index 2fa99222f..dd6f3eea6 100644 --- a/plugins/dex/order/fee_test.go +++ b/plugins/dex/order/fee_test.go @@ -28,7 +28,7 @@ func NewTestFeeConfig() FeeConfig { func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { ctx, am, keeper := setup() - keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("BNB", "XYZ-111", 1e7)) _, acc := testutils.NewAccount(ctx, am, 0) @@ -39,10 +39,10 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 100, } // no enough bnb or native fee rounding to 0 - fee := keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee := keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"ABC-000", 1}}, fee.Tokens) _, acc = testutils.NewAccount(ctx, am, 100) - fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"ABC-000", 1}}, fee.Tokens) tran = Transfer{ @@ -52,10 +52,10 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 10000, } _, acc = testutils.NewAccount(ctx, am, 1) - fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"ABC-000", 1000}}, fee.Tokens) _, acc = testutils.NewAccount(ctx, am, 100) - fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) tran = Transfer{ @@ -65,7 +65,7 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 1000, } _, acc = testutils.NewAccount(ctx, am, 100) - fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 0}}, fee.Tokens) tran = Transfer{ @@ -74,7 +74,7 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { outAsset: "ABC-000", out: 100000, } - fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) tran = Transfer{ @@ -84,7 +84,7 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 100000, } acc.SetCoins(sdk.Coins{{"ABC-000", 1000000}, {"BNB", 100}}) - fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) tran = Transfer{ inAsset: "XYZ-111", @@ -93,13 +93,13 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { out: 100000, } acc.SetCoins(sdk.Coins{{"XYZ-111", 1000000}, {"BNB", 1000}}) - fee = keeper.GlobalKeeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) + fee = keeper.FeeManager.calcTradeFeeForSingleTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 500}}, fee.Tokens) } func TestFeeManager_CalcTradesFee(t *testing.T) { ctx, am, keeper := setup() - keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("XYZ-111", "BNB", 2e7)) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BTC", 1e4)) @@ -126,7 +126,7 @@ func TestFeeManager_CalcTradesFee(t *testing.T) { {"BTC", 10e8}, {"XYZ-000", 100e8}, }) - fees := keeper.GlobalKeeper.FeeManager.CalcTradesFee(acc.GetCoins(), tradeTransfers, keeper.engines) + fees := keeper.FeeManager.CalcTradesFee(acc.GetCoins(), tradeTransfers, keeper.engines) require.Equal(t, "ABC-000:8000;BNB:15251305;BTC:100000;XYZ-111:2000", fees.String()) require.Equal(t, "BNB:250000", tradeTransfers[0].Fee.String()) require.Equal(t, "BNB:15000000", tradeTransfers[1].Fee.String()) @@ -148,7 +148,7 @@ func TestFeeManager_CalcTradesFee(t *testing.T) { func TestFeeManager_CalcExpiresFee(t *testing.T) { ctx, am, keeper := setup() - keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("XYZ-111", "BNB", 2e7)) keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC", 5e5)) @@ -173,7 +173,7 @@ func TestFeeManager_CalcExpiresFee(t *testing.T) { {"BTC", 10e8}, {"XYZ-111", 800000}, }) - fees := keeper.GlobalKeeper.FeeManager.CalcExpiresFee(acc.GetCoins(), eventFullyExpire, expireTransfers, keeper.engines, nil) + fees := keeper.FeeManager.CalcExpiresFee(acc.GetCoins(), eventFullyExpire, expireTransfers, keeper.engines, nil) require.Equal(t, "ABC-000:1000000;BNB:120000;BTC:500;XYZ-111:800000", fees.String()) require.Equal(t, "BNB:20000", expireTransfers[0].Fee.String()) require.Equal(t, "BNB:20000", expireTransfers[1].Fee.String()) @@ -195,17 +195,17 @@ func TestFeeManager_CalcExpiresFee(t *testing.T) { func TestFeeManager_CalcTradeFee(t *testing.T) { ctx, am, keeper := setup() - keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) // BNB _, acc := testutils.NewAccount(ctx, am, 0) // the tradeIn amount is large enough to make the fee > 0 tradeIn := sdk.NewCoin(types.NativeTokenSymbol, 100e8) - fee := keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee := keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 5e6)}, fee.Tokens) // small tradeIn amount tradeIn = sdk.NewCoin(types.NativeTokenSymbol, 100) - fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 0)}, fee.Tokens) // !BNB @@ -213,11 +213,11 @@ func TestFeeManager_CalcTradeFee(t *testing.T) { // has enough bnb tradeIn = sdk.NewCoin("ABC-000", 1000e8) acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e8)}) - fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 5e6)}, fee.Tokens) // no enough bnb acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e6)}) - fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e8)}, fee.Tokens) // very high price to produce int64 overflow @@ -225,64 +225,64 @@ func TestFeeManager_CalcTradeFee(t *testing.T) { // has enough bnb tradeIn = sdk.NewCoin("ABC-000", 1000e8) acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e16)}) - fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 5e15)}, fee.Tokens) // no enough bnb, fee is within int64 acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e15)}) - fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e8)}, fee.Tokens) // no enough bnb, even the fee overflows tradeIn = sdk.NewCoin("ABC-000", 1e16) - fee = keeper.GlobalKeeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) + fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e13)}, fee.Tokens) } func TestFeeManager_CalcFixedFee(t *testing.T) { ctx, am, keeper := setup() - keeper.GlobalKeeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) _, acc := testutils.NewAccount(ctx, am, 1e4) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC-000", 1e5)) // in BNB // no enough BNB, but inAsset == BNB - fee := keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) + fee := keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e4)}, fee.Tokens) // enough BNB acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 3e4)}) - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2e4)}, fee.Tokens) - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventIOCFullyExpire, types.NativeTokenSymbol, keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventIOCFullyExpire, types.NativeTokenSymbol, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e4)}, fee.Tokens) - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyCancel, types.NativeTokenSymbol, keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyCancel, types.NativeTokenSymbol, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2e4)}, fee.Tokens) // ABC-000_BNB, sell ABC-000 - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2e4)}, fee.Tokens) // No enough native token, but enough ABC-000 acc.SetCoins(sdk.Coins{{Denom: types.NativeTokenSymbol, Amount: 1e4}, {Denom: "ABC-000", Amount: 1e8}}) - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e6)}, fee.Tokens) // No enough native token and ABC-000 acc.SetCoins(sdk.Coins{{Denom: types.NativeTokenSymbol, Amount: 1e4}, {Denom: "ABC-000", Amount: 1e5}}) - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e5)}, fee.Tokens) // BNB_BTC-000, sell BTC-000 acc.SetCoins(sdk.Coins{{Denom: "BTC-000", Amount: 1e4}}) - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("BTC-000", 1e2)}, fee.Tokens) // extreme prices keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1)) keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC-000", 1e16)) acc.SetCoins(sdk.Coins{{Denom: "ABC-000", Amount: 1e16}, {Denom: "BTC-000", Amount: 1e16}}) - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e13)}, fee.Tokens) - fee = keeper.GlobalKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin("BTC-000", 1e13)}, fee.Tokens) } diff --git a/plugins/dex/order/global_keeper.go b/plugins/dex/order/global_keeper.go index ed72ef113..61b4c8e47 100644 --- a/plugins/dex/order/global_keeper.go +++ b/plugins/dex/order/global_keeper.go @@ -3,7 +3,13 @@ package order import ( "errors" "fmt" + "github.com/binance-chain/node/common/fees" + "github.com/binance-chain/node/common/utils" + "github.com/binance-chain/node/plugins/dex/store" + "math" + "strings" "sync" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -14,33 +20,157 @@ import ( "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/dex/matcheng" + me "github.com/binance-chain/node/plugins/dex/matcheng" + dexTypes "github.com/binance-chain/node/plugins/dex/types" + dexUtils "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/plugins/param/paramhub" paramTypes "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/wire" ) -type GlobalKeeper struct { +const ( + BEP2TypeValue = 1 + MiniTypeValue = 2 +) + +type SymbolPairType int8 + +var PairType = struct { + BEP2 SymbolPairType + MINI SymbolPairType +}{BEP2TypeValue, MiniTypeValue} + +type IDexKeeper interface { + InitRecentPrices(ctx sdk.Context) + AddEngine(pair dexTypes.TradingPair) *me.MatchEng + UpdateTickSizeAndLotSize(ctx sdk.Context) + DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) + UpdateLotSize(symbol string, lotSize int64) + AddOrder(info OrderInfo, isRecovery bool) (err error) + RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) + GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) + OrderExists(symbol, id string) (OrderInfo, bool) + GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel + GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder + GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap + GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel + GetLastTrades(height int64, pair string) ([]me.Trade, int64) + GetLastTradesForPair(pair string) ([]me.Trade, int64) + ClearOrderBook(pair string) + ClearOrderChanges() + StoreTradePrices(ctx sdk.Context) + ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) + MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) + GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) + GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 + DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) + CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error + CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error + SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) + LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) + GetPairMapper() store.TradingPairMapper + GetOrderChanges(pairType SymbolPairType) OrderChanges + GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish + GetAllOrders() map[string]map[string]*OrderInfo + GetAllOrdersForPair(symbol string) map[string]*OrderInfo + getAccountKeeper() *auth.AccountKeeper + getLogger() tmlog.Logger + getFeeManager() *FeeManager + GetEngines() map[string]*me.MatchEng + ShouldPublishOrder() bool + UpdateOrderChange(change OrderChange, symbol string) + UpdateOrderChangeSync(change OrderChange, symbol string) + ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error + SelectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string + ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) +} + +type DexKeeper struct { + PairMapper store.TradingPairMapper + storeKey sdk.StoreKey // The key used to access the store from the Context. + codespace sdk.CodespaceType + recentPrices map[string]*utils.FixedSizeRing // symbol -> latest "numPricesStored" prices per "pricesStoreEvery" blocks am auth.AccountKeeper FeeManager *FeeManager RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee CollectOrderInfoForPublish bool + engines map[string]*me.MatchEng logger tmlog.Logger + poolSize uint // number of concurrent channels, counted in the pow of 2 + cdc *wire.Codec + OrderKeepers []IDexOrderKeeper } -func NewGlobalKeeper(cdc *wire.Codec, am auth.AccountKeeper, collectOrderInfoForPublish bool) *GlobalKeeper { - logger := bnclog.With("module", "dex_global_keeper") - return &GlobalKeeper{ +var _ IDexKeeper = &DexKeeper{} + +func NewDexKeeper(key sdk.StoreKey, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, cdc *wire.Codec, am auth.AccountKeeper, collectOrderInfoForPublish bool, concurrency uint) *DexKeeper { + logger := bnclog.With("module", "dex_keeper") + return &DexKeeper{ + PairMapper: tradingPairMapper, + storeKey: key, + codespace: codespace, + recentPrices: make(map[string]*utils.FixedSizeRing, 256), am: am, RoundOrderFees: make(map[string]*types.Fee, 256), FeeManager: NewFeeManager(cdc, logger), CollectOrderInfoForPublish: collectOrderInfoForPublish, + engines: make(map[string]*me.MatchEng), + poolSize: concurrency, + cdc: cdc, logger: logger, + OrderKeepers: []IDexOrderKeeper{NewBEP2OrderKeeper(), NewMiniOrderKeeper()}, + } +} + +func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { + return me.NewMatchEng(pairSymbol, basePrice, lotSize, 0.05) +} + +func (kp *DexKeeper) InitRecentPrices(ctx sdk.Context) { + kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) +} + +func (kp *DexKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { + symbol := strings.ToUpper(pair.GetSymbol()) + eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) + kp.engines[symbol] = eng + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.initOrders(symbol) + break + } + } + return eng +} + +func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { + //try update order book first + symbol := strings.ToUpper(info.Symbol) + eng, ok := kp.engines[symbol] + if !ok { + err = fmt.Errorf("match engine of symbol %s doesn't exist", symbol) + return + } + + _, err = eng.Book.InsertOrder(info.Id, info.Side, info.CreatedHeight, info.Price, info.Quantity) + if err != nil { + return err } + + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) + break + } + } + + kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) + return nil } // deliberately make `fee` parameter not a pointer // in case we modify the original fee (which will be referenced when distribute to validator) -func (kp *GlobalKeeper) updateRoundOrderFee(addr string, fee types.Fee) { +func (kp *DexKeeper) updateRoundOrderFee(addr string, fee types.Fee) { if existingFee, ok := kp.RoundOrderFees[addr]; ok { existingFee.AddFee(fee) } else { @@ -48,14 +178,14 @@ func (kp *GlobalKeeper) updateRoundOrderFee(addr string, fee types.Fee) { } } -func (kp *GlobalKeeper) ClearRoundFee() { +func (kp *DexKeeper) ClearRoundFee() { kp.RoundOrderFees = make(map[string]*types.Fee, 256) } -func (kp *GlobalKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer), engines map[string]*matcheng.MatchEng) ( +func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( types.Fee, map[string]*types.Fee) { if !sdk.IsUpgrade(upgrade.BEP19) { - return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler, engines) + return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler, kp.engines) } // use string of the addr as the key since map makes a fast path for string key. @@ -97,7 +227,7 @@ func (kp *GlobalKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAl for addrStr, trans := range tradeTransfers { addr := sdk.AccAddress(addrStr) acc := kp.am.GetAccount(ctx, addr) - fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, engines) + fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, kp.engines) if !fees.IsEmpty() { feesPerAcc[addrStr] = &fees acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) @@ -110,7 +240,7 @@ func (kp *GlobalKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAl addr := sdk.AccAddress(addrStr) acc := kp.am.GetAccount(ctx, addr) - fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, engines, postAllocateHandler) + fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, kp.engines, postAllocateHandler) if !fees.IsEmpty() { if _, ok := feesPerAcc[addrStr]; ok { feesPerAcc[addrStr].AddFee(fees) @@ -125,11 +255,10 @@ func (kp *GlobalKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAl return totalFee, feesPerAcc } -func (kp *GlobalKeeper) allocateAndCalcFee( +func (kp *DexKeeper) allocateAndCalcFee( ctx sdk.Context, tradeOuts []chan Transfer, - postAlloTransHandler TransferHandler, - engines map[string]*matcheng.MatchEng) types.Fee { + postAlloTransHandler TransferHandler) types.Fee { concurrency := len(tradeOuts) var wg sync.WaitGroup wg.Add(concurrency) @@ -137,7 +266,7 @@ func (kp *GlobalKeeper) allocateAndCalcFee( feesPerAcc := make([]map[string]*types.Fee, concurrency) allocatePerCh := func(index int, tranCh <-chan Transfer) { defer wg.Done() - fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler, engines) + fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) feesPerCh[index].AddFee(fee) feesPerAcc[index] = feeByAcc } @@ -161,7 +290,7 @@ func (kp *GlobalKeeper) allocateAndCalcFee( } // DEPRECATED -func (kp *GlobalKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer), engines map[string]*matcheng.MatchEng) ( +func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer), engines map[string]*matcheng.MatchEng) ( types.Fee, map[string]*types.Fee) { // use string of the addr as the key since map makes a fast path for string key. // Also, making the key have same length is also an optimization. @@ -242,7 +371,7 @@ func (kp *GlobalKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Tra return totalFee, feesPerAcc } -func (kp *GlobalKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { +func (kp *DexKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. @@ -269,7 +398,7 @@ func (kp *GlobalKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { return nil } -func (kp *GlobalKeeper) SubscribeParamChange(hub *paramhub.Keeper) { +func (kp *DexKeeper) SubscribeParamChange(hub *paramhub.Keeper) { hub.SubscribeParamChange( func(ctx sdk.Context, changes []interface{}) { for _, c := range changes { @@ -306,3 +435,655 @@ func (kp *GlobalKeeper) SubscribeParamChange(hub *paramhub.Keeper) { } }) } + +func (kp *DexKeeper) UpdateTickSizeAndLotSize(ctx sdk.Context) { + tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) + lotSizeCache := make(map[string]int64) // baseAsset -> lotSize + for _, pair := range tradingPairs { + if prices, ok := kp.recentPrices[pair.GetSymbol()]; ok && prices.Count() >= minimalNumPrices { + priceWMA := dexUtils.CalcPriceWMA(prices) + tickSize, lotSize := kp.determineTickAndLotSize(pair, priceWMA, lotSizeCache) + if tickSize != pair.TickSize.ToInt64() || + lotSize != pair.LotSize.ToInt64() { + ctx.Logger().Info("Updating tick/lotsize", + "pair", pair.GetSymbol(), "old_ticksize", pair.TickSize, "new_ticksize", tickSize, + "old_lotsize", pair.LotSize, "new_lotsize", lotSize) + pair.TickSize = utils.Fixed8(tickSize) + pair.LotSize = utils.Fixed8(lotSize) + kp.PairMapper.AddTradingPair(ctx, pair) + } + kp.UpdateLotSize(pair.GetSymbol(), lotSize) + } else { + // keep the current tick_size/lot_size + continue + } + } +} + +func (kp *DexKeeper) determineTickAndLotSize(pair dexTypes.TradingPair, priceWMA int64, lotSizeCache map[string]int64) (tickSize, lotSize int64) { + tickSize = dexUtils.CalcTickSize(priceWMA) + if !sdk.IsUpgrade(upgrade.LotSizeOptimization) { + lotSize = dexUtils.CalcLotSize(priceWMA) + return + } + if lotSize, cached := lotSizeCache[pair.BaseAssetSymbol]; cached { + return tickSize, lotSize + } + + lotSize = kp.DetermineLotSize(pair.BaseAssetSymbol, pair.QuoteAssetSymbol, priceWMA) + lotSizeCache[pair.BaseAssetSymbol] = lotSize + return +} + +func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) { + var priceAgainstNative int64 + if baseAssetSymbol == types.NativeTokenSymbol { + // price of BNB/BNB is 1e8 + priceAgainstNative = 1e8 + } else if quoteAssetSymbol == types.NativeTokenSymbol { + priceAgainstNative = price + } else { + if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { + priceAgainstNative = dexUtils.CalcPriceWMA(ps) + } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { + wma := dexUtils.CalcPriceWMA(ps) + priceAgainstNative = 1e16 / wma + } else { + // the recentPrices still have not collected any price yet, iff the native pair is listed for less than kp.pricesStoreEvery blocks + if engine, ok := kp.engines[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { + priceAgainstNative = engine.LastTradePrice + } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { + priceAgainstNative = 1e16 / engine.LastTradePrice + } else { + // should not happen + kp.logger.Error("DetermineLotSize failed because no native pair found", "base", baseAssetSymbol, "quote", quoteAssetSymbol) + } + } + } + lotSize = dexUtils.CalcLotSize(priceAgainstNative) + return lotSize +} + +func (kp *DexKeeper) UpdateLotSize(symbol string, lotSize int64) { + eng, ok := kp.engines[symbol] + if !ok { + panic(fmt.Sprintf("match engine of symbol %s doesn't exist", symbol)) + } + eng.LotSize = lotSize +} + +func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { + symbol = strings.ToUpper(symbol) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + return orderKeeper.removeOrder(kp, id, symbol, postCancelHandler) + } + } + return orderNotFound(symbol, id) +} + +func (kp *DexKeeper) GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) { + symbol = strings.ToUpper(symbol) + _, ok := kp.OrderExists(symbol, id) + if !ok { + return me.OrderPart{}, orderNotFound(symbol, id) + } + eng, ok := kp.engines[symbol] + if !ok { + return me.OrderPart{}, orderNotFound(symbol, id) + } + return eng.Book.GetOrder(id, side, price) +} + +func (kp *DexKeeper) OrderExists(symbol, id string) (OrderInfo, bool) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + return orderKeeper.orderExists(symbol, id) + } + } + return OrderInfo{}, false +} + +func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { + orderbook := make([]store.OrderBookLevel, maxLevels) + + i, j := 0, 0 + + if eng, ok := kp.engines[pair]; ok { + // TODO: check considered bucket splitting? + eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { + orderbook[i].BuyPrice = utils.Fixed8(p.Price) + orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) + i++ + }, + func(p *me.PriceLevel) { + orderbook[j].SellPrice = utils.Fixed8(p.Price) + orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) + j++ + }) + } + return orderbook +} + +func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(msg.Symbol) { + return orderKeeper.validateOrder(kp, context, account, msg) + } + } + return fmt.Errorf("symbol:%s is not supported", msg.Symbol) +} + +func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(pair) { + return orderKeeper.getOpenOrders(pair, addr) + } + } + return make([]store.OpenOrder, 0) +} + +func (kp *DexKeeper) GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap { + var res = make(ChangedPriceLevelsMap) + for pair, eng := range kp.engines { + buys := make(map[int64]int64) + sells := make(map[int64]int64) + res[pair] = ChangedPriceLevelsPerSymbol{buys, sells} + + // TODO: check considered bucket splitting? + eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { + buys[p.Price] = p.TotalLeavesQty() + }, func(p *me.PriceLevel) { + sells[p.Price] = p.TotalLeavesQty() + }) + } + + return res +} + +func (kp *DexKeeper) GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel { + if eng, ok := kp.engines[pair]; ok { + return eng.Book.GetPriceLevel(price, side) + } else { + return nil + } +} + +func (kp *DexKeeper) GetLastTrades(height int64, pair string) ([]me.Trade, int64) { + if eng, ok := kp.engines[pair]; ok { + if eng.LastMatchHeight == height { + return eng.Trades, eng.LastTradePrice + } + } + return nil, 0 +} + +// !!! FOR TEST USE ONLY +func (kp *DexKeeper) GetLastTradesForPair(pair string) ([]me.Trade, int64) { + if eng, ok := kp.engines[pair]; ok { + return eng.Trades, eng.LastTradePrice + } + return nil, 0 +} + +func (kp *DexKeeper) ClearOrderBook(pair string) { + if eng, ok := kp.engines[pair]; ok { + eng.Book.Clear() + } +} + +func (kp *DexKeeper) ClearOrderChanges() { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + orderKeeper.clearOrderChanges() + } + } +} + +func (kp *DexKeeper) StoreTradePrices(ctx sdk.Context) { + // TODO: check block height != 0 + if ctx.BlockHeight()%pricesStoreEvery == 0 { + lastTradePrices := make(map[string]int64, len(kp.engines)) + for symbol, engine := range kp.engines { + lastTradePrices[symbol] = engine.LastTradePrice + if _, ok := kp.recentPrices[symbol]; !ok { + kp.recentPrices[symbol] = utils.NewFixedSizedRing(numPricesStored) + } + kp.recentPrices[symbol].Push(engine.LastTradePrice) + } + if len(lastTradePrices) != 0 { + kp.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices) + } + } +} + +func (kp *DexKeeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { + allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) + } + } + size := len(allOrders) + if size == 0 { + kp.logger.Info("No orders to expire") + return nil + } + + // TODO: make effectiveDays configurable + const effectiveDays = 3 + expireHeight, err := kp.GetBreatheBlockHeight(ctx, blockTime, effectiveDays) + if err != nil { + // breathe block not found, that should only happens in in the first three days, just log it and ignore. + kp.logger.Info(err.Error()) + return nil + } + + channelSize := size >> kp.poolSize + concurrency := 1 << kp.poolSize + if size%concurrency != 0 { + channelSize += 1 + } + + transferChs := make([]chan Transfer, concurrency) + for i := range transferChs { + // TODO: channelSize is enough for buffer to facilitate ? + transferChs[i] = make(chan Transfer, channelSize*2) + } + + expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { + engine.Book.RemoveOrders(expireHeight, side, func(ord me.OrderPart) { + // gen transfer + if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { + h := channelHash(ordMsg.Sender, concurrency) + transferChs[h] <- TransferFromExpired(ord, *ordMsg) + // delete from allOrders + delete(orders, ord.Id) + } else { + kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) + } + }) + } + + symbolCh := make(chan string, concurrency) + utils.ConcurrentExecuteAsync(concurrency, + func() { + for symbol := range allOrders { + symbolCh <- symbol + } + close(symbolCh) + }, func() { + for symbol := range symbolCh { + engine := kp.engines[symbol] + orders := allOrders[symbol] + expire(orders, engine, me.BUYSIDE) + expire(orders, engine, me.SELLSIDE) + } + }, func() { + for _, transferCh := range transferChs { + close(transferCh) + } + }) + + return transferChs +} + +func (kp *DexKeeper) ExpireOrders( + ctx sdk.Context, + blockTime time.Time, + postAlloTransHandler TransferHandler, +) { + transferChs := kp.expireOrders(ctx, blockTime) + if transferChs == nil { + return + } + + totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAlloTransHandler) + fees.Pool.AddAndCommitFee("EXPIRE", totalFee) +} + +func (kp *DexKeeper) MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) { + key := utils.Int642Bytes(blockTime.Unix() / utils.SecondsPerDay) + store := ctx.KVStore(kp.storeKey) + bz, err := kp.cdc.MarshalBinaryBare(height) + if err != nil { + panic(err) + } + kp.logger.Debug(fmt.Sprintf("mark breathe block for key: %v (blockTime: %d), value: %v\n", key, blockTime.Unix(), bz)) + store.Set([]byte(key), bz) +} + +func (kp *DexKeeper) GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) { + store := ctx.KVStore(kp.storeKey) + t := timeNow.AddDate(0, 0, -daysBack).Unix() + day := t / utils.SecondsPerDay + bz := store.Get(utils.Int642Bytes(day)) + if bz == nil { + return 0, fmt.Errorf("breathe block not found for day %v", day) + } + + var height int64 + err := kp.cdc.UnmarshalBinaryBare(bz, &height) + if err != nil { + panic(err) + } + return height, nil +} + +func (kp *DexKeeper) GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 { + if blockInterval != 0 { + return (latestBlockHeight / int64(blockInterval)) * int64(blockInterval) + } else { + store := ctx.KVStore(kp.storeKey) + bz := []byte(nil) + for i := 0; i <= daysBack; i++ { + t := timeNow.AddDate(0, 0, -i).Unix() + key := utils.Int642Bytes(t / utils.SecondsPerDay) + bz = store.Get([]byte(key)) + if bz != nil { + kp.logger.Info("Located day to load breathe block height", "epochDay", key) + break + } + } + if bz == nil { + kp.logger.Error("Failed to load the latest breathe block height from", "timeNow", timeNow) + return 0 + } + var height int64 + err := kp.cdc.UnmarshalBinaryBare(bz, &height) + if err != nil { + panic(err) + } + kp.logger.Info("Loaded breathe block height", "height", height) + return height + } +} + +func orderNotFound(symbol, id string) error { + return fmt.Errorf("Failed to find order [%v] on symbol [%v]", id, symbol) +} + +func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportPairType(pairType) { + return orderKeeper.getOrderChanges() + } + } + kp.logger.Error("pairType is not supported %d", pairType) + return make(OrderChanges, 0) +} + +func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.appendOrderChange(change) + return + } + } + kp.logger.Error("symbol is not supported %d", symbol) +} + +func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.appendOrderChangeSync(change) + return + } + } + kp.logger.Error("symbol is not supported %d", symbol) +} + +func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportPairType(pairType) { + return orderKeeper.getOrderInfosForPub() + } + } + kp.logger.Error("pairType is not supported %d", pairType) + return make(OrderInfoForPublish) + +} + +func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { + return kp.PairMapper +} + +func (kp *DexKeeper) getAccountKeeper() *auth.AccountKeeper { + return &kp.am +} + +func (kp *DexKeeper) getLogger() tmlog.Logger { + return kp.logger +} + +func (kp *DexKeeper) getFeeManager() *FeeManager { + return kp.FeeManager +} + +func (kp *DexKeeper) ShouldPublishOrder() bool { + return kp.CollectOrderInfoForPublish +} + +func (kp *DexKeeper) GetEngines() map[string]*me.MatchEng { + return kp.engines +} +func appendAllOrdersMap(ms ...map[string]map[string]*OrderInfo) map[string]map[string]*OrderInfo { + res := make(map[string]map[string]*OrderInfo) + for _, m := range ms { + for k, v := range m { + res[k] = v + } + } + return res +} + +func (kp *DexKeeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { + // trading pair against native token should not be delisted if there is any other trading pair exist + baseAsset = strings.ToUpper(baseAsset) + quoteAsset = strings.ToUpper(quoteAsset) + + if baseAsset == quoteAsset { + return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") + } + + if !kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) { + return fmt.Errorf("trading pair %s_%s does not exist", baseAsset, quoteAsset) + } + + if baseAsset != types.NativeTokenSymbol && quoteAsset != types.NativeTokenSymbol { + return nil + } + + var symbolToCheck string + if baseAsset != types.NativeTokenSymbol { + symbolToCheck = baseAsset + } else { + symbolToCheck = quoteAsset + } + + tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) + for _, pair := range tradingPairs { //TODO + if (pair.BaseAssetSymbol == symbolToCheck && pair.QuoteAssetSymbol != types.NativeTokenSymbol) || + (pair.QuoteAssetSymbol == symbolToCheck && pair.BaseAssetSymbol != types.NativeTokenSymbol) { + return fmt.Errorf("trading pair %s_%s should not exist before delisting %s_%s", + pair.BaseAssetSymbol, pair.QuoteAssetSymbol, baseAsset, quoteAsset) + } + } + + return nil +} + +func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) { + _, ok := kp.engines[symbol] + if !ok { + kp.logger.Error("delist symbol does not exist", "symbol", symbol) + return + } + + transferChs := kp.expireAllOrders(ctx, symbol) + if transferChs != nil { + totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAllocTransHandler) + fees.Pool.AddAndCommitFee(fmt.Sprintf("DELIST_%s", symbol), totalFee) + } + + delete(kp.engines, symbol) + delete(kp.recentPrices, symbol) + + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + orderKeeper.deleteOrdersForPair(symbol) + break + } + } + + baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol) + err := kp.PairMapper.DeleteTradingPair(ctx, baseAsset, quoteAsset) + if err != nil { + kp.logger.Error("delete trading pair error", "err", err.Error()) + } +} + +func (kp *DexKeeper) expireAllOrders(ctx sdk.Context, symbol string) []chan Transfer { + ordersOfSymbol := make(map[string]*OrderInfo) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + ordersOfSymbol = orderKeeper.getAllOrdersForPair(symbol) + break + } + } + + orderNum := len(ordersOfSymbol) + if orderNum == 0 { + kp.logger.Info("no orders to expire", "symbol", symbol) + return nil + } + + concurrency := 1 << kp.poolSize + channelSize := orderNum / concurrency + + transferChs := make([]chan Transfer, concurrency) + for i := range transferChs { + transferChs[i] = make(chan Transfer, channelSize) + } + + expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { + _ = engine.Book.RemoveOrders(math.MaxInt64, side, func(ord me.OrderPart) { + // gen transfer + if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { + h := channelHash(ordMsg.Sender, concurrency) + transferChs[h] <- TransferFromExpired(ord, *ordMsg) + } else { + kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) + } + }) + } + + go func() { + engine := kp.engines[symbol] + orders := ordersOfSymbol + expire(orders, engine, me.BUYSIDE) + expire(orders, engine, me.SELLSIDE) + + for _, transferCh := range transferChs { + close(transferCh) + } + }() + + return transferChs +} + +func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { + // trading pair against native token should exist if quote token is not native token + baseAsset = strings.ToUpper(baseAsset) + quoteAsset = strings.ToUpper(quoteAsset) + + if baseAsset == quoteAsset { + return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") + } + + if kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) || kp.PairMapper.Exists(ctx, quoteAsset, baseAsset) { + return errors.New("trading pair exists") + } + + if baseAsset != types.NativeTokenSymbol && + quoteAsset != types.NativeTokenSymbol { + + if !kp.PairMapper.Exists(ctx, baseAsset, types.NativeTokenSymbol) && + !kp.PairMapper.Exists(ctx, types.NativeTokenSymbol, baseAsset) { + return fmt.Errorf("token %s should be listed against BNB before against %s", + baseAsset, quoteAsset) + } + + if !kp.PairMapper.Exists(ctx, quoteAsset, types.NativeTokenSymbol) && + !kp.PairMapper.Exists(ctx, types.NativeTokenSymbol, quoteAsset) { + return fmt.Errorf("token %s should be listed against BNB before listing %s against %s", + quoteAsset, baseAsset, quoteAsset) + } + } + + if isMiniSymbolPair(baseAsset, quoteAsset) && types.NativeTokenSymbol != quoteAsset { //todo permit BUSD + return errors.New("quote token is not valid for mini symbol pair: " + quoteAsset) + } + + return nil +} + +func (kp *DexKeeper) ClearAfterMatch() { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + orderKeeper.clearAfterMatch() + } + } +} + + +func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { + allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) + } + } + return allOrders +} + +func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo{ + ordersOfSymbol := make(map[string]*OrderInfo) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + ordersOfSymbol = orderKeeper.getAllOrdersForPair(symbol) + break + } + } + return ordersOfSymbol +} + +func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) + return + } + } +} + + +func isMiniSymbolPair(baseAsset, quoteAsset string) bool { + if sdk.IsUpgradeHeight(upgrade.BEP8) { + return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) + } + return false +} + +// channelHash() will choose a channel for processing by moding +// the sum of the last 7 bytes of address by bucketNumber. +// It may not be fully even. +// TODO: there is still concern on peroformance and evenness. +func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { + l := len(accAddress) + sum := 0 + for i := l - 7; i < l; i++ { + sum += int(accAddress[i]) + } + return sum % bucketNumber +} diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index 3bcb84375..34df24275 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/binance-chain/node/common/fees" common "github.com/binance-chain/node/common/types" @@ -25,15 +24,13 @@ type NewOrderResponse struct { } // NewHandler - returns a handler for dex type messages. -func NewHandler(cdc *wire.Codec, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, dexGlobalKeeper *GlobalKeeper, accKeeper auth.AccountKeeper) sdk.Handler { +func NewHandler(cdc *wire.Codec, dexKeeper *DexKeeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case NewOrderMsg: - orderKeeper, _ := selectKeeper(msg, dexKeeper, dexMiniKeeper) - return handleNewOrder(ctx, cdc, orderKeeper, msg) + return handleNewOrder(ctx, cdc, dexKeeper, msg) case CancelOrderMsg: - orderKeeper, _ := selectKeeper(msg, dexKeeper, dexMiniKeeper) - return handleCancelOrder(ctx, orderKeeper, dexGlobalKeeper, msg) + return handleCancelOrder(ctx, dexKeeper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -41,27 +38,7 @@ func NewHandler(cdc *wire.Codec, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, d } } -func selectKeeper(msg sdk.Msg, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper) (DexOrderKeeper, error) { - var orderKeeper DexOrderKeeper - var symbol string - switch v := msg.(type) { - case NewOrderMsg: - symbol = strings.ToUpper(v.Symbol) - case CancelOrderMsg: - symbol = strings.ToUpper(v.Symbol) - default: - err := fmt.Errorf("unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) - return nil, err - } - if (!sdk.IsUpgrade(upgrade.BEP8)) || !utils.IsMiniTokenTradingPair(symbol) { - orderKeeper = dexKeeper - } else { - orderKeeper = dexMiniKeeper - } - return orderKeeper, nil -} - -func validateQtyAndLockBalance(ctx sdk.Context, keeper DexOrderKeeper, acc common.NamedAccount, msg NewOrderMsg) error { +func validateQtyAndLockBalance(ctx sdk.Context, keeper *DexKeeper, acc common.NamedAccount, msg NewOrderMsg) error { symbol := strings.ToUpper(msg.Symbol) baseAssetSymbol, quoteAssetSymbol := utils.TradingPair2AssetsSafe(symbol) notional := utils.CalBigNotionalInt64(msg.Price, msg.Quantity) @@ -109,16 +86,16 @@ func validateQtyAndLockBalance(ctx sdk.Context, keeper DexOrderKeeper, acc commo } func handleNewOrder( - ctx sdk.Context, cdc *wire.Codec, keeper DexOrderKeeper, msg NewOrderMsg, + ctx sdk.Context, cdc *wire.Codec, dexKeeper *DexKeeper, msg NewOrderMsg, ) sdk.Result { // TODO: the below is mostly copied from FreezeToken. It should be rewritten once "locked" becomes a field on account // this check costs least. - if _, ok := keeper.OrderExists(msg.Symbol, msg.Id); ok { + if _, ok := dexKeeper.OrderExists(msg.Symbol, msg.Id); ok { errString := fmt.Sprintf("Duplicated order [%v] on symbol [%v]", msg.Id, msg.Symbol) return sdk.NewError(types.DefaultCodespace, types.CodeDuplicatedOrder, errString).Result() } - acc := keeper.getAccountKeeper().GetAccount(ctx, msg.Sender).(common.NamedAccount) + acc := dexKeeper.getAccountKeeper().GetAccount(ctx, msg.Sender).(common.NamedAccount) if !ctx.IsReCheckTx() { //for recheck: // 1. sequence is verified in anteHandler @@ -126,7 +103,7 @@ func handleNewOrder( // 3. trading pair is verified // 4. price/qty may have odd tick size/lot size, but it can be handled as // other existing orders. - err := keeper.validateOrder(ctx, acc, msg) + err := dexKeeper.ValidateOrder(ctx, acc, msg) if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeInvalidOrderParam, err.Error()).Result() @@ -134,7 +111,7 @@ func handleNewOrder( } // the following is done in the app's checkstate / deliverstate, so it's safe to ignore isCheckTx - err := validateQtyAndLockBalance(ctx, keeper, acc, msg) + err := validateQtyAndLockBalance(ctx, dexKeeper, acc, msg) if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeInvalidOrderParam, err.Error()).Result() } @@ -152,7 +129,7 @@ func handleNewOrder( if txSrc, ok := ctx.Value(baseapp.TxSourceKey).(int64); ok { txSource = txSrc } else { - keeper.getLogger().Error("cannot get txSource from ctx") + dexKeeper.getLogger().Error("cannot get txSource from ctx") } }) msg := OrderInfo{ @@ -161,7 +138,7 @@ func handleNewOrder( height, timestamp, 0, txHash, txSource} - err := keeper.AddOrder(msg, false) + err := dexKeeper.AddOrder(msg, false) if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeFailInsertOrder, err.Error()).Result() @@ -186,9 +163,9 @@ func handleNewOrder( // Handle CancelOffer - func handleCancelOrder( - ctx sdk.Context, keeper DexOrderKeeper, dexGlobalKeeper *GlobalKeeper, msg CancelOrderMsg, + ctx sdk.Context, dexKeeper *DexKeeper, msg CancelOrderMsg, ) sdk.Result { - origOrd, ok := keeper.OrderExists(msg.Symbol, msg.RefId) + origOrd, ok := dexKeeper.OrderExists(msg.Symbol, msg.RefId) //only check whether there exists order to cancel if !ok { @@ -202,21 +179,21 @@ func handleCancelOrder( return sdk.NewError(types.DefaultCodespace, types.CodeFailLocateOrderToCancel, errString).Result() } - ord, err := keeper.GetOrder(origOrd.Id, origOrd.Symbol, origOrd.Side, origOrd.Price) + ord, err := dexKeeper.GetOrder(origOrd.Id, origOrd.Symbol, origOrd.Side, origOrd.Price) if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeFailLocateOrderToCancel, err.Error()).Result() } transfer := TransferFromCanceled(ord, origOrd, false) - sdkError := dexGlobalKeeper.doTransfer(ctx, &transfer) + sdkError := dexKeeper.doTransfer(ctx, &transfer) if sdkError != nil { return sdkError.Result() } fee := common.Fee{} if !transfer.FeeFree() { - acc := keeper.getAccountKeeper().GetAccount(ctx, msg.Sender) - fee = keeper.getFeeManager().CalcFixedFee(acc.GetCoins(), transfer.eventType, transfer.inAsset, keeper.getEngines()) + acc := dexKeeper.getAccountKeeper().GetAccount(ctx, msg.Sender) + fee = dexKeeper.getFeeManager().CalcFixedFee(acc.GetCoins(), transfer.eventType, transfer.inAsset, dexKeeper.GetEngines()) acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - keeper.getAccountKeeper().SetAccount(ctx, acc) + dexKeeper.getAccountKeeper().SetAccount(ctx, acc) } // this is done in memory! we must not run this block in checktx or simulate! @@ -228,11 +205,11 @@ func handleCancelOrder( fees.Pool.AddFee(txHash, fee) } //remove order from cache and order book - err := keeper.RemoveOrder(origOrd.Id, origOrd.Symbol, func(ord me.OrderPart) { - if keeper.ShouldPublishOrder() { + err := dexKeeper.RemoveOrder(origOrd.Id, origOrd.Symbol, func(ord me.OrderPart) { + if dexKeeper.ShouldPublishOrder() { change := OrderChange{msg.RefId, Canceled, fee.String(), nil} - keeper.UpdateOrderChange(change) - dexGlobalKeeper.updateRoundOrderFee(string(msg.Sender), fee) + dexKeeper.UpdateOrderChangeSync(change, msg.Symbol) + dexKeeper.updateRoundOrderFee(string(msg.Sender), fee) } }) if err != nil { diff --git a/plugins/dex/order/handler_test.go b/plugins/dex/order/handler_test.go index 24364c50d..3b740020d 100644 --- a/plugins/dex/order/handler_test.go +++ b/plugins/dex/order/handler_test.go @@ -32,17 +32,16 @@ func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey, *sdk.K return ms, key, key2, key3 } -func setupMappers() (store.TradingPairMapper, auth.AccountKeeper, sdk.Context, DexOrderKeeper) { +func setupMappers() (store.TradingPairMapper, auth.AccountKeeper, sdk.Context, *DexKeeper) { ms, key, key2, key3 := setupMultiStore() var cdc = wire.NewCodec() auth.RegisterBaseAccount(cdc) cdc.RegisterConcrete(types.TradingPair{}, "dex/TradingPair", nil) - pairMapper := store.NewTradingPairMapper(cdc, key, false) + pairMapper := store.NewTradingPairMapper(cdc, key) accMapper := auth.NewAccountKeeper(cdc, key2, auth.ProtoBaseAccount) accountCache := getAccountCache(cdc, ms, key2) ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) - globalKeeper := NewGlobalKeeper(cdc, accMapper, false) - keeper := NewKeeper(key3, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, globalKeeper) + keeper := NewDexKeeper(key3, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc,accMapper, false, 2) return pairMapper, accMapper, ctx, keeper } @@ -80,13 +79,13 @@ func TestHandler_ValidateOrder_OrderNotExist(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.validateOrder(ctx, acc, msg) + err = keeper.ValidateOrder(ctx, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("trading pair not found: %s", msg.Symbol), err.Error()) } func TestHandler_ValidateOrder_WrongSymbol(t *testing.T) { - pairMapper, _, ctx, keeper := setupMappers() + _, _, ctx, keeper := setupMappers() msgs := []NewOrderMsg{ { @@ -107,7 +106,7 @@ func TestHandler_ValidateOrder_WrongSymbol(t *testing.T) { } for _, msg := range msgs { - err := keeper.validateOrder(ctx, pairMapper, nil, msg) + err := keeper.ValidateOrder(ctx, nil, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("Failed to parse trading pair symbol:%s into assets", msg.Symbol), err.Error()) } @@ -129,7 +128,7 @@ func TestHandler_ValidateOrder_WrongPrice(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.validateOrder(ctx, acc, msg) + err = keeper.ValidateOrder(ctx, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()), err.Error()) } @@ -150,7 +149,7 @@ func TestHandler_ValidateOrder_WrongQuantity(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.validateOrder(ctx, acc, msg) + err = keeper.ValidateOrder(ctx, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()), err.Error()) } @@ -170,7 +169,7 @@ func TestHandler_ValidateOrder_Normal(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.validateOrder(ctx, acc, msg) + err = keeper.ValidateOrder(ctx, acc, msg) require.NoError(t, err) } @@ -189,7 +188,7 @@ func TestHandler_ValidateOrder_MaxNotional(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.validateOrder(ctx, acc, msg) + err = keeper.ValidateOrder(ctx, acc, msg) require.Error(t, err) require.Equal(t, "notional value of the order is too large(cannot fit in int64)", err.Error()) } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 894613156..e27f512e0 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -3,23 +3,17 @@ package order import ( "errors" "fmt" - "math" - "strings" "sync" - "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" tmlog "github.com/tendermint/tendermint/libs/log" - "github.com/binance-chain/node/common/fees" bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/common/utils" me "github.com/binance-chain/node/plugins/dex/matcheng" "github.com/binance-chain/node/plugins/dex/store" - dexTypes "github.com/binance-chain/node/plugins/dex/types" dexUtils "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/wire" ) @@ -33,200 +27,75 @@ const ( type FeeHandler func(map[string]*types.Fee) type TransferHandler func(Transfer) -type DexOrderKeeper interface { - InitRecentPrices(ctx sdk.Context) - AddEngine(pair dexTypes.TradingPair) *me.MatchEng - UpdateTickSizeAndLotSize(ctx sdk.Context) - DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) - UpdateLotSize(symbol string, lotSize int64) - AddOrder(info OrderInfo, isRecovery bool) (err error) - RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) - GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) - OrderExists(symbol, id string) (OrderInfo, bool) - GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel - GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder - GetOrderBooks(maxLevels int) ChangedPriceLevelsMap - GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel - GetLastTrades(height int64, pair string) ([]me.Trade, int64) - GetLastTradesForPair(pair string) ([]me.Trade, int64) - ClearOrderBook(pair string) - ClearOrderChanges() - StoreTradePrices(ctx sdk.Context) - ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) - MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) - GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) - GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 - ClearOrders() - DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) - CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error - CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error - SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) - LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) - GetPairMapper() store.TradingPairMapper - GetOrderChanges() OrderChanges - GetOrderInfosForPub() OrderInfoForPublish - GetGlobalKeeper() *GlobalKeeper - getAccountKeeper() *auth.AccountKeeper - getLogger() tmlog.Logger - getFeeManager() *FeeManager - getEngines() map[string]*me.MatchEng - ShouldPublishOrder() bool - UpdateOrderChange(change OrderChange) - validateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error -} - -var _ DexOrderKeeper = &Keeper{} +type IDexOrderKeeper interface { + addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) + removeOrder(dexKeeper *DexKeeper, id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) + orderExists(symbol, id string) (OrderInfo, bool) + getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder + getAllOrders() map[string]map[string]*OrderInfo + deleteOrdersForPair(pair string) + clearOrderChanges() + getOrderChanges() OrderChanges + getOrderInfosForPub() OrderInfoForPublish + appendOrderChange(change OrderChange) + initOrders(symbol string) + support(pair string) bool + supportUpgradeVersion() bool + supportPairType(pairType SymbolPairType) bool + validateOrder(dexKeeper *DexKeeper, context sdk.Context, account sdk.Account, msg NewOrderMsg) error + iterateRoundPairs(func(string)) + iterateAllOrders(func(symbol string, id string)) + reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) + getRoundPairsNum() int + getRoundOrdersNum() int + getAllOrdersForPair(pair string) map[string]*OrderInfo + getRoundOrdersForPair(pair string) []string + getRoundIOCOrdersForPair(pair string) []string + clearAfterMatch() + selectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string + appendOrderChangeSync(change OrderChange) +} + +type BEP2OrderKeeper struct { + BaseOrderKeeper +} + +var _ IDexOrderKeeper = &BEP2OrderKeeper{} // in the future, this may be distributed via Sharding -type Keeper struct { - PairMapper store.TradingPairMapper - storeKey sdk.StoreKey // The key used to access the store from the Context. - codespace sdk.CodespaceType - engines map[string]*me.MatchEng - recentPrices map[string]*utils.FixedSizeRing // symbol -> latest "numPricesStored" prices per "pricesStoreEvery" blocks - allOrders map[string]map[string]*OrderInfo // symbol -> order ID -> order - OrderChangesMtx *sync.Mutex // guard OrderChanges and OrderInfosForPub during PreDevlierTx (which is async) - OrderChanges OrderChanges // order changed in this block, will be cleaned before matching for new block - OrderInfosForPub OrderInfoForPublish // for publication usage - roundOrders map[string][]string // limit to the total tx number in a block - roundIOCOrders map[string][]string - poolSize uint // number of concurrent channels, counted in the pow of 2 - cdc *wire.Codec - logger tmlog.Logger - symbolSelector SymbolSelector - GlobalKeeper *GlobalKeeper -} - -func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { - return me.NewMatchEng(pairSymbol, basePrice, lotSize, 0.05) -} - -// NewKeeper - Returns the Keeper -func NewKeeper(key sdk.StoreKey, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, - concurrency uint, cdc *wire.Codec, globalKeeper *GlobalKeeper) *Keeper { - logger := bnclog.With("module", "dexkeeper") - return &Keeper{ - PairMapper: tradingPairMapper, - storeKey: key, - codespace: codespace, - engines: make(map[string]*me.MatchEng), - recentPrices: make(map[string]*utils.FixedSizeRing, 256), - allOrders: make(map[string]map[string]*OrderInfo, 256), // need to init the nested map when a new symbol added. - OrderChangesMtx: &sync.Mutex{}, - OrderChanges: make(OrderChanges, 0), - OrderInfosForPub: make(OrderInfoForPublish), - roundOrders: make(map[string][]string, 256), - roundIOCOrders: make(map[string][]string, 256), - poolSize: concurrency, - cdc: cdc, - logger: logger, - symbolSelector: &BEP2SymbolSelector{}, - GlobalKeeper: globalKeeper, - } -} - -func (kp *Keeper) InitRecentPrices(ctx sdk.Context) { - kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) -} - -func (kp *Keeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { - symbol := strings.ToUpper(pair.GetSymbol()) - eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) - kp.engines[symbol] = eng - kp.allOrders[symbol] = map[string]*OrderInfo{} - return eng -} - -func (kp *Keeper) UpdateTickSizeAndLotSize(ctx sdk.Context) { - tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) - lotSizeCache := make(map[string]int64) // baseAsset -> lotSize - for _, pair := range tradingPairs { - if prices, ok := kp.recentPrices[pair.GetSymbol()]; ok && prices.Count() >= minimalNumPrices { - priceWMA := dexUtils.CalcPriceWMA(prices) - tickSize, lotSize := kp.determineTickAndLotSize(pair, priceWMA, lotSizeCache) - if tickSize != pair.TickSize.ToInt64() || - lotSize != pair.LotSize.ToInt64() { - ctx.Logger().Info("Updating tick/lotsize", - "pair", pair.GetSymbol(), "old_ticksize", pair.TickSize, "new_ticksize", tickSize, - "old_lotsize", pair.LotSize, "new_lotsize", lotSize) - pair.TickSize = utils.Fixed8(tickSize) - pair.LotSize = utils.Fixed8(lotSize) - kp.PairMapper.AddTradingPair(ctx, pair) - } - kp.UpdateLotSize(pair.GetSymbol(), lotSize) - } else { - // keep the current tick_size/lot_size - continue - } - } -} - -func (kp *Keeper) determineTickAndLotSize(pair dexTypes.TradingPair, priceWMA int64, lotSizeCache map[string]int64) (tickSize, lotSize int64) { - tickSize = dexUtils.CalcTickSize(priceWMA) - if !sdk.IsUpgrade(upgrade.LotSizeOptimization) { - lotSize = dexUtils.CalcLotSize(priceWMA) - return - } - if lotSize, cached := lotSizeCache[pair.BaseAssetSymbol]; cached { - return tickSize, lotSize - } - - lotSize = kp.DetermineLotSize(pair.BaseAssetSymbol, pair.QuoteAssetSymbol, priceWMA) - lotSizeCache[pair.BaseAssetSymbol] = lotSize - return -} - -func (kp *Keeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) { - var priceAgainstNative int64 - if baseAssetSymbol == types.NativeTokenSymbol { - // price of BNB/BNB is 1e8 - priceAgainstNative = 1e8 - } else if quoteAssetSymbol == types.NativeTokenSymbol { - priceAgainstNative = price - } else { - if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { - priceAgainstNative = dexUtils.CalcPriceWMA(ps) - } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { - wma := dexUtils.CalcPriceWMA(ps) - priceAgainstNative = 1e16 / wma - } else { - // the recentPrices still have not collected any price yet, iff the native pair is listed for less than kp.pricesStoreEvery blocks - if engine, ok := kp.engines[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { - priceAgainstNative = engine.LastTradePrice - } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { - priceAgainstNative = 1e16 / engine.LastTradePrice - } else { - // should not happen - kp.logger.Error("DetermineLotSize failed because no native pair found", "base", baseAssetSymbol, "quote", quoteAssetSymbol) - } - } - } - lotSize = dexUtils.CalcLotSize(priceAgainstNative) - return lotSize -} - -func (kp *Keeper) UpdateLotSize(symbol string, lotSize int64) { - eng, ok := kp.engines[symbol] - if !ok { - panic(fmt.Sprintf("match engine of symbol %s doesn't exist", symbol)) +type BaseOrderKeeper struct { + allOrders map[string]map[string]*OrderInfo // symbol -> order ID -> order + OrderChangesMtx *sync.Mutex // guard OrderChanges and OrderInfosForPub during PreDevlierTx (which is async) + OrderChanges OrderChanges // order changed in this block, will be cleaned before matching for new block + OrderInfosForPub OrderInfoForPublish // for publication usage + roundOrders map[string][]string // limit to the total tx number in a block + roundIOCOrders map[string][]string + poolSize uint // number of concurrent channels, counted in the pow of 2 + cdc *wire.Codec + logger tmlog.Logger + symbolSelector SymbolSelector +} + +// NewBEP2OrderKeeper - Returns the BEP2OrderKeeper +func NewBEP2OrderKeeper() IDexOrderKeeper { + logger := bnclog.With("module", "Bep2OrderKeeper") + return &BEP2OrderKeeper{ + BaseOrderKeeper{ + allOrders: make(map[string]map[string]*OrderInfo, 256), + // need to init the nested map when a new symbol added. + OrderChangesMtx: &sync.Mutex{}, + OrderChanges: make(OrderChanges, 0), + OrderInfosForPub: make(OrderInfoForPublish), + roundOrders: make(map[string][]string, 256), + roundIOCOrders: make(map[string][]string, 256), + logger: logger, + symbolSelector: &BEP2SymbolSelector{}, + }, } - eng.LotSize = lotSize } -func (kp *Keeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { - //try update order book first - symbol := strings.ToUpper(info.Symbol) - eng, ok := kp.engines[symbol] - if !ok { - err = fmt.Errorf("match engine of symbol %s doesn't exist", symbol) - return - } - - _, err = eng.Book.InsertOrder(info.Id, info.Side, info.CreatedHeight, info.Price, info.Quantity) - if err != nil { - return err - } +func (kp *BaseOrderKeeper) addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) { - if kp.GlobalKeeper.CollectOrderInfoForPublish { + if collectOrderInfoForPublish { change := OrderChange{info.Id, Ack, "", nil} // deliberately not add this message to orderChanges if !isRecovery { @@ -238,12 +107,9 @@ func (kp *Keeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { kp.allOrders[symbol][info.Id] = &info kp.addRoundOrders(symbol, info) - - kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) - return nil } -func (kp *Keeper) addRoundOrders(symbol string, info OrderInfo) { +func (kp *BaseOrderKeeper) addRoundOrders(symbol string, info OrderInfo) { if ids, ok := kp.roundOrders[symbol]; ok { kp.roundOrders[symbol] = append(ids, info.Id) } else { @@ -255,17 +121,22 @@ func (kp *Keeper) addRoundOrders(symbol string, info OrderInfo) { } } -func orderNotFound(symbol, id string) error { - return fmt.Errorf("Failed to find order [%v] on symbol [%v]", id, symbol) +func (kp *BaseOrderKeeper) orderExists(symbol, id string) (OrderInfo, bool) { + if orders, ok := kp.allOrders[symbol]; ok { + if msg, ok := orders[id]; ok { + return *msg, ok + } + } + return OrderInfo{}, false } -func (kp *Keeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { - symbol = strings.ToUpper(symbol) - ordMsg, ok := kp.OrderExists(symbol, id) +func (kp *BaseOrderKeeper) removeOrder(dexKeeper *DexKeeper, id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { + + ordMsg, ok := kp.orderExists(symbol, id) if !ok { return orderNotFound(symbol, id) } - eng, ok := kp.engines[symbol] + eng, ok := dexKeeper.engines[symbol] if !ok { return orderNotFound(symbol, id) } @@ -281,70 +152,49 @@ func (kp *Keeper) RemoveOrder(id string, symbol string, postCancelHandler func(o return nil } -func (kp *Keeper) GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) { - symbol = strings.ToUpper(symbol) - _, ok := kp.OrderExists(symbol, id) - if !ok { - return me.OrderPart{}, orderNotFound(symbol, id) - } - eng, ok := kp.engines[symbol] - if !ok { - return me.OrderPart{}, orderNotFound(symbol, id) - } - return eng.Book.GetOrder(id, side, price) +func (kp *BaseOrderKeeper) deleteOrdersForPair(pair string) { + delete(kp.allOrders, pair) } -func (kp *Keeper) OrderExists(symbol, id string) (OrderInfo, bool) { - if orders, ok := kp.allOrders[symbol]; ok { - if msg, ok := orders[id]; ok { - return *msg, ok - } +func (kp *BaseOrderKeeper) validateOrder(dexKeeper *DexKeeper, ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { + baseAsset, quoteAsset, err := dexUtils.TradingPair2Assets(msg.Symbol) + if err != nil { + return err } - return OrderInfo{}, false -} -// channelHash() will choose a channel for processing by moding -// the sum of the last 7 bytes of address by bucketNumber. -// It may not be fully even. -// TODO: there is still concern on peroformance and evenness. -func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { - l := len(accAddress) - sum := 0 - for i := l - 7; i < l; i++ { - sum += int(accAddress[i]) + seq := acc.GetSequence() + expectedID := GenerateOrderID(seq, msg.Sender) + if expectedID != msg.Id { + return fmt.Errorf("the order ID(%s) given did not match the expected one: `%s`", msg.Id, expectedID) } - return sum % bucketNumber -} -// Run as postConsume procedure of async, no concurrent updates of orders map -func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { - order.CumQty = cumQty - order.LastUpdatedHeight = height - order.LastUpdatedTimestamp = timestamp -} + pair, err := dexKeeper.PairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) + if err != nil { + return err + } + + if msg.Quantity <= 0 || msg.Quantity%pair.LotSize.ToInt64() != 0 { + return fmt.Errorf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()) + } -func (kp *Keeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { - orderbook := make([]store.OrderBookLevel, maxLevels) + if msg.Price <= 0 || msg.Price%pair.TickSize.ToInt64() != 0 { + return fmt.Errorf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()) + } - i, j := 0, 0 + if sdk.IsUpgrade(upgrade.LotSizeOptimization) { + if dexUtils.IsUnderMinNotional(msg.Price, msg.Quantity) { + return errors.New("notional value of the order is too small") + } + } - if eng, ok := kp.engines[pair]; ok { - // TODO: check considered bucket splitting? - eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { - orderbook[i].BuyPrice = utils.Fixed8(p.Price) - orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) - i++ - }, - func(p *me.PriceLevel) { - orderbook[j].SellPrice = utils.Fixed8(p.Price) - orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) - j++ - }) + if dexUtils.IsExceedMaxNotional(msg.Price, msg.Quantity) { + return errors.New("notional value of the order is too large(cannot fit in int64)") } - return orderbook + + return nil } -func (kp *Keeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { +func (kp *BaseOrderKeeper) getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { openOrders := make([]store.OpenOrder, 0) for _, order := range kp.allOrders[pair] { @@ -368,428 +218,112 @@ func (kp *Keeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOr return openOrders } -func (kp *Keeper) GetOrderBooks(maxLevels int) ChangedPriceLevelsMap { - var res = make(ChangedPriceLevelsMap) - for pair, eng := range kp.engines { - buys := make(map[int64]int64) - sells := make(map[int64]int64) - res[pair] = ChangedPriceLevelsPerSymbol{buys, sells} - - // TODO: check considered bucket splitting? - eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { - buys[p.Price] = p.TotalLeavesQty() - }, func(p *me.PriceLevel) { - sells[p.Price] = p.TotalLeavesQty() - }) - } - - return res +func (kp *BaseOrderKeeper) clearOrderChanges() { + kp.OrderChanges = kp.OrderChanges[:0] } -func (kp *Keeper) GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel { - if eng, ok := kp.engines[pair]; ok { - return eng.Book.GetPriceLevel(price, side) - } else { - return nil - } +func (kp *BaseOrderKeeper) getAllOrders() map[string]map[string]*OrderInfo { + return kp.allOrders } -func (kp *Keeper) GetLastTrades(height int64, pair string) ([]me.Trade, int64) { - if eng, ok := kp.engines[pair]; ok { - if eng.LastMatchHeight == height { - return eng.Trades, eng.LastTradePrice - } - } - return nil, 0 +func (kp *BaseOrderKeeper) getOrderChanges() OrderChanges { + return kp.OrderChanges } -// !!! FOR TEST USE ONLY -func (kp *Keeper) GetLastTradesForPair(pair string) ([]me.Trade, int64) { - if eng, ok := kp.engines[pair]; ok { - return eng.Trades, eng.LastTradePrice - } - return nil, 0 +func (kp *BaseOrderKeeper) getOrderInfosForPub() OrderInfoForPublish { + return kp.OrderInfosForPub } -func (kp *Keeper) ClearOrderBook(pair string) { - if eng, ok := kp.engines[pair]; ok { - eng.Book.Clear() - } +func (kp *BaseOrderKeeper) appendOrderChange(change OrderChange) { + kp.OrderChanges = append(kp.OrderChanges, change) } -func (kp *Keeper) ClearOrderChanges() { - kp.OrderChanges = kp.OrderChanges[:0] +func (kp *BaseOrderKeeper) getRoundOrdersForPair(pair string) []string { + return kp.roundOrders[pair] } -func (kp *Keeper) StoreTradePrices(ctx sdk.Context) { - // TODO: check block height != 0 - if ctx.BlockHeight()%pricesStoreEvery == 0 { - lastTradePrices := make(map[string]int64, len(kp.engines)) - for symbol, engine := range kp.engines { - lastTradePrices[symbol] = engine.LastTradePrice - if _, ok := kp.recentPrices[symbol]; !ok { - kp.recentPrices[symbol] = utils.NewFixedSizedRing(numPricesStored) - } - kp.recentPrices[symbol].Push(engine.LastTradePrice) - } - if len(lastTradePrices) != 0 { - kp.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices) - } - } +func (kp *BaseOrderKeeper) getRoundIOCOrdersForPair(pair string) []string { + return kp.roundIOCOrders[pair] } +func (kp *BaseOrderKeeper) getAllOrdersForPair(pair string) map[string]*OrderInfo { + return kp.allOrders[pair] +} -func (kp *Keeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { - size := len(kp.allOrders) - if size == 0 { - kp.logger.Info("No orders to expire") - return nil - } - - // TODO: make effectiveDays configurable - const effectiveDays = 3 - expireHeight, err := kp.GetBreatheBlockHeight(ctx, blockTime, effectiveDays) - if err != nil { - // breathe block not found, that should only happens in in the first three days, just log it and ignore. - kp.logger.Info(err.Error()) - return nil - } - - channelSize := size >> kp.poolSize - concurrency := 1 << kp.poolSize - if size%concurrency != 0 { - channelSize += 1 - } +func (kp *BaseOrderKeeper) selectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string { + return kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, timestamp, matchAllSymbols) +} - transferChs := make([]chan Transfer, concurrency) - for i := range transferChs { - // TODO: channelSize is enough for buffer to facilitate ? - transferChs[i] = make(chan Transfer, channelSize*2) - } +func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { + kp.OrderChangesMtx.Lock() + kp.OrderChanges = append(kp.OrderChanges, change) + kp.OrderChangesMtx.Unlock() +} - expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { - engine.Book.RemoveOrders(expireHeight, side, func(ord me.OrderPart) { - // gen transfer - if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { - h := channelHash(ordMsg.Sender, concurrency) - transferChs[h] <- TransferFromExpired(ord, *ordMsg) - // delete from allOrders - delete(orders, ord.Id) - } else { - kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) - } - }) +func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { + //TODO + for symbol, orders := range kp.allOrders { + for orderId := range orders{ + iter(symbol,orderId) + } } - - symbolCh := make(chan string, concurrency) - utils.ConcurrentExecuteAsync(concurrency, - func() { - for symbol := range kp.allOrders { - symbolCh <- symbol - } - close(symbolCh) - }, func() { - for symbol := range symbolCh { - engine := kp.engines[symbol] - orders := kp.allOrders[symbol] - expire(orders, engine, me.BUYSIDE) - expire(orders, engine, me.SELLSIDE) - } - }, func() { - for _, transferCh := range transferChs { - close(transferCh) - } - }) - - return transferChs } -func (kp *Keeper) ExpireOrders( - ctx sdk.Context, - blockTime time.Time, - postAlloTransHandler TransferHandler, -) { - transferChs := kp.expireOrders(ctx, blockTime) - if transferChs == nil { - return - } +//------ BEP2OrderKeeper methods ----- - totalFee := kp.GlobalKeeper.allocateAndCalcFee(ctx, transferChs, postAlloTransHandler, kp.engines) - fees.Pool.AddAndCommitFee("EXPIRE", totalFee) +func (kp *BEP2OrderKeeper) support(pair string) bool { + return !dexUtils.IsMiniTokenTradingPair(pair) } -func (kp *Keeper) MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) { - key := utils.Int642Bytes(blockTime.Unix() / utils.SecondsPerDay) - store := ctx.KVStore(kp.storeKey) - bz, err := kp.cdc.MarshalBinaryBare(height) - if err != nil { - panic(err) - } - kp.logger.Debug(fmt.Sprintf("mark breathe block for key: %v (blockTime: %d), value: %v\n", key, blockTime.Unix(), bz)) - store.Set([]byte(key), bz) +func (kp *BEP2OrderKeeper) supportUpgradeVersion() bool { + return true } -func (kp *Keeper) GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) { - store := ctx.KVStore(kp.storeKey) - t := timeNow.AddDate(0, 0, -daysBack).Unix() - day := t / utils.SecondsPerDay - bz := store.Get(utils.Int642Bytes(day)) - if bz == nil { - return 0, fmt.Errorf("breathe block not found for day %v", day) - } - - var height int64 - err := kp.cdc.UnmarshalBinaryBare(bz, &height) - if err != nil { - panic(err) - } - return height, nil +func (kp *BEP2OrderKeeper) supportPairType(pairType SymbolPairType) bool { + return PairType.BEP2 == pairType } -func (kp *Keeper) GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 { - if blockInterval != 0 { - return (latestBlockHeight / int64(blockInterval)) * int64(blockInterval) - } else { - store := ctx.KVStore(kp.storeKey) - bz := []byte(nil) - for i := 0; i <= daysBack; i++ { - t := timeNow.AddDate(0, 0, -i).Unix() - key := utils.Int642Bytes(t / utils.SecondsPerDay) - bz = store.Get([]byte(key)) - if bz != nil { - kp.logger.Info("Located day to load breathe block height", "epochDay", key) - break - } - } - if bz == nil { - kp.logger.Error("Failed to load the latest breathe block height from", "timeNow", timeNow) - return 0 - } - var height int64 - err := kp.cdc.UnmarshalBinaryBare(bz, &height) - if err != nil { - panic(err) - } - kp.logger.Info("Loaded breathe block height", "height", height) - return height - } +func (kp *BEP2OrderKeeper) initOrders(symbol string) { + kp.allOrders[symbol] = map[string]*OrderInfo{} } -// used by state sync to clear memory order book after we synced latest breathe block -func (kp *Keeper) ClearOrders() { - kp.engines = make(map[string]*me.MatchEng) - kp.allOrders = make(map[string]map[string]*OrderInfo, 256) +func (kp *BEP2OrderKeeper) clearAfterMatch() { + kp.logger.Debug("clearAfterMatchBEP2...") kp.roundOrders = make(map[string][]string, 256) kp.roundIOCOrders = make(map[string][]string, 256) - kp.OrderInfosForPub = make(OrderInfoForPublish) } -func (kp *Keeper) DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) { - _, ok := kp.engines[symbol] - if !ok { - kp.logger.Error("delist symbol does not exist", "symbol", symbol) - return - } - - transferChs := kp.expireAllOrders(ctx, symbol) - if transferChs != nil { - totalFee := kp.GlobalKeeper.allocateAndCalcFee(ctx, transferChs, postAllocTransHandler, kp.engines) - fees.Pool.AddAndCommitFee(fmt.Sprintf("DELIST_%s", symbol), totalFee) - } - - delete(kp.engines, symbol) - delete(kp.allOrders, symbol) - delete(kp.recentPrices, symbol) - - baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol) - err := kp.PairMapper.DeleteTradingPair(ctx, baseAsset, quoteAsset) - if err != nil { - kp.logger.Error("delete trading pair error", "err", err.Error()) +func (kp *BEP2OrderKeeper) iterateRoundPairs(iter func(string)) { + for symbol := range kp.roundOrders { + iter(symbol) } } -func (kp *Keeper) expireAllOrders(ctx sdk.Context, symbol string) []chan Transfer { - orderNum := len(kp.allOrders[symbol]) - if orderNum == 0 { - kp.logger.Info("no orders to expire", "symbol", symbol) - return nil - } - - concurrency := 1 << kp.poolSize - channelSize := orderNum / concurrency - - transferChs := make([]chan Transfer, concurrency) - for i := range transferChs { - transferChs[i] = make(chan Transfer, channelSize) - } - - expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { - _ = engine.Book.RemoveOrders(math.MaxInt64, side, func(ord me.OrderPart) { - // gen transfer - if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { - h := channelHash(ordMsg.Sender, concurrency) - transferChs[h] <- TransferFromExpired(ord, *ordMsg) - } else { - kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) - } - }) - } - - go func() { - engine := kp.engines[symbol] - orders := kp.allOrders[symbol] - expire(orders, engine, me.BUYSIDE) - expire(orders, engine, me.SELLSIDE) - - for _, transferCh := range transferChs { - close(transferCh) - } - }() - - return transferChs -} - -func (kp *Keeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { - // trading pair against native token should exist if quote token is not native token - baseAsset = strings.ToUpper(baseAsset) - quoteAsset = strings.ToUpper(quoteAsset) - - if baseAsset == quoteAsset { - return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") - } - - if kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) || kp.PairMapper.Exists(ctx, quoteAsset, baseAsset) { - return errors.New("trading pair exists") - } - - if baseAsset != types.NativeTokenSymbol && - quoteAsset != types.NativeTokenSymbol { - - if !kp.PairMapper.Exists(ctx, baseAsset, types.NativeTokenSymbol) && - !kp.PairMapper.Exists(ctx, types.NativeTokenSymbol, baseAsset) { - return fmt.Errorf("token %s should be listed against BNB before against %s", - baseAsset, quoteAsset) - } - - if !kp.PairMapper.Exists(ctx, quoteAsset, types.NativeTokenSymbol) && - !kp.PairMapper.Exists(ctx, types.NativeTokenSymbol, quoteAsset) { - return fmt.Errorf("token %s should be listed against BNB before listing %s against %s", - quoteAsset, baseAsset, quoteAsset) +func (kp *BEP2OrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) { + kp.allOrders[symbol][orderInfo.Id] = orderInfo + if orderInfo.CreatedHeight == height { + kp.roundOrders[symbol] = append(kp.roundOrders[symbol], orderInfo.Id) + if orderInfo.TimeInForce == TimeInForce.IOC { + kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], orderInfo.Id) } } - return nil -} - -func (kp *Keeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { - // trading pair against native token should not be delisted if there is any other trading pair exist - baseAsset = strings.ToUpper(baseAsset) - quoteAsset = strings.ToUpper(quoteAsset) - - if baseAsset == quoteAsset { - return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") - } - - if !kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) { - return fmt.Errorf("trading pair %s_%s does not exist", baseAsset, quoteAsset) - } - - if baseAsset != types.NativeTokenSymbol && quoteAsset != types.NativeTokenSymbol { - return nil - } - - var symbolToCheck string - if baseAsset != types.NativeTokenSymbol { - symbolToCheck = baseAsset - } else { - symbolToCheck = quoteAsset - } - - tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) - for _, pair := range tradingPairs { //TODO - if (pair.BaseAssetSymbol == symbolToCheck && pair.QuoteAssetSymbol != types.NativeTokenSymbol) || - (pair.QuoteAssetSymbol == symbolToCheck && pair.BaseAssetSymbol != types.NativeTokenSymbol) { - return fmt.Errorf("trading pair %s_%s should not exist before delisting %s_%s", - pair.BaseAssetSymbol, pair.QuoteAssetSymbol, baseAsset, quoteAsset) + if collectOrderInfoForPublish { + if _, exists := kp.OrderInfosForPub[orderInfo.Id]; !exists { + bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) + kp.OrderInfosForPub[orderInfo.Id] = orderInfo } } - - return nil -} - -func (kp *Keeper) GetPairMapper() store.TradingPairMapper { - return kp.PairMapper -} - -func (kp *Keeper) GetOrderChanges() OrderChanges { - return kp.OrderChanges -} - -func (kp *Keeper) GetOrderInfosForPub() OrderInfoForPublish { - return kp.OrderInfosForPub -} - -func (kp *Keeper) getAccountKeeper() *auth.AccountKeeper { - return &kp.GlobalKeeper.am -} - -func (kp *Keeper) getLogger() tmlog.Logger { - return kp.logger } -func (kp *Keeper) getFeeManager() *FeeManager { - return kp.GlobalKeeper.FeeManager +func (kp *BEP2OrderKeeper) getRoundPairsNum() int { + return len(kp.roundOrders) } -func (kp *Keeper) ShouldPublishOrder() bool { - return kp.GlobalKeeper.CollectOrderInfoForPublish -} - -func (kp *Keeper) getEngines() map[string]*me.MatchEng { - return kp.engines -} - -func (kp *Keeper) UpdateOrderChange(change OrderChange) { - kp.OrderChanges = append(kp.OrderChanges, change) -} - -func (kp *Keeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { - baseAsset, quoteAsset, err := dexUtils.TradingPair2Assets(msg.Symbol) - if err != nil { - return err +func (kp *BEP2OrderKeeper) getRoundOrdersNum() int { + n := 0 + for _, orders := range kp.roundOrders { + n += len(orders) } - - seq := acc.GetSequence() - expectedID := GenerateOrderID(seq, msg.Sender) - if expectedID != msg.Id { - return fmt.Errorf("the order ID(%s) given did not match the expected one: `%s`", msg.Id, expectedID) - } - - pair, err := kp.PairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) - if err != nil { - return err - } - - if msg.Quantity <= 0 || msg.Quantity%pair.LotSize.ToInt64() != 0 { - return fmt.Errorf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()) - } - - if msg.Price <= 0 || msg.Price%pair.TickSize.ToInt64() != 0 { - return fmt.Errorf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()) - } - - if sdk.IsUpgrade(upgrade.LotSizeOptimization) { - if dexUtils.IsUnderMinNotional(msg.Price, msg.Quantity) { - return errors.New("notional value of the order is too small") - } - } - - if dexUtils.IsExceedMaxNotional(msg.Price, msg.Quantity) { - return errors.New("notional value of the order is too large(cannot fit in int64)") - } - - return nil + return n } -func (kp *Keeper) GetGlobalKeeper() *GlobalKeeper { - return kp.GlobalKeeper -} diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 3bfc6e42c..cd272713f 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -1,99 +1,82 @@ package order import ( - "github.com/binance-chain/node/plugins/dex/matcheng" sdk "github.com/cosmos/cosmos-sdk/types" - tmlog "github.com/tendermint/tendermint/libs/log" - "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/utils" dexUtils "github.com/binance-chain/node/plugins/dex/utils" ) -func MatchAndAllocateSymbols(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool, logger tmlog.Logger) { - logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height, "symbolNum", len(dexKeeper.roundOrders)) - timestamp := ctx.BlockHeader().Time.UnixNano() - - symbolsToMatch := dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols) - symbolsToMatch = append(symbolsToMatch, dexMiniKeeper.symbolSelector.SelectSymbolsToMatch(dexMiniKeeper.roundOrders, ctx.BlockHeader().Height, timestamp, matchAllSymbols)...) - logger.Info("symbols to match", "symbols", symbolsToMatch) //todo debug - - tradeOuts := matchAndDistributeTrades(dexKeeper, dexMiniKeeper, true, ctx.BlockHeader().Height, timestamp, symbolsToMatch, logger) - if tradeOuts == nil { - logger.Info("No order comes in for the block") - } - globalKeeper := dexKeeper.GlobalKeeper - totalFee := globalKeeper.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler, mergeMatchEngineMap(dexKeeper.engines, dexMiniKeeper.engines)) - fees.Pool.AddAndCommitFee("MATCH", totalFee) - clearAfterMatchBEP2(dexKeeper) - clearAfterMatchMini(dexMiniKeeper) -} -func mergeMatchEngineMap(ms ...map[string]*matcheng.MatchEng) map[string]*matcheng.MatchEng { - res := make(map[string]*matcheng.MatchEng) - for _, m := range ms { - for k, v := range m { - res[k] = v +func (kp *DexKeeper) SelectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string { + symbolsToMatch := make([]string, 0, 256) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + symbolsToMatch = append(symbolsToMatch, orderKeeper.selectSymbolsToMatch(height, timestamp, matchAllSymbols)...) } } - return res + return symbolsToMatch } -func clearAfterMatchBEP2(kp *Keeper) { - kp.logger.Debug("clearAfterMatchBEP2...") - kp.roundOrders = make(map[string][]string, 256) - kp.roundIOCOrders = make(map[string][]string, 256) -} -func clearAfterMatchMini(kp *MiniKeeper) { - kp.logger.Debug("clearAfterMatchMini...") - for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { - delete(kp.roundOrders, symbol) - delete(kp.roundIOCOrders, symbol) +func (kp *DexKeeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { + kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height) + timestamp := ctx.BlockHeader().Time.UnixNano() + + symbolsToMatch := kp.SelectSymbolsToMatch(ctx.BlockHeader().Height, timestamp, matchAllSymbols) + kp.logger.Info("symbols to match", "symbols", symbolsToMatch) + var tradeOuts []chan Transfer + if len(symbolsToMatch) == 0 { + kp.logger.Info("No order comes in for the block") + }else{ + tradeOuts = kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp) } - emptyRoundMatchSymbols := make([]string, 0, 256) - kp.symbolSelector.SetRoundMatchSymbol(emptyRoundMatchSymbols) + + totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) + fees.Pool.AddAndCommitFee("MATCH", totalFee) + kp.ClearAfterMatch() } +type symbolKeeper struct { + symbol string + orderKeeper IDexOrderKeeper +} // please note if distributeTrade this method will work in async mode, otherwise in sync mode. -func matchAndDistributeTrades(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, distributeTrade bool, height, timestamp int64, symbolsToMatch []string, logger tmlog.Logger) []chan Transfer { - if len(symbolsToMatch) == 0 { - logger.Info("No symbols to match in the block") - return nil - } - concurrency := 1 << dexUtils.MaxOf(dexKeeper.poolSize, dexMiniKeeper.poolSize) +// Always run kp.SelectSymbolsToMatch(ctx.BlockHeader().Height, timestamp, matchAllSymbols) before matchAndDistributeTrades +func (kp *DexKeeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64) []chan Transfer { + + concurrency := 1 << kp.poolSize tradeOuts := make([]chan Transfer, concurrency) if distributeTrade { ordNum := 0 - for _, symbol := range symbolsToMatch { - if dexUtils.IsMiniTokenTradingPair(symbol) { - ordNum += len(dexMiniKeeper.roundOrders[symbol]) - } else { - ordNum += len(dexKeeper.roundOrders[symbol]) - } + + for i := range kp.OrderKeepers { + ordNum += kp.OrderKeepers[i].getRoundOrdersNum() } + for i := range tradeOuts { //assume every new order would have 2 trades and generate 4 transfer tradeOuts[i] = make(chan Transfer, ordNum*4/concurrency) } } - symbolCh := make(chan string, concurrency) + symbolCh := make(chan symbolKeeper, concurrency) producer := func() { - for _, symbol := range symbolsToMatch { - symbolCh <- symbol + //for _, symbol := range symbolsToMatch { + // symbolCh <- symbol + //} + for i := range kp.OrderKeepers { + kp.OrderKeepers[i].iterateRoundPairs(func(symbol string) { + symbolCh <- symbolKeeper{symbol: symbol, orderKeeper: kp.OrderKeepers[i]} + }) } close(symbolCh) } matchWorker := func() { - for symbol := range symbolCh { - if dexUtils.IsMiniTokenTradingPair(symbol) { - dexMiniKeeper.matchAndDistributeTradesForSymbol(symbol, height, timestamp, dexMiniKeeper.allOrders[symbol], distributeTrade, tradeOuts) - } else { - dexKeeper.matchAndDistributeTradesForSymbol(symbol, height, timestamp, dexKeeper.allOrders[symbol], distributeTrade, tradeOuts) - } + for sk := range symbolCh { + kp.matchAndDistributeTradesForSymbol(sk.symbol, sk.orderKeeper, height, timestamp, distributeTrade, tradeOuts) } } @@ -110,24 +93,24 @@ func matchAndDistributeTrades(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, dist return tradeOuts } -func MatchSymbols(height, timestamp int64, dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, matchAllSymbols bool, logger tmlog.Logger) { - symbolsToMatch := dexKeeper.symbolSelector.SelectSymbolsToMatch(dexKeeper.roundOrders, height, timestamp, matchAllSymbols) - symbolsToMatch = append(symbolsToMatch, dexMiniKeeper.symbolSelector.SelectSymbolsToMatch(dexMiniKeeper.roundOrders, height, timestamp, matchAllSymbols)...) - logger.Debug("symbols to match", "symbols", symbolsToMatch) - - tradeOuts := matchAndDistributeTrades(dexKeeper, dexMiniKeeper, true, height, timestamp, symbolsToMatch, logger) +func (kp *DexKeeper) MatchSymbols(height, timestamp int64, matchAllSymbols bool) { + symbolsToMatch := kp.SelectSymbolsToMatch(height, timestamp, matchAllSymbols) + kp.logger.Debug("symbols to match", "symbols", symbolsToMatch) - if tradeOuts == nil { - logger.Info("No order comes in for the block") + if len(symbolsToMatch) == 0 { + kp.logger.Info("No order comes in for the block") + }else { + kp.matchAndDistributeTrades(false, height, timestamp) } - clearAfterMatchBEP2(dexKeeper) - clearAfterMatchMini(dexMiniKeeper) + + kp.ClearAfterMatch() } -func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, timestamp int64, orders map[string]*OrderInfo, +func (kp *DexKeeper) matchAndDistributeTradesForSymbol(symbol string, orderKeeper IDexOrderKeeper, height, timestamp int64, distributeTrade bool, tradeOuts []chan Transfer) { engine := kp.engines[symbol] concurrency := len(tradeOuts) + orders := orderKeeper.getAllOrdersForPair(symbol) // please note there is no logging in matching, expecting to see the order book details // from the exchange's order book stream. if engine.Match(height, dexUtils.IsMiniTokenTradingPair(symbol)) { @@ -137,7 +120,7 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times updateOrderMsg(orders[t.Bid], t.BuyCumQty, height, timestamp) updateOrderMsg(orders[t.Sid], t.SellCumQty, height, timestamp) if distributeTrade { - t1, t2 := TransferFromTrade(t, symbol, kp.allOrders[symbol]) + t1, t2 := TransferFromTrade(t, symbol, orders) c := channelHash(t1.accAddress, concurrency) tradeOuts[c] <- t1 c = channelHash(t2.accAddress, concurrency) @@ -157,7 +140,7 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times // for index service. kp.logger.Error("Fatal error occurred in matching, cancel all incoming new orders", "symbol", symbol) - thisRoundIds := kp.roundOrders[symbol] + thisRoundIds := orderKeeper.getRoundOrdersForPair(symbol) for _, id := range thisRoundIds { msg := orders[id] delete(orders, id) @@ -173,16 +156,14 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times // let the order status publisher publish these abnormal // order status change outs. - if kp.GlobalKeeper.CollectOrderInfoForPublish { - kp.OrderChangesMtx.Lock() - kp.OrderChanges = append(kp.OrderChanges, OrderChange{id, FailedMatching, "", nil}) - kp.OrderChangesMtx.Unlock() + if kp.CollectOrderInfoForPublish { + orderKeeper.appendOrderChangeSync(OrderChange{id, FailedMatching, "", nil}) } } return // no need to handle IOC } var iocIDs []string - iocIDs = kp.roundIOCOrders[symbol] + iocIDs = orderKeeper.getRoundIOCOrdersForPair(symbol) for _, id := range iocIDs { if msg, ok := orders[id]; ok { delete(orders, id) @@ -198,3 +179,11 @@ func (kp *Keeper) matchAndDistributeTradesForSymbol(symbol string, height, times } } } + + +// Run as postConsume procedure of async, no concurrent updates of orders map +func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { + order.CumQty = cumQty + order.LastUpdatedHeight = height + order.LastUpdatedTimestamp = timestamp +} diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index fe5e13521..151b4a84b 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -29,9 +29,10 @@ import ( ) type OrderBookSnapshot struct { - Buys []me.PriceLevel `json:"buys"` - Sells []me.PriceLevel `json:"sells"` - LastTradePrice int64 `json:"lasttradeprice"` + Buys []me.PriceLevel `json:"buys"` + Sells []me.PriceLevel `json:"sells"` + LastTradePrice int64 `json:"lasttradeprice"` + LastMatchHeight int64 `json:"lastmatchheight"` } type ActiveOrders struct { @@ -60,18 +61,22 @@ func compressAndSave(snapshot interface{}, cdc *wire.Codec, key string, kv sdk.K return nil } -func Init(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { - initOrderBook(dexKeeper, dexMiniKeeper, ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) +func Init(dexKeeper *DexKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { + dexKeeper.initOrderBook(ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) dexKeeper.InitRecentPrices(ctx) - dexMiniKeeper.InitRecentPrices(ctx) } -func (kp *Keeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) { +func (kp *DexKeeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) { kvstore := ctx.KVStore(kp.storeKey) effectedStoreKeys = make([]string, 0) for pair, eng := range kp.engines { buys, sells := eng.Book.GetAllLevels() - snapshot := OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice} + var snapshot OrderBookSnapshot + if sdk.IsUpgradeHeight(upgrade.BEP8) { + snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice, LastMatchHeight: eng.LastMatchHeight} + } else { + snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice} + } key := genOrderBookSnapshotKey(height, pair) effectedStoreKeys = append(effectedStoreKeys, key) err := compressAndSave(snapshot, kp.cdc, key, kvstore) @@ -83,7 +88,8 @@ func (kp *Keeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStor msgKeys := make([]string, 0) idSymbolMap := make(map[string]string) - for symbol, orderMap := range kp.allOrders { + allOrders := kp.GetAllOrders() + for symbol, orderMap := range allOrders { for id := range orderMap { idSymbolMap[id] = symbol msgKeys = append(msgKeys, id) @@ -92,7 +98,7 @@ func (kp *Keeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStor sort.Strings(msgKeys) msgs := make([]OrderInfo, len(msgKeys), len(msgKeys)) for i, key := range msgKeys { - msgs[i] = *kp.allOrders[idSymbolMap[key]][key] + msgs[i] = *allOrders[idSymbolMap[key]][key] } snapshot := ActiveOrders{Orders: msgs} @@ -102,7 +108,7 @@ func (kp *Keeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStor return effectedStoreKeys, compressAndSave(snapshot, kp.cdc, key, kvstore) } -func (kp *Keeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) { +func (kp *DexKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) { height := kp.GetLastBreatheBlockHeight(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) ctx.Logger().Info("Loading order book snapshot from last breathe block", "blockHeight", height) allPairs := kp.PairMapper.ListAllTradingPairs(ctx) @@ -152,7 +158,9 @@ func (kp *Keeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64 eng.Book.InsertPriceLevel(&pl, me.SELLSIDE) } eng.LastTradePrice = ob.LastTradePrice - eng.LastMatchHeight = height + if sdk.IsUpgradeHeight(upgrade.BEP8) { + eng.LastMatchHeight = ob.LastMatchHeight + } ctx.Logger().Info("Successfully Loaded order snapshot", "pair", pair) } key := genActiveOrdersSnapshotKey(height) @@ -176,25 +184,13 @@ func (kp *Keeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64 for _, m := range ao.Orders { orderHolder := m symbol := strings.ToUpper(m.Symbol) - kp.allOrders[symbol][m.Id] = &orderHolder - if m.CreatedHeight == height { - kp.roundOrders[symbol] = append(kp.roundOrders[symbol], m.Id) - if m.TimeInForce == TimeInForce.IOC { - kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], m.Id) - } - } - if kp.GlobalKeeper.CollectOrderInfoForPublish { - if _, exists := kp.OrderInfosForPub[m.Id]; !exists { - bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", m.Id) - kp.OrderInfosForPub[m.Id] = &orderHolder - } - } + kp.ReloadOrder(symbol, &orderHolder, height) } ctx.Logger().Info("Recovered active orders. Snapshot is fully loaded") return height, nil } -func replayOneBlocks(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, logger log.Logger, block *tmtypes.Block, stateDB dbm.DB, txDecoder sdk.TxDecoder, +func (kp *DexKeeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, stateDB dbm.DB, txDecoder sdk.TxDecoder, height int64, timestamp time.Time) { if block == nil { logger.Error("No block is loaded. Ignore replay for orderbook") @@ -209,7 +205,6 @@ func replayOneBlocks(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, logger log.Lo } // the time we replay should be consistent with ctx.BlockHeader().Time t := timestamp.UnixNano() - var orderKeeper DexOrderKeeper for idx, txBytes := range block.Txs { if abciRes.DeliverTx[idx].IsErr() { logger.Info("Skip tx when replay", "height", height, "idx", idx) @@ -237,23 +232,14 @@ func replayOneBlocks(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, logger log.Lo height, t, height, t, 0, txHash.String(), txSource} - if (!sdk.IsUpgrade(upgrade.BEP8)) || !dexUtils.IsMiniTokenTradingPair(msg.Symbol) { - orderKeeper = dexKeeper - } else { - orderKeeper = dexMiniKeeper - } - orderKeeper.AddOrder(orderInfo, true) + kp.AddOrder(orderInfo, true) logger.Info("Added Order", "order", msg) case CancelOrderMsg: - if (!sdk.IsUpgrade(upgrade.BEP8)) || !dexUtils.IsMiniTokenTradingPair(msg.Symbol) { - orderKeeper = dexKeeper - } else { - orderKeeper = dexMiniKeeper - } - err := orderKeeper.RemoveOrder(msg.RefId, msg.Symbol, func(ord me.OrderPart) { - if orderKeeper.GetGlobalKeeper().CollectOrderInfoForPublish { + symbolPairType := selectPairType(msg.Symbol) + err := kp.RemoveOrder(msg.RefId, msg.Symbol, func(ord me.OrderPart) { + if kp.CollectOrderInfoForPublish { bnclog.Debug("deleted order from order changes map", "orderId", msg.RefId, "isRecovery", true) - delete(orderKeeper.GetOrderInfosForPub(), msg.RefId) + delete(kp.GetOrderInfosForPub(symbolPairType), msg.RefId) } }) if err != nil { @@ -264,21 +250,32 @@ func replayOneBlocks(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, logger log.Lo } } logger.Info("replayed all tx. Starting match", "height", height) - MatchSymbols(height, t, dexKeeper, dexMiniKeeper, false, logger) //no need to check result + kp.MatchSymbols(height, t, false) //no need to check result +} + +func selectPairType(symbol string) SymbolPairType { + var pairType SymbolPairType + + if (!sdk.IsUpgrade(upgrade.BEP8)) || !dexUtils.IsMiniTokenTradingPair(symbol) { + pairType = PairType.BEP2 + } else { + pairType = PairType.MINI + } + return pairType } -func ReplayOrdersFromBlock(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, bc *tmstore.BlockStore, stateDb dbm.DB, lastHeight, breatheHeight int64, +func (kp *DexKeeper) ReplayOrdersFromBlock(ctx sdk.Context, bc *tmstore.BlockStore, stateDb dbm.DB, lastHeight, breatheHeight int64, txDecoder sdk.TxDecoder) error { for i := breatheHeight + 1; i <= lastHeight; i++ { block := bc.LoadBlock(i) ctx.Logger().Info("Relaying block for order book", "height", i) upgrade.Mgr.SetHeight(i) - replayOneBlocks(dexKeeper, dexMiniKeeper, ctx.Logger(), block, stateDb, txDecoder, i, block.Time) + kp.replayOneBlocks(ctx.Logger(), block, stateDb, txDecoder, i, block.Time) } return nil } -func initOrderBook(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { +func (kp *DexKeeper) initOrderBook(ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { var timeOfLatestBlock time.Time if lastHeight == 0 { timeOfLatestBlock = utils.Now() @@ -286,14 +283,13 @@ func initOrderBook(dexKeeper *Keeper, dexMiniKeeper *MiniKeeper, ctx sdk.Context block := blockStore.LoadBlock(lastHeight) timeOfLatestBlock = block.Time } - height, err := dexKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) - _, err = dexMiniKeeper.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) + height, err := kp.LoadOrderBookSnapshot(ctx, lastHeight, timeOfLatestBlock, blockInterval, daysBack) if err != nil { panic(err) } logger := ctx.Logger().With("module", "dex") logger.Info("Initialized Block Store for replay", "fromHeight", height, "toHeight", lastHeight) - err = ReplayOrdersFromBlock(dexKeeper, dexMiniKeeper, ctx.WithLogger(logger), blockStore, stateDB, lastHeight, height, txDecoder) + err = kp.ReplayOrdersFromBlock(ctx.WithLogger(logger), blockStore, stateDB, lastHeight, height, txDecoder) if err != nil { panic(err) } diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index 395496a96..a1dcb29e7 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -52,23 +52,13 @@ func MakeCodec() *wire.Codec { return cdc } -func MakeKeeper(cdc *wire.Codec) *Keeper { +func MakeKeeper(cdc *wire.Codec) *DexKeeper { accKeeper := auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) codespacer := sdk.NewCodespacer() - pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) - globalKeeper := NewGlobalKeeper(cdc, accKeeper, true) - keeper := NewKeeper(common.DexStoreKey, pairMapper, - codespacer.RegisterNext(dextypes.DefaultCodespace), 2, cdc, globalKeeper) - return keeper -} + pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) + keeper := NewDexKeeper(common.DexStoreKey, pairMapper, codespacer.RegisterNext(dextypes.DefaultCodespace), + cdc,accKeeper, true, 2) -func MakeMiniKeeper(cdc *wire.Codec) *MiniKeeper { - accKeeper := auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) - codespacer := sdk.NewCodespacer() - pairMapper := store.NewTradingPairMapper(cdc, common.MiniTokenPairStoreKey, true) - globalKeeper := NewGlobalKeeper(cdc, accKeeper, true) - keeper := NewMiniKeeper(common.DexMiniStoreKey, pairMapper, - codespacer.RegisterNext(dextypes.DefaultCodespace), 2, cdc, globalKeeper) return keeper } @@ -88,7 +78,6 @@ func TestKeeper_MatchFailure(t *testing.T) { assert := assert.New(t) cdc := MakeCodec() keeper := MakeKeeper(cdc) - miniKeeper := MakeMiniKeeper(cdc) cms := MakeCMS(nil) logger := log.NewTMLogger(os.Stdout) ctx := sdk.NewContext(cms, abci.Header{}, sdk.RunTxModeCheck, logger) @@ -119,8 +108,9 @@ func TestKeeper_MatchFailure(t *testing.T) { msg = NewNewOrderMsg(accAdd, "123462", Side.BUY, "XYZ-000_BNB", 99000, 15000000) ord = OrderInfo{msg, 42, 0, 42, 0, 0, "", 0} keeper.AddOrder(ord, false) - symbolsToMatch := keeper.symbolSelector.SelectSymbolsToMatch(keeper.roundOrders, ctx.BlockHeader().Height, 0, false) - tradeOuts := matchAndDistributeTrades(keeper, miniKeeper, true, 42, 0, symbolsToMatch, logger) + symbolsToMatch := keeper.SelectSymbolsToMatch(ctx.BlockHeader().Height, 0, false) + logger.Info("symbols to match", "symbols", symbolsToMatch) + tradeOuts := keeper.matchAndDistributeTrades(true, 42, 0) c := channelHash(accAdd, 4) i := 0 for tr := range tradeOuts[c] { @@ -195,7 +185,7 @@ func MakeAddress() (sdk.AccAddress, secp256k1.PrivKeySecp256k1) { return addr, privKey } -func effectedStoredKVPairs(keeper *Keeper, ctx sdk.Context, keys []string) map[string][]byte { +func effectedStoredKVPairs(keeper *DexKeeper, ctx sdk.Context, keys []string) map[string][]byte { res := make(map[string][]byte, len(keys)) store := ctx.KVStore(keeper.storeKey) for _, key := range keys { @@ -230,8 +220,8 @@ func TestKeeper_SnapShotOrderBook(t *testing.T) { keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) msg = NewNewOrderMsg(accAdd, "123462", Side.BUY, "XYZ-000_BNB", 96000, 1500000) keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) - assert.Equal(1, len(keeper.allOrders)) - assert.Equal(7, len(keeper.allOrders["XYZ-000_BNB"])) + assert.Equal(1, len(keeper.GetAllOrders())) + assert.Equal(7, len(keeper.GetAllOrdersForPair("XYZ-000_BNB"))) assert.Equal(1, len(keeper.engines)) effectedStoredKeys1, err := keeper.SnapShotOrderBook(ctx, 43) @@ -244,8 +234,8 @@ func TestKeeper_SnapShotOrderBook(t *testing.T) { keeper.MarkBreatheBlock(ctx, 43, time.Now()) keeper2 := MakeKeeper(cdc) h, err := keeper2.LoadOrderBookSnapshot(ctx, 43, utils.Now(), 0, 10) - assert.Equal(7, len(keeper2.allOrders["XYZ-000_BNB"])) - o123459 := keeper2.allOrders["XYZ-000_BNB"]["123459"] + assert.Equal(7, len(keeper2.GetAllOrdersForPair("XYZ-000_BNB"))) + o123459 := keeper2.GetAllOrdersForPair("XYZ-000_BNB")["123459"] assert.Equal(int64(98000), o123459.Price) assert.Equal(int64(1000000), o123459.Quantity) assert.Equal(int64(0), o123459.CumQty) @@ -268,7 +258,6 @@ func TestKeeper_SnapShotAndLoadAfterMatch(t *testing.T) { assert := assert.New(t) cdc := MakeCodec() keeper := MakeKeeper(cdc) - miniKeeper := MakeMiniKeeper(cdc) cms := MakeCMS(nil) logger := log.NewTMLogger(os.Stdout) ctx := sdk.NewContext(cms, abci.Header{}, sdk.RunTxModeCheck, logger) @@ -285,25 +274,25 @@ func TestKeeper_SnapShotAndLoadAfterMatch(t *testing.T) { keeper.AddOrder(info123457, false) msg := NewNewOrderMsg(accAdd, "123458", Side.SELL, "XYZ-000_BNB", 100000, 2000000) keeper.AddOrder(OrderInfo{msg, 42, 0, 42, 0, 0, "", 0}, false) - assert.Equal(1, len(keeper.allOrders)) - assert.Equal(3, len(keeper.allOrders["XYZ-000_BNB"])) + assert.Equal(1, len(keeper.GetAllOrders())) + assert.Equal(3, len(keeper.GetAllOrdersForPair("XYZ-000_BNB"))) assert.Equal(1, len(keeper.engines)) - MatchSymbols(42, 0, keeper, miniKeeper,false,logger) + keeper.MatchSymbols(42, 0, false) _, err := keeper.SnapShotOrderBook(ctx, 43) assert.Nil(err) keeper.MarkBreatheBlock(ctx, 43, time.Now()) keeper2 := MakeKeeper(cdc) h, err := keeper2.LoadOrderBookSnapshot(ctx, 43, utils.Now(), 0, 10) - assert.Equal(2, len(keeper2.allOrders["XYZ-000_BNB"])) - assert.Equal(int64(102000), keeper2.allOrders["XYZ-000_BNB"]["123456"].Price) - assert.Equal(int64(2000000), keeper2.allOrders["XYZ-000_BNB"]["123456"].CumQty) - assert.Equal(int64(10000), keeper2.allOrders["XYZ-000_BNB"]["123457"].Price) - assert.Equal(int64(0), keeper2.allOrders["XYZ-000_BNB"]["123457"].CumQty) + assert.Equal(2, len(keeper2.GetAllOrdersForPair("XYZ-000_BNB"))) + assert.Equal(int64(102000), keeper2.GetAllOrdersForPair("XYZ-000_BNB")["123456"].Price) + assert.Equal(int64(2000000), keeper2.GetAllOrdersForPair("XYZ-000_BNB")["123456"].CumQty) + assert.Equal(int64(10000), keeper2.GetAllOrdersForPair("XYZ-000_BNB")["123457"].Price) + assert.Equal(int64(0), keeper2.GetAllOrdersForPair("XYZ-000_BNB")["123457"].CumQty) info123456_Changed := info123456 info123456_Changed.CumQty = 2000000 - assert.Equal(info123456_Changed, *keeper2.OrderInfosForPub["123456"]) - assert.Equal(info123457, *keeper2.OrderInfosForPub["123457"]) + assert.Equal(info123456_Changed, *keeper2.GetOrderInfosForPub(PairType.BEP2)["123456"]) + assert.Equal(info123457, *keeper2.GetOrderInfosForPub(PairType.BEP2)["123457"]) assert.Equal(1, len(keeper2.engines)) assert.Equal(int64(102000), keeper2.engines["XYZ-000_BNB"].LastTradePrice) assert.Equal(int64(43), h) @@ -339,7 +328,7 @@ func TestKeeper_SnapShotOrderBookEmpty(t *testing.T) { keeper2 := MakeKeeper(cdc) h, err := keeper2.LoadOrderBookSnapshot(ctx, 43, utils.Now(), 0, 10) assert.Equal(int64(43), h) - assert.Equal(0, len(keeper2.allOrders["XYZ-000_BNB"])) + assert.Equal(0, len(keeper2.GetAllOrdersForPair("XYZ-000_BNB"))) buys, sells = keeper2.engines["XYZ-000_BNB"].Book.GetAllLevels() assert.Equal(0, len(buys)) assert.Equal(0, len(sells)) @@ -552,18 +541,17 @@ func getAccountCache(cdc *codec.Codec, ms sdk.MultiStore, accountKey *sdk.KVStor return auth.NewAccountCache(accountStoreCache) } -func setup() (ctx sdk.Context, mapper auth.AccountKeeper, keeper *Keeper) { +func setup() (ctx sdk.Context, mapper auth.AccountKeeper, keeper *DexKeeper) { ms, capKey, capKey2 := testutils.SetupMultiStoreForUnitTest() cdc := wire.NewCodec() types.RegisterWire(cdc) wire.RegisterCrypto(cdc) mapper = auth.NewAccountKeeper(cdc, capKey, types.ProtoAppAccount) accountCache := getAccountCache(cdc, ms, capKey) - pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) + pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) - globalKeeper := NewGlobalKeeper(cdc, mapper, false) - keeper = NewKeeper(capKey2, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, globalKeeper) + keeper = NewDexKeeper(capKey2, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc,mapper, false, 2) return } @@ -595,13 +583,13 @@ func TestKeeper_ExpireOrders(t *testing.T) { require.Len(t, sells, 1) require.Len(t, sells[0].Orders, 1) require.Equal(t, int64(2e8), sells[0].TotalLeavesQty()) - require.Len(t, keeper.allOrders["ABC-000_BNB"], 1) + require.Len(t, keeper.GetAllOrdersForPair("ABC-000_BNB"), 1) buys, sells = keeper.engines["XYZ-000_BNB"].Book.GetAllLevels() require.Len(t, buys, 1) require.Len(t, sells, 0) require.Len(t, buys[0].Orders, 1) require.Equal(t, int64(2e6), buys[0].TotalLeavesQty()) - require.Len(t, keeper.allOrders["XYZ-000_BNB"], 1) + require.Len(t, keeper.GetAllOrdersForPair("XYZ-000_BNB"), 1) expectFees := types.NewFee(sdk.Coins{ sdk.NewCoin("BNB", 6e4), sdk.NewCoin("ABC-000", 1e7), @@ -732,7 +720,7 @@ func TestOpenOrders_AfterMatch(t *testing.T) { assert.Equal(1, len(res)) // match existing two orders - keeper.MatchSymbols(43, 86) + keeper.MatchSymbols(43, 86, false) // after match, the original buy order's cumQty and latest updated fields should be updated res = keeper.GetOpenOrders("NNB_BNB", zc) @@ -766,7 +754,7 @@ func TestOpenOrders_AfterMatch(t *testing.T) { assert.Equal(int64(88), res[0].LastUpdatedTimestamp) // match existing two orders - keeper.MatchSymbols(44, 88) + keeper.MatchSymbols(44, 88, false) // after match, all orders should be closed res = keeper.GetOpenOrders("NNB_BNB", zc) @@ -816,12 +804,12 @@ func TestKeeper_DelistTradingPair(t *testing.T) { keeper.AddOrder(OrderInfo{msg, 42, 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) - assert.Equal(1, len(keeper.allOrders)) - assert.Equal(9, len(keeper.allOrders["XYZ-000_BNB"])) + assert.Equal(1, len(keeper.GetAllOrders())) + assert.Equal(9, len(keeper.GetAllOrdersForPair("XYZ-000_BNB"))) assert.Equal(1, len(keeper.engines)) keeper.DelistTradingPair(ctx, "XYZ-000_BNB", nil) - assert.Equal(0, len(keeper.allOrders)) + assert.Equal(0, len(keeper.GetAllOrders())) assert.Equal(0, len(keeper.engines)) expectFees := types.NewFee(sdk.Coins{ @@ -842,12 +830,12 @@ func TestKeeper_DelistTradingPair_Empty(t *testing.T) { keeper.PairMapper.AddTradingPair(ctx, tradingPair) keeper.AddEngine(tradingPair) - assert.Equal(1, len(keeper.allOrders)) - assert.Equal(0, len(keeper.allOrders["XYZ-001_BNB"])) + assert.Equal(1, len(keeper.GetAllOrders())) + assert.Equal(0, len(keeper.GetAllOrdersForPair("XYZ-001_BNB"))) assert.Equal(1, len(keeper.engines)) keeper.DelistTradingPair(ctx, "XYZ-001_BNB", nil) - assert.Equal(0, len(keeper.allOrders)) + assert.Equal(0, len(keeper.GetAllOrders())) assert.Equal(0, len(keeper.engines)) expectFees := types.NewFee(sdk.Coins(nil), types.ZeroFee) diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index d87b2c92b..0bb25144c 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -1,20 +1,14 @@ package order import ( - "errors" "fmt" - "strings" - "sync" - "time" - bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/utils" - me "github.com/binance-chain/node/plugins/dex/matcheng" - "github.com/binance-chain/node/plugins/dex/store" - dexTypes "github.com/binance-chain/node/plugins/dex/types" - "github.com/binance-chain/node/wire" + "github.com/binance-chain/node/common/upgrade" + dexUtils "github.com/binance-chain/node/plugins/dex/utils" sdk "github.com/cosmos/cosmos-sdk/types" + "strings" + "sync" ) const ( @@ -23,95 +17,55 @@ const ( ) //order keeper for mini-token -type MiniKeeper struct { - Keeper //use dex order keeper as base keeper +type MiniOrderKeeper struct { + BaseOrderKeeper } -var _ DexOrderKeeper = &MiniKeeper{} +var _ IDexOrderKeeper = &MiniOrderKeeper{} -// NewKeeper - Returns the MiniToken Keeper -func NewMiniKeeper(dexMiniKey sdk.StoreKey, miniPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, - concurrency uint, cdc *wire.Codec, globalKeeper *GlobalKeeper) *MiniKeeper { +// NewBEP2OrderKeeper - Returns the MiniToken BEP2OrderKeeper +func NewMiniOrderKeeper() IDexOrderKeeper { logger := bnclog.With("module", "dexMiniKeeper") - return &MiniKeeper{ - Keeper{PairMapper: miniPairMapper, - storeKey: dexMiniKey, - codespace: codespace, - engines: make(map[string]*me.MatchEng), - recentPrices: make(map[string]*utils.FixedSizeRing, 256), + return &MiniOrderKeeper{ + BaseOrderKeeper{ allOrders: make(map[string]map[string]*OrderInfo, 256), // need to init the nested map when a new symbol added. OrderChangesMtx: &sync.Mutex{}, OrderChanges: make(OrderChanges, 0), OrderInfosForPub: make(OrderInfoForPublish), roundOrders: make(map[string][]string, 256), roundIOCOrders: make(map[string][]string, 256), - poolSize: concurrency, - cdc: cdc, logger: logger, - symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}, - GlobalKeeper: globalKeeper, - }, + symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)},}, } } -// override -func (kp *MiniKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { - eng := kp.Keeper.AddEngine(pair) - symbol := strings.ToUpper(pair.GetSymbol()) - kp.symbolSelector.AddSymbolHash(symbol) - return eng -} - -// used by state sync to clear memory order book after we synced latest breathe block -//TODO check usage -func (kp *MiniKeeper) ClearOrders() { - kp.Keeper.ClearOrders() - emptyRoundMatchSymbols := make([]string, 0, 256) - kp.symbolSelector.SetRoundMatchSymbol(emptyRoundMatchSymbols) -} - //override -func (kp *MiniKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { - // trading pair against native token should exist if quote token is not native token - baseAsset = strings.ToUpper(baseAsset) - quoteAsset = strings.ToUpper(quoteAsset) - - if baseAsset == quoteAsset { - return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") - } - - if kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) || kp.PairMapper.Exists(ctx, quoteAsset, baseAsset) { - return errors.New("trading pair exists") - } - - if types.NativeTokenSymbol != quoteAsset { //todo permit BUSD - return errors.New("quote token is not valid: " + quoteAsset) +func (kp *MiniOrderKeeper) support(pair string) bool { + if !sdk.IsUpgradeHeight(upgrade.BEP8) { + return false } - - return nil + return dexUtils.IsMiniTokenTradingPair(pair) } -//override TODO check -func (kp *MiniKeeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { - // trading pair against native token should not be delisted if there is any other trading pair exist - baseAsset = strings.ToUpper(baseAsset) - quoteAsset = strings.ToUpper(quoteAsset) - - if baseAsset == quoteAsset { - return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") - } +//override +func (kp *MiniOrderKeeper) supportUpgradeVersion() bool { + return sdk.IsUpgradeHeight(upgrade.BEP8) +} - if !kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) { - return fmt.Errorf("trading pair %s_%s does not exist", baseAsset, quoteAsset) - } +func (kp *MiniOrderKeeper) supportPairType(pairType SymbolPairType) bool { + return PairType.MINI == pairType +} - return nil +// override +func (kp *MiniOrderKeeper) initOrders(symbol string) { + kp.allOrders[symbol] = map[string]*OrderInfo{} + kp.symbolSelector.AddSymbolHash(symbol) } // override -func (kp *MiniKeeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { +func (kp *MiniOrderKeeper) validateOrder(dexKeeper *DexKeeper, ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { - err := kp.Keeper.validateOrder(ctx, acc, msg) + err := kp.BaseOrderKeeper.validateOrder(dexKeeper, ctx, acc, msg) if err != nil { return err } @@ -130,7 +84,41 @@ func (kp *MiniKeeper) validateOrder(ctx sdk.Context, acc sdk.Account, msg NewOrd return nil } -// override -func (kp *MiniKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) { - return kp.Keeper.LoadOrderBookSnapshot(ctx, latestBlockHeight, timeOfLatestBlock, blockInterval, daysBack) +func (kp *MiniOrderKeeper) clearAfterMatch() { + kp.logger.Debug("clearAfterMatchMini...") + for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { + delete(kp.roundOrders, symbol) + delete(kp.roundIOCOrders, symbol) + } + clearedRoundMatchSymbols := make([]string, 0) + kp.symbolSelector.SetRoundMatchSymbol(clearedRoundMatchSymbols) +} + +func (kp *MiniOrderKeeper) iterateRoundPairs(iter func(string)) { + for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { + iter(symbol) + } +} + +func (kp *MiniOrderKeeper) getRoundPairsNum() int { + return len(*kp.symbolSelector.GetRoundMatchSymbol()) +} + +func (kp *MiniOrderKeeper) getRoundOrdersNum() int { + n := 0 + kp.iterateRoundPairs(func(symbol string) { + n += len(kp.roundOrders[symbol]) + }) + return n +} + +func (kp *MiniOrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) { + kp.allOrders[symbol][orderInfo.Id] = orderInfo + //TODO confirm no active orders for mini symbol + if collectOrderInfoForPublish { + if _, exists := kp.OrderInfosForPub[orderInfo.Id]; !exists { + bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) + kp.OrderInfosForPub[orderInfo.Id] = orderInfo + } + } } diff --git a/plugins/dex/order/openOrders_test.go b/plugins/dex/order/openOrders_test.go index 4865ab172..0c9c52444 100644 --- a/plugins/dex/order/openOrders_test.go +++ b/plugins/dex/order/openOrders_test.go @@ -20,7 +20,7 @@ var ( zc, _ = sdk.AccAddressFromBech32(ZcAddr) ) -func initKeeper() *Keeper { +func initKeeper() *DexKeeper { cdc := MakeCodec() keeper := MakeKeeper(cdc) return keeper diff --git a/plugins/dex/order/symbol_selector.go b/plugins/dex/order/symbol_selector.go index d81436b20..6aa0188bf 100644 --- a/plugins/dex/order/symbol_selector.go +++ b/plugins/dex/order/symbol_selector.go @@ -41,15 +41,18 @@ func (bss *BEP2SymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]str } type MiniSymbolSelector struct { - miniSymbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin - matchedMiniSymbols []string //mini token pairs matched in this round + miniSymbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin + roundMiniSymbols []string //mini token pairs to match in this round } -var _ SymbolSelector = &MiniSymbolSelector{} +var _ SymbolSelector = &MiniSymbolSelector{ + make(map[string]uint32), + make([]string, 0), +} func (mss *MiniSymbolSelector) GetRoundMatchSymbol() *[]string { - return &mss.matchedMiniSymbols + return &mss.roundMiniSymbols } func (mss *MiniSymbolSelector) AddSymbolHash(symbol string) { @@ -57,7 +60,7 @@ func (mss *MiniSymbolSelector) AddSymbolHash(symbol string) { } func (mss *MiniSymbolSelector) SetRoundMatchSymbol(symbols []string) { - mss.matchedMiniSymbols = symbols + mss.roundMiniSymbols = symbols } func (mss *MiniSymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]string, height, timestamp int64, matchAllSymbols bool) []string { @@ -77,7 +80,7 @@ func (mss *MiniSymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]str } }) } - mss.matchedMiniSymbols = symbolsToMatch + mss.roundMiniSymbols = symbolsToMatch return symbolsToMatch } diff --git a/plugins/dex/order/types.go b/plugins/dex/order/types.go index 56f70adb7..d3cbefbff 100644 --- a/plugins/dex/order/types.go +++ b/plugins/dex/order/types.go @@ -121,6 +121,7 @@ type ExpireHolder struct { OrderId string Reason ChangeType Fee string + Symbol string } type SymbolWithOrderNumber struct { diff --git a/plugins/dex/plugin.go b/plugins/dex/plugin.go index b59bf856d..ffdbd4a35 100644 --- a/plugins/dex/plugin.go +++ b/plugins/dex/plugin.go @@ -2,7 +2,6 @@ package dex import ( "encoding/json" - "reflect" "strings" "time" @@ -22,21 +21,14 @@ const DexAbciQueryPrefix = "dex" const DexMiniAbciQueryPrefix = "dex_mini" const DelayedDaysForDelist = 3 -type DexKeeperType int8 - -const ( - KeeperType DexKeeperType = 0 - MiniTokenKeeperType DexKeeperType = 1 -) - // InitPlugin initializes the dex plugin. func InitPlugin( - appp app.ChainApp, dexKeeper *DexKeeper, dexMiniKeeper *DexMiniTokenKeeper, dexGlobalKeeper *DexGlobalKeeper, tokenMapper tkstore.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, + appp app.ChainApp, dexKeeper *DexKeeper, tokenMapper tkstore.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, ) { cdc := appp.GetCodec() // add msg handlers - for route, handler := range Routes(cdc, dexKeeper, dexMiniKeeper, dexGlobalKeeper, tokenMapper, miniTokenMapper, accMapper, govKeeper) { + for route, handler := range Routes(cdc, dexKeeper, tokenMapper, miniTokenMapper, accMapper, govKeeper) { appp.GetRouter().AddRoute(route, handler) } @@ -53,7 +45,7 @@ func createQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQuery } // EndBreatheBlock processes the breathe block lifecycle event. -func EndBreatheBlock(ctx sdk.Context, dexKeeper DexOrderKeeper, govKeeper gov.Keeper, height int64, blockTime time.Time) { +func EndBreatheBlock(ctx sdk.Context, dexKeeper *DexKeeper, govKeeper gov.Keeper, height int64, blockTime time.Time) { logger := bnclog.With("module", "dex") logger.Info("Delist trading pairs", "blockHeight", height) @@ -78,19 +70,9 @@ func EndBreatheBlock(ctx sdk.Context, dexKeeper DexOrderKeeper, govKeeper gov.Ke return } -func delistTradingPairs(ctx sdk.Context, govKeeper gov.Keeper, dexKeeper DexOrderKeeper, blockTime time.Time) { +func delistTradingPairs(ctx sdk.Context, govKeeper gov.Keeper, dexKeeper *DexKeeper, blockTime time.Time) { logger := bnclog.With("module", "dex") - var dexKeeperType DexKeeperType - switch dexKeeper.(type) { - case *DexKeeper: - dexKeeperType = KeeperType - case *DexMiniTokenKeeper: - dexKeeperType = MiniTokenKeeperType - default: - logger.Error("unknown dexKeeper type", "dexKeeper", reflect.TypeOf(dexKeeper)) - return - } - symbolsToDelist := getSymbolsToDelist(ctx, govKeeper, blockTime, dexKeeperType) + symbolsToDelist := getSymbolsToDelist(ctx, govKeeper, blockTime) for _, symbol := range symbolsToDelist { logger.Info("Delist trading pair", "symbol", symbol) @@ -109,7 +91,7 @@ func delistTradingPairs(ctx sdk.Context, govKeeper gov.Keeper, dexKeeper DexOrde } } -func getSymbolsToDelist(ctx sdk.Context, govKeeper gov.Keeper, blockTime time.Time, dexKeeperType DexKeeperType) []string { +func getSymbolsToDelist(ctx sdk.Context, govKeeper gov.Keeper, blockTime time.Time) []string { logger := bnclog.With("module", "dex") symbols := make([]string, 0) @@ -137,9 +119,6 @@ func getSymbolsToDelist(ctx sdk.Context, govKeeper gov.Keeper, blockTime time.Ti timeToDelist := passedTime.Add(DelayedDaysForDelist * 24 * time.Hour) if timeToDelist.Before(blockTime) { symbol := utils.Assets2TradingPair(strings.ToUpper(delistParam.BaseAssetSymbol), strings.ToUpper(delistParam.QuoteAssetSymbol)) - if (dexKeeperType == MiniTokenKeeperType) != utils.IsMiniTokenTradingPair(symbol) { - return false - } symbols = append(symbols, symbol) // update proposal delisted status delistParam.IsExecuted = true diff --git a/plugins/dex/route.go b/plugins/dex/route.go index 1507c35f5..d18c664e5 100644 --- a/plugins/dex/route.go +++ b/plugins/dex/route.go @@ -14,13 +14,13 @@ import ( ) // Routes exports dex message routes -func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, dexMiniKeeper *DexMiniTokenKeeper, dexGlobalKeeper *DexGlobalKeeper, tokenMapper tokens.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, +func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accKeeper auth.AccountKeeper, govKeeper gov.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) - orderHandler := order.NewHandler(cdc, dexKeeper, dexMiniKeeper, dexGlobalKeeper, accKeeper) + orderHandler := order.NewHandler(cdc, dexKeeper) routes[order.RouteNewOrder] = orderHandler routes[order.RouteCancelOrder] = orderHandler routes[list.Route] = list.NewHandler(dexKeeper, tokenMapper, govKeeper) - routes[listmini.Route] = listmini.NewHandler(dexMiniKeeper, miniTokenMapper, tokenMapper) + routes[listmini.Route] = listmini.NewHandler(dexKeeper, miniTokenMapper, tokenMapper) return routes } diff --git a/plugins/dex/store/mapper.go b/plugins/dex/store/mapper.go index dd3d21e09..51ba9c9da 100644 --- a/plugins/dex/store/mapper.go +++ b/plugins/dex/store/mapper.go @@ -10,7 +10,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" cmn "github.com/binance-chain/node/common/types" - common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/utils" "github.com/binance-chain/node/plugins/dex/types" dexUtils "github.com/binance-chain/node/plugins/dex/utils" @@ -34,30 +33,23 @@ var _ TradingPairMapper = mapper{} type mapper struct { key sdk.StoreKey cdc *wire.Codec - forMiniPair bool } -func NewTradingPairMapper(cdc *wire.Codec, key sdk.StoreKey, forMiniPair bool) TradingPairMapper { +func NewTradingPairMapper(cdc *wire.Codec, key sdk.StoreKey) TradingPairMapper { return mapper{ key: key, - cdc: cdc, - forMiniPair: forMiniPair} + cdc: cdc} } func (m mapper) AddTradingPair(ctx sdk.Context, pair types.TradingPair) error { baseAsset := pair.BaseAssetSymbol quoteAsset := pair.QuoteAssetSymbol - if m.forMiniPair{ - if err := cmn.ValidateMapperMiniTokenSymbol(baseAsset); err != nil { - return err - } - if quoteAsset!= common.NativeTokenSymbol{ //todo permit BUSD - return errors.New("quote token is not valid") - } - }else { + if !cmn.IsMiniTokenSymbol(baseAsset) { if err := cmn.ValidateMapperTokenSymbol(baseAsset); err != nil { return err } + } + if !cmn.IsMiniTokenSymbol(quoteAsset) { if err := cmn.ValidateMapperTokenSymbol(quoteAsset); err != nil { return err } diff --git a/plugins/dex/utils/pair.go b/plugins/dex/utils/pair.go index 58dd11b1b..9d6e2afe7 100644 --- a/plugins/dex/utils/pair.go +++ b/plugins/dex/utils/pair.go @@ -86,9 +86,9 @@ func Assets2TradingPair(baseAsset, quoteAsset string) (symbol string) { } func IsMiniTokenTradingPair(symbol string) bool { - baseAsset, _, err := TradingPair2Assets(symbol) + baseAsset, quoteAsset, err := TradingPair2Assets(symbol) if err != nil{ return false } - return types.IsMiniTokenSymbol(baseAsset) + return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) } From 11033eb636f222e9e66d659bd0f362b972549c9c Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 8 May 2020 17:16:47 +0800 Subject: [PATCH 20/96] format --- admin/tx.go | 2 +- app/app.go | 20 +++++++------- app/config/config.go | 2 +- app/pub/helpers.go | 6 ++--- app/pub/keeper_pub_test.go | 14 +++++----- app/pub/publisher.go | 2 +- app/pub/types.go | 32 +++++++++++------------ common/stores.go | 26 +++++++++--------- common/types/mini_token.go | 2 +- plugins/dex/aliases.go | 2 -- plugins/dex/listmini/msg.go | 2 +- plugins/dex/matcheng/engine_new.go | 4 +-- plugins/dex/order/global_keeper.go | 11 ++++---- plugins/dex/order/handler_test.go | 4 +-- plugins/dex/order/keeper.go | 6 ++--- plugins/dex/order/keeper_match.go | 8 +++--- plugins/dex/order/keeper_test.go | 4 +-- plugins/dex/order/mini_keeper.go | 7 ++--- plugins/dex/order/quickselect.go | 6 ++--- plugins/dex/order/quickselect_test.go | 3 ++- plugins/dex/order/symbol_selector.go | 1 - plugins/dex/store/codec.go | 9 ++++--- plugins/dex/store/utils.go | 2 +- plugins/dex/utils/pair.go | 2 +- plugins/miniTokens/client/cli/commands.go | 2 +- plugins/miniTokens/client/cli/issue.go | 5 ++-- plugins/miniTokens/issue/handler.go | 2 -- plugins/miniTokens/issue/handler_test.go | 3 ++- plugins/miniTokens/seturi/handler.go | 1 - plugins/miniTokens/seturi/msg.go | 12 ++++----- plugins/miniTokens/store/mapper.go | 2 -- plugins/param/types/types.go | 2 +- plugins/tokens/client/cli/issue.go | 2 +- plugins/tokens/freeze/handler.go | 9 +++---- plugins/tokens/issue/handler.go | 3 ++- plugins/tokens/issue/handler_test.go | 7 +++-- plugins/tokens/plugin.go | 2 +- plugins/tokens/swap/handler.go | 2 ++ 38 files changed, 112 insertions(+), 119 deletions(-) diff --git a/admin/tx.go b/admin/tx.go index 74755273e..8458b2f0d 100644 --- a/admin/tx.go +++ b/admin/tx.go @@ -8,11 +8,11 @@ import ( "github.com/binance-chain/node/common/runtime" "github.com/binance-chain/node/plugins/dex/order" + miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" "github.com/binance-chain/node/plugins/tokens/timelock" - miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" ) var transferOnlyModeBlackList = []string{ diff --git a/app/app.go b/app/app.go index 1c4f298d8..e8cd0dcb8 100644 --- a/app/app.go +++ b/app/app.go @@ -82,16 +82,16 @@ type BinanceChain struct { queryHandlers map[string]types.AbciQueryHandler // keepers - CoinKeeper bank.Keeper - DexKeeper *dex.DexKeeper - AccountKeeper auth.AccountKeeper - TokenMapper tkstore.Mapper - MiniTokenMapper miniTkstore.MiniTokenMapper - ValAddrCache *ValAddrCache - stakeKeeper stake.Keeper - govKeeper gov.Keeper - timeLockKeeper timelock.Keeper - swapKeeper swap.Keeper + CoinKeeper bank.Keeper + DexKeeper *dex.DexKeeper + AccountKeeper auth.AccountKeeper + TokenMapper tkstore.Mapper + MiniTokenMapper miniTkstore.MiniTokenMapper + ValAddrCache *ValAddrCache + stakeKeeper stake.Keeper + govKeeper gov.Keeper + timeLockKeeper timelock.Keeper + swapKeeper swap.Keeper // keeper to process param store and update ParamHub *param.ParamHub diff --git a/app/config/config.go b/app/config/config.go index a5e23b11a..3f620170d 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -368,7 +368,7 @@ type UpgradeConfig struct { FixZeroBalanceHeight int64 `mapstructure:"FixZeroBalanceHeight"` // TODO: add upgrade name - BEP8Height int64 `mapstructure:"BEP8Height"` + BEP8Height int64 `mapstructure:"BEP8Height"` } func defaultUpgradeConfig() *UpgradeConfig { diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 0d27dc3ef..e31dc98e4 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -268,7 +268,7 @@ func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Contex // This channels is used for protect not update `dexKeeper.OrderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) // while dexKeeper.OrderChanges are not separated by concurrent factor (users here) - iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize + MiniTransferCollectionChannelSize) + iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize+MiniTransferCollectionChannelSize) wg := sync.WaitGroup{} wg.Add(1) @@ -324,7 +324,7 @@ func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, trad TickType: int(trade.TickType), } tradeIdx += 1 - if types.IsMiniTokenSymbol(symbol){ + if types.IsMiniTokenSymbol(symbol) { miniTradesToPublish = append(miniTradesToPublish, t) } tradesToPublish = append(tradesToPublish, t) @@ -518,7 +518,7 @@ func collectOrdersToPublish( feeHolder orderPkg.FeeHolder, timestamp int64, miniTrades []*Trade, miniOrderChanges orderPkg.OrderChanges, - miniOrderInfos orderPkg.OrderInfoForPublish) (opensToPublish []*Order, closedToPublish []*Order, miniOpensToPublish []*Order, miniClosedToPublish []*Order, feeToPublish map[string]string, ) { + miniOrderInfos orderPkg.OrderInfoForPublish) (opensToPublish []*Order, closedToPublish []*Order, miniOpensToPublish []*Order, miniClosedToPublish []*Order, feeToPublish map[string]string) { opensToPublish = make([]*Order, 0) closedToPublish = make([]*Order, 0) miniOpensToPublish = make([]*Order, 0) diff --git a/app/pub/keeper_pub_test.go b/app/pub/keeper_pub_test.go index e268073be..287368c82 100644 --- a/app/pub/keeper_pub_test.go +++ b/app/pub/keeper_pub_test.go @@ -39,7 +39,7 @@ func newTestFeeConfig() orderPkg.FeeConfig { return feeConfig } -var keeper *orderPkg.BEP2OrderKeeper +var keeper *orderPkg.DexKeeper var buyer sdk.AccAddress var seller sdk.AccAddress var am auth.AccountKeeper @@ -60,8 +60,8 @@ func setupKeeperTest(t *testing.T) (*assert.Assertions, *require.Assertions) { accountCache := getAccountCache(cdc, ms, capKey) ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, logger).WithAccountCache(accountCache) - pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey, false) - keeper = orderPkg.NewBEP2OrderKeeper(capKey2, am, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, true) + pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) + keeper = orderPkg.NewDexKeeper(capKey2, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc, am, true, 2) tradingPair := dextypes.NewTradingPair("XYZ-000", types.NativeTokenSymbol, 1e8) keeper.PairMapper.AddTradingPair(ctx, tradingPair) keeper.AddEngine(tradingPair) @@ -89,15 +89,15 @@ func TestKeeper_AddOrder(t *testing.T) { msg = orderPkg.NewNewOrderMsg(buyer, "2", orderPkg.Side.BUY, "XYZ-000_BNB", 101000, 1000000) keeper.AddOrder(orderPkg.OrderInfo{msg, 43, 105, 43, 105, 0, "0D42245EB2BF574A5B9D485404E0E61B1A2397A9", 0}, false) - require.Len(keeper.OrderChanges, 2) - require.Len(keeper.OrderInfosForPub, 2) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 2) // verify order0 - and the order in orderchanges slice - orderChange0 := keeper.OrderChanges[0] + orderChange0 := keeper.GetOrderChanges()[0] assert.Equal("1", orderChange0.Id) assert.Equal(orderPkg.Ack, orderChange0.Tpe) // verify order1 - make sure the fields are correct - orderInfo1 := keeper.OrderInfosForPub["2"] + orderInfo1 := keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2)["2"] assert.Equal(buyer, orderInfo1.Sender) assert.Equal("2", orderInfo1.Id) assert.Equal("XYZ-000_BNB", orderInfo1.Symbol) diff --git a/app/pub/publisher.go b/app/pub/publisher.go index 3bdfef938..f10e702c3 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -91,7 +91,7 @@ func Publish( marketData.proposalsToPublish, marketData.stakeUpdates, miniOrdersToPublish, - marketData.miniTradesToPublish, ) + marketData.miniTradesToPublish) }) if metrics != nil { diff --git a/app/pub/types.go b/app/pub/types.go index 2af819c2f..4e7a1a717 100644 --- a/app/pub/types.go +++ b/app/pub/types.go @@ -6,23 +6,23 @@ import ( // intermediate data structures to deal with concurrent publication between main thread and publisher thread type BlockInfoToPublish struct { - height int64 - timestamp int64 - tradesToPublish []*Trade - proposalsToPublish *Proposals - stakeUpdates *StakeUpdates - orderChanges orderPkg.OrderChanges - orderInfos orderPkg.OrderInfoForPublish - accounts map[string]Account - latestPricesLevels orderPkg.ChangedPriceLevelsMap + height int64 + timestamp int64 + tradesToPublish []*Trade + proposalsToPublish *Proposals + stakeUpdates *StakeUpdates + orderChanges orderPkg.OrderChanges + orderInfos orderPkg.OrderInfoForPublish + accounts map[string]Account + latestPricesLevels orderPkg.ChangedPriceLevelsMap miniLatestPriceLevels orderPkg.ChangedPriceLevelsMap - blockFee BlockFee - feeHolder orderPkg.FeeHolder - transfers *Transfers - block *Block - miniTradesToPublish []*Trade - miniOrderChanges orderPkg.OrderChanges - miniOrderInfos orderPkg.OrderInfoForPublish + blockFee BlockFee + feeHolder orderPkg.FeeHolder + transfers *Transfers + block *Block + miniTradesToPublish []*Trade + miniOrderChanges orderPkg.OrderChanges + miniOrderInfos orderPkg.OrderInfoForPublish } func NewBlockInfoToPublish( diff --git a/common/stores.go b/common/stores.go index 775a3d38e..693b6023c 100644 --- a/common/stores.go +++ b/common/stores.go @@ -3,18 +3,18 @@ package common import sdk "github.com/cosmos/cosmos-sdk/types" const ( - MainStoreName = "main" - AccountStoreName = "acc" - ValAddrStoreName = "val" - TokenStoreName = "tokens" - MiniTokenStoreName = "minitokens" - DexStoreName = "dex" - PairStoreName = "pairs" - StakeStoreName = "stake" - ParamsStoreName = "params" - GovStoreName = "gov" - TimeLockStoreName = "time_lock" - AtomicSwapStoreName = "atomic_swap" + MainStoreName = "main" + AccountStoreName = "acc" + ValAddrStoreName = "val" + TokenStoreName = "tokens" + MiniTokenStoreName = "minitokens" + DexStoreName = "dex" + PairStoreName = "pairs" + StakeStoreName = "stake" + ParamsStoreName = "params" + GovStoreName = "gov" + TimeLockStoreName = "time_lock" + AtomicSwapStoreName = "atomic_swap" StakeTransientStoreName = "transient_stake" ParamsTransientStoreName = "transient_params" @@ -37,7 +37,7 @@ var ( TStakeStoreKey = sdk.NewTransientStoreKey(StakeTransientStoreName) TParamsStoreKey = sdk.NewTransientStoreKey(ParamsTransientStoreName) - MiniTokenStoreKey = sdk.NewKVStoreKey(MiniTokenStoreName) + MiniTokenStoreKey = sdk.NewKVStoreKey(MiniTokenStoreName) StoreKeyNameMap = map[string]sdk.StoreKey{ MainStoreName: MainStoreKey, diff --git a/common/types/mini_token.go b/common/types/mini_token.go index cc868cb74..9cf529365 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -55,7 +55,7 @@ func (t SupplyRangeType) String() string { var SupplyRange = struct { TINY SupplyRangeType MINI SupplyRangeType -}{TinyRangeType, MiniRangeType } +}{TinyRangeType, MiniRangeType} type MiniToken struct { Name string `json:"name"` diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index 330647e0f..6df7171bb 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -17,8 +17,6 @@ type DexKeeper = order.DexKeeper type SymbolPairType = order.SymbolPairType var NewTradingPairMapper = store.NewTradingPairMapper -var NewOrderKeeper = order.NewBEP2OrderKeeper -var NewMiniOrderKeeper = order.NewMiniOrderKeeper var NewDexKeeper = order.NewDexKeeper var PairType = order.PairType diff --git a/plugins/dex/listmini/msg.go b/plugins/dex/listmini/msg.go index 3fc4ab793..be09d2989 100644 --- a/plugins/dex/listmini/msg.go +++ b/plugins/dex/listmini/msg.go @@ -40,7 +40,7 @@ func (msg ListMiniMsg) ValidateBasic() sdk.Error { if err != nil { return sdk.ErrInvalidCoins("base token: " + err.Error()) } - if types.NativeTokenSymbol != msg.QuoteAssetSymbol {//todo permit BUSD + if types.NativeTokenSymbol != msg.QuoteAssetSymbol { //todo permit BUSD return sdk.ErrInvalidCoins("quote token: " + err.Error()) } if msg.InitPrice <= 0 { diff --git a/plugins/dex/matcheng/engine_new.go b/plugins/dex/matcheng/engine_new.go index bf56c0582..64890296c 100644 --- a/plugins/dex/matcheng/engine_new.go +++ b/plugins/dex/matcheng/engine_new.go @@ -40,8 +40,8 @@ func (me *MatchEng) Match(height int64, isMini bool) bool { var lastMatchHeight int64 if isMini { lastMatchHeight = me.LastMatchHeight - }else{ - lastMatchHeight = height -1 //Every block is deemed as performed matching for all BEP2 symbols + } else { + lastMatchHeight = height - 1 //Every block is deemed as performed matching for all BEP2 symbols } takerSide, err := me.determineTakerSide(lastMatchHeight, index) if err != nil { diff --git a/plugins/dex/order/global_keeper.go b/plugins/dex/order/global_keeper.go index 61b4c8e47..8fd6dc0f2 100644 --- a/plugins/dex/order/global_keeper.go +++ b/plugins/dex/order/global_keeper.go @@ -3,14 +3,15 @@ package order import ( "errors" "fmt" - "github.com/binance-chain/node/common/fees" - "github.com/binance-chain/node/common/utils" - "github.com/binance-chain/node/plugins/dex/store" "math" "strings" "sync" "time" + "github.com/binance-chain/node/common/fees" + "github.com/binance-chain/node/common/utils" + "github.com/binance-chain/node/plugins/dex/store" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -1036,7 +1037,6 @@ func (kp *DexKeeper) ClearAfterMatch() { } } - func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator for _, orderKeeper := range kp.OrderKeepers { @@ -1047,7 +1047,7 @@ func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { return allOrders } -func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo{ +func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo { ordersOfSymbol := make(map[string]*OrderInfo) for _, orderKeeper := range kp.OrderKeepers { if orderKeeper.support(symbol) { @@ -1067,7 +1067,6 @@ func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int } } - func isMiniSymbolPair(baseAsset, quoteAsset string) bool { if sdk.IsUpgradeHeight(upgrade.BEP8) { return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) diff --git a/plugins/dex/order/handler_test.go b/plugins/dex/order/handler_test.go index 3b740020d..ddde92c4a 100644 --- a/plugins/dex/order/handler_test.go +++ b/plugins/dex/order/handler_test.go @@ -41,7 +41,7 @@ func setupMappers() (store.TradingPairMapper, auth.AccountKeeper, sdk.Context, * accMapper := auth.NewAccountKeeper(cdc, key2, auth.ProtoBaseAccount) accountCache := getAccountCache(cdc, ms, key2) ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) - keeper := NewDexKeeper(key3, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc,accMapper, false, 2) + keeper := NewDexKeeper(key3, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc, accMapper, false, 2) return pairMapper, accMapper, ctx, keeper } @@ -155,7 +155,7 @@ func TestHandler_ValidateOrder_WrongQuantity(t *testing.T) { } func TestHandler_ValidateOrder_Normal(t *testing.T) { - pairMapper, accMapper, ctx, keeper:= setupMappers() + pairMapper, accMapper, ctx, keeper := setupMappers() err := pairMapper.AddTradingPair(ctx, types.NewTradingPair("AAA-000", "BNB", 1e8)) require.NoError(t, err) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index e27f512e0..b3cf02716 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -61,6 +61,7 @@ type BEP2OrderKeeper struct { } var _ IDexOrderKeeper = &BEP2OrderKeeper{} + // in the future, this may be distributed via Sharding type BaseOrderKeeper struct { allOrders map[string]map[string]*OrderInfo // symbol -> order ID -> order @@ -263,8 +264,8 @@ func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { //TODO for symbol, orders := range kp.allOrders { - for orderId := range orders{ - iter(symbol,orderId) + for orderId := range orders { + iter(symbol, orderId) } } } @@ -326,4 +327,3 @@ func (kp *BEP2OrderKeeper) getRoundOrdersNum() int { } return n } - diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index cd272713f..160eea57f 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -8,7 +8,6 @@ import ( dexUtils "github.com/binance-chain/node/plugins/dex/utils" ) - func (kp *DexKeeper) SelectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string { symbolsToMatch := make([]string, 0, 256) for _, orderKeeper := range kp.OrderKeepers { @@ -19,7 +18,6 @@ func (kp *DexKeeper) SelectSymbolsToMatch(height, timestamp int64, matchAllSymbo return symbolsToMatch } - func (kp *DexKeeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height) timestamp := ctx.BlockHeader().Time.UnixNano() @@ -29,7 +27,7 @@ func (kp *DexKeeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandl var tradeOuts []chan Transfer if len(symbolsToMatch) == 0 { kp.logger.Info("No order comes in for the block") - }else{ + } else { tradeOuts = kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp) } @@ -42,6 +40,7 @@ type symbolKeeper struct { symbol string orderKeeper IDexOrderKeeper } + // please note if distributeTrade this method will work in async mode, otherwise in sync mode. // Always run kp.SelectSymbolsToMatch(ctx.BlockHeader().Height, timestamp, matchAllSymbols) before matchAndDistributeTrades func (kp *DexKeeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64) []chan Transfer { @@ -99,7 +98,7 @@ func (kp *DexKeeper) MatchSymbols(height, timestamp int64, matchAllSymbols bool) if len(symbolsToMatch) == 0 { kp.logger.Info("No order comes in for the block") - }else { + } else { kp.matchAndDistributeTrades(false, height, timestamp) } @@ -180,7 +179,6 @@ func (kp *DexKeeper) matchAndDistributeTradesForSymbol(symbol string, orderKeepe } } - // Run as postConsume procedure of async, no concurrent updates of orders map func updateOrderMsg(order *OrderInfo, cumQty, height, timestamp int64) { order.CumQty = cumQty diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index a1dcb29e7..6a94f6e8f 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -57,7 +57,7 @@ func MakeKeeper(cdc *wire.Codec) *DexKeeper { codespacer := sdk.NewCodespacer() pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) keeper := NewDexKeeper(common.DexStoreKey, pairMapper, codespacer.RegisterNext(dextypes.DefaultCodespace), - cdc,accKeeper, true, 2) + cdc, accKeeper, true, 2) return keeper } @@ -551,7 +551,7 @@ func setup() (ctx sdk.Context, mapper auth.AccountKeeper, keeper *DexKeeper) { pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) - keeper = NewDexKeeper(capKey2, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc,mapper, false, 2) + keeper = NewDexKeeper(capKey2, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc, mapper, false, 2) return } diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 0bb25144c..3e46e63ba 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -2,13 +2,14 @@ package order import ( "fmt" + "strings" + "sync" + bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" dexUtils "github.com/binance-chain/node/plugins/dex/utils" sdk "github.com/cosmos/cosmos-sdk/types" - "strings" - "sync" ) const ( @@ -35,7 +36,7 @@ func NewMiniOrderKeeper() IDexOrderKeeper { roundOrders: make(map[string][]string, 256), roundIOCOrders: make(map[string][]string, 256), logger: logger, - symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)},}, + symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}}, } } diff --git a/plugins/dex/order/quickselect.go b/plugins/dex/order/quickselect.go index 08ca407d0..70836faae 100644 --- a/plugins/dex/order/quickselect.go +++ b/plugins/dex/order/quickselect.go @@ -1,17 +1,15 @@ package order - //Find and return top K symbols with largest number of order. // The returned top K slice is not sorted. The input orderNums may be re-ordered in place. // If more than one symbols have same order numbers, these symbol will be selected by ascending alphabetical sequence. func findTopKLargest(orderNums []*SymbolWithOrderNumber, k int) []*SymbolWithOrderNumber { - if k>=len(orderNums) { + if k >= len(orderNums) { return orderNums } return quickselect(orderNums, 0, len(orderNums)-1, k) } - func partition(orderNums []*SymbolWithOrderNumber, start, end, pivot int) int { // move pivot to end orderNums[end], orderNums[pivot] = orderNums[pivot], orderNums[end] @@ -32,7 +30,7 @@ func partition(orderNums []*SymbolWithOrderNumber, start, end, pivot int) int { func compare(orderNumA *SymbolWithOrderNumber, orderNumB *SymbolWithOrderNumber) bool { if orderNumA.numberOfOrders > orderNumB.numberOfOrders { return true - }else if orderNumA.numberOfOrders == orderNumB.numberOfOrders { + } else if orderNumA.numberOfOrders == orderNumB.numberOfOrders { return orderNumA.symbol < orderNumB.symbol } return false diff --git a/plugins/dex/order/quickselect_test.go b/plugins/dex/order/quickselect_test.go index ec6eca55d..a7b73434e 100644 --- a/plugins/dex/order/quickselect_test.go +++ b/plugins/dex/order/quickselect_test.go @@ -2,8 +2,9 @@ package order import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func Test_findKthLargest(t *testing.T) { diff --git a/plugins/dex/order/symbol_selector.go b/plugins/dex/order/symbol_selector.go index 6aa0188bf..04538ed16 100644 --- a/plugins/dex/order/symbol_selector.go +++ b/plugins/dex/order/symbol_selector.go @@ -50,7 +50,6 @@ var _ SymbolSelector = &MiniSymbolSelector{ make([]string, 0), } - func (mss *MiniSymbolSelector) GetRoundMatchSymbol() *[]string { return &mss.roundMiniSymbols } diff --git a/plugins/dex/store/codec.go b/plugins/dex/store/codec.go index 572dd17f8..fa4836d3a 100644 --- a/plugins/dex/store/codec.go +++ b/plugins/dex/store/codec.go @@ -2,6 +2,7 @@ package store import ( "fmt" + "github.com/binance-chain/node/plugins/dex/utils" "github.com/cosmos/cosmos-sdk/client/context" @@ -12,10 +13,10 @@ import ( // queryOrderBook queries the store for the serialized order book for a given pair. func queryOrderBook(cdc *wire.Codec, ctx context.CLIContext, pair string, levels int) (*[]byte, error) { var path string - if utils.IsMiniTokenTradingPair(pair){ + if utils.IsMiniTokenTradingPair(pair) { path = fmt.Sprintf("dex_mini/orderbook/%s/%d", pair, levels) } - path =fmt.Sprintf("dex/orderbook/%s/%d", pair, levels) + path = fmt.Sprintf("dex/orderbook/%s/%d", pair, levels) bz, err := ctx.Query(path, nil) if err != nil { return nil, err @@ -48,10 +49,10 @@ func GetOrderBook(cdc *wire.Codec, ctx context.CLIContext, pair string, levels i func queryOpenOrders(cdc *wire.Codec, ctx context.CLIContext, pair string, addr string) (*[]byte, error) { var path string - if utils.IsMiniTokenTradingPair(pair){ + if utils.IsMiniTokenTradingPair(pair) { path = fmt.Sprintf("dex/openorders/%s/%s", pair, addr) } - path =fmt.Sprintf("dex/openorders/%s/%s", pair, addr) + path = fmt.Sprintf("dex/openorders/%s/%s", pair, addr) if bz, err := ctx.Query(path, nil); err != nil { return nil, err } else { diff --git a/plugins/dex/store/utils.go b/plugins/dex/store/utils.go index 294ce7068..b523bd70f 100644 --- a/plugins/dex/store/utils.go +++ b/plugins/dex/store/utils.go @@ -25,7 +25,7 @@ func ValidatePairSymbol(symbol string) error { return errors.New("invalid symbol: trading pair must contain an underscore ('_')") } for _, tokenSymbol := range tokenSymbols { - if types.IsMiniTokenSymbol(tokenSymbol){ + if types.IsMiniTokenSymbol(tokenSymbol) { continue } if err := types.ValidateMapperTokenSymbol(tokenSymbol); err != nil { diff --git a/plugins/dex/utils/pair.go b/plugins/dex/utils/pair.go index 9d6e2afe7..c28525748 100644 --- a/plugins/dex/utils/pair.go +++ b/plugins/dex/utils/pair.go @@ -87,7 +87,7 @@ func Assets2TradingPair(baseAsset, quoteAsset string) (symbol string) { func IsMiniTokenTradingPair(symbol string) bool { baseAsset, quoteAsset, err := TradingPair2Assets(symbol) - if err != nil{ + if err != nil { return false } return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) diff --git a/plugins/miniTokens/client/cli/commands.go b/plugins/miniTokens/client/cli/commands.go index ec497211c..1baee7c1c 100644 --- a/plugins/miniTokens/client/cli/commands.go +++ b/plugins/miniTokens/client/cli/commands.go @@ -27,7 +27,7 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { client.PostCommands( getTokenInfoCmd(cmdr), issueMiniTokenCmd(cmdr), - setTokenURICmd(cmdr),)...) + setTokenURICmd(cmdr))...) miniTokenCmd.AddCommand(client.LineBreak) diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/miniTokens/client/cli/issue.go index 829af40e9..6a0d7776f 100644 --- a/plugins/miniTokens/client/cli/issue.go +++ b/plugins/miniTokens/client/cli/issue.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -12,7 +13,7 @@ import ( ) const ( - flagTokenType = "token-type" + flagTokenType = "token-type" flagTotalSupply = "total-supply" flagTokenName = "token-name" flagMintable = "mintable" @@ -92,7 +93,7 @@ func checkSupplyAmount(amount int64, tokenType int8) error { return errors.New("invalid supply amount") } if amount > types.SupplyRangeType(tokenType).UpperBound() { - return errors.New(fmt.Sprintf("supply amount cannot exceed max supply amount of %s - %d",types.SupplyRangeType(tokenType).String(),types.SupplyRangeType(tokenType).UpperBound())) + return errors.New(fmt.Sprintf("supply amount cannot exceed max supply amount of %s - %d", types.SupplyRangeType(tokenType).String(), types.SupplyRangeType(tokenType).UpperBound())) } return nil } diff --git a/plugins/miniTokens/issue/handler.go b/plugins/miniTokens/issue/handler.go index 35150435b..0c58ad2b5 100644 --- a/plugins/miniTokens/issue/handler.go +++ b/plugins/miniTokens/issue/handler.go @@ -113,5 +113,3 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe Log: fmt.Sprintf("Issued %s", token.Symbol), } } - - diff --git a/plugins/miniTokens/issue/handler_test.go b/plugins/miniTokens/issue/handler_test.go index 853e5ba3f..f8051903a 100644 --- a/plugins/miniTokens/issue/handler_test.go +++ b/plugins/miniTokens/issue/handler_test.go @@ -1,9 +1,10 @@ package issue import ( - "github.com/binance-chain/node/common/upgrade" "testing" + "github.com/binance-chain/node/common/upgrade" + "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/baseapp" diff --git a/plugins/miniTokens/seturi/handler.go b/plugins/miniTokens/seturi/handler.go index d35927bea..ab43543bf 100644 --- a/plugins/miniTokens/seturi/handler.go +++ b/plugins/miniTokens/seturi/handler.go @@ -53,7 +53,6 @@ func handleSetURI(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, msg Se return sdk.ErrInternal(fmt.Sprintf("update token uri failed")).Result() } - logger.Info("finished update token uri") return sdk.Result{ Data: []byte(msg.TokenURI), diff --git a/plugins/miniTokens/seturi/msg.go b/plugins/miniTokens/seturi/msg.go index ab8229b96..684204c60 100644 --- a/plugins/miniTokens/seturi/msg.go +++ b/plugins/miniTokens/seturi/msg.go @@ -14,21 +14,21 @@ const SetURIRoute = "miniTokensSetURI" var _ sdk.Msg = SetURIMsg{} type SetURIMsg struct { - From sdk.AccAddress `json:"from"` - Symbol string `json:"symbol"` - TokenURI string `json:"token_uri"` + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + TokenURI string `json:"token_uri"` } func NewSetUriMsg(from sdk.AccAddress, symbol string, tokenURI string) SetURIMsg { return SetURIMsg{ - From: from, - Symbol: symbol, + From: from, + Symbol: symbol, TokenURI: tokenURI, } } func (msg SetURIMsg) ValidateBasic() sdk.Error { - if msg.From == nil || len(msg.From) == 0{ + if msg.From == nil || len(msg.From) == 0 { return sdk.ErrInvalidAddress("sender address cannot be empty") } diff --git a/plugins/miniTokens/store/mapper.go b/plugins/miniTokens/store/mapper.go index edd2af36f..5a82c2b7b 100644 --- a/plugins/miniTokens/store/mapper.go +++ b/plugins/miniTokens/store/mapper.go @@ -155,7 +155,6 @@ func (m mapper) decodeToken(bz []byte) (token types.MiniToken) { return } - func (m mapper) UpdateTokenURI(ctx sdk.Context, symbol string, uri string) error { if len(symbol) == 0 { return errors.New("symbol cannot be empty") @@ -184,4 +183,3 @@ func (m mapper) UpdateTokenURI(ctx sdk.Context, symbol string, uri string) error } return nil } - diff --git a/plugins/param/types/types.go b/plugins/param/types/types.go index 94e60f696..4acab6873 100644 --- a/plugins/param/types/types.go +++ b/plugins/param/types/types.go @@ -42,7 +42,7 @@ var ( "refundHTLT": {}, "tinyIssueMsg": {}, - "miniIssueMsg": {}, + "miniIssueMsg": {}, "miniTokensSetURI": {}, "dexListMini": {}, } diff --git a/plugins/tokens/client/cli/issue.go b/plugins/tokens/client/cli/issue.go index 14096a60f..b274c16c3 100644 --- a/plugins/tokens/client/cli/issue.go +++ b/plugins/tokens/client/cli/issue.go @@ -92,7 +92,7 @@ func (c Commander) mintToken(cmd *cobra.Command, args []string) error { if err != nil { return err } - }else { + } else { err = types.ValidateMapperTokenSymbol(symbol) if err != nil { return err diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 30b051d66..e08005f1e 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -103,9 +103,9 @@ func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenM return sdk.ErrInsufficientCoins("do not have enough token to freeze").Result() } - useAllBalance := coins.AmountOf(symbol) == freezeAmount + useAllBalance := coins.AmountOf(symbol) == freezeAmount - if msg.Amount<=0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinTotalSupply)){ + if msg.Amount <= 0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinTotalSupply)) { logger.Info(errLogMsg, "reason", "freeze amount doesn't reach the min supply") return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", common.MiniTokenMinTotalSupply)).Result() @@ -127,7 +127,7 @@ func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniToke logger := log.With("module", "miniToken", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) frozenAmount := account.GetFrozenCoins().AmountOf(symbol) - useAllFrozenBalance := frozenAmount == unfreezeAmount + useAllFrozenBalance := frozenAmount == unfreezeAmount errLogMsg := "unfreeze token failed" _, err := miniTokenMapper.GetToken(ctx, symbol) @@ -136,7 +136,7 @@ func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniToke return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() } - if unfreezeAmount<=0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinTotalSupply)) { + if unfreezeAmount <= 0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinTotalSupply)) { logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", common.MiniTokenMinTotalSupply)).Result() @@ -156,4 +156,3 @@ func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniToke logger.Debug("finish unfreezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) return sdk.Result{} } - diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index ae3c0aac8..62a2d3407 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -3,11 +3,12 @@ package issue import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" "reflect" "strconv" "strings" + "github.com/binance-chain/node/common/upgrade" + "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index ecd5a95bb..4d062310a 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -1,9 +1,10 @@ package issue import ( - "github.com/binance-chain/node/common/upgrade" "testing" + "github.com/binance-chain/node/common/upgrade" + "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/baseapp" @@ -108,7 +109,6 @@ func TestHandleMintToken(t *testing.T) { require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "cannot mint native token") } - func TestHandleMintMiniToken(t *testing.T) { setChainVersion() defer resetChainVersion() @@ -130,7 +130,7 @@ func TestHandleMintMiniToken(t *testing.T) { require.Equal(t, *expectedToken, token) _, err = tokenMapper.GetToken(ctx, "NNB-000M") - require.NotNil(t,err) + require.NotNil(t, err) require.Contains(t, err.Error(), "token(NNB-000M) not found") sdkResult = handler(ctx, mintMsg) @@ -160,4 +160,3 @@ func TestHandleMintMiniToken(t *testing.T) { invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "cannot mint native token") } - diff --git a/plugins/tokens/plugin.go b/plugins/tokens/plugin.go index cd7833abb..eb60bacdd 100644 --- a/plugins/tokens/plugin.go +++ b/plugins/tokens/plugin.go @@ -10,9 +10,9 @@ import ( bnclog "github.com/binance-chain/node/common/log" app "github.com/binance-chain/node/common/types" + miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" - miniToken "github.com/binance-chain/node/plugins/minitokens" ) const abciQueryPrefix = "tokens" diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index 505a60c61..48c672810 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -6,7 +6,9 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/binance-chain/node/common/types" + ) func NewHandler(kp Keeper) sdk.Handler { From 36fd5f5180c82b636209e920236fbeda2fd372bb Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 8 May 2020 17:34:32 +0800 Subject: [PATCH 21/96] fix ut --- app/pub/keeper_pub_test.go | 87 ++++++++++--------- app_test/utils_test.go | 2 +- networks/publisher/ordergen.sh | 2 +- plugins/dex/aliases.go | 2 - plugins/dex/list/handler_test.go | 10 +-- plugins/dex/order/mini_keeper.go | 2 +- plugins/dex/store/mapper_test.go | 2 +- plugins/{miniTokens => minitokens}/abci.go | 0 .../client/cli/commands.go | 0 .../client/cli/helper.go | 0 .../client/cli/info.go | 0 .../client/cli/issue.go | 0 .../client/cli/seturi.go | 0 .../issue/handler.go | 6 +- .../issue/handler_test.go | 30 ++++--- .../{miniTokens => minitokens}/issue/msg.go | 0 .../{miniTokens => minitokens}/mini_tokens.go | 0 plugins/{miniTokens => minitokens}/plugin.go | 0 plugins/{miniTokens => minitokens}/route.go | 0 .../seturi/handler.go | 0 .../{miniTokens => minitokens}/seturi/msg.go | 0 .../store/mapper.go | 0 plugins/{miniTokens => minitokens}/wire.go | 0 plugins/tokens/issue/handler_test.go | 21 +++-- plugins/tokens/swap/handler.go | 1 - plugins/tokens/swap/handler_test.go | 12 +-- 26 files changed, 94 insertions(+), 83 deletions(-) rename plugins/{miniTokens => minitokens}/abci.go (100%) rename plugins/{miniTokens => minitokens}/client/cli/commands.go (100%) rename plugins/{miniTokens => minitokens}/client/cli/helper.go (100%) rename plugins/{miniTokens => minitokens}/client/cli/info.go (100%) rename plugins/{miniTokens => minitokens}/client/cli/issue.go (100%) rename plugins/{miniTokens => minitokens}/client/cli/seturi.go (100%) rename plugins/{miniTokens => minitokens}/issue/handler.go (96%) rename plugins/{miniTokens => minitokens}/issue/handler_test.go (69%) rename plugins/{miniTokens => minitokens}/issue/msg.go (100%) rename plugins/{miniTokens => minitokens}/mini_tokens.go (100%) rename plugins/{miniTokens => minitokens}/plugin.go (100%) rename plugins/{miniTokens => minitokens}/route.go (100%) rename plugins/{miniTokens => minitokens}/seturi/handler.go (100%) rename plugins/{miniTokens => minitokens}/seturi/msg.go (100%) rename plugins/{miniTokens => minitokens}/store/mapper.go (100%) rename plugins/{miniTokens => minitokens}/wire.go (100%) diff --git a/app/pub/keeper_pub_test.go b/app/pub/keeper_pub_test.go index 287368c82..5805d2c96 100644 --- a/app/pub/keeper_pub_test.go +++ b/app/pub/keeper_pub_test.go @@ -92,7 +92,7 @@ func TestKeeper_AddOrder(t *testing.T) { require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 2) // verify order0 - and the order in orderchanges slice - orderChange0 := keeper.GetOrderChanges()[0] + orderChange0 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[0] assert.Equal("1", orderChange0.Id) assert.Equal(orderPkg.Ack, orderChange0.Tpe) @@ -117,17 +117,18 @@ func TestKeeper_IOCExpireWithFee(t *testing.T) { msg := orderPkg.NewOrderMsg{buyer, "1", "XYZ-000_BNB", orderPkg.OrderType.LIMIT, orderPkg.Side.BUY, 102000, 3000000, orderPkg.TimeInForce.IOC} keeper.AddOrder(orderPkg.OrderInfo{msg, 42, 100, 42, 100, 0, "08E19B16880CF70D59DDD996E3D75C66CD0405DE", 0}, false) - require.Len(keeper.OrderChanges, 1) - require.Len(keeper.OrderInfosForPub, 1) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 1) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 1) - trades := MatchAndAllocateAllForPublish(keeper, nil, ctx, false) + trades, miniTrades := MatchAndAllocateAllForPublish(keeper, ctx, false) - require.Len(keeper.OrderChanges, 2) - require.Len(keeper.OrderInfosForPub, 1) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 1) require.Len(trades, 0) + require.Len(miniTrades, 0) - orderChange0 := keeper.OrderChanges[0] - orderChange1 := keeper.OrderChanges[1] + orderChange0 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[0] + orderChange1 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[1] // verify orderChange0 - Ack assert.Equal("1", orderChange0.Id) assert.Equal(orderPkg.Ack, orderChange0.Tpe) @@ -143,17 +144,17 @@ func TestKeeper_ExpireWithFee(t *testing.T) { msg := orderPkg.NewOrderMsg{buyer, "1", "XYZ-000_BNB", orderPkg.OrderType.LIMIT, orderPkg.Side.BUY, 102000, 3000000, orderPkg.TimeInForce.GTE} keeper.AddOrder(orderPkg.OrderInfo{msg, 42, 100, 42, 100, 0, "08E19B16880CF70D59DDD996E3D75C66CD0405DE", 0}, false) - require.Len(keeper.OrderChanges, 1) - require.Len(keeper.OrderInfosForPub, 1) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 1) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 1) breathTime := prepareExpire(int64(43)) ExpireOrdersForPublish(keeper, ctx, breathTime) - require.Len(keeper.OrderChanges, 2) - require.Len(keeper.OrderInfosForPub, 1) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 1) - orderChange0 := keeper.OrderChanges[0] - orderChange1 := keeper.OrderChanges[1] + orderChange0 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[0] + orderChange1 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[1] // verify orderChange0 - Ack assert.Equal("1", orderChange0.Id) assert.Equal(orderPkg.Ack, orderChange0.Tpe) @@ -168,16 +169,16 @@ func TestKeeper_DelistWithFee(t *testing.T) { msg := orderPkg.NewOrderMsg{buyer, "1", "XYZ-000_BNB", orderPkg.OrderType.LIMIT, orderPkg.Side.BUY, 102000, 3000000, orderPkg.TimeInForce.GTE} keeper.AddOrder(orderPkg.OrderInfo{msg, 42, 100, 42, 100, 0, "08E19B16880CF70D59DDD996E3D75C66CD0405DE", 0}, false) - require.Len(keeper.OrderChanges, 1) - require.Len(keeper.OrderInfosForPub, 1) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 1) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 1) DelistTradingPairForPublish(ctx, keeper, "XYZ-000_BNB") - require.Len(keeper.OrderChanges, 2) - require.Len(keeper.OrderInfosForPub, 1) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 1) - orderChange0 := keeper.OrderChanges[0] - orderChange1 := keeper.OrderChanges[1] + orderChange0 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[0] + orderChange1 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[1] // verify orderChange0 - Ack assert.Equal("1", orderChange0.Id) @@ -195,10 +196,10 @@ func Test_IOCPartialExpire(t *testing.T) { msg2 := orderPkg.NewOrderMsg{seller, "s-1", "XYZ-000_BNB", orderPkg.OrderType.LIMIT, orderPkg.Side.SELL, 100000000, 100000000, orderPkg.TimeInForce.GTE} keeper.AddOrder(orderPkg.OrderInfo{msg2, 42, 100, 42, 100, 0, "", 0}, false) - require.Len(keeper.OrderChanges, 2) - require.Len(keeper.OrderInfosForPub, 2) - orderChange0 := keeper.OrderChanges[0] - orderChange1 := keeper.OrderChanges[1] + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 2) + orderChange0 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[0] + orderChange1 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[1] // verify orderChange0 - Ack assert.Equal("b-1", orderChange0.Id) assert.Equal(orderPkg.Ack, orderChange0.Tpe) @@ -206,10 +207,10 @@ func Test_IOCPartialExpire(t *testing.T) { assert.Equal("s-1", orderChange1.Id) assert.Equal(orderPkg.Ack, orderChange1.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, nil, ctx, false) + trades, _ := MatchAndAllocateAllForPublish(keeper, ctx, false) - require.Len(keeper.OrderChanges, 3) - require.Len(keeper.OrderInfosForPub, 2) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 3) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 2) require.Len(trades, 1) trade0 := trades[0] assert.Equal("0-0", trade0.Id) @@ -219,7 +220,7 @@ func Test_IOCPartialExpire(t *testing.T) { assert.Equal("s-1", trade0.Sid) assert.Equal("b-1", trade0.Bid) - orderChange2 := keeper.OrderChanges[2] + orderChange2 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[2] assert.Equal("b-1", orderChange2.Id) assert.Equal(orderPkg.IocExpire, orderChange2.Tpe) @@ -235,10 +236,10 @@ func Test_GTEPartialExpire(t *testing.T) { msg2 := orderPkg.NewOrderMsg{seller, "s-1", "XYZ-000_BNB", orderPkg.OrderType.LIMIT, orderPkg.Side.SELL, 100000000, 300000000, orderPkg.TimeInForce.GTE} keeper.AddOrder(orderPkg.OrderInfo{msg2, 42, 100, 42, 100, 0, "", 0}, false) - require.Len(keeper.OrderChanges, 2) - require.Len(keeper.OrderInfosForPub, 2) - orderChange0 := keeper.OrderChanges[0] - orderChange1 := keeper.OrderChanges[1] + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 2) + orderChange0 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[0] + orderChange1 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[1] // verify orderChange0 - Ack assert.Equal("b-1", orderChange0.Id) assert.Equal(orderPkg.Ack, orderChange0.Tpe) @@ -246,7 +247,7 @@ func Test_GTEPartialExpire(t *testing.T) { assert.Equal("s-1", orderChange1.Id) assert.Equal(orderPkg.Ack, orderChange1.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, nil, ctx, false) + trades, _ := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(trades, 1) trade0 := trades[0] assert.Equal("0-0", trade0.Id) @@ -259,15 +260,15 @@ func Test_GTEPartialExpire(t *testing.T) { assert.Equal("BNB:50000", keeper.RoundOrderFees[string(buyer.Bytes())].String()) assert.Equal("BNB:50000", keeper.RoundOrderFees[string(seller.Bytes())].String()) - require.Len(keeper.OrderChanges, 2) // for GTE order, fully fill is not derived from transfer (will be generated by trade) - require.Len(keeper.OrderInfosForPub, 2) + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) // for GTE order, fully fill is not derived from transfer (will be generated by trade) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 2) // let the sell order expire breathTime := prepareExpire(int64(43)) ExpireOrdersForPublish(keeper, ctx, breathTime) - require.Len(keeper.OrderChanges, 3) - orderChange2 := keeper.OrderChanges[2] + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 3) + orderChange2 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[2] assert.Equal("s-1", orderChange2.Id) assert.Equal(orderPkg.Expired, orderChange2.Tpe) } @@ -282,11 +283,11 @@ func Test_OneBuyVsTwoSell(t *testing.T) { msg3 := orderPkg.NewOrderMsg{seller, "s-2", "XYZ-000_BNB", orderPkg.OrderType.LIMIT, orderPkg.Side.SELL, 100000000, 200000000, orderPkg.TimeInForce.GTE} keeper.AddOrder(orderPkg.OrderInfo{msg3, 42, 100, 42, 100, 0, "", 0}, false) - require.Len(keeper.OrderChanges, 3) - require.Len(keeper.OrderInfosForPub, 3) - orderChange0 := keeper.OrderChanges[0] - orderChange1 := keeper.OrderChanges[1] - orderChange2 := keeper.OrderChanges[2] + require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 3) + require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 3) + orderChange0 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[0] + orderChange1 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[1] + orderChange2 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[2] // verify orderChange0 - Ack assert.Equal("b-1", orderChange0.Id) assert.Equal(orderPkg.Ack, orderChange0.Tpe) @@ -297,7 +298,7 @@ func Test_OneBuyVsTwoSell(t *testing.T) { assert.Equal("s-2", orderChange2.Id) assert.Equal(orderPkg.Ack, orderChange2.Tpe) - trades := MatchAndAllocateAllForPublish(keeper, nil, ctx, false) + trades, _ := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(trades, 2) trade0 := trades[0] assert.Equal("0-0", trade0.Id) diff --git a/app_test/utils_test.go b/app_test/utils_test.go index 20269c754..d0d34e497 100644 --- a/app_test/utils_test.go +++ b/app_test/utils_test.go @@ -24,7 +24,7 @@ import ( // this file has to named with suffix _test, this is a golang bug: https://github.com/golang/go/issues/24895 var ( - keeper *orderPkg.BEP2OrderKeeper + keeper *orderPkg.DexKeeper buyer sdk.AccAddress seller sdk.AccAddress am auth.AccountKeeper diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index ca9c610df..22f12372a 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -38,7 +38,7 @@ function random() while : do side=$(random 1 2) - price=$(random 1 2) + price=$(random 1 4) qty=$(random 1 2) pause=$(random 5 7) symbolNum=$(random 1 10) diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index 6df7171bb..a07348394 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -10,8 +10,6 @@ import ( // type TradingPair = types.TradingPair type TradingPairMapper = store.TradingPairMapper -type BEP2OrderKeeper = order.BEP2OrderKeeper -type MiniOrderKeeper = order.MiniOrderKeeper type IDexOrderKeeper = order.IDexOrderKeeper type DexKeeper = order.DexKeeper type SymbolPairType = order.SymbolPairType diff --git a/plugins/dex/list/handler_test.go b/plugins/dex/list/handler_test.go index 401d3a24a..fd1762df8 100644 --- a/plugins/dex/list/handler_test.go +++ b/plugins/dex/list/handler_test.go @@ -42,7 +42,7 @@ func MakeCodec() *codec.Codec { return cdc } -func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, orderKeeper *order.BEP2OrderKeeper, tokenMapper tokenStore.Mapper, govKeeper gov.Keeper) { +func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, dexKeeper *order.DexKeeper, tokenMapper tokenStore.Mapper, govKeeper gov.Keeper) { accKey := sdk.NewKVStoreKey("acc") pairKey := sdk.NewKVStoreKey("pair") tokenKey := sdk.NewKVStoreKey("token") @@ -64,9 +64,9 @@ func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, orderKeeper *o accKeeper := auth.NewAccountKeeper(cdc, accKey, types.ProtoAppAccount) codespacer := sdk.NewCodespacer() - pairMapper := store.NewTradingPairMapper(cdc, pairKey, false) - orderKeeper = order.NewBEP2OrderKeeper(common.DexStoreKey, accKeeper, pairMapper, - codespacer.RegisterNext(dexTypes.DefaultCodespace), 2, cdc, false) + pairMapper := store.NewTradingPairMapper(cdc, pairKey) + dexKeeper = order.NewDexKeeper(common.DexStoreKey, pairMapper, + codespacer.RegisterNext(dexTypes.DefaultCodespace), cdc, accKeeper, false, 2) tokenMapper = tokenStore.NewMapper(cdc, tokenKey) @@ -85,7 +85,7 @@ func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, orderKeeper *o gov.DefaultCodespace, new(sdk.Pool)) - return ms, orderKeeper, tokenMapper, govKeeper + return ms, dexKeeper, tokenMapper, govKeeper } func getProposal(lowerCase bool, baseAssetSymbol string, quoteAssetSymbol string) gov.Proposal { diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 3e46e63ba..aa3e9043b 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -24,7 +24,7 @@ type MiniOrderKeeper struct { var _ IDexOrderKeeper = &MiniOrderKeeper{} -// NewBEP2OrderKeeper - Returns the MiniToken BEP2OrderKeeper +// NewBEP2OrderKeeper - Returns the MiniToken orderKeeper func NewMiniOrderKeeper() IDexOrderKeeper { logger := bnclog.With("module", "dexMiniKeeper") return &MiniOrderKeeper{ diff --git a/plugins/dex/store/mapper_test.go b/plugins/dex/store/mapper_test.go index 56ebe1cdc..3bef25063 100644 --- a/plugins/dex/store/mapper_test.go +++ b/plugins/dex/store/mapper_test.go @@ -24,7 +24,7 @@ func setup() (TradingPairMapper, sdk.Context) { var cdc = wire.NewCodec() cdc.RegisterConcrete(dextypes.TradingPair{}, "dex/TradingPair", nil) cdc.RegisterConcrete(RecentPrice{}, "dex/RecentPrice", nil) - return NewTradingPairMapper(cdc, key, false), ctx + return NewTradingPairMapper(cdc, key), ctx } func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) { diff --git a/plugins/miniTokens/abci.go b/plugins/minitokens/abci.go similarity index 100% rename from plugins/miniTokens/abci.go rename to plugins/minitokens/abci.go diff --git a/plugins/miniTokens/client/cli/commands.go b/plugins/minitokens/client/cli/commands.go similarity index 100% rename from plugins/miniTokens/client/cli/commands.go rename to plugins/minitokens/client/cli/commands.go diff --git a/plugins/miniTokens/client/cli/helper.go b/plugins/minitokens/client/cli/helper.go similarity index 100% rename from plugins/miniTokens/client/cli/helper.go rename to plugins/minitokens/client/cli/helper.go diff --git a/plugins/miniTokens/client/cli/info.go b/plugins/minitokens/client/cli/info.go similarity index 100% rename from plugins/miniTokens/client/cli/info.go rename to plugins/minitokens/client/cli/info.go diff --git a/plugins/miniTokens/client/cli/issue.go b/plugins/minitokens/client/cli/issue.go similarity index 100% rename from plugins/miniTokens/client/cli/issue.go rename to plugins/minitokens/client/cli/issue.go diff --git a/plugins/miniTokens/client/cli/seturi.go b/plugins/minitokens/client/cli/seturi.go similarity index 100% rename from plugins/miniTokens/client/cli/seturi.go rename to plugins/minitokens/client/cli/seturi.go diff --git a/plugins/miniTokens/issue/handler.go b/plugins/minitokens/issue/handler.go similarity index 96% rename from plugins/miniTokens/issue/handler.go rename to plugins/minitokens/issue/handler.go index 0c58ad2b5..b66d0aeb2 100644 --- a/plugins/miniTokens/issue/handler.go +++ b/plugins/minitokens/issue/handler.go @@ -62,10 +62,10 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe common.MiniTokenMinTotalSupply)).Result() } - if msg.TotalSupply > common.MiniTokenSupplyUpperBound { + if msg.TotalSupply > common.SupplyRangeType(msg.TokenType).UpperBound() { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply upperbound is %d", - common.MiniTokenSupplyUpperBound)).Result() + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply is %d", + common.SupplyRangeType(msg.TokenType).UpperBound())).Result() } // the symbol is suffixed with the first n bytes of the tx hash symbol = fmt.Sprintf("%s-%s", symbol, suffix) diff --git a/plugins/miniTokens/issue/handler_test.go b/plugins/minitokens/issue/handler_test.go similarity index 69% rename from plugins/miniTokens/issue/handler_test.go rename to plugins/minitokens/issue/handler_test.go index f8051903a..b33533aae 100644 --- a/plugins/miniTokens/issue/handler_test.go +++ b/plugins/minitokens/issue/handler_test.go @@ -52,27 +52,37 @@ func TestHandleIssueToken(t *testing.T) { _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100001e8, 100000e8, false, "http://www.xyz.com/nnb.json") + msg := NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8+100, false, "http://www.xyz.com/nnb.json") sdkResult := handler(ctx, msg) require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "max total supply is too large") + require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, 10000e8+100, false, "http://www.xyz.com/nnb.json") - sdkResult = handler(ctx, msg) - require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply is") - - ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100000e8, 100000e8, false, "http://www.xyz.com/nnb.json") + msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") sdkResult = handler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 100000e8, 100000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, token) sdkResult = handler(ctx, msg) require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + msg = NewIssueMsg(acc.GetAddress(), "New BB", "NBB", 2, 100000e8+100, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + msg = NewIssueMsg(acc.GetAddress(), "New BB", "NBB", 2, 10000e8+100, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err = tokenMapper.GetToken(ctx, "NBB-002M") + require.NoError(t, err) + expectedToken, err = types.NewMiniToken("New BB", "NBB-002M", 2, 10000e8+100, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, token) } diff --git a/plugins/miniTokens/issue/msg.go b/plugins/minitokens/issue/msg.go similarity index 100% rename from plugins/miniTokens/issue/msg.go rename to plugins/minitokens/issue/msg.go diff --git a/plugins/miniTokens/mini_tokens.go b/plugins/minitokens/mini_tokens.go similarity index 100% rename from plugins/miniTokens/mini_tokens.go rename to plugins/minitokens/mini_tokens.go diff --git a/plugins/miniTokens/plugin.go b/plugins/minitokens/plugin.go similarity index 100% rename from plugins/miniTokens/plugin.go rename to plugins/minitokens/plugin.go diff --git a/plugins/miniTokens/route.go b/plugins/minitokens/route.go similarity index 100% rename from plugins/miniTokens/route.go rename to plugins/minitokens/route.go diff --git a/plugins/miniTokens/seturi/handler.go b/plugins/minitokens/seturi/handler.go similarity index 100% rename from plugins/miniTokens/seturi/handler.go rename to plugins/minitokens/seturi/handler.go diff --git a/plugins/miniTokens/seturi/msg.go b/plugins/minitokens/seturi/msg.go similarity index 100% rename from plugins/miniTokens/seturi/msg.go rename to plugins/minitokens/seturi/msg.go diff --git a/plugins/miniTokens/store/mapper.go b/plugins/minitokens/store/mapper.go similarity index 100% rename from plugins/miniTokens/store/mapper.go rename to plugins/minitokens/store/mapper.go diff --git a/plugins/miniTokens/wire.go b/plugins/minitokens/wire.go similarity index 100% rename from plugins/miniTokens/wire.go rename to plugins/minitokens/wire.go diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 4d062310a..acd49fde3 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -114,11 +114,11 @@ func TestHandleMintMiniToken(t *testing.T) { defer resetChainVersion() ctx, handler, miniTokenHandler, accountKeeper, tokenMapper, miniTokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) - mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 10000e8) + mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1001e8) sdkResult := handler(ctx, mintMsg) require.Contains(t, sdkResult.Log, "symbol(NNB-000M) does not exist") - issueMsg := miniIssue.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 100000e8, 90000e8, true, "http://www.xyz.com/nnb.json") + issueMsg := miniIssue.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 9000e8, true, "http://www.xyz.com/nnb.json") ctx = ctx.WithValue(baseapp.TxHashKey, "000") sdkResult = miniTokenHandler(ctx, issueMsg) require.Equal(t, true, sdkResult.Code.IsOK()) @@ -126,7 +126,7 @@ func TestHandleMintMiniToken(t *testing.T) { sdkResult = handler(ctx, mintMsg) token, err := miniTokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 100000e8, 100000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 9000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, token) _, err = tokenMapper.GetToken(ctx, "NNB-000M") @@ -137,22 +137,25 @@ func TestHandleMintMiniToken(t *testing.T) { require.Equal(t, false, sdkResult.Code.IsOK()) require.Contains(t, sdkResult.Log, "mint amount is too large") - invalidMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", types.MiniTokenSupplyUpperBound) - sdkResult = handler(ctx, invalidMintMsg) - require.Contains(t, sdkResult.Log, "mint amount is too large") + validMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1000e8) + sdkResult = handler(ctx, validMintMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + token, err = miniTokenMapper.GetToken(ctx, "NNB-000M") + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, token) _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) - invalidMintMsg = NewMintMsg(acc2.GetAddress(), "NNB-000M", types.MiniTokenSupplyUpperBound) + invalidMintMsg := NewMintMsg(acc2.GetAddress(), "NNB-000M", 100e8) sdkResult = handler(ctx, invalidMintMsg) require.Contains(t, sdkResult.Log, "only the owner can mint token NNB") // issue a non-mintable token - issueMsg = miniIssue.NewIssueMsg(acc.GetAddress(), "New BNB2", "NNB2", 100000e8, 100000e8, false, "http://www.xyz.com/nnb.json") + issueMsg = miniIssue.NewIssueMsg(acc.GetAddress(), "New BNB2", "NNB2", 1, 9000e8, false, "http://www.xyz.com/nnb.json") ctx = ctx.WithValue(baseapp.TxHashKey, "000") sdkResult = miniTokenHandler(ctx, issueMsg) require.Equal(t, true, sdkResult.Code.IsOK()) - mintMsg = NewMintMsg(acc.GetAddress(), "NNB2-000M", 10000e8) + mintMsg = NewMintMsg(acc.GetAddress(), "NNB2-000M", 1000e8) sdkResult = handler(ctx, mintMsg) require.Contains(t, sdkResult.Log, "token(NNB2-000M) cannot be minted") diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index 48c672810..b37193220 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" - ) func NewHandler(kp Keeper) sdk.Handler { diff --git a/plugins/tokens/swap/handler_test.go b/plugins/tokens/swap/handler_test.go index ff23198cc..e40159b3e 100644 --- a/plugins/tokens/swap/handler_test.go +++ b/plugins/tokens/swap/handler_test.go @@ -145,7 +145,7 @@ func TestHandleCreateAndClaimSwapForSingleChain(t *testing.T) { _, acc2 := testutils.NewAccount(ctx, accKeeper, 10000e8) acc2Coins := acc2.GetCoins() - acc2Coins = acc2Coins.Plus(sdk.Coins{sdk.Coin{"ABC", 1000000000000}}) + acc2Coins = acc2Coins.Plus(sdk.Coins{sdk.Coin{"ABC-123", 1000000000000}}) _ = acc2.SetCoins(acc2Coins) accKeeper.SetAccount(ctx, acc2) @@ -169,7 +169,7 @@ func TestHandleCreateAndClaimSwapForSingleChain(t *testing.T) { swapIDStr := strings.Replace(result.Log, "swapID: ", "", -1) swapID, _ := hex.DecodeString(swapIDStr) - amountABC := sdk.Coins{sdk.Coin{"ABC", 100000000}} + amountABC := sdk.Coins{sdk.Coin{"ABC-123", 100000000}} expectedIncome = "10000:BNB" msg = NewDepositHTLTMsg(acc2.GetAddress(), amountABC, swapID) @@ -205,12 +205,12 @@ func TestHandleCreateAndClaimSwapForSingleChain(t *testing.T) { require.Equal(t, Completed, swap.Status) acc1Acc := accKeeper.GetAccount(ctx, acc1.GetAddress()) - require.Equal(t, amountABC[0].Amount, acc1Acc.GetCoins().AmountOf("ABC")) + require.Equal(t, amountABC[0].Amount, acc1Acc.GetCoins().AmountOf("ABC-123")) require.Equal(t, amountBNB[0].Amount, acc1OrignalCoins.AmountOf("BNB")-acc1Acc.GetCoins().AmountOf("BNB")) acc2Acc := accKeeper.GetAccount(ctx, acc2.GetAddress()) require.Equal(t, amountBNB[0].Amount, acc2Acc.GetCoins().AmountOf("BNB")-acc2OrignalCoins.AmountOf("BNB")) - require.Equal(t, amountABC[0].Amount, acc2OrignalCoins.AmountOf("ABC")-acc2Acc.GetCoins().AmountOf("ABC")) + require.Equal(t, amountABC[0].Amount, acc2OrignalCoins.AmountOf("ABC-123")-acc2Acc.GetCoins().AmountOf("ABC-123")) } func TestHandleCreateAndRefundSwapForSingleChain(t *testing.T) { @@ -222,7 +222,7 @@ func TestHandleCreateAndRefundSwapForSingleChain(t *testing.T) { _, acc2 := testutils.NewAccount(ctx, accKeeper, 10000e8) acc2Coins := acc2.GetCoins() - acc2Coins = acc2Coins.Plus(sdk.Coins{sdk.Coin{"ABC", 1000000000000}}) + acc2Coins = acc2Coins.Plus(sdk.Coins{sdk.Coin{"ABC-123", 1000000000000}}) _ = acc2.SetCoins(acc2Coins) accKeeper.SetAccount(ctx, acc2) @@ -246,7 +246,7 @@ func TestHandleCreateAndRefundSwapForSingleChain(t *testing.T) { swapIDStr := strings.Replace(result.Log, "swapID: ", "", -1) swapID, _ := hex.DecodeString(swapIDStr) - amountABC := sdk.Coins{sdk.Coin{"ABC", 100000000}} + amountABC := sdk.Coins{sdk.Coin{"ABC-123", 100000000}} expectedIncome = "10000:BNB" msg = NewDepositHTLTMsg(acc2.GetAddress(), amountABC, swapID) From 9b21c30bb23b496c20327ff6e54fa719b7218722 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 8 May 2020 19:23:42 +0800 Subject: [PATCH 22/96] rename file --- plugins/dex/order/global_keeper.go | 1088 -------------------------- plugins/dex/order/keeper.go | 1175 +++++++++++++++++++++++----- plugins/dex/order/order_keeper.go | 329 ++++++++ 3 files changed, 1296 insertions(+), 1296 deletions(-) delete mode 100644 plugins/dex/order/global_keeper.go create mode 100644 plugins/dex/order/order_keeper.go diff --git a/plugins/dex/order/global_keeper.go b/plugins/dex/order/global_keeper.go deleted file mode 100644 index 8fd6dc0f2..000000000 --- a/plugins/dex/order/global_keeper.go +++ /dev/null @@ -1,1088 +0,0 @@ -package order - -import ( - "errors" - "fmt" - "math" - "strings" - "sync" - "time" - - "github.com/binance-chain/node/common/fees" - "github.com/binance-chain/node/common/utils" - "github.com/binance-chain/node/plugins/dex/store" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - - tmlog "github.com/tendermint/tendermint/libs/log" - - bnclog "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" - "github.com/binance-chain/node/plugins/dex/matcheng" - me "github.com/binance-chain/node/plugins/dex/matcheng" - dexTypes "github.com/binance-chain/node/plugins/dex/types" - dexUtils "github.com/binance-chain/node/plugins/dex/utils" - "github.com/binance-chain/node/plugins/param/paramhub" - paramTypes "github.com/binance-chain/node/plugins/param/types" - "github.com/binance-chain/node/wire" -) - -const ( - BEP2TypeValue = 1 - MiniTypeValue = 2 -) - -type SymbolPairType int8 - -var PairType = struct { - BEP2 SymbolPairType - MINI SymbolPairType -}{BEP2TypeValue, MiniTypeValue} - -type IDexKeeper interface { - InitRecentPrices(ctx sdk.Context) - AddEngine(pair dexTypes.TradingPair) *me.MatchEng - UpdateTickSizeAndLotSize(ctx sdk.Context) - DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) - UpdateLotSize(symbol string, lotSize int64) - AddOrder(info OrderInfo, isRecovery bool) (err error) - RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) - GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) - OrderExists(symbol, id string) (OrderInfo, bool) - GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel - GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder - GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap - GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel - GetLastTrades(height int64, pair string) ([]me.Trade, int64) - GetLastTradesForPair(pair string) ([]me.Trade, int64) - ClearOrderBook(pair string) - ClearOrderChanges() - StoreTradePrices(ctx sdk.Context) - ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) - MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) - GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) - GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 - DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) - CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error - CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error - SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) - LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) - GetPairMapper() store.TradingPairMapper - GetOrderChanges(pairType SymbolPairType) OrderChanges - GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish - GetAllOrders() map[string]map[string]*OrderInfo - GetAllOrdersForPair(symbol string) map[string]*OrderInfo - getAccountKeeper() *auth.AccountKeeper - getLogger() tmlog.Logger - getFeeManager() *FeeManager - GetEngines() map[string]*me.MatchEng - ShouldPublishOrder() bool - UpdateOrderChange(change OrderChange, symbol string) - UpdateOrderChangeSync(change OrderChange, symbol string) - ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error - SelectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string - ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) -} - -type DexKeeper struct { - PairMapper store.TradingPairMapper - storeKey sdk.StoreKey // The key used to access the store from the Context. - codespace sdk.CodespaceType - recentPrices map[string]*utils.FixedSizeRing // symbol -> latest "numPricesStored" prices per "pricesStoreEvery" blocks - am auth.AccountKeeper - FeeManager *FeeManager - RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee - CollectOrderInfoForPublish bool - engines map[string]*me.MatchEng - logger tmlog.Logger - poolSize uint // number of concurrent channels, counted in the pow of 2 - cdc *wire.Codec - OrderKeepers []IDexOrderKeeper -} - -var _ IDexKeeper = &DexKeeper{} - -func NewDexKeeper(key sdk.StoreKey, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, cdc *wire.Codec, am auth.AccountKeeper, collectOrderInfoForPublish bool, concurrency uint) *DexKeeper { - logger := bnclog.With("module", "dex_keeper") - return &DexKeeper{ - PairMapper: tradingPairMapper, - storeKey: key, - codespace: codespace, - recentPrices: make(map[string]*utils.FixedSizeRing, 256), - am: am, - RoundOrderFees: make(map[string]*types.Fee, 256), - FeeManager: NewFeeManager(cdc, logger), - CollectOrderInfoForPublish: collectOrderInfoForPublish, - engines: make(map[string]*me.MatchEng), - poolSize: concurrency, - cdc: cdc, - logger: logger, - OrderKeepers: []IDexOrderKeeper{NewBEP2OrderKeeper(), NewMiniOrderKeeper()}, - } -} - -func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { - return me.NewMatchEng(pairSymbol, basePrice, lotSize, 0.05) -} - -func (kp *DexKeeper) InitRecentPrices(ctx sdk.Context) { - kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) -} - -func (kp *DexKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { - symbol := strings.ToUpper(pair.GetSymbol()) - eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) - kp.engines[symbol] = eng - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.initOrders(symbol) - break - } - } - return eng -} - -func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { - //try update order book first - symbol := strings.ToUpper(info.Symbol) - eng, ok := kp.engines[symbol] - if !ok { - err = fmt.Errorf("match engine of symbol %s doesn't exist", symbol) - return - } - - _, err = eng.Book.InsertOrder(info.Id, info.Side, info.CreatedHeight, info.Price, info.Quantity) - if err != nil { - return err - } - - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) - break - } - } - - kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) - return nil -} - -// deliberately make `fee` parameter not a pointer -// in case we modify the original fee (which will be referenced when distribute to validator) -func (kp *DexKeeper) updateRoundOrderFee(addr string, fee types.Fee) { - if existingFee, ok := kp.RoundOrderFees[addr]; ok { - existingFee.AddFee(fee) - } else { - kp.RoundOrderFees[addr] = &fee - } -} - -func (kp *DexKeeper) ClearRoundFee() { - kp.RoundOrderFees = make(map[string]*types.Fee, 256) -} - -func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( - types.Fee, map[string]*types.Fee) { - if !sdk.IsUpgrade(upgrade.BEP19) { - return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler, kp.engines) - } - - // use string of the addr as the key since map makes a fast path for string key. - // Also, making the key have same length is also an optimization. - tradeTransfers := make(map[string]TradeTransfers) - // expire fee is fixed, so we count by numbers. - expireTransfers := make(map[string]ExpireTransfers) - // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. - var expireEventType transferEventType - var totalFee types.Fee - for tran := range tranCh { - kp.doTransfer(ctx, &tran) - if !tran.FeeFree() { - addrStr := string(tran.accAddress.Bytes()) - // need a copy of tran as it is reused - tranCp := tran - if tran.IsExpiredWithFee() { - expireEventType = tran.eventType - if _, ok := expireTransfers[addrStr]; !ok { - expireTransfers[addrStr] = ExpireTransfers{&tranCp} - } else { - expireTransfers[addrStr] = append(expireTransfers[addrStr], &tranCp) - } - } else if tran.eventType == eventFilled { - if _, ok := tradeTransfers[addrStr]; !ok { - tradeTransfers[addrStr] = TradeTransfers{&tranCp} - } else { - tradeTransfers[addrStr] = append(tradeTransfers[addrStr], &tranCp) - } - } - } else if tran.IsExpire() { - if postAllocateHandler != nil { - postAllocateHandler(tran) - } - } - } - - feesPerAcc := make(map[string]*types.Fee) - for addrStr, trans := range tradeTransfers { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, kp.engines) - if !fees.IsEmpty() { - feesPerAcc[addrStr] = &fees - acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) - kp.am.SetAccount(ctx, acc) - totalFee.AddFee(fees) - } - } - - for addrStr, trans := range expireTransfers { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - - fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, kp.engines, postAllocateHandler) - if !fees.IsEmpty() { - if _, ok := feesPerAcc[addrStr]; ok { - feesPerAcc[addrStr].AddFee(fees) - } else { - feesPerAcc[addrStr] = &fees - } - acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) - kp.am.SetAccount(ctx, acc) - totalFee.AddFee(fees) - } - } - return totalFee, feesPerAcc -} - -func (kp *DexKeeper) allocateAndCalcFee( - ctx sdk.Context, - tradeOuts []chan Transfer, - postAlloTransHandler TransferHandler) types.Fee { - concurrency := len(tradeOuts) - var wg sync.WaitGroup - wg.Add(concurrency) - feesPerCh := make([]types.Fee, concurrency) - feesPerAcc := make([]map[string]*types.Fee, concurrency) - allocatePerCh := func(index int, tranCh <-chan Transfer) { - defer wg.Done() - fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) - feesPerCh[index].AddFee(fee) - feesPerAcc[index] = feeByAcc - } - - for i, tradeTranCh := range tradeOuts { - go allocatePerCh(i, tradeTranCh) - } - wg.Wait() - totalFee := types.Fee{} - for i := 0; i < concurrency; i++ { - totalFee.AddFee(feesPerCh[i]) - } - if kp.CollectOrderInfoForPublish { - for _, m := range feesPerAcc { - for k, v := range m { - kp.updateRoundOrderFee(k, *v) - } - } - } - return totalFee -} - -// DEPRECATED -func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer), engines map[string]*matcheng.MatchEng) ( - types.Fee, map[string]*types.Fee) { - // use string of the addr as the key since map makes a fast path for string key. - // Also, making the key have same length is also an optimization. - tradeInAsset := make(map[string]*sortedAsset) - // expire fee is fixed, so we count by numbers. - expireInAsset := make(map[string]*sortedAsset) - // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. - var expireEventType transferEventType - var totalFee types.Fee - for tran := range tranCh { - kp.doTransfer(ctx, &tran) - if !tran.FeeFree() { - addrStr := string(tran.accAddress.Bytes()) - if tran.IsExpiredWithFee() { - expireEventType = tran.eventType - fees, ok := expireInAsset[addrStr] - if !ok { - fees = &sortedAsset{} - expireInAsset[addrStr] = fees - } - fees.addAsset(tran.inAsset, 1) - } else if tran.eventType == eventFilled { - fees, ok := tradeInAsset[addrStr] - if !ok { - fees = &sortedAsset{} - tradeInAsset[addrStr] = fees - } - // no possible to overflow, for tran.in == otherSide.tran.out <= TotalSupply(otherSide.tran.outAsset) - fees.addAsset(tran.inAsset, tran.in) - } - } - if postAllocateHandler != nil { - postAllocateHandler(tran) - } - } - - feesPerAcc := make(map[string]*types.Fee) - collectFee := func(assetsMap map[string]*sortedAsset, calcFeeAndDeduct func(acc sdk.Account, in sdk.Coin) types.Fee) { - for addrStr, assets := range assetsMap { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - - var fees types.Fee - if exists, ok := feesPerAcc[addrStr]; ok { - fees = *exists - } - if assets.native != 0 { - fee := calcFeeAndDeduct(acc, sdk.NewCoin(types.NativeTokenSymbol, assets.native)) - fees.AddFee(fee) - totalFee.AddFee(fee) - } - for _, asset := range assets.tokens { - fee := calcFeeAndDeduct(acc, asset) - fees.AddFee(fee) - totalFee.AddFee(fee) - } - if !fees.IsEmpty() { - feesPerAcc[addrStr] = &fees - kp.am.SetAccount(ctx, acc) - } - } - } - collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { - fee := kp.FeeManager.CalcTradeFee(acc.GetCoins(), in, engines) - acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - return fee - }) - collectFee(expireInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { - var i int64 = 0 - var fees types.Fee - for ; i < in.Amount; i++ { - fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, engines) - acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - fees.AddFee(fee) - } - return fees - }) - return totalFee, feesPerAcc -} - -func (kp *DexKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { - account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) - newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) - // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. - // they should never happen, there would be a severe bug if happen and we have to cancel all orders when app restarts. - if !newLocked.IsNotNegative() { - panic(fmt.Errorf( - "no enough locked tokens to unlock, oid: %s, newLocked: %s, unlock: %d", - tran.Oid, - newLocked.String(), - tran.unlock)) - } - if tran.unlock < tran.out { - panic(errors.New("unlocked tokens cannot cover the expense")) - } - account.SetLockedCoins(newLocked) - accountCoin := account.GetCoins(). - Plus(sdk.Coins{sdk.NewCoin(tran.inAsset, tran.in)}) - if remain := tran.unlock - tran.out; remain > 0 || !sdk.IsUpgrade(upgrade.FixZeroBalance) { - accountCoin = accountCoin.Plus(sdk.Coins{sdk.NewCoin(tran.outAsset, remain)}) - } - account.SetCoins(accountCoin) - - kp.am.SetAccount(ctx, account) - return nil -} - -func (kp *DexKeeper) SubscribeParamChange(hub *paramhub.Keeper) { - hub.SubscribeParamChange( - func(ctx sdk.Context, changes []interface{}) { - for _, c := range changes { - switch change := c.(type) { - case []paramTypes.FeeParam: - feeConfig := ParamToFeeConfig(change) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } - default: - kp.logger.Debug("Receive param changes that not interested.") - } - } - }, - func(context sdk.Context, state paramTypes.GenesisState) { - feeConfig := ParamToFeeConfig(state.FeeGenesis) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } else { - panic("Genesis with no dex fee config ") - } - }, - func(context sdk.Context, iLoad interface{}) { - switch load := iLoad.(type) { - case []paramTypes.FeeParam: - feeConfig := ParamToFeeConfig(load) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } else { - panic("Load with no dex fee config ") - } - default: - kp.logger.Debug("Receive param load that not interested.") - } - }) -} - -func (kp *DexKeeper) UpdateTickSizeAndLotSize(ctx sdk.Context) { - tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) - lotSizeCache := make(map[string]int64) // baseAsset -> lotSize - for _, pair := range tradingPairs { - if prices, ok := kp.recentPrices[pair.GetSymbol()]; ok && prices.Count() >= minimalNumPrices { - priceWMA := dexUtils.CalcPriceWMA(prices) - tickSize, lotSize := kp.determineTickAndLotSize(pair, priceWMA, lotSizeCache) - if tickSize != pair.TickSize.ToInt64() || - lotSize != pair.LotSize.ToInt64() { - ctx.Logger().Info("Updating tick/lotsize", - "pair", pair.GetSymbol(), "old_ticksize", pair.TickSize, "new_ticksize", tickSize, - "old_lotsize", pair.LotSize, "new_lotsize", lotSize) - pair.TickSize = utils.Fixed8(tickSize) - pair.LotSize = utils.Fixed8(lotSize) - kp.PairMapper.AddTradingPair(ctx, pair) - } - kp.UpdateLotSize(pair.GetSymbol(), lotSize) - } else { - // keep the current tick_size/lot_size - continue - } - } -} - -func (kp *DexKeeper) determineTickAndLotSize(pair dexTypes.TradingPair, priceWMA int64, lotSizeCache map[string]int64) (tickSize, lotSize int64) { - tickSize = dexUtils.CalcTickSize(priceWMA) - if !sdk.IsUpgrade(upgrade.LotSizeOptimization) { - lotSize = dexUtils.CalcLotSize(priceWMA) - return - } - if lotSize, cached := lotSizeCache[pair.BaseAssetSymbol]; cached { - return tickSize, lotSize - } - - lotSize = kp.DetermineLotSize(pair.BaseAssetSymbol, pair.QuoteAssetSymbol, priceWMA) - lotSizeCache[pair.BaseAssetSymbol] = lotSize - return -} - -func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) { - var priceAgainstNative int64 - if baseAssetSymbol == types.NativeTokenSymbol { - // price of BNB/BNB is 1e8 - priceAgainstNative = 1e8 - } else if quoteAssetSymbol == types.NativeTokenSymbol { - priceAgainstNative = price - } else { - if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { - priceAgainstNative = dexUtils.CalcPriceWMA(ps) - } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { - wma := dexUtils.CalcPriceWMA(ps) - priceAgainstNative = 1e16 / wma - } else { - // the recentPrices still have not collected any price yet, iff the native pair is listed for less than kp.pricesStoreEvery blocks - if engine, ok := kp.engines[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { - priceAgainstNative = engine.LastTradePrice - } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { - priceAgainstNative = 1e16 / engine.LastTradePrice - } else { - // should not happen - kp.logger.Error("DetermineLotSize failed because no native pair found", "base", baseAssetSymbol, "quote", quoteAssetSymbol) - } - } - } - lotSize = dexUtils.CalcLotSize(priceAgainstNative) - return lotSize -} - -func (kp *DexKeeper) UpdateLotSize(symbol string, lotSize int64) { - eng, ok := kp.engines[symbol] - if !ok { - panic(fmt.Sprintf("match engine of symbol %s doesn't exist", symbol)) - } - eng.LotSize = lotSize -} - -func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { - symbol = strings.ToUpper(symbol) - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - return orderKeeper.removeOrder(kp, id, symbol, postCancelHandler) - } - } - return orderNotFound(symbol, id) -} - -func (kp *DexKeeper) GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) { - symbol = strings.ToUpper(symbol) - _, ok := kp.OrderExists(symbol, id) - if !ok { - return me.OrderPart{}, orderNotFound(symbol, id) - } - eng, ok := kp.engines[symbol] - if !ok { - return me.OrderPart{}, orderNotFound(symbol, id) - } - return eng.Book.GetOrder(id, side, price) -} - -func (kp *DexKeeper) OrderExists(symbol, id string) (OrderInfo, bool) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - return orderKeeper.orderExists(symbol, id) - } - } - return OrderInfo{}, false -} - -func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { - orderbook := make([]store.OrderBookLevel, maxLevels) - - i, j := 0, 0 - - if eng, ok := kp.engines[pair]; ok { - // TODO: check considered bucket splitting? - eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { - orderbook[i].BuyPrice = utils.Fixed8(p.Price) - orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) - i++ - }, - func(p *me.PriceLevel) { - orderbook[j].SellPrice = utils.Fixed8(p.Price) - orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) - j++ - }) - } - return orderbook -} - -func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(msg.Symbol) { - return orderKeeper.validateOrder(kp, context, account, msg) - } - } - return fmt.Errorf("symbol:%s is not supported", msg.Symbol) -} - -func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(pair) { - return orderKeeper.getOpenOrders(pair, addr) - } - } - return make([]store.OpenOrder, 0) -} - -func (kp *DexKeeper) GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap { - var res = make(ChangedPriceLevelsMap) - for pair, eng := range kp.engines { - buys := make(map[int64]int64) - sells := make(map[int64]int64) - res[pair] = ChangedPriceLevelsPerSymbol{buys, sells} - - // TODO: check considered bucket splitting? - eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { - buys[p.Price] = p.TotalLeavesQty() - }, func(p *me.PriceLevel) { - sells[p.Price] = p.TotalLeavesQty() - }) - } - - return res -} - -func (kp *DexKeeper) GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel { - if eng, ok := kp.engines[pair]; ok { - return eng.Book.GetPriceLevel(price, side) - } else { - return nil - } -} - -func (kp *DexKeeper) GetLastTrades(height int64, pair string) ([]me.Trade, int64) { - if eng, ok := kp.engines[pair]; ok { - if eng.LastMatchHeight == height { - return eng.Trades, eng.LastTradePrice - } - } - return nil, 0 -} - -// !!! FOR TEST USE ONLY -func (kp *DexKeeper) GetLastTradesForPair(pair string) ([]me.Trade, int64) { - if eng, ok := kp.engines[pair]; ok { - return eng.Trades, eng.LastTradePrice - } - return nil, 0 -} - -func (kp *DexKeeper) ClearOrderBook(pair string) { - if eng, ok := kp.engines[pair]; ok { - eng.Book.Clear() - } -} - -func (kp *DexKeeper) ClearOrderChanges() { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { - orderKeeper.clearOrderChanges() - } - } -} - -func (kp *DexKeeper) StoreTradePrices(ctx sdk.Context) { - // TODO: check block height != 0 - if ctx.BlockHeight()%pricesStoreEvery == 0 { - lastTradePrices := make(map[string]int64, len(kp.engines)) - for symbol, engine := range kp.engines { - lastTradePrices[symbol] = engine.LastTradePrice - if _, ok := kp.recentPrices[symbol]; !ok { - kp.recentPrices[symbol] = utils.NewFixedSizedRing(numPricesStored) - } - kp.recentPrices[symbol].Push(engine.LastTradePrice) - } - if len(lastTradePrices) != 0 { - kp.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices) - } - } -} - -func (kp *DexKeeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { - allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { - allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) - } - } - size := len(allOrders) - if size == 0 { - kp.logger.Info("No orders to expire") - return nil - } - - // TODO: make effectiveDays configurable - const effectiveDays = 3 - expireHeight, err := kp.GetBreatheBlockHeight(ctx, blockTime, effectiveDays) - if err != nil { - // breathe block not found, that should only happens in in the first three days, just log it and ignore. - kp.logger.Info(err.Error()) - return nil - } - - channelSize := size >> kp.poolSize - concurrency := 1 << kp.poolSize - if size%concurrency != 0 { - channelSize += 1 - } - - transferChs := make([]chan Transfer, concurrency) - for i := range transferChs { - // TODO: channelSize is enough for buffer to facilitate ? - transferChs[i] = make(chan Transfer, channelSize*2) - } - - expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { - engine.Book.RemoveOrders(expireHeight, side, func(ord me.OrderPart) { - // gen transfer - if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { - h := channelHash(ordMsg.Sender, concurrency) - transferChs[h] <- TransferFromExpired(ord, *ordMsg) - // delete from allOrders - delete(orders, ord.Id) - } else { - kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) - } - }) - } - - symbolCh := make(chan string, concurrency) - utils.ConcurrentExecuteAsync(concurrency, - func() { - for symbol := range allOrders { - symbolCh <- symbol - } - close(symbolCh) - }, func() { - for symbol := range symbolCh { - engine := kp.engines[symbol] - orders := allOrders[symbol] - expire(orders, engine, me.BUYSIDE) - expire(orders, engine, me.SELLSIDE) - } - }, func() { - for _, transferCh := range transferChs { - close(transferCh) - } - }) - - return transferChs -} - -func (kp *DexKeeper) ExpireOrders( - ctx sdk.Context, - blockTime time.Time, - postAlloTransHandler TransferHandler, -) { - transferChs := kp.expireOrders(ctx, blockTime) - if transferChs == nil { - return - } - - totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAlloTransHandler) - fees.Pool.AddAndCommitFee("EXPIRE", totalFee) -} - -func (kp *DexKeeper) MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) { - key := utils.Int642Bytes(blockTime.Unix() / utils.SecondsPerDay) - store := ctx.KVStore(kp.storeKey) - bz, err := kp.cdc.MarshalBinaryBare(height) - if err != nil { - panic(err) - } - kp.logger.Debug(fmt.Sprintf("mark breathe block for key: %v (blockTime: %d), value: %v\n", key, blockTime.Unix(), bz)) - store.Set([]byte(key), bz) -} - -func (kp *DexKeeper) GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) { - store := ctx.KVStore(kp.storeKey) - t := timeNow.AddDate(0, 0, -daysBack).Unix() - day := t / utils.SecondsPerDay - bz := store.Get(utils.Int642Bytes(day)) - if bz == nil { - return 0, fmt.Errorf("breathe block not found for day %v", day) - } - - var height int64 - err := kp.cdc.UnmarshalBinaryBare(bz, &height) - if err != nil { - panic(err) - } - return height, nil -} - -func (kp *DexKeeper) GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 { - if blockInterval != 0 { - return (latestBlockHeight / int64(blockInterval)) * int64(blockInterval) - } else { - store := ctx.KVStore(kp.storeKey) - bz := []byte(nil) - for i := 0; i <= daysBack; i++ { - t := timeNow.AddDate(0, 0, -i).Unix() - key := utils.Int642Bytes(t / utils.SecondsPerDay) - bz = store.Get([]byte(key)) - if bz != nil { - kp.logger.Info("Located day to load breathe block height", "epochDay", key) - break - } - } - if bz == nil { - kp.logger.Error("Failed to load the latest breathe block height from", "timeNow", timeNow) - return 0 - } - var height int64 - err := kp.cdc.UnmarshalBinaryBare(bz, &height) - if err != nil { - panic(err) - } - kp.logger.Info("Loaded breathe block height", "height", height) - return height - } -} - -func orderNotFound(symbol, id string) error { - return fmt.Errorf("Failed to find order [%v] on symbol [%v]", id, symbol) -} - -func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportPairType(pairType) { - return orderKeeper.getOrderChanges() - } - } - kp.logger.Error("pairType is not supported %d", pairType) - return make(OrderChanges, 0) -} - -func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.appendOrderChange(change) - return - } - } - kp.logger.Error("symbol is not supported %d", symbol) -} - -func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.appendOrderChangeSync(change) - return - } - } - kp.logger.Error("symbol is not supported %d", symbol) -} - -func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportPairType(pairType) { - return orderKeeper.getOrderInfosForPub() - } - } - kp.logger.Error("pairType is not supported %d", pairType) - return make(OrderInfoForPublish) - -} - -func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { - return kp.PairMapper -} - -func (kp *DexKeeper) getAccountKeeper() *auth.AccountKeeper { - return &kp.am -} - -func (kp *DexKeeper) getLogger() tmlog.Logger { - return kp.logger -} - -func (kp *DexKeeper) getFeeManager() *FeeManager { - return kp.FeeManager -} - -func (kp *DexKeeper) ShouldPublishOrder() bool { - return kp.CollectOrderInfoForPublish -} - -func (kp *DexKeeper) GetEngines() map[string]*me.MatchEng { - return kp.engines -} -func appendAllOrdersMap(ms ...map[string]map[string]*OrderInfo) map[string]map[string]*OrderInfo { - res := make(map[string]map[string]*OrderInfo) - for _, m := range ms { - for k, v := range m { - res[k] = v - } - } - return res -} - -func (kp *DexKeeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { - // trading pair against native token should not be delisted if there is any other trading pair exist - baseAsset = strings.ToUpper(baseAsset) - quoteAsset = strings.ToUpper(quoteAsset) - - if baseAsset == quoteAsset { - return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") - } - - if !kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) { - return fmt.Errorf("trading pair %s_%s does not exist", baseAsset, quoteAsset) - } - - if baseAsset != types.NativeTokenSymbol && quoteAsset != types.NativeTokenSymbol { - return nil - } - - var symbolToCheck string - if baseAsset != types.NativeTokenSymbol { - symbolToCheck = baseAsset - } else { - symbolToCheck = quoteAsset - } - - tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) - for _, pair := range tradingPairs { //TODO - if (pair.BaseAssetSymbol == symbolToCheck && pair.QuoteAssetSymbol != types.NativeTokenSymbol) || - (pair.QuoteAssetSymbol == symbolToCheck && pair.BaseAssetSymbol != types.NativeTokenSymbol) { - return fmt.Errorf("trading pair %s_%s should not exist before delisting %s_%s", - pair.BaseAssetSymbol, pair.QuoteAssetSymbol, baseAsset, quoteAsset) - } - } - - return nil -} - -func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) { - _, ok := kp.engines[symbol] - if !ok { - kp.logger.Error("delist symbol does not exist", "symbol", symbol) - return - } - - transferChs := kp.expireAllOrders(ctx, symbol) - if transferChs != nil { - totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAllocTransHandler) - fees.Pool.AddAndCommitFee(fmt.Sprintf("DELIST_%s", symbol), totalFee) - } - - delete(kp.engines, symbol) - delete(kp.recentPrices, symbol) - - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { - orderKeeper.deleteOrdersForPair(symbol) - break - } - } - - baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol) - err := kp.PairMapper.DeleteTradingPair(ctx, baseAsset, quoteAsset) - if err != nil { - kp.logger.Error("delete trading pair error", "err", err.Error()) - } -} - -func (kp *DexKeeper) expireAllOrders(ctx sdk.Context, symbol string) []chan Transfer { - ordersOfSymbol := make(map[string]*OrderInfo) - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - ordersOfSymbol = orderKeeper.getAllOrdersForPair(symbol) - break - } - } - - orderNum := len(ordersOfSymbol) - if orderNum == 0 { - kp.logger.Info("no orders to expire", "symbol", symbol) - return nil - } - - concurrency := 1 << kp.poolSize - channelSize := orderNum / concurrency - - transferChs := make([]chan Transfer, concurrency) - for i := range transferChs { - transferChs[i] = make(chan Transfer, channelSize) - } - - expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { - _ = engine.Book.RemoveOrders(math.MaxInt64, side, func(ord me.OrderPart) { - // gen transfer - if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { - h := channelHash(ordMsg.Sender, concurrency) - transferChs[h] <- TransferFromExpired(ord, *ordMsg) - } else { - kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) - } - }) - } - - go func() { - engine := kp.engines[symbol] - orders := ordersOfSymbol - expire(orders, engine, me.BUYSIDE) - expire(orders, engine, me.SELLSIDE) - - for _, transferCh := range transferChs { - close(transferCh) - } - }() - - return transferChs -} - -func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { - // trading pair against native token should exist if quote token is not native token - baseAsset = strings.ToUpper(baseAsset) - quoteAsset = strings.ToUpper(quoteAsset) - - if baseAsset == quoteAsset { - return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") - } - - if kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) || kp.PairMapper.Exists(ctx, quoteAsset, baseAsset) { - return errors.New("trading pair exists") - } - - if baseAsset != types.NativeTokenSymbol && - quoteAsset != types.NativeTokenSymbol { - - if !kp.PairMapper.Exists(ctx, baseAsset, types.NativeTokenSymbol) && - !kp.PairMapper.Exists(ctx, types.NativeTokenSymbol, baseAsset) { - return fmt.Errorf("token %s should be listed against BNB before against %s", - baseAsset, quoteAsset) - } - - if !kp.PairMapper.Exists(ctx, quoteAsset, types.NativeTokenSymbol) && - !kp.PairMapper.Exists(ctx, types.NativeTokenSymbol, quoteAsset) { - return fmt.Errorf("token %s should be listed against BNB before listing %s against %s", - quoteAsset, baseAsset, quoteAsset) - } - } - - if isMiniSymbolPair(baseAsset, quoteAsset) && types.NativeTokenSymbol != quoteAsset { //todo permit BUSD - return errors.New("quote token is not valid for mini symbol pair: " + quoteAsset) - } - - return nil -} - -func (kp *DexKeeper) ClearAfterMatch() { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { - orderKeeper.clearAfterMatch() - } - } -} - -func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { - allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { - allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) - } - } - return allOrders -} - -func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo { - ordersOfSymbol := make(map[string]*OrderInfo) - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - ordersOfSymbol = orderKeeper.getAllOrdersForPair(symbol) - break - } - } - return ordersOfSymbol -} - -func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) - return - } - } -} - -func isMiniSymbolPair(baseAsset, quoteAsset string) bool { - if sdk.IsUpgradeHeight(upgrade.BEP8) { - return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) - } - return false -} - -// channelHash() will choose a channel for processing by moding -// the sum of the last 7 bytes of address by bucketNumber. -// It may not be fully even. -// TODO: there is still concern on peroformance and evenness. -func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { - l := len(accAddress) - sum := 0 - for i := l - 7; i < l; i++ { - sum += int(accAddress[i]) - } - return sum % bucketNumber -} diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index b3cf02716..8fd6dc0f2 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -3,327 +3,1086 @@ package order import ( "errors" "fmt" + "math" + "strings" "sync" + "time" + + "github.com/binance-chain/node/common/fees" + "github.com/binance-chain/node/common/utils" + "github.com/binance-chain/node/plugins/dex/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + tmlog "github.com/tendermint/tendermint/libs/log" bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" - "github.com/binance-chain/node/common/utils" + "github.com/binance-chain/node/plugins/dex/matcheng" me "github.com/binance-chain/node/plugins/dex/matcheng" - "github.com/binance-chain/node/plugins/dex/store" + dexTypes "github.com/binance-chain/node/plugins/dex/types" dexUtils "github.com/binance-chain/node/plugins/dex/utils" + "github.com/binance-chain/node/plugins/param/paramhub" + paramTypes "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/wire" ) const ( - numPricesStored = 2000 - pricesStoreEvery = 1000 - minimalNumPrices = 500 + BEP2TypeValue = 1 + MiniTypeValue = 2 ) -type FeeHandler func(map[string]*types.Fee) -type TransferHandler func(Transfer) - -type IDexOrderKeeper interface { - addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) - removeOrder(dexKeeper *DexKeeper, id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) - orderExists(symbol, id string) (OrderInfo, bool) - getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder - getAllOrders() map[string]map[string]*OrderInfo - deleteOrdersForPair(pair string) - clearOrderChanges() - getOrderChanges() OrderChanges - getOrderInfosForPub() OrderInfoForPublish - appendOrderChange(change OrderChange) - initOrders(symbol string) - support(pair string) bool - supportUpgradeVersion() bool - supportPairType(pairType SymbolPairType) bool - validateOrder(dexKeeper *DexKeeper, context sdk.Context, account sdk.Account, msg NewOrderMsg) error - iterateRoundPairs(func(string)) - iterateAllOrders(func(symbol string, id string)) - reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) - getRoundPairsNum() int - getRoundOrdersNum() int - getAllOrdersForPair(pair string) map[string]*OrderInfo - getRoundOrdersForPair(pair string) []string - getRoundIOCOrdersForPair(pair string) []string - clearAfterMatch() - selectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string - appendOrderChangeSync(change OrderChange) -} - -type BEP2OrderKeeper struct { - BaseOrderKeeper -} - -var _ IDexOrderKeeper = &BEP2OrderKeeper{} - -// in the future, this may be distributed via Sharding -type BaseOrderKeeper struct { - allOrders map[string]map[string]*OrderInfo // symbol -> order ID -> order - OrderChangesMtx *sync.Mutex // guard OrderChanges and OrderInfosForPub during PreDevlierTx (which is async) - OrderChanges OrderChanges // order changed in this block, will be cleaned before matching for new block - OrderInfosForPub OrderInfoForPublish // for publication usage - roundOrders map[string][]string // limit to the total tx number in a block - roundIOCOrders map[string][]string - poolSize uint // number of concurrent channels, counted in the pow of 2 - cdc *wire.Codec - logger tmlog.Logger - symbolSelector SymbolSelector -} - -// NewBEP2OrderKeeper - Returns the BEP2OrderKeeper -func NewBEP2OrderKeeper() IDexOrderKeeper { - logger := bnclog.With("module", "Bep2OrderKeeper") - return &BEP2OrderKeeper{ - BaseOrderKeeper{ - allOrders: make(map[string]map[string]*OrderInfo, 256), - // need to init the nested map when a new symbol added. - OrderChangesMtx: &sync.Mutex{}, - OrderChanges: make(OrderChanges, 0), - OrderInfosForPub: make(OrderInfoForPublish), - roundOrders: make(map[string][]string, 256), - roundIOCOrders: make(map[string][]string, 256), - logger: logger, - symbolSelector: &BEP2SymbolSelector{}, - }, +type SymbolPairType int8 + +var PairType = struct { + BEP2 SymbolPairType + MINI SymbolPairType +}{BEP2TypeValue, MiniTypeValue} + +type IDexKeeper interface { + InitRecentPrices(ctx sdk.Context) + AddEngine(pair dexTypes.TradingPair) *me.MatchEng + UpdateTickSizeAndLotSize(ctx sdk.Context) + DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) + UpdateLotSize(symbol string, lotSize int64) + AddOrder(info OrderInfo, isRecovery bool) (err error) + RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) + GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) + OrderExists(symbol, id string) (OrderInfo, bool) + GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel + GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder + GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap + GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel + GetLastTrades(height int64, pair string) ([]me.Trade, int64) + GetLastTradesForPair(pair string) ([]me.Trade, int64) + ClearOrderBook(pair string) + ClearOrderChanges() + StoreTradePrices(ctx sdk.Context) + ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) + MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) + GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) + GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 + DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) + CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error + CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error + SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) + LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) + GetPairMapper() store.TradingPairMapper + GetOrderChanges(pairType SymbolPairType) OrderChanges + GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish + GetAllOrders() map[string]map[string]*OrderInfo + GetAllOrdersForPair(symbol string) map[string]*OrderInfo + getAccountKeeper() *auth.AccountKeeper + getLogger() tmlog.Logger + getFeeManager() *FeeManager + GetEngines() map[string]*me.MatchEng + ShouldPublishOrder() bool + UpdateOrderChange(change OrderChange, symbol string) + UpdateOrderChangeSync(change OrderChange, symbol string) + ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error + SelectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string + ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) +} + +type DexKeeper struct { + PairMapper store.TradingPairMapper + storeKey sdk.StoreKey // The key used to access the store from the Context. + codespace sdk.CodespaceType + recentPrices map[string]*utils.FixedSizeRing // symbol -> latest "numPricesStored" prices per "pricesStoreEvery" blocks + am auth.AccountKeeper + FeeManager *FeeManager + RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee + CollectOrderInfoForPublish bool + engines map[string]*me.MatchEng + logger tmlog.Logger + poolSize uint // number of concurrent channels, counted in the pow of 2 + cdc *wire.Codec + OrderKeepers []IDexOrderKeeper +} + +var _ IDexKeeper = &DexKeeper{} + +func NewDexKeeper(key sdk.StoreKey, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, cdc *wire.Codec, am auth.AccountKeeper, collectOrderInfoForPublish bool, concurrency uint) *DexKeeper { + logger := bnclog.With("module", "dex_keeper") + return &DexKeeper{ + PairMapper: tradingPairMapper, + storeKey: key, + codespace: codespace, + recentPrices: make(map[string]*utils.FixedSizeRing, 256), + am: am, + RoundOrderFees: make(map[string]*types.Fee, 256), + FeeManager: NewFeeManager(cdc, logger), + CollectOrderInfoForPublish: collectOrderInfoForPublish, + engines: make(map[string]*me.MatchEng), + poolSize: concurrency, + cdc: cdc, + logger: logger, + OrderKeepers: []IDexOrderKeeper{NewBEP2OrderKeeper(), NewMiniOrderKeeper()}, } } -func (kp *BaseOrderKeeper) addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) { +func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { + return me.NewMatchEng(pairSymbol, basePrice, lotSize, 0.05) +} + +func (kp *DexKeeper) InitRecentPrices(ctx sdk.Context) { + kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) +} + +func (kp *DexKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { + symbol := strings.ToUpper(pair.GetSymbol()) + eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) + kp.engines[symbol] = eng + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.initOrders(symbol) + break + } + } + return eng +} + +func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { + //try update order book first + symbol := strings.ToUpper(info.Symbol) + eng, ok := kp.engines[symbol] + if !ok { + err = fmt.Errorf("match engine of symbol %s doesn't exist", symbol) + return + } + + _, err = eng.Book.InsertOrder(info.Id, info.Side, info.CreatedHeight, info.Price, info.Quantity) + if err != nil { + return err + } - if collectOrderInfoForPublish { - change := OrderChange{info.Id, Ack, "", nil} - // deliberately not add this message to orderChanges - if !isRecovery { - kp.OrderChanges = append(kp.OrderChanges, change) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) + break } - kp.logger.Debug("add order to order changes map", "orderId", info.Id, "isRecovery", isRecovery) - kp.OrderInfosForPub[info.Id] = &info } - kp.allOrders[symbol][info.Id] = &info - kp.addRoundOrders(symbol, info) + kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) + return nil } -func (kp *BaseOrderKeeper) addRoundOrders(symbol string, info OrderInfo) { - if ids, ok := kp.roundOrders[symbol]; ok { - kp.roundOrders[symbol] = append(ids, info.Id) +// deliberately make `fee` parameter not a pointer +// in case we modify the original fee (which will be referenced when distribute to validator) +func (kp *DexKeeper) updateRoundOrderFee(addr string, fee types.Fee) { + if existingFee, ok := kp.RoundOrderFees[addr]; ok { + existingFee.AddFee(fee) } else { - newIds := make([]string, 0, 16) - kp.roundOrders[symbol] = append(newIds, info.Id) + kp.RoundOrderFees[addr] = &fee + } +} + +func (kp *DexKeeper) ClearRoundFee() { + kp.RoundOrderFees = make(map[string]*types.Fee, 256) +} + +func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( + types.Fee, map[string]*types.Fee) { + if !sdk.IsUpgrade(upgrade.BEP19) { + return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler, kp.engines) + } + + // use string of the addr as the key since map makes a fast path for string key. + // Also, making the key have same length is also an optimization. + tradeTransfers := make(map[string]TradeTransfers) + // expire fee is fixed, so we count by numbers. + expireTransfers := make(map[string]ExpireTransfers) + // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. + var expireEventType transferEventType + var totalFee types.Fee + for tran := range tranCh { + kp.doTransfer(ctx, &tran) + if !tran.FeeFree() { + addrStr := string(tran.accAddress.Bytes()) + // need a copy of tran as it is reused + tranCp := tran + if tran.IsExpiredWithFee() { + expireEventType = tran.eventType + if _, ok := expireTransfers[addrStr]; !ok { + expireTransfers[addrStr] = ExpireTransfers{&tranCp} + } else { + expireTransfers[addrStr] = append(expireTransfers[addrStr], &tranCp) + } + } else if tran.eventType == eventFilled { + if _, ok := tradeTransfers[addrStr]; !ok { + tradeTransfers[addrStr] = TradeTransfers{&tranCp} + } else { + tradeTransfers[addrStr] = append(tradeTransfers[addrStr], &tranCp) + } + } + } else if tran.IsExpire() { + if postAllocateHandler != nil { + postAllocateHandler(tran) + } + } } - if info.TimeInForce == TimeInForce.IOC { - kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], info.Id) + + feesPerAcc := make(map[string]*types.Fee) + for addrStr, trans := range tradeTransfers { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, kp.engines) + if !fees.IsEmpty() { + feesPerAcc[addrStr] = &fees + acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) + kp.am.SetAccount(ctx, acc) + totalFee.AddFee(fees) + } + } + + for addrStr, trans := range expireTransfers { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + + fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, kp.engines, postAllocateHandler) + if !fees.IsEmpty() { + if _, ok := feesPerAcc[addrStr]; ok { + feesPerAcc[addrStr].AddFee(fees) + } else { + feesPerAcc[addrStr] = &fees + } + acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) + kp.am.SetAccount(ctx, acc) + totalFee.AddFee(fees) + } } + return totalFee, feesPerAcc } -func (kp *BaseOrderKeeper) orderExists(symbol, id string) (OrderInfo, bool) { - if orders, ok := kp.allOrders[symbol]; ok { - if msg, ok := orders[id]; ok { - return *msg, ok +func (kp *DexKeeper) allocateAndCalcFee( + ctx sdk.Context, + tradeOuts []chan Transfer, + postAlloTransHandler TransferHandler) types.Fee { + concurrency := len(tradeOuts) + var wg sync.WaitGroup + wg.Add(concurrency) + feesPerCh := make([]types.Fee, concurrency) + feesPerAcc := make([]map[string]*types.Fee, concurrency) + allocatePerCh := func(index int, tranCh <-chan Transfer) { + defer wg.Done() + fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) + feesPerCh[index].AddFee(fee) + feesPerAcc[index] = feeByAcc + } + + for i, tradeTranCh := range tradeOuts { + go allocatePerCh(i, tradeTranCh) + } + wg.Wait() + totalFee := types.Fee{} + for i := 0; i < concurrency; i++ { + totalFee.AddFee(feesPerCh[i]) + } + if kp.CollectOrderInfoForPublish { + for _, m := range feesPerAcc { + for k, v := range m { + kp.updateRoundOrderFee(k, *v) + } } } - return OrderInfo{}, false + return totalFee } -func (kp *BaseOrderKeeper) removeOrder(dexKeeper *DexKeeper, id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { +// DEPRECATED +func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer), engines map[string]*matcheng.MatchEng) ( + types.Fee, map[string]*types.Fee) { + // use string of the addr as the key since map makes a fast path for string key. + // Also, making the key have same length is also an optimization. + tradeInAsset := make(map[string]*sortedAsset) + // expire fee is fixed, so we count by numbers. + expireInAsset := make(map[string]*sortedAsset) + // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. + var expireEventType transferEventType + var totalFee types.Fee + for tran := range tranCh { + kp.doTransfer(ctx, &tran) + if !tran.FeeFree() { + addrStr := string(tran.accAddress.Bytes()) + if tran.IsExpiredWithFee() { + expireEventType = tran.eventType + fees, ok := expireInAsset[addrStr] + if !ok { + fees = &sortedAsset{} + expireInAsset[addrStr] = fees + } + fees.addAsset(tran.inAsset, 1) + } else if tran.eventType == eventFilled { + fees, ok := tradeInAsset[addrStr] + if !ok { + fees = &sortedAsset{} + tradeInAsset[addrStr] = fees + } + // no possible to overflow, for tran.in == otherSide.tran.out <= TotalSupply(otherSide.tran.outAsset) + fees.addAsset(tran.inAsset, tran.in) + } + } + if postAllocateHandler != nil { + postAllocateHandler(tran) + } + } + + feesPerAcc := make(map[string]*types.Fee) + collectFee := func(assetsMap map[string]*sortedAsset, calcFeeAndDeduct func(acc sdk.Account, in sdk.Coin) types.Fee) { + for addrStr, assets := range assetsMap { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) - ordMsg, ok := kp.orderExists(symbol, id) - if !ok { - return orderNotFound(symbol, id) + var fees types.Fee + if exists, ok := feesPerAcc[addrStr]; ok { + fees = *exists + } + if assets.native != 0 { + fee := calcFeeAndDeduct(acc, sdk.NewCoin(types.NativeTokenSymbol, assets.native)) + fees.AddFee(fee) + totalFee.AddFee(fee) + } + for _, asset := range assets.tokens { + fee := calcFeeAndDeduct(acc, asset) + fees.AddFee(fee) + totalFee.AddFee(fee) + } + if !fees.IsEmpty() { + feesPerAcc[addrStr] = &fees + kp.am.SetAccount(ctx, acc) + } + } + } + collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { + fee := kp.FeeManager.CalcTradeFee(acc.GetCoins(), in, engines) + acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) + return fee + }) + collectFee(expireInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { + var i int64 = 0 + var fees types.Fee + for ; i < in.Amount; i++ { + fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, engines) + acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) + fees.AddFee(fee) + } + return fees + }) + return totalFee, feesPerAcc +} + +func (kp *DexKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { + account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) + newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) + // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. + // they should never happen, there would be a severe bug if happen and we have to cancel all orders when app restarts. + if !newLocked.IsNotNegative() { + panic(fmt.Errorf( + "no enough locked tokens to unlock, oid: %s, newLocked: %s, unlock: %d", + tran.Oid, + newLocked.String(), + tran.unlock)) + } + if tran.unlock < tran.out { + panic(errors.New("unlocked tokens cannot cover the expense")) + } + account.SetLockedCoins(newLocked) + accountCoin := account.GetCoins(). + Plus(sdk.Coins{sdk.NewCoin(tran.inAsset, tran.in)}) + if remain := tran.unlock - tran.out; remain > 0 || !sdk.IsUpgrade(upgrade.FixZeroBalance) { + accountCoin = accountCoin.Plus(sdk.Coins{sdk.NewCoin(tran.outAsset, remain)}) + } + account.SetCoins(accountCoin) + + kp.am.SetAccount(ctx, account) + return nil +} + +func (kp *DexKeeper) SubscribeParamChange(hub *paramhub.Keeper) { + hub.SubscribeParamChange( + func(ctx sdk.Context, changes []interface{}) { + for _, c := range changes { + switch change := c.(type) { + case []paramTypes.FeeParam: + feeConfig := ParamToFeeConfig(change) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } + default: + kp.logger.Debug("Receive param changes that not interested.") + } + } + }, + func(context sdk.Context, state paramTypes.GenesisState) { + feeConfig := ParamToFeeConfig(state.FeeGenesis) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } else { + panic("Genesis with no dex fee config ") + } + }, + func(context sdk.Context, iLoad interface{}) { + switch load := iLoad.(type) { + case []paramTypes.FeeParam: + feeConfig := ParamToFeeConfig(load) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } else { + panic("Load with no dex fee config ") + } + default: + kp.logger.Debug("Receive param load that not interested.") + } + }) +} + +func (kp *DexKeeper) UpdateTickSizeAndLotSize(ctx sdk.Context) { + tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) + lotSizeCache := make(map[string]int64) // baseAsset -> lotSize + for _, pair := range tradingPairs { + if prices, ok := kp.recentPrices[pair.GetSymbol()]; ok && prices.Count() >= minimalNumPrices { + priceWMA := dexUtils.CalcPriceWMA(prices) + tickSize, lotSize := kp.determineTickAndLotSize(pair, priceWMA, lotSizeCache) + if tickSize != pair.TickSize.ToInt64() || + lotSize != pair.LotSize.ToInt64() { + ctx.Logger().Info("Updating tick/lotsize", + "pair", pair.GetSymbol(), "old_ticksize", pair.TickSize, "new_ticksize", tickSize, + "old_lotsize", pair.LotSize, "new_lotsize", lotSize) + pair.TickSize = utils.Fixed8(tickSize) + pair.LotSize = utils.Fixed8(lotSize) + kp.PairMapper.AddTradingPair(ctx, pair) + } + kp.UpdateLotSize(pair.GetSymbol(), lotSize) + } else { + // keep the current tick_size/lot_size + continue + } } - eng, ok := dexKeeper.engines[symbol] +} + +func (kp *DexKeeper) determineTickAndLotSize(pair dexTypes.TradingPair, priceWMA int64, lotSizeCache map[string]int64) (tickSize, lotSize int64) { + tickSize = dexUtils.CalcTickSize(priceWMA) + if !sdk.IsUpgrade(upgrade.LotSizeOptimization) { + lotSize = dexUtils.CalcLotSize(priceWMA) + return + } + if lotSize, cached := lotSizeCache[pair.BaseAssetSymbol]; cached { + return tickSize, lotSize + } + + lotSize = kp.DetermineLotSize(pair.BaseAssetSymbol, pair.QuoteAssetSymbol, priceWMA) + lotSizeCache[pair.BaseAssetSymbol] = lotSize + return +} + +func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) { + var priceAgainstNative int64 + if baseAssetSymbol == types.NativeTokenSymbol { + // price of BNB/BNB is 1e8 + priceAgainstNative = 1e8 + } else if quoteAssetSymbol == types.NativeTokenSymbol { + priceAgainstNative = price + } else { + if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { + priceAgainstNative = dexUtils.CalcPriceWMA(ps) + } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { + wma := dexUtils.CalcPriceWMA(ps) + priceAgainstNative = 1e16 / wma + } else { + // the recentPrices still have not collected any price yet, iff the native pair is listed for less than kp.pricesStoreEvery blocks + if engine, ok := kp.engines[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { + priceAgainstNative = engine.LastTradePrice + } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { + priceAgainstNative = 1e16 / engine.LastTradePrice + } else { + // should not happen + kp.logger.Error("DetermineLotSize failed because no native pair found", "base", baseAssetSymbol, "quote", quoteAssetSymbol) + } + } + } + lotSize = dexUtils.CalcLotSize(priceAgainstNative) + return lotSize +} + +func (kp *DexKeeper) UpdateLotSize(symbol string, lotSize int64) { + eng, ok := kp.engines[symbol] if !ok { - return orderNotFound(symbol, id) + panic(fmt.Sprintf("match engine of symbol %s doesn't exist", symbol)) } - delete(kp.allOrders[symbol], id) - ord, err := eng.Book.RemoveOrder(id, ordMsg.Side, ordMsg.Price) - if err != nil { - return err + eng.LotSize = lotSize +} + +func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { + symbol = strings.ToUpper(symbol) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + return orderKeeper.removeOrder(kp, id, symbol, postCancelHandler) + } } + return orderNotFound(symbol, id) +} - if postCancelHandler != nil { - postCancelHandler(ord) +func (kp *DexKeeper) GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) { + symbol = strings.ToUpper(symbol) + _, ok := kp.OrderExists(symbol, id) + if !ok { + return me.OrderPart{}, orderNotFound(symbol, id) } - return nil + eng, ok := kp.engines[symbol] + if !ok { + return me.OrderPart{}, orderNotFound(symbol, id) + } + return eng.Book.GetOrder(id, side, price) } -func (kp *BaseOrderKeeper) deleteOrdersForPair(pair string) { - delete(kp.allOrders, pair) +func (kp *DexKeeper) OrderExists(symbol, id string) (OrderInfo, bool) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + return orderKeeper.orderExists(symbol, id) + } + } + return OrderInfo{}, false } -func (kp *BaseOrderKeeper) validateOrder(dexKeeper *DexKeeper, ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { - baseAsset, quoteAsset, err := dexUtils.TradingPair2Assets(msg.Symbol) - if err != nil { - return err +func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { + orderbook := make([]store.OrderBookLevel, maxLevels) + + i, j := 0, 0 + + if eng, ok := kp.engines[pair]; ok { + // TODO: check considered bucket splitting? + eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { + orderbook[i].BuyPrice = utils.Fixed8(p.Price) + orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) + i++ + }, + func(p *me.PriceLevel) { + orderbook[j].SellPrice = utils.Fixed8(p.Price) + orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) + j++ + }) } + return orderbook +} - seq := acc.GetSequence() - expectedID := GenerateOrderID(seq, msg.Sender) - if expectedID != msg.Id { - return fmt.Errorf("the order ID(%s) given did not match the expected one: `%s`", msg.Id, expectedID) +func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(msg.Symbol) { + return orderKeeper.validateOrder(kp, context, account, msg) + } } + return fmt.Errorf("symbol:%s is not supported", msg.Symbol) +} - pair, err := dexKeeper.PairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) - if err != nil { - return err +func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(pair) { + return orderKeeper.getOpenOrders(pair, addr) + } } + return make([]store.OpenOrder, 0) +} - if msg.Quantity <= 0 || msg.Quantity%pair.LotSize.ToInt64() != 0 { - return fmt.Errorf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()) +func (kp *DexKeeper) GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap { + var res = make(ChangedPriceLevelsMap) + for pair, eng := range kp.engines { + buys := make(map[int64]int64) + sells := make(map[int64]int64) + res[pair] = ChangedPriceLevelsPerSymbol{buys, sells} + + // TODO: check considered bucket splitting? + eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { + buys[p.Price] = p.TotalLeavesQty() + }, func(p *me.PriceLevel) { + sells[p.Price] = p.TotalLeavesQty() + }) } - if msg.Price <= 0 || msg.Price%pair.TickSize.ToInt64() != 0 { - return fmt.Errorf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()) + return res +} + +func (kp *DexKeeper) GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel { + if eng, ok := kp.engines[pair]; ok { + return eng.Book.GetPriceLevel(price, side) + } else { + return nil } +} - if sdk.IsUpgrade(upgrade.LotSizeOptimization) { - if dexUtils.IsUnderMinNotional(msg.Price, msg.Quantity) { - return errors.New("notional value of the order is too small") +func (kp *DexKeeper) GetLastTrades(height int64, pair string) ([]me.Trade, int64) { + if eng, ok := kp.engines[pair]; ok { + if eng.LastMatchHeight == height { + return eng.Trades, eng.LastTradePrice } } + return nil, 0 +} - if dexUtils.IsExceedMaxNotional(msg.Price, msg.Quantity) { - return errors.New("notional value of the order is too large(cannot fit in int64)") +// !!! FOR TEST USE ONLY +func (kp *DexKeeper) GetLastTradesForPair(pair string) ([]me.Trade, int64) { + if eng, ok := kp.engines[pair]; ok { + return eng.Trades, eng.LastTradePrice } + return nil, 0 +} - return nil +func (kp *DexKeeper) ClearOrderBook(pair string) { + if eng, ok := kp.engines[pair]; ok { + eng.Book.Clear() + } +} + +func (kp *DexKeeper) ClearOrderChanges() { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + orderKeeper.clearOrderChanges() + } + } } -func (kp *BaseOrderKeeper) getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { - openOrders := make([]store.OpenOrder, 0) +func (kp *DexKeeper) StoreTradePrices(ctx sdk.Context) { + // TODO: check block height != 0 + if ctx.BlockHeight()%pricesStoreEvery == 0 { + lastTradePrices := make(map[string]int64, len(kp.engines)) + for symbol, engine := range kp.engines { + lastTradePrices[symbol] = engine.LastTradePrice + if _, ok := kp.recentPrices[symbol]; !ok { + kp.recentPrices[symbol] = utils.NewFixedSizedRing(numPricesStored) + } + kp.recentPrices[symbol].Push(engine.LastTradePrice) + } + if len(lastTradePrices) != 0 { + kp.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices) + } + } +} - for _, order := range kp.allOrders[pair] { - if string(order.Sender.Bytes()) == string(addr.Bytes()) { - openOrders = append( - openOrders, - store.OpenOrder{ - order.Id, - pair, - utils.Fixed8(order.Price), - utils.Fixed8(order.Quantity), - utils.Fixed8(order.CumQty), - order.CreatedHeight, - order.CreatedTimestamp, - order.LastUpdatedHeight, - order.LastUpdatedTimestamp, - }) +func (kp *DexKeeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { + allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) } } + size := len(allOrders) + if size == 0 { + kp.logger.Info("No orders to expire") + return nil + } + + // TODO: make effectiveDays configurable + const effectiveDays = 3 + expireHeight, err := kp.GetBreatheBlockHeight(ctx, blockTime, effectiveDays) + if err != nil { + // breathe block not found, that should only happens in in the first three days, just log it and ignore. + kp.logger.Info(err.Error()) + return nil + } + + channelSize := size >> kp.poolSize + concurrency := 1 << kp.poolSize + if size%concurrency != 0 { + channelSize += 1 + } + + transferChs := make([]chan Transfer, concurrency) + for i := range transferChs { + // TODO: channelSize is enough for buffer to facilitate ? + transferChs[i] = make(chan Transfer, channelSize*2) + } + + expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { + engine.Book.RemoveOrders(expireHeight, side, func(ord me.OrderPart) { + // gen transfer + if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { + h := channelHash(ordMsg.Sender, concurrency) + transferChs[h] <- TransferFromExpired(ord, *ordMsg) + // delete from allOrders + delete(orders, ord.Id) + } else { + kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) + } + }) + } + + symbolCh := make(chan string, concurrency) + utils.ConcurrentExecuteAsync(concurrency, + func() { + for symbol := range allOrders { + symbolCh <- symbol + } + close(symbolCh) + }, func() { + for symbol := range symbolCh { + engine := kp.engines[symbol] + orders := allOrders[symbol] + expire(orders, engine, me.BUYSIDE) + expire(orders, engine, me.SELLSIDE) + } + }, func() { + for _, transferCh := range transferChs { + close(transferCh) + } + }) + + return transferChs +} + +func (kp *DexKeeper) ExpireOrders( + ctx sdk.Context, + blockTime time.Time, + postAlloTransHandler TransferHandler, +) { + transferChs := kp.expireOrders(ctx, blockTime) + if transferChs == nil { + return + } + + totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAlloTransHandler) + fees.Pool.AddAndCommitFee("EXPIRE", totalFee) +} + +func (kp *DexKeeper) MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) { + key := utils.Int642Bytes(blockTime.Unix() / utils.SecondsPerDay) + store := ctx.KVStore(kp.storeKey) + bz, err := kp.cdc.MarshalBinaryBare(height) + if err != nil { + panic(err) + } + kp.logger.Debug(fmt.Sprintf("mark breathe block for key: %v (blockTime: %d), value: %v\n", key, blockTime.Unix(), bz)) + store.Set([]byte(key), bz) +} + +func (kp *DexKeeper) GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) { + store := ctx.KVStore(kp.storeKey) + t := timeNow.AddDate(0, 0, -daysBack).Unix() + day := t / utils.SecondsPerDay + bz := store.Get(utils.Int642Bytes(day)) + if bz == nil { + return 0, fmt.Errorf("breathe block not found for day %v", day) + } - return openOrders + var height int64 + err := kp.cdc.UnmarshalBinaryBare(bz, &height) + if err != nil { + panic(err) + } + return height, nil +} + +func (kp *DexKeeper) GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 { + if blockInterval != 0 { + return (latestBlockHeight / int64(blockInterval)) * int64(blockInterval) + } else { + store := ctx.KVStore(kp.storeKey) + bz := []byte(nil) + for i := 0; i <= daysBack; i++ { + t := timeNow.AddDate(0, 0, -i).Unix() + key := utils.Int642Bytes(t / utils.SecondsPerDay) + bz = store.Get([]byte(key)) + if bz != nil { + kp.logger.Info("Located day to load breathe block height", "epochDay", key) + break + } + } + if bz == nil { + kp.logger.Error("Failed to load the latest breathe block height from", "timeNow", timeNow) + return 0 + } + var height int64 + err := kp.cdc.UnmarshalBinaryBare(bz, &height) + if err != nil { + panic(err) + } + kp.logger.Info("Loaded breathe block height", "height", height) + return height + } } -func (kp *BaseOrderKeeper) clearOrderChanges() { - kp.OrderChanges = kp.OrderChanges[:0] +func orderNotFound(symbol, id string) error { + return fmt.Errorf("Failed to find order [%v] on symbol [%v]", id, symbol) } -func (kp *BaseOrderKeeper) getAllOrders() map[string]map[string]*OrderInfo { - return kp.allOrders +func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportPairType(pairType) { + return orderKeeper.getOrderChanges() + } + } + kp.logger.Error("pairType is not supported %d", pairType) + return make(OrderChanges, 0) } -func (kp *BaseOrderKeeper) getOrderChanges() OrderChanges { - return kp.OrderChanges +func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.appendOrderChange(change) + return + } + } + kp.logger.Error("symbol is not supported %d", symbol) } -func (kp *BaseOrderKeeper) getOrderInfosForPub() OrderInfoForPublish { - return kp.OrderInfosForPub +func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.appendOrderChangeSync(change) + return + } + } + kp.logger.Error("symbol is not supported %d", symbol) } -func (kp *BaseOrderKeeper) appendOrderChange(change OrderChange) { - kp.OrderChanges = append(kp.OrderChanges, change) +func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportPairType(pairType) { + return orderKeeper.getOrderInfosForPub() + } + } + kp.logger.Error("pairType is not supported %d", pairType) + return make(OrderInfoForPublish) + } -func (kp *BaseOrderKeeper) getRoundOrdersForPair(pair string) []string { - return kp.roundOrders[pair] +func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { + return kp.PairMapper } -func (kp *BaseOrderKeeper) getRoundIOCOrdersForPair(pair string) []string { - return kp.roundIOCOrders[pair] +func (kp *DexKeeper) getAccountKeeper() *auth.AccountKeeper { + return &kp.am } -func (kp *BaseOrderKeeper) getAllOrdersForPair(pair string) map[string]*OrderInfo { - return kp.allOrders[pair] +func (kp *DexKeeper) getLogger() tmlog.Logger { + return kp.logger } -func (kp *BaseOrderKeeper) selectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string { - return kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, timestamp, matchAllSymbols) +func (kp *DexKeeper) getFeeManager() *FeeManager { + return kp.FeeManager } -func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { - kp.OrderChangesMtx.Lock() - kp.OrderChanges = append(kp.OrderChanges, change) - kp.OrderChangesMtx.Unlock() +func (kp *DexKeeper) ShouldPublishOrder() bool { + return kp.CollectOrderInfoForPublish } -func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { - //TODO - for symbol, orders := range kp.allOrders { - for orderId := range orders { - iter(symbol, orderId) +func (kp *DexKeeper) GetEngines() map[string]*me.MatchEng { + return kp.engines +} +func appendAllOrdersMap(ms ...map[string]map[string]*OrderInfo) map[string]map[string]*OrderInfo { + res := make(map[string]map[string]*OrderInfo) + for _, m := range ms { + for k, v := range m { + res[k] = v } } + return res } -//------ BEP2OrderKeeper methods ----- +func (kp *DexKeeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { + // trading pair against native token should not be delisted if there is any other trading pair exist + baseAsset = strings.ToUpper(baseAsset) + quoteAsset = strings.ToUpper(quoteAsset) + + if baseAsset == quoteAsset { + return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") + } -func (kp *BEP2OrderKeeper) support(pair string) bool { - return !dexUtils.IsMiniTokenTradingPair(pair) + if !kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) { + return fmt.Errorf("trading pair %s_%s does not exist", baseAsset, quoteAsset) + } + + if baseAsset != types.NativeTokenSymbol && quoteAsset != types.NativeTokenSymbol { + return nil + } + + var symbolToCheck string + if baseAsset != types.NativeTokenSymbol { + symbolToCheck = baseAsset + } else { + symbolToCheck = quoteAsset + } + + tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) + for _, pair := range tradingPairs { //TODO + if (pair.BaseAssetSymbol == symbolToCheck && pair.QuoteAssetSymbol != types.NativeTokenSymbol) || + (pair.QuoteAssetSymbol == symbolToCheck && pair.BaseAssetSymbol != types.NativeTokenSymbol) { + return fmt.Errorf("trading pair %s_%s should not exist before delisting %s_%s", + pair.BaseAssetSymbol, pair.QuoteAssetSymbol, baseAsset, quoteAsset) + } + } + + return nil } -func (kp *BEP2OrderKeeper) supportUpgradeVersion() bool { - return true +func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) { + _, ok := kp.engines[symbol] + if !ok { + kp.logger.Error("delist symbol does not exist", "symbol", symbol) + return + } + + transferChs := kp.expireAllOrders(ctx, symbol) + if transferChs != nil { + totalFee := kp.allocateAndCalcFee(ctx, transferChs, postAllocTransHandler) + fees.Pool.AddAndCommitFee(fmt.Sprintf("DELIST_%s", symbol), totalFee) + } + + delete(kp.engines, symbol) + delete(kp.recentPrices, symbol) + + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + orderKeeper.deleteOrdersForPair(symbol) + break + } + } + + baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol) + err := kp.PairMapper.DeleteTradingPair(ctx, baseAsset, quoteAsset) + if err != nil { + kp.logger.Error("delete trading pair error", "err", err.Error()) + } } -func (kp *BEP2OrderKeeper) supportPairType(pairType SymbolPairType) bool { - return PairType.BEP2 == pairType +func (kp *DexKeeper) expireAllOrders(ctx sdk.Context, symbol string) []chan Transfer { + ordersOfSymbol := make(map[string]*OrderInfo) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + ordersOfSymbol = orderKeeper.getAllOrdersForPair(symbol) + break + } + } + + orderNum := len(ordersOfSymbol) + if orderNum == 0 { + kp.logger.Info("no orders to expire", "symbol", symbol) + return nil + } + + concurrency := 1 << kp.poolSize + channelSize := orderNum / concurrency + + transferChs := make([]chan Transfer, concurrency) + for i := range transferChs { + transferChs[i] = make(chan Transfer, channelSize) + } + + expire := func(orders map[string]*OrderInfo, engine *me.MatchEng, side int8) { + _ = engine.Book.RemoveOrders(math.MaxInt64, side, func(ord me.OrderPart) { + // gen transfer + if ordMsg, ok := orders[ord.Id]; ok && ordMsg != nil { + h := channelHash(ordMsg.Sender, concurrency) + transferChs[h] <- TransferFromExpired(ord, *ordMsg) + } else { + kp.logger.Error("failed to locate order to remove in order book", "oid", ord.Id) + } + }) + } + + go func() { + engine := kp.engines[symbol] + orders := ordersOfSymbol + expire(orders, engine, me.BUYSIDE) + expire(orders, engine, me.SELLSIDE) + + for _, transferCh := range transferChs { + close(transferCh) + } + }() + + return transferChs } -func (kp *BEP2OrderKeeper) initOrders(symbol string) { - kp.allOrders[symbol] = map[string]*OrderInfo{} +func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { + // trading pair against native token should exist if quote token is not native token + baseAsset = strings.ToUpper(baseAsset) + quoteAsset = strings.ToUpper(quoteAsset) + + if baseAsset == quoteAsset { + return fmt.Errorf("base asset symbol should not be identical to quote asset symbol") + } + + if kp.PairMapper.Exists(ctx, baseAsset, quoteAsset) || kp.PairMapper.Exists(ctx, quoteAsset, baseAsset) { + return errors.New("trading pair exists") + } + + if baseAsset != types.NativeTokenSymbol && + quoteAsset != types.NativeTokenSymbol { + + if !kp.PairMapper.Exists(ctx, baseAsset, types.NativeTokenSymbol) && + !kp.PairMapper.Exists(ctx, types.NativeTokenSymbol, baseAsset) { + return fmt.Errorf("token %s should be listed against BNB before against %s", + baseAsset, quoteAsset) + } + + if !kp.PairMapper.Exists(ctx, quoteAsset, types.NativeTokenSymbol) && + !kp.PairMapper.Exists(ctx, types.NativeTokenSymbol, quoteAsset) { + return fmt.Errorf("token %s should be listed against BNB before listing %s against %s", + quoteAsset, baseAsset, quoteAsset) + } + } + + if isMiniSymbolPair(baseAsset, quoteAsset) && types.NativeTokenSymbol != quoteAsset { //todo permit BUSD + return errors.New("quote token is not valid for mini symbol pair: " + quoteAsset) + } + + return nil } -func (kp *BEP2OrderKeeper) clearAfterMatch() { - kp.logger.Debug("clearAfterMatchBEP2...") - kp.roundOrders = make(map[string][]string, 256) - kp.roundIOCOrders = make(map[string][]string, 256) +func (kp *DexKeeper) ClearAfterMatch() { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + orderKeeper.clearAfterMatch() + } + } } -func (kp *BEP2OrderKeeper) iterateRoundPairs(iter func(string)) { - for symbol := range kp.roundOrders { - iter(symbol) +func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { + allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) + } } + return allOrders } -func (kp *BEP2OrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) { - kp.allOrders[symbol][orderInfo.Id] = orderInfo - if orderInfo.CreatedHeight == height { - kp.roundOrders[symbol] = append(kp.roundOrders[symbol], orderInfo.Id) - if orderInfo.TimeInForce == TimeInForce.IOC { - kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], orderInfo.Id) +func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo { + ordersOfSymbol := make(map[string]*OrderInfo) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + ordersOfSymbol = orderKeeper.getAllOrdersForPair(symbol) + break } } - if collectOrderInfoForPublish { - if _, exists := kp.OrderInfosForPub[orderInfo.Id]; !exists { - bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) - kp.OrderInfosForPub[orderInfo.Id] = orderInfo + return ordersOfSymbol +} + +func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) + return } } } -func (kp *BEP2OrderKeeper) getRoundPairsNum() int { - return len(kp.roundOrders) +func isMiniSymbolPair(baseAsset, quoteAsset string) bool { + if sdk.IsUpgradeHeight(upgrade.BEP8) { + return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) + } + return false } -func (kp *BEP2OrderKeeper) getRoundOrdersNum() int { - n := 0 - for _, orders := range kp.roundOrders { - n += len(orders) +// channelHash() will choose a channel for processing by moding +// the sum of the last 7 bytes of address by bucketNumber. +// It may not be fully even. +// TODO: there is still concern on peroformance and evenness. +func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { + l := len(accAddress) + sum := 0 + for i := l - 7; i < l; i++ { + sum += int(accAddress[i]) } - return n + return sum % bucketNumber } diff --git a/plugins/dex/order/order_keeper.go b/plugins/dex/order/order_keeper.go new file mode 100644 index 000000000..b3cf02716 --- /dev/null +++ b/plugins/dex/order/order_keeper.go @@ -0,0 +1,329 @@ +package order + +import ( + "errors" + "fmt" + "sync" + + sdk "github.com/cosmos/cosmos-sdk/types" + tmlog "github.com/tendermint/tendermint/libs/log" + + bnclog "github.com/binance-chain/node/common/log" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/common/utils" + me "github.com/binance-chain/node/plugins/dex/matcheng" + "github.com/binance-chain/node/plugins/dex/store" + dexUtils "github.com/binance-chain/node/plugins/dex/utils" + "github.com/binance-chain/node/wire" +) + +const ( + numPricesStored = 2000 + pricesStoreEvery = 1000 + minimalNumPrices = 500 +) + +type FeeHandler func(map[string]*types.Fee) +type TransferHandler func(Transfer) + +type IDexOrderKeeper interface { + addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) + removeOrder(dexKeeper *DexKeeper, id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) + orderExists(symbol, id string) (OrderInfo, bool) + getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder + getAllOrders() map[string]map[string]*OrderInfo + deleteOrdersForPair(pair string) + clearOrderChanges() + getOrderChanges() OrderChanges + getOrderInfosForPub() OrderInfoForPublish + appendOrderChange(change OrderChange) + initOrders(symbol string) + support(pair string) bool + supportUpgradeVersion() bool + supportPairType(pairType SymbolPairType) bool + validateOrder(dexKeeper *DexKeeper, context sdk.Context, account sdk.Account, msg NewOrderMsg) error + iterateRoundPairs(func(string)) + iterateAllOrders(func(symbol string, id string)) + reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) + getRoundPairsNum() int + getRoundOrdersNum() int + getAllOrdersForPair(pair string) map[string]*OrderInfo + getRoundOrdersForPair(pair string) []string + getRoundIOCOrdersForPair(pair string) []string + clearAfterMatch() + selectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string + appendOrderChangeSync(change OrderChange) +} + +type BEP2OrderKeeper struct { + BaseOrderKeeper +} + +var _ IDexOrderKeeper = &BEP2OrderKeeper{} + +// in the future, this may be distributed via Sharding +type BaseOrderKeeper struct { + allOrders map[string]map[string]*OrderInfo // symbol -> order ID -> order + OrderChangesMtx *sync.Mutex // guard OrderChanges and OrderInfosForPub during PreDevlierTx (which is async) + OrderChanges OrderChanges // order changed in this block, will be cleaned before matching for new block + OrderInfosForPub OrderInfoForPublish // for publication usage + roundOrders map[string][]string // limit to the total tx number in a block + roundIOCOrders map[string][]string + poolSize uint // number of concurrent channels, counted in the pow of 2 + cdc *wire.Codec + logger tmlog.Logger + symbolSelector SymbolSelector +} + +// NewBEP2OrderKeeper - Returns the BEP2OrderKeeper +func NewBEP2OrderKeeper() IDexOrderKeeper { + logger := bnclog.With("module", "Bep2OrderKeeper") + return &BEP2OrderKeeper{ + BaseOrderKeeper{ + allOrders: make(map[string]map[string]*OrderInfo, 256), + // need to init the nested map when a new symbol added. + OrderChangesMtx: &sync.Mutex{}, + OrderChanges: make(OrderChanges, 0), + OrderInfosForPub: make(OrderInfoForPublish), + roundOrders: make(map[string][]string, 256), + roundIOCOrders: make(map[string][]string, 256), + logger: logger, + symbolSelector: &BEP2SymbolSelector{}, + }, + } +} + +func (kp *BaseOrderKeeper) addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) { + + if collectOrderInfoForPublish { + change := OrderChange{info.Id, Ack, "", nil} + // deliberately not add this message to orderChanges + if !isRecovery { + kp.OrderChanges = append(kp.OrderChanges, change) + } + kp.logger.Debug("add order to order changes map", "orderId", info.Id, "isRecovery", isRecovery) + kp.OrderInfosForPub[info.Id] = &info + } + + kp.allOrders[symbol][info.Id] = &info + kp.addRoundOrders(symbol, info) +} + +func (kp *BaseOrderKeeper) addRoundOrders(symbol string, info OrderInfo) { + if ids, ok := kp.roundOrders[symbol]; ok { + kp.roundOrders[symbol] = append(ids, info.Id) + } else { + newIds := make([]string, 0, 16) + kp.roundOrders[symbol] = append(newIds, info.Id) + } + if info.TimeInForce == TimeInForce.IOC { + kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], info.Id) + } +} + +func (kp *BaseOrderKeeper) orderExists(symbol, id string) (OrderInfo, bool) { + if orders, ok := kp.allOrders[symbol]; ok { + if msg, ok := orders[id]; ok { + return *msg, ok + } + } + return OrderInfo{}, false +} + +func (kp *BaseOrderKeeper) removeOrder(dexKeeper *DexKeeper, id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { + + ordMsg, ok := kp.orderExists(symbol, id) + if !ok { + return orderNotFound(symbol, id) + } + eng, ok := dexKeeper.engines[symbol] + if !ok { + return orderNotFound(symbol, id) + } + delete(kp.allOrders[symbol], id) + ord, err := eng.Book.RemoveOrder(id, ordMsg.Side, ordMsg.Price) + if err != nil { + return err + } + + if postCancelHandler != nil { + postCancelHandler(ord) + } + return nil +} + +func (kp *BaseOrderKeeper) deleteOrdersForPair(pair string) { + delete(kp.allOrders, pair) +} + +func (kp *BaseOrderKeeper) validateOrder(dexKeeper *DexKeeper, ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { + baseAsset, quoteAsset, err := dexUtils.TradingPair2Assets(msg.Symbol) + if err != nil { + return err + } + + seq := acc.GetSequence() + expectedID := GenerateOrderID(seq, msg.Sender) + if expectedID != msg.Id { + return fmt.Errorf("the order ID(%s) given did not match the expected one: `%s`", msg.Id, expectedID) + } + + pair, err := dexKeeper.PairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) + if err != nil { + return err + } + + if msg.Quantity <= 0 || msg.Quantity%pair.LotSize.ToInt64() != 0 { + return fmt.Errorf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()) + } + + if msg.Price <= 0 || msg.Price%pair.TickSize.ToInt64() != 0 { + return fmt.Errorf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()) + } + + if sdk.IsUpgrade(upgrade.LotSizeOptimization) { + if dexUtils.IsUnderMinNotional(msg.Price, msg.Quantity) { + return errors.New("notional value of the order is too small") + } + } + + if dexUtils.IsExceedMaxNotional(msg.Price, msg.Quantity) { + return errors.New("notional value of the order is too large(cannot fit in int64)") + } + + return nil +} + +func (kp *BaseOrderKeeper) getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { + openOrders := make([]store.OpenOrder, 0) + + for _, order := range kp.allOrders[pair] { + if string(order.Sender.Bytes()) == string(addr.Bytes()) { + openOrders = append( + openOrders, + store.OpenOrder{ + order.Id, + pair, + utils.Fixed8(order.Price), + utils.Fixed8(order.Quantity), + utils.Fixed8(order.CumQty), + order.CreatedHeight, + order.CreatedTimestamp, + order.LastUpdatedHeight, + order.LastUpdatedTimestamp, + }) + } + } + + return openOrders +} + +func (kp *BaseOrderKeeper) clearOrderChanges() { + kp.OrderChanges = kp.OrderChanges[:0] +} + +func (kp *BaseOrderKeeper) getAllOrders() map[string]map[string]*OrderInfo { + return kp.allOrders +} + +func (kp *BaseOrderKeeper) getOrderChanges() OrderChanges { + return kp.OrderChanges +} + +func (kp *BaseOrderKeeper) getOrderInfosForPub() OrderInfoForPublish { + return kp.OrderInfosForPub +} + +func (kp *BaseOrderKeeper) appendOrderChange(change OrderChange) { + kp.OrderChanges = append(kp.OrderChanges, change) +} + +func (kp *BaseOrderKeeper) getRoundOrdersForPair(pair string) []string { + return kp.roundOrders[pair] +} + +func (kp *BaseOrderKeeper) getRoundIOCOrdersForPair(pair string) []string { + return kp.roundIOCOrders[pair] +} + +func (kp *BaseOrderKeeper) getAllOrdersForPair(pair string) map[string]*OrderInfo { + return kp.allOrders[pair] +} + +func (kp *BaseOrderKeeper) selectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string { + return kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, timestamp, matchAllSymbols) +} + +func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { + kp.OrderChangesMtx.Lock() + kp.OrderChanges = append(kp.OrderChanges, change) + kp.OrderChangesMtx.Unlock() +} + +func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { + //TODO + for symbol, orders := range kp.allOrders { + for orderId := range orders { + iter(symbol, orderId) + } + } +} + +//------ BEP2OrderKeeper methods ----- + +func (kp *BEP2OrderKeeper) support(pair string) bool { + return !dexUtils.IsMiniTokenTradingPair(pair) +} + +func (kp *BEP2OrderKeeper) supportUpgradeVersion() bool { + return true +} + +func (kp *BEP2OrderKeeper) supportPairType(pairType SymbolPairType) bool { + return PairType.BEP2 == pairType +} + +func (kp *BEP2OrderKeeper) initOrders(symbol string) { + kp.allOrders[symbol] = map[string]*OrderInfo{} +} + +func (kp *BEP2OrderKeeper) clearAfterMatch() { + kp.logger.Debug("clearAfterMatchBEP2...") + kp.roundOrders = make(map[string][]string, 256) + kp.roundIOCOrders = make(map[string][]string, 256) +} + +func (kp *BEP2OrderKeeper) iterateRoundPairs(iter func(string)) { + for symbol := range kp.roundOrders { + iter(symbol) + } +} + +func (kp *BEP2OrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) { + kp.allOrders[symbol][orderInfo.Id] = orderInfo + if orderInfo.CreatedHeight == height { + kp.roundOrders[symbol] = append(kp.roundOrders[symbol], orderInfo.Id) + if orderInfo.TimeInForce == TimeInForce.IOC { + kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], orderInfo.Id) + } + } + if collectOrderInfoForPublish { + if _, exists := kp.OrderInfosForPub[orderInfo.Id]; !exists { + bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) + kp.OrderInfosForPub[orderInfo.Id] = orderInfo + } + } +} + +func (kp *BEP2OrderKeeper) getRoundPairsNum() int { + return len(kp.roundOrders) +} + +func (kp *BEP2OrderKeeper) getRoundOrdersNum() int { + n := 0 + for _, orders := range kp.roundOrders { + n += len(orders) + } + return n +} From 55627f02e8fa88fffbdc2e7b7e3e4e312c32dc00 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 8 May 2020 20:20:09 +0800 Subject: [PATCH 23/96] change order --- networks/publisher/ordergen.sh | 8 +- plugins/dex/order/keeper.go | 962 ++++++++++++++++----------------- 2 files changed, 485 insertions(+), 485 deletions(-) diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index 22f12372a..655d1df1e 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -43,15 +43,15 @@ do pause=$(random 5 7) symbolNum=$(random 1 10) - symbol="ZCB-51A_BNB" + symbol="NNB-5D4_BNB" if [ $symbolNum -lt 4 ] then - symbol="ZCB-51A_BNB" + symbol="NNB-5D4_BNB" elif [ $symbolNum -lt 6 ] then - symbol="ZCB-51A_BNB" + symbol="NNB-5D4_BNB" else [ $symbolNum -lt 8 ] - symbol="ZCB-51A_BNB" + symbol="NNB-5D4_BNB" fi from="zc" if [ $side == 1 ] diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 8fd6dc0f2..4066ec4ae 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -8,20 +8,19 @@ import ( "sync" "time" - "github.com/binance-chain/node/common/fees" - "github.com/binance-chain/node/common/utils" - "github.com/binance-chain/node/plugins/dex/store" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" tmlog "github.com/tendermint/tendermint/libs/log" + "github.com/binance-chain/node/common/fees" bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/common/utils" "github.com/binance-chain/node/plugins/dex/matcheng" me "github.com/binance-chain/node/plugins/dex/matcheng" + "github.com/binance-chain/node/plugins/dex/store" dexTypes "github.com/binance-chain/node/plugins/dex/types" dexUtils "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/plugins/param/paramhub" @@ -123,14 +122,86 @@ func NewDexKeeper(key sdk.StoreKey, tradingPairMapper store.TradingPairMapper, c } } -func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { - return me.NewMatchEng(pairSymbol, basePrice, lotSize, 0.05) -} - func (kp *DexKeeper) InitRecentPrices(ctx sdk.Context) { kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) } +func (kp *DexKeeper) UpdateTickSizeAndLotSize(ctx sdk.Context) { + tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) + lotSizeCache := make(map[string]int64) // baseAsset -> lotSize + for _, pair := range tradingPairs { + if prices, ok := kp.recentPrices[pair.GetSymbol()]; ok && prices.Count() >= minimalNumPrices { + priceWMA := dexUtils.CalcPriceWMA(prices) + tickSize, lotSize := kp.determineTickAndLotSize(pair, priceWMA, lotSizeCache) + if tickSize != pair.TickSize.ToInt64() || + lotSize != pair.LotSize.ToInt64() { + ctx.Logger().Info("Updating tick/lotsize", + "pair", pair.GetSymbol(), "old_ticksize", pair.TickSize, "new_ticksize", tickSize, + "old_lotsize", pair.LotSize, "new_lotsize", lotSize) + pair.TickSize = utils.Fixed8(tickSize) + pair.LotSize = utils.Fixed8(lotSize) + kp.PairMapper.AddTradingPair(ctx, pair) + } + kp.UpdateLotSize(pair.GetSymbol(), lotSize) + } else { + // keep the current tick_size/lot_size + continue + } + } +} + +func (kp *DexKeeper) determineTickAndLotSize(pair dexTypes.TradingPair, priceWMA int64, lotSizeCache map[string]int64) (tickSize, lotSize int64) { + tickSize = dexUtils.CalcTickSize(priceWMA) + if !sdk.IsUpgrade(upgrade.LotSizeOptimization) { + lotSize = dexUtils.CalcLotSize(priceWMA) + return + } + if lotSize, cached := lotSizeCache[pair.BaseAssetSymbol]; cached { + return tickSize, lotSize + } + + lotSize = kp.DetermineLotSize(pair.BaseAssetSymbol, pair.QuoteAssetSymbol, priceWMA) + lotSizeCache[pair.BaseAssetSymbol] = lotSize + return +} + +func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) { + var priceAgainstNative int64 + if baseAssetSymbol == types.NativeTokenSymbol { + // price of BNB/BNB is 1e8 + priceAgainstNative = 1e8 + } else if quoteAssetSymbol == types.NativeTokenSymbol { + priceAgainstNative = price + } else { + if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { + priceAgainstNative = dexUtils.CalcPriceWMA(ps) + } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { + wma := dexUtils.CalcPriceWMA(ps) + priceAgainstNative = 1e16 / wma + } else { + // the recentPrices still have not collected any price yet, iff the native pair is listed for less than kp.pricesStoreEvery blocks + if engine, ok := kp.engines[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { + priceAgainstNative = engine.LastTradePrice + } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { + priceAgainstNative = 1e16 / engine.LastTradePrice + } else { + // should not happen + kp.logger.Error("DetermineLotSize failed because no native pair found", "base", baseAssetSymbol, "quote", quoteAssetSymbol) + } + } + } + lotSize = dexUtils.CalcLotSize(priceAgainstNative) + return lotSize +} + +func (kp *DexKeeper) UpdateLotSize(symbol string, lotSize int64) { + eng, ok := kp.engines[symbol] + if !ok { + panic(fmt.Sprintf("match engine of symbol %s doesn't exist", symbol)) + } + eng.LotSize = lotSize +} + func (kp *DexKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { symbol := strings.ToUpper(pair.GetSymbol()) eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) @@ -169,125 +240,303 @@ func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { return nil } -// deliberately make `fee` parameter not a pointer -// in case we modify the original fee (which will be referenced when distribute to validator) -func (kp *DexKeeper) updateRoundOrderFee(addr string, fee types.Fee) { - if existingFee, ok := kp.RoundOrderFees[addr]; ok { - existingFee.AddFee(fee) - } else { - kp.RoundOrderFees[addr] = &fee +func orderNotFound(symbol, id string) error { + return fmt.Errorf("Failed to find order [%v] on symbol [%v]", id, symbol) +} + +func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { + symbol = strings.ToUpper(symbol) + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + return orderKeeper.removeOrder(kp, id, symbol, postCancelHandler) + } } + return orderNotFound(symbol, id) } -func (kp *DexKeeper) ClearRoundFee() { - kp.RoundOrderFees = make(map[string]*types.Fee, 256) +func (kp *DexKeeper) GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) { + symbol = strings.ToUpper(symbol) + _, ok := kp.OrderExists(symbol, id) + if !ok { + return me.OrderPart{}, orderNotFound(symbol, id) + } + eng, ok := kp.engines[symbol] + if !ok { + return me.OrderPart{}, orderNotFound(symbol, id) + } + return eng.Book.GetOrder(id, side, price) } -func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( - types.Fee, map[string]*types.Fee) { - if !sdk.IsUpgrade(upgrade.BEP19) { - return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler, kp.engines) +func (kp *DexKeeper) OrderExists(symbol, id string) (OrderInfo, bool) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + return orderKeeper.orderExists(symbol, id) + } + } + return OrderInfo{}, false +} + +// channelHash() will choose a channel for processing by moding +// the sum of the last 7 bytes of address by bucketNumber. +// It may not be fully even. +// TODO: there is still concern on peroformance and evenness. +func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { + l := len(accAddress) + sum := 0 + for i := l - 7; i < l; i++ { + sum += int(accAddress[i]) } + return sum % bucketNumber +} - // use string of the addr as the key since map makes a fast path for string key. - // Also, making the key have same length is also an optimization. - tradeTransfers := make(map[string]TradeTransfers) - // expire fee is fixed, so we count by numbers. - expireTransfers := make(map[string]ExpireTransfers) - // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. - var expireEventType transferEventType - var totalFee types.Fee - for tran := range tranCh { - kp.doTransfer(ctx, &tran) - if !tran.FeeFree() { - addrStr := string(tran.accAddress.Bytes()) - // need a copy of tran as it is reused - tranCp := tran - if tran.IsExpiredWithFee() { - expireEventType = tran.eventType - if _, ok := expireTransfers[addrStr]; !ok { - expireTransfers[addrStr] = ExpireTransfers{&tranCp} - } else { - expireTransfers[addrStr] = append(expireTransfers[addrStr], &tranCp) +func (kp *DexKeeper) SubscribeParamChange(hub *paramhub.Keeper) { + hub.SubscribeParamChange( + func(ctx sdk.Context, changes []interface{}) { + for _, c := range changes { + switch change := c.(type) { + case []paramTypes.FeeParam: + feeConfig := ParamToFeeConfig(change) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } + default: + kp.logger.Debug("Receive param changes that not interested.") } - } else if tran.eventType == eventFilled { - if _, ok := tradeTransfers[addrStr]; !ok { - tradeTransfers[addrStr] = TradeTransfers{&tranCp} + } + }, + func(context sdk.Context, state paramTypes.GenesisState) { + feeConfig := ParamToFeeConfig(state.FeeGenesis) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } else { + panic("Genesis with no dex fee config ") + } + }, + func(context sdk.Context, iLoad interface{}) { + switch load := iLoad.(type) { + case []paramTypes.FeeParam: + feeConfig := ParamToFeeConfig(load) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) } else { - tradeTransfers[addrStr] = append(tradeTransfers[addrStr], &tranCp) + panic("Load with no dex fee config ") } + default: + kp.logger.Debug("Receive param load that not interested.") } - } else if tran.IsExpire() { - if postAllocateHandler != nil { - postAllocateHandler(tran) - } - } - } + }) +} - feesPerAcc := make(map[string]*types.Fee) - for addrStr, trans := range tradeTransfers { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) - fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, kp.engines) - if !fees.IsEmpty() { - feesPerAcc[addrStr] = &fees - acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) - kp.am.SetAccount(ctx, acc) - totalFee.AddFee(fees) - } - } +func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { + orderbook := make([]store.OrderBookLevel, maxLevels) - for addrStr, trans := range expireTransfers { - addr := sdk.AccAddress(addrStr) - acc := kp.am.GetAccount(ctx, addr) + i, j := 0, 0 - fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, kp.engines, postAllocateHandler) - if !fees.IsEmpty() { - if _, ok := feesPerAcc[addrStr]; ok { - feesPerAcc[addrStr].AddFee(fees) - } else { - feesPerAcc[addrStr] = &fees - } - acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) - kp.am.SetAccount(ctx, acc) - totalFee.AddFee(fees) + if eng, ok := kp.engines[pair]; ok { + // TODO: check considered bucket splitting? + eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { + orderbook[i].BuyPrice = utils.Fixed8(p.Price) + orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) + i++ + }, + func(p *me.PriceLevel) { + orderbook[j].SellPrice = utils.Fixed8(p.Price) + orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) + j++ + }) + } + return orderbook +} + +func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(pair) { + return orderKeeper.getOpenOrders(pair, addr) } } - return totalFee, feesPerAcc + return make([]store.OpenOrder, 0) } -func (kp *DexKeeper) allocateAndCalcFee( - ctx sdk.Context, - tradeOuts []chan Transfer, - postAlloTransHandler TransferHandler) types.Fee { - concurrency := len(tradeOuts) - var wg sync.WaitGroup - wg.Add(concurrency) - feesPerCh := make([]types.Fee, concurrency) - feesPerAcc := make([]map[string]*types.Fee, concurrency) - allocatePerCh := func(index int, tranCh <-chan Transfer) { - defer wg.Done() - fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) - feesPerCh[index].AddFee(fee) - feesPerAcc[index] = feeByAcc +func (kp *DexKeeper) GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap { + var res = make(ChangedPriceLevelsMap) + for pair, eng := range kp.engines { + buys := make(map[int64]int64) + sells := make(map[int64]int64) + res[pair] = ChangedPriceLevelsPerSymbol{buys, sells} + + // TODO: check considered bucket splitting? + eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { + buys[p.Price] = p.TotalLeavesQty() + }, func(p *me.PriceLevel) { + sells[p.Price] = p.TotalLeavesQty() + }) } - for i, tradeTranCh := range tradeOuts { - go allocatePerCh(i, tradeTranCh) + return res +} + +func (kp *DexKeeper) GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel { + if eng, ok := kp.engines[pair]; ok { + return eng.Book.GetPriceLevel(price, side) + } else { + return nil } - wg.Wait() - totalFee := types.Fee{} - for i := 0; i < concurrency; i++ { - totalFee.AddFee(feesPerCh[i]) +} + +func (kp *DexKeeper) GetLastTrades(height int64, pair string) ([]me.Trade, int64) { + if eng, ok := kp.engines[pair]; ok { + if eng.LastMatchHeight == height { + return eng.Trades, eng.LastTradePrice + } } - if kp.CollectOrderInfoForPublish { - for _, m := range feesPerAcc { - for k, v := range m { - kp.updateRoundOrderFee(k, *v) + return nil, 0 +} + +// !!! FOR TEST USE ONLY +func (kp *DexKeeper) GetLastTradesForPair(pair string) ([]me.Trade, int64) { + if eng, ok := kp.engines[pair]; ok { + return eng.Trades, eng.LastTradePrice + } + return nil, 0 +} + +func (kp *DexKeeper) ClearOrderBook(pair string) { + if eng, ok := kp.engines[pair]; ok { + eng.Book.Clear() + } +} + +func (kp *DexKeeper) ClearOrderChanges() { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + orderKeeper.clearOrderChanges() + } + } +} + +func (kp *DexKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { + account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) + newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) + // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. + // they should never happen, there would be a severe bug if happen and we have to cancel all orders when app restarts. + if !newLocked.IsNotNegative() { + panic(fmt.Errorf( + "no enough locked tokens to unlock, oid: %s, newLocked: %s, unlock: %d", + tran.Oid, + newLocked.String(), + tran.unlock)) + } + if tran.unlock < tran.out { + panic(errors.New("unlocked tokens cannot cover the expense")) + } + account.SetLockedCoins(newLocked) + accountCoin := account.GetCoins(). + Plus(sdk.Coins{sdk.NewCoin(tran.inAsset, tran.in)}) + if remain := tran.unlock - tran.out; remain > 0 || !sdk.IsUpgrade(upgrade.FixZeroBalance) { + accountCoin = accountCoin.Plus(sdk.Coins{sdk.NewCoin(tran.outAsset, remain)}) + } + account.SetCoins(accountCoin) + + kp.am.SetAccount(ctx, account) + return nil +} + +func (kp *DexKeeper) ClearAfterMatch() { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + orderKeeper.clearAfterMatch() + } + } +} + +func (kp *DexKeeper) StoreTradePrices(ctx sdk.Context) { + // TODO: check block height != 0 + if ctx.BlockHeight()%pricesStoreEvery == 0 { + lastTradePrices := make(map[string]int64, len(kp.engines)) + for symbol, engine := range kp.engines { + lastTradePrices[symbol] = engine.LastTradePrice + if _, ok := kp.recentPrices[symbol]; !ok { + kp.recentPrices[symbol] = utils.NewFixedSizedRing(numPricesStored) } + kp.recentPrices[symbol].Push(engine.LastTradePrice) + } + if len(lastTradePrices) != 0 { + kp.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices) } } - return totalFee +} + +func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( + types.Fee, map[string]*types.Fee) { + if !sdk.IsUpgrade(upgrade.BEP19) { + return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler, kp.engines) + } + + // use string of the addr as the key since map makes a fast path for string key. + // Also, making the key have same length is also an optimization. + tradeTransfers := make(map[string]TradeTransfers) + // expire fee is fixed, so we count by numbers. + expireTransfers := make(map[string]ExpireTransfers) + // we need to distinguish different expire event, IOCExpire or Expire. only one of the two will exist. + var expireEventType transferEventType + var totalFee types.Fee + for tran := range tranCh { + kp.doTransfer(ctx, &tran) + if !tran.FeeFree() { + addrStr := string(tran.accAddress.Bytes()) + // need a copy of tran as it is reused + tranCp := tran + if tran.IsExpiredWithFee() { + expireEventType = tran.eventType + if _, ok := expireTransfers[addrStr]; !ok { + expireTransfers[addrStr] = ExpireTransfers{&tranCp} + } else { + expireTransfers[addrStr] = append(expireTransfers[addrStr], &tranCp) + } + } else if tran.eventType == eventFilled { + if _, ok := tradeTransfers[addrStr]; !ok { + tradeTransfers[addrStr] = TradeTransfers{&tranCp} + } else { + tradeTransfers[addrStr] = append(tradeTransfers[addrStr], &tranCp) + } + } + } else if tran.IsExpire() { + if postAllocateHandler != nil { + postAllocateHandler(tran) + } + } + } + + feesPerAcc := make(map[string]*types.Fee) + for addrStr, trans := range tradeTransfers { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + fees := kp.FeeManager.CalcTradesFee(acc.GetCoins(), trans, kp.engines) + if !fees.IsEmpty() { + feesPerAcc[addrStr] = &fees + acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) + kp.am.SetAccount(ctx, acc) + totalFee.AddFee(fees) + } + } + + for addrStr, trans := range expireTransfers { + addr := sdk.AccAddress(addrStr) + acc := kp.am.GetAccount(ctx, addr) + + fees := kp.FeeManager.CalcExpiresFee(acc.GetCoins(), expireEventType, trans, kp.engines, postAllocateHandler) + if !fees.IsEmpty() { + if _, ok := feesPerAcc[addrStr]; ok { + feesPerAcc[addrStr].AddFee(fees) + } else { + feesPerAcc[addrStr] = &fees + } + acc.SetCoins(acc.GetCoins().Minus(fees.Tokens)) + kp.am.SetAccount(ctx, acc) + totalFee.AddFee(fees) + } + } + return totalFee, feesPerAcc } // DEPRECATED @@ -361,301 +610,49 @@ func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transf }) collectFee(expireInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { var i int64 = 0 - var fees types.Fee - for ; i < in.Amount; i++ { - fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, engines) - acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - fees.AddFee(fee) - } - return fees - }) - return totalFee, feesPerAcc -} - -func (kp *DexKeeper) doTransfer(ctx sdk.Context, tran *Transfer) sdk.Error { - account := kp.am.GetAccount(ctx, tran.accAddress).(types.NamedAccount) - newLocked := account.GetLockedCoins().Minus(sdk.Coins{sdk.NewCoin(tran.outAsset, tran.unlock)}) - // these two non-negative check are to ensure the Transfer gen result is correct before we actually operate the acc. - // they should never happen, there would be a severe bug if happen and we have to cancel all orders when app restarts. - if !newLocked.IsNotNegative() { - panic(fmt.Errorf( - "no enough locked tokens to unlock, oid: %s, newLocked: %s, unlock: %d", - tran.Oid, - newLocked.String(), - tran.unlock)) - } - if tran.unlock < tran.out { - panic(errors.New("unlocked tokens cannot cover the expense")) - } - account.SetLockedCoins(newLocked) - accountCoin := account.GetCoins(). - Plus(sdk.Coins{sdk.NewCoin(tran.inAsset, tran.in)}) - if remain := tran.unlock - tran.out; remain > 0 || !sdk.IsUpgrade(upgrade.FixZeroBalance) { - accountCoin = accountCoin.Plus(sdk.Coins{sdk.NewCoin(tran.outAsset, remain)}) - } - account.SetCoins(accountCoin) - - kp.am.SetAccount(ctx, account) - return nil -} - -func (kp *DexKeeper) SubscribeParamChange(hub *paramhub.Keeper) { - hub.SubscribeParamChange( - func(ctx sdk.Context, changes []interface{}) { - for _, c := range changes { - switch change := c.(type) { - case []paramTypes.FeeParam: - feeConfig := ParamToFeeConfig(change) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } - default: - kp.logger.Debug("Receive param changes that not interested.") - } - } - }, - func(context sdk.Context, state paramTypes.GenesisState) { - feeConfig := ParamToFeeConfig(state.FeeGenesis) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } else { - panic("Genesis with no dex fee config ") - } - }, - func(context sdk.Context, iLoad interface{}) { - switch load := iLoad.(type) { - case []paramTypes.FeeParam: - feeConfig := ParamToFeeConfig(load) - if feeConfig != nil { - kp.FeeManager.UpdateConfig(*feeConfig) - } else { - panic("Load with no dex fee config ") - } - default: - kp.logger.Debug("Receive param load that not interested.") - } - }) -} - -func (kp *DexKeeper) UpdateTickSizeAndLotSize(ctx sdk.Context) { - tradingPairs := kp.PairMapper.ListAllTradingPairs(ctx) - lotSizeCache := make(map[string]int64) // baseAsset -> lotSize - for _, pair := range tradingPairs { - if prices, ok := kp.recentPrices[pair.GetSymbol()]; ok && prices.Count() >= minimalNumPrices { - priceWMA := dexUtils.CalcPriceWMA(prices) - tickSize, lotSize := kp.determineTickAndLotSize(pair, priceWMA, lotSizeCache) - if tickSize != pair.TickSize.ToInt64() || - lotSize != pair.LotSize.ToInt64() { - ctx.Logger().Info("Updating tick/lotsize", - "pair", pair.GetSymbol(), "old_ticksize", pair.TickSize, "new_ticksize", tickSize, - "old_lotsize", pair.LotSize, "new_lotsize", lotSize) - pair.TickSize = utils.Fixed8(tickSize) - pair.LotSize = utils.Fixed8(lotSize) - kp.PairMapper.AddTradingPair(ctx, pair) - } - kp.UpdateLotSize(pair.GetSymbol(), lotSize) - } else { - // keep the current tick_size/lot_size - continue - } - } -} - -func (kp *DexKeeper) determineTickAndLotSize(pair dexTypes.TradingPair, priceWMA int64, lotSizeCache map[string]int64) (tickSize, lotSize int64) { - tickSize = dexUtils.CalcTickSize(priceWMA) - if !sdk.IsUpgrade(upgrade.LotSizeOptimization) { - lotSize = dexUtils.CalcLotSize(priceWMA) - return - } - if lotSize, cached := lotSizeCache[pair.BaseAssetSymbol]; cached { - return tickSize, lotSize - } - - lotSize = kp.DetermineLotSize(pair.BaseAssetSymbol, pair.QuoteAssetSymbol, priceWMA) - lotSizeCache[pair.BaseAssetSymbol] = lotSize - return -} - -func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) { - var priceAgainstNative int64 - if baseAssetSymbol == types.NativeTokenSymbol { - // price of BNB/BNB is 1e8 - priceAgainstNative = 1e8 - } else if quoteAssetSymbol == types.NativeTokenSymbol { - priceAgainstNative = price - } else { - if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { - priceAgainstNative = dexUtils.CalcPriceWMA(ps) - } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { - wma := dexUtils.CalcPriceWMA(ps) - priceAgainstNative = 1e16 / wma - } else { - // the recentPrices still have not collected any price yet, iff the native pair is listed for less than kp.pricesStoreEvery blocks - if engine, ok := kp.engines[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { - priceAgainstNative = engine.LastTradePrice - } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { - priceAgainstNative = 1e16 / engine.LastTradePrice - } else { - // should not happen - kp.logger.Error("DetermineLotSize failed because no native pair found", "base", baseAssetSymbol, "quote", quoteAssetSymbol) - } - } - } - lotSize = dexUtils.CalcLotSize(priceAgainstNative) - return lotSize -} - -func (kp *DexKeeper) UpdateLotSize(symbol string, lotSize int64) { - eng, ok := kp.engines[symbol] - if !ok { - panic(fmt.Sprintf("match engine of symbol %s doesn't exist", symbol)) - } - eng.LotSize = lotSize -} - -func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { - symbol = strings.ToUpper(symbol) - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - return orderKeeper.removeOrder(kp, id, symbol, postCancelHandler) - } - } - return orderNotFound(symbol, id) -} - -func (kp *DexKeeper) GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) { - symbol = strings.ToUpper(symbol) - _, ok := kp.OrderExists(symbol, id) - if !ok { - return me.OrderPart{}, orderNotFound(symbol, id) - } - eng, ok := kp.engines[symbol] - if !ok { - return me.OrderPart{}, orderNotFound(symbol, id) - } - return eng.Book.GetOrder(id, side, price) -} - -func (kp *DexKeeper) OrderExists(symbol, id string) (OrderInfo, bool) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - return orderKeeper.orderExists(symbol, id) - } - } - return OrderInfo{}, false -} - -func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) []store.OrderBookLevel { - orderbook := make([]store.OrderBookLevel, maxLevels) - - i, j := 0, 0 - - if eng, ok := kp.engines[pair]; ok { - // TODO: check considered bucket splitting? - eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { - orderbook[i].BuyPrice = utils.Fixed8(p.Price) - orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) - i++ - }, - func(p *me.PriceLevel) { - orderbook[j].SellPrice = utils.Fixed8(p.Price) - orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) - j++ - }) - } - return orderbook -} - -func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(msg.Symbol) { - return orderKeeper.validateOrder(kp, context, account, msg) - } - } - return fmt.Errorf("symbol:%s is not supported", msg.Symbol) -} - -func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(pair) { - return orderKeeper.getOpenOrders(pair, addr) - } - } - return make([]store.OpenOrder, 0) -} - -func (kp *DexKeeper) GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap { - var res = make(ChangedPriceLevelsMap) - for pair, eng := range kp.engines { - buys := make(map[int64]int64) - sells := make(map[int64]int64) - res[pair] = ChangedPriceLevelsPerSymbol{buys, sells} - - // TODO: check considered bucket splitting? - eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel) { - buys[p.Price] = p.TotalLeavesQty() - }, func(p *me.PriceLevel) { - sells[p.Price] = p.TotalLeavesQty() - }) - } - - return res -} - -func (kp *DexKeeper) GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel { - if eng, ok := kp.engines[pair]; ok { - return eng.Book.GetPriceLevel(price, side) - } else { - return nil - } -} - -func (kp *DexKeeper) GetLastTrades(height int64, pair string) ([]me.Trade, int64) { - if eng, ok := kp.engines[pair]; ok { - if eng.LastMatchHeight == height { - return eng.Trades, eng.LastTradePrice + var fees types.Fee + for ; i < in.Amount; i++ { + fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, engines) + acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) + fees.AddFee(fee) } - } - return nil, 0 + return fees + }) + return totalFee, feesPerAcc } -// !!! FOR TEST USE ONLY -func (kp *DexKeeper) GetLastTradesForPair(pair string) ([]me.Trade, int64) { - if eng, ok := kp.engines[pair]; ok { - return eng.Trades, eng.LastTradePrice +func (kp *DexKeeper) allocateAndCalcFee( + ctx sdk.Context, + tradeOuts []chan Transfer, + postAlloTransHandler TransferHandler) types.Fee { + concurrency := len(tradeOuts) + var wg sync.WaitGroup + wg.Add(concurrency) + feesPerCh := make([]types.Fee, concurrency) + feesPerAcc := make([]map[string]*types.Fee, concurrency) + allocatePerCh := func(index int, tranCh <-chan Transfer) { + defer wg.Done() + fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) + feesPerCh[index].AddFee(fee) + feesPerAcc[index] = feeByAcc } - return nil, 0 -} -func (kp *DexKeeper) ClearOrderBook(pair string) { - if eng, ok := kp.engines[pair]; ok { - eng.Book.Clear() + for i, tradeTranCh := range tradeOuts { + go allocatePerCh(i, tradeTranCh) } -} - -func (kp *DexKeeper) ClearOrderChanges() { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { - orderKeeper.clearOrderChanges() - } + wg.Wait() + totalFee := types.Fee{} + for i := 0; i < concurrency; i++ { + totalFee.AddFee(feesPerCh[i]) } -} - -func (kp *DexKeeper) StoreTradePrices(ctx sdk.Context) { - // TODO: check block height != 0 - if ctx.BlockHeight()%pricesStoreEvery == 0 { - lastTradePrices := make(map[string]int64, len(kp.engines)) - for symbol, engine := range kp.engines { - lastTradePrices[symbol] = engine.LastTradePrice - if _, ok := kp.recentPrices[symbol]; !ok { - kp.recentPrices[symbol] = utils.NewFixedSizedRing(numPricesStored) + if kp.CollectOrderInfoForPublish { + for _, m := range feesPerAcc { + for k, v := range m { + kp.updateRoundOrderFee(k, *v) } - kp.recentPrices[symbol].Push(engine.LastTradePrice) - } - if len(lastTradePrices) != 0 { - kp.PairMapper.UpdateRecentPrices(ctx, pricesStoreEvery, numPricesStored, lastTradePrices) } } + return totalFee } func (kp *DexKeeper) expireOrders(ctx sdk.Context, blockTime time.Time) []chan Transfer { @@ -800,82 +797,18 @@ func (kp *DexKeeper) GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeigh } } -func orderNotFound(symbol, id string) error { - return fmt.Errorf("Failed to find order [%v] on symbol [%v]", id, symbol) -} - -func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportPairType(pairType) { - return orderKeeper.getOrderChanges() - } - } - kp.logger.Error("pairType is not supported %d", pairType) - return make(OrderChanges, 0) -} - -func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.appendOrderChange(change) - return - } - } - kp.logger.Error("symbol is not supported %d", symbol) -} - -func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.appendOrderChangeSync(change) - return - } - } - kp.logger.Error("symbol is not supported %d", symbol) -} - -func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportPairType(pairType) { - return orderKeeper.getOrderInfosForPub() - } +// deliberately make `fee` parameter not a pointer +// in case we modify the original fee (which will be referenced when distribute to validator) +func (kp *DexKeeper) updateRoundOrderFee(addr string, fee types.Fee) { + if existingFee, ok := kp.RoundOrderFees[addr]; ok { + existingFee.AddFee(fee) + } else { + kp.RoundOrderFees[addr] = &fee } - kp.logger.Error("pairType is not supported %d", pairType) - return make(OrderInfoForPublish) - -} - -func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { - return kp.PairMapper -} - -func (kp *DexKeeper) getAccountKeeper() *auth.AccountKeeper { - return &kp.am -} - -func (kp *DexKeeper) getLogger() tmlog.Logger { - return kp.logger -} - -func (kp *DexKeeper) getFeeManager() *FeeManager { - return kp.FeeManager -} - -func (kp *DexKeeper) ShouldPublishOrder() bool { - return kp.CollectOrderInfoForPublish } -func (kp *DexKeeper) GetEngines() map[string]*me.MatchEng { - return kp.engines -} -func appendAllOrdersMap(ms ...map[string]map[string]*OrderInfo) map[string]map[string]*OrderInfo { - res := make(map[string]map[string]*OrderInfo) - for _, m := range ms { - for k, v := range m { - res[k] = v - } - } - return res +func (kp *DexKeeper) ClearRoundFee() { + kp.RoundOrderFees = make(map[string]*types.Fee, 256) } func (kp *DexKeeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { @@ -1029,14 +962,6 @@ func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset s return nil } -func (kp *DexKeeper) ClearAfterMatch() { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { - orderKeeper.clearAfterMatch() - } - } -} - func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator for _, orderKeeper := range kp.OrderKeepers { @@ -1067,22 +992,97 @@ func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int } } +func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(msg.Symbol) { + return orderKeeper.validateOrder(kp, context, account, msg) + } + } + return fmt.Errorf("symbol:%s is not supported", msg.Symbol) +} + + +func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportPairType(pairType) { + return orderKeeper.getOrderChanges() + } + } + kp.logger.Error("pairType is not supported %d", pairType) + return make(OrderChanges, 0) +} + +func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.appendOrderChange(change) + return + } + } + kp.logger.Error("symbol is not supported %d", symbol) +} + +func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(symbol) { + orderKeeper.appendOrderChangeSync(change) + return + } + } + kp.logger.Error("symbol is not supported %d", symbol) +} + +func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportPairType(pairType) { + return orderKeeper.getOrderInfosForPub() + } + } + kp.logger.Error("pairType is not supported %d", pairType) + return make(OrderInfoForPublish) + +} + +func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { + return kp.PairMapper +} + +func (kp *DexKeeper) getAccountKeeper() *auth.AccountKeeper { + return &kp.am +} + +func (kp *DexKeeper) getLogger() tmlog.Logger { + return kp.logger +} + +func (kp *DexKeeper) getFeeManager() *FeeManager { + return kp.FeeManager +} + +func (kp *DexKeeper) ShouldPublishOrder() bool { + return kp.CollectOrderInfoForPublish +} + +func (kp *DexKeeper) GetEngines() map[string]*me.MatchEng { + return kp.engines +} +func appendAllOrdersMap(ms ...map[string]map[string]*OrderInfo) map[string]map[string]*OrderInfo { + res := make(map[string]map[string]*OrderInfo) + for _, m := range ms { + for k, v := range m { + res[k] = v + } + } + return res +} + +func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { + return me.NewMatchEng(pairSymbol, basePrice, lotSize, 0.05) +} + func isMiniSymbolPair(baseAsset, quoteAsset string) bool { if sdk.IsUpgradeHeight(upgrade.BEP8) { return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) } return false } - -// channelHash() will choose a channel for processing by moding -// the sum of the last 7 bytes of address by bucketNumber. -// It may not be fully even. -// TODO: there is still concern on peroformance and evenness. -func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { - l := len(accAddress) - sum := 0 - for i := l - 7; i < l; i++ { - sum += int(accAddress[i]) - } - return sum % bucketNumber -} From 25cd11da0f8c197a973e7a63dd6735c3f42abf4a Mon Sep 17 00:00:00 2001 From: George Date: Sat, 9 May 2020 10:08:01 +0800 Subject: [PATCH 24/96] remove hardcode home in shell scripts --- networks/publisher/list_mini.sh | 14 +++++++++----- networks/publisher/newIndexer.sh | 14 +++++++++----- networks/publisher/newPublisher.sh | 14 +++++++++----- networks/publisher/newValidator.sh | 8 ++++---- networks/publisher/ordergen.sh | 9 +++++---- networks/publisher/setup.sh | 16 +++++++++++----- networks/publisher/setup_mini.sh | 16 +++++++++++----- 7 files changed, 58 insertions(+), 33 deletions(-) diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index 603ccd03a..38b0d1aff 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -6,12 +6,16 @@ # TODO: support two validator without docker in same machine ########################### SETUP ######################### -src='/Users/luerheng/go/src/github.com/binance-chain/node' -home='/Users/luerheng' -deamonhome='/Users/luerheng/.bnbchaind' -witnesshome='/Users/luerheng/.bnbchaind_witness' -clihome='/Users/luerheng/.bnbcli' +home=$HOME +src="${home}/go/src/github.com/binance-chain/node" +deamonhome="${home}/.bnbchaind" +witnesshome="${home}/.bnbchaind_witness" +clihome="${home}/.bnbcli" chain_id='test-chain-n4b735' +echo $src +echo $deamonhome +echo $witnesshome +echo $clihome key_seed_path="${home}" executable="${src}/build/bnbchaind" diff --git a/networks/publisher/newIndexer.sh b/networks/publisher/newIndexer.sh index 043af5ece..307279218 100755 --- a/networks/publisher/newIndexer.sh +++ b/networks/publisher/newIndexer.sh @@ -1,12 +1,16 @@ #!/usr/bin/env bash ########################### SETUP ######################### -src='/Users/zhaocong/go/src/github.com/binance-chain/node' -home='/Users/zhaocong' -deamonhome='/Users/zhaocong/.bnbchaind' -witnesshome='/Users/zhaocong/.bnbchaind_indexer' -clihome='/Users/zhaocong/.bnbcli' +home=$HOME +src="${home}/go/src/github.com/binance-chain/node" +deamonhome="${home}/.bnbchaind" +witnesshome="${home}/.bnbchaind_witness" +clihome="${home}/.bnbcli" chain_id='test-chain-n4b735' +echo $src +echo $deamonhome +echo $witnesshome +echo $clihome key_seed_path="${home}" executable="${src}/build/bnbchaind" diff --git a/networks/publisher/newPublisher.sh b/networks/publisher/newPublisher.sh index d0ff359f6..17e951913 100755 --- a/networks/publisher/newPublisher.sh +++ b/networks/publisher/newPublisher.sh @@ -1,12 +1,16 @@ #!/usr/bin/env bash ########################### SETUP ######################### -src='/Users/luerheng/go/src/github.com/binance-chain/node' -home='/Users/luerheng' -deamonhome='/Users/luerheng/.bnbchaind' -witnesshome='/Users/luerheng/.bnbchaind_publisher' -clihome='/Users/luerheng/.bnbcli' +home=$HOME +src="${home}/go/src/github.com/binance-chain/node" +deamonhome="${home}/.bnbchaind" +witnesshome="${home}/.bnbchaind_witness" +clihome="${home}/.bnbcli" chain_id='test-chain-n4b735' +echo $src +echo $deamonhome +echo $witnesshome +echo $clihome key_seed_path="${home}" executable="${src}/build/bnbchaind" diff --git a/networks/publisher/newValidator.sh b/networks/publisher/newValidator.sh index 8bdcca4b4..a4915fdd5 100755 --- a/networks/publisher/newValidator.sh +++ b/networks/publisher/newValidator.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash -src='/Users/zhaocong/go/src/github.com/binance-chain/node' -executable='/Users/zhaocong/go/src/github.com/binance-chain/node/build/bnbchaind' -cli='/Users/zhaocong/go/src/github.com/binance-chain/node/build/bnbcli' -home='/Users/zhaocong' +home=$HOME +src="${home}/go/src/github.com/binance-chain/node" +executable="${home}/go/src/github.com/binance-chain/node/build/bnbchaind" +cli="${home}/go/src/github.com/binance-chain/node/build/bnbcli" ## clean history data #rm -r ${home}/.bnbchaind_val2 diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index 655d1df1e..00d378f56 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -1,11 +1,12 @@ #!/bin/bash ########################### SETUP ######################### -clipath='/Users/luerheng/go/src/github.com/binance-chain/node/build/bnbcli' -home='/Users/luerheng' -clihome='/Users/luerheng/.bnbcli' +home=$HOME +src="${home}/go/src/github.com/binance-chain/node" +clipath="${home}/go/src/github.com/binance-chain/node/build/bnbcli" +clihome="${home}/.bnbcli" chainId='test-chain-n4b735' # should be same with publisher/setup.sh or testnet/deploy.sh -src='/Users/luerheng/go/src/github.com/binance-chain/node' + cli="${clipath} --home ${clihome}" scripthome="${src}/networks/publisher" diff --git a/networks/publisher/setup.sh b/networks/publisher/setup.sh index 12fe03445..a859b98c7 100755 --- a/networks/publisher/setup.sh +++ b/networks/publisher/setup.sh @@ -6,12 +6,16 @@ # TODO: support two validator without docker in same machine ########################### SETUP ######################### -src='/Users/zhaocong/go/src/github.com/binance-chain/node' -home='/Users/zhaocong' -deamonhome='/Users/zhaocong/.bnbchaind' -witnesshome='/Users/zhaocong/.bnbchaind_witness' -clihome='/Users/zhaocong/.bnbcli' +home=$HOME +src="${home}/go/src/github.com/binance-chain/node" +deamonhome="${home}/.bnbchaind" +witnesshome="${home}/.bnbchaind_witness" +clihome="${home}/.bnbcli" chain_id='test-chain-n4b735' +echo $src +echo $deamonhome +echo $witnesshome +echo $clihome key_seed_path="${home}" executable="${src}/build/bnbchaind" @@ -40,6 +44,8 @@ mkdir -p ${home}/.bnbchaind_witness/config sed -i -e "s/log_level = \"main:info,state:info,\*:error\"/log_level = \"debug\"/g" ${deamonhome}/config/config.toml sed -i -e "s/allow_duplicate_ip = false/allow_duplicate_ip = true/g" ${deamonhome}/config/config.toml sed -i -e "s/addr_book_strict = true/addr_book_strict = false/g" ${deamonhome}/config/config.toml +# for http-ap testing +sed -i -e "s/index_tags = \"\"/index_tags = \"tx.height\"/g" ${deamonhome}/config/config.toml sed -i -e 's/logToConsole = true/logToConsole = false/g' ${deamonhome}/config/app.toml sed -i -e 's/breatheBlockInterval = 0/breatheBlockInterval = 100/g' ${deamonhome}/config/app.toml diff --git a/networks/publisher/setup_mini.sh b/networks/publisher/setup_mini.sh index 876620868..53b4a4ed6 100755 --- a/networks/publisher/setup_mini.sh +++ b/networks/publisher/setup_mini.sh @@ -6,12 +6,16 @@ # TODO: support two validator without docker in same machine ########################### SETUP ######################### -src='/Users/luerheng/go/src/github.com/binance-chain/node' -home='/Users/luerheng' -deamonhome='/Users/luerheng/.bnbchaind' -witnesshome='/Users/luerheng/.bnbchaind_witness' -clihome='/Users/luerheng/.bnbcli' +home=$HOME +src="${home}/go/src/github.com/binance-chain/node" +deamonhome="${home}/.bnbchaind" +witnesshome="${home}/.bnbchaind_witness" +clihome="${home}/.bnbcli" chain_id='test-chain-n4b735' +echo $src +echo $deamonhome +echo $witnesshome +echo $clihome key_seed_path="${home}" executable="${src}/build/bnbchaind" @@ -40,6 +44,8 @@ mkdir -p ${home}/.bnbchaind_witness/config sed -i -e "s/log_level = \"main:info,state:info,\*:error\"/log_level = \"debug\"/g" ${deamonhome}/config/config.toml sed -i -e "s/allow_duplicate_ip = false/allow_duplicate_ip = true/g" ${deamonhome}/config/config.toml sed -i -e "s/addr_book_strict = true/addr_book_strict = false/g" ${deamonhome}/config/config.toml +# for http-ap testing +sed -i -e "s/index_tags = \"\"/index_tags = \"tx.height\"/g" ${deamonhome}/config/config.toml sed -i -e 's/logToConsole = true/logToConsole = false/g' ${deamonhome}/config/app.toml sed -i -e 's/breatheBlockInterval = 0/breatheBlockInterval = 100/g' ${deamonhome}/config/app.toml From e1dbad67e7101ba08ece48b5d3af73771bbd1f82 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sat, 9 May 2020 14:20:33 +0800 Subject: [PATCH 25/96] fix upgrade version --- networks/publisher/list_mini.sh | 8 ++++---- networks/publisher/ordergen.sh | 10 ++++++---- plugins/dex/order/keeper.go | 2 +- plugins/dex/order/keeper_recovery.go | 4 ++-- plugins/dex/order/mini_keeper.go | 4 ++-- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index 603ccd03a..5cb7cdab7 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -21,12 +21,12 @@ scripthome="${src}/networks/publisher" ############################ END ########################## #x1mini_symbol="x1mini-ED3" -result=$(${cli} miniToken issue --from=zc --token-name="X1MINI Coin" --symbol=X1M --total-supply=80000000000000 --token-type=2 --chain-id ${chain_id}) -x1mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "x1mini-[0-9A-Z]*") +result=$(${cli} miniToken issue --from=zc --token-name="Y2NINI Coin" --symbol=Y2N --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) +x1mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "Y2N-[0-9A-Z]*") echo ${x1mini_symbol} sleep 2 -echo 1234qwerasdf|${cli} dex list-mini -s=${x1mini_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} +echo 1234qwerasdf|${cli} dex list-mini -s=${x1mini_symbol} --quote-asset-symbol=BNB --init-price=100000000 --from=zc --chain-id ${chain_id} sleep 1 zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") -echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=20000000000000:${x1mini_symbol} --chain-id ${chain_id} +echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=200000000000:${x1mini_symbol} --chain-id ${chain_id} sleep 5 diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index 655d1df1e..e97f61a20 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -43,15 +43,17 @@ do pause=$(random 5 7) symbolNum=$(random 1 10) - symbol="NNB-5D4_BNB" + #symbol="NNB-5D4_BNB" + symbol="X1M-B0FM_BNB" if [ $symbolNum -lt 4 ] then - symbol="NNB-5D4_BNB" + symbol="X1M-B0FM_BNB" elif [ $symbolNum -lt 6 ] then - symbol="NNB-5D4_BNB" + symbol="Y2N-C47M_BNB" else [ $symbolNum -lt 8 ] - symbol="NNB-5D4_BNB" + #symbol="YCB-357_BNB" + symbol="Y2N-C47M_BNB" fi from="zc" if [ $side == 1 ] diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 4066ec4ae..d3d83feda 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -1081,7 +1081,7 @@ func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { } func isMiniSymbolPair(baseAsset, quoteAsset string) bool { - if sdk.IsUpgradeHeight(upgrade.BEP8) { + if sdk.IsUpgrade(upgrade.BEP8) { return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) } return false diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 151b4a84b..275fdfa5a 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -72,7 +72,7 @@ func (kp *DexKeeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedS for pair, eng := range kp.engines { buys, sells := eng.Book.GetAllLevels() var snapshot OrderBookSnapshot - if sdk.IsUpgradeHeight(upgrade.BEP8) { + if sdk.IsUpgrade(upgrade.BEP8) { snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice, LastMatchHeight: eng.LastMatchHeight} } else { snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice} @@ -158,7 +158,7 @@ func (kp *DexKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight in eng.Book.InsertPriceLevel(&pl, me.SELLSIDE) } eng.LastTradePrice = ob.LastTradePrice - if sdk.IsUpgradeHeight(upgrade.BEP8) { + if sdk.IsUpgrade(upgrade.BEP8) { eng.LastMatchHeight = ob.LastMatchHeight } ctx.Logger().Info("Successfully Loaded order snapshot", "pair", pair) diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index aa3e9043b..ae4a0a138 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -42,7 +42,7 @@ func NewMiniOrderKeeper() IDexOrderKeeper { //override func (kp *MiniOrderKeeper) support(pair string) bool { - if !sdk.IsUpgradeHeight(upgrade.BEP8) { + if !sdk.IsUpgrade(upgrade.BEP8) { return false } return dexUtils.IsMiniTokenTradingPair(pair) @@ -50,7 +50,7 @@ func (kp *MiniOrderKeeper) support(pair string) bool { //override func (kp *MiniOrderKeeper) supportUpgradeVersion() bool { - return sdk.IsUpgradeHeight(upgrade.BEP8) + return sdk.IsUpgrade(upgrade.BEP8) } func (kp *MiniOrderKeeper) supportPairType(pairType SymbolPairType) bool { From 7ddd914f34179a48244e8c1bf49266a1b927083a Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sat, 9 May 2020 14:46:58 +0800 Subject: [PATCH 26/96] add fork check --- networks/publisher/list_mini.sh | 2 +- networks/publisher/setup_mini.sh | 52 +++++++++++------------ plugins/minitokens/client/cli/commands.go | 2 +- plugins/minitokens/issue/msg.go | 2 +- plugins/tokens/issue/msg.go | 2 +- plugins/tokens/swap/handler.go | 17 +++++--- 6 files changed, 41 insertions(+), 36 deletions(-) diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index 7fb40344f..b8615552d 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -25,7 +25,7 @@ scripthome="${src}/networks/publisher" ############################ END ########################## #x1mini_symbol="x1mini-ED3" -result=$(${cli} miniToken issue --from=zc --token-name="Y2NINI Coin" --symbol=Y2N --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) +result=$(${cli} mini-token issue --from=zc --token-name="Y2NINI Coin" --symbol=Y2N --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) x1mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "Y2N-[0-9A-Z]*") echo ${x1mini_symbol} sleep 2 diff --git a/networks/publisher/setup_mini.sh b/networks/publisher/setup_mini.sh index 53b4a4ed6..adac067f1 100755 --- a/networks/publisher/setup_mini.sh +++ b/networks/publisher/setup_mini.sh @@ -86,29 +86,29 @@ result=$(expect ${scripthome}/recover.exp "${secret}" "zc" "${clipath}" "${cliho result=$(expect ${scripthome}/add_key.exp "zz" "${clipath}" "${clihome}") zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") -sleep 5 -# issue&list NNB and ZCB for ordergen -result=$(${cli} token issue --from=zc --token-name="New BNB Coin" --symbol=NNB --total-supply=2000000000000000 --chain-id ${chain_id}) -nnb_symbol=$(echo "${result}" | tail -n 1 | grep -o "NNB-[0-9A-Z]*") -echo ${nnb_symbol} -sleep 5 -((expire_time=$(date '+%s')+1000)) -${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${nnb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 8 --json -sleep 2 -${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 1 --option Yes --json -sleep 7 -${cli} dex list -s=${nnb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 1 -sleep 1 -result=$(${cli} token issue --from=zc --token-name="ZC Coin" --symbol=ZCB --total-supply=2000000000000000 --chain-id ${chain_id}) -zcb_symbol=$(echo "${result}" | tail -n 1 | grep -o "ZCB-[0-9A-Z]*") -echo ${zcb_symbol} -sleep 5 -((expire_time=$(date '+%s')+1000)) -${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${zcb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 5 --json -sleep 2 -${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 2 --option Yes --json -sleep 6 -${cli} dex list -s=${zcb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 2 -sleep 1 -${cli} send --from=zc --to=${zz_addr} --amount=1000000000000000:BNB --chain-id ${chain_id} -sleep 5 +#sleep 5 +## issue&list NNB and ZCB for ordergen +#result=$(${cli} token issue --from=zc --token-name="New BNB Coin" --symbol=NNB --total-supply=2000000000000000 --chain-id ${chain_id}) +#nnb_symbol=$(echo "${result}" | tail -n 1 | grep -o "NNB-[0-9A-Z]*") +#echo ${nnb_symbol} +#sleep 5 +#((expire_time=$(date '+%s')+1000)) +#${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${nnb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 8 --json +#sleep 2 +#${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 1 --option Yes --json +#sleep 7 +#${cli} dex list -s=${nnb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 1 +#sleep 1 +#result=$(${cli} token issue --from=zc --token-name="ZC Coin" --symbol=ZCB --total-supply=2000000000000000 --chain-id ${chain_id}) +#zcb_symbol=$(echo "${result}" | tail -n 1 | grep -o "ZCB-[0-9A-Z]*") +#echo ${zcb_symbol} +#sleep 5 +#((expire_time=$(date '+%s')+1000)) +#${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${zcb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 5 --json +#sleep 2 +#${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 2 --option Yes --json +#sleep 6 +#${cli} dex list -s=${zcb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 2 +#sleep 1 +#${cli} send --from=zc --to=${zz_addr} --amount=1000000000000000:BNB --chain-id ${chain_id} +#sleep 5 diff --git a/plugins/minitokens/client/cli/commands.go b/plugins/minitokens/client/cli/commands.go index 1baee7c1c..274682996 100644 --- a/plugins/minitokens/client/cli/commands.go +++ b/plugins/minitokens/client/cli/commands.go @@ -17,7 +17,7 @@ const ( func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { miniTokenCmd := &cobra.Command{ - Use: "miniToken", + Use: "mini-token", Short: "issue or view mini tokens", Long: ``, } diff --git a/plugins/minitokens/issue/msg.go b/plugins/minitokens/issue/msg.go index 6df2b4f69..f920aaa2f 100644 --- a/plugins/minitokens/issue/msg.go +++ b/plugins/minitokens/issue/msg.go @@ -66,7 +66,7 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { } if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.SupplyRangeType(msg.TokenType).UpperBound() { - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.SupplyRangeType(msg.TokenType).UpperBound())) + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinTotalSupply, types.SupplyRangeType(msg.TokenType).UpperBound())) } return nil diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index f5e27cb2d..fb55a2f68 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -129,7 +129,7 @@ func (msg MintMsg) validateMiniTokenBasic() sdk.Error { // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenSupplyUpperBound { - return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenSupplyUpperBound)) + return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d and %d", types.MiniTokenMinTotalSupply, types.MiniTokenSupplyUpperBound)) } return nil diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index b37193220..f9f3c3bf3 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" @@ -29,9 +30,11 @@ func NewHandler(kp Keeper) sdk.Handler { } func handleHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg HTLTMsg) sdk.Result { - symbolError := types.ValidateMapperTokenCoins(msg.Amount) - if symbolError != nil { - return sdk.ErrInvalidCoins(symbolError.Error()).Result() + if sdk.IsUpgrade(upgrade.BEP8) { + symbolError := types.ValidateMapperTokenCoins(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()).Result() + } } blockTime := ctx.BlockHeader().Time.Unix() if msg.Timestamp < blockTime-ThirtyMinutes || msg.Timestamp > blockTime+FifteenMinutes { @@ -67,9 +70,11 @@ func handleHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg HTLTMsg) sdk. } func handleDepositHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg DepositHTLTMsg) sdk.Result { - symbolError := types.ValidateMapperTokenCoins(msg.Amount) - if symbolError != nil { - return sdk.ErrInvalidCoins(symbolError.Error()).Result() + if sdk.IsUpgrade(upgrade.BEP8) { + symbolError := types.ValidateMapperTokenCoins(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()).Result() + } } swap := kp.GetSwap(ctx, msg.SwapID) if swap == nil { From e17252477ef4610676022a554d5e21382c44127a Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sat, 9 May 2020 15:42:45 +0800 Subject: [PATCH 27/96] fix mini match --- app/pub/helpers.go | 6 ++++-- networks/publisher/list_mini.sh | 4 ++-- networks/publisher/ordergen.sh | 10 ++++------ plugins/tokens/swap/handler.go | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index e31dc98e4..a3ee187a3 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -22,6 +22,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" abci "github.com/tendermint/tendermint/abci/types" + "github.com/binance-chain/node/plugins/dex/utils" ) func GetTradeAndOrdersRelatedAccounts(kp *orderPkg.DexKeeper, tradesToPublish []*Trade, pairType orderPkg.SymbolPairType) []string { @@ -324,10 +325,11 @@ func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, trad TickType: int(trade.TickType), } tradeIdx += 1 - if types.IsMiniTokenSymbol(symbol) { + if utils.IsMiniTokenTradingPair(symbol) { miniTradesToPublish = append(miniTradesToPublish, t) + }else { + tradesToPublish = append(tradesToPublish, t) } - tradesToPublish = append(tradesToPublish, t) } } return tradesToPublish, miniTradesToPublish diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index b8615552d..1546cef7a 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -25,8 +25,8 @@ scripthome="${src}/networks/publisher" ############################ END ########################## #x1mini_symbol="x1mini-ED3" -result=$(${cli} mini-token issue --from=zc --token-name="Y2NINI Coin" --symbol=Y2N --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) -x1mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "Y2N-[0-9A-Z]*") +result=$(${cli} mini-token issue --from=zc --token-name="X1M Coin" --symbol=X1M --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) +x1mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "X1M-[0-9A-Z]*") echo ${x1mini_symbol} sleep 2 echo 1234qwerasdf|${cli} dex list-mini -s=${x1mini_symbol} --quote-asset-symbol=BNB --init-price=100000000 --from=zc --chain-id ${chain_id} diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index 284dd7e4e..ee748a3a7 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -44,17 +44,15 @@ do pause=$(random 5 7) symbolNum=$(random 1 10) - #symbol="NNB-5D4_BNB" - symbol="X1M-B0FM_BNB" + symbol="YCB-E9D_BNB" if [ $symbolNum -lt 4 ] then - symbol="X1M-B0FM_BNB" + symbol="X1M-71AM_BNB" elif [ $symbolNum -lt 6 ] then - symbol="Y2N-C47M_BNB" + symbol="Y2N-02AM_BNB" else [ $symbolNum -lt 8 ] - #symbol="YCB-357_BNB" - symbol="Y2N-C47M_BNB" + symbol="ZCK-064_BNB" fi from="zc" if [ $side == 1 ] diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index f9f3c3bf3..b6950b564 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -4,11 +4,11 @@ import ( "bytes" "encoding/hex" "fmt" - "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" ) func NewHandler(kp Keeper) sdk.Handler { From 1c90c81e885186876b352de5bc640931ffa5e709 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sat, 9 May 2020 18:27:26 +0800 Subject: [PATCH 28/96] fix schema --- app/pub/msgs.go | 16 ++++++++-------- app/pub/publisher.go | 4 ++-- networks/publisher/list_mini.sh | 12 ++++++------ networks/publisher/ordergen.sh | 8 ++++---- networks/publisher/setup_mini.sh | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/pub/msgs.go b/app/pub/msgs.go index d835f9ea0..4304087da 100644 --- a/app/pub/msgs.go +++ b/app/pub/msgs.go @@ -98,8 +98,8 @@ type ExecutionResults struct { Orders Orders Proposals Proposals StakeUpdates StakeUpdates - miniTrades trades - miniOrders Orders + MiniTrades trades + MiniOrders Orders } func (msg *ExecutionResults) String() string { @@ -123,11 +123,11 @@ func (msg *ExecutionResults) ToNativeMap() map[string]interface{} { if msg.StakeUpdates.NumOfMsgs > 0 { native["stakeUpdates"] = map[string]interface{}{"org.binance.dex.model.avro.StakeUpdates": msg.StakeUpdates.ToNativeMap()} } - if msg.miniTrades.NumOfMsgs > 0 { - native["miniTrades"] = map[string]interface{}{"org.binance.dex.model.avro.Trades": msg.miniTrades.ToNativeMap()} + if msg.MiniTrades.NumOfMsgs > 0 { + native["miniTrades"] = map[string]interface{}{"org.binance.dex.model.avro.Trades": msg.MiniTrades.ToNativeMap()} } - if msg.miniOrders.NumOfMsgs > 0 { - native["miniOrders"] = map[string]interface{}{"org.binance.dex.model.avro.Orders": msg.miniOrders.ToNativeMap()} + if msg.MiniOrders.NumOfMsgs > 0 { + native["miniOrders"] = map[string]interface{}{"org.binance.dex.model.avro.Orders": msg.MiniOrders.ToNativeMap()} } return native } @@ -135,7 +135,7 @@ func (msg *ExecutionResults) ToNativeMap() map[string]interface{} { func (msg *ExecutionResults) EssentialMsg() string { // mainly used to recover for large breathe block expiring message, there should be no trade on breathe block orders := msg.Orders.EssentialMsg() - miniOrders := msg.miniOrders.EssentialMsg() + miniOrders := msg.MiniOrders.EssentialMsg() //TODO output other fields: trades, stakeUpdate etc. return fmt.Sprintf("height:%d\ntime:%d\norders:\n%s\nminiOrders:\n%s\n", msg.Height, msg.Timestamp, orders, miniOrders) } @@ -148,7 +148,7 @@ func (msg *ExecutionResults) EmptyCopy() AvroOrJsonMsg { } } var nonExpiredMiniOrders []*Order - for _, order := range msg.miniOrders.Orders { + for _, order := range msg.MiniOrders.Orders { if order.Status != orderPkg.Expired { nonExpiredMiniOrders = append(nonExpiredMiniOrders, order) } diff --git a/app/pub/publisher.go b/app/pub/publisher.go index f10e702c3..8b412ba0b 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -232,10 +232,10 @@ func publishExecutionResult(publisher MarketDataPublisher, height int64, timesta executionResultsMsg.StakeUpdates = *stakeUpdates } if numOfMiniOrders > 0 { - executionResultsMsg.miniOrders = Orders{numOfOrders, miniOrders} + executionResultsMsg.MiniOrders = Orders{numOfOrders, miniOrders} } if numOfMiniTrades > 0 { - executionResultsMsg.miniTrades = trades{numOfTrades, miniTrades} + executionResultsMsg.MiniTrades = trades{numOfTrades, miniTrades} } publisher.publish(&executionResultsMsg, executionResultTpe, height, timestamp) diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index 1546cef7a..14cedc127 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -24,13 +24,13 @@ cli="${clipath} --home ${clihome}" scripthome="${src}/networks/publisher" ############################ END ########################## -#x1mini_symbol="x1mini-ED3" -result=$(${cli} mini-token issue --from=zc --token-name="X1M Coin" --symbol=X1M --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) -x1mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "X1M-[0-9A-Z]*") -echo ${x1mini_symbol} +#Y2Bini_symbol="Y2Bini-ED3" +result=$(${cli} mini-token issue --from=zc --token-name="Y2B Coin" --symbol=Y2B --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) +Y2Bini_symbol=$(echo "${result}" | tail -n 1 | grep -o "Y2B-[0-9A-Z]*") +echo ${Y2Bini_symbol} sleep 2 -echo 1234qwerasdf|${cli} dex list-mini -s=${x1mini_symbol} --quote-asset-symbol=BNB --init-price=100000000 --from=zc --chain-id ${chain_id} +echo 1234qwerasdf|${cli} dex list-mini -s=${Y2Bini_symbol} --quote-asset-symbol=BNB --init-price=100000000 --from=zc --chain-id ${chain_id} sleep 1 zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") -echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=200000000000:${x1mini_symbol} --chain-id ${chain_id} +echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=200000000000:${Y2Bini_symbol} --chain-id ${chain_id} sleep 5 diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index ee748a3a7..34e324536 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -44,15 +44,15 @@ do pause=$(random 5 7) symbolNum=$(random 1 10) - symbol="YCB-E9D_BNB" + symbol="X1M-5B9M_BNB" if [ $symbolNum -lt 4 ] then - symbol="X1M-71AM_BNB" + symbol="Y2B-93AM_BNB" elif [ $symbolNum -lt 6 ] then - symbol="Y2N-02AM_BNB" + symbol="Y2B-93AM_BNB" else [ $symbolNum -lt 8 ] - symbol="ZCK-064_BNB" + symbol="X1M-5B9M_BNB" fi from="zc" if [ $side == 1 ] diff --git a/networks/publisher/setup_mini.sh b/networks/publisher/setup_mini.sh index adac067f1..740da48b2 100755 --- a/networks/publisher/setup_mini.sh +++ b/networks/publisher/setup_mini.sh @@ -86,7 +86,7 @@ result=$(expect ${scripthome}/recover.exp "${secret}" "zc" "${clipath}" "${cliho result=$(expect ${scripthome}/add_key.exp "zz" "${clipath}" "${clihome}") zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") -#sleep 5 +sleep 5 ## issue&list NNB and ZCB for ordergen #result=$(${cli} token issue --from=zc --token-name="New BNB Coin" --symbol=NNB --total-supply=2000000000000000 --chain-id ${chain_id}) #nnb_symbol=$(echo "${result}" | tail -n 1 | grep -o "NNB-[0-9A-Z]*") @@ -110,5 +110,5 @@ zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep #sleep 6 #${cli} dex list -s=${zcb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 2 #sleep 1 -#${cli} send --from=zc --to=${zz_addr} --amount=1000000000000000:BNB --chain-id ${chain_id} +${cli} send --from=zc --to=${zz_addr} --amount=1000000000000000:BNB --chain-id ${chain_id} #sleep 5 From 3d233901e35917395b61831e29ae819114f86b3f Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sat, 9 May 2020 19:21:45 +0800 Subject: [PATCH 29/96] add height before load snapshot --- networks/publisher/newPublisher.sh | 2 +- plugins/dex/order/keeper_recovery.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/networks/publisher/newPublisher.sh b/networks/publisher/newPublisher.sh index 17e951913..f70da490b 100755 --- a/networks/publisher/newPublisher.sh +++ b/networks/publisher/newPublisher.sh @@ -4,7 +4,7 @@ home=$HOME src="${home}/go/src/github.com/binance-chain/node" deamonhome="${home}/.bnbchaind" -witnesshome="${home}/.bnbchaind_witness" +witnesshome="${home}/.bnbchaind_publisher" clihome="${home}/.bnbcli" chain_id='test-chain-n4b735' echo $src diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 275fdfa5a..65ae532b0 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -124,6 +124,7 @@ func (kp *DexKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight in return height, nil } + upgrade.Mgr.SetHeight(height) kvStore := ctx.KVStore(kp.storeKey) for _, pair := range allPairs { symbol := pair.GetSymbol() From 55e0fc633f8614b555dea575d188fbd03d7c7a43 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Sat, 9 May 2020 20:32:16 +0800 Subject: [PATCH 30/96] fix mini publish number --- app/pub/publisher.go | 4 ++-- networks/publisher/list_mini.sh | 12 ++++++------ networks/publisher/ordergen.sh | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/pub/publisher.go b/app/pub/publisher.go index 8b412ba0b..7d8761a7a 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -232,10 +232,10 @@ func publishExecutionResult(publisher MarketDataPublisher, height int64, timesta executionResultsMsg.StakeUpdates = *stakeUpdates } if numOfMiniOrders > 0 { - executionResultsMsg.MiniOrders = Orders{numOfOrders, miniOrders} + executionResultsMsg.MiniOrders = Orders{numOfMiniOrders, miniOrders} } if numOfMiniTrades > 0 { - executionResultsMsg.MiniTrades = trades{numOfTrades, miniTrades} + executionResultsMsg.MiniTrades = trades{numOfMiniTrades, miniTrades} } publisher.publish(&executionResultsMsg, executionResultTpe, height, timestamp) diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index 14cedc127..560a0a974 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -24,13 +24,13 @@ cli="${clipath} --home ${clihome}" scripthome="${src}/networks/publisher" ############################ END ########################## -#Y2Bini_symbol="Y2Bini-ED3" -result=$(${cli} mini-token issue --from=zc --token-name="Y2B Coin" --symbol=Y2B --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) -Y2Bini_symbol=$(echo "${result}" | tail -n 1 | grep -o "Y2B-[0-9A-Z]*") -echo ${Y2Bini_symbol} +#X1Mini_symbol="X1Mini-ED3" +result=$(${cli} mini-token issue --from=zc --token-name="X1M Coin" --symbol=X1M --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) +X1Mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "X1M-[0-9A-Z]*") +echo ${X1Mini_symbol} sleep 2 -echo 1234qwerasdf|${cli} dex list-mini -s=${Y2Bini_symbol} --quote-asset-symbol=BNB --init-price=100000000 --from=zc --chain-id ${chain_id} +echo 1234qwerasdf|${cli} dex list-mini -s=${X1Mini_symbol} --quote-asset-symbol=BNB --init-price=100000000 --from=zc --chain-id ${chain_id} sleep 1 zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") -echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=200000000000:${Y2Bini_symbol} --chain-id ${chain_id} +echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=200000000000:${X1Mini_symbol} --chain-id ${chain_id} sleep 5 diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index 34e324536..d755ff4f0 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -44,15 +44,15 @@ do pause=$(random 5 7) symbolNum=$(random 1 10) - symbol="X1M-5B9M_BNB" + symbol="ZCK-980_BNB" if [ $symbolNum -lt 4 ] then - symbol="Y2B-93AM_BNB" + symbol="Y2B-822M_BNB" elif [ $symbolNum -lt 6 ] then - symbol="Y2B-93AM_BNB" + symbol="X1M-42FM_BNB" else [ $symbolNum -lt 8 ] - symbol="X1M-5B9M_BNB" + symbol="ZCK-CD6_BNB" fi from="zc" if [ $side == 1 ] From 372c1f19767eadae6278808992a13feffd97080d Mon Sep 17 00:00:00 2001 From: George Date: Mon, 11 May 2020 10:22:59 +0800 Subject: [PATCH 31/96] register minitoken wire --- common/types/wire.go | 1 + 1 file changed, 1 insertion(+) diff --git a/common/types/wire.go b/common/types/wire.go index 90e3161ae..e76c7adaf 100644 --- a/common/types/wire.go +++ b/common/types/wire.go @@ -13,4 +13,5 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(&AppAccount{}, "bnbchain/Account", nil) cdc.RegisterConcrete(Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(MiniToken{}, "bnbchain/MiniToken", nil) } From f53bf972972ac753fb6a180548220491b0d0d560 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 11 May 2020 11:17:55 +0800 Subject: [PATCH 32/96] Revert "Merge branch 'mini_token_bak' of https://github.com/binance-chain/node into mini_token_bak" This reverts commit 62a28cefde6a6d84200e5499ea1d8bf92108a8ca, reversing changes made to 55e0fc633f8614b555dea575d188fbd03d7c7a43. --- app/pub/helpers.go | 6 ++- app/pub/msgs.go | 16 ++++---- app/pub/publisher.go | 4 +- common/types/wire.go | 1 - networks/publisher/list_mini.sh | 12 +++--- networks/publisher/newPublisher.sh | 2 +- networks/publisher/ordergen.sh | 8 ++-- networks/publisher/setup_mini.sh | 48 +++++++++++------------ plugins/dex/order/keeper.go | 3 +- plugins/dex/order/keeper_recovery.go | 5 ++- plugins/dex/order/mini_keeper.go | 4 +- plugins/minitokens/client/cli/commands.go | 2 +- plugins/minitokens/issue/msg.go | 2 +- plugins/tokens/issue/msg.go | 2 +- plugins/tokens/swap/handler.go | 17 +++++--- 15 files changed, 69 insertions(+), 63 deletions(-) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index e31dc98e4..a3ee187a3 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -22,6 +22,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" abci "github.com/tendermint/tendermint/abci/types" + "github.com/binance-chain/node/plugins/dex/utils" ) func GetTradeAndOrdersRelatedAccounts(kp *orderPkg.DexKeeper, tradesToPublish []*Trade, pairType orderPkg.SymbolPairType) []string { @@ -324,10 +325,11 @@ func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, trad TickType: int(trade.TickType), } tradeIdx += 1 - if types.IsMiniTokenSymbol(symbol) { + if utils.IsMiniTokenTradingPair(symbol) { miniTradesToPublish = append(miniTradesToPublish, t) + }else { + tradesToPublish = append(tradesToPublish, t) } - tradesToPublish = append(tradesToPublish, t) } } return tradesToPublish, miniTradesToPublish diff --git a/app/pub/msgs.go b/app/pub/msgs.go index d835f9ea0..4304087da 100644 --- a/app/pub/msgs.go +++ b/app/pub/msgs.go @@ -98,8 +98,8 @@ type ExecutionResults struct { Orders Orders Proposals Proposals StakeUpdates StakeUpdates - miniTrades trades - miniOrders Orders + MiniTrades trades + MiniOrders Orders } func (msg *ExecutionResults) String() string { @@ -123,11 +123,11 @@ func (msg *ExecutionResults) ToNativeMap() map[string]interface{} { if msg.StakeUpdates.NumOfMsgs > 0 { native["stakeUpdates"] = map[string]interface{}{"org.binance.dex.model.avro.StakeUpdates": msg.StakeUpdates.ToNativeMap()} } - if msg.miniTrades.NumOfMsgs > 0 { - native["miniTrades"] = map[string]interface{}{"org.binance.dex.model.avro.Trades": msg.miniTrades.ToNativeMap()} + if msg.MiniTrades.NumOfMsgs > 0 { + native["miniTrades"] = map[string]interface{}{"org.binance.dex.model.avro.Trades": msg.MiniTrades.ToNativeMap()} } - if msg.miniOrders.NumOfMsgs > 0 { - native["miniOrders"] = map[string]interface{}{"org.binance.dex.model.avro.Orders": msg.miniOrders.ToNativeMap()} + if msg.MiniOrders.NumOfMsgs > 0 { + native["miniOrders"] = map[string]interface{}{"org.binance.dex.model.avro.Orders": msg.MiniOrders.ToNativeMap()} } return native } @@ -135,7 +135,7 @@ func (msg *ExecutionResults) ToNativeMap() map[string]interface{} { func (msg *ExecutionResults) EssentialMsg() string { // mainly used to recover for large breathe block expiring message, there should be no trade on breathe block orders := msg.Orders.EssentialMsg() - miniOrders := msg.miniOrders.EssentialMsg() + miniOrders := msg.MiniOrders.EssentialMsg() //TODO output other fields: trades, stakeUpdate etc. return fmt.Sprintf("height:%d\ntime:%d\norders:\n%s\nminiOrders:\n%s\n", msg.Height, msg.Timestamp, orders, miniOrders) } @@ -148,7 +148,7 @@ func (msg *ExecutionResults) EmptyCopy() AvroOrJsonMsg { } } var nonExpiredMiniOrders []*Order - for _, order := range msg.miniOrders.Orders { + for _, order := range msg.MiniOrders.Orders { if order.Status != orderPkg.Expired { nonExpiredMiniOrders = append(nonExpiredMiniOrders, order) } diff --git a/app/pub/publisher.go b/app/pub/publisher.go index f10e702c3..7d8761a7a 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -232,10 +232,10 @@ func publishExecutionResult(publisher MarketDataPublisher, height int64, timesta executionResultsMsg.StakeUpdates = *stakeUpdates } if numOfMiniOrders > 0 { - executionResultsMsg.miniOrders = Orders{numOfOrders, miniOrders} + executionResultsMsg.MiniOrders = Orders{numOfMiniOrders, miniOrders} } if numOfMiniTrades > 0 { - executionResultsMsg.miniTrades = trades{numOfTrades, miniTrades} + executionResultsMsg.MiniTrades = trades{numOfMiniTrades, miniTrades} } publisher.publish(&executionResultsMsg, executionResultTpe, height, timestamp) diff --git a/common/types/wire.go b/common/types/wire.go index e76c7adaf..90e3161ae 100644 --- a/common/types/wire.go +++ b/common/types/wire.go @@ -13,5 +13,4 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(&AppAccount{}, "bnbchain/Account", nil) cdc.RegisterConcrete(Token{}, "bnbchain/Token", nil) - cdc.RegisterConcrete(MiniToken{}, "bnbchain/MiniToken", nil) } diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index 38b0d1aff..560a0a974 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -24,13 +24,13 @@ cli="${clipath} --home ${clihome}" scripthome="${src}/networks/publisher" ############################ END ########################## -#x1mini_symbol="x1mini-ED3" -result=$(${cli} miniToken issue --from=zc --token-name="X1MINI Coin" --symbol=X1M --total-supply=80000000000000 --token-type=2 --chain-id ${chain_id}) -x1mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "x1mini-[0-9A-Z]*") -echo ${x1mini_symbol} +#X1Mini_symbol="X1Mini-ED3" +result=$(${cli} mini-token issue --from=zc --token-name="X1M Coin" --symbol=X1M --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) +X1Mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "X1M-[0-9A-Z]*") +echo ${X1Mini_symbol} sleep 2 -echo 1234qwerasdf|${cli} dex list-mini -s=${x1mini_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} +echo 1234qwerasdf|${cli} dex list-mini -s=${X1Mini_symbol} --quote-asset-symbol=BNB --init-price=100000000 --from=zc --chain-id ${chain_id} sleep 1 zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") -echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=20000000000000:${x1mini_symbol} --chain-id ${chain_id} +echo 1234qwerasdf|${cli} send --from=zc --to=${zz_addr} --amount=200000000000:${X1Mini_symbol} --chain-id ${chain_id} sleep 5 diff --git a/networks/publisher/newPublisher.sh b/networks/publisher/newPublisher.sh index 17e951913..f70da490b 100755 --- a/networks/publisher/newPublisher.sh +++ b/networks/publisher/newPublisher.sh @@ -4,7 +4,7 @@ home=$HOME src="${home}/go/src/github.com/binance-chain/node" deamonhome="${home}/.bnbchaind" -witnesshome="${home}/.bnbchaind_witness" +witnesshome="${home}/.bnbchaind_publisher" clihome="${home}/.bnbcli" chain_id='test-chain-n4b735' echo $src diff --git a/networks/publisher/ordergen.sh b/networks/publisher/ordergen.sh index 00d378f56..d755ff4f0 100755 --- a/networks/publisher/ordergen.sh +++ b/networks/publisher/ordergen.sh @@ -44,15 +44,15 @@ do pause=$(random 5 7) symbolNum=$(random 1 10) - symbol="NNB-5D4_BNB" + symbol="ZCK-980_BNB" if [ $symbolNum -lt 4 ] then - symbol="NNB-5D4_BNB" + symbol="Y2B-822M_BNB" elif [ $symbolNum -lt 6 ] then - symbol="NNB-5D4_BNB" + symbol="X1M-42FM_BNB" else [ $symbolNum -lt 8 ] - symbol="NNB-5D4_BNB" + symbol="ZCK-CD6_BNB" fi from="zc" if [ $side == 1 ] diff --git a/networks/publisher/setup_mini.sh b/networks/publisher/setup_mini.sh index 53b4a4ed6..740da48b2 100755 --- a/networks/publisher/setup_mini.sh +++ b/networks/publisher/setup_mini.sh @@ -87,28 +87,28 @@ result=$(expect ${scripthome}/add_key.exp "zz" "${clipath}" "${clihome}") zz_addr=$(${cli} keys list | grep "zz.*local" | grep -o "bnb[0-9a-zA-Z]*" | grep -v "bnbp") sleep 5 -# issue&list NNB and ZCB for ordergen -result=$(${cli} token issue --from=zc --token-name="New BNB Coin" --symbol=NNB --total-supply=2000000000000000 --chain-id ${chain_id}) -nnb_symbol=$(echo "${result}" | tail -n 1 | grep -o "NNB-[0-9A-Z]*") -echo ${nnb_symbol} -sleep 5 -((expire_time=$(date '+%s')+1000)) -${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${nnb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 8 --json -sleep 2 -${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 1 --option Yes --json -sleep 7 -${cli} dex list -s=${nnb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 1 -sleep 1 -result=$(${cli} token issue --from=zc --token-name="ZC Coin" --symbol=ZCB --total-supply=2000000000000000 --chain-id ${chain_id}) -zcb_symbol=$(echo "${result}" | tail -n 1 | grep -o "ZCB-[0-9A-Z]*") -echo ${zcb_symbol} -sleep 5 -((expire_time=$(date '+%s')+1000)) -${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${zcb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 5 --json -sleep 2 -${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 2 --option Yes --json -sleep 6 -${cli} dex list -s=${zcb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 2 -sleep 1 +## issue&list NNB and ZCB for ordergen +#result=$(${cli} token issue --from=zc --token-name="New BNB Coin" --symbol=NNB --total-supply=2000000000000000 --chain-id ${chain_id}) +#nnb_symbol=$(echo "${result}" | tail -n 1 | grep -o "NNB-[0-9A-Z]*") +#echo ${nnb_symbol} +#sleep 5 +#((expire_time=$(date '+%s')+1000)) +#${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${nnb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 8 --json +#sleep 2 +#${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 1 --option Yes --json +#sleep 7 +#${cli} dex list -s=${nnb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 1 +#sleep 1 +#result=$(${cli} token issue --from=zc --token-name="ZC Coin" --symbol=ZCB --total-supply=2000000000000000 --chain-id ${chain_id}) +#zcb_symbol=$(echo "${result}" | tail -n 1 | grep -o "ZCB-[0-9A-Z]*") +#echo ${zcb_symbol} +#sleep 5 +#((expire_time=$(date '+%s')+1000)) +#${cli} gov submit-list-proposal --chain-id ${chain_id} --from zc --deposit 200000000000:BNB --base-asset-symbol ${zcb_symbol} --quote-asset-symbol BNB --init-price 1000000000 --title "list NNB/BNB" --description "list NNB/BNB" --expire-time ${expire_time} --voting-period 5 --json +#sleep 2 +#${cli} gov vote --from zc --chain-id ${chain_id} --proposal-id 2 --option Yes --json +#sleep 6 +#${cli} dex list -s=${zcb_symbol} --quote-asset-symbol=BNB --init-price=1000000000 --from=zc --chain-id ${chain_id} --proposal-id 2 +#sleep 1 ${cli} send --from=zc --to=${zz_addr} --amount=1000000000000000:BNB --chain-id ${chain_id} -sleep 5 +#sleep 5 diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 4066ec4ae..2618b9e00 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -1001,7 +1001,6 @@ func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg return fmt.Errorf("symbol:%s is not supported", msg.Symbol) } - func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { for _, orderKeeper := range kp.OrderKeepers { if orderKeeper.supportPairType(pairType) { @@ -1081,7 +1080,7 @@ func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { } func isMiniSymbolPair(baseAsset, quoteAsset string) bool { - if sdk.IsUpgradeHeight(upgrade.BEP8) { + if sdk.IsUpgrade(upgrade.BEP8) { return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) } return false diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 151b4a84b..65ae532b0 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -72,7 +72,7 @@ func (kp *DexKeeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedS for pair, eng := range kp.engines { buys, sells := eng.Book.GetAllLevels() var snapshot OrderBookSnapshot - if sdk.IsUpgradeHeight(upgrade.BEP8) { + if sdk.IsUpgrade(upgrade.BEP8) { snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice, LastMatchHeight: eng.LastMatchHeight} } else { snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice} @@ -124,6 +124,7 @@ func (kp *DexKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight in return height, nil } + upgrade.Mgr.SetHeight(height) kvStore := ctx.KVStore(kp.storeKey) for _, pair := range allPairs { symbol := pair.GetSymbol() @@ -158,7 +159,7 @@ func (kp *DexKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight in eng.Book.InsertPriceLevel(&pl, me.SELLSIDE) } eng.LastTradePrice = ob.LastTradePrice - if sdk.IsUpgradeHeight(upgrade.BEP8) { + if sdk.IsUpgrade(upgrade.BEP8) { eng.LastMatchHeight = ob.LastMatchHeight } ctx.Logger().Info("Successfully Loaded order snapshot", "pair", pair) diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index aa3e9043b..ae4a0a138 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -42,7 +42,7 @@ func NewMiniOrderKeeper() IDexOrderKeeper { //override func (kp *MiniOrderKeeper) support(pair string) bool { - if !sdk.IsUpgradeHeight(upgrade.BEP8) { + if !sdk.IsUpgrade(upgrade.BEP8) { return false } return dexUtils.IsMiniTokenTradingPair(pair) @@ -50,7 +50,7 @@ func (kp *MiniOrderKeeper) support(pair string) bool { //override func (kp *MiniOrderKeeper) supportUpgradeVersion() bool { - return sdk.IsUpgradeHeight(upgrade.BEP8) + return sdk.IsUpgrade(upgrade.BEP8) } func (kp *MiniOrderKeeper) supportPairType(pairType SymbolPairType) bool { diff --git a/plugins/minitokens/client/cli/commands.go b/plugins/minitokens/client/cli/commands.go index 1baee7c1c..274682996 100644 --- a/plugins/minitokens/client/cli/commands.go +++ b/plugins/minitokens/client/cli/commands.go @@ -17,7 +17,7 @@ const ( func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { miniTokenCmd := &cobra.Command{ - Use: "miniToken", + Use: "mini-token", Short: "issue or view mini tokens", Long: ``, } diff --git a/plugins/minitokens/issue/msg.go b/plugins/minitokens/issue/msg.go index 6df2b4f69..f920aaa2f 100644 --- a/plugins/minitokens/issue/msg.go +++ b/plugins/minitokens/issue/msg.go @@ -66,7 +66,7 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { } if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.SupplyRangeType(msg.TokenType).UpperBound() { - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.SupplyRangeType(msg.TokenType).UpperBound())) + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinTotalSupply, types.SupplyRangeType(msg.TokenType).UpperBound())) } return nil diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index f5e27cb2d..fb55a2f68 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -129,7 +129,7 @@ func (msg MintMsg) validateMiniTokenBasic() sdk.Error { // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenSupplyUpperBound { - return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d ~ %d", types.MiniTokenMinTotalSupply, types.MiniTokenSupplyUpperBound)) + return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d and %d", types.MiniTokenMinTotalSupply, types.MiniTokenSupplyUpperBound)) } return nil diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index b37193220..b6950b564 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" ) func NewHandler(kp Keeper) sdk.Handler { @@ -29,9 +30,11 @@ func NewHandler(kp Keeper) sdk.Handler { } func handleHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg HTLTMsg) sdk.Result { - symbolError := types.ValidateMapperTokenCoins(msg.Amount) - if symbolError != nil { - return sdk.ErrInvalidCoins(symbolError.Error()).Result() + if sdk.IsUpgrade(upgrade.BEP8) { + symbolError := types.ValidateMapperTokenCoins(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()).Result() + } } blockTime := ctx.BlockHeader().Time.Unix() if msg.Timestamp < blockTime-ThirtyMinutes || msg.Timestamp > blockTime+FifteenMinutes { @@ -67,9 +70,11 @@ func handleHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg HTLTMsg) sdk. } func handleDepositHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg DepositHTLTMsg) sdk.Result { - symbolError := types.ValidateMapperTokenCoins(msg.Amount) - if symbolError != nil { - return sdk.ErrInvalidCoins(symbolError.Error()).Result() + if sdk.IsUpgrade(upgrade.BEP8) { + symbolError := types.ValidateMapperTokenCoins(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()).Result() + } } swap := kp.GetSwap(ctx, msg.SwapID) if swap == nil { From 9b15a1bde6f5eaaea4f9df8c2a661789305b248a Mon Sep 17 00:00:00 2001 From: George Date: Mon, 11 May 2020 11:21:44 +0800 Subject: [PATCH 33/96] register mini token wire --- common/types/wire.go | 1 + 1 file changed, 1 insertion(+) diff --git a/common/types/wire.go b/common/types/wire.go index 90e3161ae..e76c7adaf 100644 --- a/common/types/wire.go +++ b/common/types/wire.go @@ -13,4 +13,5 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(&AppAccount{}, "bnbchain/Account", nil) cdc.RegisterConcrete(Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(MiniToken{}, "bnbchain/MiniToken", nil) } From 6c2045ead35fd6216cd7ae1048ad6ca5b2d74252 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 11 May 2020 16:56:50 +0800 Subject: [PATCH 34/96] add mini-token api query --- plugins/api/handlers.go | 23 +++++++++++--- plugins/api/routes.go | 11 ++++++- plugins/dex/abci.go | 41 +++++++++++++++++++++++-- plugins/dex/client/rest/getpairs.go | 8 ++--- plugins/minitokens/issue/handler.go | 2 +- plugins/minitokens/seturi/handler.go | 2 +- plugins/tokens/burn/handler.go | 2 +- plugins/tokens/client/rest/gettoken.go | 14 ++++++--- plugins/tokens/client/rest/gettokens.go | 14 ++++++--- plugins/tokens/freeze/handler.go | 4 +-- 10 files changed, 97 insertions(+), 24 deletions(-) diff --git a/plugins/api/handlers.go b/plugins/api/handlers.go index 7757c2403..9007d1f98 100644 --- a/plugins/api/handlers.go +++ b/plugins/api/handlers.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" hnd "github.com/binance-chain/node/plugins/api/handlers" + "github.com/binance-chain/node/plugins/dex" dexapi "github.com/binance-chain/node/plugins/dex/client/rest" paramapi "github.com/binance-chain/node/plugins/param/client/rest" tksapi "github.com/binance-chain/node/plugins/tokens/client/rest" @@ -94,10 +95,15 @@ func (s *server) handleSimulateReq(cdc *wire.Codec, ctx context.CLIContext) http return s.withTextPlainForm(s.limitReqSize(h)) } -func (s *server) handlePairsReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { - return dexapi.GetPairsReqHandler(cdc, ctx) +func (s *server) handleBEP2PairsReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { + return dexapi.GetPairsReqHandler(cdc, ctx, dex.DexAbciQueryPrefix) } +func (s *server) handleMiniPairsReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { + return dexapi.GetPairsReqHandler(cdc, ctx, dex.DexMiniAbciQueryPrefix) +} + + func (s *server) handleDexDepthReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { return dexapi.DepthReqHandler(cdc, ctx) } @@ -112,13 +118,22 @@ func (s *server) handleDexOpenOrdersReq(cdc *wire.Codec, ctx context.CLIContext) } func (s *server) handleTokenReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { - return tksapi.GetTokenReqHandler(cdc, ctx) + return tksapi.GetTokenReqHandler(cdc, ctx, false) } func (s *server) handleTokensReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { - return tksapi.GetTokensReqHandler(cdc, ctx) + return tksapi.GetTokensReqHandler(cdc, ctx, true) +} + +func (s *server) handleMiniTokenReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { + return tksapi.GetTokenReqHandler(cdc, ctx, true) +} + +func (s *server) handleMiniTokensReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { + return tksapi.GetTokensReqHandler(cdc, ctx, true) } + func (s *server) handleBalancesReq(cdc *wire.Codec, ctx context.CLIContext, tokens tkstore.Mapper) http.HandlerFunc { return tksapi.BalancesReqHandler(cdc, ctx, tokens) } diff --git a/plugins/api/routes.go b/plugins/api/routes.go index 70b0c8874..b30c43418 100644 --- a/plugins/api/routes.go +++ b/plugins/api/routes.go @@ -29,7 +29,7 @@ func (s *server) bindRoutes() *server { Methods("POST") // dex routes - r.HandleFunc(prefix+"/markets", s.handlePairsReq(s.cdc, s.ctx)). + r.HandleFunc(prefix+"/markets", s.handleBEP2PairsReq(s.cdc, s.ctx)). Methods("GET") r.HandleFunc(prefix+"/depth", s.handleDexDepthReq(s.cdc, s.ctx)). Queries("symbol", "{symbol}", "limit", "{limit:[0-9]+}"). @@ -44,6 +44,9 @@ func (s *server) bindRoutes() *server { Queries("address", "{address}", "symbol", "{symbol}"). Methods("GET") + r.HandleFunc(prefix+"/mini-token/markets", s.handleMiniPairsReq(s.cdc, s.ctx)). + Methods("GET") + // tokens routes r.HandleFunc(prefix+"/tokens", s.handleTokensReq(s.cdc, s.ctx)). Methods("GET") @@ -54,6 +57,12 @@ func (s *server) bindRoutes() *server { r.HandleFunc(prefix+"/balances/{address}/{symbol}", s.handleBalanceReq(s.cdc, s.ctx, s.tokens)). Methods("GET") + // mini tokens routes + r.HandleFunc(prefix+"/mini-token/tokens", s.handleMiniTokensReq(s.cdc, s.ctx)). + Methods("GET") + r.HandleFunc(prefix+"/mini-token/tokens/{symbol}", s.handleMiniTokenReq(s.cdc, s.ctx)). + Methods("GET") + // fee params r.HandleFunc(prefix+"/fees", s.handleFeesParamReq(s.cdc, s.ctx)). Methods("GET") diff --git a/plugins/dex/abci.go b/plugins/dex/abci.go index 1ddd28686..cf9148710 100644 --- a/plugins/dex/abci.go +++ b/plugins/dex/abci.go @@ -26,7 +26,7 @@ func createAbciQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQ return nil } switch path[1] { - case "pairs": // args: ["dex", "pairs", , ] + case "pairs": // args: ["dex" or "dex_mini", "pairs", , ] if len(path) < 4 { return &abci.ResponseQuery{ Code: uint32(sdk.CodeUnknownRequest), @@ -36,7 +36,7 @@ func createAbciQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQ } } ctx := app.GetContextForCheckState() - pairs := keeper.PairMapper.ListAllTradingPairs(ctx) + pairs := listPairs(keeper, ctx, queryPrefix) var offset, limit, end int var err error if pairs == nil || len(pairs) == 0 { @@ -82,6 +82,14 @@ func createAbciQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQ Value: bz, } case "orderbook": // args: ["dex", "orderbook"] + if queryPrefix == DexMiniAbciQueryPrefix { + return &abci.ResponseQuery{ + Code: uint32(sdk.ABCICodeOK), + Info: fmt.Sprintf( + "Unknown `%s` query path: %v", + queryPrefix, path), + } + } //TODO: sync lock, validate pair if len(path) < 3 { return &abci.ResponseQuery{ @@ -124,6 +132,14 @@ func createAbciQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQ Value: bz, } case "openorders": // args: ["dex", "openorders", , ] + if queryPrefix == DexMiniAbciQueryPrefix { + return &abci.ResponseQuery{ + Code: uint32(sdk.ABCICodeOK), + Info: fmt.Sprintf( + "Unknown `%s` query path: %v", + queryPrefix, path), + } + } if len(path) < 4 { return &abci.ResponseQuery{ Code: uint32(sdk.CodeUnknownRequest), @@ -179,3 +195,24 @@ func createAbciQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQ } } } + +func listPairs(keeper *DexKeeper, ctx sdk.Context, abciPrefix string) []types.TradingPair { + pairs := keeper.PairMapper.ListAllTradingPairs(ctx) + rs := make([]types.TradingPair, 0, len(pairs)) + for _, pair := range pairs { + if isMiniPair(pair) { + if abciPrefix == DexMiniAbciQueryPrefix { + rs = append(rs, pair) + } + } else { + if abciPrefix == DexAbciQueryPrefix { + rs = append(rs, pair) + } + } + } + return rs +} + +func isMiniPair(pair types.TradingPair) bool { + return app.IsMiniTokenSymbol(pair.BaseAssetSymbol) || app.IsMiniTokenSymbol(pair.QuoteAssetSymbol) +} diff --git a/plugins/dex/client/rest/getpairs.go b/plugins/dex/client/rest/getpairs.go index cb755a9c9..200551229 100644 --- a/plugins/dex/client/rest/getpairs.go +++ b/plugins/dex/client/rest/getpairs.go @@ -16,8 +16,8 @@ const maxPairsLimit = 1000 const defaultPairsLimit = 100 const defaultPairsOffset = 0 -func listAllTradingPairs(ctx context.CLIContext, cdc *wire.Codec, offset int, limit int) ([]types.TradingPair, error) { - bz, err := ctx.Query(fmt.Sprintf("dex/pairs/%d/%d", offset, limit), nil) +func listAllTradingPairs(ctx context.CLIContext, cdc *wire.Codec, prefix string, offset int, limit int) ([]types.TradingPair, error) { + bz, err := ctx.Query(fmt.Sprintf("%s/pairs/%d/%d", prefix, offset, limit), nil) if err != nil { return nil, err } @@ -27,7 +27,7 @@ func listAllTradingPairs(ctx context.CLIContext, cdc *wire.Codec, offset int, li } // GetPairsReqHandler creates an http request handler to list -func GetPairsReqHandler(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { +func GetPairsReqHandler(cdc *wire.Codec, ctx context.CLIContext, abciQueryPrefix string) http.HandlerFunc { type params struct { limit int offset int @@ -79,7 +79,7 @@ func GetPairsReqHandler(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFun params.limit = maxPairsLimit } - pairs, err := listAllTradingPairs(ctx, cdc, params.offset, params.limit) + pairs, err := listAllTradingPairs(ctx, cdc, abciQueryPrefix, params.offset, params.limit) if err != nil { throw(w, http.StatusInternalServerError, err) return diff --git a/plugins/minitokens/issue/handler.go b/plugins/minitokens/issue/handler.go index b66d0aeb2..df9f77a88 100644 --- a/plugins/minitokens/issue/handler.go +++ b/plugins/minitokens/issue/handler.go @@ -32,7 +32,7 @@ func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handl func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKeeper bank.Keeper, msg IssueMsg) sdk.Result { errLogMsg := "issue miniToken failed" symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "miniToken", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) + logger := log.With("module", "mini-token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) var suffix string if !sdk.IsUpgrade(upgrade.BEP8) { diff --git a/plugins/minitokens/seturi/handler.go b/plugins/minitokens/seturi/handler.go index ab43543bf..f4f7e74b3 100644 --- a/plugins/minitokens/seturi/handler.go +++ b/plugins/minitokens/seturi/handler.go @@ -26,7 +26,7 @@ func NewHandler(tokenMapper store.MiniTokenMapper) sdk.Handler { func handleSetURI(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, msg SetURIMsg) sdk.Result { symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "miniToken", "symbol", symbol, "tokenURI", msg.TokenURI, "from", msg.From) + logger := log.With("module", "mini-token", "symbol", symbol, "tokenURI", msg.TokenURI, "from", msg.From) errLogMsg := "set token URI failed" token, err := miniTokenMapper.GetToken(ctx, symbol) diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 3d7a31ad7..3063ed21a 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -72,7 +72,7 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep } func handleBurnMiniToken(ctx sdk.Context, tokenMapper miniToken.MiniTokenMapper, keeper bank.Keeper, msg BurnMsg) sdk.Result { - logger := log.With("module", "miniToken", "symbol", msg.Symbol, "amount", msg.Amount) + logger := log.With("module", "mini-token", "symbol", msg.Symbol, "amount", msg.Amount) burnAmount := msg.Amount symbol := strings.ToUpper(msg.Symbol) token, err := tokenMapper.GetToken(ctx, symbol) diff --git a/plugins/tokens/client/rest/gettoken.go b/plugins/tokens/client/rest/gettoken.go index 38378e9a9..1fe0aac45 100644 --- a/plugins/tokens/client/rest/gettoken.go +++ b/plugins/tokens/client/rest/gettoken.go @@ -14,8 +14,14 @@ import ( "github.com/binance-chain/node/wire" ) -func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string) (*types.Token, error) { - bz, err := ctx.Query(fmt.Sprintf("tokens/info/%s", symbol), nil) +func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini bool) (*types.Token, error) { + var abciPrefix string + if isMini { + abciPrefix = "mini-tokens" + }else{ + abciPrefix = "tokens" + } + bz, err := ctx.Query(fmt.Sprintf("%s/info/%s", abciPrefix, symbol), nil) if err != nil { return nil, err } @@ -25,7 +31,7 @@ func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string) (*type } // GetTokenReqHandler creates an http request handler to get info for an individual token -func GetTokenReqHandler(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { +func GetTokenReqHandler(cdc *wire.Codec, ctx context.CLIContext, isMini bool) http.HandlerFunc { type params struct { symbol string } @@ -55,7 +61,7 @@ func GetTokenReqHandler(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFun return } - token, err := getTokenInfo(ctx, cdc, params.symbol) + token, err := getTokenInfo(ctx, cdc, params.symbol, isMini) if err != nil { throw(w, http.StatusInternalServerError, err) return diff --git a/plugins/tokens/client/rest/gettokens.go b/plugins/tokens/client/rest/gettokens.go index 51af8d5f0..2fd26ea15 100644 --- a/plugins/tokens/client/rest/gettokens.go +++ b/plugins/tokens/client/rest/gettokens.go @@ -17,8 +17,14 @@ const maxTokensLimit = 1000 const defaultTokensLimit = 100 const defaultTokensOffset = 0 -func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit int, showZeroSupplyTokens bool) ([]types.Token, error) { - bz, err := ctx.Query(fmt.Sprintf("tokens/list/%d/%d/%s", offset, limit, strconv.FormatBool(showZeroSupplyTokens)), nil) +func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit int, showZeroSupplyTokens bool, isMini bool) ([]types.Token, error) { + var abciPrefix string + if isMini { + abciPrefix = "mini-tokens" + }else{ + abciPrefix = "tokens" + } + bz, err := ctx.Query(fmt.Sprintf("%s/list/%d/%d/%s", abciPrefix, offset, limit, strconv.FormatBool(showZeroSupplyTokens)), nil) if err != nil { return nil, err } @@ -28,7 +34,7 @@ func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit in } // GetTokensReqHandler creates an http request handler to get the list of tokens in the token mapper -func GetTokensReqHandler(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { +func GetTokensReqHandler(cdc *wire.Codec, ctx context.CLIContext, isMini bool) http.HandlerFunc { type params struct { limit int offset int @@ -88,7 +94,7 @@ func GetTokensReqHandler(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFu params.limit = maxTokensLimit } - tokens, err := listAllTokens(ctx, cdc, params.offset, params.limit, params.showZeroSupplyTokens) + tokens, err := listAllTokens(ctx, cdc, params.offset, params.limit, params.showZeroSupplyTokens, isMini) if err != nil { throw(w, http.StatusInternalServerError, err) return diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index e08005f1e..cc1052eed 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -89,7 +89,7 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg FreezeMsg) sdk.Result { freezeAmount := msg.Amount symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "miniToken", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) + logger := log.With("module", "mini-token", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) errLogMsg := "freeze token failed" _, err := miniTokenMapper.GetToken(ctx, symbol) if err != nil { @@ -124,7 +124,7 @@ func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenM func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg UnfreezeMsg) sdk.Result { unfreezeAmount := msg.Amount symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "miniToken", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) + logger := log.With("module", "mini-token", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) frozenAmount := account.GetFrozenCoins().AmountOf(symbol) useAllFrozenBalance := frozenAmount == unfreezeAmount From e21404706d5cdd1c6852a9b10bf717e23fff8f70 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 12 May 2020 11:02:02 +0800 Subject: [PATCH 35/96] fix api server --- plugins/api/handlers.go | 2 +- plugins/dex/plugin.go | 2 +- plugins/tokens/client/rest/gettoken.go | 21 +++++++++++++++++---- plugins/tokens/client/rest/gettokens.go | 21 +++++++++++++++++---- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/plugins/api/handlers.go b/plugins/api/handlers.go index 9007d1f98..854d9631f 100644 --- a/plugins/api/handlers.go +++ b/plugins/api/handlers.go @@ -122,7 +122,7 @@ func (s *server) handleTokenReq(cdc *wire.Codec, ctx context.CLIContext) http.Ha } func (s *server) handleTokensReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { - return tksapi.GetTokensReqHandler(cdc, ctx, true) + return tksapi.GetTokensReqHandler(cdc, ctx, false) } func (s *server) handleMiniTokenReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { diff --git a/plugins/dex/plugin.go b/plugins/dex/plugin.go index ffdbd4a35..8e7be9b5e 100644 --- a/plugins/dex/plugin.go +++ b/plugins/dex/plugin.go @@ -18,7 +18,7 @@ import ( ) const DexAbciQueryPrefix = "dex" -const DexMiniAbciQueryPrefix = "dex_mini" +const DexMiniAbciQueryPrefix = "dex-mini" const DelayedDaysForDelist = 3 // InitPlugin initializes the dex plugin. diff --git a/plugins/tokens/client/rest/gettoken.go b/plugins/tokens/client/rest/gettoken.go index 1fe0aac45..3c98e8085 100644 --- a/plugins/tokens/client/rest/gettoken.go +++ b/plugins/tokens/client/rest/gettoken.go @@ -14,7 +14,7 @@ import ( "github.com/binance-chain/node/wire" ) -func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini bool) (*types.Token, error) { +func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini bool) (interface{}, error) { var abciPrefix string if isMini { abciPrefix = "mini-tokens" @@ -25,9 +25,22 @@ func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini if err != nil { return nil, err } - var token types.Token - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &token) - return &token, nil + + if isMini { + var token types.MiniToken + err = cdc.UnmarshalBinaryLengthPrefixed(bz, &token) + if err!=nil{ + fmt.Println(err) + } + return token, nil + }else{ + var token types.Token + err = cdc.UnmarshalBinaryLengthPrefixed(bz, &token) + if err!=nil{ + fmt.Println(err) + } + return token, nil + } } // GetTokenReqHandler creates an http request handler to get info for an individual token diff --git a/plugins/tokens/client/rest/gettokens.go b/plugins/tokens/client/rest/gettokens.go index 2fd26ea15..f211f254d 100644 --- a/plugins/tokens/client/rest/gettokens.go +++ b/plugins/tokens/client/rest/gettokens.go @@ -17,7 +17,7 @@ const maxTokensLimit = 1000 const defaultTokensLimit = 100 const defaultTokensOffset = 0 -func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit int, showZeroSupplyTokens bool, isMini bool) ([]types.Token, error) { +func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit int, showZeroSupplyTokens bool, isMini bool) (interface{}, error) { var abciPrefix string if isMini { abciPrefix = "mini-tokens" @@ -28,9 +28,22 @@ func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit in if err != nil { return nil, err } - tokens := make([]types.Token, 0) - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) - return tokens, nil + if isMini { + tokens := make([]types.MiniToken, 0) + err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) + if err!=nil{ + fmt.Println(err) + } + return tokens, nil + }else{ + tokens := make([]types.Token, 0) + err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) + if err!=nil{ + fmt.Println(err) + } + return tokens, nil + } + } // GetTokensReqHandler creates an http request handler to get the list of tokens in the token mapper From 434a201798d34c2db2becc1e3edfd3f3d2b61207 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 12 May 2020 12:06:41 +0800 Subject: [PATCH 36/96] fix ut --- app/config/config.go | 4 ++-- app/pub/helpers.go | 4 ++-- common/upgrade/upgrade.go | 3 +-- plugins/api/handlers.go | 2 -- plugins/dex/order/keeper_test.go | 4 ++-- plugins/tokens/client/rest/gettoken.go | 8 ++++---- plugins/tokens/client/rest/gettokens.go | 8 ++++---- 7 files changed, 15 insertions(+), 18 deletions(-) diff --git a/app/config/config.go b/app/config/config.go index 2911965ec..52e933e97 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -374,7 +374,7 @@ type UpgradeConfig struct { // Hubble Upgrade BEP12Height int64 `mapstructure:"BEP12Height"` // Archimedes Upgrade - BEP3Height int64 `mapstructure:"BEP3Height"` + BEP3Height int64 `mapstructure:"BEP3Height"` // TODO: add upgrade name FixSignBytesOverflowHeight int64 `mapstructure:"FixSignBytesOverflowHeight"` @@ -383,7 +383,7 @@ type UpgradeConfig struct { FixZeroBalanceHeight int64 `mapstructure:"FixZeroBalanceHeight"` // TODO: add upgrade name - BEP8Height int64 `mapstructure:"BEP8Height"` + BEP8Height int64 `mapstructure:"BEP8Height"` BEP67Height int64 `mapstructure:"BEP67Height"` BEP70Height int64 `mapstructure:"BEP70Height"` } diff --git a/app/pub/helpers.go b/app/pub/helpers.go index a3ee187a3..523d1954f 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -17,12 +17,12 @@ import ( "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/types" orderPkg "github.com/binance-chain/node/plugins/dex/order" + "github.com/binance-chain/node/plugins/dex/utils" miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" abci "github.com/tendermint/tendermint/abci/types" - "github.com/binance-chain/node/plugins/dex/utils" ) func GetTradeAndOrdersRelatedAccounts(kp *orderPkg.DexKeeper, tradesToPublish []*Trade, pairType orderPkg.SymbolPairType) []string { @@ -327,7 +327,7 @@ func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, trad tradeIdx += 1 if utils.IsMiniTokenTradingPair(symbol) { miniTradesToPublish = append(miniTradesToPublish, t) - }else { + } else { tradesToPublish = append(tradesToPublish, t) } } diff --git a/common/upgrade/upgrade.go b/common/upgrade/upgrade.go index 477d42696..d4efa0e8f 100644 --- a/common/upgrade/upgrade.go +++ b/common/upgrade/upgrade.go @@ -18,7 +18,6 @@ const ( // Archimedes Upgrade BEP3 = "BEP3" // https://github.com/binance-chain/BEPs/pull/30 - // TODO: add upgrade name FixSignBytesOverflow = sdk.FixSignBytesOverflow LotSizeOptimization = "LotSizeOptimization" @@ -26,7 +25,7 @@ const ( FixZeroBalance = "FixZeroBalance" //Nightingale upgrade - BEP8 = "BEP8" // https://github.com/binance-chain/BEPs/pull/69 Mini token upgrade + BEP8 = "BEP8" // https://github.com/binance-chain/BEPs/pull/69 Mini token upgrade BEP67 = "BEP67" // https://github.com/binance-chain/BEPs/pull/67 Expiry time upgrade BEP70 = "BEP70" // https://github.com/binance-chain/BEPs/pull/70 BUSD Pair Upgrade ) diff --git a/plugins/api/handlers.go b/plugins/api/handlers.go index 854d9631f..45c8ad6b3 100644 --- a/plugins/api/handlers.go +++ b/plugins/api/handlers.go @@ -103,7 +103,6 @@ func (s *server) handleMiniPairsReq(cdc *wire.Codec, ctx context.CLIContext) htt return dexapi.GetPairsReqHandler(cdc, ctx, dex.DexMiniAbciQueryPrefix) } - func (s *server) handleDexDepthReq(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { return dexapi.DepthReqHandler(cdc, ctx) } @@ -133,7 +132,6 @@ func (s *server) handleMiniTokensReq(cdc *wire.Codec, ctx context.CLIContext) ht return tksapi.GetTokensReqHandler(cdc, ctx, true) } - func (s *server) handleBalancesReq(cdc *wire.Codec, ctx context.CLIContext, tokens tkstore.Mapper) http.HandlerFunc { return tksapi.BalancesReqHandler(cdc, ctx, tokens) } diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index 5947ec39b..71e31d206 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -642,13 +642,13 @@ func TestKeeper_ExpireOrdersBasedOnPrice(t *testing.T) { require.Len(t, sells, 2) require.Len(t, sells[0].Orders, 1) require.Equal(t, int64(1e8), sells[0].TotalLeavesQty()) - require.Len(t, keeper.allOrders["ABC-000_BNB"], 4) + require.Len(t, keeper.GetAllOrdersForPair("ABC-000_BNB"), 4) buys, sells = keeper.engines["XYZ-000_BNB"].Book.GetAllLevels() require.Len(t, buys, 2) require.Len(t, sells, 0) require.Len(t, buys[0].Orders, 1) require.Equal(t, int64(2e6), buys[0].TotalLeavesQty()) - require.Len(t, keeper.allOrders["XYZ-000_BNB"], 2) + require.Len(t, keeper.GetAllOrdersForPair("XYZ-000_BNB"), 2) fees.Pool.Clear() upgrade.Mgr.AddUpgradeHeight(upgrade.BEP67, 0) } diff --git a/plugins/tokens/client/rest/gettoken.go b/plugins/tokens/client/rest/gettoken.go index 70b4b7955..53e5b9b24 100644 --- a/plugins/tokens/client/rest/gettoken.go +++ b/plugins/tokens/client/rest/gettoken.go @@ -18,7 +18,7 @@ func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini var abciPrefix string if isMini { abciPrefix = "mini-tokens" - }else{ + } else { abciPrefix = "tokens" } bz, err := ctx.Query(fmt.Sprintf("%s/info/%s", abciPrefix, symbol), nil) @@ -29,14 +29,14 @@ func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini if isMini { var token types.MiniToken err = cdc.UnmarshalBinaryLengthPrefixed(bz, &token) - if err!=nil{ + if err != nil { fmt.Println(err) } return token, nil - }else{ + } else { var token types.Token err = cdc.UnmarshalBinaryLengthPrefixed(bz, &token) - if err!=nil{ + if err != nil { fmt.Println(err) } return token, nil diff --git a/plugins/tokens/client/rest/gettokens.go b/plugins/tokens/client/rest/gettokens.go index f211f254d..1d33b4a66 100644 --- a/plugins/tokens/client/rest/gettokens.go +++ b/plugins/tokens/client/rest/gettokens.go @@ -21,7 +21,7 @@ func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit in var abciPrefix string if isMini { abciPrefix = "mini-tokens" - }else{ + } else { abciPrefix = "tokens" } bz, err := ctx.Query(fmt.Sprintf("%s/list/%d/%d/%s", abciPrefix, offset, limit, strconv.FormatBool(showZeroSupplyTokens)), nil) @@ -31,14 +31,14 @@ func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit in if isMini { tokens := make([]types.MiniToken, 0) err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) - if err!=nil{ + if err != nil { fmt.Println(err) } return tokens, nil - }else{ + } else { tokens := make([]types.Token, 0) err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) - if err!=nil{ + if err != nil { fmt.Println(err) } return tokens, nil From 7516839ba1b6c6b1b0e98d855d7b49cceae48d1c Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 12 May 2020 17:07:11 +0800 Subject: [PATCH 37/96] remove minitoken plugin --- admin/tx.go | 2 +- app/app.go | 19 +- app/pub/helpers.go | 2 +- cmd/bnbcli/main.go | 2 - common/stores.go | 5 - common/types/mini_token.go | 28 +-- networks/tools/snapshot_viewer/snapshot.go | 3 +- plugins/api/server.go | 3 - plugins/dex/listmini/handler.go | 9 +- plugins/dex/plugin.go | 5 +- plugins/dex/route.go | 5 +- plugins/minitokens/abci.go | 232 +++++++++--------- plugins/minitokens/client/cli/commands.go | 35 --- plugins/minitokens/client/cli/helper.go | 126 +++++----- plugins/minitokens/mini_tokens.go | 5 - plugins/minitokens/plugin.go | 50 ++-- plugins/minitokens/route.go | 18 -- plugins/minitokens/store/mapper.go | 185 -------------- plugins/minitokens/wire.go | 13 - plugins/param/plugin.go | 28 +-- plugins/tokens/burn/handler.go | 9 +- plugins/tokens/client/cli/commands.go | 16 ++ plugins/tokens/client/cli/helper.go | 19 ++ .../client/cli/info_mini.go} | 10 +- .../client/cli/issue_mini.go} | 14 +- .../client/cli/seturi_mini.go} | 4 +- plugins/tokens/freeze/handler.go | 15 +- plugins/tokens/issue/handler.go | 11 +- plugins/tokens/issue/handler_test.go | 2 +- .../issue => tokens/issue_mini}/handler.go | 10 +- .../issue_mini}/handler_test.go | 2 +- .../issue => tokens/issue_mini}/msg.go | 2 +- plugins/tokens/plugin.go | 5 +- plugins/tokens/route.go | 13 +- .../seturi => tokens/seturi_mini}/handler.go | 12 +- .../seturi => tokens/seturi_mini}/msg.go | 2 +- plugins/tokens/store/mapper.go | 38 ++- plugins/tokens/store/mapper_mini.go | 125 ++++++++++ plugins/tokens/wire.go | 4 + 39 files changed, 494 insertions(+), 594 deletions(-) delete mode 100644 plugins/minitokens/client/cli/commands.go delete mode 100644 plugins/minitokens/mini_tokens.go delete mode 100644 plugins/minitokens/route.go delete mode 100644 plugins/minitokens/store/mapper.go delete mode 100644 plugins/minitokens/wire.go rename plugins/{minitokens/client/cli/info.go => tokens/client/cli/info_mini.go} (79%) rename plugins/{minitokens/client/cli/issue.go => tokens/client/cli/issue_mini.go} (84%) rename plugins/{minitokens/client/cli/seturi.go => tokens/client/cli/seturi_mini.go} (90%) rename plugins/{minitokens/issue => tokens/issue_mini}/handler.go (92%) rename plugins/{minitokens/issue => tokens/issue_mini}/handler_test.go (99%) rename plugins/{minitokens/issue => tokens/issue_mini}/msg.go (99%) rename plugins/{minitokens/seturi => tokens/seturi_mini}/handler.go (81%) rename plugins/{minitokens/seturi => tokens/seturi_mini}/msg.go (98%) create mode 100644 plugins/tokens/store/mapper_mini.go diff --git a/admin/tx.go b/admin/tx.go index 8458b2f0d..2e1527f92 100644 --- a/admin/tx.go +++ b/admin/tx.go @@ -8,10 +8,10 @@ import ( "github.com/binance-chain/node/common/runtime" "github.com/binance-chain/node/plugins/dex/order" - miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" + miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/timelock" ) diff --git a/app/app.go b/app/app.go index 82a25d6f7..66ac481fe 100644 --- a/app/app.go +++ b/app/app.go @@ -41,13 +41,11 @@ import ( "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/ico" - "github.com/binance-chain/node/plugins/minitokens" - miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" - "github.com/binance-chain/node/plugins/minitokens/seturi" - miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" "github.com/binance-chain/node/plugins/param" "github.com/binance-chain/node/plugins/param/paramhub" "github.com/binance-chain/node/plugins/tokens" + miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" + "github.com/binance-chain/node/plugins/tokens/seturi_mini" tkstore "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" @@ -86,7 +84,6 @@ type BinanceChain struct { DexKeeper *dex.DexKeeper AccountKeeper auth.AccountKeeper TokenMapper tkstore.Mapper - MiniTokenMapper miniTkstore.MiniTokenMapper ValAddrCache *ValAddrCache stakeKeeper stake.Keeper govKeeper gov.Keeper @@ -137,7 +134,6 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp // mappers app.AccountKeeper = auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) app.TokenMapper = tkstore.NewMapper(cdc, common.TokenStoreKey) - app.MiniTokenMapper = miniTkstore.NewMiniTokenMapper(cdc, common.MiniTokenStoreKey) app.CoinKeeper = bank.NewBaseKeeper(app.AccountKeeper) app.ParamHub = paramhub.NewKeeper(cdc, common.ParamsStoreKey, common.TParamsStoreKey) tradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.PairStoreKey) @@ -225,7 +221,6 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp common.GovStoreKey, common.TimeLockStoreKey, common.AtomicSwapStoreKey, - common.MiniTokenStoreKey, ) app.SetAnteHandler(tx.NewAnteHandler(app.AccountKeeper)) app.SetPreChecker(tx.NewTxPreChecker()) @@ -283,8 +278,6 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { upgrade.Mgr.RegisterStoreKeys(upgrade.BEP9, common.TimeLockStoreKey.Name()) upgrade.Mgr.RegisterStoreKeys(upgrade.BEP3, common.AtomicSwapStoreKey.Name()) - upgrade.Mgr.RegisterStoreKeys(upgrade.BEP8, common.MiniTokenStoreKey.Name()) - // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP9, timelock.TimeLockMsg{}.Type(), @@ -303,7 +296,7 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, miniIssue.IssueMsg{}.Type(), - seturi.SetURIMsg{}.Type(), + seturi_mini.SetURIMsg{}.Type(), listmini.ListMiniMsg{}.Type(), ) } @@ -353,9 +346,8 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { } func (app *BinanceChain) initPlugins() { - tokens.InitPlugin(app, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) - minitokens.InitPlugin(app, app.MiniTokenMapper, app.AccountKeeper, app.CoinKeeper) - dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.MiniTokenMapper, app.AccountKeeper, app.govKeeper) + tokens.InitPlugin(app, app.TokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) + dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.AccountKeeper, app.govKeeper) param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) } @@ -779,7 +771,6 @@ func MakeCodec() *wire.Codec { stake.RegisterCodec(cdc) gov.RegisterCodec(cdc) param.RegisterWire(cdc) - minitokens.RegisterWire(cdc) return cdc } diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 523d1954f..fa9657bbf 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -18,10 +18,10 @@ import ( "github.com/binance-chain/node/common/types" orderPkg "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/utils" - miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" + miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" abci "github.com/tendermint/tendermint/abci/types" ) diff --git a/cmd/bnbcli/main.go b/cmd/bnbcli/main.go index bd83e5ff3..7b4ba81b3 100644 --- a/cmd/bnbcli/main.go +++ b/cmd/bnbcli/main.go @@ -21,7 +21,6 @@ import ( accountcmd "github.com/binance-chain/node/plugins/account/client/cli" apiserv "github.com/binance-chain/node/plugins/api" dexcmd "github.com/binance-chain/node/plugins/dex/client/cli" - miniTokencmd "github.com/binance-chain/node/plugins/minitokens/client/cli" paramcmd "github.com/binance-chain/node/plugins/param/client/cli" tokencmd "github.com/binance-chain/node/plugins/tokens/client/cli" "github.com/binance-chain/node/version" @@ -88,7 +87,6 @@ func main() { accountcmd.AddCommands(rootCmd, cdc) dexcmd.AddCommands(rootCmd, cdc) paramcmd.AddCommands(rootCmd, cdc) - miniTokencmd.AddCommands(rootCmd, cdc) // stake cmds rootCmd.AddCommand( diff --git a/common/stores.go b/common/stores.go index 693b6023c..b39b69381 100644 --- a/common/stores.go +++ b/common/stores.go @@ -7,7 +7,6 @@ const ( AccountStoreName = "acc" ValAddrStoreName = "val" TokenStoreName = "tokens" - MiniTokenStoreName = "minitokens" DexStoreName = "dex" PairStoreName = "pairs" StakeStoreName = "stake" @@ -37,8 +36,6 @@ var ( TStakeStoreKey = sdk.NewTransientStoreKey(StakeTransientStoreName) TParamsStoreKey = sdk.NewTransientStoreKey(ParamsTransientStoreName) - MiniTokenStoreKey = sdk.NewKVStoreKey(MiniTokenStoreName) - StoreKeyNameMap = map[string]sdk.StoreKey{ MainStoreName: MainStoreKey, AccountStoreName: AccountStoreKey, @@ -53,7 +50,6 @@ var ( AtomicSwapStoreName: AtomicSwapStoreKey, StakeTransientStoreName: TStakeStoreKey, ParamsTransientStoreName: TParamsStoreKey, - MiniTokenStoreName: MiniTokenStoreKey, } NonTransientStoreKeyNames = []string{ @@ -68,7 +64,6 @@ var ( GovStoreName, TimeLockStoreName, AtomicSwapStoreName, - MiniTokenStoreName, } ) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 9cf529365..89fea3cd1 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -58,14 +58,9 @@ var SupplyRange = struct { }{TinyRangeType, MiniRangeType} type MiniToken struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - OrigSymbol string `json:"original_symbol"` - TokenType SupplyRangeType `json:"token_type"` - TotalSupply utils.Fixed8 `json:"total_supply"` - Owner sdk.AccAddress `json:"owner"` - Mintable bool `json:"mintable"` - TokenURI string `json:"token_uri"` //TODO set max length + Token + TokenType SupplyRangeType `json:"token_type"` + TokenURI string `json:"token_uri"` //TODO set max length } func NewMiniToken(name, symbol string, supplyRangeType int8, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken, error) { @@ -78,14 +73,15 @@ func NewMiniToken(name, symbol string, supplyRangeType int8, totalSupply int64, return nil, err } return &MiniToken{ - Name: name, - Symbol: symbol, - OrigSymbol: parts[0], - TokenType: SupplyRangeType(supplyRangeType), - TotalSupply: utils.Fixed8(totalSupply), - Owner: owner, - Mintable: mintable, - TokenURI: tokenURI, + Token{Name: name, + Symbol: symbol, + OrigSymbol: parts[0], + TotalSupply: utils.Fixed8(totalSupply), + Owner: owner, + Mintable: mintable, + }, + SupplyRangeType(supplyRangeType), + tokenURI, }, nil } diff --git a/networks/tools/snapshot_viewer/snapshot.go b/networks/tools/snapshot_viewer/snapshot.go index fbda70251..ef56bca9e 100644 --- a/networks/tools/snapshot_viewer/snapshot.go +++ b/networks/tools/snapshot_viewer/snapshot.go @@ -47,8 +47,7 @@ func prepareCms(root string, appDB *db.GoLevelDB) sdk.CommitMultiStore { keys := []store.StoreKey{ common.MainStoreKey, common.TokenStoreKey, common.DexStoreKey, common.PairStoreKey, common.GovStoreKey, common.StakeStoreKey, - common.ParamsStoreKey, common.ValAddrStoreKey, common.AccountStoreKey, - common.MiniTokenStoreKey} + common.ParamsStoreKey, common.ValAddrStoreKey, common.AccountStoreKey,} cms := store.NewCommitMultiStore(appDB) for _, key := range keys { diff --git a/plugins/api/server.go b/plugins/api/server.go index 77ab62a90..38f9ddf30 100644 --- a/plugins/api/server.go +++ b/plugins/api/server.go @@ -8,7 +8,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/binance-chain/node/common" - miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" tkstore "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) @@ -32,7 +31,6 @@ type server struct { accStoreName string - miniTokens miniTkstore.MiniTokenMapper } // NewServer provides a new server structure. @@ -50,6 +48,5 @@ func newServer(ctx context.CLIContext, cdc *wire.Codec) *server { keyBase: kb, tokens: tkstore.NewMapper(cdc, common.TokenStoreKey), accStoreName: common.AccountStoreName, - miniTokens: miniTkstore.NewMiniTokenMapper(cdc, common.MiniTokenStoreKey), } } diff --git a/plugins/dex/listmini/handler.go b/plugins/dex/listmini/handler.go index 6540eaa81..bdb0b0026 100644 --- a/plugins/dex/listmini/handler.go +++ b/plugins/dex/listmini/handler.go @@ -9,17 +9,16 @@ import ( "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/plugins/dex/utils" - "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens" sdk "github.com/cosmos/cosmos-sdk/types" ) // NewHandler initialises dex message handlers -func NewHandler(dexKeeper *order.DexKeeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper) sdk.Handler { +func NewHandler(dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case ListMiniMsg: - return handleList(ctx, dexKeeper, miniTokenMapper, tokenMapper, msg) + return handleList(ctx, dexKeeper, tokenMapper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -27,7 +26,7 @@ func NewHandler(dexKeeper *order.DexKeeper, miniTokenMapper minitokens.MiniToken } } -func handleList(ctx sdk.Context, dexKeeper *order.DexKeeper, miniTokenMapper minitokens.MiniTokenMapper, tokenMapper tokens.Mapper, +func handleList(ctx sdk.Context, dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper, msg ListMiniMsg) sdk.Result { if !sdk.IsUpgrade(upgrade.BEP8) { return sdk.ErrInternal(fmt.Sprint("list mini-token is not supported at current height")).Result() @@ -37,7 +36,7 @@ func handleList(ctx sdk.Context, dexKeeper *order.DexKeeper, miniTokenMapper min return sdk.ErrInvalidCoins(err.Error()).Result() } - baseToken, err := miniTokenMapper.GetToken(ctx, msg.BaseAssetSymbol) + baseToken, err := tokenMapper.GetMiniToken(ctx, msg.BaseAssetSymbol) if err != nil { return sdk.ErrInvalidCoins(err.Error()).Result() } diff --git a/plugins/dex/plugin.go b/plugins/dex/plugin.go index 8e7be9b5e..d03e0f2c4 100644 --- a/plugins/dex/plugin.go +++ b/plugins/dex/plugin.go @@ -13,7 +13,6 @@ import ( bnclog "github.com/binance-chain/node/common/log" app "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/dex/utils" - miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" tkstore "github.com/binance-chain/node/plugins/tokens/store" ) @@ -23,12 +22,12 @@ const DelayedDaysForDelist = 3 // InitPlugin initializes the dex plugin. func InitPlugin( - appp app.ChainApp, dexKeeper *DexKeeper, tokenMapper tkstore.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, + appp app.ChainApp, dexKeeper *DexKeeper, tokenMapper tkstore.Mapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, ) { cdc := appp.GetCodec() // add msg handlers - for route, handler := range Routes(cdc, dexKeeper, tokenMapper, miniTokenMapper, accMapper, govKeeper) { + for route, handler := range Routes(cdc, dexKeeper, tokenMapper, accMapper, govKeeper) { appp.GetRouter().AddRoute(route, handler) } diff --git a/plugins/dex/route.go b/plugins/dex/route.go index d18c664e5..c28ef55a6 100644 --- a/plugins/dex/route.go +++ b/plugins/dex/route.go @@ -8,19 +8,18 @@ import ( "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" - miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/wire" ) // Routes exports dex message routes -func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, miniTokenMapper miniTkstore.MiniTokenMapper, +func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, accKeeper auth.AccountKeeper, govKeeper gov.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) orderHandler := order.NewHandler(cdc, dexKeeper) routes[order.RouteNewOrder] = orderHandler routes[order.RouteCancelOrder] = orderHandler routes[list.Route] = list.NewHandler(dexKeeper, tokenMapper, govKeeper) - routes[listmini.Route] = listmini.NewHandler(dexKeeper, miniTokenMapper, tokenMapper) + routes[listmini.Route] = listmini.NewHandler(dexKeeper, tokenMapper) return routes } diff --git a/plugins/minitokens/abci.go b/plugins/minitokens/abci.go index 3c8e25d4c..e8816a26f 100644 --- a/plugins/minitokens/abci.go +++ b/plugins/minitokens/abci.go @@ -1,118 +1,118 @@ package minitokens -import ( - "fmt" - "strconv" - "strings" - - abci "github.com/tendermint/tendermint/abci/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - - app "github.com/binance-chain/node/common/types" -) - -func createAbciQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { - return func(app app.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { - // expects at least two query path segments. - if path[0] != abciQueryPrefix || len(path) < 2 { - return nil - } - switch path[1] { - case "info": // args: ["minitokens", "info", ] - if len(path) < 3 { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeUnknownRequest), - Log: fmt.Sprintf( - "%s %s query requires a symbol path arg", - abciQueryPrefix, path[1]), - } - } - ctx := app.GetContextForCheckState() - symbol := path[2] - if len(symbol) == 0 { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: "empty symbol not permitted", - } - } - token, err := mapper.GetToken(ctx, symbol) - if err != nil { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: err.Error(), - } - } - bz, err := app.GetCodec().MarshalBinaryLengthPrefixed(token) - if err != nil { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: err.Error(), - } - } - return &abci.ResponseQuery{ - Code: uint32(sdk.ABCICodeOK), - Value: bz, - } - case "list": // args: ["minitokens", "list", , , ] - if len(path) < 4 { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeUnknownRequest), - Log: fmt.Sprintf( - "%s %s query requires offset and limit path segments", - abciQueryPrefix, path[1]), - } - } - showZeroSupplyTokens := false - if len(path) == 5 && strings.ToLower(path[4]) == "true" { - showZeroSupplyTokens = true - } - ctx := app.GetContextForCheckState() - tokens := mapper.GetTokenList(ctx, showZeroSupplyTokens) - offset, err := strconv.Atoi(path[2]) - if err != nil || offset < 0 || offset >= len(tokens) { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: "unable to parse offset", - } - } - limit, err := strconv.Atoi(path[3]) - if err != nil || limit <= 0 { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: "unable to parse limit", - } - } - end := offset + limit - if end > len(tokens) { - end = len(tokens) - } - if end <= 0 || end <= offset { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: "malformed range", - } - } - bz, err := app.GetCodec().MarshalBinaryLengthPrefixed( - tokens[offset:end], - ) - if err != nil { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: err.Error(), - } - } - return &abci.ResponseQuery{ - Code: uint32(sdk.ABCICodeOK), - Value: bz, - } - default: - return &abci.ResponseQuery{ - Code: uint32(sdk.ABCICodeOK), - Info: fmt.Sprintf( - "Unknown `%s` query path: %v", - abciQueryPrefix, path), - } - } - } -} +//import ( +// "fmt" +// "strconv" +// "strings" +// +// abci "github.com/tendermint/tendermint/abci/types" +// +// sdk "github.com/cosmos/cosmos-sdk/types" +// +// app "github.com/binance-chain/node/common/types" +//) +// +//func createAbciQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { +// return func(app app.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { +// // expects at least two query path segments. +// if path[0] != abciQueryPrefix || len(path) < 2 { +// return nil +// } +// switch path[1] { +// case "info": // args: ["minitokens", "info", ] +// if len(path) < 3 { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeUnknownRequest), +// Log: fmt.Sprintf( +// "%s %s query requires a symbol path arg", +// abciQueryPrefix, path[1]), +// } +// } +// ctx := app.GetContextForCheckState() +// symbol := path[2] +// if len(symbol) == 0 { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeInternal), +// Log: "empty symbol not permitted", +// } +// } +// token, err := mapper.GetToken(ctx, symbol) +// if err != nil { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeInternal), +// Log: err.Error(), +// } +// } +// bz, err := app.GetCodec().MarshalBinaryLengthPrefixed(token) +// if err != nil { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeInternal), +// Log: err.Error(), +// } +// } +// return &abci.ResponseQuery{ +// Code: uint32(sdk.ABCICodeOK), +// Value: bz, +// } +// case "list": // args: ["minitokens", "list", , , ] +// if len(path) < 4 { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeUnknownRequest), +// Log: fmt.Sprintf( +// "%s %s query requires offset and limit path segments", +// abciQueryPrefix, path[1]), +// } +// } +// showZeroSupplyTokens := false +// if len(path) == 5 && strings.ToLower(path[4]) == "true" { +// showZeroSupplyTokens = true +// } +// ctx := app.GetContextForCheckState() +// tokens := mapper.GetTokenList(ctx, showZeroSupplyTokens) +// offset, err := strconv.Atoi(path[2]) +// if err != nil || offset < 0 || offset >= len(tokens) { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeInternal), +// Log: "unable to parse offset", +// } +// } +// limit, err := strconv.Atoi(path[3]) +// if err != nil || limit <= 0 { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeInternal), +// Log: "unable to parse limit", +// } +// } +// end := offset + limit +// if end > len(tokens) { +// end = len(tokens) +// } +// if end <= 0 || end <= offset { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeInternal), +// Log: "malformed range", +// } +// } +// bz, err := app.GetCodec().MarshalBinaryLengthPrefixed( +// tokens[offset:end], +// ) +// if err != nil { +// return &abci.ResponseQuery{ +// Code: uint32(sdk.CodeInternal), +// Log: err.Error(), +// } +// } +// return &abci.ResponseQuery{ +// Code: uint32(sdk.ABCICodeOK), +// Value: bz, +// } +// default: +// return &abci.ResponseQuery{ +// Code: uint32(sdk.ABCICodeOK), +// Info: fmt.Sprintf( +// "Unknown `%s` query path: %v", +// abciQueryPrefix, path), +// } +// } +// } +//} diff --git a/plugins/minitokens/client/cli/commands.go b/plugins/minitokens/client/cli/commands.go deleted file mode 100644 index 274682996..000000000 --- a/plugins/minitokens/client/cli/commands.go +++ /dev/null @@ -1,35 +0,0 @@ -package commands - -import ( - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - - "github.com/binance-chain/node/wire" -) - -const ( - flagSymbol = "symbol" - flagAmount = "amount" - flagURI = "uri" -) - -func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { - - miniTokenCmd := &cobra.Command{ - Use: "mini-token", - Short: "issue or view mini tokens", - Long: ``, - } - - cmdr := Commander{Cdc: cdc} - miniTokenCmd.AddCommand( - client.PostCommands( - getTokenInfoCmd(cmdr), - issueMiniTokenCmd(cmdr), - setTokenURICmd(cmdr))...) - - miniTokenCmd.AddCommand(client.LineBreak) - - cmd.AddCommand(miniTokenCmd) -} diff --git a/plugins/minitokens/client/cli/helper.go b/plugins/minitokens/client/cli/helper.go index 735a0d7a7..b58ba2f5d 100644 --- a/plugins/minitokens/client/cli/helper.go +++ b/plugins/minitokens/client/cli/helper.go @@ -1,69 +1,59 @@ package commands - -import ( - "errors" - "strconv" - "strings" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/common/client" - "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/wire" -) - -type Commander struct { - Cdc *wire.Codec -} - -type msgBuilder func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg - -func (c Commander) checkAndSendTx(cmd *cobra.Command, args []string, builder msgBuilder) error { - cliCtx, txBuilder := client.PrepareCtx(c.Cdc) - - from, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - - symbol := viper.GetString(flagSymbol) - err = types.ValidateMapperMiniTokenSymbol(symbol) - if err != nil { - return err - } - - symbol = strings.ToUpper(symbol) - - amountStr := viper.GetString(flagAmount) - amount, err := parseAmount(amountStr) - if err != nil { - return err - } - - // build message - msg := builder(from, symbol, amount) - return client.SendOrPrintTx(cliCtx, txBuilder, msg) -} - -func parseAmount(amountStr string) (int64, error) { - amount, err := strconv.ParseInt(amountStr, 10, 64) - if err != nil { - return 0, err - } - - if amount <= 0 { - return amount, errors.New("the amount should be greater than 0") - } - - return amount, nil -} - -func validateTokenURI(uri string) error { - if len(uri) > 2048 { - return errors.New("uri cannot be longer than 2048 characters") - } - return nil -} +// +//import ( +// "errors" +// "strconv" +// "strings" +// +// "github.com/spf13/cobra" +// "github.com/spf13/viper" +// +// sdk "github.com/cosmos/cosmos-sdk/types" +// +// "github.com/binance-chain/node/common/client" +// "github.com/binance-chain/node/common/types" +// "github.com/binance-chain/node/wire" +//) +// +//type msgBuilder func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg +// +//func (c Commander) checkAndSendTx(cmd *cobra.Command, args []string, builder msgBuilder) error { +// cliCtx, txBuilder := client.PrepareCtx(c.Cdc) +// +// from, err := cliCtx.GetFromAddress() +// if err != nil { +// return err +// } +// +// symbol := viper.GetString(flagSymbol) +// err = types.ValidateMapperMiniTokenSymbol(symbol) +// if err != nil { +// return err +// } +// +// symbol = strings.ToUpper(symbol) +// +// amountStr := viper.GetString(flagAmount) +// amount, err := parseAmount(amountStr) +// if err != nil { +// return err +// } +// +// // build message +// msg := builder(from, symbol, amount) +// return client.SendOrPrintTx(cliCtx, txBuilder, msg) +//} +// +//func parseAmount(amountStr string) (int64, error) { +// amount, err := strconv.ParseInt(amountStr, 10, 64) +// if err != nil { +// return 0, err +// } +// +// if amount <= 0 { +// return amount, errors.New("the amount should be greater than 0") +// } +// +// return amount, nil +//} +// diff --git a/plugins/minitokens/mini_tokens.go b/plugins/minitokens/mini_tokens.go deleted file mode 100644 index a1cf6679f..000000000 --- a/plugins/minitokens/mini_tokens.go +++ /dev/null @@ -1,5 +0,0 @@ -package minitokens - -import "github.com/binance-chain/node/plugins/minitokens/store" - -type MiniTokenMapper = store.MiniTokenMapper diff --git a/plugins/minitokens/plugin.go b/plugins/minitokens/plugin.go index 4214e8bb9..19a41b8dc 100644 --- a/plugins/minitokens/plugin.go +++ b/plugins/minitokens/plugin.go @@ -1,27 +1,27 @@ package minitokens -import ( - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - - app "github.com/binance-chain/node/common/types" -) - -const abciQueryPrefix = "mini-tokens" - -// InitPlugin initializes the plugin. -func InitPlugin( - appp app.ChainApp, mapper MiniTokenMapper, accKeeper auth.AccountKeeper, coinKeeper bank.Keeper) { - // add msg handlers - for route, handler := range Routes(mapper, accKeeper, coinKeeper) { - appp.GetRouter().AddRoute(route, handler) - } - - // add abci handlers - handler := createQueryHandler(mapper) - appp.RegisterQueryHandler(abciQueryPrefix, handler) -} - -func createQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { - return createAbciQueryHandler(mapper) -} +//import ( +// "github.com/cosmos/cosmos-sdk/x/auth" +// "github.com/cosmos/cosmos-sdk/x/bank" +// +// app "github.com/binance-chain/node/common/types" +//) +// +//const abciQueryPrefix = "mini-tokens" +// +//// InitPlugin initializes the plugin. +//func InitPlugin( +// appp app.ChainApp, mapper MiniTokenMapper, accKeeper auth.AccountKeeper, coinKeeper bank.Keeper) { +// // add msg handlers +// for route, handler := range Routes(mapper, accKeeper, coinKeeper) { +// appp.GetRouter().AddRoute(route, handler) +// } +// +// // add abci handlers +// handler := createQueryHandler(mapper) +// appp.RegisterQueryHandler(abciQueryPrefix, handler) +//} +// +//func createQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { +// return createAbciQueryHandler(mapper) +//} diff --git a/plugins/minitokens/route.go b/plugins/minitokens/route.go deleted file mode 100644 index 972d50886..000000000 --- a/plugins/minitokens/route.go +++ /dev/null @@ -1,18 +0,0 @@ -package minitokens - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - - "github.com/binance-chain/node/plugins/minitokens/issue" - "github.com/binance-chain/node/plugins/minitokens/seturi" - "github.com/binance-chain/node/plugins/minitokens/store" -) - -func Routes(tokenMapper store.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) map[string]sdk.Handler { - routes := make(map[string]sdk.Handler) - routes[issue.Route] = issue.NewHandler(tokenMapper, keeper) - routes[seturi.SetURIRoute] = seturi.NewHandler(tokenMapper) - return routes -} diff --git a/plugins/minitokens/store/mapper.go b/plugins/minitokens/store/mapper.go deleted file mode 100644 index 5a82c2b7b..000000000 --- a/plugins/minitokens/store/mapper.go +++ /dev/null @@ -1,185 +0,0 @@ -package store - -import ( - "errors" - "fmt" - "strings" - - "github.com/cosmos/cosmos-sdk/client/context" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/common" - "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/utils" - "github.com/binance-chain/node/wire" -) - -type MiniTokens []types.MiniToken - -func (t MiniTokens) GetSymbols() *[]string { - var symbols []string - for _, token := range t { - symbols = append(symbols, token.Symbol) - } - return &symbols -} - -type MiniTokenMapper interface { - NewToken(ctx sdk.Context, token types.MiniToken) error - Exists(ctx sdk.Context, symbol string) bool - ExistsCC(ctx context.CLIContext, symbol string) bool - GetTokenList(ctx sdk.Context, showZeroSupplyMiniTokens bool) MiniTokens - GetToken(ctx sdk.Context, symbol string) (types.MiniToken, error) - // we do not provide the updateToken method - UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) error - UpdateTokenURI(ctx sdk.Context, symbol string, uri string) error -} - -var _ MiniTokenMapper = mapper{} - -type mapper struct { - key sdk.StoreKey - cdc *wire.Codec -} - -func NewMiniTokenMapper(cdc *wire.Codec, key sdk.StoreKey) MiniTokenMapper { - return mapper{ - key: key, - cdc: cdc, - } -} - -func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.MiniToken, error) { - store := ctx.KVStore(m.key) - key := []byte(strings.ToUpper(symbol)) - - bz := store.Get(key) - if bz != nil { - return m.decodeToken(bz), nil - } - - return types.MiniToken{}, fmt.Errorf("token(%v) not found", symbol) -} - -func (m mapper) GetTokenCC(ctx context.CLIContext, symbol string) (types.MiniToken, error) { - key := []byte(strings.ToUpper(symbol)) - bz, err := ctx.QueryStore(key, common.MiniTokenStoreName) - if err != nil { - return types.MiniToken{}, err - } - if bz != nil { - return m.decodeToken(bz), nil - } - return types.MiniToken{}, fmt.Errorf("token(%v) not found", symbol) -} - -func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyMiniTokens bool) MiniTokens { - var res MiniTokens - store := ctx.KVStore(m.key) - iter := store.Iterator(nil, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - token := m.decodeToken(iter.Value()) - if !showZeroSupplyMiniTokens && token.TotalSupply.ToInt64() == 0 { - continue - } - res = append(res, token) - } - return res -} - -func (m mapper) Exists(ctx sdk.Context, symbol string) bool { - store := ctx.KVStore(m.key) - key := []byte(strings.ToUpper(symbol)) - return store.Has(key) -} - -func (m mapper) ExistsCC(ctx context.CLIContext, symbol string) bool { - key := []byte(strings.ToUpper(symbol)) - bz, err := ctx.QueryStore(key, common.MiniTokenStoreName) - if err != nil { - return false - } - if bz != nil { - return true - } - return false -} - -func (m mapper) NewToken(ctx sdk.Context, token types.MiniToken) error { - symbol := token.Symbol - if err := types.ValidateMiniToken(token); err != nil { - return err - } - key := []byte(strings.ToUpper(symbol)) - store := ctx.KVStore(m.key) - value := m.encodeToken(token) - store.Set(key, value) - return nil -} - -func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) error { - if len(symbol) == 0 { - return errors.New("symbol cannot be empty") - } - - key := []byte(strings.ToUpper(symbol)) - store := ctx.KVStore(m.key) - bz := store.Get(key) - if bz == nil { - return errors.New("token does not exist") - } - - toBeUpdated := m.decodeToken(bz) - - if toBeUpdated.TotalSupply.ToInt64() != supply { - toBeUpdated.TotalSupply = utils.Fixed8(supply) - store.Set(key, m.encodeToken(toBeUpdated)) - } - return nil -} - -func (m mapper) encodeToken(token types.MiniToken) []byte { - bz, err := m.cdc.MarshalBinaryBare(token) - if err != nil { - panic(err) - } - return bz -} - -func (m mapper) decodeToken(bz []byte) (token types.MiniToken) { - err := m.cdc.UnmarshalBinaryBare(bz, &token) - if err != nil { - panic(err) - } - return -} - -func (m mapper) UpdateTokenURI(ctx sdk.Context, symbol string, uri string) error { - if len(symbol) == 0 { - return errors.New("symbol cannot be empty") - } - - if len(uri) == 0 { - return errors.New("uri cannot be empty") - } - - if len(uri) > 2048 { - return errors.New("uri length cannot be larger than 2048") - } - - key := []byte(strings.ToUpper(symbol)) - store := ctx.KVStore(m.key) - bz := store.Get(key) - if bz == nil { - return errors.New("token does not exist") - } - - toBeUpdated := m.decodeToken(bz) - - if toBeUpdated.TokenURI != uri { - toBeUpdated.TokenURI = uri - store.Set(key, m.encodeToken(toBeUpdated)) - } - return nil -} diff --git a/plugins/minitokens/wire.go b/plugins/minitokens/wire.go deleted file mode 100644 index aad97eb68..000000000 --- a/plugins/minitokens/wire.go +++ /dev/null @@ -1,13 +0,0 @@ -package minitokens - -import ( - "github.com/binance-chain/node/plugins/minitokens/issue" - "github.com/binance-chain/node/plugins/minitokens/seturi" - "github.com/binance-chain/node/wire" -) - -// Register concrete types on wire codec -func RegisterWire(cdc *wire.Codec) { - cdc.RegisterConcrete(issue.IssueMsg{}, "minitokens/IssueMsg", nil) - cdc.RegisterConcrete(seturi.SetURIMsg{}, "minitokens/SetURIMsg", nil) -} diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 2edd2a5a5..12e1b7b9c 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -14,14 +14,14 @@ import ( "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/plugins/dex/order" - miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" - miniURI "github.com/binance-chain/node/plugins/minitokens/seturi" "github.com/binance-chain/node/plugins/param/paramhub" param "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" + miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" + miniURI "github.com/binance-chain/node/plugins/tokens/seturi_mini" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" ) @@ -96,17 +96,17 @@ func init() { burn.BurnRoute: fees.FixedFeeCalculatorGen, account.SetAccountFlagsMsgType: fees.FixedFeeCalculatorGen, freeze.FreezeRoute: fees.FixedFeeCalculatorGen, - timelock.TimeLockMsg{}.Type(): fees.FixedFeeCalculatorGen, - timelock.TimeUnlockMsg{}.Type(): fees.FixedFeeCalculatorGen, - timelock.TimeRelockMsg{}.Type(): fees.FixedFeeCalculatorGen, - bank.MsgSend{}.Type(): tokens.TransferFeeCalculatorGen, - swap.HTLT: fees.FixedFeeCalculatorGen, - swap.DepositHTLT: fees.FixedFeeCalculatorGen, - swap.ClaimHTLT: fees.FixedFeeCalculatorGen, - swap.RefundHTLT: fees.FixedFeeCalculatorGen, - miniIssue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, - miniIssue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, - miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, - listmini.Route: fees.FixedFeeCalculatorGen, + timelock.TimeLockMsg{}.Type(): fees.FixedFeeCalculatorGen, + timelock.TimeUnlockMsg{}.Type(): fees.FixedFeeCalculatorGen, + timelock.TimeRelockMsg{}.Type(): fees.FixedFeeCalculatorGen, + bank.MsgSend{}.Type(): tokens.TransferFeeCalculatorGen, + swap.HTLT: fees.FixedFeeCalculatorGen, + swap.DepositHTLT: fees.FixedFeeCalculatorGen, + swap.ClaimHTLT: fees.FixedFeeCalculatorGen, + swap.RefundHTLT: fees.FixedFeeCalculatorGen, + miniIssue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, + miniIssue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, + miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, + listmini.Route: fees.FixedFeeCalculatorGen, } } diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 3063ed21a..cec23c9e4 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -10,16 +10,15 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/store" ) -func NewHandler(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { +func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { if msg, ok := msg.(BurnMsg); ok { symbol := strings.ToUpper(msg.Symbol) if common.IsMiniTokenSymbol(symbol) { - return handleBurnMiniToken(ctx, miniTokenMapper, keeper, msg) + return handleBurnMiniToken(ctx, tokenMapper, keeper, msg) } else { return handleBurnToken(ctx, tokenMapper, keeper, msg) } @@ -71,11 +70,11 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep return sdk.Result{} } -func handleBurnMiniToken(ctx sdk.Context, tokenMapper miniToken.MiniTokenMapper, keeper bank.Keeper, msg BurnMsg) sdk.Result { +func handleBurnMiniToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keeper, msg BurnMsg) sdk.Result { logger := log.With("module", "mini-token", "symbol", msg.Symbol, "amount", msg.Amount) burnAmount := msg.Amount symbol := strings.ToUpper(msg.Symbol) - token, err := tokenMapper.GetToken(ctx, symbol) + token, err := tokenMapper.GetMiniToken(ctx, symbol) errLogMsg := "burn token failed" if err != nil { logger.Info("burn token failed", "reason", "invalid token symbol") diff --git a/plugins/tokens/client/cli/commands.go b/plugins/tokens/client/cli/commands.go index f0c6cc093..5212f4689 100644 --- a/plugins/tokens/client/cli/commands.go +++ b/plugins/tokens/client/cli/commands.go @@ -11,6 +11,7 @@ import ( const ( flagSymbol = "symbol" flagAmount = "amount" + flagURI = "uri" ) func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { @@ -54,4 +55,19 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { tokenCmd.AddCommand(client.LineBreak) cmd.AddCommand(tokenCmd) + + miniTokenCmd := &cobra.Command{ + Use: "mini-token", + Short: "issue or update uri or view mini tokens", + Long: ``, + } + + miniTokenCmd.AddCommand( + client.PostCommands( + getMiniTokenInfoCmd(cmdr), + issueMiniTokenCmd(cmdr), + setTokenURICmd(cmdr))...) + + miniTokenCmd.AddCommand(client.LineBreak) + cmd.AddCommand(miniTokenCmd) } diff --git a/plugins/tokens/client/cli/helper.go b/plugins/tokens/client/cli/helper.go index dc33e121e..9d44f93b0 100644 --- a/plugins/tokens/client/cli/helper.go +++ b/plugins/tokens/client/cli/helper.go @@ -1,6 +1,7 @@ package commands import ( + "bytes" "errors" "strconv" "strings" @@ -15,6 +16,8 @@ import ( "github.com/binance-chain/node/wire" ) +const miniTokenKeyPrefix = "mini" + type Commander struct { Cdc *wire.Codec } @@ -60,3 +63,19 @@ func parseAmount(amountStr string) (int64, error) { return amount, nil } + + +func validateTokenURI(uri string) error { + if len(uri) > 2048 { + return errors.New("uri cannot be longer than 2048 characters") + } + return nil +} + +func calcMiniTokenKey(symbol string) []byte { + var buf bytes.Buffer + buf.WriteString(miniTokenKeyPrefix) + buf.WriteString(":") + buf.WriteString(symbol) + return buf.Bytes() +} \ No newline at end of file diff --git a/plugins/minitokens/client/cli/info.go b/plugins/tokens/client/cli/info_mini.go similarity index 79% rename from plugins/minitokens/client/cli/info.go rename to plugins/tokens/client/cli/info_mini.go index 5ce4d76a6..dbba51c05 100644 --- a/plugins/minitokens/client/cli/info.go +++ b/plugins/tokens/client/cli/info_mini.go @@ -15,18 +15,18 @@ import ( "github.com/binance-chain/node/wire" ) -func getTokenInfoCmd(cmdr Commander) *cobra.Command { +func getMiniTokenInfoCmd(cmdr Commander) *cobra.Command { cmd := &cobra.Command{ Use: "info ", Short: "Query mini-token info", - RunE: cmdr.runGetToken, + RunE: cmdr.runGetMiniToken, } cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the mini-token") return cmd } -func (c Commander) runGetToken(cmd *cobra.Command, args []string) error { +func (c Commander) runGetMiniToken(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(c.Cdc) symbol := viper.GetString(flagSymbol) @@ -34,9 +34,9 @@ func (c Commander) runGetToken(cmd *cobra.Command, args []string) error { return errors.New("you must provide the symbol") } - key := []byte(strings.ToUpper(symbol)) + key := calcMiniTokenKey(strings.ToUpper(symbol)) - res, err := ctx.QueryStore(key, common.MiniTokenStoreName) + res, err := ctx.QueryStore(key, common.TokenStoreName) if err != nil { return err } diff --git a/plugins/minitokens/client/cli/issue.go b/plugins/tokens/client/cli/issue_mini.go similarity index 84% rename from plugins/minitokens/client/cli/issue.go rename to plugins/tokens/client/cli/issue_mini.go index 6a0d7776f..6f0ffd07c 100644 --- a/plugins/minitokens/client/cli/issue.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -2,21 +2,17 @@ package commands import ( "fmt" - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/minitokens/issue" + "github.com/binance-chain/node/plugins/tokens/issue_mini" ) const ( flagTokenType = "token-type" - flagTotalSupply = "total-supply" - flagTokenName = "token-name" - flagMintable = "mintable" flagTokenUri = "token-uri" ) @@ -38,7 +34,7 @@ func issueMiniTokenCmd(cmdr Commander) *cobra.Command { return cmd } -func (c Commander) issueToken(cmd *cobra.Command, args []string) error { +func (c Commander) issueMiniToken(cmd *cobra.Command, args []string) error { cliCtx, txBldr := client.PrepareCtx(c.Cdc) from, err := cliCtx.GetFromAddress() if err != nil { @@ -63,7 +59,7 @@ func (c Commander) issueToken(cmd *cobra.Command, args []string) error { } supply := viper.GetInt64(flagTotalSupply) - err = checkSupplyAmount(supply, int8(tokenType)) + err = checkMiniSupplyAmount(supply, int8(tokenType)) if err != nil { return err } @@ -77,7 +73,7 @@ func (c Commander) issueToken(cmd *cobra.Command, args []string) error { } // build message - msg := issue.NewIssueMsg(from, name, symbol, int8(tokenType), supply, mintable, tokenURI) + msg := issue_mini.NewIssueMsg(from, name, symbol, int8(tokenType), supply, mintable, tokenURI) return client.SendOrPrintTx(cliCtx, txBldr, msg) } @@ -88,7 +84,7 @@ func checkTokenType(tokenType int) error { return nil } -func checkSupplyAmount(amount int64, tokenType int8) error { +func checkMiniSupplyAmount(amount int64, tokenType int8) error { if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenSupplyUpperBound { return errors.New("invalid supply amount") } diff --git a/plugins/minitokens/client/cli/seturi.go b/plugins/tokens/client/cli/seturi_mini.go similarity index 90% rename from plugins/minitokens/client/cli/seturi.go rename to plugins/tokens/client/cli/seturi_mini.go index 9f5082830..1e66f5dd0 100644 --- a/plugins/minitokens/client/cli/seturi.go +++ b/plugins/tokens/client/cli/seturi_mini.go @@ -3,7 +3,7 @@ package commands import ( "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/minitokens/seturi" + "github.com/binance-chain/node/plugins/tokens/seturi_mini" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -39,6 +39,6 @@ func (c Commander) setTokenURI(cmd *cobra.Command, args []string) error { return err } - msg := seturi.NewSetUriMsg(from, symbol, tokenURI) + msg := seturi_mini.NewSetUriMsg(from, symbol, tokenURI) return client.SendOrPrintTx(cliCtx, txBldr, msg) } diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index cc1052eed..5aecd3b00 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -11,25 +11,24 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/store" ) // NewHandler creates a new token freeze message handler -func NewHandler(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) sdk.Handler { +func NewHandler(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case FreezeMsg: symbol := strings.ToUpper(msg.Symbol) if common.IsMiniTokenSymbol(symbol) { - return handleFreezeMiniToken(ctx, miniTokenMapper, accKeeper, keeper, msg) + return handleFreezeMiniToken(ctx, tokenMapper, accKeeper, keeper, msg) } else { return handleFreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) } case UnfreezeMsg: symbol := strings.ToUpper(msg.Symbol) if common.IsMiniTokenSymbol(symbol) { - return handleUnfreezeMiniToken(ctx, miniTokenMapper, accKeeper, keeper, msg) + return handleUnfreezeMiniToken(ctx, tokenMapper, accKeeper, keeper, msg) } else { return handleUnfreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) } @@ -86,12 +85,12 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au return sdk.Result{} } -func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg FreezeMsg) sdk.Result { +func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg FreezeMsg) sdk.Result { freezeAmount := msg.Amount symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) errLogMsg := "freeze token failed" - _, err := miniTokenMapper.GetToken(ctx, symbol) + _, err := miniTokenMapper.GetMiniToken(ctx, symbol) if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() @@ -121,7 +120,7 @@ func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenM return sdk.Result{} } -func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg UnfreezeMsg) sdk.Result { +func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg UnfreezeMsg) sdk.Result { unfreezeAmount := msg.Amount symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) @@ -130,7 +129,7 @@ func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniToke useAllFrozenBalance := frozenAmount == unfreezeAmount errLogMsg := "unfreeze token failed" - _, err := miniTokenMapper.GetToken(ctx, symbol) + _, err := miniTokenMapper.GetMiniToken(ctx, symbol) if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 62a2d3407..291039f69 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -16,12 +16,11 @@ import ( "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" common "github.com/binance-chain/node/common/types" - miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/store" ) // NewHandler creates a new token issue message handler -func NewHandler(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { +func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case IssueMsg: @@ -29,7 +28,7 @@ func NewHandler(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMap case MintMsg: symbol := strings.ToUpper(msg.Symbol) if common.IsMiniTokenSymbol(symbol) { - return handleMintMiniToken(ctx, miniTokenMapper, keeper, msg) + return handleMintMiniToken(ctx, tokenMapper, keeper, msg) } else { return handleMintToken(ctx, tokenMapper, keeper, msg) } @@ -155,14 +154,14 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. } } -func handleMintMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { +func handleMintMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "token", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) if !sdk.IsUpgrade(upgrade.BEP8) { return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")).Result() } errLogMsg := "mint token failed" - token, err := miniTokenMapper.GetToken(ctx, symbol) + token, err := tokenMapper.GetMiniToken(ctx, symbol) if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() @@ -196,7 +195,7 @@ func handleMintMiniToken(ctx sdk.Context, miniTokenMapper miniToken.MiniTokenMap common.MiniTokenSupplyUpperBound)).Result() } newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount - err = miniTokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) + err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) if err != nil { logger.Error(errLogMsg, "reason", "update total supply failed: "+err.Error()) return sdk.ErrInternal(fmt.Sprintf("update total supply failed")).Result() diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index acd49fde3..1b022fd0d 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -17,8 +17,8 @@ import ( "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" - miniIssue "github.com/binance-chain/node/plugins/minitokens/issue" miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" + miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) diff --git a/plugins/minitokens/issue/handler.go b/plugins/tokens/issue_mini/handler.go similarity index 92% rename from plugins/minitokens/issue/handler.go rename to plugins/tokens/issue_mini/handler.go index df9f77a88..996755c89 100644 --- a/plugins/minitokens/issue/handler.go +++ b/plugins/tokens/issue_mini/handler.go @@ -1,4 +1,4 @@ -package issue +package issue_mini import ( "encoding/json" @@ -13,11 +13,11 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" - "github.com/binance-chain/node/plugins/minitokens/store" + "github.com/binance-chain/node/plugins/tokens/store" ) // NewHandler creates a new token issue message handler -func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handler { +func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case IssueMsg: @@ -29,7 +29,7 @@ func NewHandler(tokenMapper store.MiniTokenMapper, keeper bank.Keeper) sdk.Handl } } -func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKeeper bank.Keeper, msg IssueMsg) sdk.Result { +func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg IssueMsg) sdk.Result { errLogMsg := "issue miniToken failed" symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) @@ -86,7 +86,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.MiniTokenMapper, bankKe return sdk.ErrInternal(fmt.Sprintf("unable to create token struct: %s", err.Error())).Result() } - if err := tokenMapper.NewToken(ctx, *token); err != nil { + if err := tokenMapper.NewMiniToken(ctx, *token); err != nil { logger.Error(errLogMsg, "reason", "add token failed: "+err.Error()) return sdk.ErrInvalidCoins(err.Error()).Result() } diff --git a/plugins/minitokens/issue/handler_test.go b/plugins/tokens/issue_mini/handler_test.go similarity index 99% rename from plugins/minitokens/issue/handler_test.go rename to plugins/tokens/issue_mini/handler_test.go index b33533aae..0820272fe 100644 --- a/plugins/minitokens/issue/handler_test.go +++ b/plugins/tokens/issue_mini/handler_test.go @@ -1,4 +1,4 @@ -package issue +package issue_mini import ( "testing" diff --git a/plugins/minitokens/issue/msg.go b/plugins/tokens/issue_mini/msg.go similarity index 99% rename from plugins/minitokens/issue/msg.go rename to plugins/tokens/issue_mini/msg.go index f920aaa2f..70d4e720d 100644 --- a/plugins/minitokens/issue/msg.go +++ b/plugins/tokens/issue_mini/msg.go @@ -1,4 +1,4 @@ -package issue +package issue_mini import ( "encoding/json" diff --git a/plugins/tokens/plugin.go b/plugins/tokens/plugin.go index eb60bacdd..b41bc6b32 100644 --- a/plugins/tokens/plugin.go +++ b/plugins/tokens/plugin.go @@ -10,7 +10,6 @@ import ( bnclog "github.com/binance-chain/node/common/log" app "github.com/binance-chain/node/common/types" - miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" ) @@ -19,10 +18,10 @@ const abciQueryPrefix = "tokens" // InitPlugin initializes the plugin. func InitPlugin( - appp app.ChainApp, mapper Mapper, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, coinKeeper bank.Keeper, + appp app.ChainApp, mapper Mapper, accKeeper auth.AccountKeeper, coinKeeper bank.Keeper, timeLockKeeper timelock.Keeper, swapKeeper swap.Keeper) { // add msg handlers - for route, handler := range Routes(mapper, miniTokenMapper, accKeeper, coinKeeper, timeLockKeeper, swapKeeper) { + for route, handler := range Routes(mapper, accKeeper, coinKeeper, timeLockKeeper, swapKeeper) { appp.GetRouter().AddRoute(route, handler) } diff --git a/plugins/tokens/route.go b/plugins/tokens/route.go index 506815dd0..35f0835c8 100644 --- a/plugins/tokens/route.go +++ b/plugins/tokens/route.go @@ -1,11 +1,12 @@ package tokens import ( + "github.com/binance-chain/node/plugins/tokens/issue_mini" + "github.com/binance-chain/node/plugins/tokens/seturi_mini" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" - miniToken "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" @@ -14,13 +15,15 @@ import ( "github.com/binance-chain/node/plugins/tokens/timelock" ) -func Routes(tokenMapper store.Mapper, miniTokenMapper miniToken.MiniTokenMapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, +func Routes(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, timeLockKeeper timelock.Keeper, swapKeeper swap.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) - routes[issue.Route] = issue.NewHandler(tokenMapper, miniTokenMapper, keeper) - routes[burn.BurnRoute] = burn.NewHandler(tokenMapper, miniTokenMapper, keeper) - routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, miniTokenMapper, accKeeper, keeper) + routes[issue.Route] = issue.NewHandler(tokenMapper, keeper) + routes[burn.BurnRoute] = burn.NewHandler(tokenMapper, keeper) + routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, accKeeper, keeper) routes[timelock.MsgRoute] = timelock.NewHandler(timeLockKeeper) routes[swap.AtomicSwapRoute] = swap.NewHandler(swapKeeper) + routes[issue_mini.Route] = issue_mini.NewHandler(tokenMapper, keeper) + routes[seturi_mini.SetURIRoute] = seturi_mini.NewHandler(tokenMapper) return routes } diff --git a/plugins/minitokens/seturi/handler.go b/plugins/tokens/seturi_mini/handler.go similarity index 81% rename from plugins/minitokens/seturi/handler.go rename to plugins/tokens/seturi_mini/handler.go index f4f7e74b3..5730628c3 100644 --- a/plugins/minitokens/seturi/handler.go +++ b/plugins/tokens/seturi_mini/handler.go @@ -1,4 +1,4 @@ -package seturi +package seturi_mini import ( "fmt" @@ -9,10 +9,10 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/minitokens/store" + "github.com/binance-chain/node/plugins/tokens/store" ) -func NewHandler(tokenMapper store.MiniTokenMapper) sdk.Handler { +func NewHandler(tokenMapper store.Mapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case SetURIMsg: @@ -24,12 +24,12 @@ func NewHandler(tokenMapper store.MiniTokenMapper) sdk.Handler { } } -func handleSetURI(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, msg SetURIMsg) sdk.Result { +func handleSetURI(ctx sdk.Context, tokenMapper store.Mapper, msg SetURIMsg) sdk.Result { symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", symbol, "tokenURI", msg.TokenURI, "from", msg.From) errLogMsg := "set token URI failed" - token, err := miniTokenMapper.GetToken(ctx, symbol) + token, err := tokenMapper.GetMiniToken(ctx, symbol) if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() @@ -47,7 +47,7 @@ func handleSetURI(ctx sdk.Context, miniTokenMapper store.MiniTokenMapper, msg Se if len(msg.TokenURI) > common.MaxTokenURILength { return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", common.MaxTokenURILength)).Result() } - err = miniTokenMapper.UpdateTokenURI(ctx, symbol, msg.TokenURI) + err = tokenMapper.UpdateMiniTokenURI(ctx, symbol, msg.TokenURI) if err != nil { logger.Error(errLogMsg, "reason", "update token uri failed: "+err.Error()) return sdk.ErrInternal(fmt.Sprintf("update token uri failed")).Result() diff --git a/plugins/minitokens/seturi/msg.go b/plugins/tokens/seturi_mini/msg.go similarity index 98% rename from plugins/minitokens/seturi/msg.go rename to plugins/tokens/seturi_mini/msg.go index 684204c60..02da0c0b5 100644 --- a/plugins/minitokens/seturi/msg.go +++ b/plugins/tokens/seturi_mini/msg.go @@ -1,4 +1,4 @@ -package seturi +package seturi_mini import ( "encoding/json" diff --git a/plugins/tokens/store/mapper.go b/plugins/tokens/store/mapper.go index d1c27ffcd..32b024ad7 100644 --- a/plugins/tokens/store/mapper.go +++ b/plugins/tokens/store/mapper.go @@ -1,6 +1,7 @@ package store import ( + "bytes" "errors" "fmt" "strings" @@ -15,6 +16,9 @@ import ( ) type Tokens []types.Token +type MiniTokens []types.MiniToken + +const miniTokenKeyPrefix = "mini" func (t Tokens) GetSymbols() *[]string { var symbols []string @@ -32,6 +36,10 @@ type Mapper interface { GetToken(ctx sdk.Context, symbol string) (types.Token, error) // we do not provide the updateToken method UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) error + NewMiniToken(ctx sdk.Context, token types.MiniToken) error + GetMiniTokenList(ctx sdk.Context, showZeroSupplyMiniTokens bool) MiniTokens + GetMiniToken(ctx sdk.Context, symbol string) (types.MiniToken, error) + UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) error } var _ Mapper = mapper{} @@ -49,6 +57,10 @@ func NewMapper(cdc *wire.Codec, key sdk.StoreKey) mapper { } func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.Token, error) { + if strings.HasPrefix(symbol, miniTokenKeyPrefix) { + //Mini token is not allowed to query by this method + return types.Token{}, fmt.Errorf("token(%v) not found", symbol) + } store := ctx.KVStore(m.key) key := []byte(strings.ToUpper(symbol)) @@ -61,6 +73,10 @@ func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.Token, error) { } func (m mapper) GetTokenCC(ctx context.CLIContext, symbol string) (types.Token, error) { + if strings.HasPrefix(symbol, miniTokenKeyPrefix) { + //Mini token is not allowed to query by this method + return types.Token{}, fmt.Errorf("token(%v) not found", symbol) + } key := []byte(strings.ToUpper(symbol)) bz, err := ctx.QueryStore(key, common.TokenStoreName) if err != nil { @@ -78,6 +94,9 @@ func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool) Tokens iter := store.Iterator(nil, nil) defer iter.Close() for ; iter.Valid(); iter.Next() { + if bytes.HasPrefix(iter.Key(), []byte(miniTokenKeyPrefix)) { + continue + } token := m.decodeToken(iter.Value()) if !showZeroSupplyTokens && token.TotalSupply.ToInt64() == 0 { continue @@ -89,12 +108,22 @@ func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool) Tokens func (m mapper) Exists(ctx sdk.Context, symbol string) bool { store := ctx.KVStore(m.key) - key := []byte(strings.ToUpper(symbol)) + var key []byte + if types.IsMiniTokenSymbol(symbol) { + key = m.calcMiniTokenKey(strings.ToUpper(symbol)) + }else{ + key = []byte(strings.ToUpper(symbol)) + } return store.Has(key) } func (m mapper) ExistsCC(ctx context.CLIContext, symbol string) bool { - key := []byte(strings.ToUpper(symbol)) + var key []byte + if types.IsMiniTokenSymbol(symbol) { + key = m.calcMiniTokenKey(strings.ToUpper(symbol)) + }else{ + key = []byte(strings.ToUpper(symbol)) + } bz, err := ctx.QueryStore(key, common.TokenStoreName) if err != nil { return false @@ -111,6 +140,7 @@ func (m mapper) NewToken(ctx sdk.Context, token types.Token) error { return err } key := []byte(strings.ToUpper(symbol)) + store := ctx.KVStore(m.key) value := m.encodeToken(token) store.Set(key, value) @@ -122,6 +152,10 @@ func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) return errors.New("symbol cannot be empty") } + if types.IsMiniTokenSymbol(symbol) { + return m.updateMiniTotalSupply(ctx, symbol, supply) + } + key := []byte(strings.ToUpper(symbol)) store := ctx.KVStore(m.key) bz := store.Get(key) diff --git a/plugins/tokens/store/mapper_mini.go b/plugins/tokens/store/mapper_mini.go new file mode 100644 index 000000000..74291285d --- /dev/null +++ b/plugins/tokens/store/mapper_mini.go @@ -0,0 +1,125 @@ +package store + +import ( + "bytes" + "errors" + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/utils" +) + +func (m mapper) GetMiniToken(ctx sdk.Context, symbol string) (types.MiniToken, error) { + store := ctx.KVStore(m.key) + key := m.calcMiniTokenKey(strings.ToUpper(symbol)) + + bz := store.Get(key) + if bz != nil { + return m.decodeMiniToken(bz), nil + } + + return types.MiniToken{}, fmt.Errorf("mini-token(%v) not found", symbol) +} +func (m mapper) GetMiniTokenList(ctx sdk.Context, showZeroSupplyMiniTokens bool) MiniTokens { + var res MiniTokens + store := ctx.KVStore(m.key) + iter := store.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + if !bytes.HasPrefix(iter.Key(), []byte(miniTokenKeyPrefix)) { + continue + } + token := m.decodeMiniToken(iter.Value()) + if !showZeroSupplyMiniTokens && token.TotalSupply.ToInt64() == 0 { + continue + } + res = append(res, token) + } + return res +} + +func (m mapper) NewMiniToken(ctx sdk.Context, token types.MiniToken) error { + symbol := token.Symbol + if err := types.ValidateMiniToken(token); err != nil { + return err + } + key := m.calcMiniTokenKey(strings.ToUpper(symbol)) + store := ctx.KVStore(m.key) + value := m.encodeMiniToken(token) + store.Set(key, value) + return nil +} + +func (m mapper) updateMiniTotalSupply(ctx sdk.Context, symbol string, supply int64) error { + key := []byte(strings.ToUpper(symbol)) + store := ctx.KVStore(m.key) + bz := store.Get(key) + if bz == nil { + return errors.New("mini token does not exist") + } + + toBeUpdated := m.decodeMiniToken(bz) + + if toBeUpdated.TotalSupply.ToInt64() != supply { + toBeUpdated.TotalSupply = utils.Fixed8(supply) + store.Set(key, m.encodeMiniToken(toBeUpdated)) + } + return nil +} + +func (m mapper) UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) error { + if len(symbol) == 0 { + return errors.New("symbol cannot be empty") + } + + if len(uri) == 0 { + return errors.New("uri cannot be empty") + } + + if len(uri) > 2048 { + return errors.New("uri length cannot be larger than 2048") + } + + key := []byte(strings.ToUpper(symbol)) + store := ctx.KVStore(m.key) + bz := store.Get(key) + if bz == nil { + return errors.New("token does not exist") + } + + toBeUpdated := m.decodeMiniToken(bz) + + if toBeUpdated.TokenURI != uri { + toBeUpdated.TokenURI = uri + store.Set(key, m.encodeMiniToken(toBeUpdated)) + } + return nil +} + +func (m mapper) encodeMiniToken(token types.MiniToken) []byte { + bz, err := m.cdc.MarshalBinaryBare(token) + if err != nil { + panic(err) + } + return bz +} + +func (m mapper) decodeMiniToken(bz []byte) (token types.MiniToken) { + err := m.cdc.UnmarshalBinaryBare(bz, &token) + if err != nil { + panic(err) + } + return +} + +func (m mapper) calcMiniTokenKey(symbol string) []byte { + var buf bytes.Buffer + buf.WriteString(miniTokenKeyPrefix) + buf.WriteString(":") + buf.WriteString(symbol) + return buf.Bytes() +} + diff --git a/plugins/tokens/wire.go b/plugins/tokens/wire.go index af0df4740..cbd83f301 100644 --- a/plugins/tokens/wire.go +++ b/plugins/tokens/wire.go @@ -4,6 +4,8 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" + "github.com/binance-chain/node/plugins/tokens/issue_mini" + "github.com/binance-chain/node/plugins/tokens/seturi_mini" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" "github.com/binance-chain/node/wire" @@ -23,4 +25,6 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(swap.DepositHTLTMsg{}, "tokens/DepositHTLTMsg", nil) cdc.RegisterConcrete(swap.ClaimHTLTMsg{}, "tokens/ClaimHTLTMsg", nil) cdc.RegisterConcrete(swap.RefundHTLTMsg{}, "tokens/RefundHTLTMsg", nil) + cdc.RegisterConcrete(issue_mini.IssueMsg{}, "minitokens/IssueMsg", nil) + cdc.RegisterConcrete(seturi_mini.SetURIMsg{}, "minitokens/SetURIMsg", nil) } From daaa4a36ee02e09f286222ca4b87817f65891b75 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 12 May 2020 17:16:16 +0800 Subject: [PATCH 38/96] fix config --- app/config/config.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/config/config.go b/app/config/config.go index 52e933e97..1275bd62d 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -67,16 +67,13 @@ LotSizeUpgradeHeight = {{ .UpgradeConfig.LotSizeUpgradeHeight }} ListingRuleUpgradeHeight = {{ .UpgradeConfig.ListingRuleUpgradeHeight }} # Block height of FixZeroBalanceHeight upgrade FixZeroBalanceHeight = {{ .UpgradeConfig.FixZeroBalanceHeight }} -<<<<<<< HEAD # Block height of BEP8 upgrade BEP8Height = {{ .UpgradeConfig.BEP8Height }} -======= # Block height of BEP67 upgrade BEP67Height = {{ .UpgradeConfig.BEP67Height }} # Block height of BEP70 upgrade BEP70Height = {{ .UpgradeConfig.BEP70Height }} ->>>>>>> origin/develop [query] # ABCI query interface black list, suggested value: ["custom/gov/proposals", "custom/timelock/timelocks", "custom/atomicSwap/swapcreator", "custom/atomicSwap/swaprecipient"] ABCIQueryBlackList = {{ .QueryConfig.ABCIQueryBlackList }} From 9cfa7ab51c02dcb10e08ae4c36549c749710f7d7 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 12 May 2020 20:16:36 +0800 Subject: [PATCH 39/96] fix issue mini abci --- admin/tx.go | 2 +- app/app.go | 2 +- app/pub/helpers.go | 2 +- networks/publisher/setup_mini.sh | 2 +- plugins/minitokens/abci.go | 118 ------------------------ plugins/minitokens/client/cli/helper.go | 59 ------------ plugins/minitokens/plugin.go | 27 ------ plugins/tokens/abci.go | 79 +++++++++++----- plugins/tokens/client/cli/helper.go | 8 +- plugins/tokens/issue_mini/handler.go | 4 +- plugins/tokens/issue_mini/msg.go | 24 ++--- plugins/tokens/plugin.go | 11 ++- plugins/tokens/wire.go | 4 +- 13 files changed, 90 insertions(+), 252 deletions(-) delete mode 100644 plugins/minitokens/abci.go delete mode 100644 plugins/minitokens/client/cli/helper.go delete mode 100644 plugins/minitokens/plugin.go diff --git a/admin/tx.go b/admin/tx.go index 2e1527f92..4b5f264a2 100644 --- a/admin/tx.go +++ b/admin/tx.go @@ -26,7 +26,7 @@ var transferOnlyModeBlackList = []string{ timelock.TimeLockMsg{}.Type(), timelock.TimeUnlockMsg{}.Type(), timelock.TimeRelockMsg{}.Type(), - miniIssue.IssueMsg{}.Type(), + miniIssue.IssueMiniMsg{}.Type(), } var TxBlackList = map[runtime.Mode][]string{ diff --git a/app/app.go b/app/app.go index 66ac481fe..622272d13 100644 --- a/app/app.go +++ b/app/app.go @@ -295,7 +295,7 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { ) // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, - miniIssue.IssueMsg{}.Type(), + miniIssue.IssueMiniMsg{}.Type(), seturi_mini.SetURIMsg{}.Type(), listmini.ListMiniMsg{}.Type(), ) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index fa9657bbf..2f54b89e7 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -132,7 +132,7 @@ func GetBlockPublished(pool *sdk.Pool, header abci.Header, blockHash []byte) *Bl case freeze.UnfreezeMsg: txAsset = msg.Symbol // will not cover timelock, timeUnlock, timeRelock, atomic Swap - case miniIssue.IssueMsg: + case miniIssue.IssueMiniMsg: txAsset = msg.Symbol } transactionsToPublish = append(transactionsToPublish, Transaction{ diff --git a/networks/publisher/setup_mini.sh b/networks/publisher/setup_mini.sh index 740da48b2..ba56770b4 100755 --- a/networks/publisher/setup_mini.sh +++ b/networks/publisher/setup_mini.sh @@ -69,7 +69,7 @@ sed -i -e "s/6060/7060/g" ${witnesshome}/config/config.toml ${executable} start --pruning breathe > ${deamonhome}/log.txt 2>&1 & validator_pid=$! echo ${validator_pid} -sleep 60 # sleep in case cli status call failed to get node id +sleep 20 # sleep in case cli status call failed to get node id validatorStatus=$(${cli} status) validator_id=$(echo ${validatorStatus} | grep -o "\"id\":\"[a-zA-Z0-9]*\"" | sed "s/\"//g" | sed "s/id://g") #echo ${validator_id} diff --git a/plugins/minitokens/abci.go b/plugins/minitokens/abci.go deleted file mode 100644 index e8816a26f..000000000 --- a/plugins/minitokens/abci.go +++ /dev/null @@ -1,118 +0,0 @@ -package minitokens - -//import ( -// "fmt" -// "strconv" -// "strings" -// -// abci "github.com/tendermint/tendermint/abci/types" -// -// sdk "github.com/cosmos/cosmos-sdk/types" -// -// app "github.com/binance-chain/node/common/types" -//) -// -//func createAbciQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { -// return func(app app.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { -// // expects at least two query path segments. -// if path[0] != abciQueryPrefix || len(path) < 2 { -// return nil -// } -// switch path[1] { -// case "info": // args: ["minitokens", "info", ] -// if len(path) < 3 { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeUnknownRequest), -// Log: fmt.Sprintf( -// "%s %s query requires a symbol path arg", -// abciQueryPrefix, path[1]), -// } -// } -// ctx := app.GetContextForCheckState() -// symbol := path[2] -// if len(symbol) == 0 { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeInternal), -// Log: "empty symbol not permitted", -// } -// } -// token, err := mapper.GetToken(ctx, symbol) -// if err != nil { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeInternal), -// Log: err.Error(), -// } -// } -// bz, err := app.GetCodec().MarshalBinaryLengthPrefixed(token) -// if err != nil { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeInternal), -// Log: err.Error(), -// } -// } -// return &abci.ResponseQuery{ -// Code: uint32(sdk.ABCICodeOK), -// Value: bz, -// } -// case "list": // args: ["minitokens", "list", , , ] -// if len(path) < 4 { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeUnknownRequest), -// Log: fmt.Sprintf( -// "%s %s query requires offset and limit path segments", -// abciQueryPrefix, path[1]), -// } -// } -// showZeroSupplyTokens := false -// if len(path) == 5 && strings.ToLower(path[4]) == "true" { -// showZeroSupplyTokens = true -// } -// ctx := app.GetContextForCheckState() -// tokens := mapper.GetTokenList(ctx, showZeroSupplyTokens) -// offset, err := strconv.Atoi(path[2]) -// if err != nil || offset < 0 || offset >= len(tokens) { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeInternal), -// Log: "unable to parse offset", -// } -// } -// limit, err := strconv.Atoi(path[3]) -// if err != nil || limit <= 0 { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeInternal), -// Log: "unable to parse limit", -// } -// } -// end := offset + limit -// if end > len(tokens) { -// end = len(tokens) -// } -// if end <= 0 || end <= offset { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeInternal), -// Log: "malformed range", -// } -// } -// bz, err := app.GetCodec().MarshalBinaryLengthPrefixed( -// tokens[offset:end], -// ) -// if err != nil { -// return &abci.ResponseQuery{ -// Code: uint32(sdk.CodeInternal), -// Log: err.Error(), -// } -// } -// return &abci.ResponseQuery{ -// Code: uint32(sdk.ABCICodeOK), -// Value: bz, -// } -// default: -// return &abci.ResponseQuery{ -// Code: uint32(sdk.ABCICodeOK), -// Info: fmt.Sprintf( -// "Unknown `%s` query path: %v", -// abciQueryPrefix, path), -// } -// } -// } -//} diff --git a/plugins/minitokens/client/cli/helper.go b/plugins/minitokens/client/cli/helper.go deleted file mode 100644 index b58ba2f5d..000000000 --- a/plugins/minitokens/client/cli/helper.go +++ /dev/null @@ -1,59 +0,0 @@ -package commands -// -//import ( -// "errors" -// "strconv" -// "strings" -// -// "github.com/spf13/cobra" -// "github.com/spf13/viper" -// -// sdk "github.com/cosmos/cosmos-sdk/types" -// -// "github.com/binance-chain/node/common/client" -// "github.com/binance-chain/node/common/types" -// "github.com/binance-chain/node/wire" -//) -// -//type msgBuilder func(from sdk.AccAddress, symbol string, amount int64) sdk.Msg -// -//func (c Commander) checkAndSendTx(cmd *cobra.Command, args []string, builder msgBuilder) error { -// cliCtx, txBuilder := client.PrepareCtx(c.Cdc) -// -// from, err := cliCtx.GetFromAddress() -// if err != nil { -// return err -// } -// -// symbol := viper.GetString(flagSymbol) -// err = types.ValidateMapperMiniTokenSymbol(symbol) -// if err != nil { -// return err -// } -// -// symbol = strings.ToUpper(symbol) -// -// amountStr := viper.GetString(flagAmount) -// amount, err := parseAmount(amountStr) -// if err != nil { -// return err -// } -// -// // build message -// msg := builder(from, symbol, amount) -// return client.SendOrPrintTx(cliCtx, txBuilder, msg) -//} -// -//func parseAmount(amountStr string) (int64, error) { -// amount, err := strconv.ParseInt(amountStr, 10, 64) -// if err != nil { -// return 0, err -// } -// -// if amount <= 0 { -// return amount, errors.New("the amount should be greater than 0") -// } -// -// return amount, nil -//} -// diff --git a/plugins/minitokens/plugin.go b/plugins/minitokens/plugin.go deleted file mode 100644 index 19a41b8dc..000000000 --- a/plugins/minitokens/plugin.go +++ /dev/null @@ -1,27 +0,0 @@ -package minitokens - -//import ( -// "github.com/cosmos/cosmos-sdk/x/auth" -// "github.com/cosmos/cosmos-sdk/x/bank" -// -// app "github.com/binance-chain/node/common/types" -//) -// -//const abciQueryPrefix = "mini-tokens" -// -//// InitPlugin initializes the plugin. -//func InitPlugin( -// appp app.ChainApp, mapper MiniTokenMapper, accKeeper auth.AccountKeeper, coinKeeper bank.Keeper) { -// // add msg handlers -// for route, handler := range Routes(mapper, accKeeper, coinKeeper) { -// appp.GetRouter().AddRoute(route, handler) -// } -// -// // add abci handlers -// handler := createQueryHandler(mapper) -// appp.RegisterQueryHandler(abciQueryPrefix, handler) -//} -// -//func createQueryHandler(mapper MiniTokenMapper) app.AbciQueryHandler { -// return createAbciQueryHandler(mapper) -//} diff --git a/plugins/tokens/abci.go b/plugins/tokens/abci.go index 3b8b7a470..76e789c46 100644 --- a/plugins/tokens/abci.go +++ b/plugins/tokens/abci.go @@ -9,11 +9,21 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - app "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/types" ) -func createAbciQueryHandler(mapper Mapper) app.AbciQueryHandler { - return func(app app.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { +func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler { + abciQueryPrefix := prefix + var isMini bool + switch abciQueryPrefix { + case abciQueryPrefix: + isMini = false + case miniAbciQueryPrefix: + isMini = true + default: + isMini = false + } + return func(app types.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { // expects at least two query path segments. if path[0] != abciQueryPrefix || len(path) < 2 { return nil @@ -36,24 +46,7 @@ func createAbciQueryHandler(mapper Mapper) app.AbciQueryHandler { Log: "empty symbol not permitted", } } - token, err := mapper.GetToken(ctx, symbol) - if err != nil { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: err.Error(), - } - } - bz, err := app.GetCodec().MarshalBinaryLengthPrefixed(token) - if err != nil { - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: err.Error(), - } - } - return &abci.ResponseQuery{ - Code: uint32(sdk.ABCICodeOK), - Value: bz, - } + return queryAndMarshallToken(app, mapper, ctx, symbol, isMini) case "list": // args: ["tokens", "list", , , ] if len(path) < 4 { return &abci.ResponseQuery{ @@ -116,3 +109,47 @@ func createAbciQueryHandler(mapper Mapper) app.AbciQueryHandler { } } } + +func queryAndMarshallToken(app types.ChainApp, mapper Mapper, ctx sdk.Context, symbol string, isMini bool) *abci.ResponseQuery { + var bz []byte + var err error + var token interface{} + + token, err = getToken(mapper, ctx, symbol, isMini) + if err != nil { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: err.Error(), + } + } + switch token.(type) { + case types.MiniToken: + bz, err = app.GetCodec().MarshalBinaryLengthPrefixed(token.(types.MiniToken)) + case types.Token: + bz, err = app.GetCodec().MarshalBinaryLengthPrefixed(token.(types.Token)) + default: + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: err.Error(), + } + } + + if err != nil { + return &abci.ResponseQuery{ + Code: uint32(sdk.CodeInternal), + Log: err.Error(), + } + } + return &abci.ResponseQuery{ + Code: uint32(sdk.ABCICodeOK), + Value: bz, + } +} + +func getToken(mapper Mapper, ctx sdk.Context, symbol string, isMini bool) (interface{}, error) { + if isMini { + return mapper.GetMiniToken(ctx, symbol) + } else { + return mapper.GetToken(ctx, symbol) + } +} diff --git a/plugins/tokens/client/cli/helper.go b/plugins/tokens/client/cli/helper.go index 9d44f93b0..7eca6e219 100644 --- a/plugins/tokens/client/cli/helper.go +++ b/plugins/tokens/client/cli/helper.go @@ -33,9 +33,11 @@ func (c Commander) checkAndSendTx(cmd *cobra.Command, args []string, builder msg } symbol := viper.GetString(flagSymbol) - err = types.ValidateMapperTokenSymbol(symbol) - if err != nil { - return err + if !types.IsMiniTokenSymbol(symbol) { + err = types.ValidateMapperTokenSymbol(symbol) + if err != nil { + return err + } } symbol = strings.ToUpper(symbol) diff --git a/plugins/tokens/issue_mini/handler.go b/plugins/tokens/issue_mini/handler.go index 996755c89..f3cac7c27 100644 --- a/plugins/tokens/issue_mini/handler.go +++ b/plugins/tokens/issue_mini/handler.go @@ -20,7 +20,7 @@ import ( func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { - case IssueMsg: + case IssueMiniMsg: return handleIssueToken(ctx, tokenMapper, keeper, msg) default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() @@ -29,7 +29,7 @@ func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { } } -func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg IssueMsg) sdk.Result { +func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg IssueMiniMsg) sdk.Result { errLogMsg := "issue miniToken failed" symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) diff --git a/plugins/tokens/issue_mini/msg.go b/plugins/tokens/issue_mini/msg.go index 70d4e720d..9b1a740e8 100644 --- a/plugins/tokens/issue_mini/msg.go +++ b/plugins/tokens/issue_mini/msg.go @@ -18,9 +18,9 @@ const ( maxTokenNameLength = 32 ) -var _ sdk.Msg = IssueMsg{} +var _ sdk.Msg = IssueMiniMsg{} -type IssueMsg struct { +type IssueMiniMsg struct { From sdk.AccAddress `json:"from"` Name string `json:"name"` Symbol string `json:"symbol"` @@ -30,8 +30,8 @@ type IssueMsg struct { TokenURI string `json:"token_uri"` } -func NewIssueMsg(from sdk.AccAddress, name, symbol string, tokenType int8, supply int64, mintable bool, tokenURI string) IssueMsg { - return IssueMsg{ +func NewIssueMsg(from sdk.AccAddress, name, symbol string, tokenType int8, supply int64, mintable bool, tokenURI string) IssueMiniMsg { + return IssueMiniMsg{ From: from, Name: name, Symbol: symbol, @@ -44,7 +44,7 @@ func NewIssueMsg(from sdk.AccAddress, name, symbol string, tokenType int8, suppl // ValidateBasic does a simple validation check that // doesn't require access to any other information. -func (msg IssueMsg) ValidateBasic() sdk.Error { +func (msg IssueMiniMsg) ValidateBasic() sdk.Error { if msg.From == nil { return sdk.ErrInvalidAddress("sender address cannot be empty") } @@ -72,9 +72,9 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { return nil } -// Implements IssueMsg. -func (msg IssueMsg) Route() string { return Route } -func (msg IssueMsg) Type() string { +// Implements IssueMiniMsg. +func (msg IssueMiniMsg) Route() string { return Route } +func (msg IssueMiniMsg) Type() string { switch types.SupplyRangeType(msg.TokenType) { case types.SupplyRange.TINY: return IssueTinyMsgType @@ -84,15 +84,15 @@ func (msg IssueMsg) Type() string { return IssueMiniMsgType } } -func (msg IssueMsg) String() string { return fmt.Sprintf("IssueMsg{%#v}", msg) } -func (msg IssueMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } -func (msg IssueMsg) GetSignBytes() []byte { +func (msg IssueMiniMsg) String() string { return fmt.Sprintf("IssueMiniMsg{%#v}", msg) } +func (msg IssueMiniMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } +func (msg IssueMiniMsg) GetSignBytes() []byte { b, err := json.Marshal(msg) // XXX: ensure some canonical form if err != nil { panic(err) } return b } -func (msg IssueMsg) GetInvolvedAddresses() []sdk.AccAddress { +func (msg IssueMiniMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } diff --git a/plugins/tokens/plugin.go b/plugins/tokens/plugin.go index b41bc6b32..c54c52bf9 100644 --- a/plugins/tokens/plugin.go +++ b/plugins/tokens/plugin.go @@ -15,6 +15,7 @@ import ( ) const abciQueryPrefix = "tokens" +const miniAbciQueryPrefix = "mini-tokens" // InitPlugin initializes the plugin. func InitPlugin( @@ -26,12 +27,14 @@ func InitPlugin( } // add abci handlers - handler := createQueryHandler(mapper) - appp.RegisterQueryHandler(abciQueryPrefix, handler) + tokenHandler := createQueryHandler(mapper, abciQueryPrefix) + miniTokenHandler := createQueryHandler(mapper, miniAbciQueryPrefix) + appp.RegisterQueryHandler(abciQueryPrefix, tokenHandler) + appp.RegisterQueryHandler(miniAbciQueryPrefix, miniTokenHandler) } -func createQueryHandler(mapper Mapper) app.AbciQueryHandler { - return createAbciQueryHandler(mapper) +func createQueryHandler(mapper Mapper, queryPrefix string) app.AbciQueryHandler { + return createAbciQueryHandler(mapper, queryPrefix) } // EndBreatheBlock processes the breathe block lifecycle event. diff --git a/plugins/tokens/wire.go b/plugins/tokens/wire.go index cbd83f301..64501055a 100644 --- a/plugins/tokens/wire.go +++ b/plugins/tokens/wire.go @@ -25,6 +25,6 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(swap.DepositHTLTMsg{}, "tokens/DepositHTLTMsg", nil) cdc.RegisterConcrete(swap.ClaimHTLTMsg{}, "tokens/ClaimHTLTMsg", nil) cdc.RegisterConcrete(swap.RefundHTLTMsg{}, "tokens/RefundHTLTMsg", nil) - cdc.RegisterConcrete(issue_mini.IssueMsg{}, "minitokens/IssueMsg", nil) - cdc.RegisterConcrete(seturi_mini.SetURIMsg{}, "minitokens/SetURIMsg", nil) + cdc.RegisterConcrete(issue_mini.IssueMiniMsg{}, "tokens/IssueMiniMsg", nil) + cdc.RegisterConcrete(seturi_mini.SetURIMsg{}, "tokens/SetURIMsg", nil) } From 513169e232fceacfa65b71dd5d77ef1bc834db5b Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 13 May 2020 19:39:05 +0800 Subject: [PATCH 40/96] move mini token mapper to token mapper --- common/types/mini_token.go | 11 +-- common/types/token.go | 48 ++++++++++++- common/types/wire.go | 6 +- plugins/dex/list/handler.go | 2 +- plugins/dex/list/handler_test.go | 12 ++-- plugins/dex/list/hooks_test.go | 18 ++--- plugins/dex/listmini/handler.go | 2 +- plugins/tokens/abci.go | 44 +++++------- plugins/tokens/abci_test.go | 12 ++-- plugins/tokens/burn/handler.go | 22 +++--- plugins/tokens/client/cli/issue_mini.go | 2 +- plugins/tokens/client/rest/gettokens.go | 20 ++---- plugins/tokens/freeze/handler.go | 4 +- plugins/tokens/genesis.go | 2 +- plugins/tokens/issue/handler.go | 18 ++--- plugins/tokens/issue/handler_test.go | 26 ++++--- plugins/tokens/issue_mini/handler.go | 2 +- plugins/tokens/seturi_mini/handler.go | 2 +- plugins/tokens/store/mapper.go | 95 +++++++++++++------------ plugins/tokens/store/mapper_mini.go | 85 ++-------------------- 20 files changed, 194 insertions(+), 239 deletions(-) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 89fea3cd1..3df631838 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -1,7 +1,6 @@ package types import ( - "bytes" "errors" "fmt" "regexp" @@ -63,6 +62,8 @@ type MiniToken struct { TokenURI string `json:"token_uri"` //TODO set max length } +var _ IToken = &MiniToken{} + func NewMiniToken(name, symbol string, supplyRangeType int8, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken, error) { // double check that the symbol is suffixed if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { @@ -92,7 +93,7 @@ func IsMiniTokenSymbol(symbol string) bool { return true } -func (token *MiniToken) IsOwner(addr sdk.AccAddress) bool { return bytes.Equal(token.Owner, addr) } +//func (token *MiniToken) IsOwner(addr sdk.AccAddress) bool { return bytes.Equal(token.Owner, addr) } func (token MiniToken) String() string { return fmt.Sprintf("{Name: %v, Symbol: %v, TokenType: %v, TotalSupply: %v, Owner: %X, Mintable: %v, TokenURI: %v}", token.Name, token.Symbol, token.TokenType, token.TotalSupply, token.Owner, token.Mintable, token.TokenURI) @@ -100,11 +101,11 @@ func (token MiniToken) String() string { // Token Validation -func ValidateMiniToken(token MiniToken) error { - if err := ValidateMapperMiniTokenSymbol(token.Symbol); err != nil { +func ValidateMiniToken(token IToken) error { + if err := ValidateMapperMiniTokenSymbol(token.GetSymbol()); err != nil { return err } - if err := ValidateIssueMsgMiniTokenSymbol(token.OrigSymbol); err != nil { + if err := ValidateIssueMsgMiniTokenSymbol(token.GetOrigSymbol()); err != nil { return err } return nil diff --git a/common/types/token.go b/common/types/token.go index 500260fd0..95c63f150 100644 --- a/common/types/token.go +++ b/common/types/token.go @@ -26,6 +26,20 @@ const ( NativeTokenTotalSupply = 2e16 ) +type IToken interface { + GetName() string + GetSymbol() string + GetOrigSymbol() string + GetTotalSupply() utils.Fixed8 + SetTotalSupply(totalSupply utils.Fixed8) + GetOwner() sdk.AccAddress + IsMintable() bool + IsOwner(addr sdk.AccAddress) bool + String() string +} + +var _ IToken = &Token{} + type Token struct { Name string `json:"name"` Symbol string `json:"symbol"` @@ -35,6 +49,34 @@ type Token struct { Mintable bool `json:"mintable"` } +func (token Token) GetName() string { + return token.Name +} + +func (token Token) GetSymbol() string { + return token.Symbol +} + +func (token Token) GetOrigSymbol() string { + return token.OrigSymbol +} + +func (token Token) GetTotalSupply() utils.Fixed8 { + return token.TotalSupply +} + +func (token *Token) SetTotalSupply(totalSupply utils.Fixed8) { + token.TotalSupply = totalSupply +} + +func (token Token) GetOwner() sdk.AccAddress { + return token.Owner +} + +func (token Token) IsMintable() bool { + return token.Mintable +} + func NewToken(name, symbol string, totalSupply int64, owner sdk.AccAddress, mintable bool) (*Token, error) { // double check that the symbol is suffixed if err := ValidateMapperTokenSymbol(symbol); err != nil { @@ -62,11 +104,11 @@ func (token Token) String() string { // Token Validation -func ValidateToken(token Token) error { - if err := ValidateMapperTokenSymbol(token.Symbol); err != nil { +func ValidateToken(token IToken) error { + if err := ValidateMapperTokenSymbol(token.GetSymbol()); err != nil { return err } - if err := ValidateIssueMsgTokenSymbol(token.OrigSymbol); err != nil { + if err := ValidateIssueMsgTokenSymbol(token.GetOrigSymbol()); err != nil { return err } return nil diff --git a/common/types/wire.go b/common/types/wire.go index e76c7adaf..7f5b56a25 100644 --- a/common/types/wire.go +++ b/common/types/wire.go @@ -10,8 +10,10 @@ func RegisterWire(cdc *wire.Codec) { // Register AppAccount cdc.RegisterInterface((*sdk.Account)(nil), nil) cdc.RegisterInterface((*NamedAccount)(nil), nil) + cdc.RegisterInterface((*IToken)(nil), nil) + cdc.RegisterConcrete(&AppAccount{}, "bnbchain/Account", nil) - cdc.RegisterConcrete(Token{}, "bnbchain/Token", nil) - cdc.RegisterConcrete(MiniToken{}, "bnbchain/MiniToken", nil) + cdc.RegisterConcrete(&Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(&MiniToken{}, "bnbchain/MiniToken", nil) } diff --git a/plugins/dex/list/handler.go b/plugins/dex/list/handler.go index 463e23b08..a94e1b3e5 100644 --- a/plugins/dex/list/handler.go +++ b/plugins/dex/list/handler.go @@ -90,7 +90,7 @@ func handleList(ctx sdk.Context, keeper *order.DexKeeper, tokenMapper tokens.Map } if sdk.IsUpgrade(upgrade.ListingRuleUpgrade) { - quoteToken, err := tokenMapper.GetToken(ctx, msg.QuoteAssetSymbol) + quoteToken, err := tokenMapper.GetToken(ctx, msg.QuoteAssetSymbol) //todo if err != nil { return sdk.ErrInvalidCoins(err.Error()).Result() } diff --git a/plugins/dex/list/handler_test.go b/plugins/dex/list/handler_test.go index fd1762df8..c689ae06e 100644 --- a/plugins/dex/list/handler_test.go +++ b/plugins/dex/list/handler_test.go @@ -207,7 +207,7 @@ func TestListHandler(t *testing.T) { }) require.Contains(t, result.Log, "token(BTC-000) not found") - err := tokenMapper.NewToken(ctx, types.Token{ + err := tokenMapper.NewToken(ctx, &types.Token{ Name: "Bitcoin", Symbol: "BTC-000", OrigSymbol: "BTC", @@ -234,7 +234,7 @@ func TestListHandler(t *testing.T) { }) require.Contains(t, result.Log, "quote token does not exist") - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: types.NativeTokenSymbol, OrigSymbol: types.NativeTokenSymbol, @@ -258,7 +258,7 @@ func TestListHandler_LowerCase(t *testing.T) { cdc := MakeCodec() ms, orderKeeper, tokenMapper, govKeeper := MakeKeepers(cdc) ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) - err := tokenMapper.NewToken(ctx, types.Token{ + err := tokenMapper.NewToken(ctx, &types.Token{ Name: "Bitcoin", Symbol: "BTC-000", OrigSymbol: "BTC", @@ -267,7 +267,7 @@ func TestListHandler_LowerCase(t *testing.T) { }) require.Nil(t, err, "new token error") - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: types.NativeTokenSymbol, OrigSymbol: types.NativeTokenSymbol, @@ -325,7 +325,7 @@ func TestListHandler_AfterUpgrade(t *testing.T) { cdc := MakeCodec() ms, orderKeeper, tokenMapper, govKeeper := MakeKeepers(cdc) ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) - err := tokenMapper.NewToken(ctx, types.Token{ + err := tokenMapper.NewToken(ctx, &types.Token{ Name: "Bitcoin", Symbol: "BTC-000", OrigSymbol: "BTC", @@ -334,7 +334,7 @@ func TestListHandler_AfterUpgrade(t *testing.T) { }) require.Nil(t, err, "new token error") - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: types.NativeTokenSymbol, OrigSymbol: types.NativeTokenSymbol, diff --git a/plugins/dex/list/hooks_test.go b/plugins/dex/list/hooks_test.go index 2c86f610f..996a0f946 100644 --- a/plugins/dex/list/hooks_test.go +++ b/plugins/dex/list/hooks_test.go @@ -177,7 +177,7 @@ func TestTradingPairExists(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.BaseAssetSymbol, OrigSymbol: listParams.BaseAssetSymbol, @@ -186,7 +186,7 @@ func TestTradingPairExists(t *testing.T) { }) require.Nil(t, err, "new token error") - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.QuoteAssetSymbol, OrigSymbol: "BTC", @@ -226,7 +226,7 @@ func TestPrerequisiteTradingPair(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.BaseAssetSymbol, OrigSymbol: "BTC", @@ -235,7 +235,7 @@ func TestPrerequisiteTradingPair(t *testing.T) { }) require.Nil(t, err, "new token error") - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.QuoteAssetSymbol, OrigSymbol: "ETH", @@ -260,7 +260,7 @@ func TestPrerequisiteTradingPair(t *testing.T) { err = orderKeeper.PairMapper.AddTradingPair(ctx, pair) require.Nil(t, err, "add trading pair error") - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.BaseAssetSymbol, OrigSymbol: "BTC", @@ -269,7 +269,7 @@ func TestPrerequisiteTradingPair(t *testing.T) { }) require.Nil(t, err, "new token error") - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.QuoteAssetSymbol, OrigSymbol: "ETH", @@ -330,7 +330,7 @@ func TestQuoteTokenDoesNotExist(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.BaseAssetSymbol, OrigSymbol: "BNB", @@ -366,7 +366,7 @@ func TestRightProposal(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.BaseAssetSymbol, OrigSymbol: listParams.BaseAssetSymbol, @@ -375,7 +375,7 @@ func TestRightProposal(t *testing.T) { }) require.Nil(t, err, "new token error") - err = tokenMapper.NewToken(ctx, types.Token{ + err = tokenMapper.NewToken(ctx, &types.Token{ Name: "Native Token", Symbol: listParams.QuoteAssetSymbol, OrigSymbol: "BTC", diff --git a/plugins/dex/listmini/handler.go b/plugins/dex/listmini/handler.go index bdb0b0026..f3230c1ea 100644 --- a/plugins/dex/listmini/handler.go +++ b/plugins/dex/listmini/handler.go @@ -36,7 +36,7 @@ func handleList(ctx sdk.Context, dexKeeper *order.DexKeeper, tokenMapper tokens. return sdk.ErrInvalidCoins(err.Error()).Result() } - baseToken, err := tokenMapper.GetMiniToken(ctx, msg.BaseAssetSymbol) + baseToken, err := tokenMapper.GetToken(ctx, msg.BaseAssetSymbol) if err != nil { return sdk.ErrInvalidCoins(err.Error()).Result() } diff --git a/plugins/tokens/abci.go b/plugins/tokens/abci.go index 76e789c46..13aa8f171 100644 --- a/plugins/tokens/abci.go +++ b/plugins/tokens/abci.go @@ -13,9 +13,9 @@ import ( ) func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler { - abciQueryPrefix := prefix + queryPrefix := prefix var isMini bool - switch abciQueryPrefix { + switch queryPrefix { case abciQueryPrefix: isMini = false case miniAbciQueryPrefix: @@ -25,7 +25,7 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler } return func(app types.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { // expects at least two query path segments. - if path[0] != abciQueryPrefix || len(path) < 2 { + if path[0] != queryPrefix || len(path) < 2 { return nil } switch path[1] { @@ -35,7 +35,7 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler Code: uint32(sdk.CodeUnknownRequest), Log: fmt.Sprintf( "%s %s query requires a symbol path arg", - abciQueryPrefix, path[1]), + queryPrefix, path[1]), } } ctx := app.GetContextForCheckState() @@ -53,7 +53,7 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler Code: uint32(sdk.CodeUnknownRequest), Log: fmt.Sprintf( "%s %s query requires offset and limit path segments", - abciQueryPrefix, path[1]), + queryPrefix, path[1]), } } showZeroSupplyTokens := false @@ -61,7 +61,14 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler showZeroSupplyTokens = true } ctx := app.GetContextForCheckState() - tokens := mapper.GetTokenList(ctx, showZeroSupplyTokens) + //var tokens interface{} + //if isMini{ + // tokens = mapper.GetMiniTokenList(ctx, showZeroSupplyTokens) + //}else { + // tokens = mapper.GetTokenList(ctx, showZeroSupplyTokens) + //} TODO + + tokens := mapper.GetTokenList(ctx, showZeroSupplyTokens, isMini) offset, err := strconv.Atoi(path[2]) if err != nil || offset < 0 || offset >= len(tokens) { return &abci.ResponseQuery{ @@ -104,7 +111,7 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler Code: uint32(sdk.ABCICodeOK), Info: fmt.Sprintf( "Unknown `%s` query path: %v", - abciQueryPrefix, path), + queryPrefix, path), } } } @@ -115,25 +122,14 @@ func queryAndMarshallToken(app types.ChainApp, mapper Mapper, ctx sdk.Context, s var err error var token interface{} - token, err = getToken(mapper, ctx, symbol, isMini) + token, err = mapper.GetToken(ctx, symbol) if err != nil { return &abci.ResponseQuery{ Code: uint32(sdk.CodeInternal), Log: err.Error(), } } - switch token.(type) { - case types.MiniToken: - bz, err = app.GetCodec().MarshalBinaryLengthPrefixed(token.(types.MiniToken)) - case types.Token: - bz, err = app.GetCodec().MarshalBinaryLengthPrefixed(token.(types.Token)) - default: - return &abci.ResponseQuery{ - Code: uint32(sdk.CodeInternal), - Log: err.Error(), - } - } - + bz, err = app.GetCodec().MarshalBinaryLengthPrefixed(token) if err != nil { return &abci.ResponseQuery{ Code: uint32(sdk.CodeInternal), @@ -145,11 +141,3 @@ func queryAndMarshallToken(app types.ChainApp, mapper Mapper, ctx sdk.Context, s Value: bz, } } - -func getToken(mapper Mapper, ctx sdk.Context, symbol string, isMini bool) (interface{}, error) { - if isMini { - return mapper.GetMiniToken(ctx, symbol) - } else { - return mapper.GetToken(ctx, symbol) - } -} diff --git a/plugins/tokens/abci_test.go b/plugins/tokens/abci_test.go index 542ab4b22..9836af255 100644 --- a/plugins/tokens/abci_test.go +++ b/plugins/tokens/abci_test.go @@ -26,8 +26,8 @@ var ( addr = sdk.AccAddress(pk.Address()) token1Ptr, _ = common.NewToken("XXX", "XXX-000", 10000000000, addr, false) token2Ptr, _ = common.NewToken("XXY", "XXY-000", 10000000000, addr, false) - token1 = *token1Ptr - token2 = *token2Ptr + token1 = token1Ptr + token2 = token2Ptr ) func Test_Tokens_ABCI_GetInfo_Success(t *testing.T) { @@ -107,14 +107,14 @@ func Test_Tokens_ABCI_GetTokens_Success(t *testing.T) { res := app.Query(query) cdc := app.GetCodec() - actual := make([]common.Token, 2) + actual := make([]common.IToken, 2) err = cdc.UnmarshalBinaryLengthPrefixed(res.Value, &actual) if err != nil { t.Fatal(err.Error()) } assert.True(t, sdk.ABCICodeType(res.Code).IsOK()) - assert.Equal(t, []common.Token{ + assert.Equal(t, []common.IToken{ token1, token2, }, actual) } @@ -146,7 +146,7 @@ func Test_Tokens_ABCI_GetTokens_Success_WithOffset(t *testing.T) { } assert.True(t, sdk.ABCICodeType(res.Code).IsOK()) - assert.Equal(t, []common.Token{ + assert.Equal(t, []common.IToken{ token2, }, actual) } @@ -178,7 +178,7 @@ func Test_Tokens_ABCI_GetTokens_Success_WithLimit(t *testing.T) { } assert.True(t, sdk.ABCICodeType(res.Code).IsOK()) - assert.Equal(t, []common.Token{ + assert.Equal(t, []common.IToken{ token1, }, actual) } diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index cec23c9e4..eb1762b8a 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -39,18 +39,18 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep } if !token.IsOwner(msg.From) { - logger.Info("burn token failed", "reason", "not token's owner", "from", msg.From, "owner", token.Owner) + logger.Info("burn token failed", "reason", "not token's owner", "from", msg.From, "owner", token.GetOwner()) return sdk.ErrUnauthorized("only the owner of the token can burn the token").Result() } - coins := keeper.GetCoins(ctx, token.Owner) + coins := keeper.GetCoins(ctx, token.GetOwner()) if coins.AmountOf(symbol) < burnAmount || - token.TotalSupply.ToInt64() < burnAmount { + token.GetTotalSupply().ToInt64() < burnAmount { logger.Info("burn token failed", "reason", "no enough tokens to burn") return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() } - _, _, sdkError := keeper.SubtractCoins(ctx, token.Owner, sdk.Coins{{ + _, _, sdkError := keeper.SubtractCoins(ctx, token.GetOwner(), sdk.Coins{{ Denom: symbol, Amount: burnAmount, }}) @@ -59,7 +59,7 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep return sdkError.Result() } - newTotalSupply := token.TotalSupply.ToInt64() - burnAmount + newTotalSupply := token.GetTotalSupply().ToInt64() - burnAmount err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) if err != nil { logger.Error("burn token failed", "reason", "update total supply failed: "+err.Error()) @@ -74,7 +74,7 @@ func handleBurnMiniToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank. logger := log.With("module", "mini-token", "symbol", msg.Symbol, "amount", msg.Amount) burnAmount := msg.Amount symbol := strings.ToUpper(msg.Symbol) - token, err := tokenMapper.GetMiniToken(ctx, symbol) + token, err := tokenMapper.GetToken(ctx, symbol) errLogMsg := "burn token failed" if err != nil { logger.Info("burn token failed", "reason", "invalid token symbol") @@ -82,11 +82,11 @@ func handleBurnMiniToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank. } if !token.IsOwner(msg.From) { - logger.Info("burn token failed", "reason", "not token's owner", "from", msg.From, "owner", token.Owner) + logger.Info("burn token failed", "reason", "not token's owner", "from", msg.From, "owner", token.GetOwner()) return sdk.ErrUnauthorized("only the owner of the token can burn the token").Result() } - coins := keeper.GetCoins(ctx, token.Owner) + coins := keeper.GetCoins(ctx, token.GetOwner()) useAllBalance := coins.AmountOf(symbol) == burnAmount @@ -97,12 +97,12 @@ func handleBurnMiniToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank. } if coins.AmountOf(symbol) < burnAmount || - token.TotalSupply.ToInt64() < burnAmount { + token.GetTotalSupply().ToInt64() < burnAmount { logger.Info("burn token failed", "reason", "no enough tokens to burn") return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() } - _, _, sdkError := keeper.SubtractCoins(ctx, token.Owner, sdk.Coins{{ + _, _, sdkError := keeper.SubtractCoins(ctx, token.GetOwner(), sdk.Coins{{ Denom: symbol, Amount: burnAmount, }}) @@ -111,7 +111,7 @@ func handleBurnMiniToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank. return sdkError.Result() } - newTotalSupply := token.TotalSupply.ToInt64() - burnAmount + newTotalSupply := token.GetTotalSupply().ToInt64() - burnAmount err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) if err != nil { logger.Error("burn token failed", "reason", "update total supply failed: "+err.Error()) diff --git a/plugins/tokens/client/cli/issue_mini.go b/plugins/tokens/client/cli/issue_mini.go index 6f0ffd07c..76af0479c 100644 --- a/plugins/tokens/client/cli/issue_mini.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -20,7 +20,7 @@ func issueMiniTokenCmd(cmdr Commander) *cobra.Command { cmd := &cobra.Command{ Use: "issue", Short: "issue a new mini-token", - RunE: cmdr.issueToken, + RunE: cmdr.issueMiniToken, } cmd.Flags().String(flagTokenName, "", "name of the new token") diff --git a/plugins/tokens/client/rest/gettokens.go b/plugins/tokens/client/rest/gettokens.go index 1d33b4a66..df0aef894 100644 --- a/plugins/tokens/client/rest/gettokens.go +++ b/plugins/tokens/client/rest/gettokens.go @@ -28,21 +28,13 @@ func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit in if err != nil { return nil, err } - if isMini { - tokens := make([]types.MiniToken, 0) - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) - if err != nil { - fmt.Println(err) - } - return tokens, nil - } else { - tokens := make([]types.Token, 0) - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) - if err != nil { - fmt.Println(err) - } - return tokens, nil + + tokens := make([]types.IToken, 0) + err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) + if err != nil { + fmt.Println(err) } + return tokens, nil } diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 5aecd3b00..91c7dfc4b 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -90,7 +90,7 @@ func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper store.Mapper, accKee symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) errLogMsg := "freeze token failed" - _, err := miniTokenMapper.GetMiniToken(ctx, symbol) + _, err := miniTokenMapper.GetToken(ctx, symbol) if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() @@ -129,7 +129,7 @@ func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper store.Mapper, accK useAllFrozenBalance := frozenAmount == unfreezeAmount errLogMsg := "unfreeze token failed" - _, err := miniTokenMapper.GetMiniToken(ctx, symbol) + _, err := miniTokenMapper.GetToken(ctx, symbol) if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() diff --git a/plugins/tokens/genesis.go b/plugins/tokens/genesis.go index 0e7524326..473821e89 100644 --- a/plugins/tokens/genesis.go +++ b/plugins/tokens/genesis.go @@ -44,7 +44,7 @@ func InitGenesis(ctx sdk.Context, tokenMapper store.Mapper, coinKeeper bank.Keep if err != nil { panic(err) } - err = tokenMapper.NewToken(ctx, *token) + err = tokenMapper.NewToken(ctx, token) if err != nil { panic(err) } diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 291039f69..d2c749e43 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -76,7 +76,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank return sdk.ErrInternal(fmt.Sprintf("unable to create token struct: %s", err.Error())).Result() } - if err := tokenMapper.NewToken(ctx, *token); err != nil { + if err := tokenMapper.NewToken(ctx, token); err != nil { logger.Error(errLogMsg, "reason", "add token failed: "+err.Error()) return sdk.ErrInvalidCoins(err.Error()).Result() } @@ -115,7 +115,7 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() } - if !token.Mintable { + if !token.IsMintable() { logger.Info(errLogMsg, "reason", "token cannot be minted") return sdk.ErrInvalidCoins(fmt.Sprintf("token(%s) cannot be minted", msg.Symbol)).Result() } @@ -126,21 +126,21 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. } // use minus to prevent overflow - if msg.Amount > common.TokenMaxTotalSupply-token.TotalSupply.ToInt64() { + if msg.Amount > common.TokenMaxTotalSupply-token.GetTotalSupply().ToInt64() { logger.Info(errLogMsg, "reason", "exceed the max total supply") return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %ds", common.TokenMaxTotalSupply)).Result() } - newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount + newTotalSupply := token.GetTotalSupply().ToInt64() + msg.Amount err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) if err != nil { logger.Error(errLogMsg, "reason", "update total supply failed: "+err.Error()) return sdk.ErrInternal(fmt.Sprintf("update total supply failed")).Result() } - _, _, sdkError := bankKeeper.AddCoins(ctx, token.Owner, + _, _, sdkError := bankKeeper.AddCoins(ctx, token.GetOwner(), sdk.Coins{{ - Denom: token.Symbol, + Denom: token.GetSymbol(), Amount: msg.Amount, }}) if sdkError != nil { @@ -161,13 +161,15 @@ func handleMintMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper b return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")).Result() } errLogMsg := "mint token failed" - token, err := tokenMapper.GetMiniToken(ctx, symbol) + + iToken, err := tokenMapper.GetToken(ctx, symbol) + token := iToken.(*types.MiniToken) //todo if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() } - if !token.Mintable { + if !token.IsMintable() { logger.Info(errLogMsg, "reason", "token cannot be minted") return sdk.ErrInvalidCoins(fmt.Sprintf("token(%s) cannot be minted", msg.Symbol)).Result() } diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 1b022fd0d..16f1d30ae 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -17,27 +17,25 @@ import ( "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" - miniTkstore "github.com/binance-chain/node/plugins/minitokens/store" miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) -func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper, miniTkstore.MiniTokenMapper) { - ms, capKey1, capKey2, capKey3 := testutils.SetupThreeMultiStoreForUnitTest() +func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { + ms, capKey1, capKey2, _ := testutils.SetupThreeMultiStoreForUnitTest() cdc := wire.NewCodec() tokenMapper := store.NewMapper(cdc, capKey1) accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) - miniTokenMapper := miniTkstore.NewMiniTokenMapper(cdc, capKey3) bankKeeper := bank.NewBaseKeeper(accountKeeper) - handler := NewHandler(tokenMapper, miniTokenMapper, bankKeeper) - miniTokenHandler := miniIssue.NewHandler(miniTokenMapper, bankKeeper) + handler := NewHandler(tokenMapper, bankKeeper) + miniTokenHandler := miniIssue.NewHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, sdk.RunTxModeDeliver, log.NewNopLogger()). WithAccountCache(auth.NewAccountCache(accountStoreCache)) - return ctx, handler, miniTokenHandler, accountKeeper, tokenMapper, miniTokenMapper + return ctx, handler, miniTokenHandler, accountKeeper, tokenMapper } func setChainVersion() { @@ -49,7 +47,7 @@ func resetChainVersion() { } func TestHandleIssueToken(t *testing.T) { - ctx, handler, _, accountKeeper, tokenMapper, _ := setup() + ctx, handler, _, accountKeeper, tokenMapper:= setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") @@ -66,7 +64,7 @@ func TestHandleIssueToken(t *testing.T) { } func TestHandleMintToken(t *testing.T) { - ctx, handler, _, accountKeeper, tokenMapper, _ := setup() + ctx, handler, _, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000", 10000e8) sdkResult := handler(ctx, mintMsg) @@ -112,7 +110,7 @@ func TestHandleMintToken(t *testing.T) { func TestHandleMintMiniToken(t *testing.T) { setChainVersion() defer resetChainVersion() - ctx, handler, miniTokenHandler, accountKeeper, tokenMapper, miniTokenMapper := setup() + ctx, handler, miniTokenHandler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1001e8) sdkResult := handler(ctx, mintMsg) @@ -124,10 +122,10 @@ func TestHandleMintMiniToken(t *testing.T) { require.Equal(t, true, sdkResult.Code.IsOK()) sdkResult = handler(ctx, mintMsg) - token, err := miniTokenMapper.GetToken(ctx, "NNB-000M") + token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 9000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, token) + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) _, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NotNil(t, err) @@ -140,9 +138,9 @@ func TestHandleMintMiniToken(t *testing.T) { validMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1000e8) sdkResult = handler(ctx, validMintMsg) require.Equal(t, true, sdkResult.Code.IsOK()) - token, err = miniTokenMapper.GetToken(ctx, "NNB-000M") + token, err = tokenMapper.GetToken(ctx, "NNB-000M") expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, token) + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) invalidMintMsg := NewMintMsg(acc2.GetAddress(), "NNB-000M", 100e8) diff --git a/plugins/tokens/issue_mini/handler.go b/plugins/tokens/issue_mini/handler.go index f3cac7c27..ebe09d8bd 100644 --- a/plugins/tokens/issue_mini/handler.go +++ b/plugins/tokens/issue_mini/handler.go @@ -86,7 +86,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank return sdk.ErrInternal(fmt.Sprintf("unable to create token struct: %s", err.Error())).Result() } - if err := tokenMapper.NewMiniToken(ctx, *token); err != nil { + if err := tokenMapper.NewToken(ctx, token); err != nil { logger.Error(errLogMsg, "reason", "add token failed: "+err.Error()) return sdk.ErrInvalidCoins(err.Error()).Result() } diff --git a/plugins/tokens/seturi_mini/handler.go b/plugins/tokens/seturi_mini/handler.go index 5730628c3..4dbb996a2 100644 --- a/plugins/tokens/seturi_mini/handler.go +++ b/plugins/tokens/seturi_mini/handler.go @@ -29,7 +29,7 @@ func handleSetURI(ctx sdk.Context, tokenMapper store.Mapper, msg SetURIMsg) sdk. logger := log.With("module", "mini-token", "symbol", symbol, "tokenURI", msg.TokenURI, "from", msg.From) errLogMsg := "set token URI failed" - token, err := tokenMapper.GetMiniToken(ctx, symbol) + token, err := tokenMapper.GetToken(ctx, symbol) if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() diff --git a/plugins/tokens/store/mapper.go b/plugins/tokens/store/mapper.go index 32b024ad7..9fdbab622 100644 --- a/plugins/tokens/store/mapper.go +++ b/plugins/tokens/store/mapper.go @@ -17,8 +17,9 @@ import ( type Tokens []types.Token type MiniTokens []types.MiniToken +type ITokens []types.IToken -const miniTokenKeyPrefix = "mini" +const miniTokenKeyPrefix = "mini:" func (t Tokens) GetSymbols() *[]string { var symbols []string @@ -29,16 +30,13 @@ func (t Tokens) GetSymbols() *[]string { } type Mapper interface { - NewToken(ctx sdk.Context, token types.Token) error + NewToken(ctx sdk.Context, token types.IToken) error Exists(ctx sdk.Context, symbol string) bool ExistsCC(ctx context.CLIContext, symbol string) bool - GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool) Tokens - GetToken(ctx sdk.Context, symbol string) (types.Token, error) + GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool, isMini bool) ITokens + GetToken(ctx sdk.Context, symbol string) (types.IToken, error) // we do not provide the updateToken method UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) error - NewMiniToken(ctx sdk.Context, token types.MiniToken) error - GetMiniTokenList(ctx sdk.Context, showZeroSupplyMiniTokens bool) MiniTokens - GetMiniToken(ctx sdk.Context, symbol string) (types.MiniToken, error) UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) error } @@ -56,49 +54,47 @@ func NewMapper(cdc *wire.Codec, key sdk.StoreKey) mapper { } } -func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.Token, error) { - if strings.HasPrefix(symbol, miniTokenKeyPrefix) { - //Mini token is not allowed to query by this method - return types.Token{}, fmt.Errorf("token(%v) not found", symbol) - } +func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.IToken, error) { store := ctx.KVStore(m.key) - key := []byte(strings.ToUpper(symbol)) + var key []byte + if types.IsMiniTokenSymbol(symbol) { + key = m.calcMiniTokenKey(strings.ToUpper(symbol)) + } else { + key = []byte(strings.ToUpper(symbol)) + } bz := store.Get(key) if bz != nil { - return m.decodeToken(bz), nil + return m.decodeIToken(bz), nil } - return types.Token{}, fmt.Errorf("token(%v) not found", symbol) + return nil, fmt.Errorf("token(%v) not found", symbol) } -func (m mapper) GetTokenCC(ctx context.CLIContext, symbol string) (types.Token, error) { - if strings.HasPrefix(symbol, miniTokenKeyPrefix) { - //Mini token is not allowed to query by this method - return types.Token{}, fmt.Errorf("token(%v) not found", symbol) - } +func (m mapper) GetTokenCC(ctx context.CLIContext, symbol string) (types.IToken, error) { key := []byte(strings.ToUpper(symbol)) bz, err := ctx.QueryStore(key, common.TokenStoreName) if err != nil { - return types.Token{}, err + return nil, err } if bz != nil { - return m.decodeToken(bz), nil + return m.decodeIToken(bz), nil } - return types.Token{}, fmt.Errorf("token(%v) not found", symbol) + return nil, fmt.Errorf("token(%v) not found", symbol) } -func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool) Tokens { - var res Tokens +func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool, isMini bool) ITokens { + var res ITokens store := ctx.KVStore(m.key) iter := store.Iterator(nil, nil) defer iter.Close() for ; iter.Valid(); iter.Next() { - if bytes.HasPrefix(iter.Key(), []byte(miniTokenKeyPrefix)) { + isValid := isMini == bytes.HasPrefix(iter.Key(), []byte(miniTokenKeyPrefix)) + if !isValid { continue } - token := m.decodeToken(iter.Value()) - if !showZeroSupplyTokens && token.TotalSupply.ToInt64() == 0 { + token := m.decodeIToken(iter.Value()) + if !showZeroSupplyTokens && token.GetTotalSupply().ToInt64() == 0 { continue } res = append(res, token) @@ -111,7 +107,7 @@ func (m mapper) Exists(ctx sdk.Context, symbol string) bool { var key []byte if types.IsMiniTokenSymbol(symbol) { key = m.calcMiniTokenKey(strings.ToUpper(symbol)) - }else{ + } else { key = []byte(strings.ToUpper(symbol)) } return store.Has(key) @@ -121,7 +117,7 @@ func (m mapper) ExistsCC(ctx context.CLIContext, symbol string) bool { var key []byte if types.IsMiniTokenSymbol(symbol) { key = m.calcMiniTokenKey(strings.ToUpper(symbol)) - }else{ + } else { key = []byte(strings.ToUpper(symbol)) } bz, err := ctx.QueryStore(key, common.TokenStoreName) @@ -134,15 +130,23 @@ func (m mapper) ExistsCC(ctx context.CLIContext, symbol string) bool { return false } -func (m mapper) NewToken(ctx sdk.Context, token types.Token) error { - symbol := token.Symbol - if err := types.ValidateToken(token); err != nil { - return err +func (m mapper) NewToken(ctx sdk.Context, token types.IToken) error { + symbol := token.GetSymbol() + var key []byte + if types.IsMiniTokenSymbol(symbol) { + if err := types.ValidateMiniToken(token); err != nil { + return err + } + key = m.calcMiniTokenKey(strings.ToUpper(symbol)) + } else { + if err := types.ValidateToken(token); err != nil { + return err + } + key = []byte(strings.ToUpper(symbol)) } - key := []byte(strings.ToUpper(symbol)) store := ctx.KVStore(m.key) - value := m.encodeToken(token) + value := m.encodeIToken(token) store.Set(key, value) return nil } @@ -152,10 +156,6 @@ func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) return errors.New("symbol cannot be empty") } - if types.IsMiniTokenSymbol(symbol) { - return m.updateMiniTotalSupply(ctx, symbol, supply) - } - key := []byte(strings.ToUpper(symbol)) store := ctx.KVStore(m.key) bz := store.Get(key) @@ -163,16 +163,16 @@ func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) return errors.New("token does not exist") } - toBeUpdated := m.decodeToken(bz) + toBeUpdated := m.decodeIToken(bz) - if toBeUpdated.TotalSupply.ToInt64() != supply { - toBeUpdated.TotalSupply = utils.Fixed8(supply) - store.Set(key, m.encodeToken(toBeUpdated)) + if toBeUpdated.GetTotalSupply().ToInt64() != supply { + toBeUpdated.SetTotalSupply(utils.Fixed8(supply)) + store.Set(key, m.encodeIToken(toBeUpdated)) } return nil } -func (m mapper) encodeToken(token types.Token) []byte { +func (m mapper) encodeIToken(token types.IToken) []byte { bz, err := m.cdc.MarshalBinaryBare(token) if err != nil { panic(err) @@ -180,10 +180,11 @@ func (m mapper) encodeToken(token types.Token) []byte { return bz } -func (m mapper) decodeToken(bz []byte) (token types.Token) { +func (m mapper) decodeIToken(bz []byte) types.IToken { + var token types.IToken err := m.cdc.UnmarshalBinaryBare(bz, &token) if err != nil { panic(err) } - return + return token } diff --git a/plugins/tokens/store/mapper_mini.go b/plugins/tokens/store/mapper_mini.go index 74291285d..83c367fbf 100644 --- a/plugins/tokens/store/mapper_mini.go +++ b/plugins/tokens/store/mapper_mini.go @@ -3,72 +3,13 @@ package store import ( "bytes" "errors" - "fmt" "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/utils" ) -func (m mapper) GetMiniToken(ctx sdk.Context, symbol string) (types.MiniToken, error) { - store := ctx.KVStore(m.key) - key := m.calcMiniTokenKey(strings.ToUpper(symbol)) - - bz := store.Get(key) - if bz != nil { - return m.decodeMiniToken(bz), nil - } - - return types.MiniToken{}, fmt.Errorf("mini-token(%v) not found", symbol) -} -func (m mapper) GetMiniTokenList(ctx sdk.Context, showZeroSupplyMiniTokens bool) MiniTokens { - var res MiniTokens - store := ctx.KVStore(m.key) - iter := store.Iterator(nil, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - if !bytes.HasPrefix(iter.Key(), []byte(miniTokenKeyPrefix)) { - continue - } - token := m.decodeMiniToken(iter.Value()) - if !showZeroSupplyMiniTokens && token.TotalSupply.ToInt64() == 0 { - continue - } - res = append(res, token) - } - return res -} - -func (m mapper) NewMiniToken(ctx sdk.Context, token types.MiniToken) error { - symbol := token.Symbol - if err := types.ValidateMiniToken(token); err != nil { - return err - } - key := m.calcMiniTokenKey(strings.ToUpper(symbol)) - store := ctx.KVStore(m.key) - value := m.encodeMiniToken(token) - store.Set(key, value) - return nil -} - -func (m mapper) updateMiniTotalSupply(ctx sdk.Context, symbol string, supply int64) error { - key := []byte(strings.ToUpper(symbol)) - store := ctx.KVStore(m.key) - bz := store.Get(key) - if bz == nil { - return errors.New("mini token does not exist") - } - - toBeUpdated := m.decodeMiniToken(bz) - - if toBeUpdated.TotalSupply.ToInt64() != supply { - toBeUpdated.TotalSupply = utils.Fixed8(supply) - store.Set(key, m.encodeMiniToken(toBeUpdated)) - } - return nil -} func (m mapper) UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) error { if len(symbol) == 0 { @@ -90,35 +31,23 @@ func (m mapper) UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) e return errors.New("token does not exist") } - toBeUpdated := m.decodeMiniToken(bz) + decodedToken := m.decodeIToken(bz) + + toBeUpdated, ok := decodedToken.(*types.MiniToken) + if !ok { + return errors.New("token cannot be converted to MiniToken") + } if toBeUpdated.TokenURI != uri { toBeUpdated.TokenURI = uri - store.Set(key, m.encodeMiniToken(toBeUpdated)) + store.Set(key, m.encodeIToken(toBeUpdated)) } return nil } -func (m mapper) encodeMiniToken(token types.MiniToken) []byte { - bz, err := m.cdc.MarshalBinaryBare(token) - if err != nil { - panic(err) - } - return bz -} - -func (m mapper) decodeMiniToken(bz []byte) (token types.MiniToken) { - err := m.cdc.UnmarshalBinaryBare(bz, &token) - if err != nil { - panic(err) - } - return -} - func (m mapper) calcMiniTokenKey(symbol string) []byte { var buf bytes.Buffer buf.WriteString(miniTokenKeyPrefix) - buf.WriteString(":") buf.WriteString(symbol) return buf.Bytes() } From 69549eb54f88d7b3c4e25813e6dac178bd3951af Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 13 May 2020 20:39:16 +0800 Subject: [PATCH 41/96] fix ut --- cmd/dexperf/main.go | 2 -- plugins/tokens/abci_test.go | 6 +++--- plugins/tokens/issue/handler.go | 5 +++-- plugins/tokens/issue/handler_test.go | 11 +++++++---- plugins/tokens/issue_mini/handler_test.go | 13 ++++++++----- plugins/tokens/store/mapper.go | 8 ++++++-- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/cmd/dexperf/main.go b/cmd/dexperf/main.go index 0fec019a8..459e0abb0 100644 --- a/cmd/dexperf/main.go +++ b/cmd/dexperf/main.go @@ -37,7 +37,6 @@ import ( "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/dex" "github.com/binance-chain/node/plugins/dex/order" - "github.com/binance-chain/node/plugins/minitokens" "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/wire" ) @@ -545,7 +544,6 @@ func MakeCodec() *wire.Codec { tokens.RegisterWire(cdc) types.RegisterWire(cdc) tx.RegisterWire(cdc) - minitokens.RegisterWire(cdc) return cdc } diff --git a/plugins/tokens/abci_test.go b/plugins/tokens/abci_test.go index 9836af255..4eec1132a 100644 --- a/plugins/tokens/abci_test.go +++ b/plugins/tokens/abci_test.go @@ -53,7 +53,7 @@ func Test_Tokens_ABCI_GetInfo_Success(t *testing.T) { } assert.True(t, sdk.ABCICodeType(res.Code).IsOK()) - assert.Equal(t, token1, actual) + assert.Equal(t, *token1, actual) } func Test_Tokens_ABCI_GetInfo_Error_NotFound(t *testing.T) { @@ -139,7 +139,7 @@ func Test_Tokens_ABCI_GetTokens_Success_WithOffset(t *testing.T) { res := app.Query(query) cdc := app.GetCodec() - actual := make([]common.Token, 1) + actual := make([]common.IToken, 1) err = cdc.UnmarshalBinaryLengthPrefixed(res.Value, &actual) if err != nil { t.Fatal(err.Error()) @@ -171,7 +171,7 @@ func Test_Tokens_ABCI_GetTokens_Success_WithLimit(t *testing.T) { res := app.Query(query) cdc := app.GetCodec() - actual := make([]common.Token, 1) + actual := make([]common.IToken, 1) err = cdc.UnmarshalBinaryLengthPrefixed(res.Value, &actual) if err != nil { t.Fatal(err.Error()) diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index d2c749e43..522faef2c 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -163,11 +163,12 @@ func handleMintMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper b errLogMsg := "mint token failed" iToken, err := tokenMapper.GetToken(ctx, symbol) - token := iToken.(*types.MiniToken) //todo - if err != nil { + //token = iToken.(*types.MiniToken) //todo + if err != nil || iToken == nil{ logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() } + token := iToken.(*types.MiniToken) if !token.IsMintable() { logger.Info(errLogMsg, "reason", "token cannot be minted") diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 16f1d30ae..450de9d98 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -25,6 +25,9 @@ import ( func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { ms, capKey1, capKey2, _ := testutils.SetupThreeMultiStoreForUnitTest() cdc := wire.NewCodec() + cdc.RegisterInterface((*types.IToken)(nil), nil) + cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) tokenMapper := store.NewMapper(cdc, capKey1) accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(accountKeeper) @@ -57,7 +60,7 @@ func TestHandleIssueToken(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000") require.NoError(t, err) expectedToken, err := types.NewToken("New BNB", "NNB-000", 100000e8, acc.GetAddress(), false) - require.Equal(t, *expectedToken, token) + require.Equal(t, *expectedToken, *token.(*types.Token)) sdkResult = handler(ctx, msg) require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") @@ -81,7 +84,7 @@ func TestHandleMintToken(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000") require.NoError(t, err) expectedToken, err := types.NewToken("New BNB", "NNB-000", 110000e8, acc.GetAddress(), true) - require.Equal(t, *expectedToken, token) + require.Equal(t, *expectedToken, *token.(*types.Token)) invalidMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000", types.TokenMaxTotalSupply) sdkResult = handler(ctx, invalidMintMsg) @@ -127,9 +130,9 @@ func TestHandleMintMiniToken(t *testing.T) { expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 9000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) - _, err = tokenMapper.GetToken(ctx, "NNB-000M") + _, err = tokenMapper.GetToken(ctx, "NNB-000") require.NotNil(t, err) - require.Contains(t, err.Error(), "token(NNB-000M) not found") + require.Contains(t, err.Error(), "token(NNB-000) not found") sdkResult = handler(ctx, mintMsg) require.Equal(t, false, sdkResult.Code.IsOK()) diff --git a/plugins/tokens/issue_mini/handler_test.go b/plugins/tokens/issue_mini/handler_test.go index 0820272fe..a4ef4ebc0 100644 --- a/plugins/tokens/issue_mini/handler_test.go +++ b/plugins/tokens/issue_mini/handler_test.go @@ -17,14 +17,17 @@ import ( "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/minitokens/store" + "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) -func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.MiniTokenMapper) { +func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() cdc := wire.NewCodec() - tokenMapper := store.NewMiniTokenMapper(cdc, capKey1) + cdc.RegisterInterface((*types.IToken)(nil), nil) + cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) + tokenMapper := store.NewMapper(cdc, capKey1) accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, bankKeeper) @@ -65,7 +68,7 @@ func TestHandleIssueToken(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, token) + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) sdkResult = handler(ctx, msg) require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") @@ -84,5 +87,5 @@ func TestHandleIssueToken(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NBB-002M") require.NoError(t, err) expectedToken, err = types.NewMiniToken("New BB", "NBB-002M", 2, 10000e8+100, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, token) + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) } diff --git a/plugins/tokens/store/mapper.go b/plugins/tokens/store/mapper.go index 9fdbab622..e1cba8b17 100644 --- a/plugins/tokens/store/mapper.go +++ b/plugins/tokens/store/mapper.go @@ -155,8 +155,12 @@ func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) if len(symbol) == 0 { return errors.New("symbol cannot be empty") } - - key := []byte(strings.ToUpper(symbol)) + var key []byte + if types.IsMiniTokenSymbol(symbol) { + key = m.calcMiniTokenKey(strings.ToUpper(symbol)) + }else { + key = []byte(strings.ToUpper(symbol)) + } store := ctx.KVStore(m.key) bz := store.Get(key) if bz == nil { From 9d2a587306a15a155f7b9c3ed73912344af30049 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 14 May 2020 14:32:37 +0800 Subject: [PATCH 42/96] add ut --- plugins/tokens/abci.go | 8 +- plugins/tokens/burn/handler_test.go | 141 +++++++++++++++++++++ plugins/tokens/freeze/handler_test.go | 141 +++++++++++++++++++++ plugins/tokens/issue/handler.go | 2 +- plugins/tokens/issue/handler_test.go | 2 +- plugins/tokens/seturi_mini/handler_test.go | 91 +++++++++++++ plugins/tokens/store/mapper_mini.go | 2 +- 7 files changed, 377 insertions(+), 10 deletions(-) create mode 100644 plugins/tokens/burn/handler_test.go create mode 100644 plugins/tokens/freeze/handler_test.go create mode 100644 plugins/tokens/seturi_mini/handler_test.go diff --git a/plugins/tokens/abci.go b/plugins/tokens/abci.go index 13aa8f171..7f807b081 100644 --- a/plugins/tokens/abci.go +++ b/plugins/tokens/abci.go @@ -61,12 +61,6 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler showZeroSupplyTokens = true } ctx := app.GetContextForCheckState() - //var tokens interface{} - //if isMini{ - // tokens = mapper.GetMiniTokenList(ctx, showZeroSupplyTokens) - //}else { - // tokens = mapper.GetTokenList(ctx, showZeroSupplyTokens) - //} TODO tokens := mapper.GetTokenList(ctx, showZeroSupplyTokens, isMini) offset, err := strconv.Atoi(path[2]) @@ -120,7 +114,7 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler func queryAndMarshallToken(app types.ChainApp, mapper Mapper, ctx sdk.Context, symbol string, isMini bool) *abci.ResponseQuery { var bz []byte var err error - var token interface{} + var token types.IToken token, err = mapper.GetToken(ctx, symbol) if err != nil { diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go new file mode 100644 index 000000000..364f92245 --- /dev/null +++ b/plugins/tokens/burn/handler_test.go @@ -0,0 +1,141 @@ +package burn + +import ( + "github.com/binance-chain/node/plugins/tokens/issue" + "github.com/binance-chain/node/plugins/tokens/issue_mini" + "github.com/cosmos/cosmos-sdk/x/bank" + "testing" + + "github.com/binance-chain/node/common/upgrade" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/binance-chain/node/common/testutils" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/tokens/store" + "github.com/binance-chain/node/wire" +) + +func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { + ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() + cdc := wire.NewCodec() + cdc.RegisterInterface((*types.IToken)(nil), nil) + cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) + tokenMapper := store.NewMapper(cdc, capKey1) + accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) + bankKeeper := bank.NewBaseKeeper(accountKeeper) + handler := NewHandler(tokenMapper, bankKeeper) + tokenHandler := issue.NewHandler(tokenMapper, bankKeeper) + miniTokenHandler := issue_mini.NewHandler(tokenMapper, bankKeeper) + + accountStore := ms.GetKVStore(capKey2) + accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, + sdk.RunTxModeDeliver, log.NewNopLogger()). + WithAccountCache(auth.NewAccountCache(accountStoreCache)) + return ctx, handler, tokenHandler, miniTokenHandler, accountKeeper, tokenMapper +} + +func setChainVersion() { + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) +} + +func resetChainVersion() { + upgrade.Mgr.Config.HeightMap = nil +} + +func TestHandleBurnMini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + ctx, handler, _, miniIssueHandler, accountKeeper, tokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg := issue_mini.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + sdkResult := miniIssueHandler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + burnMsg := NewMsg(acc.GetAddress(), "NNB-000M", 10001e8+1) + sdkResult = handler(ctx, burnMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "do not have enough token to burn") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + burnMsg = NewMsg(acc.GetAddress(), "NNB-000M", 9999e8+1) + sdkResult = handler(ctx, burnMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "do not have enough token to burn") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + burnMsg = NewMsg(acc.GetAddress(), "NNB-000M", 9001e8) + sdkResult = handler(ctx, burnMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err = tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 999e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + burnMsg = NewMsg(acc2.GetAddress(), "NNB-000M", 1e8) + sdkResult = handler(ctx, burnMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "only the owner of the token can burn the token") +} + +func TestHandleBurn(t *testing.T) { + setChainVersion() + defer resetChainVersion() + ctx, handler, issueHandler, _, accountKeeper, tokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg := issue.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false) + sdkResult := issueHandler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + + _, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NotNil(t, err) + require.Contains(t, err.Error(), "token(NNB-000M) not found") + + token, err := tokenMapper.GetToken(ctx, "NNB-000") + require.Equal(t, true, sdkResult.Code.IsOK()) + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + burnMsg := NewMsg(acc.GetAddress(), "NNB-000", 10001e8) + sdkResult = handler(ctx, burnMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "do not have enough token to burn") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + burnMsg = NewMsg(acc.GetAddress(), "NNB-000", 9999e8+1) + sdkResult = handler(ctx, burnMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err = tokenMapper.GetToken(ctx, "NNB-000") + require.NoError(t, err) + expectedToken, err := types.NewToken("New BNB", "NNB-000", 1e8-1, acc.GetAddress(), false) + require.Equal(t, *expectedToken, *(token.(*types.Token))) + + _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + burnMsg = NewMsg(acc2.GetAddress(), "NNB-000", 1e8) + sdkResult = handler(ctx, burnMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "only the owner of the token can burn the token") +} diff --git a/plugins/tokens/freeze/handler_test.go b/plugins/tokens/freeze/handler_test.go new file mode 100644 index 000000000..d835a1819 --- /dev/null +++ b/plugins/tokens/freeze/handler_test.go @@ -0,0 +1,141 @@ +package freeze + +import ( + "github.com/binance-chain/node/plugins/tokens/issue" + "github.com/binance-chain/node/plugins/tokens/issue_mini" + "github.com/cosmos/cosmos-sdk/x/bank" + "testing" + + "github.com/binance-chain/node/common/upgrade" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/binance-chain/node/common/testutils" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/tokens/store" + "github.com/binance-chain/node/wire" +) + +func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { + ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() + cdc := wire.NewCodec() + cdc.RegisterInterface((*types.IToken)(nil), nil) + cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) + tokenMapper := store.NewMapper(cdc, capKey1) + accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) + bankKeeper := bank.NewBaseKeeper(accountKeeper) + handler := NewHandler(tokenMapper, accountKeeper, bankKeeper) + tokenHandler := issue.NewHandler(tokenMapper, bankKeeper) + miniTokenHandler := issue_mini.NewHandler(tokenMapper, bankKeeper) + + accountStore := ms.GetKVStore(capKey2) + accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, + sdk.RunTxModeDeliver, log.NewNopLogger()). + WithAccountCache(auth.NewAccountCache(accountStoreCache)) + return ctx, handler, tokenHandler, miniTokenHandler, accountKeeper, tokenMapper +} + +func setChainVersion() { + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) +} + +func resetChainVersion() { + upgrade.Mgr.Config.HeightMap = nil +} + +func TestHandleFreezeMini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + ctx, handler, _, miniIssueHandler, accountKeeper, tokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg := issue_mini.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + sdkResult := miniIssueHandler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + freezeMsg := NewFreezeMsg(acc.GetAddress(), "NNB-000M", 10001e8+1) + sdkResult = handler(ctx, freezeMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "do not have enough token to freeze") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + freezeMsg = NewFreezeMsg(acc.GetAddress(), "NNB-000M", 9999e8+1) + sdkResult = handler(ctx, freezeMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "do not have enough token to freeze") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + freezeMsg = NewFreezeMsg(acc.GetAddress(), "NNB-000M", 9001e8) + sdkResult = handler(ctx, freezeMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + //token, err = tokenMapper.GetToken(ctx, "NNB-000M") + //require.NoError(t, err) + //expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 999e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + //require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + // + //_, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) + //ctx = ctx.WithValue(baseapp.TxHashKey, "002") + //freezeMsg = NewMsg(acc2.GetAddress(), "NNB-000M", 1e8) + //sdkResult = handler(ctx, freezeMsg) + //require.Equal(t, false, sdkResult.Code.IsOK()) + //require.Contains(t, sdkResult.Log, "only the owner of the token can burn the token") +} + +func TestHandleFreeze(t *testing.T) { + setChainVersion() + defer resetChainVersion() + ctx, handler, issueHandler, _, accountKeeper, tokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg := issue.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false) + sdkResult := issueHandler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + + _, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NotNil(t, err) + require.Contains(t, err.Error(), "token(NNB-000M) not found") + + _, err = tokenMapper.GetToken(ctx, "NNB-000") + require.Equal(t, true, sdkResult.Code.IsOK()) + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + freezeMsg := NewFreezeMsg(acc.GetAddress(), "NNB-000", 10001e8) + sdkResult = handler(ctx, freezeMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "do not have enough token to freeze") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + freezeMsg = NewFreezeMsg(acc.GetAddress(), "NNB-000", 9999e8+1) + sdkResult = handler(ctx, freezeMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + //token, err = tokenMapper.GetToken(ctx, "NNB-000") + //require.NoError(t, err) + //expectedToken, err := types.NewToken("New BNB", "NNB-000", 1e8-1, acc.GetAddress(), false) + //require.Equal(t, *expectedToken, *(token.(*types.Token))) + // + //_, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) + //ctx = ctx.WithValue(baseapp.TxHashKey, "002") + //freezeMsg = NewFreezeMsg(acc2.GetAddress(), "NNB-000", 1e8) + //sdkResult = handler(ctx, freezeMsg) + //require.Equal(t, false, sdkResult.Code.IsOK()) + //require.Contains(t, sdkResult.Log, "only the owner of the token can burn the token") +} diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 522faef2c..98a9453d6 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -164,7 +164,7 @@ func handleMintMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper b iToken, err := tokenMapper.GetToken(ctx, symbol) //token = iToken.(*types.MiniToken) //todo - if err != nil || iToken == nil{ + if err != nil { logger.Info(errLogMsg, "reason", "symbol not exist") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() } diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 450de9d98..9a2a47779 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -50,7 +50,7 @@ func resetChainVersion() { } func TestHandleIssueToken(t *testing.T) { - ctx, handler, _, accountKeeper, tokenMapper:= setup() + ctx, handler, _, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") diff --git a/plugins/tokens/seturi_mini/handler_test.go b/plugins/tokens/seturi_mini/handler_test.go new file mode 100644 index 000000000..e159d00f2 --- /dev/null +++ b/plugins/tokens/seturi_mini/handler_test.go @@ -0,0 +1,91 @@ +package seturi_mini + +import ( + "github.com/binance-chain/node/plugins/tokens/issue_mini" + "github.com/cosmos/cosmos-sdk/x/bank" + "testing" + + "github.com/binance-chain/node/common/upgrade" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/binance-chain/node/common/testutils" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/tokens/store" + "github.com/binance-chain/node/wire" +) + +func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { + ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() + cdc := wire.NewCodec() + cdc.RegisterInterface((*types.IToken)(nil), nil) + cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) + tokenMapper := store.NewMapper(cdc, capKey1) + accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) + handler := NewHandler(tokenMapper) + + bankKeeper := bank.NewBaseKeeper(accountKeeper) + miniTokenHandler := issue_mini.NewHandler(tokenMapper, bankKeeper) + + accountStore := ms.GetKVStore(capKey2) + accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, + sdk.RunTxModeDeliver, log.NewNopLogger()). + WithAccountCache(auth.NewAccountCache(accountStoreCache)) + return ctx, handler, miniTokenHandler, accountKeeper, tokenMapper +} + +func setChainVersion() { + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) +} + +func resetChainVersion() { + upgrade.Mgr.Config.HeightMap = nil +} + +func TestHandleSetURI(t *testing.T) { + setChainVersion() + defer resetChainVersion() + ctx, handler, miniIssueHandler, accountKeeper, tokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg := issue_mini.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + sdkResult := miniIssueHandler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + setUriMsg := NewSetUriMsg(acc.GetAddress(), "NBB", "http://www.123.com/nnb_new.json") + sdkResult = handler(ctx, setUriMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "symbol(NBB) does not exist") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + setUriMsg = NewSetUriMsg(acc.GetAddress(), "NNB-000M", "http://www.123.com/nnb_new.json") + sdkResult = handler(ctx, setUriMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err = tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.123.com/nnb_new.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + setUriMsg = NewSetUriMsg(acc2.GetAddress(), "NNB-000M", "http://www.124.com/nnb_new.json") + sdkResult = handler(ctx, setUriMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "only the owner can mint token") +} diff --git a/plugins/tokens/store/mapper_mini.go b/plugins/tokens/store/mapper_mini.go index 83c367fbf..6a96d5d9d 100644 --- a/plugins/tokens/store/mapper_mini.go +++ b/plugins/tokens/store/mapper_mini.go @@ -24,7 +24,7 @@ func (m mapper) UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) e return errors.New("uri length cannot be larger than 2048") } - key := []byte(strings.ToUpper(symbol)) + key := m.calcMiniTokenKey(strings.ToUpper(symbol)) store := ctx.KVStore(m.key) bz := store.Get(key) if bz == nil { From cc81f5cea7500e3889e30febb0a2ade22a456bcf Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 14 May 2020 15:42:35 +0800 Subject: [PATCH 43/96] fix ut --- plugins/tokens/burn/handler_test.go | 29 +++++- plugins/tokens/freeze/handler_test.go | 136 +++++++++++++++++++------- plugins/tokens/issue/handler_test.go | 3 +- 3 files changed, 129 insertions(+), 39 deletions(-) diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go index 364f92245..2fe4feffb 100644 --- a/plugins/tokens/burn/handler_test.go +++ b/plugins/tokens/burn/handler_test.go @@ -29,7 +29,7 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKe cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) tokenMapper := store.NewMapper(cdc, capKey1) - accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) + accountKeeper := auth.NewAccountKeeper(cdc, capKey2, types.ProtoAppAccount) bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, bankKeeper) tokenHandler := issue.NewHandler(tokenMapper, bankKeeper) @@ -76,17 +76,30 @@ func TestHandleBurnMini(t *testing.T) { ctx = ctx.WithValue(baseapp.TxHashKey, "002") burnMsg = NewMsg(acc.GetAddress(), "NNB-000M", 9999e8+1) sdkResult = handler(ctx, burnMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err = tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 1e8 -1, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount := account.GetCoins().AmountOf("NNB-000M") + require.Equal(t, int64(1e8-1), amount) + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + burnMsg = NewMsg(acc.GetAddress(), "NNB-000M", 1e8-2) + sdkResult = handler(ctx, burnMsg) require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "do not have enough token to burn") ctx = ctx.WithValue(baseapp.TxHashKey, "002") - burnMsg = NewMsg(acc.GetAddress(), "NNB-000M", 9001e8) + burnMsg = NewMsg(acc.GetAddress(), "NNB-000M", 1e8-1) sdkResult = handler(ctx, burnMsg) require.Equal(t, true, sdkResult.Code.IsOK()) token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 999e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 0, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) @@ -95,6 +108,10 @@ func TestHandleBurnMini(t *testing.T) { sdkResult = handler(ctx, burnMsg) require.Equal(t, false, sdkResult.Code.IsOK()) require.Contains(t, sdkResult.Log, "only the owner of the token can burn the token") + + account = accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount = account.GetCoins().AmountOf("NNB-000M") + require.Equal(t, int64(0), amount) } func TestHandleBurn(t *testing.T) { @@ -132,6 +149,10 @@ func TestHandleBurn(t *testing.T) { expectedToken, err := types.NewToken("New BNB", "NNB-000", 1e8-1, acc.GetAddress(), false) require.Equal(t, *expectedToken, *(token.(*types.Token))) + account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount := account.GetCoins().AmountOf("NNB-000") + require.Equal(t, int64(1e8-1), amount) + _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "002") burnMsg = NewMsg(acc2.GetAddress(), "NNB-000", 1e8) diff --git a/plugins/tokens/freeze/handler_test.go b/plugins/tokens/freeze/handler_test.go index d835a1819..b4c8b86a3 100644 --- a/plugins/tokens/freeze/handler_test.go +++ b/plugins/tokens/freeze/handler_test.go @@ -1,23 +1,23 @@ package freeze import ( - "github.com/binance-chain/node/plugins/tokens/issue" - "github.com/binance-chain/node/plugins/tokens/issue_mini" - "github.com/cosmos/cosmos-sdk/x/bank" "testing" - "github.com/binance-chain/node/common/upgrade" - "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/plugins/tokens/issue" + "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) @@ -29,7 +29,8 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKe cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) tokenMapper := store.NewMapper(cdc, capKey1) - accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) + //app.AccountKeeper = auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) + accountKeeper := auth.NewAccountKeeper(cdc, capKey2, types.ProtoAppAccount) bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, accountKeeper, bankKeeper) tokenHandler := issue.NewHandler(tokenMapper, bankKeeper) @@ -67,34 +68,84 @@ func TestHandleFreezeMini(t *testing.T) { expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount := account.GetCoins().AmountOf("NNB-000M") + frozenAmount := account.GetFrozenCoins().AmountOf("NNB-000M") + require.Equal(t, int64(10000e8), amount) + require.Equal(t, int64(0), frozenAmount) + ctx = ctx.WithValue(baseapp.TxHashKey, "002") - freezeMsg := NewFreezeMsg(acc.GetAddress(), "NNB-000M", 10001e8+1) + freezeMsg := NewFreezeMsg(acc.GetAddress(), "NNB-000M", 10000e8+1) sdkResult = handler(ctx, freezeMsg) require.Equal(t, false, sdkResult.Code.IsOK()) require.Contains(t, sdkResult.Log, "do not have enough token to freeze") ctx = ctx.WithValue(baseapp.TxHashKey, "002") - freezeMsg = NewFreezeMsg(acc.GetAddress(), "NNB-000M", 9999e8+1) + freezeMsg = NewFreezeMsg(acc.GetAddress(), "NNB-000M", 1e8-1) sdkResult = handler(ctx, freezeMsg) require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "do not have enough token to freeze") + require.Contains(t, sdkResult.Log, "freeze amount is too small") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + freezeMsg = NewFreezeMsg(acc.GetAddress(), "NNB-000M", 9999e8+1) + sdkResult = handler(ctx, freezeMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + account = accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount = account.GetCoins().AmountOf("NNB-000M") + frozenAmount = account.GetFrozenCoins().AmountOf("NNB-000M") + require.Equal(t, int64(1e8-1), amount) + require.Equal(t, int64(9999e8+1), frozenAmount) ctx = ctx.WithValue(baseapp.TxHashKey, "002") - freezeMsg = NewFreezeMsg(acc.GetAddress(), "NNB-000M", 9001e8) + freezeMsg = NewFreezeMsg(acc.GetAddress(), "NNB-000M", 1e8-1) sdkResult = handler(ctx, freezeMsg) require.Equal(t, true, sdkResult.Code.IsOK()) - //token, err = tokenMapper.GetToken(ctx, "NNB-000M") - //require.NoError(t, err) - //expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 999e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - //require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) - // - //_, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) - //ctx = ctx.WithValue(baseapp.TxHashKey, "002") - //freezeMsg = NewMsg(acc2.GetAddress(), "NNB-000M", 1e8) - //sdkResult = handler(ctx, freezeMsg) - //require.Equal(t, false, sdkResult.Code.IsOK()) - //require.Contains(t, sdkResult.Log, "only the owner of the token can burn the token") + account = accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount = account.GetCoins().AmountOf("NNB-000M") + frozenAmount = account.GetFrozenCoins().AmountOf("NNB-000M") + require.Equal(t, int64(0), amount) + require.Equal(t, int64(10000e8), frozenAmount) + + token, err = tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + ctx = ctx.WithValue(baseapp.TxHashKey, "003") + unfreezeMsg := NewUnfreezeMsg(acc.GetAddress(), "NNB-000M", 1e8-1) + sdkResult = handler(ctx, unfreezeMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "freeze amount is too small") + + unfreezeMsg = NewUnfreezeMsg(acc.GetAddress(), "NNB-000M", 1e8) + sdkResult = handler(ctx, unfreezeMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + account = accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount = account.GetCoins().AmountOf("NNB-000M") + frozenAmount = account.GetFrozenCoins().AmountOf("NNB-000M") + require.Equal(t, int64(1e8), amount) + require.Equal(t, int64(9999e8), frozenAmount) + + unfreezeMsg = NewUnfreezeMsg(acc.GetAddress(), "NNB-000M", 9999e8-1) + sdkResult = handler(ctx, unfreezeMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + account = accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount = account.GetCoins().AmountOf("NNB-000M") + frozenAmount = account.GetFrozenCoins().AmountOf("NNB-000M") + require.Equal(t, int64(10000e8-1), amount) + require.Equal(t, int64(1), frozenAmount) + + unfreezeMsg = NewUnfreezeMsg(acc.GetAddress(), "NNB-000M", 1) + sdkResult = handler(ctx, unfreezeMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + account = accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount = account.GetCoins().AmountOf("NNB-000M") + frozenAmount = account.GetFrozenCoins().AmountOf("NNB-000M") + require.Equal(t, int64(10000e8), amount) + require.Equal(t, int64(0), frozenAmount) + } func TestHandleFreeze(t *testing.T) { @@ -108,11 +159,16 @@ func TestHandleFreeze(t *testing.T) { sdkResult := issueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) - _, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NotNil(t, err) require.Contains(t, err.Error(), "token(NNB-000M) not found") + account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount := account.GetCoins().AmountOf("NNB-000") + frozenAmount := account.GetFrozenCoins().AmountOf("NNB-000") + require.Equal(t, int64(10000e8), amount) + require.Equal(t, int64(0), frozenAmount) + _, err = tokenMapper.GetToken(ctx, "NNB-000") require.Equal(t, true, sdkResult.Code.IsOK()) @@ -127,15 +183,29 @@ func TestHandleFreeze(t *testing.T) { sdkResult = handler(ctx, freezeMsg) require.Equal(t, true, sdkResult.Code.IsOK()) - //token, err = tokenMapper.GetToken(ctx, "NNB-000") - //require.NoError(t, err) - //expectedToken, err := types.NewToken("New BNB", "NNB-000", 1e8-1, acc.GetAddress(), false) - //require.Equal(t, *expectedToken, *(token.(*types.Token))) - // - //_, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) - //ctx = ctx.WithValue(baseapp.TxHashKey, "002") - //freezeMsg = NewFreezeMsg(acc2.GetAddress(), "NNB-000", 1e8) - //sdkResult = handler(ctx, freezeMsg) - //require.Equal(t, false, sdkResult.Code.IsOK()) - //require.Contains(t, sdkResult.Log, "only the owner of the token can burn the token") + account = accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount = account.GetCoins().AmountOf("NNB-000") + frozenAmount = account.GetFrozenCoins().AmountOf("NNB-000") + require.Equal(t, int64(1e8-1), amount) + require.Equal(t, int64(9999e8+1), frozenAmount) + + token, err := tokenMapper.GetToken(ctx, "NNB-000") + require.NoError(t, err) + expectedToken, err := types.NewToken("New BNB", "NNB-000", 10000e8, acc.GetAddress(), false) + require.Equal(t, *expectedToken, *(token.(*types.Token))) + + ctx = ctx.WithValue(baseapp.TxHashKey, "003") + unfreezeMsg := NewUnfreezeMsg(acc.GetAddress(), "NNB-000", 1) + sdkResult = handler(ctx, unfreezeMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + unfreezeMsg = NewUnfreezeMsg(acc.GetAddress(), "NNB-000", 9999e8) + sdkResult = handler(ctx, unfreezeMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + account = accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) + amount = account.GetCoins().AmountOf("NNB-000") + frozenAmount = account.GetFrozenCoins().AmountOf("NNB-000") + require.Equal(t, int64(10000e8), amount) + require.Equal(t, int64(0), frozenAmount) + } diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 9a2a47779..4ab824df9 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -3,8 +3,6 @@ package issue import ( "testing" - "github.com/binance-chain/node/common/upgrade" - "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/baseapp" @@ -17,6 +15,7 @@ import ( "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" From 6d4f740f5cfe220a6b26e82445509a84a87a1b33 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 14 May 2020 16:29:21 +0800 Subject: [PATCH 44/96] fix ut --- plugins/tokens/burn/handler.go | 64 +++---------------- plugins/tokens/burn/msg.go | 3 +- plugins/tokens/freeze/handler.go | 101 ++++++------------------------ plugins/tokens/freeze/msg.go | 3 +- plugins/tokens/issue/handler.go | 95 +++++++--------------------- plugins/tokens/issue/msg.go | 7 +-- plugins/tokens/issue_mini/msg.go | 5 ++ plugins/tokens/seturi_mini/msg.go | 4 ++ 8 files changed, 69 insertions(+), 213 deletions(-) diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index eb1762b8a..183c4efd4 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -2,6 +2,7 @@ package burn import ( "fmt" + "github.com/binance-chain/node/common/upgrade" "reflect" "strings" @@ -16,12 +17,7 @@ import ( func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { if msg, ok := msg.(BurnMsg); ok { - symbol := strings.ToUpper(msg.Symbol) - if common.IsMiniTokenSymbol(symbol) { - return handleBurnMiniToken(ctx, tokenMapper, keeper, msg) - } else { - return handleBurnToken(ctx, tokenMapper, keeper, msg) - } + return handleBurnToken(ctx, tokenMapper, keeper, msg) } errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -50,56 +46,16 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() } - _, _, sdkError := keeper.SubtractCoins(ctx, token.GetOwner(), sdk.Coins{{ - Denom: symbol, - Amount: burnAmount, - }}) - if sdkError != nil { - logger.Error("burn token failed", "reason", "subtract tokens failed: "+sdkError.Error()) - return sdkError.Result() - } + if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + coins := keeper.GetCoins(ctx, token.GetOwner()) - newTotalSupply := token.GetTotalSupply().ToInt64() - burnAmount - err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) - if err != nil { - logger.Error("burn token failed", "reason", "update total supply failed: "+err.Error()) - return sdk.ErrInternal(err.Error()).Result() - } - - logger.Info("successfully burnt token", "NewTotalSupply", newTotalSupply) - return sdk.Result{} -} + useAllBalance := coins.AmountOf(symbol) == burnAmount -func handleBurnMiniToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keeper, msg BurnMsg) sdk.Result { - logger := log.With("module", "mini-token", "symbol", msg.Symbol, "amount", msg.Amount) - burnAmount := msg.Amount - symbol := strings.ToUpper(msg.Symbol) - token, err := tokenMapper.GetToken(ctx, symbol) - errLogMsg := "burn token failed" - if err != nil { - logger.Info("burn token failed", "reason", "invalid token symbol") - return sdk.ErrInvalidCoins(err.Error()).Result() - } - - if !token.IsOwner(msg.From) { - logger.Info("burn token failed", "reason", "not token's owner", "from", msg.From, "owner", token.GetOwner()) - return sdk.ErrUnauthorized("only the owner of the token can burn the token").Result() - } - - coins := keeper.GetCoins(ctx, token.GetOwner()) - - useAllBalance := coins.AmountOf(symbol) == burnAmount - - if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { - logger.Info(errLogMsg, "reason", "burn amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("burn amount is too small, the min amount is %d or total free balance", - common.MiniTokenMinTotalSupply)).Result() - } - - if coins.AmountOf(symbol) < burnAmount || - token.GetTotalSupply().ToInt64() < burnAmount { - logger.Info("burn token failed", "reason", "no enough tokens to burn") - return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() + if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { + logger.Info("burn token failed", "reason", "burn amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("burn amount is too small, the min amount is %d or total free balance", + common.MiniTokenMinTotalSupply)).Result() + } } _, _, sdkError := keeper.SubtractCoins(ctx, token.GetOwner(), sdk.Coins{{ diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index febca9f6a..4ec4e0988 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -3,6 +3,7 @@ package burn import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" @@ -41,7 +42,7 @@ func (msg BurnMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAdd // doesn't require access to any other information. func (msg BurnMsg) ValidateBasic() sdk.Error { - if types.IsMiniTokenSymbol(msg.Symbol) { + if sdk.IsUpgrade(upgrade.BEP8) && types.IsMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 91c7dfc4b..75bca78c7 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -2,6 +2,7 @@ package freeze import ( "fmt" + "github.com/binance-chain/node/common/upgrade" "reflect" "strings" @@ -19,19 +20,9 @@ func NewHandler(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper b return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case FreezeMsg: - symbol := strings.ToUpper(msg.Symbol) - if common.IsMiniTokenSymbol(symbol) { - return handleFreezeMiniToken(ctx, tokenMapper, accKeeper, keeper, msg) - } else { - return handleFreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) - } + return handleFreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) case UnfreezeMsg: - symbol := strings.ToUpper(msg.Symbol) - if common.IsMiniTokenSymbol(symbol) { - return handleUnfreezeMiniToken(ctx, tokenMapper, accKeeper, keeper, msg) - } else { - return handleUnfreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) - } + return handleUnfreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -49,6 +40,16 @@ func handleFreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper auth return sdk.ErrInsufficientCoins("do not have enough token to freeze").Result() } + if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + useAllBalance := coins.AmountOf(symbol) == freezeAmount + + if msg.Amount <= 0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinTotalSupply)) { + logger.Info("freeze token failed", "reason", "freeze amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", + common.MiniTokenMinTotalSupply)).Result() + } + } + account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) newFrozenTokens := account.GetFrozenCoins().Plus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) newFreeTokens := account.GetCoins().Minus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) @@ -76,79 +77,17 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au return sdk.ErrInsufficientCoins("do not have enough token to unfreeze").Result() } - newFrozenTokens := account.GetFrozenCoins().Minus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) - newFreeTokens := account.GetCoins().Plus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) - account.SetFrozenCoins(newFrozenTokens) - account.SetCoins(newFreeTokens) - accKeeper.SetAccount(ctx, account) - logger.Debug("finish unfreezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) - return sdk.Result{} -} - -func handleFreezeMiniToken(ctx sdk.Context, miniTokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg FreezeMsg) sdk.Result { - freezeAmount := msg.Amount - symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "mini-token", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) - errLogMsg := "freeze token failed" - _, err := miniTokenMapper.GetToken(ctx, symbol) - if err != nil { - logger.Info(errLogMsg, "reason", "symbol not exist") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() - } - - coins := keeper.GetCoins(ctx, msg.From) - if coins.AmountOf(symbol) < freezeAmount { - logger.Info(errLogMsg, "reason", "no enough free tokens to freeze") - return sdk.ErrInsufficientCoins("do not have enough token to freeze").Result() - } - - useAllBalance := coins.AmountOf(symbol) == freezeAmount - - if msg.Amount <= 0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinTotalSupply)) { - logger.Info(errLogMsg, "reason", "freeze amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", - common.MiniTokenMinTotalSupply)).Result() - } - - account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) - newFrozenTokens := account.GetFrozenCoins().Plus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) - newFreeTokens := account.GetCoins().Minus(sdk.Coins{{Denom: symbol, Amount: freezeAmount}}) - account.SetFrozenCoins(newFrozenTokens) - account.SetCoins(newFreeTokens) - accKeeper.SetAccount(ctx, account) - logger.Info("finish freezing token", "NewFrozenToken", newFrozenTokens, "NewFreeTokens", newFreeTokens) - return sdk.Result{} -} - -func handleUnfreezeMiniToken(ctx sdk.Context, miniTokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank.Keeper, msg UnfreezeMsg) sdk.Result { - unfreezeAmount := msg.Amount - symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "mini-token", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) - account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) - frozenAmount := account.GetFrozenCoins().AmountOf(symbol) - useAllFrozenBalance := frozenAmount == unfreezeAmount - errLogMsg := "unfreeze token failed" - - _, err := miniTokenMapper.GetToken(ctx, symbol) - if err != nil { - logger.Info(errLogMsg, "reason", "symbol not exist") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() - } - - if unfreezeAmount <= 0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinTotalSupply)) { - logger.Info(errLogMsg, "reason", "unfreeze amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", - common.MiniTokenMinTotalSupply)).Result() - } - - if frozenAmount < unfreezeAmount { - logger.Info(errLogMsg, "reason", "no enough frozen tokens to unfreeze") - return sdk.ErrInsufficientCoins("do not have enough token to unfreeze").Result() + if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + useAllFrozenBalance := frozenAmount == unfreezeAmount + if unfreezeAmount <= 0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinTotalSupply)) { + logger.Info("unfreeze token failed", "reason", "unfreeze amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", + common.MiniTokenMinTotalSupply)).Result() + } } newFrozenTokens := account.GetFrozenCoins().Minus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) newFreeTokens := account.GetCoins().Plus(sdk.Coins{{Denom: symbol, Amount: unfreezeAmount}}) - account.SetFrozenCoins(newFrozenTokens) account.SetCoins(newFreeTokens) accKeeper.SetAccount(ctx, account) diff --git a/plugins/tokens/freeze/msg.go b/plugins/tokens/freeze/msg.go index e02a9d351..af5b7a396 100644 --- a/plugins/tokens/freeze/msg.go +++ b/plugins/tokens/freeze/msg.go @@ -3,6 +3,7 @@ package freeze import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" @@ -41,7 +42,7 @@ func (msg FreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccA // doesn't require access to any other information. func (msg FreezeMsg) ValidateBasic() sdk.Error { - if types.IsMiniTokenSymbol(msg.Symbol) { + if sdk.IsUpgrade(upgrade.BEP8) && types.IsMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 98a9453d6..f34008080 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -26,12 +26,8 @@ func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { case IssueMsg: return handleIssueToken(ctx, tokenMapper, keeper, msg) case MintMsg: - symbol := strings.ToUpper(msg.Symbol) - if common.IsMiniTokenSymbol(symbol) { - return handleMintMiniToken(ctx, tokenMapper, keeper, msg) - } else { - return handleMintToken(ctx, tokenMapper, keeper, msg) - } + return handleMintToken(ctx, tokenMapper, keeper, msg) + default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -104,6 +100,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank } } +//Mint MiniToken is also handled by this function func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "token", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) @@ -131,82 +128,38 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %ds", common.TokenMaxTotalSupply)).Result() } - newTotalSupply := token.GetTotalSupply().ToInt64() + msg.Amount - err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) - if err != nil { - logger.Error(errLogMsg, "reason", "update total supply failed: "+err.Error()) - return sdk.ErrInternal(fmt.Sprintf("update total supply failed")).Result() - } - - _, _, sdkError := bankKeeper.AddCoins(ctx, token.GetOwner(), - sdk.Coins{{ - Denom: token.GetSymbol(), - Amount: msg.Amount, - }}) - if sdkError != nil { - logger.Error(errLogMsg, "reason", "update balance failed: "+sdkError.Error()) - return sdkError.Result() - } - - logger.Info("finished minting token") - return sdk.Result{ - Data: []byte(strconv.FormatInt(newTotalSupply, 10)), - } -} - -func handleMintMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { - symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "token", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) - if !sdk.IsUpgrade(upgrade.BEP8) { - return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")).Result() - } - errLogMsg := "mint token failed" - - iToken, err := tokenMapper.GetToken(ctx, symbol) - //token = iToken.(*types.MiniToken) //todo - if err != nil { - logger.Info(errLogMsg, "reason", "symbol not exist") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() - } - token := iToken.(*types.MiniToken) - if !token.IsMintable() { - logger.Info(errLogMsg, "reason", "token cannot be minted") - return sdk.ErrInvalidCoins(fmt.Sprintf("token(%s) cannot be minted", msg.Symbol)).Result() - } - - if !token.IsOwner(msg.From) { - logger.Info(errLogMsg, "reason", "not the token owner") - return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() - } + if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + miniToken := token.(*types.MiniToken) + if msg.Amount < common.MiniTokenMinTotalSupply { + logger.Info(errLogMsg, "reason", "mint amount doesn't reach the min supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %d", + common.MiniTokenMinTotalSupply)).Result() + } + // use minus to prevent overflow + if msg.Amount > miniToken.TokenType.UpperBound()-miniToken.TotalSupply.ToInt64() { + logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %d", + miniToken.TokenType.UpperBound())).Result() + } - if msg.Amount < common.MiniTokenMinTotalSupply { - logger.Info(errLogMsg, "reason", "mint amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %d", - common.MiniTokenMinTotalSupply)).Result() - } - // use minus to prevent overflow - if msg.Amount > token.TokenType.UpperBound()-token.TotalSupply.ToInt64() { - logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %d", - token.TokenType.UpperBound())).Result() + if msg.Amount > common.MiniTokenSupplyUpperBound-miniToken.TotalSupply.ToInt64() { + logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply upper bound") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %d", + common.MiniTokenSupplyUpperBound)).Result() + } } - if msg.Amount > common.MiniTokenSupplyUpperBound-token.TotalSupply.ToInt64() { - logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply upper bound") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %d", - common.MiniTokenSupplyUpperBound)).Result() - } - newTotalSupply := token.TotalSupply.ToInt64() + msg.Amount + newTotalSupply := token.GetTotalSupply().ToInt64() + msg.Amount err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) if err != nil { logger.Error(errLogMsg, "reason", "update total supply failed: "+err.Error()) return sdk.ErrInternal(fmt.Sprintf("update total supply failed")).Result() } - _, _, sdkError := bankKeeper.AddCoins(ctx, token.Owner, + _, _, sdkError := bankKeeper.AddCoins(ctx, token.GetOwner(), sdk.Coins{{ - Denom: token.Symbol, + Denom: token.GetSymbol(), Amount: msg.Amount, }}) if sdkError != nil { diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index fb55a2f68..49ba2760e 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -3,6 +3,7 @@ package issue import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" @@ -93,7 +94,7 @@ func NewMintMsg(from sdk.AccAddress, symbol string, amount int64) MintMsg { func (msg MintMsg) ValidateBasic() sdk.Error { - if types.IsMiniTokenSymbol(msg.Symbol) { + if sdk.IsUpgrade(upgrade.BEP8) && types.IsMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } @@ -123,10 +124,6 @@ func (msg MintMsg) validateMiniTokenBasic() sdk.Error { return sdk.ErrInvalidAddress("sender address cannot be empty") } - if err := types.ValidateMapperMiniTokenSymbol(msg.Symbol); err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } - // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenSupplyUpperBound { return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d and %d", types.MiniTokenMinTotalSupply, types.MiniTokenSupplyUpperBound)) diff --git a/plugins/tokens/issue_mini/msg.go b/plugins/tokens/issue_mini/msg.go index 9b1a740e8..6811da2a9 100644 --- a/plugins/tokens/issue_mini/msg.go +++ b/plugins/tokens/issue_mini/msg.go @@ -3,6 +3,7 @@ package issue_mini import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" @@ -45,6 +46,10 @@ func NewIssueMsg(from sdk.AccAddress, name, symbol string, tokenType int8, suppl // ValidateBasic does a simple validation check that // doesn't require access to any other information. func (msg IssueMiniMsg) ValidateBasic() sdk.Error { + if !sdk.IsUpgrade(upgrade.BEP8){ + return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")) + } + if msg.From == nil { return sdk.ErrInvalidAddress("sender address cannot be empty") } diff --git a/plugins/tokens/seturi_mini/msg.go b/plugins/tokens/seturi_mini/msg.go index 02da0c0b5..fc092e6af 100644 --- a/plugins/tokens/seturi_mini/msg.go +++ b/plugins/tokens/seturi_mini/msg.go @@ -3,6 +3,7 @@ package seturi_mini import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" @@ -28,6 +29,9 @@ func NewSetUriMsg(from sdk.AccAddress, symbol string, tokenURI string) SetURIMsg } func (msg SetURIMsg) ValidateBasic() sdk.Error { + if !sdk.IsUpgrade(upgrade.BEP8) { + return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")) + } if msg.From == nil || len(msg.From) == 0 { return sdk.ErrInvalidAddress("sender address cannot be empty") } From 76dace59bbbae314b73f782807ca2f39f6cb11b2 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 14 May 2020 20:20:54 +0800 Subject: [PATCH 45/96] add integration test for mini --- integration_test.sh | 56 +++++++++++++++++++++ networks/demo/issue_mini.exp | 21 ++++++++ networks/demo/list_mini.exp | 19 +++++++ plugins/tokens/client/cli/commands.go | 35 +++++++------ plugins/tokens/client/cli/info.go | 13 +++-- plugins/tokens/client/cli/info_mini.go | 64 ------------------------ plugins/tokens/client/cli/issue_mini.go | 2 +- plugins/tokens/client/cli/seturi_mini.go | 3 +- plugins/tokens/seturi_mini/handler.go | 2 +- 9 files changed, 128 insertions(+), 87 deletions(-) create mode 100755 networks/demo/issue_mini.exp create mode 100755 networks/demo/list_mini.exp delete mode 100644 plugins/tokens/client/cli/info_mini.go diff --git a/integration_test.sh b/integration_test.sh index d147954a2..826109f9b 100755 --- a/integration_test.sh +++ b/integration_test.sh @@ -320,4 +320,60 @@ sleep 1s result=$(expect ./deposit.exp ${swapID} "10000:${eth_symbol}" bob ${chain_id} ${cli_home}) check_operation "Deposit to a deposited single chain atomic swap" "${result}" "ERROR" +## ROUND 5 ## + +sleep 1s +# issue token +result=$(expect ./issue_mini.exp MBC MiniBitcoin 900000000000 true alice ${chain_id} ${cli_home}) 1 sample +mbc_symbol=$(echo "${result}" | tail -n 1 | grep -o "MBC-[0-9A-Z]*M") +check_operation "Issue Mini Token" "${result}" "${chain_operation_words}" + +# send +result=$(expect ./send.exp ${cli_home} alice ${chain_id} "100000000000:${mbc_symbol}" ${bob_addr}) +check_operation "Send Token" "${result}" "${chain_operation_words}" + +sleep 1s +# multi send +echo ${bob_addr} +result=$(expect ./multi_send.exp ${cli_home} alice ${chain_id} "[{\"to\":\"${bob_addr}\",\"amount\":\"10000000000:${mbc_symbol}\"},{\"to\":\"${alice_addr}\",\"amount\":\"1000000000:${mbc_symbol}\"}]") +check_operation "Multi Send Token" "${result}" "${chain_operation_words}" + +sleep 1s +# mint token +result=$(expect ./mint.exp ${mbc_symbol} 10000000000 bob ${chain_id} ${cli_home}) +check_operation "Mint Token" "${result}" "${chain_operation_words}" + +sleep 3s +# list trading pair +result=$(expect ./list_mini.exp ${mbc_symbol} BNB 100000000 bob ${chain_id} ${cli_home} 1) +check_operation "List Trading Pair" "${result}" "${chain_operation_words}" + +sleep 1s +# place buy order +result=$(expect ./order.exp ${mbc_symbol}_BNB 1 100000000 1000000000 alice ${chain_id} gte ${cli_home}) +check_operation "Place Order" "${result}" "${chain_operation_words}" +order_id=$(echo "${result}" | tail -n 1 | grep -o "[0-9A-Z]\{4,\}-[0-9]*") # capture order id, not symbol +printf "Order ID: $order_id\n" + +sleep 2s +# cancel order +result=$(expect ./cancel.exp "${mbc_symbol}_BNB" "${order_id}" alice ${chain_id} ${cli_home}) +check_operation "Cancel Order" "${result}" "${chain_operation_words}" + +sleep 1s +# place buy order +result=$(expect ./order.exp ${mbc_symbol}_BNB 1 100000000 1000000000 alice ${chain_id} gte ${cli_home}) +check_operation "Place Order" "${result}" "${chain_operation_words}" + +echo "" +./bnbcli dex show -l ${mbc_symbol}_BNB --trust-node true + +sleep 1s +# place Sell order +result=$(expect ./order.exp ${mbc_symbol}_BNB 2 100000000 2000000000 bob ${chain_id} gte ${cli_home}) +check_operation "Place Order" "${result}" "${chain_operation_words}" + +result=$(./bnbcli dex show -l ${mbc_symbol}_BNB --trust-node true) +check_operation "Order Book" "${result}" "${order_book_words}" + exit_test 0 diff --git a/networks/demo/issue_mini.exp b/networks/demo/issue_mini.exp new file mode 100755 index 000000000..e1533efb9 --- /dev/null +++ b/networks/demo/issue_mini.exp @@ -0,0 +1,21 @@ +#!/usr/bin/expect + +set symbol [lindex $argv 0] +set token_name [lindex $argv 1] +set supply [lindex $argv 2] +set mintable [lindex $argv 3] +set from [lindex $argv 4] +set chain_id [lindex $argv 5] +set home [lindex $argv 6] +set type [lindex $argv 7] +set uri [lindex $argv 8] + +set timeout 30 + if {"${home}" == ""} { + spawn ./bnbcli token issue-mini -s $symbol --token-name $token_name -n $supply --mintable $mintable --from $from --token-uri $uri --token-type $type --chain-id $chain_id + } else { + spawn ./bnbcli token issue-mini --home $home -s $symbol --token-name $token_name -n $supply --mintable $mintable --from $from --token-uri $uri --token-type $type --chain-id $chain_id + } + expect "Password*" + send "12345678\r" +interact diff --git a/networks/demo/list_mini.exp b/networks/demo/list_mini.exp new file mode 100755 index 000000000..af41805c0 --- /dev/null +++ b/networks/demo/list_mini.exp @@ -0,0 +1,19 @@ +#!/usr/bin/expect + +set symbol [lindex $argv 0] +set quote_symbol [lindex $argv 1] +set init_price [lindex $argv 2] +set from [lindex $argv 3] +set chain_id [lindex $argv 4] +set home [lindex $argv 5] +set proposal_id [lindex $argv 6] + +set timeout 30 + if {"${home}" == ""} { + spawn ./bnbcli dex list-mini -s $symbol --quote-asset-symbol $quote_symbol --from $from --init-price $init_price --chain-id $chain_id --proposal-id $proposal_id + } else { + spawn ./bnbcli dex list-mini --home $home -s $symbol --quote-asset-symbol $quote_symbol --from $from --init-price $init_price --chain-id $chain_id --proposal-id $proposal_id + } + expect "Password*" + send "12345678\r" +interact diff --git a/plugins/tokens/client/cli/commands.go b/plugins/tokens/client/cli/commands.go index 5212f4689..f3d8aba12 100644 --- a/plugins/tokens/client/cli/commands.go +++ b/plugins/tokens/client/cli/commands.go @@ -11,7 +11,6 @@ import ( const ( flagSymbol = "symbol" flagAmount = "amount" - flagURI = "uri" ) func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { @@ -52,22 +51,28 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { client.PostCommands(MultiSendCmd(cdc))..., ) + tokenCmd.AddCommand( + client.PostCommands( + issueMiniTokenCmd(cmdr), + setTokenURICmd(cmdr))..., + ) + tokenCmd.AddCommand(client.LineBreak) cmd.AddCommand(tokenCmd) - miniTokenCmd := &cobra.Command{ - Use: "mini-token", - Short: "issue or update uri or view mini tokens", - Long: ``, - } - - miniTokenCmd.AddCommand( - client.PostCommands( - getMiniTokenInfoCmd(cmdr), - issueMiniTokenCmd(cmdr), - setTokenURICmd(cmdr))...) - - miniTokenCmd.AddCommand(client.LineBreak) - cmd.AddCommand(miniTokenCmd) + //miniTokenCmd := &cobra.Command{ + // Use: "mini-token", + // Short: "issue or update uri or view mini tokens", + // Long: ``, + //} + // + //miniTokenCmd.AddCommand( + // client.PostCommands( + // getMiniTokenInfoCmd(cmdr), + // issueMiniTokenCmd(cmdr), + // setTokenURICmd(cmdr))...) + // + //miniTokenCmd.AddCommand(client.LineBreak) + //cmd.AddCommand(miniTokenCmd) } diff --git a/plugins/tokens/client/cli/info.go b/plugins/tokens/client/cli/info.go index 625ab4395..d12536d66 100644 --- a/plugins/tokens/client/cli/info.go +++ b/plugins/tokens/client/cli/info.go @@ -18,7 +18,7 @@ import ( func getTokenInfoCmd(cmdr Commander) *cobra.Command { cmd := &cobra.Command{ Use: "info ", - Short: "Query token info", + Short: "Query token/mini-token info", RunE: cmdr.runGetToken, } @@ -34,7 +34,12 @@ func (c Commander) runGetToken(cmd *cobra.Command, args []string) error { return errors.New("you must provide the symbol") } - key := []byte(strings.ToUpper(symbol)) + var key []byte + if types.IsMiniTokenSymbol(symbol) { + key = calcMiniTokenKey(strings.ToUpper(symbol)) + }else { + key = []byte(strings.ToUpper(symbol)) + } res, err := ctx.QueryStore(key, common.TokenStoreName) if err != nil { @@ -47,14 +52,14 @@ func (c Commander) runGetToken(cmd *cobra.Command, args []string) error { } // decode the value - token := new(types.Token) + var token types.IToken err = c.Cdc.UnmarshalBinaryBare(res, &token) if err != nil { return err } // print out the toke info - output, err := wire.MarshalJSONIndent(c.Cdc, token) + output, err := wire.MarshalJSONIndent(c.Cdc, &token) if err != nil { return err } diff --git a/plugins/tokens/client/cli/info_mini.go b/plugins/tokens/client/cli/info_mini.go deleted file mode 100644 index dbba51c05..000000000 --- a/plugins/tokens/client/cli/info_mini.go +++ /dev/null @@ -1,64 +0,0 @@ -package commands - -import ( - "fmt" - "strings" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/context" - - "github.com/binance-chain/node/common" - "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/wire" -) - -func getMiniTokenInfoCmd(cmdr Commander) *cobra.Command { - cmd := &cobra.Command{ - Use: "info ", - Short: "Query mini-token info", - RunE: cmdr.runGetMiniToken, - } - - cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the mini-token") - return cmd -} - -func (c Commander) runGetMiniToken(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(c.Cdc) - - symbol := viper.GetString(flagSymbol) - if len(symbol) == 0 { - return errors.New("you must provide the symbol") - } - - key := calcMiniTokenKey(strings.ToUpper(symbol)) - - res, err := ctx.QueryStore(key, common.TokenStoreName) - if err != nil { - return err - } - - if len(res) == 0 { - fmt.Printf("No such mini-token(%v) exists\n", symbol) - return nil - } - - // decode the value - token := new(types.MiniToken) - err = c.Cdc.UnmarshalBinaryBare(res, &token) - if err != nil { - return err - } - - // print out the toke info - output, err := wire.MarshalJSONIndent(c.Cdc, token) - if err != nil { - return err - } - - fmt.Println(string(output)) - return nil -} diff --git a/plugins/tokens/client/cli/issue_mini.go b/plugins/tokens/client/cli/issue_mini.go index 76af0479c..262781919 100644 --- a/plugins/tokens/client/cli/issue_mini.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -18,7 +18,7 @@ const ( func issueMiniTokenCmd(cmdr Commander) *cobra.Command { cmd := &cobra.Command{ - Use: "issue", + Use: "issue-mini", Short: "issue a new mini-token", RunE: cmdr.issueMiniToken, } diff --git a/plugins/tokens/client/cli/seturi_mini.go b/plugins/tokens/client/cli/seturi_mini.go index 1e66f5dd0..0bed7d51f 100644 --- a/plugins/tokens/client/cli/seturi_mini.go +++ b/plugins/tokens/client/cli/seturi_mini.go @@ -10,13 +10,12 @@ import ( func setTokenURICmd(cmdr Commander) *cobra.Command { cmd := &cobra.Command{ - Use: "set-uri --symbol {symbol} --uri {token uri} --from {token issuer address}", + Use: "set-uri-mini --symbol {symbol} --uri {token uri} --from {token issuer address}", Short: "set token URI of mini-token", RunE: cmdr.setTokenURI, } cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the mini-token") - cmd.Flags().StringP(flagURI, "u", "", "a distinct uri for the mini-token") cmd.Flags().String(flagTokenUri, "", "uri of the token information") return cmd diff --git a/plugins/tokens/seturi_mini/handler.go b/plugins/tokens/seturi_mini/handler.go index 4dbb996a2..afc944dd9 100644 --- a/plugins/tokens/seturi_mini/handler.go +++ b/plugins/tokens/seturi_mini/handler.go @@ -41,7 +41,7 @@ func handleSetURI(ctx sdk.Context, tokenMapper store.Mapper, msg SetURIMsg) sdk. } if len(msg.TokenURI) < 1 { - return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not exceed %v characters", common.MaxTokenURILength)).Result() + return sdk.ErrInvalidCoins(fmt.Sprintf("token uri should not be empty")).Result() } if len(msg.TokenURI) > common.MaxTokenURILength { From b0be4a8ca4b4b91325b4520be8ce9fee114971f4 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 14 May 2020 21:25:51 +0800 Subject: [PATCH 46/96] fix integration test --- integration_test.sh | 20 +++++++++++--------- networks/demo/list_mini.exp | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/integration_test.sh b/integration_test.sh index 826109f9b..a271b100b 100755 --- a/integration_test.sh +++ b/integration_test.sh @@ -75,7 +75,6 @@ bob_addr=$(./bnbcli keys list --home ${cli_home} | grep bob | grep -o "bnb1[0-9a # wait for the chain sleep 10s - ## ROUND 1 ## # send @@ -320,16 +319,19 @@ sleep 1s result=$(expect ./deposit.exp ${swapID} "10000:${eth_symbol}" bob ${chain_id} ${cli_home}) check_operation "Deposit to a deposited single chain atomic swap" "${result}" "ERROR" + ## ROUND 5 ## sleep 1s # issue token -result=$(expect ./issue_mini.exp MBC MiniBitcoin 900000000000 true alice ${chain_id} ${cli_home}) 1 sample +result=$(expect ./issue_mini.exp MBC MiniBitcoin 900000000000 true alice ${chain_id} ${cli_home} 1 sample) mbc_symbol=$(echo "${result}" | tail -n 1 | grep -o "MBC-[0-9A-Z]*M") check_operation "Issue Mini Token" "${result}" "${chain_operation_words}" + +sleep 1s # send -result=$(expect ./send.exp ${cli_home} alice ${chain_id} "100000000000:${mbc_symbol}" ${bob_addr}) +result=$(expect ./send.exp ${cli_home} alice ${chain_id} "100000000000:${mbc_symbol}" ${bob_addr} a) check_operation "Send Token" "${result}" "${chain_operation_words}" sleep 1s @@ -340,29 +342,29 @@ check_operation "Multi Send Token" "${result}" "${chain_operation_words}" sleep 1s # mint token -result=$(expect ./mint.exp ${mbc_symbol} 10000000000 bob ${chain_id} ${cli_home}) +result=$(expect ./mint.exp ${mbc_symbol} 10000000000 alice ${chain_id} ${cli_home}) check_operation "Mint Token" "${result}" "${chain_operation_words}" sleep 3s # list trading pair -result=$(expect ./list_mini.exp ${mbc_symbol} BNB 100000000 bob ${chain_id} ${cli_home} 1) +result=$(expect ./list_mini.exp ${mbc_symbol} BNB 100000000 alice ${chain_id} ${cli_home}) check_operation "List Trading Pair" "${result}" "${chain_operation_words}" sleep 1s # place buy order -result=$(expect ./order.exp ${mbc_symbol}_BNB 1 100000000 1000000000 alice ${chain_id} gte ${cli_home}) +result=$(expect ./order.exp ${mbc_symbol}_BNB 1 100000000 1000000000 bob ${chain_id} gte ${cli_home}) check_operation "Place Order" "${result}" "${chain_operation_words}" order_id=$(echo "${result}" | tail -n 1 | grep -o "[0-9A-Z]\{4,\}-[0-9]*") # capture order id, not symbol printf "Order ID: $order_id\n" sleep 2s # cancel order -result=$(expect ./cancel.exp "${mbc_symbol}_BNB" "${order_id}" alice ${chain_id} ${cli_home}) +result=$(expect ./cancel.exp "${mbc_symbol}_BNB" "${order_id}" bob ${chain_id} ${cli_home}) check_operation "Cancel Order" "${result}" "${chain_operation_words}" sleep 1s # place buy order -result=$(expect ./order.exp ${mbc_symbol}_BNB 1 100000000 1000000000 alice ${chain_id} gte ${cli_home}) +result=$(expect ./order.exp ${mbc_symbol}_BNB 1 100000000 1000000000 bob ${chain_id} gte ${cli_home}) check_operation "Place Order" "${result}" "${chain_operation_words}" echo "" @@ -370,7 +372,7 @@ echo "" sleep 1s # place Sell order -result=$(expect ./order.exp ${mbc_symbol}_BNB 2 100000000 2000000000 bob ${chain_id} gte ${cli_home}) +result=$(expect ./order.exp ${mbc_symbol}_BNB 2 100000000 2000000000 alice ${chain_id} gte ${cli_home}) check_operation "Place Order" "${result}" "${chain_operation_words}" result=$(./bnbcli dex show -l ${mbc_symbol}_BNB --trust-node true) diff --git a/networks/demo/list_mini.exp b/networks/demo/list_mini.exp index af41805c0..58cf6f515 100755 --- a/networks/demo/list_mini.exp +++ b/networks/demo/list_mini.exp @@ -10,9 +10,9 @@ set proposal_id [lindex $argv 6] set timeout 30 if {"${home}" == ""} { - spawn ./bnbcli dex list-mini -s $symbol --quote-asset-symbol $quote_symbol --from $from --init-price $init_price --chain-id $chain_id --proposal-id $proposal_id + spawn ./bnbcli dex list-mini -s $symbol --quote-asset-symbol $quote_symbol --from $from --init-price $init_price --chain-id $chain_id } else { - spawn ./bnbcli dex list-mini --home $home -s $symbol --quote-asset-symbol $quote_symbol --from $from --init-price $init_price --chain-id $chain_id --proposal-id $proposal_id + spawn ./bnbcli dex list-mini --home $home -s $symbol --quote-asset-symbol $quote_symbol --from $from --init-price $init_price --chain-id $chain_id } expect "Password*" send "12345678\r" From b52a6b9a6011dfdf1f10baed5e8b7a8bc66505c7 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 15 May 2020 15:01:50 +0800 Subject: [PATCH 47/96] refactor --- admin/tx.go | 3 +- app/app.go | 31 ++-- app/helpers.go | 2 +- app/pub/helpers.go | 7 +- plugins/dex/aliases.go | 1 + plugins/dex/client/cli/list.go | 6 +- .../handler.go => list/handler_mini.go} | 8 +- .../dex/{listmini/msg.go => list/msg_mini.go} | 16 +- plugins/dex/order/keeper.go | 14 +- plugins/dex/order/keeper_recovery.go | 5 +- plugins/dex/order/mini_keeper.go | 20 +-- plugins/dex/order/order_keeper.go | 61 ++++---- plugins/dex/route.go | 3 +- plugins/dex/wire.go | 3 +- plugins/param/plugin.go | 16 +- plugins/tokens/burn/handler_test.go | 5 +- plugins/tokens/client/cli/issue_mini.go | 4 +- plugins/tokens/freeze/handler_test.go | 5 +- .../handler.go => issue/handler_mini.go} | 8 +- plugins/tokens/issue/handler_mini_test.go | 137 ++++++++++++++++++ plugins/tokens/issue/handler_test.go | 57 +------- .../{issue_mini/msg.go => issue/msg_mini.go} | 15 +- plugins/tokens/issue_mini/handler_test.go | 91 ------------ plugins/tokens/route.go | 3 +- plugins/tokens/seturi_mini/handler_test.go | 6 +- plugins/tokens/wire.go | 3 +- 26 files changed, 260 insertions(+), 270 deletions(-) rename plugins/dex/{listmini/handler.go => list/handler_mini.go} (90%) rename plugins/dex/{listmini/msg.go => list/msg_mini.go} (70%) rename plugins/tokens/{issue_mini/handler.go => issue/handler_mini.go} (93%) create mode 100644 plugins/tokens/issue/handler_mini_test.go rename plugins/tokens/{issue_mini/msg.go => issue/msg_mini.go} (87%) delete mode 100644 plugins/tokens/issue_mini/handler_test.go diff --git a/admin/tx.go b/admin/tx.go index 4b5f264a2..0378ff1c1 100644 --- a/admin/tx.go +++ b/admin/tx.go @@ -11,7 +11,6 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" - miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/timelock" ) @@ -26,7 +25,7 @@ var transferOnlyModeBlackList = []string{ timelock.TimeLockMsg{}.Type(), timelock.TimeUnlockMsg{}.Type(), timelock.TimeRelockMsg{}.Type(), - miniIssue.IssueMiniMsg{}.Type(), + issue.IssueMiniMsg{}.Type(), } var TxBlackList = map[runtime.Mode][]string{ diff --git a/app/app.go b/app/app.go index 622272d13..53b52c2ee 100644 --- a/app/app.go +++ b/app/app.go @@ -3,6 +3,7 @@ package app import ( "encoding/json" "fmt" + "github.com/binance-chain/node/plugins/tokens/issue" "io" "os" "runtime/debug" @@ -38,13 +39,11 @@ import ( "github.com/binance-chain/node/plugins/account" "github.com/binance-chain/node/plugins/dex" "github.com/binance-chain/node/plugins/dex/list" - "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/ico" "github.com/binance-chain/node/plugins/param" "github.com/binance-chain/node/plugins/param/paramhub" "github.com/binance-chain/node/plugins/tokens" - miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/seturi_mini" tkstore "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/plugins/tokens/swap" @@ -80,15 +79,15 @@ type BinanceChain struct { queryHandlers map[string]types.AbciQueryHandler // keepers - CoinKeeper bank.Keeper - DexKeeper *dex.DexKeeper - AccountKeeper auth.AccountKeeper - TokenMapper tkstore.Mapper - ValAddrCache *ValAddrCache - stakeKeeper stake.Keeper - govKeeper gov.Keeper - timeLockKeeper timelock.Keeper - swapKeeper swap.Keeper + CoinKeeper bank.Keeper + DexKeeper *dex.DexKeeper + AccountKeeper auth.AccountKeeper + TokenMapper tkstore.Mapper + ValAddrCache *ValAddrCache + stakeKeeper stake.Keeper + govKeeper gov.Keeper + timeLockKeeper timelock.Keeper + swapKeeper swap.Keeper // keeper to process param store and update ParamHub *param.ParamHub @@ -295,9 +294,9 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { ) // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, - miniIssue.IssueMiniMsg{}.Type(), + issue.IssueMiniMsg{}.Type(), seturi_mini.SetURIMsg{}.Type(), - listmini.ListMiniMsg{}.Type(), + list.ListMiniMsg{}.Type(), ) } @@ -333,7 +332,7 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { stateDB := baseapp.LoadStateDB() defer stateDB.Close() - order.Init( + dex.InitOrders( app.DexKeeper, app.CheckState.Ctx, app.baseConfig.BreatheBlockInterval, @@ -853,11 +852,11 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli // remove item from OrderInfoForPublish when we published removed order (cancel, iocnofill, fullyfilled, expired) for id := range pub.ToRemoveOrderIdCh { pub.Logger.Debug("delete order from order changes map", "orderId", id) - delete(app.DexKeeper.GetOrderInfosForPub(dex.PairType.BEP2), id) //TODO change to removeOrderInfosForPub method + app.DexKeeper.RemoveOrderInfosForPub(dex.PairType.BEP2, id) } for id := range pub.ToRemoveMiniOrderIdCh { pub.Logger.Debug("delete mini order from order changes map", "orderId", id) - delete(app.DexKeeper.GetOrderInfosForPub(dex.PairType.MINI), id) + app.DexKeeper.RemoveOrderInfosForPub(dex.PairType.MINI, id) } pub.Logger.Debug("finish publish", "height", height) diff --git a/app/helpers.go b/app/helpers.go index 34c4ce70f..cd8a0749c 100644 --- a/app/helpers.go +++ b/app/helpers.go @@ -148,7 +148,7 @@ func (app *BinanceChain) processErrAbciResponseForPub(txBytes []byte) { case order.CancelOrderMsg: app.Logger.Info("failed to process CancelOrderMsg", "oid", msg.RefId) // The error on deliver should be rare and only impact witness publisher's performance - // OrderInfo must has been in keeper.OrderInfosForPub + // OrderInfo must has been in keeper.orderInfosForPub app.DexKeeper.UpdateOrderChangeSync(order.OrderChange{msg.RefId, order.FailedBlocking, "", msg}, msg.Symbol) default: // deliberately do nothing for message other than NewOrderMsg diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 2f54b89e7..ace09defe 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -21,7 +21,6 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" - miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" abci "github.com/tendermint/tendermint/abci/types" ) @@ -132,7 +131,7 @@ func GetBlockPublished(pool *sdk.Pool, header abci.Header, blockHash []byte) *Bl case freeze.UnfreezeMsg: txAsset = msg.Symbol // will not cover timelock, timeUnlock, timeRelock, atomic Swap - case miniIssue.IssueMiniMsg: + case issue.IssueMiniMsg: txAsset = msg.Symbol } transactionsToPublish = append(transactionsToPublish, Transaction{ @@ -266,9 +265,9 @@ func GetAccountBalances(mapper auth.AccountKeeper, ctx sdk.Context, accSlices .. } func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, matchAllMiniSymbols bool) ([]*Trade, []*Trade) { - // This channels is used for protect not update `dexKeeper.OrderChanges` concurrently + // This channels is used for protect not update `dexKeeper.orderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) - // while dexKeeper.OrderChanges are not separated by concurrent factor (users here) + // while dexKeeper.orderChanges are not separated by concurrent factor (users here) iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize+MiniTransferCollectionChannelSize) wg := sync.WaitGroup{} wg.Add(1) diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index a07348394..fa258fe05 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -17,5 +17,6 @@ type SymbolPairType = order.SymbolPairType var NewTradingPairMapper = store.NewTradingPairMapper var NewDexKeeper = order.NewDexKeeper var PairType = order.PairType +var InitOrders = order.Init const DefaultCodespace = types.DefaultCodespace diff --git a/plugins/dex/client/cli/list.go b/plugins/dex/client/cli/list.go index 4aa9c5413..49fc647e8 100644 --- a/plugins/dex/client/cli/list.go +++ b/plugins/dex/client/cli/list.go @@ -11,7 +11,6 @@ import ( "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/utils" "github.com/binance-chain/node/plugins/dex/list" - "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/wire" ) @@ -95,8 +94,7 @@ func listMiniTradingPairCmd(cdc *wire.Codec) *cobra.Command { } quoteAsset := viper.GetString(flagQuoteAsset) - if quoteAsset != types.NativeTokenSymbol { - // TODO BUSD + if quoteAsset != types.NativeTokenSymbol && !strings.HasPrefix(quoteAsset, "BUSD") { return errors.New("invalid quote asset") } @@ -109,7 +107,7 @@ func listMiniTradingPairCmd(cdc *wire.Codec) *cobra.Command { return err } - msg := listmini.NewMsg(from, baseAsset, quoteAsset, initPrice) + msg := list.NewMiniMsg(from, baseAsset, quoteAsset, initPrice) err = client.SendOrPrintTx(cliCtx, txbldr, msg) if err != nil { return err diff --git a/plugins/dex/listmini/handler.go b/plugins/dex/list/handler_mini.go similarity index 90% rename from plugins/dex/listmini/handler.go rename to plugins/dex/list/handler_mini.go index f3230c1ea..3fdc5f84d 100644 --- a/plugins/dex/listmini/handler.go +++ b/plugins/dex/list/handler_mini.go @@ -1,4 +1,4 @@ -package listmini +package list import ( "fmt" @@ -14,11 +14,11 @@ import ( ) // NewHandler initialises dex message handlers -func NewHandler(dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper) sdk.Handler { +func NewMiniHandler(dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case ListMiniMsg: - return handleList(ctx, dexKeeper, tokenMapper, msg) + return handleListMini(ctx, dexKeeper, tokenMapper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -26,7 +26,7 @@ func NewHandler(dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper) sdk.Handl } } -func handleList(ctx sdk.Context, dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper, +func handleListMini(ctx sdk.Context, dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper, msg ListMiniMsg) sdk.Result { if !sdk.IsUpgrade(upgrade.BEP8) { return sdk.ErrInternal(fmt.Sprint("list mini-token is not supported at current height")).Result() diff --git a/plugins/dex/listmini/msg.go b/plugins/dex/list/msg_mini.go similarity index 70% rename from plugins/dex/listmini/msg.go rename to plugins/dex/list/msg_mini.go index be09d2989..b34f328e2 100644 --- a/plugins/dex/listmini/msg.go +++ b/plugins/dex/list/msg_mini.go @@ -1,15 +1,16 @@ -package listmini +package list import ( "encoding/json" "fmt" + "github.com/binance-chain/node/plugins/dex/order" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" ) -const Route = "dexListMini" +const MiniRoute = "dexListMini" var _ sdk.Msg = ListMiniMsg{} @@ -20,7 +21,7 @@ type ListMiniMsg struct { InitPrice int64 `json:"init_price"` } -func NewMsg(from sdk.AccAddress, baseAssetSymbol string, quoteAssetSymbol string, initPrice int64) ListMiniMsg { +func NewMiniMsg(from sdk.AccAddress, baseAssetSymbol string, quoteAssetSymbol string, initPrice int64) ListMiniMsg { return ListMiniMsg{ From: from, BaseAssetSymbol: baseAssetSymbol, @@ -29,8 +30,8 @@ func NewMsg(from sdk.AccAddress, baseAssetSymbol string, quoteAssetSymbol string } } -func (msg ListMiniMsg) Route() string { return Route } -func (msg ListMiniMsg) Type() string { return Route } +func (msg ListMiniMsg) Route() string { return MiniRoute } +func (msg ListMiniMsg) Type() string { return MiniRoute } func (msg ListMiniMsg) String() string { return fmt.Sprintf("MsgListMini{%#v}", msg) } func (msg ListMiniMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } @@ -40,7 +41,10 @@ func (msg ListMiniMsg) ValidateBasic() sdk.Error { if err != nil { return sdk.ErrInvalidCoins("base token: " + err.Error()) } - if types.NativeTokenSymbol != msg.QuoteAssetSymbol { //todo permit BUSD + if len(msg.QuoteAssetSymbol) == 0 { + return sdk.ErrInvalidCoins("quote token is empty: " + err.Error()) + } + if types.NativeTokenSymbol != msg.QuoteAssetSymbol && order.BUSDSymbol!= msg.QuoteAssetSymbol{ return sdk.ErrInvalidCoins("quote token: " + err.Error()) } if msg.InitPrice <= 0 { diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 685e1337a..674869ae6 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -986,7 +986,7 @@ func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset s if baseAsset != types.NativeTokenSymbol && quoteAsset != types.NativeTokenSymbol { - // support busd pair listing + // support busd pair listing including mini-token as base if sdk.IsUpgrade(upgrade.BEP70) && len(BUSDSymbol) > 0 { if baseAsset == BUSDSymbol || quoteAsset == BUSDSymbol { if kp.pairExistsBetween(ctx, types.NativeTokenSymbol, BUSDSymbol) { @@ -1006,7 +1006,7 @@ func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset s } } - if isMiniSymbolPair(baseAsset, quoteAsset) && types.NativeTokenSymbol != quoteAsset { //todo permit BUSD + if isMiniSymbolPair(baseAsset, quoteAsset) && types.NativeTokenSymbol != quoteAsset { return errors.New("quote token is not valid for mini symbol pair: " + quoteAsset) } @@ -1093,6 +1093,16 @@ func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPu } +func (kp *DexKeeper) RemoveOrderInfosForPub(pairType SymbolPairType, orderId string) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportPairType(pairType) { + orderKeeper.removeOrderInfosForPub(orderId) + return + } + } + kp.logger.Error("pairType is not supported %d", pairType) +} + func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { return kp.PairMapper } diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 65ae532b0..fc00dd1b7 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -72,10 +72,9 @@ func (kp *DexKeeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedS for pair, eng := range kp.engines { buys, sells := eng.Book.GetAllLevels() var snapshot OrderBookSnapshot + snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice} if sdk.IsUpgrade(upgrade.BEP8) { - snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice, LastMatchHeight: eng.LastMatchHeight} - } else { - snapshot = OrderBookSnapshot{Buys: buys, Sells: sells, LastTradePrice: eng.LastTradePrice} + snapshot.LastMatchHeight = eng.LastMatchHeight } key := genOrderBookSnapshotKey(height, pair) effectedStoreKeys = append(effectedStoreKeys, key) diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index ae4a0a138..dd5d4f7b1 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -2,14 +2,12 @@ package order import ( "fmt" - "strings" - "sync" - bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" dexUtils "github.com/binance-chain/node/plugins/dex/utils" sdk "github.com/cosmos/cosmos-sdk/types" + "strings" ) const ( @@ -26,17 +24,9 @@ var _ IDexOrderKeeper = &MiniOrderKeeper{} // NewBEP2OrderKeeper - Returns the MiniToken orderKeeper func NewMiniOrderKeeper() IDexOrderKeeper { - logger := bnclog.With("module", "dexMiniKeeper") return &MiniOrderKeeper{ - BaseOrderKeeper{ - allOrders: make(map[string]map[string]*OrderInfo, 256), // need to init the nested map when a new symbol added. - OrderChangesMtx: &sync.Mutex{}, - OrderChanges: make(OrderChanges, 0), - OrderInfosForPub: make(OrderInfoForPublish), - roundOrders: make(map[string][]string, 256), - roundIOCOrders: make(map[string][]string, 256), - logger: logger, - symbolSelector: &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}}, + NewBaseOrderKeeper("dexMiniKeeper", + &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}), } } @@ -117,9 +107,9 @@ func (kp *MiniOrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, heig kp.allOrders[symbol][orderInfo.Id] = orderInfo //TODO confirm no active orders for mini symbol if collectOrderInfoForPublish { - if _, exists := kp.OrderInfosForPub[orderInfo.Id]; !exists { + if _, exists := kp.orderInfosForPub[orderInfo.Id]; !exists { bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) - kp.OrderInfosForPub[orderInfo.Id] = orderInfo + kp.orderInfosForPub[orderInfo.Id] = orderInfo } } } diff --git a/plugins/dex/order/order_keeper.go b/plugins/dex/order/order_keeper.go index 637d41b6f..c63401d42 100644 --- a/plugins/dex/order/order_keeper.go +++ b/plugins/dex/order/order_keeper.go @@ -33,6 +33,7 @@ type IDexOrderKeeper interface { clearOrderChanges() getOrderChanges() OrderChanges getOrderInfosForPub() OrderInfoForPublish + removeOrderInfosForPub(orderId string) appendOrderChange(change OrderChange) initOrders(symbol string) support(pair string) bool @@ -61,9 +62,9 @@ var _ IDexOrderKeeper = &BEP2OrderKeeper{} // in the future, this may be distributed via Sharding type BaseOrderKeeper struct { allOrders map[string]map[string]*OrderInfo // symbol -> order ID -> order - OrderChangesMtx *sync.Mutex // guard OrderChanges and OrderInfosForPub during PreDevlierTx (which is async) - OrderChanges OrderChanges // order changed in this block, will be cleaned before matching for new block - OrderInfosForPub OrderInfoForPublish // for publication usage + orderChangesMtx *sync.Mutex // guard orderChanges and orderInfosForPub during PreDevlierTx (which is async) + orderChanges OrderChanges // order changed in this block, will be cleaned before matching for new block + orderInfosForPub OrderInfoForPublish // for publication usage roundOrders map[string][]string // limit to the total tx number in a block roundIOCOrders map[string][]string poolSize uint // number of concurrent channels, counted in the pow of 2 @@ -74,19 +75,23 @@ type BaseOrderKeeper struct { // NewBEP2OrderKeeper - Returns the BEP2OrderKeeper func NewBEP2OrderKeeper() IDexOrderKeeper { - logger := bnclog.With("module", "Bep2OrderKeeper") return &BEP2OrderKeeper{ - BaseOrderKeeper{ - allOrders: make(map[string]map[string]*OrderInfo, 256), - // need to init the nested map when a new symbol added. - OrderChangesMtx: &sync.Mutex{}, - OrderChanges: make(OrderChanges, 0), - OrderInfosForPub: make(OrderInfoForPublish), - roundOrders: make(map[string][]string, 256), - roundIOCOrders: make(map[string][]string, 256), - logger: logger, - symbolSelector: &BEP2SymbolSelector{}, - }, + NewBaseOrderKeeper("Bep2OrderKeeper", &BEP2SymbolSelector{}), + } +} + +func NewBaseOrderKeeper(moduleName string, symbolSelector SymbolSelector) BaseOrderKeeper { + logger := bnclog.With("module", moduleName) + return BaseOrderKeeper{ + allOrders: make(map[string]map[string]*OrderInfo, 256), + // need to init the nested map when a new symbol added. + orderChangesMtx: &sync.Mutex{}, + orderChanges: make(OrderChanges, 0), + orderInfosForPub: make(OrderInfoForPublish), + roundOrders: make(map[string][]string, 256), + roundIOCOrders: make(map[string][]string, 256), + logger: logger, + symbolSelector: symbolSelector, } } @@ -96,10 +101,10 @@ func (kp *BaseOrderKeeper) addOrder(symbol string, info OrderInfo, collectOrderI change := OrderChange{info.Id, Ack, "", nil} // deliberately not add this message to orderChanges if !isRecovery { - kp.OrderChanges = append(kp.OrderChanges, change) + kp.orderChanges = append(kp.orderChanges, change) } kp.logger.Debug("add order to order changes map", "orderId", info.Id, "isRecovery", isRecovery) - kp.OrderInfosForPub[info.Id] = &info + kp.orderInfosForPub[info.Id] = &info } kp.allOrders[symbol][info.Id] = &info @@ -216,7 +221,7 @@ func (kp *BaseOrderKeeper) getOpenOrders(pair string, addr sdk.AccAddress) []sto } func (kp *BaseOrderKeeper) clearOrderChanges() { - kp.OrderChanges = kp.OrderChanges[:0] + kp.orderChanges = kp.orderChanges[:0] } func (kp *BaseOrderKeeper) getAllOrders() map[string]map[string]*OrderInfo { @@ -224,15 +229,19 @@ func (kp *BaseOrderKeeper) getAllOrders() map[string]map[string]*OrderInfo { } func (kp *BaseOrderKeeper) getOrderChanges() OrderChanges { - return kp.OrderChanges + return kp.orderChanges } func (kp *BaseOrderKeeper) getOrderInfosForPub() OrderInfoForPublish { - return kp.OrderInfosForPub + return kp.orderInfosForPub +} + +func (kp *BaseOrderKeeper) removeOrderInfosForPub(orderId string) { + delete(kp.orderInfosForPub, orderId) } func (kp *BaseOrderKeeper) appendOrderChange(change OrderChange) { - kp.OrderChanges = append(kp.OrderChanges, change) + kp.orderChanges = append(kp.orderChanges, change) } func (kp *BaseOrderKeeper) getRoundOrdersForPair(pair string) []string { @@ -252,9 +261,9 @@ func (kp *BaseOrderKeeper) selectSymbolsToMatch(height, timestamp int64, matchAl } func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { - kp.OrderChangesMtx.Lock() - kp.OrderChanges = append(kp.OrderChanges, change) - kp.OrderChangesMtx.Unlock() + kp.orderChangesMtx.Lock() + kp.orderChanges = append(kp.orderChanges, change) + kp.orderChangesMtx.Unlock() } func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { @@ -305,9 +314,9 @@ func (kp *BEP2OrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, heig } } if collectOrderInfoForPublish { - if _, exists := kp.OrderInfosForPub[orderInfo.Id]; !exists { + if _, exists := kp.orderInfosForPub[orderInfo.Id]; !exists { bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) - kp.OrderInfosForPub[orderInfo.Id] = orderInfo + kp.orderInfosForPub[orderInfo.Id] = orderInfo } } } diff --git a/plugins/dex/route.go b/plugins/dex/route.go index c28ef55a6..1a873eda8 100644 --- a/plugins/dex/route.go +++ b/plugins/dex/route.go @@ -1,7 +1,6 @@ package dex import ( - "github.com/binance-chain/node/plugins/dex/listmini" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" @@ -20,6 +19,6 @@ func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, routes[order.RouteNewOrder] = orderHandler routes[order.RouteCancelOrder] = orderHandler routes[list.Route] = list.NewHandler(dexKeeper, tokenMapper, govKeeper) - routes[listmini.Route] = listmini.NewHandler(dexKeeper, tokenMapper) + routes[list.MiniRoute] = list.NewMiniHandler(dexKeeper, tokenMapper) return routes } diff --git a/plugins/dex/wire.go b/plugins/dex/wire.go index 1c0169603..e0900b5e0 100644 --- a/plugins/dex/wire.go +++ b/plugins/dex/wire.go @@ -2,7 +2,6 @@ package dex import ( "github.com/binance-chain/node/plugins/dex/list" - "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/store" "github.com/binance-chain/node/plugins/dex/types" @@ -19,7 +18,7 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(list.ListMsg{}, "dex/ListMsg", nil) cdc.RegisterConcrete(types.TradingPair{}, "dex/TradingPair", nil) - cdc.RegisterConcrete(listmini.ListMiniMsg{}, "dex/ListMiniMsg", nil) + cdc.RegisterConcrete(list.ListMiniMsg{}, "dex/ListMiniMsg", nil) cdc.RegisterConcrete(order.FeeConfig{}, "dex/FeeConfig", nil) cdc.RegisterConcrete(order.OrderBookSnapshot{}, "dex/OrderBookSnapshot", nil) diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 12e1b7b9c..96fdf2f9c 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -12,7 +12,6 @@ import ( "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/account" "github.com/binance-chain/node/plugins/dex/list" - "github.com/binance-chain/node/plugins/dex/listmini" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/param/paramhub" param "github.com/binance-chain/node/plugins/param/types" @@ -20,7 +19,6 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" - miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" miniURI "github.com/binance-chain/node/plugins/tokens/seturi_mini" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" @@ -65,10 +63,10 @@ func RegisterUpgradeBeginBlocker(paramHub *ParamHub) { }) upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP8, func(ctx sdk.Context) { miniTokenFeeParams := []param.FeeParam{ - ¶m.FixedFeeParams{MsgType: miniIssue.IssueTinyMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: miniIssue.IssueMiniMsgType, Fee: AdvMiniIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: issue.IssueTinyMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: issue.IssueMiniMsgType, Fee: AdvMiniIssueFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: miniURI.SetURIMsg{}.Type(), Fee: MiniSetUriFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: listmini.ListMiniMsg{}.Type(), Fee: MiniListingFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: list.ListMiniMsg{}.Type(), Fee: MiniListingFee, FeeFor: types.FeeForProposer}, } paramHub.UpdateFeeParams(ctx, miniTokenFeeParams) }) @@ -83,7 +81,7 @@ func init() { // CalculatorsGen is defined in a common package which can't import app package. // Reasonable to init here, since fee param drive the calculator. fees.CalculatorsGen = map[string]fees.FeeCalculatorGenerator{ - gov.MsgSubmitProposal{}.Type(): fees.FixedFeeCalculatorGen, + gov.MsgSubmitProposal{}.Type(): fees.FixedFeeCalculatorGen, gov.MsgDeposit{}.Type(): fees.FixedFeeCalculatorGen, gov.MsgVote{}.Type(): fees.FixedFeeCalculatorGen, stake.MsgCreateValidator{}.Type(): fees.FixedFeeCalculatorGen, @@ -104,9 +102,9 @@ func init() { swap.DepositHTLT: fees.FixedFeeCalculatorGen, swap.ClaimHTLT: fees.FixedFeeCalculatorGen, swap.RefundHTLT: fees.FixedFeeCalculatorGen, - miniIssue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, - miniIssue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, + issue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, + issue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, - listmini.Route: fees.FixedFeeCalculatorGen, + list.MiniRoute: fees.FixedFeeCalculatorGen, } } diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go index 2fe4feffb..28e072305 100644 --- a/plugins/tokens/burn/handler_test.go +++ b/plugins/tokens/burn/handler_test.go @@ -2,7 +2,6 @@ package burn import ( "github.com/binance-chain/node/plugins/tokens/issue" - "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/cosmos/cosmos-sdk/x/bank" "testing" @@ -33,7 +32,7 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKe bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, bankKeeper) tokenHandler := issue.NewHandler(tokenMapper, bankKeeper) - miniTokenHandler := issue_mini.NewHandler(tokenMapper, bankKeeper) + miniTokenHandler := issue.NewMiniHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) @@ -58,7 +57,7 @@ func TestHandleBurnMini(t *testing.T) { _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := issue_mini.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") sdkResult := miniIssueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) diff --git a/plugins/tokens/client/cli/issue_mini.go b/plugins/tokens/client/cli/issue_mini.go index 262781919..cb92aa9b9 100644 --- a/plugins/tokens/client/cli/issue_mini.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -2,13 +2,13 @@ package commands import ( "fmt" + "github.com/binance-chain/node/plugins/tokens/issue" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/tokens/issue_mini" ) const ( @@ -73,7 +73,7 @@ func (c Commander) issueMiniToken(cmd *cobra.Command, args []string) error { } // build message - msg := issue_mini.NewIssueMsg(from, name, symbol, int8(tokenType), supply, mintable, tokenURI) + msg := issue.NewIssueMiniMsg(from, name, symbol, int8(tokenType), supply, mintable, tokenURI) return client.SendOrPrintTx(cliCtx, txBldr, msg) } diff --git a/plugins/tokens/freeze/handler_test.go b/plugins/tokens/freeze/handler_test.go index b4c8b86a3..734eed21f 100644 --- a/plugins/tokens/freeze/handler_test.go +++ b/plugins/tokens/freeze/handler_test.go @@ -17,7 +17,6 @@ import ( "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/tokens/issue" - "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) @@ -34,7 +33,7 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKe bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, accountKeeper, bankKeeper) tokenHandler := issue.NewHandler(tokenMapper, bankKeeper) - miniTokenHandler := issue_mini.NewHandler(tokenMapper, bankKeeper) + miniTokenHandler := issue.NewMiniHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) @@ -59,7 +58,7 @@ func TestHandleFreezeMini(t *testing.T) { _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := issue_mini.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") sdkResult := miniIssueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) diff --git a/plugins/tokens/issue_mini/handler.go b/plugins/tokens/issue/handler_mini.go similarity index 93% rename from plugins/tokens/issue_mini/handler.go rename to plugins/tokens/issue/handler_mini.go index ebe09d8bd..712d664fb 100644 --- a/plugins/tokens/issue_mini/handler.go +++ b/plugins/tokens/issue/handler_mini.go @@ -1,4 +1,4 @@ -package issue_mini +package issue import ( "encoding/json" @@ -17,11 +17,11 @@ import ( ) // NewHandler creates a new token issue message handler -func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { +func NewMiniHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case IssueMiniMsg: - return handleIssueToken(ctx, tokenMapper, keeper, msg) + return handleIssueMiniToken(ctx, tokenMapper, keeper, msg) default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -29,7 +29,7 @@ func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { } } -func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg IssueMiniMsg) sdk.Result { +func handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg IssueMiniMsg) sdk.Result { errLogMsg := "issue miniToken failed" symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) diff --git a/plugins/tokens/issue/handler_mini_test.go b/plugins/tokens/issue/handler_mini_test.go new file mode 100644 index 000000000..aa0f746f1 --- /dev/null +++ b/plugins/tokens/issue/handler_mini_test.go @@ -0,0 +1,137 @@ +package issue + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/binance-chain/node/common/testutils" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/tokens/store" + "github.com/binance-chain/node/wire" +) + +func setupMini() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { + ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() + cdc := wire.NewCodec() + cdc.RegisterInterface((*types.IToken)(nil), nil) + cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) + cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) + tokenMapper := store.NewMapper(cdc, capKey1) + accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) + bankKeeper := bank.NewBaseKeeper(accountKeeper) + handler := NewMiniHandler(tokenMapper, bankKeeper) + + accountStore := ms.GetKVStore(capKey2) + accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, + sdk.RunTxModeDeliver, log.NewNopLogger()). + WithAccountCache(auth.NewAccountCache(accountStoreCache)) + return ctx, handler, accountKeeper, tokenMapper +} + +func TestHandleIssueMiniToken(t *testing.T) { + setChainVersion() + defer resetChainVersion() + ctx, handler, accountKeeper, tokenMapper := setupMini() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg := NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8+100, false, "http://www.xyz.com/nnb.json") + sdkResult := handler(ctx, msg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") + + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + msg = NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + sdkResult = handler(ctx, msg) + require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + msg = NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 2, 100000e8+100, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") + + ctx = ctx.WithValue(baseapp.TxHashKey, "002") + msg = NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 2, 10000e8+100, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + token, err = tokenMapper.GetToken(ctx, "NBB-002M") + require.NoError(t, err) + expectedToken, err = types.NewMiniToken("New BB", "NBB-002M", 2, 10000e8+100, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) +} + + +func TestHandleMintMiniToken(t *testing.T) { + setChainVersion() + defer resetChainVersion() + ctx, handler, miniTokenHandler, accountKeeper, tokenMapper := setup() + _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) + mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1001e8) + sdkResult := handler(ctx, mintMsg) + require.Contains(t, sdkResult.Log, "symbol(NNB-000M) does not exist") + + issueMsg := NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 9000e8, true, "http://www.xyz.com/nnb.json") + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + sdkResult = miniTokenHandler(ctx, issueMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + sdkResult = handler(ctx, mintMsg) + token, err := tokenMapper.GetToken(ctx, "NNB-000M") + require.NoError(t, err) + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 9000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + _, err = tokenMapper.GetToken(ctx, "NNB-000") + require.NotNil(t, err) + require.Contains(t, err.Error(), "token(NNB-000) not found") + + sdkResult = handler(ctx, mintMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, "mint amount is too large") + + validMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1000e8) + sdkResult = handler(ctx, validMintMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + token, err = tokenMapper.GetToken(ctx, "NNB-000M") + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") + require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + + _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) + invalidMintMsg := NewMintMsg(acc2.GetAddress(), "NNB-000M", 100e8) + sdkResult = handler(ctx, invalidMintMsg) + require.Contains(t, sdkResult.Log, "only the owner can mint token NNB") + + // issue a non-mintable token + issueMsg = NewIssueMiniMsg(acc.GetAddress(), "New BNB2", "NNB2", 1, 9000e8, false, "http://www.xyz.com/nnb.json") + ctx = ctx.WithValue(baseapp.TxHashKey, "000") + sdkResult = miniTokenHandler(ctx, issueMsg) + require.Equal(t, true, sdkResult.Code.IsOK()) + + mintMsg = NewMintMsg(acc.GetAddress(), "NNB2-000M", 1000e8) + sdkResult = handler(ctx, mintMsg) + require.Contains(t, sdkResult.Log, "token(NNB2-000M) cannot be minted") + + // mint native token + invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) + require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "cannot mint native token") +} diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 4ab824df9..60de41c14 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -16,7 +16,6 @@ import ( "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" - miniIssue "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) @@ -31,7 +30,7 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.M accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, bankKeeper) - miniTokenHandler := miniIssue.NewHandler(tokenMapper, bankKeeper) + miniTokenHandler := NewMiniHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, @@ -109,57 +108,3 @@ func TestHandleMintToken(t *testing.T) { require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "cannot mint native token") } -func TestHandleMintMiniToken(t *testing.T) { - setChainVersion() - defer resetChainVersion() - ctx, handler, miniTokenHandler, accountKeeper, tokenMapper := setup() - _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) - mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1001e8) - sdkResult := handler(ctx, mintMsg) - require.Contains(t, sdkResult.Log, "symbol(NNB-000M) does not exist") - - issueMsg := miniIssue.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 9000e8, true, "http://www.xyz.com/nnb.json") - ctx = ctx.WithValue(baseapp.TxHashKey, "000") - sdkResult = miniTokenHandler(ctx, issueMsg) - require.Equal(t, true, sdkResult.Code.IsOK()) - - sdkResult = handler(ctx, mintMsg) - token, err := tokenMapper.GetToken(ctx, "NNB-000M") - require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 9000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) - - _, err = tokenMapper.GetToken(ctx, "NNB-000") - require.NotNil(t, err) - require.Contains(t, err.Error(), "token(NNB-000) not found") - - sdkResult = handler(ctx, mintMsg) - require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "mint amount is too large") - - validMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1000e8) - sdkResult = handler(ctx, validMintMsg) - require.Equal(t, true, sdkResult.Code.IsOK()) - token, err = tokenMapper.GetToken(ctx, "NNB-000M") - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) - - _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) - invalidMintMsg := NewMintMsg(acc2.GetAddress(), "NNB-000M", 100e8) - sdkResult = handler(ctx, invalidMintMsg) - require.Contains(t, sdkResult.Log, "only the owner can mint token NNB") - - // issue a non-mintable token - issueMsg = miniIssue.NewIssueMsg(acc.GetAddress(), "New BNB2", "NNB2", 1, 9000e8, false, "http://www.xyz.com/nnb.json") - ctx = ctx.WithValue(baseapp.TxHashKey, "000") - sdkResult = miniTokenHandler(ctx, issueMsg) - require.Equal(t, true, sdkResult.Code.IsOK()) - - mintMsg = NewMintMsg(acc.GetAddress(), "NNB2-000M", 1000e8) - sdkResult = handler(ctx, mintMsg) - require.Contains(t, sdkResult.Log, "token(NNB2-000M) cannot be minted") - - // mint native token - invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) - require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "cannot mint native token") -} diff --git a/plugins/tokens/issue_mini/msg.go b/plugins/tokens/issue/msg_mini.go similarity index 87% rename from plugins/tokens/issue_mini/msg.go rename to plugins/tokens/issue/msg_mini.go index 6811da2a9..6d10392c0 100644 --- a/plugins/tokens/issue_mini/msg.go +++ b/plugins/tokens/issue/msg_mini.go @@ -1,4 +1,4 @@ -package issue_mini +package issue import ( "encoding/json" @@ -13,10 +13,9 @@ import ( // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash // const Route = "tokens/issue" const ( - Route = "miniTokensIssue" - IssueTinyMsgType = "tinyIssueMsg" - IssueMiniMsgType = "miniIssueMsg" //For max total supply in range 2 - maxTokenNameLength = 32 + MiniRoute = "miniTokensIssue" + IssueTinyMsgType = "tinyIssueMsg" + IssueMiniMsgType = "miniIssueMsg" //For max total supply in range 2 ) var _ sdk.Msg = IssueMiniMsg{} @@ -31,7 +30,7 @@ type IssueMiniMsg struct { TokenURI string `json:"token_uri"` } -func NewIssueMsg(from sdk.AccAddress, name, symbol string, tokenType int8, supply int64, mintable bool, tokenURI string) IssueMiniMsg { +func NewIssueMiniMsg(from sdk.AccAddress, name, symbol string, tokenType int8, supply int64, mintable bool, tokenURI string) IssueMiniMsg { return IssueMiniMsg{ From: from, Name: name, @@ -46,7 +45,7 @@ func NewIssueMsg(from sdk.AccAddress, name, symbol string, tokenType int8, suppl // ValidateBasic does a simple validation check that // doesn't require access to any other information. func (msg IssueMiniMsg) ValidateBasic() sdk.Error { - if !sdk.IsUpgrade(upgrade.BEP8){ + if !sdk.IsUpgrade(upgrade.BEP8) { return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")) } @@ -78,7 +77,7 @@ func (msg IssueMiniMsg) ValidateBasic() sdk.Error { } // Implements IssueMiniMsg. -func (msg IssueMiniMsg) Route() string { return Route } +func (msg IssueMiniMsg) Route() string { return MiniRoute } func (msg IssueMiniMsg) Type() string { switch types.SupplyRangeType(msg.TokenType) { case types.SupplyRange.TINY: diff --git a/plugins/tokens/issue_mini/handler_test.go b/plugins/tokens/issue_mini/handler_test.go deleted file mode 100644 index a4ef4ebc0..000000000 --- a/plugins/tokens/issue_mini/handler_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package issue_mini - -import ( - "testing" - - "github.com/binance-chain/node/common/upgrade" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - - "github.com/binance-chain/node/common/testutils" - "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/tokens/store" - "github.com/binance-chain/node/wire" -) - -func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { - ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() - cdc := wire.NewCodec() - cdc.RegisterInterface((*types.IToken)(nil), nil) - cdc.RegisterConcrete(&types.Token{}, "bnbchain/Token", nil) - cdc.RegisterConcrete(&types.MiniToken{}, "bnbchain/MiniToken", nil) - tokenMapper := store.NewMapper(cdc, capKey1) - accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper) - handler := NewHandler(tokenMapper, bankKeeper) - - accountStore := ms.GetKVStore(capKey2) - accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, - sdk.RunTxModeDeliver, log.NewNopLogger()). - WithAccountCache(auth.NewAccountCache(accountStoreCache)) - return ctx, handler, accountKeeper, tokenMapper -} - -func setChainVersion() { - upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) -} - -func resetChainVersion() { - upgrade.Mgr.Config.HeightMap = nil -} - -func TestHandleIssueToken(t *testing.T) { - setChainVersion() - defer resetChainVersion() - ctx, handler, accountKeeper, tokenMapper := setup() - _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) - - ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8+100, false, "http://www.xyz.com/nnb.json") - sdkResult := handler(ctx, msg) - require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") - - ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg = NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") - sdkResult = handler(ctx, msg) - require.Equal(t, true, sdkResult.Code.IsOK()) - - token, err := tokenMapper.GetToken(ctx, "NNB-000M") - require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) - - sdkResult = handler(ctx, msg) - require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") - - ctx = ctx.WithValue(baseapp.TxHashKey, "002") - msg = NewIssueMsg(acc.GetAddress(), "New BB", "NBB", 2, 100000e8+100, false, "http://www.xyz.com/nnb.json") - sdkResult = handler(ctx, msg) - require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") - - ctx = ctx.WithValue(baseapp.TxHashKey, "002") - msg = NewIssueMsg(acc.GetAddress(), "New BB", "NBB", 2, 10000e8+100, false, "http://www.xyz.com/nnb.json") - sdkResult = handler(ctx, msg) - require.Equal(t, true, sdkResult.Code.IsOK()) - - token, err = tokenMapper.GetToken(ctx, "NBB-002M") - require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BB", "NBB-002M", 2, 10000e8+100, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) -} diff --git a/plugins/tokens/route.go b/plugins/tokens/route.go index 35f0835c8..82d91a7a5 100644 --- a/plugins/tokens/route.go +++ b/plugins/tokens/route.go @@ -1,7 +1,6 @@ package tokens import ( - "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/seturi_mini" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -23,7 +22,7 @@ func Routes(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank. routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, accKeeper, keeper) routes[timelock.MsgRoute] = timelock.NewHandler(timeLockKeeper) routes[swap.AtomicSwapRoute] = swap.NewHandler(swapKeeper) - routes[issue_mini.Route] = issue_mini.NewHandler(tokenMapper, keeper) + routes[issue.MiniRoute] = issue.NewMiniHandler(tokenMapper, keeper) routes[seturi_mini.SetURIRoute] = seturi_mini.NewHandler(tokenMapper) return routes } diff --git a/plugins/tokens/seturi_mini/handler_test.go b/plugins/tokens/seturi_mini/handler_test.go index e159d00f2..3bceb81a6 100644 --- a/plugins/tokens/seturi_mini/handler_test.go +++ b/plugins/tokens/seturi_mini/handler_test.go @@ -1,7 +1,7 @@ package seturi_mini import ( - "github.com/binance-chain/node/plugins/tokens/issue_mini" + "github.com/binance-chain/node/plugins/tokens/issue" "github.com/cosmos/cosmos-sdk/x/bank" "testing" @@ -32,7 +32,7 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.M handler := NewHandler(tokenMapper) bankKeeper := bank.NewBaseKeeper(accountKeeper) - miniTokenHandler := issue_mini.NewHandler(tokenMapper, bankKeeper) + miniTokenHandler := issue.NewMiniHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) @@ -57,7 +57,7 @@ func TestHandleSetURI(t *testing.T) { _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := issue_mini.NewIssueMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") sdkResult := miniIssueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) diff --git a/plugins/tokens/wire.go b/plugins/tokens/wire.go index 64501055a..064a9324d 100644 --- a/plugins/tokens/wire.go +++ b/plugins/tokens/wire.go @@ -4,7 +4,6 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" - "github.com/binance-chain/node/plugins/tokens/issue_mini" "github.com/binance-chain/node/plugins/tokens/seturi_mini" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" @@ -25,6 +24,6 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(swap.DepositHTLTMsg{}, "tokens/DepositHTLTMsg", nil) cdc.RegisterConcrete(swap.ClaimHTLTMsg{}, "tokens/ClaimHTLTMsg", nil) cdc.RegisterConcrete(swap.RefundHTLTMsg{}, "tokens/RefundHTLTMsg", nil) - cdc.RegisterConcrete(issue_mini.IssueMiniMsg{}, "tokens/IssueMiniMsg", nil) + cdc.RegisterConcrete(issue.IssueMiniMsg{}, "tokens/IssueMiniMsg", nil) cdc.RegisterConcrete(seturi_mini.SetURIMsg{}, "tokens/SetURIMsg", nil) } From d6cecbbc7687de8eb5236ae23e03449ac5306efe Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 15 May 2020 16:25:59 +0800 Subject: [PATCH 48/96] refactor --- common/fees/pool.go | 5 - integration_test.sh | 2 +- plugins/dex/matcheng/engine_new.go | 14 +-- plugins/dex/order/keeper.go | 154 +++++++++++------------------ plugins/dex/order/keeper_match.go | 15 ++- 5 files changed, 72 insertions(+), 118 deletions(-) diff --git a/common/fees/pool.go b/common/fees/pool.go index baec4555b..b66280231 100644 --- a/common/fees/pool.go +++ b/common/fees/pool.go @@ -2,8 +2,6 @@ package fees import ( "fmt" - "sync" - "github.com/binance-chain/node/common/types" ) @@ -13,7 +11,6 @@ var Pool pool = newPool() type pool struct { fees map[string]types.Fee // TxHash -> fee committedFees types.Fee - sync.Mutex } func newPool() pool { @@ -28,8 +25,6 @@ func (p *pool) AddFee(txHash string, fee types.Fee) { } func (p *pool) AddAndCommitFee(txHash string, fee types.Fee) { - p.Lock() - defer p.Unlock() p.fees[txHash] = fee p.committedFees.AddFee(fee) } diff --git a/integration_test.sh b/integration_test.sh index a271b100b..bca3c9252 100755 --- a/integration_test.sh +++ b/integration_test.sh @@ -331,7 +331,7 @@ check_operation "Issue Mini Token" "${result}" "${chain_operation_words}" sleep 1s # send -result=$(expect ./send.exp ${cli_home} alice ${chain_id} "100000000000:${mbc_symbol}" ${bob_addr} a) +result=$(expect ./send.exp ${cli_home} alice ${chain_id} "100000000000:${mbc_symbol}" ${bob_addr} 1) check_operation "Send Token" "${result}" "${chain_operation_words}" sleep 1s diff --git a/plugins/dex/matcheng/engine_new.go b/plugins/dex/matcheng/engine_new.go index 64890296c..46bbeca63 100644 --- a/plugins/dex/matcheng/engine_new.go +++ b/plugins/dex/matcheng/engine_new.go @@ -12,7 +12,7 @@ import ( "github.com/binance-chain/node/common/utils" ) -func (me *MatchEng) Match(height int64, isMini bool) bool { +func (me *MatchEng) Match(height int64, lastMatchedHeight int64) bool { if !sdk.IsUpgrade(upgrade.BEP19) { return me.MatchBeforeGalileo(height) } @@ -20,30 +20,21 @@ func (me *MatchEng) Match(height int64, isMini bool) bool { me.Trades = me.Trades[:0] r := me.Book.GetOverlappedRange(&me.overLappedLevel, &me.buyBuf, &me.sellBuf) if r <= 0 { - me.LastMatchHeight = height return true } prepareMatch(&me.overLappedLevel) tradePrice, index := getTradePrice(&me.overLappedLevel, &me.maxExec, &me.leastSurplus, me.LastTradePrice, me.PriceLimitPct) if index < 0 { - me.LastMatchHeight = height return false } if err := me.dropRedundantQty(index); err != nil { me.logger.Error("dropRedundantQty failed", "error", err) - me.LastMatchHeight = height return false } //If order height > the last Match height, then it's maker. // Block Height cannot be used here since mini-token is not matched in every block - var lastMatchHeight int64 - if isMini { - lastMatchHeight = me.LastMatchHeight - } else { - lastMatchHeight = height - 1 //Every block is deemed as performed matching for all BEP2 symbols - } - takerSide, err := me.determineTakerSide(lastMatchHeight, index) + takerSide, err := me.determineTakerSide(lastMatchedHeight, index) if err != nil { me.logger.Error("determineTakerSide failed", "error", err) return false @@ -52,7 +43,6 @@ func (me *MatchEng) Match(height int64, isMini bool) bool { surplus := me.overLappedLevel[index].BuySellSurplus me.fillOrdersNew(takerSide, takerSideOrders, index, tradePrice, surplus) me.LastTradePrice = tradePrice - me.LastMatchHeight = height return true } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 674869ae6..3bd17afa8 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -46,51 +46,6 @@ var BUSDSymbol string type FeeHandler func(map[string]*types.Fee) type TransferHandler func(Transfer) -type IDexKeeper interface { - InitRecentPrices(ctx sdk.Context) - AddEngine(pair dexTypes.TradingPair) *me.MatchEng - UpdateTickSizeAndLotSize(ctx sdk.Context) - DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, price int64) (lotSize int64) - UpdateLotSize(symbol string, lotSize int64) - AddOrder(info OrderInfo, isRecovery bool) (err error) - RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) - GetOrder(id string, symbol string, side int8, price int64) (ord me.OrderPart, err error) - OrderExists(symbol, id string) (OrderInfo, bool) - GetOrderBookLevels(pair string, maxLevels int) (orderbook []store.OrderBookLevel, pendingMatch bool) - GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder - GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap - GetPriceLevel(pair string, side int8, price int64) *me.PriceLevel - GetLastTrades(height int64, pair string) ([]me.Trade, int64) - GetLastTradesForPair(pair string) ([]me.Trade, int64) - ClearOrderBook(pair string) - ClearOrderChanges() - StoreTradePrices(ctx sdk.Context) - ExpireOrders(ctx sdk.Context, blockTime time.Time, postAlloTransHandler TransferHandler) - MarkBreatheBlock(ctx sdk.Context, height int64, blockTime time.Time) - GetBreatheBlockHeight(ctx sdk.Context, timeNow time.Time, daysBack int) (int64, error) - GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeight int64, timeNow time.Time, blockInterval, daysBack int) int64 - DelistTradingPair(ctx sdk.Context, symbol string, postAllocTransHandler TransferHandler) - CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error - CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error - SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) - LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight int64, timeOfLatestBlock time.Time, blockInterval, daysBack int) (int64, error) - GetPairMapper() store.TradingPairMapper - GetOrderChanges(pairType SymbolPairType) OrderChanges - GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPublish - GetAllOrders() map[string]map[string]*OrderInfo - GetAllOrdersForPair(symbol string) map[string]*OrderInfo - getAccountKeeper() *auth.AccountKeeper - getLogger() tmlog.Logger - getFeeManager() *FeeManager - GetEngines() map[string]*me.MatchEng - ShouldPublishOrder() bool - UpdateOrderChange(change OrderChange, symbol string) - UpdateOrderChangeSync(change OrderChange, symbol string) - ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error - SelectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string - ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) -} - type DexKeeper struct { PairMapper store.TradingPairMapper storeKey sdk.StoreKey // The key used to access the store from the Context. @@ -107,8 +62,6 @@ type DexKeeper struct { OrderKeepers []IDexOrderKeeper } -var _ IDexKeeper = &DexKeeper{} - func NewDexKeeper(key sdk.StoreKey, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, cdc *wire.Codec, am auth.AccountKeeper, collectOrderInfoForPublish bool, concurrency uint) *DexKeeper { logger := bnclog.With("module", "dex_keeper") return &DexKeeper{ @@ -132,6 +85,15 @@ func (kp *DexKeeper) SetBUSDSymbol(symbol string) { BUSDSymbol = symbol } +func (kp *DexKeeper) GetSupportedOrderKeeper(pair string) (IDexOrderKeeper, error) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(pair) { + return orderKeeper, nil + } + } + return nil, fmt.Errorf("failed to find orderKeeper for symbol pair [%v]", pair) +} + func (kp *DexKeeper) InitRecentPrices(ctx sdk.Context) { kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) } @@ -216,11 +178,10 @@ func (kp *DexKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { symbol := strings.ToUpper(pair.GetSymbol()) eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) kp.engines[symbol] = eng - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.initOrders(symbol) - break - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + dexOrderKeeper.initOrders(symbol) + } else { + kp.logger.Error(err.Error()) } return eng } @@ -239,11 +200,10 @@ func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { return err } - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) - break - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + dexOrderKeeper.addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) + } else { + kp.logger.Error(err.Error()) } kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) @@ -256,10 +216,10 @@ func orderNotFound(symbol, id string) error { func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { symbol = strings.ToUpper(symbol) - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - return orderKeeper.removeOrder(kp, id, symbol, postCancelHandler) - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + return dexOrderKeeper.removeOrder(kp, id, symbol, postCancelHandler) + } else { + kp.logger.Debug(err.Error()) } return orderNotFound(symbol, id) } @@ -278,10 +238,10 @@ func (kp *DexKeeper) GetOrder(id string, symbol string, side int8, price int64) } func (kp *DexKeeper) OrderExists(symbol, id string) (OrderInfo, bool) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - return orderKeeper.orderExists(symbol, id) - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + return dexOrderKeeper.orderExists(symbol, id) + } else { + kp.logger.Debug(err.Error()) } return OrderInfo{}, false } @@ -355,11 +315,10 @@ func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) (orderbook [ j++ }) var roundOrders []string - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(pair) { - roundOrders = orderKeeper.getRoundOrdersForPair(pair) - break - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(pair); err != nil { + roundOrders = dexOrderKeeper.getRoundOrdersForPair(pair) + } else { + kp.logger.Error(err.Error()) } pendingMatch = len(roundOrders) > 0 @@ -368,10 +327,10 @@ func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) (orderbook [ } func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(pair) { - return orderKeeper.getOpenOrders(pair, addr) - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(pair); err != nil { + return dexOrderKeeper.getOpenOrders(pair, addr) + } else { + kp.logger.Debug(err.Error()) } return make([]store.OpenOrder, 0) } @@ -923,11 +882,11 @@ func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAlloc func (kp *DexKeeper) expireAllOrders(ctx sdk.Context, symbol string) []chan Transfer { ordersOfSymbol := make(map[string]*OrderInfo) - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - ordersOfSymbol = orderKeeper.getAllOrdersForPair(symbol) - break - } + + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + ordersOfSymbol = dexOrderKeeper.getAllOrdersForPair(symbol) + } else { + kp.logger.Debug(err.Error()) } orderNum := len(ordersOfSymbol) @@ -1025,29 +984,27 @@ func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo { ordersOfSymbol := make(map[string]*OrderInfo) - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - ordersOfSymbol = orderKeeper.getAllOrdersForPair(symbol) - break - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + ordersOfSymbol = dexOrderKeeper.getAllOrdersForPair(symbol) + } else { + kp.logger.Debug(err.Error()) } return ordersOfSymbol } func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) - return - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + dexOrderKeeper.reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) + } else { + kp.logger.Error(err.Error()) } } func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(msg.Symbol) { - return orderKeeper.validateOrder(kp, context, account, msg) - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(msg.Symbol); err != nil { + return dexOrderKeeper.validateOrder(kp, context, account, msg) + } else { + kp.logger.Debug(err.Error()) } return fmt.Errorf("symbol:%s is not supported", msg.Symbol) } @@ -1073,11 +1030,11 @@ func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { } func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.appendOrderChangeSync(change) - return - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + dexOrderKeeper.appendOrderChangeSync(change) + return + } else { + kp.logger.Debug(err.Error()) } kp.logger.Error("symbol is not supported %d", symbol) } @@ -1090,7 +1047,6 @@ func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPu } kp.logger.Error("pairType is not supported %d", pairType) return make(OrderInfoForPublish) - } func (kp *DexKeeper) RemoveOrderInfosForPub(pairType SymbolPairType, orderId string) { diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 160eea57f..e19612ed2 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -1,6 +1,7 @@ package order import ( + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/fees" @@ -110,9 +111,18 @@ func (kp *DexKeeper) matchAndDistributeTradesForSymbol(symbol string, orderKeepe engine := kp.engines[symbol] concurrency := len(tradeOuts) orders := orderKeeper.getAllOrdersForPair(symbol) + var lastMatchHeight int64 + if dexUtils.IsMiniTokenTradingPair(symbol) { + lastMatchHeight = engine.LastMatchHeight + } else { + lastMatchHeight = height - 1 //Every block is deemed as performed matching for all BEP2 symbols + } // please note there is no logging in matching, expecting to see the order book details // from the exchange's order book stream. - if engine.Match(height, dexUtils.IsMiniTokenTradingPair(symbol)) { + if engine.Match(height, lastMatchHeight) { + if sdk.IsUpgrade(upgrade.BEP19) { + engine.LastMatchHeight = height + } kp.logger.Debug("Match finish:", "symbol", symbol, "lastTradePrice", engine.LastTradePrice) for i := range engine.Trades { t := &engine.Trades[i] @@ -139,6 +149,9 @@ func (kp *DexKeeper) matchAndDistributeTradesForSymbol(symbol string, orderKeepe // for index service. kp.logger.Error("Fatal error occurred in matching, cancel all incoming new orders", "symbol", symbol) + if sdk.IsUpgrade(upgrade.BEP19) { + engine.LastMatchHeight = height + } thisRoundIds := orderKeeper.getRoundOrdersForPair(symbol) for _, id := range thisRoundIds { msg := orders[id] From ff04b92a90194279cba37a7f2b91f07951f3a95a Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 15 May 2020 16:50:14 +0800 Subject: [PATCH 49/96] refactor --- integration_test.sh | 2 +- networks/demo/multi_send.exp | 3 ++- networks/publisher/list_mini.sh | 2 +- plugins/dex/matcheng/match_new_test.go | 4 ++-- plugins/dex/order/keeper.go | 22 +++++++++++----------- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/integration_test.sh b/integration_test.sh index bca3c9252..84d49dc0b 100755 --- a/integration_test.sh +++ b/integration_test.sh @@ -337,7 +337,7 @@ check_operation "Send Token" "${result}" "${chain_operation_words}" sleep 1s # multi send echo ${bob_addr} -result=$(expect ./multi_send.exp ${cli_home} alice ${chain_id} "[{\"to\":\"${bob_addr}\",\"amount\":\"10000000000:${mbc_symbol}\"},{\"to\":\"${alice_addr}\",\"amount\":\"1000000000:${mbc_symbol}\"}]") +result=$(expect ./multi_send.exp ${cli_home} alice ${chain_id} "[{\"to\":\"${bob_addr}\",\"amount\":\"10000000000:${mbc_symbol}\"},{\"to\":\"${alice_addr}\",\"amount\":\"1000000000:${mbc_symbol}\"}]" 1) check_operation "Multi Send Token" "${result}" "${chain_operation_words}" sleep 1s diff --git a/networks/demo/multi_send.exp b/networks/demo/multi_send.exp index 3f634f171..4e62bf174 100755 --- a/networks/demo/multi_send.exp +++ b/networks/demo/multi_send.exp @@ -4,9 +4,10 @@ set home [lindex $argv 0] set from [lindex $argv 1] set chain_id [lindex $argv 2] set tx [lindex $argv 3] +set memo [lindex $argv 4] set timeout 30 - spawn ./bnbcli token multi-send --home $home --from $from --chain-id=$chain_id --transfers $tx + spawn ./bnbcli token multi-send --home $home --from $from --chain-id=$chain_id --transfers $tx --memo $memo expect "Password*" send "12345678\r" interact diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index 560a0a974..000bb3e6e 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -25,7 +25,7 @@ scripthome="${src}/networks/publisher" ############################ END ########################## #X1Mini_symbol="X1Mini-ED3" -result=$(${cli} mini-token issue --from=zc --token-name="X1M Coin" --symbol=X1M --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) +result=$(${cli} token issue-mini --from=zc --token-name="X1M Coin" --symbol=X1M --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) X1Mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "X1M-[0-9A-Z]*") echo ${X1Mini_symbol} sleep 2 diff --git a/plugins/dex/matcheng/match_new_test.go b/plugins/dex/matcheng/match_new_test.go index be27e6d3e..4e4ac8be8 100644 --- a/plugins/dex/matcheng/match_new_test.go +++ b/plugins/dex/matcheng/match_new_test.go @@ -923,7 +923,7 @@ func TestMatchEng_Match(t *testing.T) { me.Book.InsertOrder("16", BUYSIDE, 100, 100, 20) upgrade.Mgr.SetHeight(100) - assert.True(me.Match(100, false)) + assert.True(me.Match(100, 99)) assert.Equal(4, len(me.overLappedLevel)) assert.Equal(int64(100), me.LastTradePrice) assert.Equal([]Trade{ @@ -979,7 +979,7 @@ func TestMatchEng_Match(t *testing.T) { me.Book.InsertOrder("6", BUYSIDE, 100, 110, 40) me.Book.InsertOrder("8", BUYSIDE, 100, 110, 100) - assert.True(me.Match(100, false)) + assert.True(me.Match(100, 99)) assert.Equal(4, len(me.overLappedLevel)) assert.Equal(int64(104), me.LastTradePrice) assert.Equal([]Trade{ diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 3bd17afa8..c5ffe0d0d 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -178,7 +178,7 @@ func (kp *DexKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { symbol := strings.ToUpper(pair.GetSymbol()) eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) kp.engines[symbol] = eng - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { dexOrderKeeper.initOrders(symbol) } else { kp.logger.Error(err.Error()) @@ -200,7 +200,7 @@ func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { return err } - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { dexOrderKeeper.addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) } else { kp.logger.Error(err.Error()) @@ -216,7 +216,7 @@ func orderNotFound(symbol, id string) error { func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { symbol = strings.ToUpper(symbol) - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { return dexOrderKeeper.removeOrder(kp, id, symbol, postCancelHandler) } else { kp.logger.Debug(err.Error()) @@ -238,7 +238,7 @@ func (kp *DexKeeper) GetOrder(id string, symbol string, side int8, price int64) } func (kp *DexKeeper) OrderExists(symbol, id string) (OrderInfo, bool) { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { return dexOrderKeeper.orderExists(symbol, id) } else { kp.logger.Debug(err.Error()) @@ -315,7 +315,7 @@ func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) (orderbook [ j++ }) var roundOrders []string - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(pair); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(pair); err == nil { roundOrders = dexOrderKeeper.getRoundOrdersForPair(pair) } else { kp.logger.Error(err.Error()) @@ -327,7 +327,7 @@ func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) (orderbook [ } func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(pair); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(pair); err == nil { return dexOrderKeeper.getOpenOrders(pair, addr) } else { kp.logger.Debug(err.Error()) @@ -883,7 +883,7 @@ func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAlloc func (kp *DexKeeper) expireAllOrders(ctx sdk.Context, symbol string) []chan Transfer { ordersOfSymbol := make(map[string]*OrderInfo) - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { ordersOfSymbol = dexOrderKeeper.getAllOrdersForPair(symbol) } else { kp.logger.Debug(err.Error()) @@ -984,7 +984,7 @@ func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo { ordersOfSymbol := make(map[string]*OrderInfo) - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { ordersOfSymbol = dexOrderKeeper.getAllOrdersForPair(symbol) } else { kp.logger.Debug(err.Error()) @@ -993,7 +993,7 @@ func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo { } func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { dexOrderKeeper.reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) } else { kp.logger.Error(err.Error()) @@ -1001,7 +1001,7 @@ func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int } func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(msg.Symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(msg.Symbol); err == nil { return dexOrderKeeper.validateOrder(kp, context, account, msg) } else { kp.logger.Debug(err.Error()) @@ -1030,7 +1030,7 @@ func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { } func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err != nil { + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { dexOrderKeeper.appendOrderChangeSync(change) return } else { From acfa33f3cb2d02e680e2ff5c6e1882f35dabd4bc Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 18 May 2020 11:12:26 +0800 Subject: [PATCH 50/96] fix ut --- plugins/dex/list/msg_mini.go | 4 +-- plugins/dex/list/msg_mini_test.go | 50 ++++++++++++++++++++++++++++ plugins/dex/order/keeper_recovery.go | 2 +- 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 plugins/dex/list/msg_mini_test.go diff --git a/plugins/dex/list/msg_mini.go b/plugins/dex/list/msg_mini.go index b34f328e2..3980131a5 100644 --- a/plugins/dex/list/msg_mini.go +++ b/plugins/dex/list/msg_mini.go @@ -42,10 +42,10 @@ func (msg ListMiniMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidCoins("base token: " + err.Error()) } if len(msg.QuoteAssetSymbol) == 0 { - return sdk.ErrInvalidCoins("quote token is empty: " + err.Error()) + return sdk.ErrInvalidCoins("quote token is empty ") } if types.NativeTokenSymbol != msg.QuoteAssetSymbol && order.BUSDSymbol!= msg.QuoteAssetSymbol{ - return sdk.ErrInvalidCoins("quote token: " + err.Error()) + return sdk.ErrInvalidCoins("quote token is not valid ") } if msg.InitPrice <= 0 { return sdk.ErrInvalidCoins("price should be positive") diff --git a/plugins/dex/list/msg_mini_test.go b/plugins/dex/list/msg_mini_test.go new file mode 100644 index 000000000..1e7611d30 --- /dev/null +++ b/plugins/dex/list/msg_mini_test.go @@ -0,0 +1,50 @@ +package list + +import ( + "github.com/binance-chain/node/plugins/dex/order" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestMiniIdenticalBaseAssetAndQuoteAsset(t *testing.T) { + msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BTC-000M", 1000) + err := msg.ValidateBasic() + require.NotNil(t, err, "msg should be error") + require.Contains(t, err.Error(), "quote token is not valid") +} + +func TestMiniWrongBaseAssetSymbol(t *testing.T) { + msg := NewMiniMsg(sdk.AccAddress{}, "BTC", "BTC-000", 1000) + err := msg.ValidateBasic() + require.NotNil(t, err, "msg should be error") + require.Contains(t, err.Error(), "base token: suffixed mini-token symbol must contain a hyphen") +} + +func TestMiniWrongQuoteAssetSymbol(t *testing.T) { + msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "ETH-123", 1000) + err := msg.ValidateBasic() + require.NotNil(t, err, "msg should be error") + require.Contains(t, err.Error(), "quote token is not valid") +} + +func TestMiniWrongInitPrice(t *testing.T) { + msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BNB", -1000) + err := msg.ValidateBasic() + require.NotNil(t, err, "msg should be error") + require.Contains(t, err.Error(), "price should be positive") +} + +func TestMiniRightMsg(t *testing.T) { + msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BNB", 1000) + err := msg.ValidateBasic() + require.Nil(t, err, "msg should not be error") +} + +func TestMiniBUSDQuote(t *testing.T) { + order.BUSDSymbol = "BUSD-000" + msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BUSD-000", 1000) + err := msg.ValidateBasic() + require.Nil(t, err, "msg should not be error") +} diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index fc00dd1b7..fd451b315 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -239,7 +239,7 @@ func (kp *DexKeeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, st err := kp.RemoveOrder(msg.RefId, msg.Symbol, func(ord me.OrderPart) { if kp.CollectOrderInfoForPublish { bnclog.Debug("deleted order from order changes map", "orderId", msg.RefId, "isRecovery", true) - delete(kp.GetOrderInfosForPub(symbolPairType), msg.RefId) + kp.RemoveOrderInfosForPub(symbolPairType, msg.RefId) } }) if err != nil { From 6a86f029a3f25da058b131569e3e180a06f39d7e Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 18 May 2020 17:14:24 +0800 Subject: [PATCH 51/96] fix ut --- app/app.go | 6 +- app/app_pub_test.go | 4 +- app/apptest/match_allocation_test.go | 2 + app/helpers.go | 3 +- app/pub/keeper_pub_test.go | 4 +- app_test/abci_open_orders_test.go | 98 ++++++++++- app_test/utils_test.go | 22 ++- common/testutils/testutils.go | 8 +- plugins/dex/list/handler_mini_test.go | 104 +++++++++++ plugins/dex/list/msg_mini_test.go | 14 +- plugins/dex/order/fee_test.go | 164 ++++++++++++------ plugins/dex/order/keeper.go | 2 +- plugins/dex/order/keeper_test.go | 95 ++++++++++ plugins/param/plugin.go | 2 +- plugins/tokens/client/cli/seturi_mini.go | 4 +- plugins/tokens/route.go | 4 +- .../tokens/{seturi_mini => seturi}/handler.go | 2 +- .../{seturi_mini => seturi}/handler_test.go | 2 +- plugins/tokens/{seturi_mini => seturi}/msg.go | 2 +- plugins/tokens/wire.go | 4 +- 20 files changed, 461 insertions(+), 85 deletions(-) create mode 100644 plugins/dex/list/handler_mini_test.go rename plugins/tokens/{seturi_mini => seturi}/handler.go (98%) rename plugins/tokens/{seturi_mini => seturi}/handler_test.go (99%) rename plugins/tokens/{seturi_mini => seturi}/msg.go (98%) diff --git a/app/app.go b/app/app.go index 53b52c2ee..701d76293 100644 --- a/app/app.go +++ b/app/app.go @@ -3,7 +3,6 @@ package app import ( "encoding/json" "fmt" - "github.com/binance-chain/node/plugins/tokens/issue" "io" "os" "runtime/debug" @@ -44,7 +43,8 @@ import ( "github.com/binance-chain/node/plugins/param" "github.com/binance-chain/node/plugins/param/paramhub" "github.com/binance-chain/node/plugins/tokens" - "github.com/binance-chain/node/plugins/tokens/seturi_mini" + "github.com/binance-chain/node/plugins/tokens/issue" + "github.com/binance-chain/node/plugins/tokens/seturi" tkstore "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" @@ -295,7 +295,7 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, issue.IssueMiniMsg{}.Type(), - seturi_mini.SetURIMsg{}.Type(), + seturi.SetURIMsg{}.Type(), list.ListMiniMsg{}.Type(), ) } diff --git a/app/app_pub_test.go b/app/app_pub_test.go index 786296a85..6fd8f2cc7 100644 --- a/app/app_pub_test.go +++ b/app/app_pub_test.go @@ -112,8 +112,8 @@ func setupAppTest(t *testing.T) (*assert.Assertions, *require.Assertions, *Binan keeper.FeeManager.FeeConfig.CancelFee = 12 keeper.FeeManager.FeeConfig.CancelFeeNative = 6 - _, buyerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 0, 0) // give user enough coins to pay the fee - _, sellerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 0, 0) + _, buyerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 0, 0, "XYZ-000") // give user enough coins to pay the fee + _, sellerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 0, 0, "XYZ-000") return assert.New(t), require.New(t), app, buyerAcc, sellerAcc } diff --git a/app/apptest/match_allocation_test.go b/app/apptest/match_allocation_test.go index 0d39725f7..5c9dbd936 100644 --- a/app/apptest/match_allocation_test.go +++ b/app/apptest/match_allocation_test.go @@ -127,6 +127,8 @@ func SetupTest(initPrices ...int64) (crypto.Address, sdk.Context, []sdk.Account) func SetupTest_new(initPrices ...int64) (crypto.Address, sdk.Context, []sdk.Account) { // for new match engine upgrade.Mgr.AddUpgradeHeight(upgrade.BEP19, -1) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, -1) addr := secp256k1.GenPrivKey().PubKey().Address() accAddr := sdk.AccAddress(addr) baseAcc := auth.BaseAccount{Address: accAddr} diff --git a/app/helpers.go b/app/helpers.go index cd8a0749c..a0bced910 100644 --- a/app/helpers.go +++ b/app/helpers.go @@ -29,6 +29,7 @@ import ( "github.com/binance-chain/node/common" bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/utils" + "github.com/binance-chain/node/plugins/dex" "github.com/binance-chain/node/plugins/dex/order" ) @@ -183,7 +184,7 @@ func (app *BinanceChain) getLastBreatheBlockHeight() int64 { } func (app *BinanceChain) reInitChain() error { - order.Init( + dex.InitOrders( app.DexKeeper, app.CheckState.Ctx, app.baseConfig.BreatheBlockInterval, diff --git a/app/pub/keeper_pub_test.go b/app/pub/keeper_pub_test.go index 5805d2c96..9afc12986 100644 --- a/app/pub/keeper_pub_test.go +++ b/app/pub/keeper_pub_test.go @@ -72,10 +72,10 @@ func setupKeeperTest(t *testing.T) (*assert.Assertions, *require.Assertions) { //keeper.FeeConfig.SetFeeRate(ctx, 1000) //keeper.FeeConfig.SetFeeRateNative(ctx, 500) - _, buyerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 100000000000, 100000000000) // give user enough coins to pay the fee + _, buyerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 100000000000, 100000000000, "XYZ-000") // give user enough coins to pay the fee buyer = buyerAcc.GetAddress() - _, sellerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 100000000000, 100000000000) + _, sellerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 100000000000, 100000000000, "XYZ-000") seller = sellerAcc.GetAddress() return assert.New(t), require.New(t) diff --git a/app_test/abci_open_orders_test.go b/app_test/abci_open_orders_test.go index 472352c70..2c5ef262e 100644 --- a/app_test/abci_open_orders_test.go +++ b/app_test/abci_open_orders_test.go @@ -18,8 +18,21 @@ import ( ) func Test_Success(t *testing.T) { - assert, require, pair := setup(t) + baseSymbol := "XYZ-000" + runTestSuccess(t, baseSymbol, true) +} + +func Test_Success_Before_Upgrade(t *testing.T) { + baseSymbol := "XYZ-000" + runTestSuccess(t, baseSymbol, false) +} +func Test_Success_Mini(t *testing.T) { + baseSymbol := "XYZ-000M" + runTestSuccess(t, baseSymbol, true) +} +func runTestSuccess(t *testing.T, symbol string, upgrade bool) { + assert, require, pair := setup(t, symbol, true) msg := orderPkg.NewNewOrderMsg(buyer, "b-1", orderPkg.Side.BUY, pair, 102000, 3000000) keeper.AddOrder(orderPkg.OrderInfo{msg, 100, 0, 100, 0, 0, "", 0}, false) @@ -59,15 +72,52 @@ func Test_Success(t *testing.T) { } func Test_InvalidPair(t *testing.T) { - assert, _, _ := setup(t) + setChainVersion() + defer resetChainVersion() + baseSymbol := "XYZ-000" + runInvalidPair(t, baseSymbol) +} + +func Test_InvalidPair_Before_Upgrade(t *testing.T) { + baseSymbol := "XYZ-000" + runInvalidPair(t, baseSymbol) +} +func Test_InvalidPair_Mini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + baseSymbol := "XYZ-000M" + runInvalidPair(t, baseSymbol) +} + +func runInvalidPair(t *testing.T, symbol string) { + assert, _, _ := setup(t, symbol, true) res := issueQuery("%afuiewf%@^&2blf", buyer.String()) assert.Equal(uint32(sdk.CodeInternal), res.Code) assert.Equal("pair is not valid", res.Log) } func Test_NonListedPair(t *testing.T) { - assert, _, _ := setup(t) + setChainVersion() + defer resetChainVersion() + baseSymbol := "XYZ-000" + runNonListedPair(t, baseSymbol) +} + +func Test_NonListedPair_Before_Upgrade(t *testing.T) { + baseSymbol := "XYZ-000" + runNonListedPair(t, baseSymbol) +} + +func Test_NonListedPair_Mini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + baseSymbol := "XYZ-000M" + runNonListedPair(t, baseSymbol) +} + +func runNonListedPair(t *testing.T, symbol string) { + assert, _, _ := setup(t, symbol, true) res := issueQuery("NNB-000_BNB", buyer.String()) assert.Equal(uint32(sdk.CodeInternal), res.Code) @@ -75,7 +125,26 @@ func Test_NonListedPair(t *testing.T) { } func Test_InvalidAddr(t *testing.T) { - assert, _, pair := setup(t) + setChainVersion() + defer resetChainVersion() + baseSymbol := "XYZ-000" + runInvalidAddr(t, baseSymbol) +} + +func Test_InvalidAddr_Before_Upgrade(t *testing.T) { + baseSymbol := "XYZ-000" + runInvalidAddr(t, baseSymbol) +} + +func Test_InvalidAddr_Mini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + baseSymbol := "XYZ-000M" + runInvalidAddr(t, baseSymbol) +} + +func runInvalidAddr(t *testing.T, symbol string) { + assert, _, pair := setup(t, symbol, true) res := issueQuery(pair, "%afuiewf%@^&2blf") assert.Equal(uint32(sdk.CodeInternal), res.Code) @@ -83,7 +152,26 @@ func Test_InvalidAddr(t *testing.T) { } func Test_NonExistAddr(t *testing.T) { - assert, _, pair := setup(t) + setChainVersion() + defer resetChainVersion() + baseSymbol := "XYZ-000" + runNonExistAddr(t, baseSymbol) +} + +func Test_NonExistAddr_Before_Upgrade(t *testing.T) { + baseSymbol := "XYZ-000" + runNonExistAddr(t, baseSymbol) +} + +func Test_NonExistAddr_Mini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + baseSymbol := "XYZ-000M" + runNonExistAddr(t, baseSymbol) +} + +func runNonExistAddr(t *testing.T, symbol string) { + assert, _, pair := setup(t, symbol, true) msg := orderPkg.NewNewOrderMsg(seller, "s-1", orderPkg.Side.SELL, pair, 102000, 3000000) keeper.AddOrder(orderPkg.OrderInfo{msg, 100, 0, 100, 0, 0, "", 0}, false) diff --git a/app_test/utils_test.go b/app_test/utils_test.go index d0d34e497..b3d3eae2a 100644 --- a/app_test/utils_test.go +++ b/app_test/utils_test.go @@ -2,6 +2,7 @@ package app_test import ( "fmt" + "github.com/binance-chain/node/common/upgrade" "os" "testing" @@ -33,8 +34,8 @@ var ( cdc *wire.Codec ) -func setup(t *testing.T) (ass *assert.Assertions, req *require.Assertions, pair string) { - baseAssetSymbol := "XYZ-000" +func setup(t *testing.T, symbol string, upgrade bool) (ass *assert.Assertions, req *require.Assertions, pair string) { + baseAssetSymbol := symbol logger := log.NewTMLogger(os.Stdout) db := dbm.NewMemDB() @@ -43,19 +44,32 @@ func setup(t *testing.T) (ass *assert.Assertions, req *require.Assertions, pair ctx = app.GetContextForCheckState() cdc = app.GetCodec() + if upgrade { + setChainVersion() + } + keeper = app.(*appPkg.BinanceChain).DexKeeper tradingPair := dextypes.NewTradingPair(baseAssetSymbol, types.NativeTokenSymbol, 1e8) keeper.PairMapper.AddTradingPair(ctx, tradingPair) keeper.AddEngine(tradingPair) am = app.(*appPkg.BinanceChain).AccountKeeper - _, buyerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 100000000000, 100000000000) // give user enough coins to pay the fee + _, buyerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 100000000000, 100000000000, symbol) // give user enough coins to pay the fee buyer = buyerAcc.GetAddress() - _, sellerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 100000000000, 100000000000) + _, sellerAcc := testutils.NewAccountForPub(ctx, am, 100000000000, 100000000000, 100000000000, symbol) seller = sellerAcc.GetAddress() pair = fmt.Sprintf("%s_%s", baseAssetSymbol, types.NativeTokenSymbol) return assert.New(t), require.New(t), pair } + +func setChainVersion() { + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, -1) +} + +func resetChainVersion() { + upgrade.Mgr.Config.HeightMap = nil +} diff --git a/common/testutils/testutils.go b/common/testutils/testutils.go index 09b9eaf2f..c85255808 100644 --- a/common/testutils/testutils.go +++ b/common/testutils/testutils.go @@ -79,19 +79,19 @@ func NewNamedAccount(ctx sdk.Context, am auth.AccountKeeper, free int64) (crypto return privKey, appAcc } -func NewAccountForPub(ctx sdk.Context, am auth.AccountKeeper, free, locked, freeze int64) (crypto.PrivKey, sdk.Account) { +func NewAccountForPub(ctx sdk.Context, am auth.AccountKeeper, free, locked, freeze int64, symbol string) (crypto.PrivKey, sdk.Account) { privKey, addr := PrivAndAddr() acc := am.NewAccountWithAddress(ctx, addr) coins := NewNativeTokens(free) - coins = append(coins, sdk.NewCoin("XYZ-000", free)) + coins = append(coins, sdk.NewCoin(symbol, free)) acc.SetCoins(coins) appAcc := acc.(*types.AppAccount) lockedCoins := NewNativeTokens(locked) - lockedCoins = append(lockedCoins, sdk.NewCoin("XYZ-000", locked)) + lockedCoins = append(lockedCoins, sdk.NewCoin(symbol, locked)) appAcc.SetLockedCoins(lockedCoins) freezeCoins := NewNativeTokens(freeze) - freezeCoins = append(freezeCoins, sdk.NewCoin("XYZ-000", freeze)) + freezeCoins = append(freezeCoins, sdk.NewCoin(symbol, freeze)) appAcc.SetFrozenCoins(freezeCoins) am.SetAccount(ctx, acc) return privKey, acc diff --git a/plugins/dex/list/handler_mini_test.go b/plugins/dex/list/handler_mini_test.go new file mode 100644 index 000000000..3b216e4bd --- /dev/null +++ b/plugins/dex/list/handler_mini_test.go @@ -0,0 +1,104 @@ +package list + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + tokenStore "github.com/binance-chain/node/plugins/tokens/store" +) + +func setChainVersion() { + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, -1) +} + +func resetChainVersion() { + upgrade.Mgr.Config.HeightMap = nil +} + +func setupForMini(ctx sdk.Context, tokenMapper tokenStore.Mapper, t *testing.T ){ + err := tokenMapper.NewToken(ctx, &types.Token{ + Name: "Bitcoin", + Symbol: "BTC-000", + OrigSymbol: "BTC", + TotalSupply: 10000, + Owner: sdk.AccAddress("testacc"), + }) + require.Nil(t, err, "new token error") + + err = tokenMapper.NewToken(ctx, &types.Token{ + Name: "Native Token", + Symbol: types.NativeTokenSymbol, + OrigSymbol: types.NativeTokenSymbol, + TotalSupply: 10000, + Owner: sdk.AccAddress("testacc"), + }) + require.Nil(t, err, "new token error") + + err = tokenMapper.NewToken(ctx, &types.Token{ + Name: "Bitcoin Mini", + Symbol: "BTC-000M", + OrigSymbol: "BTC", + TotalSupply: 10000, + Owner: sdk.AccAddress("testacc"), + }) + require.Nil(t, err, "new token error") + +} + +func TestHandleListMiniIdenticalSymbols(t *testing.T) { + setChainVersion() + defer resetChainVersion() + cdc := MakeCodec() + ms, orderKeeper, tokenMapper, _ := MakeKeepers(cdc) + ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) + setupForMini(ctx, tokenMapper, t) + result := handleListMini(ctx, orderKeeper, tokenMapper, ListMiniMsg{ + From: sdk.AccAddress("testacc"), + BaseAssetSymbol: "BTC-000M", + QuoteAssetSymbol: "BTC-000M", + InitPrice: 1000, + }) + require.Contains(t, result.Log, "base asset symbol should not be identical to quote asset symbol") +} + +func TestHandleListMiniWrongBaseSymbol(t *testing.T) { + setChainVersion() + defer resetChainVersion() + cdc := MakeCodec() + ms, orderKeeper, tokenMapper, _ := MakeKeepers(cdc) + ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) + setupForMini(ctx, tokenMapper, t) + result := handleListMini(ctx, orderKeeper, tokenMapper, ListMiniMsg{ + From: sdk.AccAddress("testacc"), + BaseAssetSymbol: "BTC", + QuoteAssetSymbol: "BNB", + InitPrice: 1000, + }) + //require.Equal(t, result.Code, sdk.ABCICodeOK) + require.Contains(t, result.Log, "token(BTC) not found") +} + +func TestHandleListMiniRight(t *testing.T) { + setChainVersion() + defer resetChainVersion() + cdc := MakeCodec() + ms, orderKeeper, tokenMapper, _ := MakeKeepers(cdc) + ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) + setupForMini(ctx, tokenMapper, t) + result := handleListMini(ctx, orderKeeper, tokenMapper, ListMiniMsg{ + From: sdk.AccAddress("testacc"), + BaseAssetSymbol: "BTC-000M", + QuoteAssetSymbol: "BNB", + InitPrice: 1000, + }) + require.Equal(t, result.Code, sdk.ABCICodeOK) +} diff --git a/plugins/dex/list/msg_mini_test.go b/plugins/dex/list/msg_mini_test.go index 1e7611d30..9abea5b44 100644 --- a/plugins/dex/list/msg_mini_test.go +++ b/plugins/dex/list/msg_mini_test.go @@ -22,6 +22,13 @@ func TestMiniWrongBaseAssetSymbol(t *testing.T) { require.Contains(t, err.Error(), "base token: suffixed mini-token symbol must contain a hyphen") } +func TestMiniWrongBaseAssetSymbolNotMiniToken(t *testing.T) { + msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000", "BTC-000", 1000) + err := msg.ValidateBasic() + require.NotNil(t, err, "msg should be error") + require.Contains(t, err.Error(), "base token: mini-token symbol suffix must be 4 chars in length, got 3") +} + func TestMiniWrongQuoteAssetSymbol(t *testing.T) { msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "ETH-123", 1000) err := msg.ValidateBasic() @@ -43,8 +50,13 @@ func TestMiniRightMsg(t *testing.T) { } func TestMiniBUSDQuote(t *testing.T) { - order.BUSDSymbol = "BUSD-000" msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BUSD-000", 1000) err := msg.ValidateBasic() + require.NotNil(t, err, "msg should be error") + require.Contains(t, err.Error(), "quote token is not valid") + + order.BUSDSymbol = "BUSD-000" + msg = NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BUSD-000", 1000) + err = msg.ValidateBasic() require.Nil(t, err, "msg should not be error") } diff --git a/plugins/dex/order/fee_test.go b/plugins/dex/order/fee_test.go index 4e40b26e6..1bb6333b1 100644 --- a/plugins/dex/order/fee_test.go +++ b/plugins/dex/order/fee_test.go @@ -3,8 +3,6 @@ package order import ( "testing" - "github.com/binance-chain/node/common/upgrade" - "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -28,34 +26,34 @@ func NewTestFeeConfig() FeeConfig { return feeConfig } -func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { +func feeManagerCalcTradeFeeForSingleTransfer(t *testing.T, symbol string){ ctx, am, keeper := setup() keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) - keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) + keeper.AddEngine(dextype.NewTradingPair(symbol, "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("BNB", "XYZ-111", 1e7)) _, acc := testutils.NewAccount(ctx, am, 0) tran := Transfer{ - inAsset: "ABC-000", + inAsset: symbol, in: 1000, outAsset: "BNB", out: 100, } // no enough bnb or native fee rounding to 0 fee := keeper.FeeManager.calcTradeFeeFromTransfer(acc.GetCoins(), &tran, keeper.engines) - require.Equal(t, sdk.Coins{{"ABC-000", 1}}, fee.Tokens) + require.Equal(t, sdk.Coins{{symbol, 1}}, fee.Tokens) _, acc = testutils.NewAccount(ctx, am, 100) fee = keeper.FeeManager.calcTradeFeeFromTransfer(acc.GetCoins(), &tran, keeper.engines) - require.Equal(t, sdk.Coins{{"ABC-000", 1}}, fee.Tokens) + require.Equal(t, sdk.Coins{{symbol, 1}}, fee.Tokens) tran = Transfer{ - inAsset: "ABC-000", + inAsset: symbol, in: 1000000, outAsset: "BNB", out: 10000, } _, acc = testutils.NewAccount(ctx, am, 1) fee = keeper.FeeManager.calcTradeFeeFromTransfer(acc.GetCoins(), &tran, keeper.engines) - require.Equal(t, sdk.Coins{{"ABC-000", 1000}}, fee.Tokens) + require.Equal(t, sdk.Coins{{symbol, 1000}}, fee.Tokens) _, acc = testutils.NewAccount(ctx, am, 100) fee = keeper.FeeManager.calcTradeFeeFromTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) @@ -63,7 +61,7 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { tran = Transfer{ inAsset: "BNB", in: 100, - outAsset: "ABC-000", + outAsset: symbol, out: 1000, } _, acc = testutils.NewAccount(ctx, am, 100) @@ -73,25 +71,25 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { tran = Transfer{ inAsset: "BNB", in: 10000, - outAsset: "ABC-000", + outAsset: symbol, out: 100000, } fee = keeper.FeeManager.calcTradeFeeFromTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) tran = Transfer{ - inAsset: "ABC-000", + inAsset: symbol, in: 100000, outAsset: "XYZ-111", out: 100000, } - acc.SetCoins(sdk.Coins{{"ABC-000", 1000000}, {"BNB", 100}}) + acc.SetCoins(sdk.Coins{{symbol, 1000000}, {"BNB", 100}}) fee = keeper.FeeManager.calcTradeFeeFromTransfer(acc.GetCoins(), &tran, keeper.engines) require.Equal(t, sdk.Coins{{"BNB", 5}}, fee.Tokens) tran = Transfer{ inAsset: "XYZ-111", in: 100000, - outAsset: "ABC-000", + outAsset: symbol, out: 100000, } acc.SetCoins(sdk.Coins{{"XYZ-111", 1000000}, {"BNB", 1000}}) @@ -99,7 +97,23 @@ func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { require.Equal(t, sdk.Coins{{"BNB", 500}}, fee.Tokens) } +func TestFeeManager_calcTradeFeeForSingleTransfer(t *testing.T) { + setChainVersion() + defer resetChainVersion() + symbol := "ABC-000" + feeManagerCalcTradeFeeForSingleTransfer(t, symbol) +} + +func TestFeeManager_calcTradeFeeForSingleTransferMini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + symbol := "ABC-000M" + feeManagerCalcTradeFeeForSingleTransfer(t, symbol) +} + func TestFeeManager_CalcTradesFee(t *testing.T) { + setChainVersion() + defer resetChainVersion() ctx, am, keeper := setup() keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) @@ -108,6 +122,7 @@ func TestFeeManager_CalcTradesFee(t *testing.T) { keeper.AddEngine(dextype.NewTradingPair("XYZ-111", "BTC", 2e4)) keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC", 5e5)) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "XYZ-111", 6e7)) + keeper.AddEngine(dextype.NewTradingPair("ZYX-000M", "BNB", 1e8)) tradeTransfers := TradeTransfers{ {inAsset: "ABC-000", outAsset: "BNB", Oid: "1", in: 1e5, out: 2e4, Trade: &matcheng.Trade{}}, @@ -120,40 +135,49 @@ func TestFeeManager_CalcTradesFee(t *testing.T) { {inAsset: "BNB", outAsset: "ABC-000", Oid: "8", in: 5e8, out: 60e8, Trade: &matcheng.Trade{}}, {inAsset: "ABC-000", outAsset: "BNB", Oid: "9", in: 7e6, out: 5e5, Trade: &matcheng.Trade{}}, {inAsset: "ABC-000", outAsset: "BTC", Oid: "10", in: 6e5, out: 8e1, Trade: &matcheng.Trade{}}, + {inAsset: "ZYX-000M", outAsset: "BNB", Oid: "11", in: 2e7, out: 2e6, Trade: &matcheng.Trade{}}, } _, acc := testutils.NewAccount(ctx, am, 0) _ = acc.SetCoins(sdk.Coins{ {"ABC-000", 100e8}, {"BNB", 15251400}, {"BTC", 10e8}, - {"XYZ-000", 100e8}, + {"XYZ-111", 100e8}, + {"ZYX-000M", 100e8}, }) fees := keeper.FeeManager.CalcTradesFee(acc.GetCoins(), tradeTransfers, keeper.engines) - require.Equal(t, "ABC-000:8000;BNB:15251305;BTC:100000;XYZ-111:2000", fees.String()) + require.Equal(t, "ABC-000:8000;BNB:15251305;BTC:100000;XYZ-111:2000;ZYX-000M:20000", fees.String()) require.Equal(t, "BNB:250000", tradeTransfers[0].Fee.String()) require.Equal(t, "BNB:15000000", tradeTransfers[1].Fee.String()) require.Equal(t, "BNB:10", tradeTransfers[2].Fee.String()) require.Equal(t, "BNB:250", tradeTransfers[3].Fee.String()) require.Equal(t, "BTC:100000", tradeTransfers[4].Fee.String()) require.Equal(t, "BNB:1000", tradeTransfers[5].Fee.String()) - require.Equal(t, "BNB:15", tradeTransfers[6].Fee.String()) - require.Equal(t, "BNB:30", tradeTransfers[7].Fee.String()) - require.Equal(t, "ABC-000:8000", tradeTransfers[8].Fee.String()) - require.Equal(t, "XYZ-111:2000", tradeTransfers[9].Fee.String()) + require.Equal(t, "ZYX-000M:20000", tradeTransfers[6].Fee.String()) + require.Equal(t, "BNB:15", tradeTransfers[7].Fee.String()) + require.Equal(t, "BNB:30", tradeTransfers[8].Fee.String()) + require.Equal(t, "ABC-000:8000", tradeTransfers[9].Fee.String()) + require.Equal(t, "XYZ-111:2000", tradeTransfers[10].Fee.String()) + require.Equal(t, sdk.Coins{ {"ABC-000", 100e8}, {"BNB", 15251400}, {"BTC", 10e8}, - {"XYZ-000", 100e8}, + {"XYZ-111", 100e8}, + {"ZYX-000M", 100e8}, }, acc.GetCoins()) } func TestFeeManager_CalcExpiresFee(t *testing.T) { + setChainVersion() + defer resetChainVersion() ctx, am, keeper := setup() keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) keeper.AddEngine(dextype.NewTradingPair("XYZ-111", "BNB", 2e7)) keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC", 5e5)) + keeper.AddEngine(dextype.NewTradingPair("ZYX-000M", "BNB", 1e8)) + // in BNB expireTransfers := ExpireTransfers{ @@ -167,6 +191,7 @@ func TestFeeManager_CalcExpiresFee(t *testing.T) { {inAsset: "BNB", Symbol: "ABC-000_BNB", Oid: "8"}, {inAsset: "ABC-000", Symbol: "ABC-000_BNB", Oid: "9"}, {inAsset: "ABC-000", Symbol: "ABC-000_BTC", Oid: "10"}, + {inAsset: "ZYX-000M", Symbol: "ZYX-000M_BTC", Oid: "11"}, } _, acc := testutils.NewAccount(ctx, am, 0) _ = acc.SetCoins(sdk.Coins{ @@ -174,9 +199,10 @@ func TestFeeManager_CalcExpiresFee(t *testing.T) { {"BNB", 120000}, {"BTC", 10e8}, {"XYZ-111", 800000}, + {"ZYX-000M", 900000}, }) fees := keeper.FeeManager.CalcExpiresFee(acc.GetCoins(), eventFullyExpire, expireTransfers, keeper.engines, nil) - require.Equal(t, "ABC-000:1000000;BNB:120000;BTC:500;XYZ-111:800000", fees.String()) + require.Equal(t, "ABC-000:1000000;BNB:120000;BTC:500;XYZ-111:800000;ZYX-000M:100000", fees.String()) require.Equal(t, "BNB:20000", expireTransfers[0].Fee.String()) require.Equal(t, "BNB:20000", expireTransfers[1].Fee.String()) require.Equal(t, "BNB:20000", expireTransfers[2].Fee.String()) @@ -187,18 +213,34 @@ func TestFeeManager_CalcExpiresFee(t *testing.T) { require.Equal(t, "BTC:500", expireTransfers[7].Fee.String()) require.Equal(t, "XYZ-111:500000", expireTransfers[8].Fee.String()) require.Equal(t, "XYZ-111:300000", expireTransfers[9].Fee.String()) + require.Equal(t, "ZYX-000M:100000", expireTransfers[10].Fee.String()) require.Equal(t, sdk.Coins{ {"ABC-000", 100e8}, {"BNB", 120000}, {"BTC", 10e8}, {"XYZ-111", 800000}, + {"ZYX-000M", 900000}, }, acc.GetCoins()) } -func TestFeeManager_CalcTradeFee(t *testing.T) { +func TestFeeManager_calcTradeFee(t *testing.T) { + setChainVersion() + defer resetChainVersion() + symbol := "ABC-000" + feeManagerCalcTradeFee(t, symbol) +} + +func TestFeeManager_calcTradeFeeMini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + symbol := "ABC-000M" + feeManagerCalcTradeFee(t, symbol) +} + +func feeManagerCalcTradeFee(t *testing.T, symbol string) { ctx, am, keeper := setup() keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) - keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) + keeper.AddEngine(dextype.NewTradingPair(symbol, "BNB", 1e7)) // BNB _, acc := testutils.NewAccount(ctx, am, 0) // the tradeIn amount is large enough to make the fee > 0 @@ -213,38 +255,54 @@ func TestFeeManager_CalcTradeFee(t *testing.T) { // !BNB _, acc = testutils.NewAccount(ctx, am, 100) // has enough bnb - tradeIn = sdk.NewCoin("ABC-000", 1000e8) + tradeIn = sdk.NewCoin(symbol, 1000e8) acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e8)}) fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 5e6)}, fee.Tokens) // no enough bnb acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e6)}) fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) - require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e8)}, fee.Tokens) + require.Equal(t, sdk.Coins{sdk.NewCoin(symbol, 1e8)}, fee.Tokens) // very high price to produce int64 overflow - keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e16)) + keeper.AddEngine(dextype.NewTradingPair(symbol, "BNB", 1e16)) // has enough bnb - tradeIn = sdk.NewCoin("ABC-000", 1000e8) + tradeIn = sdk.NewCoin(symbol, 1000e8) acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e16)}) fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 5e15)}, fee.Tokens) // no enough bnb, fee is within int64 acc.SetCoins(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 1e15)}) fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) - require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e8)}, fee.Tokens) + require.Equal(t, sdk.Coins{sdk.NewCoin(symbol, 1e8)}, fee.Tokens) // no enough bnb, even the fee overflows - tradeIn = sdk.NewCoin("ABC-000", 1e16) + tradeIn = sdk.NewCoin(symbol, 1e16) fee = keeper.FeeManager.CalcTradeFee(acc.GetCoins(), tradeIn, keeper.engines) - require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e13)}, fee.Tokens) + require.Equal(t, sdk.Coins{sdk.NewCoin(symbol, 1e13)}, fee.Tokens) } func TestFeeManager_CalcFixedFee(t *testing.T) { + setChainVersion() + defer resetChainVersion() + symbol1 := "ABC-000" + symbol2 := "BTC-000" + feeManagerCalcFixedFee(t, symbol1, symbol2) +} + +func TestFeeManager_CalcFixedFeeMini(t *testing.T) { + setChainVersion() + defer resetChainVersion() + symbol1 := "ABC-000M" + symbol2 := "BTC-000M" + feeManagerCalcFixedFee(t, symbol1, symbol2) +} + +func feeManagerCalcFixedFee(t *testing.T, symbol1 string, symbol2 string) { ctx, am, keeper := setup() keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) _, acc := testutils.NewAccount(ctx, am, 1e4) - keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1e7)) - keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC-000", 1e5)) + keeper.AddEngine(dextype.NewTradingPair(symbol1, "BNB", 1e7)) + keeper.AddEngine(dextype.NewTradingPair("BNB", symbol2, 1e5)) // in BNB // no enough BNB, but inAsset == BNB fee := keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, types.NativeTokenSymbol, keeper.engines) @@ -261,36 +319,37 @@ func TestFeeManager_CalcFixedFee(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2e4)}, fee.Tokens) // ABC-000_BNB, sell ABC-000 - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, symbol1, keeper.engines) require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2e4)}, fee.Tokens) // No enough native token, but enough ABC-000 - acc.SetCoins(sdk.Coins{{Denom: types.NativeTokenSymbol, Amount: 1e4}, {Denom: "ABC-000", Amount: 1e8}}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) - require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e6)}, fee.Tokens) + acc.SetCoins(sdk.Coins{{Denom: types.NativeTokenSymbol, Amount: 1e4}, {Denom: symbol1, Amount: 1e8}}) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, symbol1, keeper.engines) + require.Equal(t, sdk.Coins{sdk.NewCoin(symbol1, 1e6)}, fee.Tokens) // No enough native token and ABC-000 - acc.SetCoins(sdk.Coins{{Denom: types.NativeTokenSymbol, Amount: 1e4}, {Denom: "ABC-000", Amount: 1e5}}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) - require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e5)}, fee.Tokens) + acc.SetCoins(sdk.Coins{{Denom: types.NativeTokenSymbol, Amount: 1e4}, {Denom: symbol1, Amount: 1e5}}) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, symbol1, keeper.engines) + require.Equal(t, sdk.Coins{sdk.NewCoin(symbol1, 1e5)}, fee.Tokens) // BNB_BTC-000, sell BTC-000 - acc.SetCoins(sdk.Coins{{Denom: "BTC-000", Amount: 1e4}}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) - require.Equal(t, sdk.Coins{sdk.NewCoin("BTC-000", 1e2)}, fee.Tokens) + acc.SetCoins(sdk.Coins{{Denom: symbol2, Amount: 1e4}}) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, symbol2, keeper.engines) + require.Equal(t, sdk.Coins{sdk.NewCoin(symbol2, 1e2)}, fee.Tokens) // extreme prices - keeper.AddEngine(dextype.NewTradingPair("ABC-000", "BNB", 1)) - keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC-000", 1e16)) - acc.SetCoins(sdk.Coins{{Denom: "ABC-000", Amount: 1e16}, {Denom: "BTC-000", Amount: 1e16}}) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "ABC-000", keeper.engines) - require.Equal(t, sdk.Coins{sdk.NewCoin("ABC-000", 1e13)}, fee.Tokens) - fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, "BTC-000", keeper.engines) - require.Equal(t, sdk.Coins{sdk.NewCoin("BTC-000", 1e13)}, fee.Tokens) + keeper.AddEngine(dextype.NewTradingPair(symbol1, "BNB", 1)) + keeper.AddEngine(dextype.NewTradingPair("BNB", symbol2, 1e16)) + acc.SetCoins(sdk.Coins{{Denom: symbol1, Amount: 1e16}, {Denom: symbol2, Amount: 1e16}}) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, symbol1, keeper.engines) + require.Equal(t, sdk.Coins{sdk.NewCoin(symbol1, 1e13)}, fee.Tokens) + fee = keeper.FeeManager.CalcFixedFee(acc.GetCoins(), eventFullyExpire, symbol2, keeper.engines) + require.Equal(t, sdk.Coins{sdk.NewCoin(symbol2, 1e13)}, fee.Tokens) } func TestFeeManager_calcTradeFeeForSingleTransfer_SupportBUSD(t *testing.T) { - upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, -1) + setChainVersion() + defer resetChainVersion() ctx, am, keeper := setup() keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.SetBUSDSymbol("BUSD-BD1") @@ -383,7 +442,8 @@ func TestFeeManager_calcTradeFeeForSingleTransfer_SupportBUSD(t *testing.T) { } func TestFeeManager_CalcFixedFee_SupportBUSD(t *testing.T) { - upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, -1) + setChainVersion() + defer resetChainVersion() ctx, am, keeper := setup() keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.SetBUSDSymbol("BUSD-BD1") diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index c5ffe0d0d..cf6a65f6e 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -867,7 +867,7 @@ func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAlloc delete(kp.recentPrices, symbol) for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { + if orderKeeper.support(symbol) { orderKeeper.deleteOrdersForPair(symbol) break } diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index 71e31d206..26a681a8a 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -865,6 +865,64 @@ func TestKeeper_DelistTradingPair(t *testing.T) { require.Equal(t, expectFees, fees.Pool.BlockFees()) } +func TestKeeper_DelistMiniTradingPair(t *testing.T) { + setChainVersion() + defer resetChainVersion() + assert := assert.New(t) + ctx, am, keeper := setup() + fees.Pool.Clear() + keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) + _, acc := testutils.NewAccount(ctx, am, 0) + addr := acc.GetAddress() + + tradingPair := dextypes.NewTradingPair("XYZ-000M", "BNB", 1e8) + keeper.PairMapper.AddTradingPair(ctx, tradingPair) + keeper.AddEngine(tradingPair) + + acc.(types.NamedAccount).SetLockedCoins(sdk.Coins{ + sdk.NewCoin("BNB", 11e4), + sdk.NewCoin("XYZ-000M", 4e4), + }.Sort()) + + acc.(types.NamedAccount).SetCoins(sdk.Coins{ + sdk.NewCoin("XYZ-000M", 4e5), + }.Sort()) + + am.SetAccount(ctx, acc) + + msg := NewNewOrderMsg(addr, "123456", Side.BUY, "XYZ-000M_BNB", 1e6, 1e6) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + msg = NewNewOrderMsg(addr, "1234562", Side.BUY, "XYZ-000M_BNB", 1e6, 1e6) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + msg = NewNewOrderMsg(addr, "123457", Side.BUY, "XYZ-000M_BNB", 2e6, 1e6) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + msg = NewNewOrderMsg(addr, "123458", Side.BUY, "XYZ-000M_BNB", 3e6, 1e6) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + msg = NewNewOrderMsg(addr, "123459", Side.SELL, "XYZ-000M_BNB", 5e6, 1e4) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + msg = NewNewOrderMsg(addr, "123460", Side.SELL, "XYZ-000M_BNB", 6e6, 1e4) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + msg = NewNewOrderMsg(addr, "1234602", Side.SELL, "XYZ-000M_BNB", 6e6, 1e4) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + msg = NewNewOrderMsg(addr, "123461", Side.SELL, "XYZ-000M_BNB", 7e6, 1e4) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + msg = NewNewOrderMsg(addr, "123462", Side.BUY, "XYZ-000M_BNB", 4e6, 1e6) + keeper.AddOrder(OrderInfo{msg, 42, 84, 42, 84, 0, "", 0}, false) + assert.Equal(1, len(keeper.GetAllOrders())) + assert.Equal(9, len(keeper.GetAllOrdersForPair("XYZ-000M_BNB"))) + assert.Equal(1, len(keeper.engines)) + + keeper.DelistTradingPair(ctx, "XYZ-000M_BNB", nil) + assert.Equal(0, len(keeper.GetAllOrders())) + assert.Equal(0, len(keeper.engines)) + + expectFees := types.NewFee(sdk.Coins{ + sdk.NewCoin("BNB", 10e4), + sdk.NewCoin("XYZ-000M", 4e5), + }.Sort(), types.FeeForProposer) + require.Equal(t, expectFees, fees.Pool.BlockFees()) +} + // func TestKeeper_DelistTradingPair_Empty(t *testing.T) { assert := assert.New(t) @@ -954,6 +1012,7 @@ func TestKeeper_CanListTradingPair_SupportBUSD(t *testing.T) { // upgraded, but BNB-BUSD pair does not exist upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, -1) + keeper.SetBUSDSymbol("BUSD-BD1") err = keeper.CanListTradingPair(ctx, "AAA-000", "BUSD-BD1") require.NotNil(t, err) require.Contains(t, err.Error(), "token AAA-000 should be listed against BNB before against BUSD-BD1") @@ -1014,3 +1073,39 @@ func TestKeeper_CanDelistTradingPair_SupportBUSD(t *testing.T) { err = keeper.CanDelistTradingPair(ctx, "AAA-000", "XYZ-000") require.Nil(t, err) } + +func TestKeeper_CanDelistMiniTradingPair_SupportBUSD(t *testing.T) { + ctx, _, keeper := setup() + err := keeper.PairMapper.AddTradingPair(ctx, dextypes.NewTradingPair("AAA-000M", "BUSD-BD1", 1e8)) + err = keeper.CanDelistTradingPair(ctx, "AAA-000M", "BUSD-BD1") + require.Nil(t, err) + + err = keeper.PairMapper.AddTradingPair(ctx, dextypes.NewTradingPair("BUSD-BD1", "AAA-000M", 1e8)) + err = keeper.CanDelistTradingPair(ctx, "BUSD-BD1", "AAA-000M") + require.Nil(t, err) + + // delisting AAA-XYZ will not depends on BUSD-AAA or BUSD-XYZ + err = keeper.PairMapper.AddTradingPair(ctx, dextypes.NewTradingPair(types.NativeTokenSymbol, "AAA-000M", 1e8)) + err = keeper.PairMapper.AddTradingPair(ctx, dextypes.NewTradingPair(types.NativeTokenSymbol, "XYZ-000M", 1e8)) + err = keeper.PairMapper.AddTradingPair(ctx, dextypes.NewTradingPair("AAA-000M", "XYZ-000M", 1e8)) + err = keeper.CanDelistTradingPair(ctx, "AAA-000M", "XYZ-000M") + require.Nil(t, err) +} + +func TestKeeper_CanDelistMiniTradingPair(t *testing.T) { + ctx, _, keeper := setup() + err := keeper.PairMapper.AddTradingPair(ctx, dextypes.NewTradingPair("AAA-000M", types.NativeTokenSymbol, 1e8)) + err = keeper.PairMapper.AddTradingPair(ctx, dextypes.NewTradingPair("AAA-000M", "BUSD-BD1", 1e8)) + err = keeper.CanDelistTradingPair(ctx, "AAA-000M", types.NativeTokenSymbol) + err = keeper.CanDelistTradingPair(ctx, "AAA-000M", "BUSD-BD1") + require.Nil(t, err) +} + +func setChainVersion() { + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, -1) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, -1) +} + +func resetChainVersion() { + upgrade.Mgr.Config.HeightMap = nil +} diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 96fdf2f9c..a2a1a80ec 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -19,7 +19,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" - miniURI "github.com/binance-chain/node/plugins/tokens/seturi_mini" + miniURI "github.com/binance-chain/node/plugins/tokens/seturi" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" ) diff --git a/plugins/tokens/client/cli/seturi_mini.go b/plugins/tokens/client/cli/seturi_mini.go index 0bed7d51f..838f5643f 100644 --- a/plugins/tokens/client/cli/seturi_mini.go +++ b/plugins/tokens/client/cli/seturi_mini.go @@ -3,7 +3,7 @@ package commands import ( "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/tokens/seturi_mini" + "github.com/binance-chain/node/plugins/tokens/seturi" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -38,6 +38,6 @@ func (c Commander) setTokenURI(cmd *cobra.Command, args []string) error { return err } - msg := seturi_mini.NewSetUriMsg(from, symbol, tokenURI) + msg := seturi.NewSetUriMsg(from, symbol, tokenURI) return client.SendOrPrintTx(cliCtx, txBldr, msg) } diff --git a/plugins/tokens/route.go b/plugins/tokens/route.go index 82d91a7a5..37fd12913 100644 --- a/plugins/tokens/route.go +++ b/plugins/tokens/route.go @@ -1,7 +1,7 @@ package tokens import ( - "github.com/binance-chain/node/plugins/tokens/seturi_mini" + "github.com/binance-chain/node/plugins/tokens/seturi" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" @@ -23,6 +23,6 @@ func Routes(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank. routes[timelock.MsgRoute] = timelock.NewHandler(timeLockKeeper) routes[swap.AtomicSwapRoute] = swap.NewHandler(swapKeeper) routes[issue.MiniRoute] = issue.NewMiniHandler(tokenMapper, keeper) - routes[seturi_mini.SetURIRoute] = seturi_mini.NewHandler(tokenMapper) + routes[seturi.SetURIRoute] = seturi.NewHandler(tokenMapper) return routes } diff --git a/plugins/tokens/seturi_mini/handler.go b/plugins/tokens/seturi/handler.go similarity index 98% rename from plugins/tokens/seturi_mini/handler.go rename to plugins/tokens/seturi/handler.go index afc944dd9..fd2a599cc 100644 --- a/plugins/tokens/seturi_mini/handler.go +++ b/plugins/tokens/seturi/handler.go @@ -1,4 +1,4 @@ -package seturi_mini +package seturi import ( "fmt" diff --git a/plugins/tokens/seturi_mini/handler_test.go b/plugins/tokens/seturi/handler_test.go similarity index 99% rename from plugins/tokens/seturi_mini/handler_test.go rename to plugins/tokens/seturi/handler_test.go index 3bceb81a6..76389f6a1 100644 --- a/plugins/tokens/seturi_mini/handler_test.go +++ b/plugins/tokens/seturi/handler_test.go @@ -1,4 +1,4 @@ -package seturi_mini +package seturi import ( "github.com/binance-chain/node/plugins/tokens/issue" diff --git a/plugins/tokens/seturi_mini/msg.go b/plugins/tokens/seturi/msg.go similarity index 98% rename from plugins/tokens/seturi_mini/msg.go rename to plugins/tokens/seturi/msg.go index fc092e6af..8b0d9694e 100644 --- a/plugins/tokens/seturi_mini/msg.go +++ b/plugins/tokens/seturi/msg.go @@ -1,4 +1,4 @@ -package seturi_mini +package seturi import ( "encoding/json" diff --git a/plugins/tokens/wire.go b/plugins/tokens/wire.go index 064a9324d..4280f6d9c 100644 --- a/plugins/tokens/wire.go +++ b/plugins/tokens/wire.go @@ -4,7 +4,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" - "github.com/binance-chain/node/plugins/tokens/seturi_mini" + "github.com/binance-chain/node/plugins/tokens/seturi" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" "github.com/binance-chain/node/wire" @@ -25,5 +25,5 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(swap.ClaimHTLTMsg{}, "tokens/ClaimHTLTMsg", nil) cdc.RegisterConcrete(swap.RefundHTLTMsg{}, "tokens/RefundHTLTMsg", nil) cdc.RegisterConcrete(issue.IssueMiniMsg{}, "tokens/IssueMiniMsg", nil) - cdc.RegisterConcrete(seturi_mini.SetURIMsg{}, "tokens/SetURIMsg", nil) + cdc.RegisterConcrete(seturi.SetURIMsg{}, "tokens/SetURIMsg", nil) } From cd76c6e5130fae4bc240f4a5391da08d4a7d3189 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 19 May 2020 14:46:04 +0800 Subject: [PATCH 52/96] fix incompatibility --- app/pub/helpers.go | 17 ++++++++--------- plugins/dex/order/keeper.go | 8 +++++--- plugins/dex/order/order_keeper.go | 4 +++- plugins/tokens/client/cli/commands.go | 14 -------------- 4 files changed, 16 insertions(+), 27 deletions(-) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index ace09defe..374af2554 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -288,12 +288,12 @@ func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Contex close(iocExpireFeeHolderCh) tradeHeight := ctx.BlockHeight() - tradesToPublish, miniTradesToPublish := extractTradesToPublish(dexKeeper, ctx, tradeHeight) + tradesToPublish, miniTradesToPublish := extractTradesToPublish(dexKeeper, tradeHeight) wg.Wait() return tradesToPublish, miniTradesToPublish } -func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, tradeHeight int64) (tradesToPublish []*Trade, miniTradesToPublish []*Trade) { +func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, tradeHeight int64) (tradesToPublish []*Trade, miniTradesToPublish []*Trade) { tradesToPublish = make([]*Trade, 0, 32) miniTradesToPublish = make([]*Trade, 0, 32) tradeIdx := 0 @@ -520,10 +520,7 @@ func collectOrdersToPublish( timestamp int64, miniTrades []*Trade, miniOrderChanges orderPkg.OrderChanges, miniOrderInfos orderPkg.OrderInfoForPublish) (opensToPublish []*Order, closedToPublish []*Order, miniOpensToPublish []*Order, miniClosedToPublish []*Order, feeToPublish map[string]string) { - opensToPublish = make([]*Order, 0) - closedToPublish = make([]*Order, 0) - miniOpensToPublish = make([]*Order, 0) - miniClosedToPublish = make([]*Order, 0) + // serve as a cache to avoid fee's serialization several times for one address feeToPublish = make(map[string]string) @@ -534,8 +531,8 @@ func collectOrdersToPublish( chargedExpires := make(map[string]int) // collect orders (new, cancel, ioc-no-fill, expire, failed-blocking and failed-matching) from orderChanges - opensToPublish, closedToPublish = collectOrders(orderChanges, orderInfos, timestamp, opensToPublish, closedToPublish, chargedCancels, chargedExpires) - miniOpensToPublish, miniClosedToPublish = collectOrders(miniOrderChanges, miniOrderInfos, timestamp, miniOpensToPublish, miniClosedToPublish, chargedCancels, chargedExpires) + opensToPublish, closedToPublish = collectOrders(orderChanges, orderInfos, timestamp, chargedCancels, chargedExpires) + miniOpensToPublish, miniClosedToPublish = collectOrders(miniOrderChanges, miniOrderInfos, timestamp, chargedCancels, chargedExpires) // update C and E fields in serialized fee string updateCancelExpireOrderNum(closedToPublish, orderInfos, feeToPublish, chargedCancels, chargedExpires, feeHolder) @@ -595,7 +592,9 @@ func updateCancelExpireOrderNum(closedToPublish []*Order, orderInfos orderPkg.Or } } -func collectOrders(orderChanges orderPkg.OrderChanges, orderInfos orderPkg.OrderInfoForPublish, timestamp int64, opensToPublish []*Order, closedToPublish []*Order, chargedCancels map[string]int, chargedExpires map[string]int) ([]*Order, []*Order) { +func collectOrders(orderChanges orderPkg.OrderChanges, orderInfos orderPkg.OrderInfoForPublish, timestamp int64, chargedCancels map[string]int, chargedExpires map[string]int) ([]*Order, []*Order) { + opensToPublish := make([]*Order, 0) + closedToPublish := make([]*Order, 0) for _, o := range orderChanges { if orderInfo := o.ResolveOrderInfo(orderInfos); orderInfo != nil { orderToPublish := Order{ diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index cf6a65f6e..b2c7ab14e 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -200,10 +200,11 @@ func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { return err } - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { + if dexOrderKeeper, keeperNotFoundErr := kp.GetSupportedOrderKeeper(symbol); keeperNotFoundErr == nil { dexOrderKeeper.addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) } else { - kp.logger.Error(err.Error()) + //Should not happen. + kp.logger.Error(keeperNotFoundErr.Error()) } kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) @@ -219,6 +220,7 @@ func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler fun if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { return dexOrderKeeper.removeOrder(kp, id, symbol, postCancelHandler) } else { + //Leave it for debug. Return orderNotFound error for compatibility with the logic before BEP8 upgrade kp.logger.Debug(err.Error()) } return orderNotFound(symbol, id) @@ -973,7 +975,7 @@ func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset s } func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { - allOrders := make(map[string]map[string]*OrderInfo) //TODO replace by iterator + allOrders := make(map[string]map[string]*OrderInfo) for _, orderKeeper := range kp.OrderKeepers { if orderKeeper.supportUpgradeVersion() { allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) diff --git a/plugins/dex/order/order_keeper.go b/plugins/dex/order/order_keeper.go index c63401d42..52f5c7c1f 100644 --- a/plugins/dex/order/order_keeper.go +++ b/plugins/dex/order/order_keeper.go @@ -267,7 +267,6 @@ func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { } func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { - //TODO for symbol, orders := range kp.allOrders { for orderId := range orders { iter(symbol, orderId) @@ -278,6 +277,9 @@ func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { //------ BEP2OrderKeeper methods ----- func (kp *BEP2OrderKeeper) support(pair string) bool { + if !sdk.IsUpgrade(sdk.BEP8) { + return true + } return !dexUtils.IsMiniTokenTradingPair(pair) } diff --git a/plugins/tokens/client/cli/commands.go b/plugins/tokens/client/cli/commands.go index f3d8aba12..c1c9f19b0 100644 --- a/plugins/tokens/client/cli/commands.go +++ b/plugins/tokens/client/cli/commands.go @@ -61,18 +61,4 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { cmd.AddCommand(tokenCmd) - //miniTokenCmd := &cobra.Command{ - // Use: "mini-token", - // Short: "issue or update uri or view mini tokens", - // Long: ``, - //} - // - //miniTokenCmd.AddCommand( - // client.PostCommands( - // getMiniTokenInfoCmd(cmdr), - // issueMiniTokenCmd(cmdr), - // setTokenURICmd(cmdr))...) - // - //miniTokenCmd.AddCommand(client.LineBreak) - //cmd.AddCommand(miniTokenCmd) } From 8afd0ec17aef26421efcd3d163c13b1d8d801af0 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 19 May 2020 15:24:19 +0800 Subject: [PATCH 53/96] change dependency --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8a994ef3a..b902b01a8 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => /Users/luerheng/go/src/github.com/binance-chain/bnc-cosmos-sdk/ + github.com/cosmos/cosmos-sdk => github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200518113745-f65c39d47c64 github.com/tendermint/go-amino => github.com/binance-chain/bnc-go-amino v0.14.1-binance.2 github.com/tendermint/iavl => github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3 github.com/tendermint/tendermint => github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 diff --git a/go.sum b/go.sum index 92d3c70aa..099d6597b 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.20 h1:KwluEf2oheva5zdqeO/c/trvVFtrlYMyPXrCoTAAsTc= -github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.20/go.mod h1:Qd+w7Vm2WGxOqPquawShZ8KsHtA8PVDnx6XvZobloYg= +github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200518113745-f65c39d47c64 h1:Yj7cjdynPeThZBR7P5zyUaztzU0neuSjDXcBElSKHY0= +github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200518113745-f65c39d47c64/go.mod h1:Qd+w7Vm2WGxOqPquawShZ8KsHtA8PVDnx6XvZobloYg= github.com/binance-chain/bnc-go-amino v0.14.1-binance.2 h1:XcbcfisVItk92UKoGbtNT8nbcfadj3H3ayuM2srAfVs= github.com/binance-chain/bnc-go-amino v0.14.1-binance.2/go.mod h1:yaElUUxWtv/TC/ldGtlKAvS1vKwokxgJ1d97I+6is80= github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 h1:LDGvORYLSwsTEQM0W7yrbdgjrAZxQDe18WUTLNuFOEc= From 5e80b6fc9ab26ebbca5dbadf2ae9d41b6b064087 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 19 May 2020 15:33:27 +0800 Subject: [PATCH 54/96] format --- app_test/utils_test.go | 3 ++- common/fees/pool.go | 1 + common/types/token.go | 2 +- networks/tools/snapshot_viewer/snapshot.go | 2 +- plugins/api/server.go | 1 - plugins/dex/list/handler_mini_test.go | 20 ++++++++--------- plugins/dex/list/msg_mini.go | 3 ++- plugins/dex/list/msg_mini_test.go | 3 ++- plugins/dex/order/fee_test.go | 3 +-- plugins/dex/order/mini_keeper.go | 3 ++- plugins/param/plugin.go | 26 +++++++++++----------- plugins/tokens/burn/handler.go | 3 ++- plugins/tokens/burn/handler_test.go | 6 ++--- plugins/tokens/burn/msg.go | 1 + plugins/tokens/client/cli/helper.go | 3 +-- plugins/tokens/client/cli/info.go | 2 +- plugins/tokens/client/cli/issue_mini.go | 5 +++-- plugins/tokens/freeze/handler.go | 3 ++- plugins/tokens/freeze/msg.go | 1 + plugins/tokens/issue/handler_mini_test.go | 1 - plugins/tokens/issue/handler_test.go | 1 - plugins/tokens/issue/msg.go | 1 + plugins/tokens/issue/msg_mini.go | 1 + plugins/tokens/seturi/handler_test.go | 3 ++- plugins/tokens/seturi/msg.go | 1 + plugins/tokens/store/mapper.go | 2 +- plugins/tokens/store/mapper_mini.go | 2 -- 27 files changed, 55 insertions(+), 48 deletions(-) diff --git a/app_test/utils_test.go b/app_test/utils_test.go index b3d3eae2a..1a2bd38a5 100644 --- a/app_test/utils_test.go +++ b/app_test/utils_test.go @@ -2,10 +2,11 @@ package app_test import ( "fmt" - "github.com/binance-chain/node/common/upgrade" "os" "testing" + "github.com/binance-chain/node/common/upgrade" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/common/fees/pool.go b/common/fees/pool.go index b66280231..5192af6a9 100644 --- a/common/fees/pool.go +++ b/common/fees/pool.go @@ -2,6 +2,7 @@ package fees import ( "fmt" + "github.com/binance-chain/node/common/types" ) diff --git a/common/types/token.go b/common/types/token.go index 95c63f150..cffeb1c5d 100644 --- a/common/types/token.go +++ b/common/types/token.go @@ -65,7 +65,7 @@ func (token Token) GetTotalSupply() utils.Fixed8 { return token.TotalSupply } -func (token *Token) SetTotalSupply(totalSupply utils.Fixed8) { +func (token *Token) SetTotalSupply(totalSupply utils.Fixed8) { token.TotalSupply = totalSupply } diff --git a/networks/tools/snapshot_viewer/snapshot.go b/networks/tools/snapshot_viewer/snapshot.go index ef56bca9e..a79df3eb8 100644 --- a/networks/tools/snapshot_viewer/snapshot.go +++ b/networks/tools/snapshot_viewer/snapshot.go @@ -47,7 +47,7 @@ func prepareCms(root string, appDB *db.GoLevelDB) sdk.CommitMultiStore { keys := []store.StoreKey{ common.MainStoreKey, common.TokenStoreKey, common.DexStoreKey, common.PairStoreKey, common.GovStoreKey, common.StakeStoreKey, - common.ParamsStoreKey, common.ValAddrStoreKey, common.AccountStoreKey,} + common.ParamsStoreKey, common.ValAddrStoreKey, common.AccountStoreKey} cms := store.NewCommitMultiStore(appDB) for _, key := range keys { diff --git a/plugins/api/server.go b/plugins/api/server.go index 38f9ddf30..5e8523e1d 100644 --- a/plugins/api/server.go +++ b/plugins/api/server.go @@ -30,7 +30,6 @@ type server struct { tokens tkstore.Mapper accStoreName string - } // NewServer provides a new server structure. diff --git a/plugins/dex/list/handler_mini_test.go b/plugins/dex/list/handler_mini_test.go index 3b216e4bd..d2efa710b 100644 --- a/plugins/dex/list/handler_mini_test.go +++ b/plugins/dex/list/handler_mini_test.go @@ -24,7 +24,7 @@ func resetChainVersion() { upgrade.Mgr.Config.HeightMap = nil } -func setupForMini(ctx sdk.Context, tokenMapper tokenStore.Mapper, t *testing.T ){ +func setupForMini(ctx sdk.Context, tokenMapper tokenStore.Mapper, t *testing.T) { err := tokenMapper.NewToken(ctx, &types.Token{ Name: "Bitcoin", Symbol: "BTC-000", @@ -62,10 +62,10 @@ func TestHandleListMiniIdenticalSymbols(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) setupForMini(ctx, tokenMapper, t) result := handleListMini(ctx, orderKeeper, tokenMapper, ListMiniMsg{ - From: sdk.AccAddress("testacc"), - BaseAssetSymbol: "BTC-000M", + From: sdk.AccAddress("testacc"), + BaseAssetSymbol: "BTC-000M", QuoteAssetSymbol: "BTC-000M", - InitPrice: 1000, + InitPrice: 1000, }) require.Contains(t, result.Log, "base asset symbol should not be identical to quote asset symbol") } @@ -78,10 +78,10 @@ func TestHandleListMiniWrongBaseSymbol(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) setupForMini(ctx, tokenMapper, t) result := handleListMini(ctx, orderKeeper, tokenMapper, ListMiniMsg{ - From: sdk.AccAddress("testacc"), - BaseAssetSymbol: "BTC", + From: sdk.AccAddress("testacc"), + BaseAssetSymbol: "BTC", QuoteAssetSymbol: "BNB", - InitPrice: 1000, + InitPrice: 1000, }) //require.Equal(t, result.Code, sdk.ABCICodeOK) require.Contains(t, result.Log, "token(BTC) not found") @@ -95,10 +95,10 @@ func TestHandleListMiniRight(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) setupForMini(ctx, tokenMapper, t) result := handleListMini(ctx, orderKeeper, tokenMapper, ListMiniMsg{ - From: sdk.AccAddress("testacc"), - BaseAssetSymbol: "BTC-000M", + From: sdk.AccAddress("testacc"), + BaseAssetSymbol: "BTC-000M", QuoteAssetSymbol: "BNB", - InitPrice: 1000, + InitPrice: 1000, }) require.Equal(t, result.Code, sdk.ABCICodeOK) } diff --git a/plugins/dex/list/msg_mini.go b/plugins/dex/list/msg_mini.go index 3980131a5..bb73e10a9 100644 --- a/plugins/dex/list/msg_mini.go +++ b/plugins/dex/list/msg_mini.go @@ -3,6 +3,7 @@ package list import ( "encoding/json" "fmt" + "github.com/binance-chain/node/plugins/dex/order" sdk "github.com/cosmos/cosmos-sdk/types" @@ -44,7 +45,7 @@ func (msg ListMiniMsg) ValidateBasic() sdk.Error { if len(msg.QuoteAssetSymbol) == 0 { return sdk.ErrInvalidCoins("quote token is empty ") } - if types.NativeTokenSymbol != msg.QuoteAssetSymbol && order.BUSDSymbol!= msg.QuoteAssetSymbol{ + if types.NativeTokenSymbol != msg.QuoteAssetSymbol && order.BUSDSymbol != msg.QuoteAssetSymbol { return sdk.ErrInvalidCoins("quote token is not valid ") } if msg.InitPrice <= 0 { diff --git a/plugins/dex/list/msg_mini_test.go b/plugins/dex/list/msg_mini_test.go index 9abea5b44..f00bac767 100644 --- a/plugins/dex/list/msg_mini_test.go +++ b/plugins/dex/list/msg_mini_test.go @@ -1,9 +1,10 @@ package list import ( - "github.com/binance-chain/node/plugins/dex/order" "testing" + "github.com/binance-chain/node/plugins/dex/order" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) diff --git a/plugins/dex/order/fee_test.go b/plugins/dex/order/fee_test.go index 1bb6333b1..903bd89ea 100644 --- a/plugins/dex/order/fee_test.go +++ b/plugins/dex/order/fee_test.go @@ -26,7 +26,7 @@ func NewTestFeeConfig() FeeConfig { return feeConfig } -func feeManagerCalcTradeFeeForSingleTransfer(t *testing.T, symbol string){ +func feeManagerCalcTradeFeeForSingleTransfer(t *testing.T, symbol string) { ctx, am, keeper := setup() keeper.FeeManager.UpdateConfig(NewTestFeeConfig()) keeper.AddEngine(dextype.NewTradingPair(symbol, "BNB", 1e7)) @@ -178,7 +178,6 @@ func TestFeeManager_CalcExpiresFee(t *testing.T) { keeper.AddEngine(dextype.NewTradingPair("BNB", "BTC", 5e5)) keeper.AddEngine(dextype.NewTradingPair("ZYX-000M", "BNB", 1e8)) - // in BNB expireTransfers := ExpireTransfers{ {inAsset: "ABC-000", Symbol: "ABC-000_BNB", Oid: "1"}, diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index dd5d4f7b1..8ad3772a7 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -2,12 +2,13 @@ package order import ( "fmt" + "strings" + bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" dexUtils "github.com/binance-chain/node/plugins/dex/utils" sdk "github.com/cosmos/cosmos-sdk/types" - "strings" ) const ( diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index a2a1a80ec..99c1bc9df 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -81,7 +81,7 @@ func init() { // CalculatorsGen is defined in a common package which can't import app package. // Reasonable to init here, since fee param drive the calculator. fees.CalculatorsGen = map[string]fees.FeeCalculatorGenerator{ - gov.MsgSubmitProposal{}.Type(): fees.FixedFeeCalculatorGen, + gov.MsgSubmitProposal{}.Type(): fees.FixedFeeCalculatorGen, gov.MsgDeposit{}.Type(): fees.FixedFeeCalculatorGen, gov.MsgVote{}.Type(): fees.FixedFeeCalculatorGen, stake.MsgCreateValidator{}.Type(): fees.FixedFeeCalculatorGen, @@ -94,17 +94,17 @@ func init() { burn.BurnRoute: fees.FixedFeeCalculatorGen, account.SetAccountFlagsMsgType: fees.FixedFeeCalculatorGen, freeze.FreezeRoute: fees.FixedFeeCalculatorGen, - timelock.TimeLockMsg{}.Type(): fees.FixedFeeCalculatorGen, - timelock.TimeUnlockMsg{}.Type(): fees.FixedFeeCalculatorGen, - timelock.TimeRelockMsg{}.Type(): fees.FixedFeeCalculatorGen, - bank.MsgSend{}.Type(): tokens.TransferFeeCalculatorGen, - swap.HTLT: fees.FixedFeeCalculatorGen, - swap.DepositHTLT: fees.FixedFeeCalculatorGen, - swap.ClaimHTLT: fees.FixedFeeCalculatorGen, - swap.RefundHTLT: fees.FixedFeeCalculatorGen, - issue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, - issue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, - miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, - list.MiniRoute: fees.FixedFeeCalculatorGen, + timelock.TimeLockMsg{}.Type(): fees.FixedFeeCalculatorGen, + timelock.TimeUnlockMsg{}.Type(): fees.FixedFeeCalculatorGen, + timelock.TimeRelockMsg{}.Type(): fees.FixedFeeCalculatorGen, + bank.MsgSend{}.Type(): tokens.TransferFeeCalculatorGen, + swap.HTLT: fees.FixedFeeCalculatorGen, + swap.DepositHTLT: fees.FixedFeeCalculatorGen, + swap.ClaimHTLT: fees.FixedFeeCalculatorGen, + swap.RefundHTLT: fees.FixedFeeCalculatorGen, + issue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, + issue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, + miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, + list.MiniRoute: fees.FixedFeeCalculatorGen, } } diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 183c4efd4..0055dedda 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -2,10 +2,11 @@ package burn import ( "fmt" - "github.com/binance-chain/node/common/upgrade" "reflect" "strings" + "github.com/binance-chain/node/common/upgrade" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go index 28e072305..41c442698 100644 --- a/plugins/tokens/burn/handler_test.go +++ b/plugins/tokens/burn/handler_test.go @@ -1,9 +1,10 @@ package burn import ( + "testing" + "github.com/binance-chain/node/plugins/tokens/issue" "github.com/cosmos/cosmos-sdk/x/bank" - "testing" "github.com/binance-chain/node/common/upgrade" @@ -79,7 +80,7 @@ func TestHandleBurnMini(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 1e8 -1, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 1e8-1, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) @@ -124,7 +125,6 @@ func TestHandleBurn(t *testing.T) { sdkResult := issueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) - _, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NotNil(t, err) require.Contains(t, err.Error(), "token(NNB-000M) not found") diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index 4ec4e0988..6212c4485 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -3,6 +3,7 @@ package burn import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/plugins/tokens/client/cli/helper.go b/plugins/tokens/client/cli/helper.go index 7eca6e219..1fff5bb92 100644 --- a/plugins/tokens/client/cli/helper.go +++ b/plugins/tokens/client/cli/helper.go @@ -66,7 +66,6 @@ func parseAmount(amountStr string) (int64, error) { return amount, nil } - func validateTokenURI(uri string) error { if len(uri) > 2048 { return errors.New("uri cannot be longer than 2048 characters") @@ -80,4 +79,4 @@ func calcMiniTokenKey(symbol string) []byte { buf.WriteString(":") buf.WriteString(symbol) return buf.Bytes() -} \ No newline at end of file +} diff --git a/plugins/tokens/client/cli/info.go b/plugins/tokens/client/cli/info.go index d12536d66..b662dea5c 100644 --- a/plugins/tokens/client/cli/info.go +++ b/plugins/tokens/client/cli/info.go @@ -37,7 +37,7 @@ func (c Commander) runGetToken(cmd *cobra.Command, args []string) error { var key []byte if types.IsMiniTokenSymbol(symbol) { key = calcMiniTokenKey(strings.ToUpper(symbol)) - }else { + } else { key = []byte(strings.ToUpper(symbol)) } diff --git a/plugins/tokens/client/cli/issue_mini.go b/plugins/tokens/client/cli/issue_mini.go index cb92aa9b9..4688acb8f 100644 --- a/plugins/tokens/client/cli/issue_mini.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "github.com/binance-chain/node/plugins/tokens/issue" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -12,8 +13,8 @@ import ( ) const ( - flagTokenType = "token-type" - flagTokenUri = "token-uri" + flagTokenType = "token-type" + flagTokenUri = "token-uri" ) func issueMiniTokenCmd(cmdr Commander) *cobra.Command { diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 75bca78c7..ef38a5c2f 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -2,10 +2,11 @@ package freeze import ( "fmt" - "github.com/binance-chain/node/common/upgrade" "reflect" "strings" + "github.com/binance-chain/node/common/upgrade" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" diff --git a/plugins/tokens/freeze/msg.go b/plugins/tokens/freeze/msg.go index af5b7a396..8cd00314c 100644 --- a/plugins/tokens/freeze/msg.go +++ b/plugins/tokens/freeze/msg.go @@ -3,6 +3,7 @@ package freeze import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/plugins/tokens/issue/handler_mini_test.go b/plugins/tokens/issue/handler_mini_test.go index aa0f746f1..c55cd3215 100644 --- a/plugins/tokens/issue/handler_mini_test.go +++ b/plugins/tokens/issue/handler_mini_test.go @@ -80,7 +80,6 @@ func TestHandleIssueMiniToken(t *testing.T) { require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) } - func TestHandleMintMiniToken(t *testing.T) { setChainVersion() defer resetChainVersion() diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 60de41c14..1309416aa 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -107,4 +107,3 @@ func TestHandleMintToken(t *testing.T) { invalidMintMsg = NewMintMsg(acc.GetAddress(), "BNB", 10000e8) require.Contains(t, invalidMintMsg.ValidateBasic().Error(), "cannot mint native token") } - diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index 49ba2760e..adda2440b 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -3,6 +3,7 @@ package issue import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/plugins/tokens/issue/msg_mini.go b/plugins/tokens/issue/msg_mini.go index 6d10392c0..0dcc96b9f 100644 --- a/plugins/tokens/issue/msg_mini.go +++ b/plugins/tokens/issue/msg_mini.go @@ -3,6 +3,7 @@ package issue import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/plugins/tokens/seturi/handler_test.go b/plugins/tokens/seturi/handler_test.go index 76389f6a1..76131e69a 100644 --- a/plugins/tokens/seturi/handler_test.go +++ b/plugins/tokens/seturi/handler_test.go @@ -1,9 +1,10 @@ package seturi import ( + "testing" + "github.com/binance-chain/node/plugins/tokens/issue" "github.com/cosmos/cosmos-sdk/x/bank" - "testing" "github.com/binance-chain/node/common/upgrade" diff --git a/plugins/tokens/seturi/msg.go b/plugins/tokens/seturi/msg.go index 8b0d9694e..1b9037199 100644 --- a/plugins/tokens/seturi/msg.go +++ b/plugins/tokens/seturi/msg.go @@ -3,6 +3,7 @@ package seturi import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/plugins/tokens/store/mapper.go b/plugins/tokens/store/mapper.go index e1cba8b17..98600cab3 100644 --- a/plugins/tokens/store/mapper.go +++ b/plugins/tokens/store/mapper.go @@ -158,7 +158,7 @@ func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) var key []byte if types.IsMiniTokenSymbol(symbol) { key = m.calcMiniTokenKey(strings.ToUpper(symbol)) - }else { + } else { key = []byte(strings.ToUpper(symbol)) } store := ctx.KVStore(m.key) diff --git a/plugins/tokens/store/mapper_mini.go b/plugins/tokens/store/mapper_mini.go index 6a96d5d9d..9ac1e8735 100644 --- a/plugins/tokens/store/mapper_mini.go +++ b/plugins/tokens/store/mapper_mini.go @@ -10,7 +10,6 @@ import ( "github.com/binance-chain/node/common/types" ) - func (m mapper) UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) error { if len(symbol) == 0 { return errors.New("symbol cannot be empty") @@ -51,4 +50,3 @@ func (m mapper) calcMiniTokenKey(symbol string) []byte { buf.WriteString(symbol) return buf.Bytes() } - From bd69db36a41db72b1b799b49b944cedaba1c4723 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 19 May 2020 15:52:10 +0800 Subject: [PATCH 55/96] fmt --- app_test/utils_test.go | 3 +-- networks/tools/snapshot_viewer/snapshot.go | 1 + plugins/dex/list/msg_mini.go | 3 +-- plugins/dex/list/msg_mini_test.go | 5 +++-- plugins/dex/order/mini_keeper.go | 3 ++- plugins/tokens/burn/handler.go | 3 +-- plugins/tokens/burn/handler_test.go | 9 ++++----- plugins/tokens/burn/msg.go | 3 +-- plugins/tokens/client/cli/issue_mini.go | 2 +- plugins/tokens/freeze/handler.go | 3 +-- plugins/tokens/freeze/msg.go | 3 +-- plugins/tokens/issue/msg.go | 3 +-- plugins/tokens/issue/msg_mini.go | 3 +-- plugins/tokens/seturi/handler_test.go | 9 ++++----- plugins/tokens/seturi/msg.go | 3 +-- 15 files changed, 24 insertions(+), 32 deletions(-) diff --git a/app_test/utils_test.go b/app_test/utils_test.go index 1a2bd38a5..980b81d34 100644 --- a/app_test/utils_test.go +++ b/app_test/utils_test.go @@ -5,8 +5,6 @@ import ( "os" "testing" - "github.com/binance-chain/node/common/upgrade" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -19,6 +17,7 @@ import ( appPkg "github.com/binance-chain/node/app" "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" orderPkg "github.com/binance-chain/node/plugins/dex/order" dextypes "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/wire" diff --git a/networks/tools/snapshot_viewer/snapshot.go b/networks/tools/snapshot_viewer/snapshot.go index a79df3eb8..9b7a098c5 100644 --- a/networks/tools/snapshot_viewer/snapshot.go +++ b/networks/tools/snapshot_viewer/snapshot.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/go-amino" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/libs/db" diff --git a/plugins/dex/list/msg_mini.go b/plugins/dex/list/msg_mini.go index bb73e10a9..bc4494891 100644 --- a/plugins/dex/list/msg_mini.go +++ b/plugins/dex/list/msg_mini.go @@ -4,11 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/binance-chain/node/plugins/dex/order" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/dex/order" ) const MiniRoute = "dexListMini" diff --git a/plugins/dex/list/msg_mini_test.go b/plugins/dex/list/msg_mini_test.go index f00bac767..351406b70 100644 --- a/plugins/dex/list/msg_mini_test.go +++ b/plugins/dex/list/msg_mini_test.go @@ -3,10 +3,11 @@ package list import ( "testing" - "github.com/binance-chain/node/plugins/dex/order" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" + + "github.com/binance-chain/node/plugins/dex/order" ) func TestMiniIdenticalBaseAssetAndQuoteAsset(t *testing.T) { diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 8ad3772a7..bb6b9f0f9 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -4,11 +4,12 @@ import ( "fmt" "strings" + sdk "github.com/cosmos/cosmos-sdk/types" + bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" dexUtils "github.com/binance-chain/node/plugins/dex/utils" - sdk "github.com/cosmos/cosmos-sdk/types" ) const ( diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 0055dedda..d1392a67f 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -5,13 +5,12 @@ import ( "reflect" "strings" - "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/tokens/store" ) diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go index 41c442698..9a2d5e509 100644 --- a/plugins/tokens/burn/handler_test.go +++ b/plugins/tokens/burn/handler_test.go @@ -3,21 +3,20 @@ package burn import ( "testing" - "github.com/binance-chain/node/plugins/tokens/issue" - "github.com/cosmos/cosmos-sdk/x/bank" - - "github.com/binance-chain/node/common/upgrade" - "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/plugins/tokens/issue" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index 6212c4485..b8313f3e8 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -4,11 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" ) // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash diff --git a/plugins/tokens/client/cli/issue_mini.go b/plugins/tokens/client/cli/issue_mini.go index 4688acb8f..d1fbc1bfe 100644 --- a/plugins/tokens/client/cli/issue_mini.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -3,13 +3,13 @@ package commands import ( "fmt" - "github.com/binance-chain/node/plugins/tokens/issue" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/binance-chain/node/common/client" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/tokens/issue" ) const ( diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index ef38a5c2f..05a3ba4b6 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -5,14 +5,13 @@ import ( "reflect" "strings" - "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/tokens/store" ) diff --git a/plugins/tokens/freeze/msg.go b/plugins/tokens/freeze/msg.go index 8cd00314c..548cfc3f2 100644 --- a/plugins/tokens/freeze/msg.go +++ b/plugins/tokens/freeze/msg.go @@ -4,11 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" ) // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index adda2440b..027c9b363 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -4,11 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" ) // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash diff --git a/plugins/tokens/issue/msg_mini.go b/plugins/tokens/issue/msg_mini.go index 0dcc96b9f..9ea3ce71c 100644 --- a/plugins/tokens/issue/msg_mini.go +++ b/plugins/tokens/issue/msg_mini.go @@ -4,11 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" ) // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash diff --git a/plugins/tokens/seturi/handler_test.go b/plugins/tokens/seturi/handler_test.go index 76131e69a..fae25a3d5 100644 --- a/plugins/tokens/seturi/handler_test.go +++ b/plugins/tokens/seturi/handler_test.go @@ -3,21 +3,20 @@ package seturi import ( "testing" - "github.com/binance-chain/node/plugins/tokens/issue" - "github.com/cosmos/cosmos-sdk/x/bank" - - "github.com/binance-chain/node/common/upgrade" - "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/plugins/tokens/issue" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" ) diff --git a/plugins/tokens/seturi/msg.go b/plugins/tokens/seturi/msg.go index 1b9037199..960133591 100644 --- a/plugins/tokens/seturi/msg.go +++ b/plugins/tokens/seturi/msg.go @@ -4,11 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" ) const SetURIRoute = "miniTokensSetURI" From 69e6e6a06d4088fb050bcab5fdeddd0d7230a6e4 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 20 May 2020 14:47:00 +0800 Subject: [PATCH 56/96] reorder dex keeper param --- app/app.go | 2 +- app/pub/keeper_pub_test.go | 2 +- plugins/dex/list/handler_test.go | 3 +-- plugins/dex/order/handler_test.go | 2 +- plugins/dex/order/keeper.go | 2 +- plugins/dex/order/keeper_test.go | 5 ++--- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/app.go b/app/app.go index 701d76293..f4efda47c 100644 --- a/app/app.go +++ b/app/app.go @@ -317,7 +317,7 @@ func (app *BinanceChain) initRunningMode() { func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { - app.DexKeeper = dex.NewDexKeeper(common.DexStoreKey, pairMapper, app.RegisterCodespace(dex.DefaultCodespace), app.Codec, app.AccountKeeper, app.publicationConfig.ShouldPublishAny(), app.baseConfig.OrderKeeperConcurrency) + app.DexKeeper = dex.NewDexKeeper(common.DexStoreKey, app.AccountKeeper, pairMapper, app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec, app.publicationConfig.ShouldPublishAny()) app.DexKeeper.SubscribeParamChange(app.ParamHub) app.DexKeeper.SetBUSDSymbol(app.dexConfig.BUSDSymbol) diff --git a/app/pub/keeper_pub_test.go b/app/pub/keeper_pub_test.go index 9afc12986..d2167cf84 100644 --- a/app/pub/keeper_pub_test.go +++ b/app/pub/keeper_pub_test.go @@ -61,7 +61,7 @@ func setupKeeperTest(t *testing.T) (*assert.Assertions, *require.Assertions) { ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, logger).WithAccountCache(accountCache) pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) - keeper = orderPkg.NewDexKeeper(capKey2, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc, am, true, 2) + keeper = orderPkg.NewDexKeeper(capKey2, am, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, true) tradingPair := dextypes.NewTradingPair("XYZ-000", types.NativeTokenSymbol, 1e8) keeper.PairMapper.AddTradingPair(ctx, tradingPair) keeper.AddEngine(tradingPair) diff --git a/plugins/dex/list/handler_test.go b/plugins/dex/list/handler_test.go index c689ae06e..a8e4a2081 100644 --- a/plugins/dex/list/handler_test.go +++ b/plugins/dex/list/handler_test.go @@ -65,8 +65,7 @@ func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, dexKeeper *ord accKeeper := auth.NewAccountKeeper(cdc, accKey, types.ProtoAppAccount) codespacer := sdk.NewCodespacer() pairMapper := store.NewTradingPairMapper(cdc, pairKey) - dexKeeper = order.NewDexKeeper(common.DexStoreKey, pairMapper, - codespacer.RegisterNext(dexTypes.DefaultCodespace), cdc, accKeeper, false, 2) + dexKeeper = order.NewDexKeeper(common.DexStoreKey, accKeeper, pairMapper, codespacer.RegisterNext(dexTypes.DefaultCodespace), 2, cdc, false) tokenMapper = tokenStore.NewMapper(cdc, tokenKey) diff --git a/plugins/dex/order/handler_test.go b/plugins/dex/order/handler_test.go index ddde92c4a..535417852 100644 --- a/plugins/dex/order/handler_test.go +++ b/plugins/dex/order/handler_test.go @@ -41,7 +41,7 @@ func setupMappers() (store.TradingPairMapper, auth.AccountKeeper, sdk.Context, * accMapper := auth.NewAccountKeeper(cdc, key2, auth.ProtoBaseAccount) accountCache := getAccountCache(cdc, ms, key2) ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) - keeper := NewDexKeeper(key3, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc, accMapper, false, 2) + keeper := NewDexKeeper(key3, accMapper, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, false) return pairMapper, accMapper, ctx, keeper } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index b2c7ab14e..887f0d693 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -62,7 +62,7 @@ type DexKeeper struct { OrderKeepers []IDexOrderKeeper } -func NewDexKeeper(key sdk.StoreKey, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, cdc *wire.Codec, am auth.AccountKeeper, collectOrderInfoForPublish bool, concurrency uint) *DexKeeper { +func NewDexKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, concurrency uint, cdc *wire.Codec, collectOrderInfoForPublish bool) *DexKeeper { logger := bnclog.With("module", "dex_keeper") return &DexKeeper{ PairMapper: tradingPairMapper, diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index 26a681a8a..f368d8175 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -56,8 +56,7 @@ func MakeKeeper(cdc *wire.Codec) *DexKeeper { accKeeper := auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) codespacer := sdk.NewCodespacer() pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) - keeper := NewDexKeeper(common.DexStoreKey, pairMapper, codespacer.RegisterNext(dextypes.DefaultCodespace), - cdc, accKeeper, true, 2) + keeper := NewDexKeeper(common.DexStoreKey, accKeeper, pairMapper, codespacer.RegisterNext(dextypes.DefaultCodespace), 2, cdc, true) return keeper } @@ -551,7 +550,7 @@ func setup() (ctx sdk.Context, mapper auth.AccountKeeper, keeper *DexKeeper) { pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey) ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache) - keeper = NewDexKeeper(capKey2, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), cdc, mapper, false, 2) + keeper = NewDexKeeper(capKey2, mapper, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, false) return } From 30023584fd220d3b05626b0175d70455ad760f07 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 20 May 2020 15:33:10 +0800 Subject: [PATCH 57/96] seperate token classification and validation --- common/types/mini_token.go | 12 ++++++++++++ plugins/dex/store/mapper.go | 4 ++-- plugins/dex/store/utils.go | 2 +- plugins/tokens/burn/msg.go | 2 +- plugins/tokens/client/cli/helper.go | 2 +- plugins/tokens/client/cli/issue.go | 2 +- plugins/tokens/freeze/msg.go | 4 ++-- plugins/tokens/issue/handler_mini.go | 2 +- plugins/tokens/issue/msg.go | 2 +- 9 files changed, 22 insertions(+), 10 deletions(-) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 3df631838..c58f528d6 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -86,7 +86,19 @@ func NewMiniToken(name, symbol string, supplyRangeType int8, totalSupply int64, }, nil } +//check if it's mini token by last letter without validation func IsMiniTokenSymbol(symbol string) bool { + parts, err := splitSuffixedMiniTokenSymbol(symbol) + if err != nil { + return false + } + suffixPart := parts[1] + + return len(suffixPart) == MiniTokenSymbolSuffixLen && strings.HasSuffix(suffixPart, MiniTokenSymbolMSuffix) +} + +//Validate and check if it's mini token +func IsValidMiniTokenSymbol(symbol string) bool { if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { return false } diff --git a/plugins/dex/store/mapper.go b/plugins/dex/store/mapper.go index 51ba9c9da..04798385f 100644 --- a/plugins/dex/store/mapper.go +++ b/plugins/dex/store/mapper.go @@ -44,12 +44,12 @@ func NewTradingPairMapper(cdc *wire.Codec, key sdk.StoreKey) TradingPairMapper { func (m mapper) AddTradingPair(ctx sdk.Context, pair types.TradingPair) error { baseAsset := pair.BaseAssetSymbol quoteAsset := pair.QuoteAssetSymbol - if !cmn.IsMiniTokenSymbol(baseAsset) { + if !cmn.IsValidMiniTokenSymbol(baseAsset) { if err := cmn.ValidateMapperTokenSymbol(baseAsset); err != nil { return err } } - if !cmn.IsMiniTokenSymbol(quoteAsset) { + if !cmn.IsValidMiniTokenSymbol(quoteAsset) { if err := cmn.ValidateMapperTokenSymbol(quoteAsset); err != nil { return err } diff --git a/plugins/dex/store/utils.go b/plugins/dex/store/utils.go index b523bd70f..2f1bce529 100644 --- a/plugins/dex/store/utils.go +++ b/plugins/dex/store/utils.go @@ -25,7 +25,7 @@ func ValidatePairSymbol(symbol string) error { return errors.New("invalid symbol: trading pair must contain an underscore ('_')") } for _, tokenSymbol := range tokenSymbols { - if types.IsMiniTokenSymbol(tokenSymbol) { + if types.IsValidMiniTokenSymbol(tokenSymbol) { continue } if err := types.ValidateMapperTokenSymbol(tokenSymbol); err != nil { diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index b8313f3e8..3e0de28cc 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -42,7 +42,7 @@ func (msg BurnMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAdd // doesn't require access to any other information. func (msg BurnMsg) ValidateBasic() sdk.Error { - if sdk.IsUpgrade(upgrade.BEP8) && types.IsMiniTokenSymbol(msg.Symbol) { + if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") diff --git a/plugins/tokens/client/cli/helper.go b/plugins/tokens/client/cli/helper.go index 1fff5bb92..0de87bac8 100644 --- a/plugins/tokens/client/cli/helper.go +++ b/plugins/tokens/client/cli/helper.go @@ -33,7 +33,7 @@ func (c Commander) checkAndSendTx(cmd *cobra.Command, args []string, builder msg } symbol := viper.GetString(flagSymbol) - if !types.IsMiniTokenSymbol(symbol) { + if !types.IsValidMiniTokenSymbol(symbol) { err = types.ValidateMapperTokenSymbol(symbol) if err != nil { return err diff --git a/plugins/tokens/client/cli/issue.go b/plugins/tokens/client/cli/issue.go index b274c16c3..b24011f14 100644 --- a/plugins/tokens/client/cli/issue.go +++ b/plugins/tokens/client/cli/issue.go @@ -87,7 +87,7 @@ func (c Commander) mintToken(cmd *cobra.Command, args []string) error { symbol := viper.GetString(flagSymbol) amount := viper.GetInt64(flagAmount) - if types.IsMiniTokenSymbol(strings.ToUpper(symbol)) { + if types.IsValidMiniTokenSymbol(strings.ToUpper(symbol)) { err = checkMiniTokenSupplyAmount(amount) if err != nil { return err diff --git a/plugins/tokens/freeze/msg.go b/plugins/tokens/freeze/msg.go index 548cfc3f2..a534da456 100644 --- a/plugins/tokens/freeze/msg.go +++ b/plugins/tokens/freeze/msg.go @@ -42,7 +42,7 @@ func (msg FreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccA // doesn't require access to any other information. func (msg FreezeMsg) ValidateBasic() sdk.Error { - if sdk.IsUpgrade(upgrade.BEP8) && types.IsMiniTokenSymbol(msg.Symbol) { + if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") @@ -95,7 +95,7 @@ func (msg UnfreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.Ac func (msg UnfreezeMsg) ValidateBasic() sdk.Error { - if types.IsMiniTokenSymbol(msg.Symbol) { + if types.IsValidMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") diff --git a/plugins/tokens/issue/handler_mini.go b/plugins/tokens/issue/handler_mini.go index 712d664fb..ae7b1c25d 100644 --- a/plugins/tokens/issue/handler_mini.go +++ b/plugins/tokens/issue/handler_mini.go @@ -70,7 +70,7 @@ func handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper // the symbol is suffixed with the first n bytes of the tx hash symbol = fmt.Sprintf("%s-%s", symbol, suffix) - if !common.IsMiniTokenSymbol(symbol) { + if !common.IsValidMiniTokenSymbol(symbol) { logger.Info(errLogMsg, "reason", "symbol not valid") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) is not valid for mini-token", symbol)).Result() } diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index 027c9b363..e29a2b2a9 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -94,7 +94,7 @@ func NewMintMsg(from sdk.AccAddress, symbol string, amount int64) MintMsg { func (msg MintMsg) ValidateBasic() sdk.Error { - if sdk.IsUpgrade(upgrade.BEP8) && types.IsMiniTokenSymbol(msg.Symbol) { + if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } From b785df7e594cca475b70bbe7249bdc7278fc314d Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 20 May 2020 20:45:20 +0800 Subject: [PATCH 58/96] merge mini-trade/order into trade/order while publish --- app/app.go | 44 +++----- app/pub/helpers.go | 41 +++----- app/pub/keeper_pub_test.go | 11 +- app/pub/msgs.go | 24 +---- app/pub/publisher.go | 56 ++++------ app/pub/schemas.go | 4 +- app/pub/schemas/executionResults1.avsc | 138 ------------------------- app/pub/types.go | 38 +++---- cmd/pressuremaker/utils/utils.go | 4 - plugins/dex/order/keeper.go | 38 ++++++- plugins/dex/order/keeper_recovery.go | 3 +- 11 files changed, 107 insertions(+), 294 deletions(-) delete mode 100644 app/pub/schemas/executionResults1.avsc diff --git a/app/app.go b/app/app.go index f4efda47c..49b9cb583 100644 --- a/app/app.go +++ b/app/app.go @@ -537,10 +537,9 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a isBreatheBlock := app.isBreatheBlock(height, lastBlockTime, blockTime) var tradesToPublish []*pub.Trade - var miniTradesToPublish []*pub.Trade if sdk.IsUpgrade(upgrade.BEP19) || !isBreatheBlock { if app.publicationConfig.ShouldPublishAny() && pub.IsLive { - tradesToPublish, miniTradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, ctx, isBreatheBlock) + tradesToPublish = pub.MatchAndAllocateAllForPublish(app.DexKeeper, ctx, isBreatheBlock) } else { app.DexKeeper.MatchAndAllocateSymbols(ctx, nil, isBreatheBlock) } @@ -587,7 +586,7 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a var stakeUpdates pub.StakeUpdates stakeUpdates = pub.CollectStakeUpdatesForPublish(completedUbd) if height >= app.publicationConfig.FromHeightInclusive { - app.publish(tradesToPublish, miniTradesToPublish, &proposals, &stakeUpdates, blockFee, ctx, height, blockTime.UnixNano()) + app.publish(tradesToPublish, &proposals, &stakeUpdates, blockFee, ctx, height, blockTime.UnixNano()) } // clean up intermediate cached data @@ -773,21 +772,21 @@ func MakeCodec() *wire.Codec { return cdc } -func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPublish []*pub.Trade, proposalsToPublish *pub.Proposals, stakeUpdates *pub.StakeUpdates, blockFee pub.BlockFee, ctx sdk.Context, height, blockTime int64) { +func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublish *pub.Proposals, stakeUpdates *pub.StakeUpdates, blockFee pub.BlockFee, ctx sdk.Context, height, blockTime int64) { pub.Logger.Info("start to collect publish information", "height", height) var accountsToPublish map[string]pub.Account var transferToPublish *pub.Transfers var blockToPublish *pub.Block var latestPriceLevels order.ChangedPriceLevelsMap - var miniLatestPriceLevels order.ChangedPriceLevelsMap + + orderChanges := app.DexKeeper.GetAllOrderChanges() + orderInfoForPublish := app.DexKeeper.GetAllOrderInfosForPub() duration := pub.Timer(app.Logger, fmt.Sprintf("collect publish information, height=%d", height), func() { if app.publicationConfig.PublishAccountBalance { txRelatedAccounts := app.Pool.TxRelatedAddrs() - tradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, tradesToPublish, dex.PairType.BEP2) - miniTradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, miniTradesToPublish, dex.PairType.MINI) - tradeRelatedAccounts = append(tradeRelatedAccounts, miniTradeRelatedAccounts...) + tradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, tradesToPublish, orderChanges, orderInfoForPublish) accountsToPublish = pub.GetAccountBalances( app.AccountKeeper, ctx, @@ -805,8 +804,7 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli blockToPublish = pub.GetBlockPublished(app.Pool, header, blockHash) } if app.publicationConfig.PublishOrderBook { - latestPriceLevels = app.DexKeeper.GetOrderBooks(pub.MaxOrderBookLevel, dex.PairType.BEP2) - miniLatestPriceLevels = app.DexKeeper.GetOrderBooks(pub.MaxOrderBookLevel, dex.PairType.MINI) + latestPriceLevels = app.DexKeeper.GetOrderBooks(pub.MaxOrderBookLevel) } }) @@ -817,46 +815,34 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, miniTradesToPubli pub.Logger.Info("start to publish", "height", height, "blockTime", blockTime, "numOfTrades", len(tradesToPublish), "numOfOrders", // the order num we collected here doesn't include trade related orders - len(app.DexKeeper.GetOrderChanges(dex.PairType.BEP2)), - "numOfMiniTrades", len(miniTradesToPublish), - "numOfMiniOrders", // the order num we collected here doesn't include trade related orders - len(app.DexKeeper.GetOrderChanges(dex.PairType.MINI)), + len(orderChanges), "numOfProposals", proposalsToPublish.NumOfMsgs, "numOfStakeUpdates", stakeUpdates.NumOfMsgs, "numOfAccounts", len(accountsToPublish)) - pub.ToRemoveOrderIdCh = make(chan string, pub.ToRemoveOrderIdChannelSize) - pub.ToRemoveMiniOrderIdCh = make(chan string, pub.ToRemoveOrderIdChannelSize) + pub.ToRemoveOrderIdCh = make(chan pub.OrderSymbolId, pub.ToRemoveOrderIdChannelSize) pub.ToPublishCh <- pub.NewBlockInfoToPublish( height, blockTime, tradesToPublish, - miniTradesToPublish, proposalsToPublish, stakeUpdates, - app.DexKeeper.GetOrderChanges(dex.PairType.BEP2), // thread-safety is guarded by the signal from RemoveDoneCh - app.DexKeeper.GetOrderChanges(dex.PairType.MINI), - app.DexKeeper.GetOrderInfosForPub(dex.PairType.BEP2), // thread-safety is guarded by the signal from RemoveDoneCh - app.DexKeeper.GetOrderInfosForPub(dex.PairType.MINI), + orderChanges, // thread-safety is guarded by the signal from RemoveDoneCh + orderInfoForPublish, // thread-safety is guarded by the signal from RemoveDoneCh accountsToPublish, latestPriceLevels, - miniLatestPriceLevels, blockFee, app.DexKeeper.RoundOrderFees, //only use DexKeeper RoundOrderFees transferToPublish, blockToPublish) // remove item from OrderInfoForPublish when we published removed order (cancel, iocnofill, fullyfilled, expired) - for id := range pub.ToRemoveOrderIdCh { - pub.Logger.Debug("delete order from order changes map", "orderId", id) - app.DexKeeper.RemoveOrderInfosForPub(dex.PairType.BEP2, id) - } - for id := range pub.ToRemoveMiniOrderIdCh { - pub.Logger.Debug("delete mini order from order changes map", "orderId", id) - app.DexKeeper.RemoveOrderInfosForPub(dex.PairType.MINI, id) + for o := range pub.ToRemoveOrderIdCh { + pub.Logger.Debug("delete order from order changes map", "symbol", o.Symbol, "orderId", o.Id) + app.DexKeeper.RemoveOrderInfosForPub(o.Symbol, o.Id) } pub.Logger.Debug("finish publish", "height", height) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 374af2554..08dd08644 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -17,33 +17,31 @@ import ( "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/types" orderPkg "github.com/binance-chain/node/plugins/dex/order" - "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" abci "github.com/tendermint/tendermint/abci/types" ) -func GetTradeAndOrdersRelatedAccounts(kp *orderPkg.DexKeeper, tradesToPublish []*Trade, pairType orderPkg.SymbolPairType) []string { - res := make([]string, 0, len(tradesToPublish)*2+len(kp.GetOrderChanges(pairType))) - OrderInfosForPub := kp.GetOrderInfosForPub(pairType) +func GetTradeAndOrdersRelatedAccounts(kp *orderPkg.DexKeeper, tradesToPublish []*Trade, orderChanges orderPkg.OrderChanges, orderInfosForPublish orderPkg.OrderInfoForPublish) []string { + res := make([]string, 0, len(tradesToPublish)*2+len(kp.GetAllOrderChanges())) for _, t := range tradesToPublish { - if bo, ok := OrderInfosForPub[t.Bid]; ok { + if bo, ok := orderInfosForPublish[t.Bid]; ok { res = append(res, string(bo.Sender.Bytes())) } else { Logger.Error("failed to locate buy order in OrderChangesMap for trade account resolving", "bid", t.Bid) } - if so, ok := OrderInfosForPub[t.Sid]; ok { + if so, ok := orderInfosForPublish[t.Sid]; ok { res = append(res, string(so.Sender.Bytes())) } else { Logger.Error("failed to locate sell order in OrderChangesMap for trade account resolving", "sid", t.Sid) } } - for _, orderChange := range kp.GetOrderChanges(pairType) { - if orderInfo := OrderInfosForPub[orderChange.Id]; orderInfo != nil { + for _, orderChange := range orderChanges { + if orderInfo := orderInfosForPublish[orderChange.Id]; orderInfo != nil { res = append(res, string(orderInfo.Sender.Bytes())) } else { Logger.Error("failed to locate order change in OrderChangesMap", "orderChange", orderChange.String()) @@ -264,7 +262,7 @@ func GetAccountBalances(mapper auth.AccountKeeper, ctx sdk.Context, accSlices .. return } -func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, matchAllMiniSymbols bool) ([]*Trade, []*Trade) { +func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Context, matchAllMiniSymbols bool) []*Trade { // This channels is used for protect not update `dexKeeper.orderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) // while dexKeeper.orderChanges are not separated by concurrent factor (users here) @@ -288,14 +286,13 @@ func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Contex close(iocExpireFeeHolderCh) tradeHeight := ctx.BlockHeight() - tradesToPublish, miniTradesToPublish := extractTradesToPublish(dexKeeper, tradeHeight) + tradesToPublish := extractTradesToPublish(dexKeeper, tradeHeight) wg.Wait() - return tradesToPublish, miniTradesToPublish + return tradesToPublish } -func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, tradeHeight int64) (tradesToPublish []*Trade, miniTradesToPublish []*Trade) { +func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, tradeHeight int64) (tradesToPublish []*Trade) { tradesToPublish = make([]*Trade, 0, 32) - miniTradesToPublish = make([]*Trade, 0, 32) tradeIdx := 0 for symbol := range dexKeeper.GetEngines() { @@ -324,14 +321,10 @@ func extractTradesToPublish(dexKeeper *orderPkg.DexKeeper, tradeHeight int64) (t TickType: int(trade.TickType), } tradeIdx += 1 - if utils.IsMiniTokenTradingPair(symbol) { - miniTradesToPublish = append(miniTradesToPublish, t) - } else { - tradesToPublish = append(tradesToPublish, t) - } + tradesToPublish = append(tradesToPublish, t) } } - return tradesToPublish, miniTradesToPublish + return tradesToPublish } func ExpireOrdersForPublish( @@ -517,9 +510,7 @@ func collectOrdersToPublish( orderChanges orderPkg.OrderChanges, orderInfos orderPkg.OrderInfoForPublish, feeHolder orderPkg.FeeHolder, - timestamp int64, miniTrades []*Trade, - miniOrderChanges orderPkg.OrderChanges, - miniOrderInfos orderPkg.OrderInfoForPublish) (opensToPublish []*Order, closedToPublish []*Order, miniOpensToPublish []*Order, miniClosedToPublish []*Order, feeToPublish map[string]string) { + timestamp int64) (opensToPublish []*Order, closedToPublish []*Order, feeToPublish map[string]string) { // serve as a cache to avoid fee's serialization several times for one address feeToPublish = make(map[string]string) @@ -532,16 +523,14 @@ func collectOrdersToPublish( // collect orders (new, cancel, ioc-no-fill, expire, failed-blocking and failed-matching) from orderChanges opensToPublish, closedToPublish = collectOrders(orderChanges, orderInfos, timestamp, chargedCancels, chargedExpires) - miniOpensToPublish, miniClosedToPublish = collectOrders(miniOrderChanges, miniOrderInfos, timestamp, chargedCancels, chargedExpires) // update C and E fields in serialized fee string updateCancelExpireOrderNum(closedToPublish, orderInfos, feeToPublish, chargedCancels, chargedExpires, feeHolder) - updateCancelExpireOrderNum(miniClosedToPublish, miniOrderInfos, feeToPublish, chargedCancels, chargedExpires, feeHolder) + // update fee and collect orders from trades opensToPublish, closedToPublish = convertTradesToOrders(trades, orderInfos, timestamp, feeHolder, feeToPublish, opensToPublish, closedToPublish) - miniOpensToPublish, miniClosedToPublish = convertTradesToOrders(miniTrades, miniOrderInfos, timestamp, feeHolder, feeToPublish, miniOpensToPublish, miniClosedToPublish) - return opensToPublish, closedToPublish, miniOpensToPublish, miniClosedToPublish, feeToPublish + return opensToPublish, closedToPublish, feeToPublish } func convertTradesToOrders(trades []*Trade, orderInfos orderPkg.OrderInfoForPublish, timestamp int64, feeHolder orderPkg.FeeHolder, feeToPublish map[string]string, opensToPublish []*Order, closedToPublish []*Order) ([]*Order, []*Order) { diff --git a/app/pub/keeper_pub_test.go b/app/pub/keeper_pub_test.go index d2167cf84..ff9f1ad1b 100644 --- a/app/pub/keeper_pub_test.go +++ b/app/pub/keeper_pub_test.go @@ -120,12 +120,13 @@ func TestKeeper_IOCExpireWithFee(t *testing.T) { require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 1) require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 1) - trades, miniTrades := MatchAndAllocateAllForPublish(keeper, ctx, false) + trades := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 2) require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 1) require.Len(trades, 0) - require.Len(miniTrades, 0) + require.Len(keeper.GetAllOrderChanges(), 2) + require.Len(keeper.GetAllOrderInfosForPub(), 1) orderChange0 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[0] orderChange1 := keeper.GetOrderChanges(orderPkg.PairType.BEP2)[1] @@ -207,7 +208,7 @@ func Test_IOCPartialExpire(t *testing.T) { assert.Equal("s-1", orderChange1.Id) assert.Equal(orderPkg.Ack, orderChange1.Tpe) - trades, _ := MatchAndAllocateAllForPublish(keeper, ctx, false) + trades := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(keeper.GetOrderChanges(orderPkg.PairType.BEP2), 3) require.Len(keeper.GetOrderInfosForPub(orderPkg.PairType.BEP2), 2) @@ -247,7 +248,7 @@ func Test_GTEPartialExpire(t *testing.T) { assert.Equal("s-1", orderChange1.Id) assert.Equal(orderPkg.Ack, orderChange1.Tpe) - trades, _ := MatchAndAllocateAllForPublish(keeper, ctx, false) + trades := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(trades, 1) trade0 := trades[0] assert.Equal("0-0", trade0.Id) @@ -298,7 +299,7 @@ func Test_OneBuyVsTwoSell(t *testing.T) { assert.Equal("s-2", orderChange2.Id) assert.Equal(orderPkg.Ack, orderChange2.Tpe) - trades, _ := MatchAndAllocateAllForPublish(keeper, ctx, false) + trades := MatchAndAllocateAllForPublish(keeper, ctx, false) require.Len(trades, 2) trade0 := trades[0] assert.Equal("0-0", trade0.Id) diff --git a/app/pub/msgs.go b/app/pub/msgs.go index 4304087da..b97ca0897 100644 --- a/app/pub/msgs.go +++ b/app/pub/msgs.go @@ -55,7 +55,7 @@ func (this msgType) String() string { var latestSchemaVersions = map[msgType]int{ accountsTpe: 1, booksTpe: 0, - executionResultTpe: 2, + executionResultTpe: 1, blockFeeTpe: 0, transferTpe: 1, blockTpe: 0, @@ -98,8 +98,6 @@ type ExecutionResults struct { Orders Orders Proposals Proposals StakeUpdates StakeUpdates - MiniTrades trades - MiniOrders Orders } func (msg *ExecutionResults) String() string { @@ -123,21 +121,15 @@ func (msg *ExecutionResults) ToNativeMap() map[string]interface{} { if msg.StakeUpdates.NumOfMsgs > 0 { native["stakeUpdates"] = map[string]interface{}{"org.binance.dex.model.avro.StakeUpdates": msg.StakeUpdates.ToNativeMap()} } - if msg.MiniTrades.NumOfMsgs > 0 { - native["miniTrades"] = map[string]interface{}{"org.binance.dex.model.avro.Trades": msg.MiniTrades.ToNativeMap()} - } - if msg.MiniOrders.NumOfMsgs > 0 { - native["miniOrders"] = map[string]interface{}{"org.binance.dex.model.avro.Orders": msg.MiniOrders.ToNativeMap()} - } + return native } func (msg *ExecutionResults) EssentialMsg() string { // mainly used to recover for large breathe block expiring message, there should be no trade on breathe block orders := msg.Orders.EssentialMsg() - miniOrders := msg.MiniOrders.EssentialMsg() //TODO output other fields: trades, stakeUpdate etc. - return fmt.Sprintf("height:%d\ntime:%d\norders:\n%s\nminiOrders:\n%s\n", msg.Height, msg.Timestamp, orders, miniOrders) + return fmt.Sprintf("height:%d\ntime:%d\norders:\n%s\n", msg.Height, msg.Timestamp, orders) } func (msg *ExecutionResults) EmptyCopy() AvroOrJsonMsg { @@ -147,23 +139,15 @@ func (msg *ExecutionResults) EmptyCopy() AvroOrJsonMsg { nonExpiredOrders = append(nonExpiredOrders, order) } } - var nonExpiredMiniOrders []*Order - for _, order := range msg.MiniOrders.Orders { - if order.Status != orderPkg.Expired { - nonExpiredMiniOrders = append(nonExpiredMiniOrders, order) - } - } return &ExecutionResults{ msg.Height, msg.Timestamp, - msg.Proposals.NumOfMsgs + msg.StakeUpdates.NumOfMsgs + len(nonExpiredOrders) + len(nonExpiredMiniOrders), + msg.Proposals.NumOfMsgs + msg.StakeUpdates.NumOfMsgs + len(nonExpiredOrders), trades{}, // no trades on breathe block Orders{len(nonExpiredOrders), nonExpiredOrders}, msg.Proposals, msg.StakeUpdates, - trades{}, // no trades on breathe block - Orders{len(nonExpiredMiniOrders), nonExpiredMiniOrders}, } } diff --git a/app/pub/publisher.go b/app/pub/publisher.go index 7d8761a7a..bfd55f633 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -19,13 +19,17 @@ const ( MaxOrderBookLevel = 100 ) +type OrderSymbolId struct { + Symbol string + Id string +} + var ( - Logger tmlog.Logger - Cfg *config.PublicationConfig - ToPublishCh chan BlockInfoToPublish - ToRemoveOrderIdCh chan string // order ids to remove from keeper.OrderInfoForPublish - ToRemoveMiniOrderIdCh chan string // order ids to remove from keeper.miniOrderInfoForPublish - IsLive bool + Logger tmlog.Logger + Cfg *config.PublicationConfig + ToPublishCh chan BlockInfoToPublish + ToRemoveOrderIdCh chan OrderSymbolId // order symbol and ids to remove from keeper.OrderInfoForPublish + IsLive bool ) type MarketDataPublisher interface { @@ -52,21 +56,15 @@ func Publish( // they can assign buyer/seller address into trade before persist into DB var opensToPublish []*Order var closedToPublish []*Order - var miniOpensToPublish []*Order - var miniClosedToPublish []*Order var feeToPublish map[string]string if cfg.PublishOrderUpdates || cfg.PublishOrderBook { - opensToPublish, closedToPublish, miniOpensToPublish, miniClosedToPublish, feeToPublish = collectOrdersToPublish( + opensToPublish, closedToPublish, feeToPublish = collectOrdersToPublish( marketData.tradesToPublish, marketData.orderChanges, marketData.orderInfos, marketData.feeHolder, - marketData.timestamp, - marketData.miniTradesToPublish, - marketData.miniOrderChanges, - marketData.miniOrderInfos) + marketData.timestamp) addClosedOrder(closedToPublish, ToRemoveOrderIdCh) - addClosedOrder(miniClosedToPublish, ToRemoveMiniOrderIdCh) } // ToRemoveOrderIdCh would be only used in production code @@ -74,12 +72,9 @@ func Publish( if ToRemoveOrderIdCh != nil { close(ToRemoveOrderIdCh) } - if ToRemoveMiniOrderIdCh != nil { - close(ToRemoveMiniOrderIdCh) - } ordersToPublish := append(opensToPublish, closedToPublish...) - miniOrdersToPublish := append(miniOpensToPublish, miniClosedToPublish...) + if cfg.PublishOrderUpdates { duration := Timer(Logger, "publish all orders", func() { publishExecutionResult( @@ -89,9 +84,7 @@ func Publish( ordersToPublish, marketData.tradesToPublish, marketData.proposalsToPublish, - marketData.stakeUpdates, - miniOrdersToPublish, - marketData.miniTradesToPublish) + marketData.stakeUpdates) }) if metrics != nil { @@ -116,7 +109,6 @@ func Publish( var changedPrices = make(orderPkg.ChangedPriceLevelsMap) duration := Timer(Logger, "prepare order books to publish", func() { filterChangedOrderBooksByOrders(ordersToPublish, marketData.latestPricesLevels, changedPrices) - filterChangedOrderBooksByOrders(miniOrdersToPublish, marketData.miniLatestPriceLevels, changedPrices) }) if metrics != nil { numOfChangedPrices := 0 @@ -180,13 +172,13 @@ func Publish( } } -func addClosedOrder(closedToPublish []*Order, toRemoveOrderIdCh chan string) { +func addClosedOrder(closedToPublish []*Order, toRemoveOrderIdCh chan OrderSymbolId) { for _, o := range closedToPublish { if toRemoveOrderIdCh != nil { Logger.Debug( "going to delete order from order changes map", "orderId", o.OrderId, "status", o.Status) - toRemoveOrderIdCh <- o.OrderId + toRemoveOrderIdCh <- OrderSymbolId{o.Symbol, o.OrderId} } } } @@ -203,22 +195,16 @@ func Stop(publisher MarketDataPublisher) { if ToRemoveOrderIdCh != nil { close(ToRemoveOrderIdCh) } - if ToRemoveMiniOrderIdCh != nil { - close(ToRemoveMiniOrderIdCh) - } publisher.Stop() } -func publishExecutionResult(publisher MarketDataPublisher, height int64, timestamp int64, os []*Order, tradesToPublish []*Trade, proposalsToPublish *Proposals, stakeUpdates *StakeUpdates, - miniOrders []*Order, miniTrades []*Trade) { +func publishExecutionResult(publisher MarketDataPublisher, height int64, timestamp int64, os []*Order, tradesToPublish []*Trade, proposalsToPublish *Proposals, stakeUpdates *StakeUpdates) { numOfOrders := len(os) numOfTrades := len(tradesToPublish) numOfProposals := proposalsToPublish.NumOfMsgs numOfStakeUpdatedAccounts := stakeUpdates.NumOfMsgs - numOfMiniOrders := len(miniOrders) - numOfMiniTrades := len(miniTrades) - executionResultsMsg := ExecutionResults{Height: height, Timestamp: timestamp, NumOfMsgs: numOfTrades + numOfOrders + numOfProposals + numOfStakeUpdatedAccounts + numOfMiniTrades + numOfMiniOrders} + executionResultsMsg := ExecutionResults{Height: height, Timestamp: timestamp, NumOfMsgs: numOfTrades + numOfOrders + numOfProposals + numOfStakeUpdatedAccounts} if numOfOrders > 0 { executionResultsMsg.Orders = Orders{numOfOrders, os} } @@ -231,12 +217,6 @@ func publishExecutionResult(publisher MarketDataPublisher, height int64, timesta if numOfStakeUpdatedAccounts > 0 { executionResultsMsg.StakeUpdates = *stakeUpdates } - if numOfMiniOrders > 0 { - executionResultsMsg.MiniOrders = Orders{numOfMiniOrders, miniOrders} - } - if numOfMiniTrades > 0 { - executionResultsMsg.MiniTrades = trades{numOfMiniTrades, miniTrades} - } publisher.publish(&executionResultsMsg, executionResultTpe, height, timestamp) } diff --git a/app/pub/schemas.go b/app/pub/schemas.go index bc6ec41af..2165dcb1e 100644 --- a/app/pub/schemas.go +++ b/app/pub/schemas.go @@ -146,9 +146,7 @@ const ( } } ] - }], "default": null }, - { "name": "miniTrades", "type": ["null", "org.binance.dex.model.avro.Trades"], "default": null }, - { "name": "miniOrders", "type": ["null", "org.binance.dex.model.avro.Orders"], "default": null } + }], "default": null } ] } ` diff --git a/app/pub/schemas/executionResults1.avsc b/app/pub/schemas/executionResults1.avsc deleted file mode 100644 index 6739f1b0c..000000000 --- a/app/pub/schemas/executionResults1.avsc +++ /dev/null @@ -1,138 +0,0 @@ -{ - "type": "record", - "name": "ExecutionResults", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "height", "type": "long" }, - { "name": "timestamp", "type": "long" }, - { "name": "numOfMsgs", "type": "int" }, - { "name": "trades", "type": ["null", { - "type": "record", - "name": "Trades", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "numOfMsgs", "type": "int" }, - { "name": "trades", "type": { - "type": "array", - "items": - { - "type": "record", - "name": "Trade", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "symbol", "type": "string" }, - { "name": "id", "type": "string" }, - { "name": "price", "type": "long" }, - { "name": "qty", "type": "long" }, - { "name": "sid", "type": "string" }, - { "name": "bid", "type": "string" }, - { "name": "sfee", "type": "string" }, - { "name": "bfee", "type": "string" }, - { "name": "saddr", "type": "string" }, - { "name": "baddr", "type": "string" }, - { "name": "ssrc", "type": "long" , "default": 0}, - { "name": "bsrc", "type": "long" , "default": 0}, - { "name": "ssinglefee", "type": "string", "default": "null"}, - { "name": "bsinglefee", "type": "string" , "default": "null"}, - { "name": "tickType", "type": "int" , "default": 0} - ] - } - } - } - ] - }], "default": null }, - { "name": "orders", "type": ["null", { - "type": "record", - "name": "Orders", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "numOfMsgs", "type": "int" }, - { "name": "orders", "type": { - "type": "array", - "items": - { - "type": "record", - "name": "Order", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "symbol", "type": "string" }, - { "name": "status", "type": "string" }, - { "name": "orderId", "type": "string" }, - { "name": "tradeId", "type": "string" }, - { "name": "owner", "type": "string" }, - { "name": "side", "type": "int" }, - { "name": "orderType", "type": "int" }, - { "name": "price", "type": "long" }, - { "name": "qty", "type": "long" }, - { "name": "lastExecutedPrice", "type": "long" }, - { "name": "lastExecutedQty", "type": "long" }, - { "name": "cumQty", "type": "long" }, - { "name": "fee", "type": "string" }, - { "name": "orderCreationTime", "type": "long" }, - { "name": "transactionTime", "type": "long" }, - { "name": "timeInForce", "type": "int" }, - { "name": "currentExecutionType", "type": "string" }, - { "name": "txHash", "type": "string" }, - { "name": "singlefee", "type": "string", "default": "null" } - ] - } - } - } - ] - }], "default": null }, - { "name": "proposals", "type": ["null", { - "type": "record", - "name": "Proposals", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "numOfMsgs", "type": "int" }, - { "name": "proposals", "type": { - "type": "array", - "items": - { - "type": "record", - "name": "Proposal", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "id", "type": "long" }, - { "name": "status", "type": "string" } - ] - } - } - } - ] - }], "default": null }, - { "name": "stakeUpdates", "type": ["null", { - "type": "record", - "name": "StakeUpdates", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "numOfMsgs", "type": "int" }, - { "name": "completedUnbondingDelegations", "type": { - "type": "array", - "items": - { - "type": "record", - "name": "CompletedUnbondingDelegation", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "validator", "type": "string" }, - { "name": "delegator", "type": "string" }, - { "name": "amount", "type": { - "type": "record", - "name": "Coin", - "namespace": "org.binance.dex.model.avro", - "fields": [ - { "name": "denom", "type": "string" }, - { "name": "amount", "type": "long" } - ] - } - } - ] - } - } - } - ] - }], "default": null } - ] -} \ No newline at end of file diff --git a/app/pub/types.go b/app/pub/types.go index 4e7a1a717..562162836 100644 --- a/app/pub/types.go +++ b/app/pub/types.go @@ -6,39 +6,31 @@ import ( // intermediate data structures to deal with concurrent publication between main thread and publisher thread type BlockInfoToPublish struct { - height int64 - timestamp int64 - tradesToPublish []*Trade - proposalsToPublish *Proposals - stakeUpdates *StakeUpdates - orderChanges orderPkg.OrderChanges - orderInfos orderPkg.OrderInfoForPublish - accounts map[string]Account - latestPricesLevels orderPkg.ChangedPriceLevelsMap - miniLatestPriceLevels orderPkg.ChangedPriceLevelsMap - blockFee BlockFee - feeHolder orderPkg.FeeHolder - transfers *Transfers - block *Block - miniTradesToPublish []*Trade - miniOrderChanges orderPkg.OrderChanges - miniOrderInfos orderPkg.OrderInfoForPublish + height int64 + timestamp int64 + tradesToPublish []*Trade + proposalsToPublish *Proposals + stakeUpdates *StakeUpdates + orderChanges orderPkg.OrderChanges + orderInfos orderPkg.OrderInfoForPublish + accounts map[string]Account + latestPricesLevels orderPkg.ChangedPriceLevelsMap + blockFee BlockFee + feeHolder orderPkg.FeeHolder + transfers *Transfers + block *Block } func NewBlockInfoToPublish( height int64, timestamp int64, tradesToPublish []*Trade, - miniTradesToPublish []*Trade, proposalsToPublish *Proposals, stakeUpdates *StakeUpdates, orderChanges orderPkg.OrderChanges, - miniOrderChanges orderPkg.OrderChanges, orderInfos orderPkg.OrderInfoForPublish, - miniOrderInfos orderPkg.OrderInfoForPublish, accounts map[string]Account, latestPriceLevels orderPkg.ChangedPriceLevelsMap, - miniLatestPriceLevels orderPkg.ChangedPriceLevelsMap, blockFee BlockFee, feeHolder orderPkg.FeeHolder, transfers *Transfers, block *Block) BlockInfoToPublish { return BlockInfoToPublish{ @@ -51,13 +43,9 @@ func NewBlockInfoToPublish( orderInfos, accounts, latestPriceLevels, - miniLatestPriceLevels, blockFee, feeHolder, transfers, block, - miniTradesToPublish, - miniOrderChanges, - miniOrderInfos, } } diff --git a/cmd/pressuremaker/utils/utils.go b/cmd/pressuremaker/utils/utils.go index ddd7f0b65..a35b71358 100644 --- a/cmd/pressuremaker/utils/utils.go +++ b/cmd/pressuremaker/utils/utils.go @@ -148,16 +148,12 @@ func (mg MessageGenerator) Publish(height, timePub int64, tradesToPublish []*pub height, timePub, tradesToPublish, - nil, new(pub.Proposals), new(pub.StakeUpdates), orderChanges, - nil, orderChangesCopy, - nil, accounts, nil, - nil, pub.BlockFee{}, nil, transfers, diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 887f0d693..e5ca87a47 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -337,7 +337,7 @@ func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.Ope return make([]store.OpenOrder, 0) } -func (kp *DexKeeper) GetOrderBooks(maxLevels int, pairType SymbolPairType) ChangedPriceLevelsMap { +func (kp *DexKeeper) GetOrderBooks(maxLevels int) ChangedPriceLevelsMap { var res = make(ChangedPriceLevelsMap) for pair, eng := range kp.engines { buys := make(map[int64]int64) @@ -1020,6 +1020,16 @@ func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { kp.logger.Error("pairType is not supported %d", pairType) return make(OrderChanges, 0) } +func (kp *DexKeeper) GetAllOrderChanges() OrderChanges { + var res OrderChanges + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.supportUpgradeVersion() { + res = append(res, orderKeeper.getOrderChanges()...) + } + } + kp.logger.Debug("pairType is not supported %v", res) + return res +} func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { for _, orderKeeper := range kp.OrderKeepers { @@ -1051,14 +1061,24 @@ func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPu return make(OrderInfoForPublish) } -func (kp *DexKeeper) RemoveOrderInfosForPub(pairType SymbolPairType, orderId string) { +func (kp *DexKeeper) GetAllOrderInfosForPub() OrderInfoForPublish { + orderInfoForPub := make(OrderInfoForPublish) for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportPairType(pairType) { + if orderKeeper.supportUpgradeVersion() { + orderInfoForPub = appendOrderInfoForPub(orderInfoForPub, orderKeeper.getOrderInfosForPub()) + } + } + return orderInfoForPub +} + +func (kp *DexKeeper) RemoveOrderInfosForPub(pair string, orderId string) { + for _, orderKeeper := range kp.OrderKeepers { + if orderKeeper.support(pair) { orderKeeper.removeOrderInfosForPub(orderId) return } } - kp.logger.Error("pairType is not supported %d", pairType) + kp.logger.Error("pair is not supported %d", pair) } func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { @@ -1094,6 +1114,16 @@ func appendAllOrdersMap(ms ...map[string]map[string]*OrderInfo) map[string]map[s return res } +func appendOrderInfoForPub(ms ...OrderInfoForPublish) OrderInfoForPublish { + res := make(OrderInfoForPublish) + for _, m := range ms { + for k, v := range m { + res[k] = v + } + } + return res +} + func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { return me.NewMatchEng(pairSymbol, basePrice, lotSize, 0.05) } diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index fd451b315..753beeede 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -235,11 +235,10 @@ func (kp *DexKeeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, st kp.AddOrder(orderInfo, true) logger.Info("Added Order", "order", msg) case CancelOrderMsg: - symbolPairType := selectPairType(msg.Symbol) err := kp.RemoveOrder(msg.RefId, msg.Symbol, func(ord me.OrderPart) { if kp.CollectOrderInfoForPublish { bnclog.Debug("deleted order from order changes map", "orderId", msg.RefId, "isRecovery", true) - kp.RemoveOrderInfosForPub(symbolPairType, msg.RefId) + kp.RemoveOrderInfosForPub(msg.Symbol, msg.RefId) } }) if err != nil { From 4a04f49a86db4993689f501b601d3b1d47ae939a Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Wed, 20 May 2020 21:03:44 +0800 Subject: [PATCH 59/96] refactor --- app/pub/helpers.go | 3 ++- app/pub/publisher.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 08dd08644..abc3ed1c5 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -399,7 +399,8 @@ func updateExpireFeeForPublish( // collect all changed books according to published order status func filterChangedOrderBooksByOrders( ordersToPublish []*Order, - latestPriceLevels orderPkg.ChangedPriceLevelsMap, res orderPkg.ChangedPriceLevelsMap) orderPkg.ChangedPriceLevelsMap { + latestPriceLevels orderPkg.ChangedPriceLevelsMap) orderPkg.ChangedPriceLevelsMap { + var res = make(orderPkg.ChangedPriceLevelsMap) // map from symbol -> price -> qty diff in this block var buyQtyDiff = make(map[string]map[int64]int64) var sellQtyDiff = make(map[string]map[int64]int64) diff --git a/app/pub/publisher.go b/app/pub/publisher.go index bfd55f633..6d3e48132 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -108,7 +108,7 @@ func Publish( if cfg.PublishOrderBook { var changedPrices = make(orderPkg.ChangedPriceLevelsMap) duration := Timer(Logger, "prepare order books to publish", func() { - filterChangedOrderBooksByOrders(ordersToPublish, marketData.latestPricesLevels, changedPrices) + changedPrices = filterChangedOrderBooksByOrders(ordersToPublish, marketData.latestPricesLevels) }) if metrics != nil { numOfChangedPrices := 0 From ff93e9763e986a56c0f67c03f67450860fd49227 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 21 May 2020 14:58:03 +0800 Subject: [PATCH 60/96] separate issue-mini and issue-tiny --- admin/tx.go | 1 + app/app.go | 1 + common/types/mini_token.go | 4 +- networks/demo/issue_mini.exp | 4 +- networks/publisher/list_mini.sh | 2 +- plugins/dex/list/handler_mini_test.go | 29 ++++++-- plugins/dex/store/minitoken_mapper.go | 1 - plugins/param/genesis.go | 8 +-- plugins/param/plugin.go | 4 +- plugins/tokens/burn/handler_test.go | 2 +- plugins/tokens/client/cli/commands.go | 1 + plugins/tokens/client/cli/issue_mini.go | 22 +----- plugins/tokens/client/cli/issue_tiny.go | 64 +++++++++++++++++ plugins/tokens/freeze/handler_test.go | 2 +- plugins/tokens/issue/handler_mini.go | 12 ++-- plugins/tokens/issue/handler_mini_test.go | 20 +++--- plugins/tokens/issue/msg_mini.go | 23 ++----- plugins/tokens/issue/msg_tiny.go | 84 +++++++++++++++++++++++ plugins/tokens/seturi/handler_test.go | 6 +- 19 files changed, 216 insertions(+), 74 deletions(-) delete mode 100644 plugins/dex/store/minitoken_mapper.go create mode 100644 plugins/tokens/client/cli/issue_tiny.go create mode 100644 plugins/tokens/issue/msg_tiny.go diff --git a/admin/tx.go b/admin/tx.go index 0378ff1c1..889554563 100644 --- a/admin/tx.go +++ b/admin/tx.go @@ -26,6 +26,7 @@ var transferOnlyModeBlackList = []string{ timelock.TimeUnlockMsg{}.Type(), timelock.TimeRelockMsg{}.Type(), issue.IssueMiniMsg{}.Type(), + issue.IssueTinyMsg{}.Type(), } var TxBlackList = map[runtime.Mode][]string{ diff --git a/app/app.go b/app/app.go index 49b9cb583..d606a3a88 100644 --- a/app/app.go +++ b/app/app.go @@ -295,6 +295,7 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, issue.IssueMiniMsg{}.Type(), + issue.IssueTinyMsg{}.Type(), seturi.SetURIMsg{}.Type(), list.ListMiniMsg{}.Type(), ) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index c58f528d6..8a8f1adab 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -64,7 +64,7 @@ type MiniToken struct { var _ IToken = &MiniToken{} -func NewMiniToken(name, symbol string, supplyRangeType int8, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken, error) { +func NewMiniToken(name, symbol string, supplyRangeType SupplyRangeType, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken, error) { // double check that the symbol is suffixed if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { return nil, err @@ -81,7 +81,7 @@ func NewMiniToken(name, symbol string, supplyRangeType int8, totalSupply int64, Owner: owner, Mintable: mintable, }, - SupplyRangeType(supplyRangeType), + supplyRangeType, tokenURI, }, nil } diff --git a/networks/demo/issue_mini.exp b/networks/demo/issue_mini.exp index e1533efb9..39a86f5b3 100755 --- a/networks/demo/issue_mini.exp +++ b/networks/demo/issue_mini.exp @@ -12,9 +12,9 @@ set uri [lindex $argv 8] set timeout 30 if {"${home}" == ""} { - spawn ./bnbcli token issue-mini -s $symbol --token-name $token_name -n $supply --mintable $mintable --from $from --token-uri $uri --token-type $type --chain-id $chain_id + spawn ./bnbcli token issue-mini -s $symbol --token-name $token_name -n $supply --mintable $mintable --from $from --token-uri $uri --chain-id $chain_id } else { - spawn ./bnbcli token issue-mini --home $home -s $symbol --token-name $token_name -n $supply --mintable $mintable --from $from --token-uri $uri --token-type $type --chain-id $chain_id + spawn ./bnbcli token issue-mini --home $home -s $symbol --token-name $token_name -n $supply --mintable $mintable --from $from --token-uri $uri --chain-id $chain_id } expect "Password*" send "12345678\r" diff --git a/networks/publisher/list_mini.sh b/networks/publisher/list_mini.sh index 000bb3e6e..c918511a0 100755 --- a/networks/publisher/list_mini.sh +++ b/networks/publisher/list_mini.sh @@ -25,7 +25,7 @@ scripthome="${src}/networks/publisher" ############################ END ########################## #X1Mini_symbol="X1Mini-ED3" -result=$(${cli} token issue-mini --from=zc --token-name="X1M Coin" --symbol=X1M --total-supply=800000000000 --token-type=1 --chain-id ${chain_id}) +result=$(${cli} token issue-tiny --from=zc --token-name="X1M Coin" --symbol=X1M --total-supply=800000000000 --chain-id ${chain_id}) X1Mini_symbol=$(echo "${result}" | tail -n 1 | grep -o "X1M-[0-9A-Z]*") echo ${X1Mini_symbol} sleep 2 diff --git a/plugins/dex/list/handler_mini_test.go b/plugins/dex/list/handler_mini_test.go index d2efa710b..1102fb062 100644 --- a/plugins/dex/list/handler_mini_test.go +++ b/plugins/dex/list/handler_mini_test.go @@ -43,13 +43,12 @@ func setupForMini(ctx sdk.Context, tokenMapper tokenStore.Mapper, t *testing.T) }) require.Nil(t, err, "new token error") - err = tokenMapper.NewToken(ctx, &types.Token{ - Name: "Bitcoin Mini", - Symbol: "BTC-000M", - OrigSymbol: "BTC", - TotalSupply: 10000, - Owner: sdk.AccAddress("testacc"), - }) + miniToken, _ := types.NewMiniToken("Bitcoin Mini", "BTC-000M", types.MiniRangeType, 100000e8, sdk.AccAddress("testacc"), false, "") + err = tokenMapper.NewToken(ctx, miniToken) + require.Nil(t, err, "new token error") + + tinyToken, _ := types.NewMiniToken("Bitcoin Mini", "ETH-000M", types.TinyRangeType, 10000e8, sdk.AccAddress("testacc"), true, "abc") + err = tokenMapper.NewToken(ctx, tinyToken) require.Nil(t, err, "new token error") } @@ -102,3 +101,19 @@ func TestHandleListMiniRight(t *testing.T) { }) require.Equal(t, result.Code, sdk.ABCICodeOK) } + +func TestHandleListTinyRight(t *testing.T) { + setChainVersion() + defer resetChainVersion() + cdc := MakeCodec() + ms, orderKeeper, tokenMapper, _ := MakeKeepers(cdc) + ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()) + setupForMini(ctx, tokenMapper, t) + result := handleListMini(ctx, orderKeeper, tokenMapper, ListMiniMsg{ + From: sdk.AccAddress("testacc"), + BaseAssetSymbol: "ETH-000M", + QuoteAssetSymbol: "BNB", + InitPrice: 1000, + }) + require.Equal(t, result.Code, sdk.ABCICodeOK) +} diff --git a/plugins/dex/store/minitoken_mapper.go b/plugins/dex/store/minitoken_mapper.go deleted file mode 100644 index 72440ea2a..000000000 --- a/plugins/dex/store/minitoken_mapper.go +++ /dev/null @@ -1 +0,0 @@ -package store diff --git a/plugins/param/genesis.go b/plugins/param/genesis.go index 1555586e8..c4a0330ff 100644 --- a/plugins/param/genesis.go +++ b/plugins/param/genesis.go @@ -54,10 +54,10 @@ const ( IOCExpireFeeNative = 5e3 //MiniToken fee - MiniIssueFee = 10e8 - AdvMiniIssueFee = 20e8 - MiniSetUriFee = 1e8 - MiniListingFee = 100e8 + TinyIssueFee = 10e8 + MiniIssueFee = 20e8 + MiniSetUriFee = 1e8 + MiniListingFee = 100e8 ) var DefaultGenesisState = param.GenesisState{ diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 99c1bc9df..d5a1a62c0 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -63,8 +63,8 @@ func RegisterUpgradeBeginBlocker(paramHub *ParamHub) { }) upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP8, func(ctx sdk.Context) { miniTokenFeeParams := []param.FeeParam{ - ¶m.FixedFeeParams{MsgType: issue.IssueTinyMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: issue.IssueMiniMsgType, Fee: AdvMiniIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: issue.IssueTinyMsgType, Fee: TinyIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: issue.IssueMiniMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: miniURI.SetURIMsg{}.Type(), Fee: MiniSetUriFee, FeeFor: types.FeeForProposer}, ¶m.FixedFeeParams{MsgType: list.ListMiniMsg{}.Type(), Fee: MiniListingFee, FeeFor: types.FeeForProposer}, } diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go index 9a2d5e509..c8d215e58 100644 --- a/plugins/tokens/burn/handler_test.go +++ b/plugins/tokens/burn/handler_test.go @@ -57,7 +57,7 @@ func TestHandleBurnMini(t *testing.T) { _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false, "http://www.xyz.com/nnb.json") sdkResult := miniIssueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) diff --git a/plugins/tokens/client/cli/commands.go b/plugins/tokens/client/cli/commands.go index c1c9f19b0..67de8c4f6 100644 --- a/plugins/tokens/client/cli/commands.go +++ b/plugins/tokens/client/cli/commands.go @@ -54,6 +54,7 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { tokenCmd.AddCommand( client.PostCommands( issueMiniTokenCmd(cmdr), + issueTinyTokenCmd(cmdr), setTokenURICmd(cmdr))..., ) diff --git a/plugins/tokens/client/cli/issue_mini.go b/plugins/tokens/client/cli/issue_mini.go index d1fbc1bfe..73f851a08 100644 --- a/plugins/tokens/client/cli/issue_mini.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -13,8 +13,7 @@ import ( ) const ( - flagTokenType = "token-type" - flagTokenUri = "token-uri" + flagTokenUri = "token-uri" ) func issueMiniTokenCmd(cmdr Commander) *cobra.Command { @@ -26,11 +25,9 @@ func issueMiniTokenCmd(cmdr Commander) *cobra.Command { cmd.Flags().String(flagTokenName, "", "name of the new token") cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the new token") - cmd.Flags().Int8P(flagTokenType, "t", 0, "token type - 1 = tiny token, of which max supply is 10k; - 2 = mini token, of which max supply is 100k") cmd.Flags().Int64P(flagTotalSupply, "n", 0, "total supply of the new token") cmd.Flags().Bool(flagMintable, false, "whether the token can be minted") cmd.Flags().String(flagTokenUri, "", "uri of the token information") - cmd.MarkFlagRequired(flagTokenType) cmd.MarkFlagRequired(flagTotalSupply) return cmd } @@ -53,14 +50,8 @@ func (c Commander) issueMiniToken(cmd *cobra.Command, args []string) error { return err } - tokenType := viper.GetInt(flagTokenType) - err = checkTokenType(tokenType) - if err != nil { - return err - } - supply := viper.GetInt64(flagTotalSupply) - err = checkMiniSupplyAmount(supply, int8(tokenType)) + err = checkMiniSupplyAmount(supply, int8(types.MiniRangeType)) if err != nil { return err } @@ -74,17 +65,10 @@ func (c Commander) issueMiniToken(cmd *cobra.Command, args []string) error { } // build message - msg := issue.NewIssueMiniMsg(from, name, symbol, int8(tokenType), supply, mintable, tokenURI) + msg := issue.NewIssueMiniMsg(from, name, symbol, supply, mintable, tokenURI) return client.SendOrPrintTx(cliCtx, txBldr, msg) } -func checkTokenType(tokenType int) error { - if tokenType != int(types.SupplyRange.TINY) && tokenType != int(types.SupplyRange.MINI) { - return errors.New("invalid token type") - } - return nil -} - func checkMiniSupplyAmount(amount int64, tokenType int8) error { if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenSupplyUpperBound { return errors.New("invalid supply amount") diff --git a/plugins/tokens/client/cli/issue_tiny.go b/plugins/tokens/client/cli/issue_tiny.go new file mode 100644 index 000000000..294d60f44 --- /dev/null +++ b/plugins/tokens/client/cli/issue_tiny.go @@ -0,0 +1,64 @@ +package commands + +import ( + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/binance-chain/node/common/client" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/tokens/issue" +) + +func issueTinyTokenCmd(cmdr Commander) *cobra.Command { + cmd := &cobra.Command{ + Use: "issue-tiny", + Short: "issue a new tiny-token", + RunE: cmdr.issueTinyToken, + } + + cmd.Flags().String(flagTokenName, "", "name of the new token") + cmd.Flags().StringP(flagSymbol, "s", "", "symbol of the new token") + cmd.Flags().Int64P(flagTotalSupply, "n", 0, "total supply of the new token") + cmd.Flags().Bool(flagMintable, false, "whether the token can be minted") + cmd.Flags().String(flagTokenUri, "", "uri of the token information") + cmd.MarkFlagRequired(flagTotalSupply) + return cmd +} + +func (c Commander) issueTinyToken(cmd *cobra.Command, args []string) error { + cliCtx, txBldr := client.PrepareCtx(c.Cdc) + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + name := viper.GetString(flagTokenName) + if len(name) == 0 { + return errors.New("you must provide the name of the token") + } + + symbol := viper.GetString(flagSymbol) + err = types.ValidateIssueMsgMiniTokenSymbol(symbol) + if err != nil { + return err + } + + supply := viper.GetInt64(flagTotalSupply) + err = checkMiniSupplyAmount(supply, int8(types.TinyRangeType)) + if err != nil { + return err + } + + mintable := viper.GetBool(flagMintable) + + tokenURI := viper.GetString(flagTokenUri) + err = validateTokenURI(tokenURI) + if err != nil { + return err + } + + // build message + msg := issue.NewIssueTinyMsg(from, name, symbol, supply, mintable, tokenURI) + return client.SendOrPrintTx(cliCtx, txBldr, msg) +} diff --git a/plugins/tokens/freeze/handler_test.go b/plugins/tokens/freeze/handler_test.go index 734eed21f..a42a84c34 100644 --- a/plugins/tokens/freeze/handler_test.go +++ b/plugins/tokens/freeze/handler_test.go @@ -58,7 +58,7 @@ func TestHandleFreezeMini(t *testing.T) { _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false, "http://www.xyz.com/nnb.json") sdkResult := miniIssueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) diff --git a/plugins/tokens/issue/handler_mini.go b/plugins/tokens/issue/handler_mini.go index ae7b1c25d..78ebd8127 100644 --- a/plugins/tokens/issue/handler_mini.go +++ b/plugins/tokens/issue/handler_mini.go @@ -21,7 +21,9 @@ func NewMiniHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case IssueMiniMsg: - return handleIssueMiniToken(ctx, tokenMapper, keeper, msg) + return msg.handleIssueMiniToken(ctx, tokenMapper, keeper, common.MiniRangeType) + case IssueTinyMsg: + return msg.handleIssueMiniToken(ctx, tokenMapper, keeper, common.TinyRangeType) default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -29,7 +31,7 @@ func NewMiniHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { } } -func handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg IssueMiniMsg) sdk.Result { +func (msg IssueMiniMsg) handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, tokenType common.SupplyRangeType) sdk.Result { errLogMsg := "issue miniToken failed" symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) @@ -62,10 +64,10 @@ func handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper common.MiniTokenMinTotalSupply)).Result() } - if msg.TotalSupply > common.SupplyRangeType(msg.TokenType).UpperBound() { + if msg.TotalSupply > tokenType.UpperBound() { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply is %d", - common.SupplyRangeType(msg.TokenType).UpperBound())).Result() + tokenType.UpperBound())).Result() } // the symbol is suffixed with the first n bytes of the tx hash symbol = fmt.Sprintf("%s-%s", symbol, suffix) @@ -80,7 +82,7 @@ func handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) already exists", msg.Symbol)).Result() } - token, err := common.NewMiniToken(msg.Name, symbol, msg.TokenType, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) + token, err := common.NewMiniToken(msg.Name, symbol, tokenType, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) if err != nil { logger.Error(errLogMsg, "reason", "create token failed: "+err.Error()) return sdk.ErrInternal(fmt.Sprintf("unable to create token struct: %s", err.Error())).Result() diff --git a/plugins/tokens/issue/handler_mini_test.go b/plugins/tokens/issue/handler_mini_test.go index c55cd3215..c93de1885 100644 --- a/plugins/tokens/issue/handler_mini_test.go +++ b/plugins/tokens/issue/handler_mini_test.go @@ -1,6 +1,7 @@ package issue import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -45,13 +46,13 @@ func TestHandleIssueMiniToken(t *testing.T) { _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8+100, false, "http://www.xyz.com/nnb.json") + msg := NewIssueTinyMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8+100, false, "http://www.xyz.com/nnb.json") sdkResult := handler(ctx, msg) require.Equal(t, false, sdkResult.Code.IsOK()) require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg = NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + msg = NewIssueTinyMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false, "http://www.xyz.com/nnb.json") sdkResult = handler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) @@ -64,14 +65,14 @@ func TestHandleIssueMiniToken(t *testing.T) { require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") ctx = ctx.WithValue(baseapp.TxHashKey, "002") - msg = NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 2, 100000e8+100, false, "http://www.xyz.com/nnb.json") - sdkResult = handler(ctx, msg) + msgMini := NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 100000e8+100, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msgMini) require.Equal(t, false, sdkResult.Code.IsOK()) require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") ctx = ctx.WithValue(baseapp.TxHashKey, "002") - msg = NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 2, 10000e8+100, false, "http://www.xyz.com/nnb.json") - sdkResult = handler(ctx, msg) + msgMini = NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 10000e8+100, false, "http://www.xyz.com/nnb.json") + sdkResult = handler(ctx, msgMini) require.Equal(t, true, sdkResult.Code.IsOK()) token, err = tokenMapper.GetToken(ctx, "NBB-002M") @@ -89,12 +90,15 @@ func TestHandleMintMiniToken(t *testing.T) { sdkResult := handler(ctx, mintMsg) require.Contains(t, sdkResult.Log, "symbol(NNB-000M) does not exist") - issueMsg := NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 9000e8, true, "http://www.xyz.com/nnb.json") + issueMsg := NewIssueTinyMsg(acc.GetAddress(), "New BNB", "NNB", 9000e8, true, "http://www.xyz.com/nnb.json") ctx = ctx.WithValue(baseapp.TxHashKey, "000") sdkResult = miniTokenHandler(ctx, issueMsg) require.Equal(t, true, sdkResult.Code.IsOK()) sdkResult = handler(ctx, mintMsg) + require.Equal(t, false, sdkResult.Code.IsOK()) + require.Contains(t, sdkResult.Log, fmt.Sprintf("mint amount is too large, the max total supply is %d", types.TinyRangeType.UpperBound())) + token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 9000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") @@ -121,7 +125,7 @@ func TestHandleMintMiniToken(t *testing.T) { require.Contains(t, sdkResult.Log, "only the owner can mint token NNB") // issue a non-mintable token - issueMsg = NewIssueMiniMsg(acc.GetAddress(), "New BNB2", "NNB2", 1, 9000e8, false, "http://www.xyz.com/nnb.json") + issueMsg = NewIssueTinyMsg(acc.GetAddress(), "New BNB2", "NNB2", 9000e8, false, "http://www.xyz.com/nnb.json") ctx = ctx.WithValue(baseapp.TxHashKey, "000") sdkResult = miniTokenHandler(ctx, issueMsg) require.Equal(t, true, sdkResult.Code.IsOK()) diff --git a/plugins/tokens/issue/msg_mini.go b/plugins/tokens/issue/msg_mini.go index 9ea3ce71c..97e226639 100644 --- a/plugins/tokens/issue/msg_mini.go +++ b/plugins/tokens/issue/msg_mini.go @@ -14,7 +14,6 @@ import ( // const Route = "tokens/issue" const ( MiniRoute = "miniTokensIssue" - IssueTinyMsgType = "tinyIssueMsg" IssueMiniMsgType = "miniIssueMsg" //For max total supply in range 2 ) @@ -24,18 +23,16 @@ type IssueMiniMsg struct { From sdk.AccAddress `json:"from"` Name string `json:"name"` Symbol string `json:"symbol"` - TokenType int8 `json:"token_type"` TotalSupply int64 `json:"total_supply"` Mintable bool `json:"mintable"` TokenURI string `json:"token_uri"` } -func NewIssueMiniMsg(from sdk.AccAddress, name, symbol string, tokenType int8, supply int64, mintable bool, tokenURI string) IssueMiniMsg { +func NewIssueMiniMsg(from sdk.AccAddress, name, symbol string, supply int64, mintable bool, tokenURI string) IssueMiniMsg { return IssueMiniMsg{ From: from, Name: name, Symbol: symbol, - TokenType: tokenType, TotalSupply: supply, Mintable: mintable, TokenURI: tokenURI, @@ -65,12 +62,8 @@ func (msg IssueMiniMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidCoins(fmt.Sprintf("token seturi should not exceed %v characters", types.MaxTokenURILength)) } - if msg.TokenType != int8(types.SupplyRange.MINI) && msg.TokenType != int8(types.SupplyRange.TINY) { - return sdk.ErrInvalidCoins(fmt.Sprintf("token type should be %d or %d, got %d", int8(types.SupplyRange.MINI), int8(types.SupplyRange.TINY), msg.TokenType)) - } - - if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.SupplyRangeType(msg.TokenType).UpperBound() { - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinTotalSupply, types.SupplyRangeType(msg.TokenType).UpperBound())) + if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.MiniRangeType.UpperBound() { + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinTotalSupply, types.MiniRangeType.UpperBound())) } return nil @@ -79,15 +72,9 @@ func (msg IssueMiniMsg) ValidateBasic() sdk.Error { // Implements IssueMiniMsg. func (msg IssueMiniMsg) Route() string { return MiniRoute } func (msg IssueMiniMsg) Type() string { - switch types.SupplyRangeType(msg.TokenType) { - case types.SupplyRange.TINY: - return IssueTinyMsgType - case types.SupplyRange.MINI: - return IssueMiniMsgType - default: - return IssueMiniMsgType - } + return IssueMiniMsgType } + func (msg IssueMiniMsg) String() string { return fmt.Sprintf("IssueMiniMsg{%#v}", msg) } func (msg IssueMiniMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } func (msg IssueMiniMsg) GetSignBytes() []byte { diff --git a/plugins/tokens/issue/msg_tiny.go b/plugins/tokens/issue/msg_tiny.go new file mode 100644 index 000000000..1a7baf96f --- /dev/null +++ b/plugins/tokens/issue/msg_tiny.go @@ -0,0 +1,84 @@ +package issue + +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" +) + +// TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash +// const Route = "tokens/issue" +const ( + IssueTinyMsgType = "tinyIssueMsg" +) + +var _ sdk.Msg = IssueTinyMsg{} + +type IssueTinyMsg struct { + IssueMiniMsg +} + +func NewIssueTinyMsg(from sdk.AccAddress, name, symbol string, supply int64, mintable bool, tokenURI string) IssueTinyMsg { + return IssueTinyMsg{IssueMiniMsg{ + From: from, + Name: name, + Symbol: symbol, + TotalSupply: supply, + Mintable: mintable, + TokenURI: tokenURI, + }, + } +} + +// ValidateBasic does a simple validation check that +// doesn't require access to any other information. +func (msg IssueTinyMsg) ValidateBasic() sdk.Error { + if !sdk.IsUpgrade(upgrade.BEP8) { + return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")) + } + + if msg.From == nil { + return sdk.ErrInvalidAddress("sender address cannot be empty") + } + + if err := types.ValidateIssueMsgMiniTokenSymbol(msg.Symbol); err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + + if len(msg.Name) == 0 || len(msg.Name) > maxTokenNameLength { + return sdk.ErrInvalidCoins(fmt.Sprintf("token name should have 1 ~ %v characters", maxTokenNameLength)) + } + + if len(msg.TokenURI) > types.MaxTokenURILength { + return sdk.ErrInvalidCoins(fmt.Sprintf("token seturi should not exceed %v characters", types.MaxTokenURILength)) + } + + if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.TinyRangeType.UpperBound() { + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinTotalSupply, types.TinyRangeType.UpperBound())) + } + + return nil +} + +// Implements IssueTinyMsg. +func (msg IssueTinyMsg) Route() string { return MiniRoute } +func (msg IssueTinyMsg) Type() string { + return IssueTinyMsgType +} + +func (msg IssueTinyMsg) String() string { return fmt.Sprintf("IssueTinyMsg{%#v}", msg) } +func (msg IssueTinyMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } +func (msg IssueTinyMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} +func (msg IssueTinyMsg) GetInvolvedAddresses() []sdk.AccAddress { + return msg.GetSigners() +} diff --git a/plugins/tokens/seturi/handler_test.go b/plugins/tokens/seturi/handler_test.go index fae25a3d5..3b8a22c37 100644 --- a/plugins/tokens/seturi/handler_test.go +++ b/plugins/tokens/seturi/handler_test.go @@ -57,13 +57,13 @@ func TestHandleSetURI(t *testing.T) { _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") - msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 1, 10000e8, false, "http://www.xyz.com/nnb.json") + msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false, "http://www.xyz.com/nnb.json") sdkResult := miniIssueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) ctx = ctx.WithValue(baseapp.TxHashKey, "002") @@ -79,7 +79,7 @@ func TestHandleSetURI(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.123.com/nnb_new.json") + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.123.com/nnb_new.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) From bb5c884321bc6707b1f7d6826c7606179a7c14c1 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 21 May 2020 16:52:59 +0800 Subject: [PATCH 61/96] refactor --- app/pub/helpers.go | 2 +- app/pub/publisher.go | 7 ++- plugins/dex/matcheng/engine_new.go | 1 - plugins/dex/order/handler.go | 62 ++++++++++++++++++++++++--- plugins/dex/order/handler_test.go | 12 +++--- plugins/dex/order/keeper.go | 59 ++++++++----------------- plugins/dex/order/keeper_match.go | 3 -- plugins/dex/order/keeper_recovery.go | 17 -------- plugins/dex/order/mini_keeper.go | 26 ----------- plugins/dex/order/order_keeper.go | 42 ------------------ plugins/dex/store/mapper.go | 3 +- plugins/dex/utils/numbers.go | 12 ------ plugins/tokens/burn/handler.go | 2 - plugins/tokens/burn/handler_test.go | 6 +-- plugins/tokens/freeze/handler_test.go | 4 +- 15 files changed, 92 insertions(+), 166 deletions(-) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index abc3ed1c5..ccca2a2c6 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -266,7 +266,7 @@ func MatchAndAllocateAllForPublish(dexKeeper *orderPkg.DexKeeper, ctx sdk.Contex // This channels is used for protect not update `dexKeeper.orderChanges` concurrently // matcher would send item to postAlloTransHandler in several goroutine (well-designed) // while dexKeeper.orderChanges are not separated by concurrent factor (users here) - iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize+MiniTransferCollectionChannelSize) + iocExpireFeeHolderCh := make(chan orderPkg.ExpireHolder, TransferCollectionChannelSize) wg := sync.WaitGroup{} wg.Add(1) diff --git a/app/pub/publisher.go b/app/pub/publisher.go index 6d3e48132..25b326e54 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -13,10 +13,9 @@ import ( const ( // TODO(#66): revisit the setting / whole thread model here, // do we need better way to make main thread less possibility to block - TransferCollectionChannelSize = 4000 - MiniTransferCollectionChannelSize = 1000 - ToRemoveOrderIdChannelSize = 1000 - MaxOrderBookLevel = 100 + TransferCollectionChannelSize = 4000 + ToRemoveOrderIdChannelSize = 1000 + MaxOrderBookLevel = 100 ) type OrderSymbolId struct { diff --git a/plugins/dex/matcheng/engine_new.go b/plugins/dex/matcheng/engine_new.go index 46bbeca63..9deeb98d9 100644 --- a/plugins/dex/matcheng/engine_new.go +++ b/plugins/dex/matcheng/engine_new.go @@ -33,7 +33,6 @@ func (me *MatchEng) Match(height int64, lastMatchedHeight int64) bool { return false } //If order height > the last Match height, then it's maker. - // Block Height cannot be used here since mini-token is not matched in every block takerSide, err := me.determineTakerSide(lastMatchedHeight, index) if err != nil { me.logger.Error("determineTakerSide failed", "error", err) diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index 34df24275..705bf6f00 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -45,6 +45,20 @@ func validateQtyAndLockBalance(ctx sdk.Context, keeper *DexKeeper, acc common.Na // note: the check sequence is well designed. freeBalance := acc.GetCoins() + + if sdk.IsUpgrade(sdk.BEP8) && isMiniSymbolPair(baseAssetSymbol, quoteAssetSymbol) { + var quantityBigEnough bool + if msg.Side == Side.BUY { + quantityBigEnough = msg.Quantity >= common.MiniTokenMinTotalSupply + } else if msg.Side == Side.SELL { + quantityBigEnough = (msg.Quantity >= common.MiniTokenMinTotalSupply) || freeBalance.AmountOf(symbol) == msg.Quantity + } + if !quantityBigEnough { + return fmt.Errorf("quantity is too small, the min quantity is %d or total free balance of the mini token", + common.MiniTokenMinTotalSupply) + } + } + var toLockCoins sdk.Coins if msg.Side == Side.BUY { // for buy orders, @@ -81,7 +95,7 @@ func validateQtyAndLockBalance(ctx sdk.Context, keeper *DexKeeper, acc common.Na acc.SetCoins(freeBalance.Minus(toLockCoins)) acc.SetLockedCoins(acc.GetLockedCoins().Plus(toLockCoins)) - keeper.getAccountKeeper().SetAccount(ctx, acc) + keeper.am.SetAccount(ctx, acc) return nil } @@ -95,7 +109,7 @@ func handleNewOrder( return sdk.NewError(types.DefaultCodespace, types.CodeDuplicatedOrder, errString).Result() } - acc := dexKeeper.getAccountKeeper().GetAccount(ctx, msg.Sender).(common.NamedAccount) + acc := dexKeeper.am.GetAccount(ctx, msg.Sender).(common.NamedAccount) if !ctx.IsReCheckTx() { //for recheck: // 1. sequence is verified in anteHandler @@ -103,7 +117,7 @@ func handleNewOrder( // 3. trading pair is verified // 4. price/qty may have odd tick size/lot size, but it can be handled as // other existing orders. - err := dexKeeper.ValidateOrder(ctx, acc, msg) + err := validateOrder(ctx, dexKeeper, acc, msg) if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeInvalidOrderParam, err.Error()).Result() @@ -190,10 +204,10 @@ func handleCancelOrder( } fee := common.Fee{} if !transfer.FeeFree() { - acc := dexKeeper.getAccountKeeper().GetAccount(ctx, msg.Sender) + acc := dexKeeper.am.GetAccount(ctx, msg.Sender) fee = dexKeeper.getFeeManager().CalcFixedFee(acc.GetCoins(), transfer.eventType, transfer.inAsset, dexKeeper.GetEngines()) acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) - dexKeeper.getAccountKeeper().SetAccount(ctx, acc) + dexKeeper.am.SetAccount(ctx, acc) } // this is done in memory! we must not run this block in checktx or simulate! @@ -219,3 +233,41 @@ func handleCancelOrder( return sdk.Result{} } + +func validateOrder(ctx sdk.Context, dexKeeper *DexKeeper, acc sdk.Account, msg NewOrderMsg) error { + baseAsset, quoteAsset, err := utils.TradingPair2Assets(msg.Symbol) + if err != nil { + return err + } + + seq := acc.GetSequence() + expectedID := GenerateOrderID(seq, msg.Sender) + if expectedID != msg.Id { + return fmt.Errorf("the order ID(%s) given did not match the expected one: `%s`", msg.Id, expectedID) + } + + pair, err := dexKeeper.PairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) + if err != nil { + return err + } + + if msg.Quantity <= 0 || msg.Quantity%pair.LotSize.ToInt64() != 0 { + return fmt.Errorf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()) + } + + if msg.Price <= 0 || msg.Price%pair.TickSize.ToInt64() != 0 { + return fmt.Errorf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()) + } + + if sdk.IsUpgrade(upgrade.LotSizeOptimization) { + if utils.IsUnderMinNotional(msg.Price, msg.Quantity) { + return errors.New("notional value of the order is too small") + } + } + + if utils.IsExceedMaxNotional(msg.Price, msg.Quantity) { + return errors.New("notional value of the order is too large(cannot fit in int64)") + } + + return nil +} diff --git a/plugins/dex/order/handler_test.go b/plugins/dex/order/handler_test.go index 535417852..4c0eace20 100644 --- a/plugins/dex/order/handler_test.go +++ b/plugins/dex/order/handler_test.go @@ -79,7 +79,7 @@ func TestHandler_ValidateOrder_OrderNotExist(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.ValidateOrder(ctx, acc, msg) + err = validateOrder(ctx, keeper, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("trading pair not found: %s", msg.Symbol), err.Error()) } @@ -106,7 +106,7 @@ func TestHandler_ValidateOrder_WrongSymbol(t *testing.T) { } for _, msg := range msgs { - err := keeper.ValidateOrder(ctx, nil, msg) + err := validateOrder(ctx, keeper, nil, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("Failed to parse trading pair symbol:%s into assets", msg.Symbol), err.Error()) } @@ -128,7 +128,7 @@ func TestHandler_ValidateOrder_WrongPrice(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.ValidateOrder(ctx, acc, msg) + err = validateOrder(ctx, keeper, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()), err.Error()) } @@ -149,7 +149,7 @@ func TestHandler_ValidateOrder_WrongQuantity(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.ValidateOrder(ctx, acc, msg) + err = validateOrder(ctx, keeper, acc, msg) require.Error(t, err) require.Equal(t, fmt.Sprintf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()), err.Error()) } @@ -169,7 +169,7 @@ func TestHandler_ValidateOrder_Normal(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.ValidateOrder(ctx, acc, msg) + err = validateOrder(ctx, keeper, acc, msg) require.NoError(t, err) } @@ -188,7 +188,7 @@ func TestHandler_ValidateOrder_MaxNotional(t *testing.T) { Id: fmt.Sprintf("%X-0", acc.GetAddress()), } - err = keeper.ValidateOrder(ctx, acc, msg) + err = validateOrder(ctx, keeper, acc, msg) require.Error(t, err) require.Equal(t, "notional value of the order is too large(cannot fit in int64)", err.Error()) } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index e5ca87a47..1a3f8af11 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -11,14 +11,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + dbm "github.com/tendermint/tendermint/libs/db" tmlog "github.com/tendermint/tendermint/libs/log" + tmstore "github.com/tendermint/tendermint/store" "github.com/binance-chain/node/common/fees" bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/common/utils" - "github.com/binance-chain/node/plugins/dex/matcheng" me "github.com/binance-chain/node/plugins/dex/matcheng" "github.com/binance-chain/node/plugins/dex/store" dexTypes "github.com/binance-chain/node/plugins/dex/types" @@ -81,6 +82,11 @@ func NewDexKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper sto } } +func Init(dexKeeper *DexKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { + dexKeeper.initOrderBook(ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) + dexKeeper.InitRecentPrices(ctx) +} + func (kp *DexKeeper) SetBUSDSymbol(symbol string) { BUSDSymbol = symbol } @@ -449,7 +455,7 @@ func (kp *DexKeeper) StoreTradePrices(ctx sdk.Context) { func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( types.Fee, map[string]*types.Fee) { if !sdk.IsUpgrade(upgrade.BEP19) { - return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler, kp.engines) + return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler) } // use string of the addr as the key since map makes a fast path for string key. @@ -520,7 +526,7 @@ func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAlloc } // DEPRECATED -func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer), engines map[string]*matcheng.MatchEng) ( +func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transfer, postAllocateHandler func(tran Transfer)) ( types.Fee, map[string]*types.Fee) { // use string of the addr as the key since map makes a fast path for string key. // Also, making the key have same length is also an optimization. @@ -584,7 +590,7 @@ func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transf } } collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { - fee := kp.FeeManager.CalcTradeFee(acc.GetCoins(), in, engines) + fee := kp.FeeManager.CalcTradeFee(acc.GetCoins(), in, kp.engines) acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) return fee }) @@ -592,7 +598,7 @@ func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transf var i int64 = 0 var fees types.Fee for ; i < in.Amount; i++ { - fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, engines) + fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, kp.engines) acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) fees.AddFee(fee) } @@ -868,11 +874,10 @@ func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAlloc delete(kp.engines, symbol) delete(kp.recentPrices, symbol) - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.deleteOrdersForPair(symbol) - break - } + if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { + dexOrderKeeper.deleteOrdersForPair(symbol) + } else { + kp.logger.Debug(err.Error()) } baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol) @@ -967,7 +972,7 @@ func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset s } } - if isMiniSymbolPair(baseAsset, quoteAsset) && types.NativeTokenSymbol != quoteAsset { + if types.NativeTokenSymbol != quoteAsset && isMiniSymbolPair(baseAsset, quoteAsset) { return errors.New("quote token is not valid for mini symbol pair: " + quoteAsset) } @@ -977,9 +982,7 @@ func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset s func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { allOrders := make(map[string]map[string]*OrderInfo) for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.supportUpgradeVersion() { - allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) - } + allOrders = appendAllOrdersMap(allOrders, orderKeeper.getAllOrders()) } return allOrders } @@ -1002,15 +1005,6 @@ func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int } } -func (kp *DexKeeper) ValidateOrder(context sdk.Context, account sdk.Account, msg NewOrderMsg) error { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(msg.Symbol); err == nil { - return dexOrderKeeper.validateOrder(kp, context, account, msg) - } else { - kp.logger.Debug(err.Error()) - } - return fmt.Errorf("symbol:%s is not supported", msg.Symbol) -} - func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { for _, orderKeeper := range kp.OrderKeepers { if orderKeeper.supportPairType(pairType) { @@ -1031,16 +1025,6 @@ func (kp *DexKeeper) GetAllOrderChanges() OrderChanges { return res } -func (kp *DexKeeper) UpdateOrderChange(change OrderChange, symbol string) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(symbol) { - orderKeeper.appendOrderChange(change) - return - } - } - kp.logger.Error("symbol is not supported %d", symbol) -} - func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { dexOrderKeeper.appendOrderChangeSync(change) @@ -1085,10 +1069,6 @@ func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { return kp.PairMapper } -func (kp *DexKeeper) getAccountKeeper() *auth.AccountKeeper { - return &kp.am -} - func (kp *DexKeeper) getLogger() tmlog.Logger { return kp.logger } @@ -1129,10 +1109,7 @@ func CreateMatchEng(pairSymbol string, basePrice, lotSize int64) *me.MatchEng { } func isMiniSymbolPair(baseAsset, quoteAsset string) bool { - if sdk.IsUpgrade(upgrade.BEP8) { - return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) - } - return false + return types.IsMiniTokenSymbol(baseAsset) || types.IsMiniTokenSymbol(quoteAsset) } // Check whether there is trading pair between two symbols diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index e19612ed2..79fa7871f 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -64,9 +64,6 @@ func (kp *DexKeeper) matchAndDistributeTrades(distributeTrade bool, height, time symbolCh := make(chan symbolKeeper, concurrency) producer := func() { - //for _, symbol := range symbolsToMatch { - // symbolCh <- symbol - //} for i := range kp.OrderKeepers { kp.OrderKeepers[i].iterateRoundPairs(func(symbol string) { symbolCh <- symbolKeeper{symbol: symbol, orderKeeper: kp.OrderKeepers[i]} diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 753beeede..fa95b25c9 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -24,7 +24,6 @@ import ( "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/common/utils" me "github.com/binance-chain/node/plugins/dex/matcheng" - dexUtils "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/wire" ) @@ -61,11 +60,6 @@ func compressAndSave(snapshot interface{}, cdc *wire.Codec, key string, kv sdk.K return nil } -func Init(dexKeeper *DexKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { - dexKeeper.initOrderBook(ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) - dexKeeper.InitRecentPrices(ctx) -} - func (kp *DexKeeper) SnapShotOrderBook(ctx sdk.Context, height int64) (effectedStoreKeys []string, err error) { kvstore := ctx.KVStore(kp.storeKey) effectedStoreKeys = make([]string, 0) @@ -252,17 +246,6 @@ func (kp *DexKeeper) replayOneBlocks(logger log.Logger, block *tmtypes.Block, st kp.MatchSymbols(height, t, false) //no need to check result } -func selectPairType(symbol string) SymbolPairType { - var pairType SymbolPairType - - if (!sdk.IsUpgrade(upgrade.BEP8)) || !dexUtils.IsMiniTokenTradingPair(symbol) { - pairType = PairType.BEP2 - } else { - pairType = PairType.MINI - } - return pairType -} - func (kp *DexKeeper) ReplayOrdersFromBlock(ctx sdk.Context, bc *tmstore.BlockStore, stateDb dbm.DB, lastHeight, breatheHeight int64, txDecoder sdk.TxDecoder) error { for i := breatheHeight + 1; i <= lastHeight; i++ { diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index bb6b9f0f9..26ae1d602 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -1,13 +1,9 @@ package order import ( - "fmt" - "strings" - sdk "github.com/cosmos/cosmos-sdk/types" bnclog "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" dexUtils "github.com/binance-chain/node/plugins/dex/utils" ) @@ -55,28 +51,6 @@ func (kp *MiniOrderKeeper) initOrders(symbol string) { kp.symbolSelector.AddSymbolHash(symbol) } -// override -func (kp *MiniOrderKeeper) validateOrder(dexKeeper *DexKeeper, ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { - - err := kp.BaseOrderKeeper.validateOrder(dexKeeper, ctx, acc, msg) - if err != nil { - return err - } - coins := acc.GetCoins() - symbol := strings.ToUpper(msg.Symbol) - var quantityBigEnough bool - if msg.Side == Side.BUY { - quantityBigEnough = msg.Quantity >= types.MiniTokenMinTotalSupply - } else if msg.Side == Side.SELL { - quantityBigEnough = (msg.Quantity >= types.MiniTokenMinTotalSupply) || coins.AmountOf(symbol) == msg.Quantity - } - if !quantityBigEnough { - return fmt.Errorf("quantity is too small, the min quantity is %d or total free balance of the mini token", - types.MiniTokenMinTotalSupply) - } - return nil -} - func (kp *MiniOrderKeeper) clearAfterMatch() { kp.logger.Debug("clearAfterMatchMini...") for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { diff --git a/plugins/dex/order/order_keeper.go b/plugins/dex/order/order_keeper.go index 52f5c7c1f..2a765df80 100644 --- a/plugins/dex/order/order_keeper.go +++ b/plugins/dex/order/order_keeper.go @@ -1,15 +1,12 @@ package order import ( - "errors" - "fmt" "sync" sdk "github.com/cosmos/cosmos-sdk/types" tmlog "github.com/tendermint/tendermint/libs/log" bnclog "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/common/utils" me "github.com/binance-chain/node/plugins/dex/matcheng" "github.com/binance-chain/node/plugins/dex/store" @@ -39,7 +36,6 @@ type IDexOrderKeeper interface { support(pair string) bool supportUpgradeVersion() bool supportPairType(pairType SymbolPairType) bool - validateOrder(dexKeeper *DexKeeper, context sdk.Context, account sdk.Account, msg NewOrderMsg) error iterateRoundPairs(func(string)) iterateAllOrders(func(symbol string, id string)) reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) @@ -158,44 +154,6 @@ func (kp *BaseOrderKeeper) deleteOrdersForPair(pair string) { delete(kp.allOrders, pair) } -func (kp *BaseOrderKeeper) validateOrder(dexKeeper *DexKeeper, ctx sdk.Context, acc sdk.Account, msg NewOrderMsg) error { - baseAsset, quoteAsset, err := dexUtils.TradingPair2Assets(msg.Symbol) - if err != nil { - return err - } - - seq := acc.GetSequence() - expectedID := GenerateOrderID(seq, msg.Sender) - if expectedID != msg.Id { - return fmt.Errorf("the order ID(%s) given did not match the expected one: `%s`", msg.Id, expectedID) - } - - pair, err := dexKeeper.PairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) - if err != nil { - return err - } - - if msg.Quantity <= 0 || msg.Quantity%pair.LotSize.ToInt64() != 0 { - return fmt.Errorf("quantity(%v) is not rounded to lotSize(%v)", msg.Quantity, pair.LotSize.ToInt64()) - } - - if msg.Price <= 0 || msg.Price%pair.TickSize.ToInt64() != 0 { - return fmt.Errorf("price(%v) is not rounded to tickSize(%v)", msg.Price, pair.TickSize.ToInt64()) - } - - if sdk.IsUpgrade(upgrade.LotSizeOptimization) { - if dexUtils.IsUnderMinNotional(msg.Price, msg.Quantity) { - return errors.New("notional value of the order is too small") - } - } - - if dexUtils.IsExceedMaxNotional(msg.Price, msg.Quantity) { - return errors.New("notional value of the order is too large(cannot fit in int64)") - } - - return nil -} - func (kp *BaseOrderKeeper) getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { openOrders := make([]store.OpenOrder, 0) diff --git a/plugins/dex/store/mapper.go b/plugins/dex/store/mapper.go index 04798385f..0db474fc0 100644 --- a/plugins/dex/store/mapper.go +++ b/plugins/dex/store/mapper.go @@ -38,7 +38,8 @@ type mapper struct { func NewTradingPairMapper(cdc *wire.Codec, key sdk.StoreKey) TradingPairMapper { return mapper{ key: key, - cdc: cdc} + cdc: cdc, + } } func (m mapper) AddTradingPair(ctx sdk.Context, pair types.TradingPair) error { diff --git a/plugins/dex/utils/numbers.go b/plugins/dex/utils/numbers.go index 26e0534f7..2b6c881ff 100644 --- a/plugins/dex/utils/numbers.go +++ b/plugins/dex/utils/numbers.go @@ -53,15 +53,3 @@ func IsUnderMinNotional(price, qty int64) bool { return p < 1e8 } } - -func MaxOf(vars ...uint) uint { - max := vars[0] - - for _, i := range vars { - if max < i { - max = i - } - } - - return max -} diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index d1392a67f..89b82b5a6 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -47,8 +47,6 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep } if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { - coins := keeper.GetCoins(ctx, token.GetOwner()) - useAllBalance := coins.AmountOf(symbol) == burnAmount if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go index c8d215e58..e1edd4194 100644 --- a/plugins/tokens/burn/handler_test.go +++ b/plugins/tokens/burn/handler_test.go @@ -63,7 +63,7 @@ func TestHandleBurnMini(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) ctx = ctx.WithValue(baseapp.TxHashKey, "002") @@ -79,7 +79,7 @@ func TestHandleBurnMini(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 1e8-1, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 2, 1e8-1, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) @@ -98,7 +98,7 @@ func TestHandleBurnMini(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 0, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 2, 0, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) diff --git a/plugins/tokens/freeze/handler_test.go b/plugins/tokens/freeze/handler_test.go index a42a84c34..36ea5c76f 100644 --- a/plugins/tokens/freeze/handler_test.go +++ b/plugins/tokens/freeze/handler_test.go @@ -64,7 +64,7 @@ func TestHandleFreezeMini(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) @@ -109,7 +109,7 @@ func TestHandleFreezeMini(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) ctx = ctx.WithValue(baseapp.TxHashKey, "003") From 9a39fc67450e69002a71317987182005e0990d08 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 21 May 2020 19:23:55 +0800 Subject: [PATCH 62/96] register issueTinyMsg --- app/pub/helpers.go | 5 +++++ plugins/tokens/wire.go | 1 + 2 files changed, 6 insertions(+) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index ccca2a2c6..a00d43010 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "github.com/binance-chain/node/plugins/tokens/seturi" "strconv" "sync" "time" @@ -131,6 +132,10 @@ func GetBlockPublished(pool *sdk.Pool, header abci.Header, blockHash []byte) *Bl // will not cover timelock, timeUnlock, timeRelock, atomic Swap case issue.IssueMiniMsg: txAsset = msg.Symbol + case issue.IssueTinyMsg: + txAsset = msg.Symbol + case seturi.SetURIMsg: + txAsset = msg.Symbol } transactionsToPublish = append(transactionsToPublish, Transaction{ TxHash: txhash, diff --git a/plugins/tokens/wire.go b/plugins/tokens/wire.go index 4280f6d9c..f4ae7a1ff 100644 --- a/plugins/tokens/wire.go +++ b/plugins/tokens/wire.go @@ -25,5 +25,6 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(swap.ClaimHTLTMsg{}, "tokens/ClaimHTLTMsg", nil) cdc.RegisterConcrete(swap.RefundHTLTMsg{}, "tokens/RefundHTLTMsg", nil) cdc.RegisterConcrete(issue.IssueMiniMsg{}, "tokens/IssueMiniMsg", nil) + cdc.RegisterConcrete(issue.IssueTinyMsg{}, "tokens/IssueTinyMsg", nil) cdc.RegisterConcrete(seturi.SetURIMsg{}, "tokens/SetURIMsg", nil) } From 221248fda44403d1e995e6a6b41b6f0cdcd3e5e6 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Thu, 21 May 2020 20:51:03 +0800 Subject: [PATCH 63/96] clean --- plugins/dex/order/keeper.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 1a3f8af11..c39c41844 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -1011,7 +1011,7 @@ func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { return orderKeeper.getOrderChanges() } } - kp.logger.Error("pairType is not supported %d", pairType) + kp.logger.Error("pairType is not supported %d for OrderChanges", pairType) return make(OrderChanges, 0) } func (kp *DexKeeper) GetAllOrderChanges() OrderChanges { @@ -1021,7 +1021,6 @@ func (kp *DexKeeper) GetAllOrderChanges() OrderChanges { res = append(res, orderKeeper.getOrderChanges()...) } } - kp.logger.Debug("pairType is not supported %v", res) return res } @@ -1041,7 +1040,7 @@ func (kp *DexKeeper) GetOrderInfosForPub(pairType SymbolPairType) OrderInfoForPu return orderKeeper.getOrderInfosForPub() } } - kp.logger.Error("pairType is not supported %d", pairType) + kp.logger.Error("pairType is not supported %d for OrderInfosForPub", pairType) return make(OrderInfoForPublish) } From ca7778c45cc1116aa537475550a07eea5bdedc94 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 22 May 2020 19:23:16 +0800 Subject: [PATCH 64/96] clean code --- plugins/tokens/abci.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/tokens/abci.go b/plugins/tokens/abci.go index 7f807b081..6e149fa94 100644 --- a/plugins/tokens/abci.go +++ b/plugins/tokens/abci.go @@ -46,7 +46,7 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler Log: "empty symbol not permitted", } } - return queryAndMarshallToken(app, mapper, ctx, symbol, isMini) + return queryAndMarshallToken(app, mapper, ctx, symbol) case "list": // args: ["tokens", "list", , , ] if len(path) < 4 { return &abci.ResponseQuery{ @@ -111,7 +111,7 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler } } -func queryAndMarshallToken(app types.ChainApp, mapper Mapper, ctx sdk.Context, symbol string, isMini bool) *abci.ResponseQuery { +func queryAndMarshallToken(app types.ChainApp, mapper Mapper, ctx sdk.Context, symbol string) *abci.ResponseQuery { var bz []byte var err error var token types.IToken From a90d59f77dbe38ff2c298ad43d2b237585f591f4 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 22 May 2020 20:43:34 +0800 Subject: [PATCH 65/96] replace IToken interface by struct while marshal --- plugins/tokens/abci.go | 22 +++++++++++++++++++--- plugins/tokens/abci_test.go | 6 +++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/plugins/tokens/abci.go b/plugins/tokens/abci.go index 6e149fa94..e850195ad 100644 --- a/plugins/tokens/abci.go +++ b/plugins/tokens/abci.go @@ -63,6 +63,7 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler ctx := app.GetContextForCheckState() tokens := mapper.GetTokenList(ctx, showZeroSupplyTokens, isMini) + offset, err := strconv.Atoi(path[2]) if err != nil || offset < 0 || offset >= len(tokens) { return &abci.ResponseQuery{ @@ -87,9 +88,24 @@ func createAbciQueryHandler(mapper Mapper, prefix string) types.AbciQueryHandler Log: "malformed range", } } - bz, err := app.GetCodec().MarshalBinaryLengthPrefixed( - tokens[offset:end], - ) + var bz []byte + if isMini { + miniTokens := make([]*types.MiniToken, end-offset) + for i, token := range tokens[offset:end] { + miniTokens[i] = token.(*types.MiniToken) + } + bz, err = app.GetCodec().MarshalBinaryLengthPrefixed( + miniTokens, + ) + } else { + bep2Tokens := make([]*types.Token, end-offset) + for i, token := range tokens[offset:end] { + bep2Tokens[i] = token.(*types.Token) + } + bz, err = app.GetCodec().MarshalBinaryLengthPrefixed( + bep2Tokens, + ) + } if err != nil { return &abci.ResponseQuery{ Code: uint32(sdk.CodeInternal), diff --git a/plugins/tokens/abci_test.go b/plugins/tokens/abci_test.go index 4eec1132a..bc3263a8d 100644 --- a/plugins/tokens/abci_test.go +++ b/plugins/tokens/abci_test.go @@ -107,15 +107,15 @@ func Test_Tokens_ABCI_GetTokens_Success(t *testing.T) { res := app.Query(query) cdc := app.GetCodec() - actual := make([]common.IToken, 2) + actual := make([]common.Token, 2) err = cdc.UnmarshalBinaryLengthPrefixed(res.Value, &actual) if err != nil { t.Fatal(err.Error()) } assert.True(t, sdk.ABCICodeType(res.Code).IsOK()) - assert.Equal(t, []common.IToken{ - token1, token2, + assert.Equal(t, []common.Token{ + *token1, *token2, }, actual) } From 5dd0464f37b74468f1438e6213be12c8d42122cc Mon Sep 17 00:00:00 2001 From: rickyyangz Date: Mon, 25 May 2020 11:32:26 +0800 Subject: [PATCH 66/96] some refactor --- app/app.go | 3 +- app/helpers.go | 4 +- common/types/mini_token.go | 1 - plugins/dex/abci.go | 3 +- plugins/dex/aliases.go | 4 - plugins/dex/order/handler.go | 4 +- plugins/dex/order/keeper.go | 158 +++++++++++++----------------- plugins/dex/order/keeper_match.go | 20 ++-- plugins/dex/order/mini_keeper.go | 4 +- plugins/dex/order/order_keeper.go | 25 ++--- 10 files changed, 88 insertions(+), 138 deletions(-) diff --git a/app/app.go b/app/app.go index d606a3a88..08a3913ee 100644 --- a/app/app.go +++ b/app/app.go @@ -333,8 +333,7 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { stateDB := baseapp.LoadStateDB() defer stateDB.Close() - dex.InitOrders( - app.DexKeeper, + app.DexKeeper.Init( app.CheckState.Ctx, app.baseConfig.BreatheBlockInterval, app.baseConfig.BreatheBlockDaysCountBack, diff --git a/app/helpers.go b/app/helpers.go index a0bced910..35b71041a 100644 --- a/app/helpers.go +++ b/app/helpers.go @@ -29,7 +29,6 @@ import ( "github.com/binance-chain/node/common" bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/utils" - "github.com/binance-chain/node/plugins/dex" "github.com/binance-chain/node/plugins/dex/order" ) @@ -184,8 +183,7 @@ func (app *BinanceChain) getLastBreatheBlockHeight() int64 { } func (app *BinanceChain) reInitChain() error { - dex.InitOrders( - app.DexKeeper, + app.DexKeeper.Init( app.CheckState.Ctx, app.baseConfig.BreatheBlockInterval, app.baseConfig.BreatheBlockDaysCountBack, diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 8a8f1adab..7ac3c147d 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -187,7 +187,6 @@ func ValidateMapperMiniTokenSymbol(symbol string) error { } func splitSuffixedMiniTokenSymbol(suffixed string) ([]string, error) { - split := strings.SplitN(suffixed, "-", 2) if len(split) != 2 { diff --git a/plugins/dex/abci.go b/plugins/dex/abci.go index fbaf13704..bfefcf87d 100644 --- a/plugins/dex/abci.go +++ b/plugins/dex/abci.go @@ -158,8 +158,7 @@ func createAbciQueryHandler(keeper *DexKeeper, abciQueryPrefix string) app.AbciQ } } ctx := app.GetContextForCheckState() - existingPair, err := keeper.PairMapper.GetTradingPair(ctx, baseAsset, quoteAsset) - if pair != existingPair.GetSymbol() || err != nil { + if !keeper.PairMapper.Exists(ctx, baseAsset, quoteAsset) { return &abci.ResponseQuery{ Code: uint32(sdk.CodeInternal), Log: "pair is not listed", diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index fa258fe05..9e7d34657 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -10,13 +10,9 @@ import ( // type TradingPair = types.TradingPair type TradingPairMapper = store.TradingPairMapper -type IDexOrderKeeper = order.IDexOrderKeeper type DexKeeper = order.DexKeeper -type SymbolPairType = order.SymbolPairType var NewTradingPairMapper = store.NewTradingPairMapper var NewDexKeeper = order.NewDexKeeper -var PairType = order.PairType -var InitOrders = order.Init const DefaultCodespace = types.DefaultCodespace diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index 705bf6f00..19f6703c7 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -143,7 +143,7 @@ func handleNewOrder( if txSrc, ok := ctx.Value(baseapp.TxSourceKey).(int64); ok { txSource = txSrc } else { - dexKeeper.getLogger().Error("cannot get txSource from ctx") + dexKeeper.logger.Error("cannot get txSource from ctx") } }) msg := OrderInfo{ @@ -205,7 +205,7 @@ func handleCancelOrder( fee := common.Fee{} if !transfer.FeeFree() { acc := dexKeeper.am.GetAccount(ctx, msg.Sender) - fee = dexKeeper.getFeeManager().CalcFixedFee(acc.GetCoins(), transfer.eventType, transfer.inAsset, dexKeeper.GetEngines()) + fee = dexKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), transfer.eventType, transfer.inAsset, dexKeeper.GetEngines()) acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) dexKeeper.am.SetAccount(ctx, acc) } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index c39c41844..ad8a96b7c 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -57,14 +57,15 @@ type DexKeeper struct { RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee CollectOrderInfoForPublish bool engines map[string]*me.MatchEng + pairsType map[string]SymbolPairType logger tmlog.Logger poolSize uint // number of concurrent channels, counted in the pow of 2 cdc *wire.Codec - OrderKeepers []IDexOrderKeeper + OrderKeepers []DexOrderKeeper } func NewDexKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, concurrency uint, cdc *wire.Codec, collectOrderInfoForPublish bool) *DexKeeper { - logger := bnclog.With("module", "dex_keeper") + logger := bnclog.With("module", "dexkeeper") return &DexKeeper{ PairMapper: tradingPairMapper, storeKey: key, @@ -75,33 +76,48 @@ func NewDexKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper sto FeeManager: NewFeeManager(cdc, logger), CollectOrderInfoForPublish: collectOrderInfoForPublish, engines: make(map[string]*me.MatchEng), + pairsType: make(map[string]SymbolPairType), poolSize: concurrency, cdc: cdc, logger: logger, - OrderKeepers: []IDexOrderKeeper{NewBEP2OrderKeeper(), NewMiniOrderKeeper()}, + OrderKeepers: []DexOrderKeeper{NewBEP2OrderKeeper(), NewMiniOrderKeeper()}, } } -func Init(dexKeeper *DexKeeper, ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { - dexKeeper.initOrderBook(ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) - dexKeeper.InitRecentPrices(ctx) +func (kp *DexKeeper) Init(ctx sdk.Context, blockInterval, daysBack int, blockStore *tmstore.BlockStore, stateDB dbm.DB, lastHeight int64, txDecoder sdk.TxDecoder) { + kp.initOrderBook(ctx, blockInterval, daysBack, blockStore, stateDB, lastHeight, txDecoder) + kp.InitRecentPrices(ctx) +} + +func (kp *DexKeeper) InitRecentPrices(ctx sdk.Context) { + kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) } func (kp *DexKeeper) SetBUSDSymbol(symbol string) { BUSDSymbol = symbol } -func (kp *DexKeeper) GetSupportedOrderKeeper(pair string) (IDexOrderKeeper, error) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(pair) { - return orderKeeper, nil +func (kp *DexKeeper) getOrderKeeper(symbol string) (DexOrderKeeper, error) { + pairType := kp.pairsType[symbol] + for i := range kp.OrderKeepers { + if kp.OrderKeepers[i].supportPairType(pairType) { + return kp.OrderKeepers[i], nil } } - return nil, fmt.Errorf("failed to find orderKeeper for symbol pair [%v]", pair) + err := fmt.Errorf("failed to find orderKeeper for symbol pair [%v]", symbol) + kp.logger.Error(err.Error()) + return nil, err } -func (kp *DexKeeper) InitRecentPrices(ctx sdk.Context) { - kp.recentPrices = kp.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored) +func (kp *DexKeeper) mustGetOrderKeeper(symbol string) DexOrderKeeper { + pairType := kp.pairsType[symbol] + for i := range kp.OrderKeepers { + if kp.OrderKeepers[i].supportPairType(pairType) { + return kp.OrderKeepers[i] + } + } + + panic(fmt.Errorf("invalid symbol %s", symbol)) } func (kp *DexKeeper) UpdateTickSizeAndLotSize(ctx sdk.Context) { @@ -184,10 +200,15 @@ func (kp *DexKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { symbol := strings.ToUpper(pair.GetSymbol()) eng := CreateMatchEng(symbol, pair.ListPrice.ToInt64(), pair.LotSize.ToInt64()) kp.engines[symbol] = eng - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { - dexOrderKeeper.initOrders(symbol) - } else { - kp.logger.Error(err.Error()) + pairType := PairType.BEP2 + if dexUtils.IsMiniTokenTradingPair(symbol) { + pairType = PairType.MINI + } + kp.pairsType[symbol] = pairType + for i := range kp.OrderKeepers { + if kp.OrderKeepers[i].supportPairType(pairType) { + kp.OrderKeepers[i].initOrders(symbol) + } } return eng } @@ -206,13 +227,7 @@ func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { return err } - if dexOrderKeeper, keeperNotFoundErr := kp.GetSupportedOrderKeeper(symbol); keeperNotFoundErr == nil { - dexOrderKeeper.addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) - } else { - //Should not happen. - kp.logger.Error(keeperNotFoundErr.Error()) - } - + kp.mustGetOrderKeeper(symbol).addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) return nil } @@ -221,13 +236,16 @@ func orderNotFound(symbol, id string) error { return fmt.Errorf("Failed to find order [%v] on symbol [%v]", id, symbol) } -func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { +func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler func(ord me.OrderPart)) error { symbol = strings.ToUpper(symbol) - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { - return dexOrderKeeper.removeOrder(kp, id, symbol, postCancelHandler) - } else { - //Leave it for debug. Return orderNotFound error for compatibility with the logic before BEP8 upgrade - kp.logger.Debug(err.Error()) + if dexOrderKeeper, err := kp.getOrderKeeper(symbol); err == nil { + ord, err := dexOrderKeeper.removeOrder(kp, id, symbol) + if err != nil { + return err + } + if postCancelHandler != nil { + postCancelHandler(ord) + } } return orderNotFound(symbol, id) } @@ -246,10 +264,8 @@ func (kp *DexKeeper) GetOrder(id string, symbol string, side int8, price int64) } func (kp *DexKeeper) OrderExists(symbol, id string) (OrderInfo, bool) { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { + if dexOrderKeeper, err := kp.getOrderKeeper(symbol); err == nil { return dexOrderKeeper.orderExists(symbol, id) - } else { - kp.logger.Debug(err.Error()) } return OrderInfo{}, false } @@ -309,36 +325,26 @@ func (kp *DexKeeper) GetOrderBookLevels(pair string, maxLevels int) (orderbook [ orderbook = make([]store.OrderBookLevel, maxLevels) i, j := 0, 0 - if eng, ok := kp.engines[pair]; ok { // TODO: check considered bucket splitting? eng.Book.ShowDepth(maxLevels, func(p *me.PriceLevel, levelIndex int) { orderbook[i].BuyPrice = utils.Fixed8(p.Price) orderbook[i].BuyQty = utils.Fixed8(p.TotalLeavesQty()) i++ - }, - func(p *me.PriceLevel, levelIndex int) { - orderbook[j].SellPrice = utils.Fixed8(p.Price) - orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) - j++ - }) - var roundOrders []string - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(pair); err == nil { - roundOrders = dexOrderKeeper.getRoundOrdersForPair(pair) - } else { - kp.logger.Error(err.Error()) - } - + }, func(p *me.PriceLevel, levelIndex int) { + orderbook[j].SellPrice = utils.Fixed8(p.Price) + orderbook[j].SellQty = utils.Fixed8(p.TotalLeavesQty()) + j++ + }) + roundOrders := kp.mustGetOrderKeeper(pair).getRoundOrdersForPair(pair) pendingMatch = len(roundOrders) > 0 } return orderbook, pendingMatch } func (kp *DexKeeper) GetOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(pair); err == nil { + if dexOrderKeeper, err := kp.getOrderKeeper(pair); err == nil { return dexOrderKeeper.getOpenOrders(pair, addr) - } else { - kp.logger.Debug(err.Error()) } return make([]store.OpenOrder, 0) } @@ -873,12 +879,7 @@ func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAlloc delete(kp.engines, symbol) delete(kp.recentPrices, symbol) - - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { - dexOrderKeeper.deleteOrdersForPair(symbol) - } else { - kp.logger.Debug(err.Error()) - } + kp.mustGetOrderKeeper(symbol).deleteOrdersForPair(symbol) baseAsset, quoteAsset := dexUtils.TradingPair2AssetsSafe(symbol) err := kp.PairMapper.DeleteTradingPair(ctx, baseAsset, quoteAsset) @@ -889,11 +890,8 @@ func (kp *DexKeeper) DelistTradingPair(ctx sdk.Context, symbol string, postAlloc func (kp *DexKeeper) expireAllOrders(ctx sdk.Context, symbol string) []chan Transfer { ordersOfSymbol := make(map[string]*OrderInfo) - - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { + if dexOrderKeeper, err := kp.getOrderKeeper(symbol); err == nil { ordersOfSymbol = dexOrderKeeper.getAllOrdersForPair(symbol) - } else { - kp.logger.Debug(err.Error()) } orderNum := len(ordersOfSymbol) @@ -987,22 +985,13 @@ func (kp *DexKeeper) GetAllOrders() map[string]map[string]*OrderInfo { return allOrders } +// ONLY FOR TEST USE func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo { - ordersOfSymbol := make(map[string]*OrderInfo) - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { - ordersOfSymbol = dexOrderKeeper.getAllOrdersForPair(symbol) - } else { - kp.logger.Debug(err.Error()) - } - return ordersOfSymbol + return kp.mustGetOrderKeeper(symbol).getAllOrdersForPair(symbol) } func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { - dexOrderKeeper.reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) - } else { - kp.logger.Error(err.Error()) - } + kp.mustGetOrderKeeper(symbol).reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) } func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { @@ -1025,11 +1014,9 @@ func (kp *DexKeeper) GetAllOrderChanges() OrderChanges { } func (kp *DexKeeper) UpdateOrderChangeSync(change OrderChange, symbol string) { - if dexOrderKeeper, err := kp.GetSupportedOrderKeeper(symbol); err == nil { + if dexOrderKeeper, err := kp.getOrderKeeper(symbol); err == nil { dexOrderKeeper.appendOrderChangeSync(change) return - } else { - kp.logger.Debug(err.Error()) } kp.logger.Error("symbol is not supported %d", symbol) } @@ -1055,25 +1042,12 @@ func (kp *DexKeeper) GetAllOrderInfosForPub() OrderInfoForPublish { } func (kp *DexKeeper) RemoveOrderInfosForPub(pair string, orderId string) { - for _, orderKeeper := range kp.OrderKeepers { - if orderKeeper.support(pair) { - orderKeeper.removeOrderInfosForPub(orderId) - return - } + if orderKeeper, err := kp.getOrderKeeper(pair); err == nil { + orderKeeper.removeOrderInfosForPub(orderId) + return } - kp.logger.Error("pair is not supported %d", pair) -} - -func (kp *DexKeeper) GetPairMapper() store.TradingPairMapper { - return kp.PairMapper -} -func (kp *DexKeeper) getLogger() tmlog.Logger { - return kp.logger -} - -func (kp *DexKeeper) getFeeManager() *FeeManager { - return kp.FeeManager + kp.logger.Error("pair is not supported %d", pair) } func (kp *DexKeeper) ShouldPublishOrder() bool { diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 79fa7871f..43977d82d 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -37,21 +37,14 @@ func (kp *DexKeeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandl kp.ClearAfterMatch() } -type symbolKeeper struct { - symbol string - orderKeeper IDexOrderKeeper -} - // please note if distributeTrade this method will work in async mode, otherwise in sync mode. // Always run kp.SelectSymbolsToMatch(ctx.BlockHeader().Height, timestamp, matchAllSymbols) before matchAndDistributeTrades func (kp *DexKeeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64) []chan Transfer { - concurrency := 1 << kp.poolSize tradeOuts := make([]chan Transfer, concurrency) if distributeTrade { ordNum := 0 - for i := range kp.OrderKeepers { ordNum += kp.OrderKeepers[i].getRoundOrdersNum() } @@ -62,18 +55,18 @@ func (kp *DexKeeper) matchAndDistributeTrades(distributeTrade bool, height, time } } - symbolCh := make(chan symbolKeeper, concurrency) + symbolCh := make(chan string, concurrency) producer := func() { for i := range kp.OrderKeepers { kp.OrderKeepers[i].iterateRoundPairs(func(symbol string) { - symbolCh <- symbolKeeper{symbol: symbol, orderKeeper: kp.OrderKeepers[i]} + symbolCh <- symbol }) } close(symbolCh) } matchWorker := func() { - for sk := range symbolCh { - kp.matchAndDistributeTradesForSymbol(sk.symbol, sk.orderKeeper, height, timestamp, distributeTrade, tradeOuts) + for symbol := range symbolCh { + kp.matchAndDistributeTradesForSymbol(symbol, height, timestamp, distributeTrade, tradeOuts) } } @@ -103,10 +96,11 @@ func (kp *DexKeeper) MatchSymbols(height, timestamp int64, matchAllSymbols bool) kp.ClearAfterMatch() } -func (kp *DexKeeper) matchAndDistributeTradesForSymbol(symbol string, orderKeeper IDexOrderKeeper, height, timestamp int64, - distributeTrade bool, tradeOuts []chan Transfer) { +func (kp *DexKeeper) matchAndDistributeTradesForSymbol(symbol string, height, timestamp int64, distributeTrade bool, + tradeOuts []chan Transfer) { engine := kp.engines[symbol] concurrency := len(tradeOuts) + orderKeeper := kp.mustGetOrderKeeper(symbol) orders := orderKeeper.getAllOrdersForPair(symbol) var lastMatchHeight int64 if dexUtils.IsMiniTokenTradingPair(symbol) { diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 26ae1d602..c5f00e8d4 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -18,10 +18,10 @@ type MiniOrderKeeper struct { BaseOrderKeeper } -var _ IDexOrderKeeper = &MiniOrderKeeper{} +var _ DexOrderKeeper = &MiniOrderKeeper{} // NewBEP2OrderKeeper - Returns the MiniToken orderKeeper -func NewMiniOrderKeeper() IDexOrderKeeper { +func NewMiniOrderKeeper() DexOrderKeeper { return &MiniOrderKeeper{ NewBaseOrderKeeper("dexMiniKeeper", &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}), diff --git a/plugins/dex/order/order_keeper.go b/plugins/dex/order/order_keeper.go index 2a765df80..8240b0463 100644 --- a/plugins/dex/order/order_keeper.go +++ b/plugins/dex/order/order_keeper.go @@ -20,9 +20,9 @@ const ( minimalNumPrices = 500 ) -type IDexOrderKeeper interface { +type DexOrderKeeper interface { addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) - removeOrder(dexKeeper *DexKeeper, id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) + removeOrder(dexKeeper *DexKeeper, id string, symbol string) (ord me.OrderPart, err error) orderExists(symbol, id string) (OrderInfo, bool) getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder getAllOrders() map[string]map[string]*OrderInfo @@ -53,7 +53,7 @@ type BEP2OrderKeeper struct { BaseOrderKeeper } -var _ IDexOrderKeeper = &BEP2OrderKeeper{} +var _ DexOrderKeeper = &BEP2OrderKeeper{} // in the future, this may be distributed via Sharding type BaseOrderKeeper struct { @@ -70,7 +70,7 @@ type BaseOrderKeeper struct { } // NewBEP2OrderKeeper - Returns the BEP2OrderKeeper -func NewBEP2OrderKeeper() IDexOrderKeeper { +func NewBEP2OrderKeeper() DexOrderKeeper { return &BEP2OrderKeeper{ NewBaseOrderKeeper("Bep2OrderKeeper", &BEP2SymbolSelector{}), } @@ -128,26 +128,17 @@ func (kp *BaseOrderKeeper) orderExists(symbol, id string) (OrderInfo, bool) { return OrderInfo{}, false } -func (kp *BaseOrderKeeper) removeOrder(dexKeeper *DexKeeper, id string, symbol string, postCancelHandler func(ord me.OrderPart)) (err error) { - +func (kp *BaseOrderKeeper) removeOrder(dexKeeper *DexKeeper, id string, symbol string) (ord me.OrderPart, err error) { ordMsg, ok := kp.orderExists(symbol, id) if !ok { - return orderNotFound(symbol, id) + return me.OrderPart{}, orderNotFound(symbol, id) } eng, ok := dexKeeper.engines[symbol] if !ok { - return orderNotFound(symbol, id) + return me.OrderPart{}, orderNotFound(symbol, id) } delete(kp.allOrders[symbol], id) - ord, err := eng.Book.RemoveOrder(id, ordMsg.Side, ordMsg.Price) - if err != nil { - return err - } - - if postCancelHandler != nil { - postCancelHandler(ord) - } - return nil + return eng.Book.RemoveOrder(id, ordMsg.Side, ordMsg.Price) } func (kp *BaseOrderKeeper) deleteOrdersForPair(pair string) { From 931952d5341aa25cfe903d6e5f7fd0b771c7616c Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 25 May 2020 11:44:26 +0800 Subject: [PATCH 67/96] change list-mini route --- plugins/dex/aliases.go | 3 --- plugins/dex/list/handler.go | 4 +++- plugins/dex/list/handler_mini.go | 31 +------------------------------ plugins/dex/list/msg_mini.go | 6 +++--- plugins/dex/route.go | 1 - plugins/param/plugin.go | 2 +- 6 files changed, 8 insertions(+), 39 deletions(-) diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index fa258fe05..4c3f9408d 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -10,13 +10,10 @@ import ( // type TradingPair = types.TradingPair type TradingPairMapper = store.TradingPairMapper -type IDexOrderKeeper = order.IDexOrderKeeper type DexKeeper = order.DexKeeper -type SymbolPairType = order.SymbolPairType var NewTradingPairMapper = store.NewTradingPairMapper var NewDexKeeper = order.NewDexKeeper -var PairType = order.PairType var InitOrders = order.Init const DefaultCodespace = types.DefaultCodespace diff --git a/plugins/dex/list/handler.go b/plugins/dex/list/handler.go index a94e1b3e5..a8118ff4b 100644 --- a/plugins/dex/list/handler.go +++ b/plugins/dex/list/handler.go @@ -23,6 +23,8 @@ func NewHandler(keeper *order.DexKeeper, tokenMapper tokens.Mapper, govKeeper go switch msg := msg.(type) { case ListMsg: return handleList(ctx, keeper, tokenMapper, govKeeper, msg) + case ListMiniMsg: + return handleListMini(ctx, keeper, tokenMapper, msg) default: errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) return sdk.ErrUnknownRequest(errMsg).Result() @@ -90,7 +92,7 @@ func handleList(ctx sdk.Context, keeper *order.DexKeeper, tokenMapper tokens.Map } if sdk.IsUpgrade(upgrade.ListingRuleUpgrade) { - quoteToken, err := tokenMapper.GetToken(ctx, msg.QuoteAssetSymbol) //todo + quoteToken, err := tokenMapper.GetToken(ctx, msg.QuoteAssetSymbol) if err != nil { return sdk.ErrInvalidCoins(err.Error()).Result() } diff --git a/plugins/dex/list/handler_mini.go b/plugins/dex/list/handler_mini.go index 3fdc5f84d..fc8cb46be 100644 --- a/plugins/dex/list/handler_mini.go +++ b/plugins/dex/list/handler_mini.go @@ -1,36 +1,15 @@ package list import ( - "fmt" - "reflect" - "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/types" - "github.com/binance-chain/node/plugins/dex/utils" "github.com/binance-chain/node/plugins/tokens" sdk "github.com/cosmos/cosmos-sdk/types" ) -// NewHandler initialises dex message handlers -func NewMiniHandler(dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case ListMiniMsg: - return handleListMini(ctx, dexKeeper, tokenMapper, msg) - default: - errMsg := fmt.Sprintf("Unrecognized dex msg type: %v", reflect.TypeOf(msg).Name()) - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - func handleListMini(ctx sdk.Context, dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper, msg ListMiniMsg) sdk.Result { - if !sdk.IsUpgrade(upgrade.BEP8) { - return sdk.ErrInternal(fmt.Sprint("list mini-token is not supported at current height")).Result() - } if err := dexKeeper.CanListTradingPair(ctx, msg.BaseAssetSymbol, msg.QuoteAssetSymbol); err != nil { return sdk.ErrInvalidCoins(err.Error()).Result() @@ -50,16 +29,8 @@ func handleListMini(ctx sdk.Context, dexKeeper *order.DexKeeper, tokenMapper tok return sdk.ErrUnauthorized("only the owner of the base asset or quote asset can list the trading pair").Result() } - if !tokenMapper.Exists(ctx, msg.QuoteAssetSymbol) { - return sdk.ErrInvalidCoins("quote token does not exist").Result() - } + lotSize := dexKeeper.DetermineLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice) - var lotSize int64 - if sdk.IsUpgrade(upgrade.LotSizeOptimization) { - lotSize = dexKeeper.DetermineLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice) - } else { - lotSize = utils.CalcLotSize(msg.InitPrice) - } pair := types.NewTradingPairWithLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice, lotSize) err = dexKeeper.PairMapper.AddTradingPair(ctx, pair) if err != nil { diff --git a/plugins/dex/list/msg_mini.go b/plugins/dex/list/msg_mini.go index bc4494891..c940dc0bd 100644 --- a/plugins/dex/list/msg_mini.go +++ b/plugins/dex/list/msg_mini.go @@ -10,7 +10,7 @@ import ( "github.com/binance-chain/node/plugins/dex/order" ) -const MiniRoute = "dexListMini" +const MiniMsg = "dexListMini" var _ sdk.Msg = ListMiniMsg{} @@ -30,8 +30,8 @@ func NewMiniMsg(from sdk.AccAddress, baseAssetSymbol string, quoteAssetSymbol st } } -func (msg ListMiniMsg) Route() string { return MiniRoute } -func (msg ListMiniMsg) Type() string { return MiniRoute } +func (msg ListMiniMsg) Route() string { return Route } +func (msg ListMiniMsg) Type() string { return MiniMsg } func (msg ListMiniMsg) String() string { return fmt.Sprintf("MsgListMini{%#v}", msg) } func (msg ListMiniMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } diff --git a/plugins/dex/route.go b/plugins/dex/route.go index 1a873eda8..88ea04933 100644 --- a/plugins/dex/route.go +++ b/plugins/dex/route.go @@ -19,6 +19,5 @@ func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, routes[order.RouteNewOrder] = orderHandler routes[order.RouteCancelOrder] = orderHandler routes[list.Route] = list.NewHandler(dexKeeper, tokenMapper, govKeeper) - routes[list.MiniRoute] = list.NewMiniHandler(dexKeeper, tokenMapper) return routes } diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index d5a1a62c0..22be84db8 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -105,6 +105,6 @@ func init() { issue.IssueTinyMsgType: fees.FixedFeeCalculatorGen, issue.IssueMiniMsgType: fees.FixedFeeCalculatorGen, miniURI.SetURIRoute: fees.FixedFeeCalculatorGen, - list.MiniRoute: fees.FixedFeeCalculatorGen, + list.ListMiniMsg{}.Type(): fees.FixedFeeCalculatorGen, } } From 70084251edf1da9c37e9118a0982e44802a9f18b Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 25 May 2020 12:18:18 +0800 Subject: [PATCH 68/96] merge mini handler --- plugins/tokens/burn/handler_test.go | 9 ++++----- plugins/tokens/freeze/handler_test.go | 9 ++++----- plugins/tokens/issue/handler.go | 5 ++++- plugins/tokens/issue/handler_mini.go | 16 ---------------- plugins/tokens/issue/handler_mini_test.go | 2 +- plugins/tokens/issue/handler_test.go | 9 ++++----- plugins/tokens/issue/msg_mini.go | 3 +-- plugins/tokens/issue/msg_tiny.go | 2 +- plugins/tokens/route.go | 1 - plugins/tokens/seturi/handler_test.go | 9 ++++----- 10 files changed, 23 insertions(+), 42 deletions(-) diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go index e1edd4194..aa406c285 100644 --- a/plugins/tokens/burn/handler_test.go +++ b/plugins/tokens/burn/handler_test.go @@ -21,7 +21,7 @@ import ( "github.com/binance-chain/node/wire" ) -func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { +func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() cdc := wire.NewCodec() cdc.RegisterInterface((*types.IToken)(nil), nil) @@ -32,14 +32,13 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKe bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, bankKeeper) tokenHandler := issue.NewHandler(tokenMapper, bankKeeper) - miniTokenHandler := issue.NewMiniHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, sdk.RunTxModeDeliver, log.NewNopLogger()). WithAccountCache(auth.NewAccountCache(accountStoreCache)) - return ctx, handler, tokenHandler, miniTokenHandler, accountKeeper, tokenMapper + return ctx, handler, tokenHandler, accountKeeper, tokenMapper } func setChainVersion() { @@ -53,7 +52,7 @@ func resetChainVersion() { func TestHandleBurnMini(t *testing.T) { setChainVersion() defer resetChainVersion() - ctx, handler, _, miniIssueHandler, accountKeeper, tokenMapper := setup() + ctx, handler, miniIssueHandler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") @@ -116,7 +115,7 @@ func TestHandleBurnMini(t *testing.T) { func TestHandleBurn(t *testing.T) { setChainVersion() defer resetChainVersion() - ctx, handler, issueHandler, _, accountKeeper, tokenMapper := setup() + ctx, handler, issueHandler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") diff --git a/plugins/tokens/freeze/handler_test.go b/plugins/tokens/freeze/handler_test.go index 36ea5c76f..565567039 100644 --- a/plugins/tokens/freeze/handler_test.go +++ b/plugins/tokens/freeze/handler_test.go @@ -21,7 +21,7 @@ import ( "github.com/binance-chain/node/wire" ) -func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { +func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() cdc := wire.NewCodec() cdc.RegisterInterface((*types.IToken)(nil), nil) @@ -33,14 +33,13 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, sdk.Handler, auth.AccountKe bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, accountKeeper, bankKeeper) tokenHandler := issue.NewHandler(tokenMapper, bankKeeper) - miniTokenHandler := issue.NewMiniHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, sdk.RunTxModeDeliver, log.NewNopLogger()). WithAccountCache(auth.NewAccountCache(accountStoreCache)) - return ctx, handler, tokenHandler, miniTokenHandler, accountKeeper, tokenMapper + return ctx, handler, tokenHandler, accountKeeper, tokenMapper } func setChainVersion() { @@ -54,7 +53,7 @@ func resetChainVersion() { func TestHandleFreezeMini(t *testing.T) { setChainVersion() defer resetChainVersion() - ctx, handler, _, miniIssueHandler, accountKeeper, tokenMapper := setup() + ctx, handler, miniIssueHandler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") @@ -150,7 +149,7 @@ func TestHandleFreezeMini(t *testing.T) { func TestHandleFreeze(t *testing.T) { setChainVersion() defer resetChainVersion() - ctx, handler, issueHandler, _, accountKeeper, tokenMapper := setup() + ctx, handler, issueHandler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index f34008080..6aa01809d 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -27,7 +27,10 @@ func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return handleIssueToken(ctx, tokenMapper, keeper, msg) case MintMsg: return handleMintToken(ctx, tokenMapper, keeper, msg) - + case IssueMiniMsg: + return msg.handleIssueMiniToken(ctx, tokenMapper, keeper, common.MiniRangeType) + case IssueTinyMsg: + return msg.handleIssueMiniToken(ctx, tokenMapper, keeper, common.TinyRangeType) default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() diff --git a/plugins/tokens/issue/handler_mini.go b/plugins/tokens/issue/handler_mini.go index 78ebd8127..f0886ce58 100644 --- a/plugins/tokens/issue/handler_mini.go +++ b/plugins/tokens/issue/handler_mini.go @@ -3,7 +3,6 @@ package issue import ( "encoding/json" "fmt" - "reflect" "strings" "github.com/cosmos/cosmos-sdk/baseapp" @@ -16,21 +15,6 @@ import ( "github.com/binance-chain/node/plugins/tokens/store" ) -// NewHandler creates a new token issue message handler -func NewMiniHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case IssueMiniMsg: - return msg.handleIssueMiniToken(ctx, tokenMapper, keeper, common.MiniRangeType) - case IssueTinyMsg: - return msg.handleIssueMiniToken(ctx, tokenMapper, keeper, common.TinyRangeType) - default: - errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - func (msg IssueMiniMsg) handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, tokenType common.SupplyRangeType) sdk.Result { errLogMsg := "issue miniToken failed" symbol := strings.ToUpper(msg.Symbol) diff --git a/plugins/tokens/issue/handler_mini_test.go b/plugins/tokens/issue/handler_mini_test.go index c93de1885..c808e07da 100644 --- a/plugins/tokens/issue/handler_mini_test.go +++ b/plugins/tokens/issue/handler_mini_test.go @@ -29,7 +29,7 @@ func setupMini() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { tokenMapper := store.NewMapper(cdc, capKey1) accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(accountKeeper) - handler := NewMiniHandler(tokenMapper, bankKeeper) + handler := NewHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 1309416aa..16d8e5827 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -20,7 +20,7 @@ import ( "github.com/binance-chain/node/wire" ) -func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { +func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { ms, capKey1, capKey2, _ := testutils.SetupThreeMultiStoreForUnitTest() cdc := wire.NewCodec() cdc.RegisterInterface((*types.IToken)(nil), nil) @@ -30,13 +30,12 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.M accountKeeper := auth.NewAccountKeeper(cdc, capKey2, auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(accountKeeper) handler := NewHandler(tokenMapper, bankKeeper) - miniTokenHandler := NewMiniHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, sdk.RunTxModeDeliver, log.NewNopLogger()). WithAccountCache(auth.NewAccountCache(accountStoreCache)) - return ctx, handler, miniTokenHandler, accountKeeper, tokenMapper + return ctx, handler, accountKeeper, tokenMapper } func setChainVersion() { @@ -48,7 +47,7 @@ func resetChainVersion() { } func TestHandleIssueToken(t *testing.T) { - ctx, handler, _, accountKeeper, tokenMapper := setup() + ctx, handler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") @@ -65,7 +64,7 @@ func TestHandleIssueToken(t *testing.T) { } func TestHandleMintToken(t *testing.T) { - ctx, handler, _, accountKeeper, tokenMapper := setup() + ctx, handler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000", 10000e8) sdkResult := handler(ctx, mintMsg) diff --git a/plugins/tokens/issue/msg_mini.go b/plugins/tokens/issue/msg_mini.go index 97e226639..e3f4f170d 100644 --- a/plugins/tokens/issue/msg_mini.go +++ b/plugins/tokens/issue/msg_mini.go @@ -13,7 +13,6 @@ import ( // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash // const Route = "tokens/issue" const ( - MiniRoute = "miniTokensIssue" IssueMiniMsgType = "miniIssueMsg" //For max total supply in range 2 ) @@ -70,7 +69,7 @@ func (msg IssueMiniMsg) ValidateBasic() sdk.Error { } // Implements IssueMiniMsg. -func (msg IssueMiniMsg) Route() string { return MiniRoute } +func (msg IssueMiniMsg) Route() string { return Route } func (msg IssueMiniMsg) Type() string { return IssueMiniMsgType } diff --git a/plugins/tokens/issue/msg_tiny.go b/plugins/tokens/issue/msg_tiny.go index 1a7baf96f..6335344b7 100644 --- a/plugins/tokens/issue/msg_tiny.go +++ b/plugins/tokens/issue/msg_tiny.go @@ -65,7 +65,7 @@ func (msg IssueTinyMsg) ValidateBasic() sdk.Error { } // Implements IssueTinyMsg. -func (msg IssueTinyMsg) Route() string { return MiniRoute } +func (msg IssueTinyMsg) Route() string { return Route } func (msg IssueTinyMsg) Type() string { return IssueTinyMsgType } diff --git a/plugins/tokens/route.go b/plugins/tokens/route.go index 37fd12913..b084fdda3 100644 --- a/plugins/tokens/route.go +++ b/plugins/tokens/route.go @@ -22,7 +22,6 @@ func Routes(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper bank. routes[freeze.FreezeRoute] = freeze.NewHandler(tokenMapper, accKeeper, keeper) routes[timelock.MsgRoute] = timelock.NewHandler(timeLockKeeper) routes[swap.AtomicSwapRoute] = swap.NewHandler(swapKeeper) - routes[issue.MiniRoute] = issue.NewMiniHandler(tokenMapper, keeper) routes[seturi.SetURIRoute] = seturi.NewHandler(tokenMapper) return routes } diff --git a/plugins/tokens/seturi/handler_test.go b/plugins/tokens/seturi/handler_test.go index 3b8a22c37..e60323e68 100644 --- a/plugins/tokens/seturi/handler_test.go +++ b/plugins/tokens/seturi/handler_test.go @@ -21,7 +21,7 @@ import ( "github.com/binance-chain/node/wire" ) -func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { +func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() cdc := wire.NewCodec() cdc.RegisterInterface((*types.IToken)(nil), nil) @@ -32,14 +32,13 @@ func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.M handler := NewHandler(tokenMapper) bankKeeper := bank.NewBaseKeeper(accountKeeper) - miniTokenHandler := issue.NewMiniHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, sdk.RunTxModeDeliver, log.NewNopLogger()). WithAccountCache(auth.NewAccountCache(accountStoreCache)) - return ctx, handler, miniTokenHandler, accountKeeper, tokenMapper + return ctx, handler, accountKeeper, tokenMapper } func setChainVersion() { @@ -53,12 +52,12 @@ func resetChainVersion() { func TestHandleSetURI(t *testing.T) { setChainVersion() defer resetChainVersion() - ctx, handler, miniIssueHandler, accountKeeper, tokenMapper := setup() + ctx, handler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false, "http://www.xyz.com/nnb.json") - sdkResult := miniIssueHandler(ctx, msg) + sdkResult := handler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) token, err := tokenMapper.GetToken(ctx, "NNB-000M") From 6451b5ddac25450127506ed30f7324f6599cd18b Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 25 May 2020 12:33:50 +0800 Subject: [PATCH 69/96] fix ut --- plugins/dex/order/keeper.go | 2 +- plugins/tokens/abci_test.go | 12 ++++++------ plugins/tokens/issue/handler_mini_test.go | 6 +++--- plugins/tokens/seturi/handler_test.go | 9 +++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index c39c41844..31190d666 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -55,7 +55,7 @@ type DexKeeper struct { am auth.AccountKeeper FeeManager *FeeManager RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee - CollectOrderInfoForPublish bool + CollectOrderInfoForPublish bool //TODO seperate for each order keeper engines map[string]*me.MatchEng logger tmlog.Logger poolSize uint // number of concurrent channels, counted in the pow of 2 diff --git a/plugins/tokens/abci_test.go b/plugins/tokens/abci_test.go index bc3263a8d..e949c03cd 100644 --- a/plugins/tokens/abci_test.go +++ b/plugins/tokens/abci_test.go @@ -139,15 +139,15 @@ func Test_Tokens_ABCI_GetTokens_Success_WithOffset(t *testing.T) { res := app.Query(query) cdc := app.GetCodec() - actual := make([]common.IToken, 1) + actual := make([]common.Token, 1) err = cdc.UnmarshalBinaryLengthPrefixed(res.Value, &actual) if err != nil { t.Fatal(err.Error()) } assert.True(t, sdk.ABCICodeType(res.Code).IsOK()) - assert.Equal(t, []common.IToken{ - token2, + assert.Equal(t, []common.Token{ + *token2, }, actual) } @@ -171,15 +171,15 @@ func Test_Tokens_ABCI_GetTokens_Success_WithLimit(t *testing.T) { res := app.Query(query) cdc := app.GetCodec() - actual := make([]common.IToken, 1) + actual := make([]common.Token, 1) err = cdc.UnmarshalBinaryLengthPrefixed(res.Value, &actual) if err != nil { t.Fatal(err.Error()) } assert.True(t, sdk.ABCICodeType(res.Code).IsOK()) - assert.Equal(t, []common.IToken{ - token1, + assert.Equal(t, []common.Token{ + *token1, }, actual) } diff --git a/plugins/tokens/issue/handler_mini_test.go b/plugins/tokens/issue/handler_mini_test.go index c808e07da..2cbd5dee8 100644 --- a/plugins/tokens/issue/handler_mini_test.go +++ b/plugins/tokens/issue/handler_mini_test.go @@ -84,7 +84,7 @@ func TestHandleIssueMiniToken(t *testing.T) { func TestHandleMintMiniToken(t *testing.T) { setChainVersion() defer resetChainVersion() - ctx, handler, miniTokenHandler, accountKeeper, tokenMapper := setup() + ctx, handler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) mintMsg := NewMintMsg(acc.GetAddress(), "NNB-000M", 1001e8) sdkResult := handler(ctx, mintMsg) @@ -92,7 +92,7 @@ func TestHandleMintMiniToken(t *testing.T) { issueMsg := NewIssueTinyMsg(acc.GetAddress(), "New BNB", "NNB", 9000e8, true, "http://www.xyz.com/nnb.json") ctx = ctx.WithValue(baseapp.TxHashKey, "000") - sdkResult = miniTokenHandler(ctx, issueMsg) + sdkResult = handler(ctx, issueMsg) require.Equal(t, true, sdkResult.Code.IsOK()) sdkResult = handler(ctx, mintMsg) @@ -127,7 +127,7 @@ func TestHandleMintMiniToken(t *testing.T) { // issue a non-mintable token issueMsg = NewIssueTinyMsg(acc.GetAddress(), "New BNB2", "NNB2", 9000e8, false, "http://www.xyz.com/nnb.json") ctx = ctx.WithValue(baseapp.TxHashKey, "000") - sdkResult = miniTokenHandler(ctx, issueMsg) + sdkResult = handler(ctx, issueMsg) require.Equal(t, true, sdkResult.Code.IsOK()) mintMsg = NewMintMsg(acc.GetAddress(), "NNB2-000M", 1000e8) diff --git a/plugins/tokens/seturi/handler_test.go b/plugins/tokens/seturi/handler_test.go index e60323e68..a55ef3da7 100644 --- a/plugins/tokens/seturi/handler_test.go +++ b/plugins/tokens/seturi/handler_test.go @@ -21,7 +21,7 @@ import ( "github.com/binance-chain/node/wire" ) -func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { +func setup() (sdk.Context, sdk.Handler, sdk.Handler, auth.AccountKeeper, store.Mapper) { ms, capKey1, capKey2 := testutils.SetupMultiStoreForUnitTest() cdc := wire.NewCodec() cdc.RegisterInterface((*types.IToken)(nil), nil) @@ -32,13 +32,14 @@ func setup() (sdk.Context, sdk.Handler, auth.AccountKeeper, store.Mapper) { handler := NewHandler(tokenMapper) bankKeeper := bank.NewBaseKeeper(accountKeeper) + miniTokenHandler := issue.NewHandler(tokenMapper, bankKeeper) accountStore := ms.GetKVStore(capKey2) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid", Height: 1}, sdk.RunTxModeDeliver, log.NewNopLogger()). WithAccountCache(auth.NewAccountCache(accountStoreCache)) - return ctx, handler, accountKeeper, tokenMapper + return ctx, handler, miniTokenHandler, accountKeeper, tokenMapper } func setChainVersion() { @@ -52,12 +53,12 @@ func resetChainVersion() { func TestHandleSetURI(t *testing.T) { setChainVersion() defer resetChainVersion() - ctx, handler, accountKeeper, tokenMapper := setup() + ctx, handler, miniIssueHandler, accountKeeper, tokenMapper := setup() _, acc := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "000") msg := issue.NewIssueMiniMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false, "http://www.xyz.com/nnb.json") - sdkResult := handler(ctx, msg) + sdkResult := miniIssueHandler(ctx, msg) require.Equal(t, true, sdkResult.Code.IsOK()) token, err := tokenMapper.GetToken(ctx, "NNB-000M") From 1c31a84d2699733ecd108bbb75560ccfc4a366bf Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 25 May 2020 14:04:13 +0800 Subject: [PATCH 70/96] fix --- plugins/dex/aliases.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/dex/aliases.go b/plugins/dex/aliases.go index 4c3f9408d..9e7d34657 100644 --- a/plugins/dex/aliases.go +++ b/plugins/dex/aliases.go @@ -14,6 +14,5 @@ type DexKeeper = order.DexKeeper var NewTradingPairMapper = store.NewTradingPairMapper var NewDexKeeper = order.NewDexKeeper -var InitOrders = order.Init const DefaultCodespace = types.DefaultCodespace From 187d5f035f64cd9a173b0debfe7bccb965ef076f Mon Sep 17 00:00:00 2001 From: rickyyangz Date: Mon, 25 May 2020 16:15:22 +0800 Subject: [PATCH 71/96] symbol selector refactor --- plugins/dex/order/keeper.go | 1 + plugins/dex/order/keeper_match.go | 13 ++- plugins/dex/order/order_keeper.go | 6 +- plugins/dex/order/quickselect.go | 11 +- plugins/dex/order/quickselect_test.go | 158 ++++++-------------------- plugins/dex/order/symbol_selector.go | 28 ++--- 6 files changed, 68 insertions(+), 149 deletions(-) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 3ba65ec64..e80179aa8 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -208,6 +208,7 @@ func (kp *DexKeeper) AddEngine(pair dexTypes.TradingPair) *me.MatchEng { for i := range kp.OrderKeepers { if kp.OrderKeepers[i].supportPairType(pairType) { kp.OrderKeepers[i].initOrders(symbol) + break } } return eng diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 43977d82d..773c448d7 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -9,11 +9,11 @@ import ( dexUtils "github.com/binance-chain/node/plugins/dex/utils" ) -func (kp *DexKeeper) SelectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string { +func (kp *DexKeeper) SelectSymbolsToMatch(height int64, matchAllSymbols bool) []string { symbolsToMatch := make([]string, 0, 256) for _, orderKeeper := range kp.OrderKeepers { if orderKeeper.supportUpgradeVersion() { - symbolsToMatch = append(symbolsToMatch, orderKeeper.selectSymbolsToMatch(height, timestamp, matchAllSymbols)...) + symbolsToMatch = append(symbolsToMatch, orderKeeper.selectSymbolsToMatch(height, matchAllSymbols)...) } } return symbolsToMatch @@ -21,15 +21,16 @@ func (kp *DexKeeper) SelectSymbolsToMatch(height, timestamp int64, matchAllSymbo func (kp *DexKeeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandler TransferHandler, matchAllSymbols bool) { kp.logger.Debug("Start Matching for all...", "height", ctx.BlockHeader().Height) - timestamp := ctx.BlockHeader().Time.UnixNano() + blockHeader := ctx.BlockHeader() + timestamp := blockHeader.Time.UnixNano() - symbolsToMatch := kp.SelectSymbolsToMatch(ctx.BlockHeader().Height, timestamp, matchAllSymbols) + symbolsToMatch := kp.SelectSymbolsToMatch(blockHeader.Height, matchAllSymbols) kp.logger.Info("symbols to match", "symbols", symbolsToMatch) var tradeOuts []chan Transfer if len(symbolsToMatch) == 0 { kp.logger.Info("No order comes in for the block") } else { - tradeOuts = kp.matchAndDistributeTrades(true, ctx.BlockHeader().Height, timestamp) + tradeOuts = kp.matchAndDistributeTrades(true, blockHeader.Height, timestamp) } totalFee := kp.allocateAndCalcFee(ctx, tradeOuts, postAlloTransHandler) @@ -84,7 +85,7 @@ func (kp *DexKeeper) matchAndDistributeTrades(distributeTrade bool, height, time } func (kp *DexKeeper) MatchSymbols(height, timestamp int64, matchAllSymbols bool) { - symbolsToMatch := kp.SelectSymbolsToMatch(height, timestamp, matchAllSymbols) + symbolsToMatch := kp.SelectSymbolsToMatch(height, matchAllSymbols) kp.logger.Debug("symbols to match", "symbols", symbolsToMatch) if len(symbolsToMatch) == 0 { diff --git a/plugins/dex/order/order_keeper.go b/plugins/dex/order/order_keeper.go index 8240b0463..b4b1d6c5e 100644 --- a/plugins/dex/order/order_keeper.go +++ b/plugins/dex/order/order_keeper.go @@ -45,7 +45,7 @@ type DexOrderKeeper interface { getRoundOrdersForPair(pair string) []string getRoundIOCOrdersForPair(pair string) []string clearAfterMatch() - selectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string + selectSymbolsToMatch(height int64, matchAllSymbols bool) []string appendOrderChangeSync(change OrderChange) } @@ -205,8 +205,8 @@ func (kp *BaseOrderKeeper) getAllOrdersForPair(pair string) map[string]*OrderInf return kp.allOrders[pair] } -func (kp *BaseOrderKeeper) selectSymbolsToMatch(height, timestamp int64, matchAllSymbols bool) []string { - return kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, timestamp, matchAllSymbols) +func (kp *BaseOrderKeeper) selectSymbolsToMatch(height int64, matchAllSymbols bool) []string { + return kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, matchAllSymbols) } func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { diff --git a/plugins/dex/order/quickselect.go b/plugins/dex/order/quickselect.go index 70836faae..4ac89dca6 100644 --- a/plugins/dex/order/quickselect.go +++ b/plugins/dex/order/quickselect.go @@ -1,5 +1,7 @@ package order +import "github.com/tendermint/tendermint/libs/common" + //Find and return top K symbols with largest number of order. // The returned top K slice is not sorted. The input orderNums may be re-ordered in place. // If more than one symbols have same order numbers, these symbol will be selected by ascending alphabetical sequence. @@ -10,8 +12,13 @@ func findTopKLargest(orderNums []*SymbolWithOrderNumber, k int) []*SymbolWithOrd return quickselect(orderNums, 0, len(orderNums)-1, k) } -func partition(orderNums []*SymbolWithOrderNumber, start, end, pivot int) int { +func partition(orderNums []*SymbolWithOrderNumber, start, end int) int { // move pivot to end + if end == start { + return start + } + + pivot := common.RandIntn(end-start) + start orderNums[end], orderNums[pivot] = orderNums[pivot], orderNums[end] pivotValue := orderNums[end] i := start @@ -38,7 +45,7 @@ func compare(orderNumA *SymbolWithOrderNumber, orderNumB *SymbolWithOrderNumber) func quickselect(orderNums []*SymbolWithOrderNumber, start, end, n int) []*SymbolWithOrderNumber { // use last element as pivot - pivotIndex := partition(orderNums, start, end, end) + pivotIndex := partition(orderNums, start, end) if n-1 == pivotIndex { return orderNums[:pivotIndex+1] diff --git a/plugins/dex/order/quickselect_test.go b/plugins/dex/order/quickselect_test.go index a7b73434e..6c2944700 100644 --- a/plugins/dex/order/quickselect_test.go +++ b/plugins/dex/order/quickselect_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/common" ) func Test_findKthLargest(t *testing.T) { @@ -27,98 +29,33 @@ func Test_findKthLargest(t *testing.T) { //F6 := &SymbolWithOrderNumber{"f", 6} F1 := &SymbolWithOrderNumber{"FXM-987M_BNB", 1} - assert := assert.New(t) - expected := []*SymbolWithOrderNumber{A3, A4, A5} result := findTopKLargest([]*SymbolWithOrderNumber{A1, A2, A3, A4, A5}, 3) - assert.Equal(3, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{A3, A4, A5} result = findTopKLargest([]*SymbolWithOrderNumber{A5, A3, A3, A1, A4}, 3) - assert.Equal(3, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{A3, A4, A5} result = findTopKLargest([]*SymbolWithOrderNumber{A5, B3, A3, A1, A4}, 3) - assert.Equal(3, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{A6, A5} result = findTopKLargest([]*SymbolWithOrderNumber{A3, A2, A1, A5, A6, A4}, 2) - assert.Equal(2, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{A6, C4, B5} result = findTopKLargest([]*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4}, 3) - assert.Equal(3, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4} result = findTopKLargest([]*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4}, 6) - assert.Equal(6, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4} result = findTopKLargest([]*SymbolWithOrderNumber{D3, E2, F1, B5, A6, C4}, 7) - assert.Equal(6, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) } func Test_findKthLargest_SameNumber(t *testing.T) { @@ -135,75 +72,48 @@ func Test_findKthLargest_SameNumber(t *testing.T) { expected := []*SymbolWithOrderNumber{A2, B2, E2} result := findTopKLargest([]*SymbolWithOrderNumber{F2, E2, A2, B2, C1}, 3) - assert.Equal(3, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{B2, A2, C2} result = findTopKLargest([]*SymbolWithOrderNumber{A0, A1, A2, B2, C1, C2}, 3) - assert.Equal(3, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{A2} result = findTopKLargest([]*SymbolWithOrderNumber{A0, A1, A2, B2, C1, C2}, 1) - assert.Equal(1, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{A1, A2, B2, C2} result = findTopKLargest([]*SymbolWithOrderNumber{A0, A1, A2, B2, C1, C2}, 4) assert.Equal(4, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) - } - } + assertResult(t, expected, result) expected = []*SymbolWithOrderNumber{A1, A2, B2, C1, C2} result = findTopKLargest([]*SymbolWithOrderNumber{A0, A1, A2, B2, C1, C2}, 5) assert.Equal(5, len(result)) - for _, x := range result { - fmt.Printf("%v,", *x) - } - fmt.Println("") - for _, ele := range expected { - if !contains(result, ele) { - t.Fatalf("Expected contains %v, but doesn't exist", ele) + assertResult(t, expected, result) +} + +func Benchmark_findTopKLargest(b *testing.B) { + const size = 10000 + origin := make([]*SymbolWithOrderNumber, size) + for i:=0; i Date: Mon, 25 May 2020 17:17:22 +0800 Subject: [PATCH 72/96] fix order cancel --- plugins/dex/order/keeper.go | 8 +++++++- plugins/dex/order/transfer.go | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 3ba65ec64..d8ed1156e 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -98,7 +98,12 @@ func (kp *DexKeeper) SetBUSDSymbol(symbol string) { } func (kp *DexKeeper) getOrderKeeper(symbol string) (DexOrderKeeper, error) { - pairType := kp.pairsType[symbol] + pairType, ok := kp.pairsType[symbol] + if !ok { + err := fmt.Errorf("order doesn't exist [%v]", symbol) + kp.logger.Debug(err.Error()) + return nil, err + } for i := range kp.OrderKeepers { if kp.OrderKeepers[i].supportPairType(pairType) { return kp.OrderKeepers[i], nil @@ -246,6 +251,7 @@ func (kp *DexKeeper) RemoveOrder(id string, symbol string, postCancelHandler fun if postCancelHandler != nil { postCancelHandler(ord) } + return nil } return orderNotFound(symbol, id) } diff --git a/plugins/dex/order/transfer.go b/plugins/dex/order/transfer.go index 9b116c996..60692759d 100644 --- a/plugins/dex/order/transfer.go +++ b/plugins/dex/order/transfer.go @@ -167,6 +167,7 @@ func transferFromOrderRemoved(ord me.OrderPart, ordMsg OrderInfo, tranEventType outAsset: unlockAsset, out: unlock, unlock: unlock, + Symbol: ordMsg.Symbol, } } From 61c7234e958912e02b473a5fc9a7b988154b8ad0 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 25 May 2020 17:26:50 +0800 Subject: [PATCH 73/96] format --- app/pub/helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pub/helpers.go b/app/pub/helpers.go index a00d43010..863030f92 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/binance-chain/node/plugins/tokens/seturi" "strconv" "sync" "time" @@ -21,6 +20,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" + "github.com/binance-chain/node/plugins/tokens/seturi" abci "github.com/tendermint/tendermint/abci/types" ) From cf892b1a973d66c0afafa7858dd7d336e7a30ee6 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 25 May 2020 18:49:37 +0800 Subject: [PATCH 74/96] fix compiling error --- plugins/dex/order/keeper_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index f368d8175..5d4995dbf 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -107,7 +107,7 @@ func TestKeeper_MatchFailure(t *testing.T) { msg = NewNewOrderMsg(accAdd, "123462", Side.BUY, "XYZ-000_BNB", 99000, 15000000) ord = OrderInfo{msg, 42, 0, 42, 0, 0, "", 0} keeper.AddOrder(ord, false) - symbolsToMatch := keeper.SelectSymbolsToMatch(ctx.BlockHeader().Height, 0, false) + symbolsToMatch := keeper.SelectSymbolsToMatch(ctx.BlockHeader().Height, false) logger.Info("symbols to match", "symbols", symbolsToMatch) tradeOuts := keeper.matchAndDistributeTrades(true, 42, 0) c := channelHash(accAdd, 4) From 9ca65806daaf63e237fc0c1ef8daf80338294b50 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 25 May 2020 20:42:20 +0800 Subject: [PATCH 75/96] refactor lastMatchHeight --- plugins/dex/matcheng/engine_new.go | 11 +++++++++-- plugins/dex/matcheng/match_new_test.go | 7 ++++--- plugins/dex/order/keeper_match.go | 16 +--------------- plugins/dex/order/keeper_recovery.go | 2 ++ 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/plugins/dex/matcheng/engine_new.go b/plugins/dex/matcheng/engine_new.go index 9deeb98d9..5d4ec36df 100644 --- a/plugins/dex/matcheng/engine_new.go +++ b/plugins/dex/matcheng/engine_new.go @@ -12,7 +12,14 @@ import ( "github.com/binance-chain/node/common/utils" ) -func (me *MatchEng) Match(height int64, lastMatchedHeight int64) bool { +func (me *MatchEng) Match(height int64) bool { + success := me.runMatch(height) + if sdk.IsUpgrade(upgrade.BEP19) { + me.LastMatchHeight = height + } + return success +} +func (me *MatchEng) runMatch(height int64) bool { if !sdk.IsUpgrade(upgrade.BEP19) { return me.MatchBeforeGalileo(height) } @@ -33,7 +40,7 @@ func (me *MatchEng) Match(height int64, lastMatchedHeight int64) bool { return false } //If order height > the last Match height, then it's maker. - takerSide, err := me.determineTakerSide(lastMatchedHeight, index) + takerSide, err := me.determineTakerSide(me.LastMatchHeight, index) if err != nil { me.logger.Error("determineTakerSide failed", "error", err) return false diff --git a/plugins/dex/matcheng/match_new_test.go b/plugins/dex/matcheng/match_new_test.go index 4e4ac8be8..ced74a2b7 100644 --- a/plugins/dex/matcheng/match_new_test.go +++ b/plugins/dex/matcheng/match_new_test.go @@ -923,7 +923,8 @@ func TestMatchEng_Match(t *testing.T) { me.Book.InsertOrder("16", BUYSIDE, 100, 100, 20) upgrade.Mgr.SetHeight(100) - assert.True(me.Match(100, 99)) + me.LastMatchHeight = 99 + assert.True(me.Match(100)) assert.Equal(4, len(me.overLappedLevel)) assert.Equal(int64(100), me.LastTradePrice) assert.Equal([]Trade{ @@ -978,8 +979,8 @@ func TestMatchEng_Match(t *testing.T) { me.Book.InsertOrder("15", SELLSIDE, 100, 100, 30) me.Book.InsertOrder("6", BUYSIDE, 100, 110, 40) me.Book.InsertOrder("8", BUYSIDE, 100, 110, 100) - - assert.True(me.Match(100, 99)) + me.LastMatchHeight = 99 + assert.True(me.Match(100)) assert.Equal(4, len(me.overLappedLevel)) assert.Equal(int64(104), me.LastTradePrice) assert.Equal([]Trade{ diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 773c448d7..afd29fb49 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -1,12 +1,10 @@ package order import ( - "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/utils" - dexUtils "github.com/binance-chain/node/plugins/dex/utils" ) func (kp *DexKeeper) SelectSymbolsToMatch(height int64, matchAllSymbols bool) []string { @@ -103,18 +101,9 @@ func (kp *DexKeeper) matchAndDistributeTradesForSymbol(symbol string, height, ti concurrency := len(tradeOuts) orderKeeper := kp.mustGetOrderKeeper(symbol) orders := orderKeeper.getAllOrdersForPair(symbol) - var lastMatchHeight int64 - if dexUtils.IsMiniTokenTradingPair(symbol) { - lastMatchHeight = engine.LastMatchHeight - } else { - lastMatchHeight = height - 1 //Every block is deemed as performed matching for all BEP2 symbols - } // please note there is no logging in matching, expecting to see the order book details // from the exchange's order book stream. - if engine.Match(height, lastMatchHeight) { - if sdk.IsUpgrade(upgrade.BEP19) { - engine.LastMatchHeight = height - } + if engine.Match(height) { kp.logger.Debug("Match finish:", "symbol", symbol, "lastTradePrice", engine.LastTradePrice) for i := range engine.Trades { t := &engine.Trades[i] @@ -141,9 +130,6 @@ func (kp *DexKeeper) matchAndDistributeTradesForSymbol(symbol string, height, ti // for index service. kp.logger.Error("Fatal error occurred in matching, cancel all incoming new orders", "symbol", symbol) - if sdk.IsUpgrade(upgrade.BEP19) { - engine.LastMatchHeight = height - } thisRoundIds := orderKeeper.getRoundOrdersForPair(symbol) for _, id := range thisRoundIds { msg := orders[id] diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index fa95b25c9..71967f10d 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -154,6 +154,8 @@ func (kp *DexKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight in eng.LastTradePrice = ob.LastTradePrice if sdk.IsUpgrade(upgrade.BEP8) { eng.LastMatchHeight = ob.LastMatchHeight + }else{ + eng.LastMatchHeight = height } ctx.Logger().Info("Successfully Loaded order snapshot", "pair", pair) } From f52d5a9efae79b08777b30ba5945c60b6d90a71d Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 25 May 2020 21:41:22 +0800 Subject: [PATCH 76/96] fix ut --- app/apptest/ordertx_test.go | 5 +++++ plugins/dex/order/keeper_recovery.go | 2 +- plugins/dex/order/quickselect_test.go | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/apptest/ordertx_test.go b/app/apptest/ordertx_test.go index ac715909c..c84b36752 100644 --- a/app/apptest/ordertx_test.go +++ b/app/apptest/ordertx_test.go @@ -124,10 +124,12 @@ func Test_handleNewOrder_DeliverTx(t *testing.T) { tradingPair := types.NewTradingPair("BTC-000", "BNB", 1e8) testApp.DexKeeper.PairMapper.AddTradingPair(ctx, tradingPair) testApp.DexKeeper.AddEngine(tradingPair) + testApp.DexKeeper.GetEngines()["BTC-000_BNB"].LastMatchHeight = -1 tradingPair2 := types.NewTradingPair("ETH-001", "BNB", 1e8) testApp.DexKeeper.PairMapper.AddTradingPair(ctx, tradingPair2) testApp.DexKeeper.AddEngine(tradingPair2) + testApp.DexKeeper.GetEngines()["ETH-001_BNB"].LastMatchHeight = -1 add := Account(0).GetAddress() oid := fmt.Sprintf("%X-0", add) @@ -159,9 +161,11 @@ func Test_Match(t *testing.T) { ethPair := types.NewTradingPair("ETH-000", "BNB", 97e8) testApp.DexKeeper.PairMapper.AddTradingPair(ctx, ethPair) testApp.DexKeeper.AddEngine(ethPair) + testApp.DexKeeper.GetEngines()["ETH-000_BNB"].LastMatchHeight = -1 btcPair := types.NewTradingPair("BTC-000", "BNB", 96e8) testApp.DexKeeper.PairMapper.AddTradingPair(ctx, btcPair) testApp.DexKeeper.AddEngine(btcPair) + testApp.DexKeeper.GetEngines()["BTC-000_BNB"].LastMatchHeight = -1 testApp.DexKeeper.FeeManager.UpdateConfig(newTestFeeConfig()) // setup accounts @@ -316,6 +320,7 @@ func Test_handleCancelOrder_CheckTx(t *testing.T) { tradingPair := types.NewTradingPair("BTC-000", "BNB", 1e8) testApp.DexKeeper.PairMapper.AddTradingPair(ctx, tradingPair) testApp.DexKeeper.AddEngine(tradingPair) + testApp.DexKeeper.GetEngines()["BTC-000_BNB"].LastMatchHeight = -1 testApp.DexKeeper.FeeManager.UpdateConfig(newTestFeeConfig()) // setup accounts diff --git a/plugins/dex/order/keeper_recovery.go b/plugins/dex/order/keeper_recovery.go index 71967f10d..860e6dc82 100644 --- a/plugins/dex/order/keeper_recovery.go +++ b/plugins/dex/order/keeper_recovery.go @@ -154,7 +154,7 @@ func (kp *DexKeeper) LoadOrderBookSnapshot(ctx sdk.Context, latestBlockHeight in eng.LastTradePrice = ob.LastTradePrice if sdk.IsUpgrade(upgrade.BEP8) { eng.LastMatchHeight = ob.LastMatchHeight - }else{ + } else { eng.LastMatchHeight = height } ctx.Logger().Info("Successfully Loaded order snapshot", "pair", pair) diff --git a/plugins/dex/order/quickselect_test.go b/plugins/dex/order/quickselect_test.go index 6c2944700..c2f136dd3 100644 --- a/plugins/dex/order/quickselect_test.go +++ b/plugins/dex/order/quickselect_test.go @@ -96,10 +96,10 @@ func Test_findKthLargest_SameNumber(t *testing.T) { func Benchmark_findTopKLargest(b *testing.B) { const size = 10000 origin := make([]*SymbolWithOrderNumber, size) - for i:=0; i Date: Mon, 25 May 2020 21:44:22 +0800 Subject: [PATCH 77/96] orderkeeper refactor --- app/app_pub_test.go | 2 +- plugins/dex/order/keeper.go | 21 ++++- plugins/dex/order/keeper_match.go | 6 +- plugins/dex/order/mini_keeper.go | 35 ++++--- plugins/dex/order/order_keeper.go | 134 ++++++++++++++------------- plugins/dex/order/symbol_selector.go | 54 ++++------- 6 files changed, 129 insertions(+), 123 deletions(-) diff --git a/app/app_pub_test.go b/app/app_pub_test.go index 6fd8f2cc7..fc9ecf31b 100644 --- a/app/app_pub_test.go +++ b/app/app_pub_test.go @@ -98,7 +98,7 @@ func setupAppTest(t *testing.T) (*assert.Assertions, *require.Assertions, *Binan pub.IsLive = true keeper := app.DexKeeper - keeper.CollectOrderInfoForPublish = true + keeper.EnablePublish() tradingPair := dextypes.NewTradingPair("XYZ-000", "BNB", 102000) keeper.PairMapper.AddTradingPair(app.DeliverState.Ctx, tradingPair) keeper.AddEngine(tradingPair) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 0e546e634..493dbd6ca 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -55,7 +55,7 @@ type DexKeeper struct { am auth.AccountKeeper FeeManager *FeeManager RoundOrderFees FeeHolder // order (and trade) related fee of this round, str of addr bytes -> fee - CollectOrderInfoForPublish bool //TODO seperate for each order keeper + CollectOrderInfoForPublish bool //TODO separate for each order keeper engines map[string]*me.MatchEng pairsType map[string]SymbolPairType logger tmlog.Logger @@ -66,6 +66,12 @@ type DexKeeper struct { func NewDexKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper store.TradingPairMapper, codespace sdk.CodespaceType, concurrency uint, cdc *wire.Codec, collectOrderInfoForPublish bool) *DexKeeper { logger := bnclog.With("module", "dexkeeper") + bep2OrderKeeper, miniOrderKeeper := NewBEP2OrderKeeper(), NewMiniOrderKeeper() + if collectOrderInfoForPublish { + bep2OrderKeeper.enablePublish() + miniOrderKeeper.enablePublish() + } + return &DexKeeper{ PairMapper: tradingPairMapper, storeKey: key, @@ -80,7 +86,7 @@ func NewDexKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper sto poolSize: concurrency, cdc: cdc, logger: logger, - OrderKeepers: []DexOrderKeeper{NewBEP2OrderKeeper(), NewMiniOrderKeeper()}, + OrderKeepers: []DexOrderKeeper{bep2OrderKeeper, miniOrderKeeper}, } } @@ -97,6 +103,13 @@ func (kp *DexKeeper) SetBUSDSymbol(symbol string) { BUSDSymbol = symbol } +func (kp *DexKeeper) EnablePublish() { + kp.CollectOrderInfoForPublish = true + for i := range kp.OrderKeepers { + kp.OrderKeepers[i].enablePublish() + } +} + func (kp *DexKeeper) getOrderKeeper(symbol string) (DexOrderKeeper, error) { pairType, ok := kp.pairsType[symbol] if !ok { @@ -233,7 +246,7 @@ func (kp *DexKeeper) AddOrder(info OrderInfo, isRecovery bool) (err error) { return err } - kp.mustGetOrderKeeper(symbol).addOrder(symbol, info, kp.CollectOrderInfoForPublish, isRecovery) + kp.mustGetOrderKeeper(symbol).addOrder(symbol, info, isRecovery) kp.logger.Debug("Added orders", "symbol", symbol, "id", info.Id) return nil } @@ -998,7 +1011,7 @@ func (kp *DexKeeper) GetAllOrdersForPair(symbol string) map[string]*OrderInfo { } func (kp *DexKeeper) ReloadOrder(symbol string, orderInfo *OrderInfo, height int64) { - kp.mustGetOrderKeeper(symbol).reloadOrder(symbol, orderInfo, height, kp.CollectOrderInfoForPublish) + kp.mustGetOrderKeeper(symbol).reloadOrder(symbol, orderInfo, height) } func (kp *DexKeeper) GetOrderChanges(pairType SymbolPairType) OrderChanges { diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 773c448d7..a2c5da2b2 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -1,10 +1,10 @@ package order import ( - "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/fees" + "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/common/utils" dexUtils "github.com/binance-chain/node/plugins/dex/utils" ) @@ -39,7 +39,7 @@ func (kp *DexKeeper) MatchAndAllocateSymbols(ctx sdk.Context, postAlloTransHandl } // please note if distributeTrade this method will work in async mode, otherwise in sync mode. -// Always run kp.SelectSymbolsToMatch(ctx.BlockHeader().Height, timestamp, matchAllSymbols) before matchAndDistributeTrades +// Always run kp.SelectSymbolsToMatch(ctx.BlockHeader().Height, matchAllSymbols) before matchAndDistributeTrades func (kp *DexKeeper) matchAndDistributeTrades(distributeTrade bool, height, timestamp int64) []chan Transfer { concurrency := 1 << kp.poolSize tradeOuts := make([]chan Transfer, concurrency) @@ -59,7 +59,7 @@ func (kp *DexKeeper) matchAndDistributeTrades(distributeTrade bool, height, time symbolCh := make(chan string, concurrency) producer := func() { for i := range kp.OrderKeepers { - kp.OrderKeepers[i].iterateRoundPairs(func(symbol string) { + kp.OrderKeepers[i].iterateRoundSelectedPairs(func(symbol string) { symbolCh <- symbol }) } diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index c5f00e8d4..98deb6b9f 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -9,13 +9,14 @@ import ( ) const ( - defaultMiniBlockMatchInterval = 16 - defaultActiveMiniSymbolCount = 8 + defaultMiniBlockMatchInterval int = 16 + defaultActiveMiniSymbolCount int = 8 ) //order keeper for mini-token type MiniOrderKeeper struct { BaseOrderKeeper + symbolSelector MiniSymbolSelector } var _ DexOrderKeeper = &MiniOrderKeeper{} @@ -23,8 +24,11 @@ var _ DexOrderKeeper = &MiniOrderKeeper{} // NewBEP2OrderKeeper - Returns the MiniToken orderKeeper func NewMiniOrderKeeper() DexOrderKeeper { return &MiniOrderKeeper{ - NewBaseOrderKeeper("dexMiniKeeper", - &MiniSymbolSelector{make(map[string]uint32, 256), make([]string, 0, 256)}), + BaseOrderKeeper: NewBaseOrderKeeper("dexMiniKeeper"), + symbolSelector: MiniSymbolSelector{ + make(map[string]uint32, 256), + make([]string, 0, 256), + }, } } @@ -48,44 +52,47 @@ func (kp *MiniOrderKeeper) supportPairType(pairType SymbolPairType) bool { // override func (kp *MiniOrderKeeper) initOrders(symbol string) { kp.allOrders[symbol] = map[string]*OrderInfo{} - kp.symbolSelector.AddSymbolHash(symbol) + kp.symbolSelector.addSymbolHash(symbol) } func (kp *MiniOrderKeeper) clearAfterMatch() { kp.logger.Debug("clearAfterMatchMini...") - for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { + for _, symbol := range kp.symbolSelector.roundSelectedSymbols { delete(kp.roundOrders, symbol) delete(kp.roundIOCOrders, symbol) } - clearedRoundMatchSymbols := make([]string, 0) - kp.symbolSelector.SetRoundMatchSymbol(clearedRoundMatchSymbols) + kp.symbolSelector.clearRoundMatchSymbol() } -func (kp *MiniOrderKeeper) iterateRoundPairs(iter func(string)) { - for _, symbol := range *kp.symbolSelector.GetRoundMatchSymbol() { +func (kp *MiniOrderKeeper) iterateRoundSelectedPairs(iter func(string)) { + for _, symbol := range kp.symbolSelector.roundSelectedSymbols { iter(symbol) } } func (kp *MiniOrderKeeper) getRoundPairsNum() int { - return len(*kp.symbolSelector.GetRoundMatchSymbol()) + return len(kp.symbolSelector.roundSelectedSymbols) } func (kp *MiniOrderKeeper) getRoundOrdersNum() int { n := 0 - kp.iterateRoundPairs(func(symbol string) { + kp.iterateRoundSelectedPairs(func(symbol string) { n += len(kp.roundOrders[symbol]) }) return n } -func (kp *MiniOrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) { +func (kp *MiniOrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64) { kp.allOrders[symbol][orderInfo.Id] = orderInfo //TODO confirm no active orders for mini symbol - if collectOrderInfoForPublish { + if kp.collectOrderInfoForPublish { if _, exists := kp.orderInfosForPub[orderInfo.Id]; !exists { bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) kp.orderInfosForPub[orderInfo.Id] = orderInfo } } } + +func (kp *MiniOrderKeeper) selectSymbolsToMatch(height int64, matchAllSymbols bool) []string { + return kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, matchAllSymbols) +} diff --git a/plugins/dex/order/order_keeper.go b/plugins/dex/order/order_keeper.go index b4b1d6c5e..5dbec9808 100644 --- a/plugins/dex/order/order_keeper.go +++ b/plugins/dex/order/order_keeper.go @@ -11,7 +11,6 @@ import ( me "github.com/binance-chain/node/plugins/dex/matcheng" "github.com/binance-chain/node/plugins/dex/store" dexUtils "github.com/binance-chain/node/plugins/dex/utils" - "github.com/binance-chain/node/wire" ) const ( @@ -21,79 +20,70 @@ const ( ) type DexOrderKeeper interface { - addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) + initOrders(symbol string) + addOrder(symbol string, info OrderInfo, isRecovery bool) + reloadOrder(symbol string, orderInfo *OrderInfo, height int64) removeOrder(dexKeeper *DexKeeper, id string, symbol string) (ord me.OrderPart, err error) orderExists(symbol, id string) (OrderInfo, bool) getOpenOrders(pair string, addr sdk.AccAddress) []store.OpenOrder getAllOrders() map[string]map[string]*OrderInfo deleteOrdersForPair(pair string) - clearOrderChanges() - getOrderChanges() OrderChanges - getOrderInfosForPub() OrderInfoForPublish - removeOrderInfosForPub(orderId string) - appendOrderChange(change OrderChange) - initOrders(symbol string) - support(pair string) bool - supportUpgradeVersion() bool - supportPairType(pairType SymbolPairType) bool - iterateRoundPairs(func(string)) + + iterateRoundSelectedPairs(func(string)) iterateAllOrders(func(symbol string, id string)) - reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) - getRoundPairsNum() int + getRoundOrdersNum() int getAllOrdersForPair(pair string) map[string]*OrderInfo getRoundOrdersForPair(pair string) []string getRoundIOCOrdersForPair(pair string) []string clearAfterMatch() selectSymbolsToMatch(height int64, matchAllSymbols bool) []string + + // publish + enablePublish() appendOrderChangeSync(change OrderChange) -} + getOrderChanges() OrderChanges + clearOrderChanges() + getOrderInfosForPub() OrderInfoForPublish + removeOrderInfosForPub(orderId string) -type BEP2OrderKeeper struct { - BaseOrderKeeper + support(pair string) bool + supportUpgradeVersion() bool + supportPairType(pairType SymbolPairType) bool } -var _ DexOrderKeeper = &BEP2OrderKeeper{} - // in the future, this may be distributed via Sharding type BaseOrderKeeper struct { - allOrders map[string]map[string]*OrderInfo // symbol -> order ID -> order - orderChangesMtx *sync.Mutex // guard orderChanges and orderInfosForPub during PreDevlierTx (which is async) - orderChanges OrderChanges // order changed in this block, will be cleaned before matching for new block - orderInfosForPub OrderInfoForPublish // for publication usage - roundOrders map[string][]string // limit to the total tx number in a block - roundIOCOrders map[string][]string - poolSize uint // number of concurrent channels, counted in the pow of 2 - cdc *wire.Codec - logger tmlog.Logger - symbolSelector SymbolSelector -} + allOrders map[string]map[string]*OrderInfo // symbol -> order ID -> order + roundOrders map[string][]string // limit to the total tx number in a block + roundIOCOrders map[string][]string -// NewBEP2OrderKeeper - Returns the BEP2OrderKeeper -func NewBEP2OrderKeeper() DexOrderKeeper { - return &BEP2OrderKeeper{ - NewBaseOrderKeeper("Bep2OrderKeeper", &BEP2SymbolSelector{}), - } + collectOrderInfoForPublish bool + orderChangesMtx *sync.Mutex // guard orderChanges and orderInfosForPub during PreDevlierTx (which is async) + orderChanges OrderChanges // order changed in this block, will be cleaned before matching for new block + orderInfosForPub OrderInfoForPublish // for publication usage + + logger tmlog.Logger } -func NewBaseOrderKeeper(moduleName string, symbolSelector SymbolSelector) BaseOrderKeeper { +func NewBaseOrderKeeper(moduleName string) BaseOrderKeeper { logger := bnclog.With("module", moduleName) return BaseOrderKeeper{ - allOrders: make(map[string]map[string]*OrderInfo, 256), // need to init the nested map when a new symbol added. - orderChangesMtx: &sync.Mutex{}, - orderChanges: make(OrderChanges, 0), - orderInfosForPub: make(OrderInfoForPublish), - roundOrders: make(map[string][]string, 256), - roundIOCOrders: make(map[string][]string, 256), - logger: logger, - symbolSelector: symbolSelector, + allOrders: make(map[string]map[string]*OrderInfo, 256), + roundOrders: make(map[string][]string, 256), + roundIOCOrders: make(map[string][]string, 256), + + collectOrderInfoForPublish: false, // default to false, need a explicit set if needed + orderChangesMtx: &sync.Mutex{}, + orderChanges: make(OrderChanges, 0), + orderInfosForPub: make(OrderInfoForPublish), + logger: logger, } } -func (kp *BaseOrderKeeper) addOrder(symbol string, info OrderInfo, collectOrderInfoForPublish bool, isRecovery bool) { - - if collectOrderInfoForPublish { +func (kp *BaseOrderKeeper) addOrder(symbol string, info OrderInfo, isRecovery bool) { + if kp.collectOrderInfoForPublish { change := OrderChange{info.Id, Ack, "", nil} // deliberately not add this message to orderChanges if !isRecovery { @@ -169,12 +159,22 @@ func (kp *BaseOrderKeeper) getOpenOrders(pair string, addr sdk.AccAddress) []sto return openOrders } +func (kp *BaseOrderKeeper) getAllOrders() map[string]map[string]*OrderInfo { + return kp.allOrders +} + func (kp *BaseOrderKeeper) clearOrderChanges() { kp.orderChanges = kp.orderChanges[:0] } -func (kp *BaseOrderKeeper) getAllOrders() map[string]map[string]*OrderInfo { - return kp.allOrders +func (kp *BaseOrderKeeper) enablePublish() { + kp.collectOrderInfoForPublish = true +} + +func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { + kp.orderChangesMtx.Lock() + kp.orderChanges = append(kp.orderChanges, change) + kp.orderChangesMtx.Unlock() } func (kp *BaseOrderKeeper) getOrderChanges() OrderChanges { @@ -189,10 +189,6 @@ func (kp *BaseOrderKeeper) removeOrderInfosForPub(orderId string) { delete(kp.orderInfosForPub, orderId) } -func (kp *BaseOrderKeeper) appendOrderChange(change OrderChange) { - kp.orderChanges = append(kp.orderChanges, change) -} - func (kp *BaseOrderKeeper) getRoundOrdersForPair(pair string) []string { return kp.roundOrders[pair] } @@ -205,15 +201,7 @@ func (kp *BaseOrderKeeper) getAllOrdersForPair(pair string) map[string]*OrderInf return kp.allOrders[pair] } -func (kp *BaseOrderKeeper) selectSymbolsToMatch(height int64, matchAllSymbols bool) []string { - return kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, matchAllSymbols) -} -func (kp *BaseOrderKeeper) appendOrderChangeSync(change OrderChange) { - kp.orderChangesMtx.Lock() - kp.orderChanges = append(kp.orderChanges, change) - kp.orderChangesMtx.Unlock() -} func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { for symbol, orders := range kp.allOrders { @@ -224,6 +212,20 @@ func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { } //------ BEP2OrderKeeper methods ----- +var _ DexOrderKeeper = &BEP2OrderKeeper{} + +type BEP2OrderKeeper struct { + BaseOrderKeeper + symbolSelector BEP2SymbolSelector +} + +// NewBEP2OrderKeeper - Returns the BEP2OrderKeeper +func NewBEP2OrderKeeper() DexOrderKeeper { + return &BEP2OrderKeeper{ + BaseOrderKeeper: NewBaseOrderKeeper("BEP2OrderKeeper"), + symbolSelector: BEP2SymbolSelector{}, + } +} func (kp *BEP2OrderKeeper) support(pair string) bool { if !sdk.IsUpgrade(sdk.BEP8) { @@ -250,13 +252,13 @@ func (kp *BEP2OrderKeeper) clearAfterMatch() { kp.roundIOCOrders = make(map[string][]string, 256) } -func (kp *BEP2OrderKeeper) iterateRoundPairs(iter func(string)) { +func (kp *BEP2OrderKeeper) iterateRoundSelectedPairs(iter func(string)) { for symbol := range kp.roundOrders { iter(symbol) } } -func (kp *BEP2OrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64, collectOrderInfoForPublish bool) { +func (kp *BEP2OrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64) { kp.allOrders[symbol][orderInfo.Id] = orderInfo if orderInfo.CreatedHeight == height { kp.roundOrders[symbol] = append(kp.roundOrders[symbol], orderInfo.Id) @@ -264,7 +266,7 @@ func (kp *BEP2OrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, heig kp.roundIOCOrders[symbol] = append(kp.roundIOCOrders[symbol], orderInfo.Id) } } - if collectOrderInfoForPublish { + if kp.collectOrderInfoForPublish { if _, exists := kp.orderInfosForPub[orderInfo.Id]; !exists { bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) kp.orderInfosForPub[orderInfo.Id] = orderInfo @@ -283,3 +285,7 @@ func (kp *BEP2OrderKeeper) getRoundOrdersNum() int { } return n } + +func (kp *BEP2OrderKeeper) selectSymbolsToMatch(height int64, matchAllSymbols bool) []string { + return kp.symbolSelector.SelectSymbolsToMatch(kp.roundOrders, height, matchAllSymbols) +} diff --git a/plugins/dex/order/symbol_selector.go b/plugins/dex/order/symbol_selector.go index fd35ff792..352cafe90 100644 --- a/plugins/dex/order/symbol_selector.go +++ b/plugins/dex/order/symbol_selector.go @@ -6,27 +6,11 @@ import ( type SymbolSelector interface { SelectSymbolsToMatch(roundOrders map[string][]string, height int64, matchAllSymbols bool) []string - AddSymbolHash(symbol string) - GetRoundMatchSymbol() *[]string - SetRoundMatchSymbol([]string) -} - -type BEP2SymbolSelector struct { } var _ SymbolSelector = &BEP2SymbolSelector{} -func (bss *BEP2SymbolSelector) AddSymbolHash(symbol string) { - panic("unsupported method") -} - -func (bss *BEP2SymbolSelector) SetRoundMatchSymbol([]string) { - panic("unsupported method") -} - -func (bss *BEP2SymbolSelector) GetRoundMatchSymbol() *[]string { - panic("unsupported method") -} +type BEP2SymbolSelector struct{} func (bss *BEP2SymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]string, height int64, matchAllSymbols bool) []string { size := len(roundOrders) @@ -41,8 +25,8 @@ func (bss *BEP2SymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]str } type MiniSymbolSelector struct { - miniSymbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin - roundMiniSymbols []string //mini token pairs to match in this round + symbolsHash map[string]uint32 //mini token pairs -> hash value for Round-Robin + roundSelectedSymbols []string //mini token pairs to match in this round } var _ SymbolSelector = &MiniSymbolSelector{ @@ -50,16 +34,12 @@ var _ SymbolSelector = &MiniSymbolSelector{ make([]string, 0), } -func (mss *MiniSymbolSelector) GetRoundMatchSymbol() *[]string { - return &mss.roundMiniSymbols -} - -func (mss *MiniSymbolSelector) AddSymbolHash(symbol string) { - mss.miniSymbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) +func (mss *MiniSymbolSelector) addSymbolHash(symbol string) { + mss.symbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) } -func (mss *MiniSymbolSelector) SetRoundMatchSymbol(symbols []string) { - mss.roundMiniSymbols = symbols +func (mss *MiniSymbolSelector) clearRoundMatchSymbol() { + mss.roundSelectedSymbols = make([]string, 0) } func (mss *MiniSymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]string, height int64, matchAllSymbols bool) []string { @@ -73,24 +53,24 @@ func (mss *MiniSymbolSelector) SelectSymbolsToMatch(roundOrders map[string][]str symbolsToMatch = append(symbolsToMatch, symbol) } } else { - selectMiniSymbolsToMatch(roundOrders, mss.miniSymbolsHash, height, func(miniSymbols map[string]struct{}) { + mss.selectMiniSymbolsToMatch(roundOrders, height, func(miniSymbols map[string]struct{}) { for symbol := range miniSymbols { symbolsToMatch = append(symbolsToMatch, symbol) } }) } - mss.roundMiniSymbols = symbolsToMatch + mss.roundSelectedSymbols = symbolsToMatch return symbolsToMatch } -func selectMiniSymbolsToMatch(roundOrders map[string][]string, miniSymbolsHash map[string]uint32, height int64, postSelect func(map[string]struct{})) { +func (mss *MiniSymbolSelector) selectMiniSymbolsToMatch(roundOrders map[string][]string, height int64, postSelect func(map[string]struct{})) { symbolsToMatch := make(map[string]struct{}, 256) - selectActiveMiniSymbols(symbolsToMatch, roundOrders, defaultActiveMiniSymbolCount) - selectMiniSymbolsRoundRobin(symbolsToMatch, miniSymbolsHash, height) + mss.selectActiveMiniSymbols(symbolsToMatch, roundOrders, defaultActiveMiniSymbolCount) + mss.selectMiniSymbolsRoundRobin(symbolsToMatch, height, defaultMiniBlockMatchInterval) postSelect(symbolsToMatch) } -func selectActiveMiniSymbols(symbolsToMatch map[string]struct{}, roundOrdersMini map[string][]string, k int) { +func (mss *MiniSymbolSelector) selectActiveMiniSymbols(symbolsToMatch map[string]struct{}, roundOrdersMini map[string][]string, k int) { //use quick select to select top k symbols symbolOrderNumsSlice := make([]*SymbolWithOrderNumber, 0, len(roundOrdersMini)) for symbol, orders := range roundOrdersMini { @@ -103,10 +83,10 @@ func selectActiveMiniSymbols(symbolsToMatch map[string]struct{}, roundOrdersMini } } -func selectMiniSymbolsRoundRobin(symbolsToMatch map[string]struct{}, miniSymbolsHash map[string]uint32, height int64) { - m := height % defaultMiniBlockMatchInterval - for symbol, symbolHash := range miniSymbolsHash { - if int64(symbolHash%defaultMiniBlockMatchInterval) == m { +func (mss *MiniSymbolSelector) selectMiniSymbolsRoundRobin(symbolsToMatch map[string]struct{}, height int64, matchInterval int) { + m := height % int64(matchInterval) + for symbol, symbolHash := range mss.symbolsHash { + if int64(symbolHash%uint32(matchInterval)) == m { symbolsToMatch[symbol] = struct{}{} } } From 46b5f07a65456f855b16bb018ac86baf8bea12f0 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 26 May 2020 11:08:52 +0800 Subject: [PATCH 78/96] format --- plugins/dex/order/keeper_match.go | 1 - plugins/dex/order/mini_keeper.go | 2 +- plugins/dex/order/order_keeper.go | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index 7b82f1839..0b439e664 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -4,7 +4,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/fees" - "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/common/utils" ) diff --git a/plugins/dex/order/mini_keeper.go b/plugins/dex/order/mini_keeper.go index 98deb6b9f..60f9c3098 100644 --- a/plugins/dex/order/mini_keeper.go +++ b/plugins/dex/order/mini_keeper.go @@ -84,7 +84,7 @@ func (kp *MiniOrderKeeper) getRoundOrdersNum() int { func (kp *MiniOrderKeeper) reloadOrder(symbol string, orderInfo *OrderInfo, height int64) { kp.allOrders[symbol][orderInfo.Id] = orderInfo - //TODO confirm no active orders for mini symbol + //TODO confirm no round orders for mini symbol if kp.collectOrderInfoForPublish { if _, exists := kp.orderInfosForPub[orderInfo.Id]; !exists { bnclog.Debug("add order to order changes map, during load snapshot, from active orders", "orderId", orderInfo.Id) diff --git a/plugins/dex/order/order_keeper.go b/plugins/dex/order/order_keeper.go index 5dbec9808..02146f75c 100644 --- a/plugins/dex/order/order_keeper.go +++ b/plugins/dex/order/order_keeper.go @@ -201,8 +201,6 @@ func (kp *BaseOrderKeeper) getAllOrdersForPair(pair string) map[string]*OrderInf return kp.allOrders[pair] } - - func (kp *BaseOrderKeeper) iterateAllOrders(iter func(string, string)) { for symbol, orders := range kp.allOrders { for orderId := range orders { From 12f93e595ba8799ec950f5b34a34274c272df7e1 Mon Sep 17 00:00:00 2001 From: George Date: Tue, 26 May 2020 21:42:07 +0800 Subject: [PATCH 79/96] lot size calculation for busd pairs --- plugins/dex/order/keeper.go | 42 +++++++++++++++++++++++--------- plugins/dex/order/keeper_test.go | 32 ++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 493dbd6ca..db1d8f912 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "math" + "math/big" "strings" "sync" "time" @@ -185,17 +186,18 @@ func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, } else if quoteAssetSymbol == types.NativeTokenSymbol { priceAgainstNative = price } else { - if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { - priceAgainstNative = dexUtils.CalcPriceWMA(ps) - } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { - wma := dexUtils.CalcPriceWMA(ps) - priceAgainstNative = 1e16 / wma - } else { - // the recentPrices still have not collected any price yet, iff the native pair is listed for less than kp.pricesStoreEvery blocks - if engine, ok := kp.engines[dexUtils.Assets2TradingPair(baseAssetSymbol, types.NativeTokenSymbol)]; ok { - priceAgainstNative = engine.LastTradePrice - } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(types.NativeTokenSymbol, baseAssetSymbol)]; ok { - priceAgainstNative = 1e16 / engine.LastTradePrice + priceAgainstNative = kp.calcPriceAgainst(baseAssetSymbol, types.NativeTokenSymbol) + if priceAgainstNative == 0 { + if sdk.IsUpgrade(upgrade.BEP70) && len(BUSDSymbol) > 0 { + var tmp = big.NewInt(0) + priceAgainstBUSD := kp.calcPriceAgainst(baseAssetSymbol, BUSDSymbol) + priceBUSDAgainstNative := kp.calcPriceAgainst(BUSDSymbol, types.NativeTokenSymbol) + tmp = tmp.Div(tmp.Mul(big.NewInt(priceAgainstBUSD), big.NewInt(priceBUSDAgainstNative)), big.NewInt(1e8)) + if tmp.IsInt64() { + priceAgainstNative = tmp.Int64() + } else { + priceAgainstNative = math.MaxInt64 + } } else { // should not happen kp.logger.Error("DetermineLotSize failed because no native pair found", "base", baseAssetSymbol, "quote", quoteAssetSymbol) @@ -206,6 +208,24 @@ func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, return lotSize } +func (kp *DexKeeper) calcPriceAgainst(symbol, targetSymbol string) int64 { + var priceAgainst int64 = 0 + if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(symbol, targetSymbol)]; ok { + priceAgainst = dexUtils.CalcPriceWMA(ps) + } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(targetSymbol, symbol)]; ok { + wma := dexUtils.CalcPriceWMA(ps) + priceAgainst = 1e16 / wma + } else { + if engine, ok := kp.engines[dexUtils.Assets2TradingPair(symbol, targetSymbol)]; ok { + priceAgainst = engine.LastTradePrice + } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(targetSymbol, symbol)]; ok { + priceAgainst = 1e16 / engine.LastTradePrice + } + } + + return priceAgainst +} + func (kp *DexKeeper) UpdateLotSize(symbol string, lotSize int64) { eng, ok := kp.engines[symbol] if !ok { diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index 5d4995dbf..5449bf8b8 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -681,6 +681,38 @@ func TestKeeper_DetermineLotSize(t *testing.T) { assert.Equal(int64(1e5), lotsize) // wma price of BNB/BTC-000 is between 1e7 and 1e8 } +func TestKeeper_DetermineLotSize_SupportBUSD(t *testing.T) { + assert := assert.New(t) + ctx, _, keeper := setup() + + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, -1) + keeper.SetBUSDSymbol("BUSD-BD1") + + // no recentPrices recorded, use engine.LastTradePrice + pair1 := dextypes.NewTradingPairWithLotSize("BNB", "BUSD-BD1", 1e6, 1e5) + keeper.AddEngine(pair1) + pair2 := dextypes.NewTradingPairWithLotSize("AAA-000", "BUSD-BD1", 1e6, 1e7) + keeper.AddEngine(pair2) + lotsize := keeper.DetermineLotSize("BNB", "BUSD-BD1", 1e6) + assert.Equal(int64(1e5), lotsize) + lotsize = keeper.DetermineLotSize("BUSD-BD1", "BNB", 1e10) + assert.Equal(int64(1e3), lotsize) + lotsize = keeper.DetermineLotSize("AAA-000", "BUSD-BD1", 1e6) + assert.Equal(int64(1e5), lotsize) + lotsize = keeper.DetermineLotSize("BUSD-BD1", "AAA-000", 1e10) + assert.Equal(int64(1e3), lotsize) + + // store some recentPrices + keeper.StoreTradePrices(ctx.WithBlockHeight(1 * pricesStoreEvery)) + keeper.engines[pair1.GetSymbol()].LastTradePrice = 1e8 + keeper.engines[pair2.GetSymbol()].LastTradePrice = 1e8 + keeper.StoreTradePrices(ctx.WithBlockHeight(2 * pricesStoreEvery)) + lotsize = keeper.DetermineLotSize("AAA-000", "BUSD-BD1", 1e4) + assert.Equal(int64(1e6), lotsize) // wma price of AAA-000/BNB is between 1e7 and 1e8 + lotsize = keeper.DetermineLotSize("BUSD-BD1", "AAA-000", 1e12) + assert.Equal(int64(1e5), lotsize) // wma price of BUSD-BD1/BNB is between 1e8 and 1e9 +} + func TestKeeper_UpdateTickSizeAndLotSize(t *testing.T) { assert := assert.New(t) ctx, _, keeper := setup() From b2fa9b878fc794d4572b7de7961b5c4e0a366c2b Mon Sep 17 00:00:00 2001 From: George Date: Tue, 26 May 2020 22:13:42 +0800 Subject: [PATCH 80/96] small refactor --- plugins/dex/order/keeper.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index db1d8f912..f88bd4e4d 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -186,12 +186,13 @@ func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, } else if quoteAssetSymbol == types.NativeTokenSymbol { priceAgainstNative = price } else { - priceAgainstNative = kp.calcPriceAgainst(baseAssetSymbol, types.NativeTokenSymbol) - if priceAgainstNative == 0 { + var found bool + priceAgainstNative, found = kp.calcPriceAgainst(baseAssetSymbol, types.NativeTokenSymbol) + if !found { if sdk.IsUpgrade(upgrade.BEP70) && len(BUSDSymbol) > 0 { var tmp = big.NewInt(0) - priceAgainstBUSD := kp.calcPriceAgainst(baseAssetSymbol, BUSDSymbol) - priceBUSDAgainstNative := kp.calcPriceAgainst(BUSDSymbol, types.NativeTokenSymbol) + priceAgainstBUSD, _ := kp.calcPriceAgainst(baseAssetSymbol, BUSDSymbol) + priceBUSDAgainstNative, _ := kp.calcPriceAgainst(BUSDSymbol, types.NativeTokenSymbol) tmp = tmp.Div(tmp.Mul(big.NewInt(priceAgainstBUSD), big.NewInt(priceBUSDAgainstNative)), big.NewInt(1e8)) if tmp.IsInt64() { priceAgainstNative = tmp.Int64() @@ -208,22 +209,28 @@ func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, return lotSize } -func (kp *DexKeeper) calcPriceAgainst(symbol, targetSymbol string) int64 { +func (kp *DexKeeper) calcPriceAgainst(symbol, targetSymbol string) (int64, bool) { var priceAgainst int64 = 0 + var found bool if ps, ok := kp.recentPrices[dexUtils.Assets2TradingPair(symbol, targetSymbol)]; ok { priceAgainst = dexUtils.CalcPriceWMA(ps) + found = true } else if ps, ok = kp.recentPrices[dexUtils.Assets2TradingPair(targetSymbol, symbol)]; ok { wma := dexUtils.CalcPriceWMA(ps) priceAgainst = 1e16 / wma + found = true } else { + // the recentPrices still have not collected any price yet, iff the native pair is listed for less than kp.pricesStoreEvery blocks if engine, ok := kp.engines[dexUtils.Assets2TradingPair(symbol, targetSymbol)]; ok { priceAgainst = engine.LastTradePrice + found = true } else if engine, ok = kp.engines[dexUtils.Assets2TradingPair(targetSymbol, symbol)]; ok { priceAgainst = 1e16 / engine.LastTradePrice + found = true } } - return priceAgainst + return priceAgainst, found } func (kp *DexKeeper) UpdateLotSize(symbol string, lotSize int64) { From 3cfbb4d93d27af84abfcb9f318acf2474feea3c5 Mon Sep 17 00:00:00 2001 From: George Date: Wed, 27 May 2020 11:44:08 +0800 Subject: [PATCH 81/96] handle new listing --- plugins/dex/order/keeper.go | 6 +++++- plugins/dex/order/keeper_test.go | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index f88bd4e4d..ffbe36ecf 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -191,7 +191,11 @@ func (kp *DexKeeper) DetermineLotSize(baseAssetSymbol, quoteAssetSymbol string, if !found { if sdk.IsUpgrade(upgrade.BEP70) && len(BUSDSymbol) > 0 { var tmp = big.NewInt(0) - priceAgainstBUSD, _ := kp.calcPriceAgainst(baseAssetSymbol, BUSDSymbol) + priceAgainstBUSD, ok := kp.calcPriceAgainst(baseAssetSymbol, BUSDSymbol) + if !ok { + // for newly added pair, there is no trading yet + priceAgainstBUSD = price + } priceBUSDAgainstNative, _ := kp.calcPriceAgainst(BUSDSymbol, types.NativeTokenSymbol) tmp = tmp.Div(tmp.Mul(big.NewInt(priceAgainstBUSD), big.NewInt(priceBUSDAgainstNative)), big.NewInt(1e8)) if tmp.IsInt64() { diff --git a/plugins/dex/order/keeper_test.go b/plugins/dex/order/keeper_test.go index 5449bf8b8..7dbeb4b02 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -702,6 +702,10 @@ func TestKeeper_DetermineLotSize_SupportBUSD(t *testing.T) { lotsize = keeper.DetermineLotSize("BUSD-BD1", "AAA-000", 1e10) assert.Equal(int64(1e3), lotsize) + // no trading yet, use list price + lotsize = keeper.DetermineLotSize("BBB-000", "BUSD-BD1", 1e8) + assert.Equal(int64(1e3), lotsize) + // store some recentPrices keeper.StoreTradePrices(ctx.WithBlockHeight(1 * pricesStoreEvery)) keeper.engines[pair1.GetSymbol()].LastTradePrice = 1e8 From e5197c4e1e9a3ad3947c8692882c31edfe2f98b5 Mon Sep 17 00:00:00 2001 From: rickyyangz Date: Wed, 27 May 2020 18:50:34 +0800 Subject: [PATCH 82/96] msg&handler refactor --- common/types/mini_token.go | 28 +++--- plugins/api/routes.go | 6 +- plugins/dex/list/handler_mini_test.go | 5 +- plugins/dex/order/handler.go | 8 +- plugins/dex/order/keeper.go | 4 +- plugins/tokens/burn/handler.go | 7 +- plugins/tokens/burn/handler_test.go | 14 +-- plugins/tokens/burn/msg.go | 1 - plugins/tokens/client/cli/issue.go | 2 +- plugins/tokens/client/cli/issue_mini.go | 2 +- plugins/tokens/client/rest/gettoken.go | 22 ++--- plugins/tokens/client/rest/gettokens.go | 2 +- plugins/tokens/freeze/handler.go | 8 +- plugins/tokens/freeze/handler_test.go | 10 +-- plugins/tokens/issue/handler.go | 101 ++++++++++++---------- plugins/tokens/issue/handler_mini.go | 85 ++---------------- plugins/tokens/issue/handler_mini_test.go | 24 ++--- plugins/tokens/issue/handler_test.go | 4 +- plugins/tokens/issue/msg.go | 4 +- plugins/tokens/issue/msg_mini.go | 9 +- plugins/tokens/issue/msg_tiny.go | 9 +- plugins/tokens/seturi/handler_test.go | 8 +- plugins/tokens/seturi/msg.go | 4 - plugins/tokens/store/mapper.go | 12 --- 24 files changed, 136 insertions(+), 243 deletions(-) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 7ac3c147d..9f419ddb8 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -18,10 +18,10 @@ const ( MiniTokenSymbolTxHashSuffixLen = 3 // probably enough. if it collides (unlikely) the issuer can just use another tx. MiniTokenSymbolMSuffix = "M" - MiniTokenMinTotalSupply int64 = 100000000 // 1 with 8 decimal digits - MiniTokenSupplyUpperBound int64 = 10000000000000 // 100k with 8 decimal digits - TinyTokenSupplyUpperBound int64 = 1000000000000 - MaxTokenURILength = 2048 + MiniTokenMinExecutionAmount int64 = 100000000 // 1 with 8 decimal digits + MiniTokenSupplyUpperBound int64 = 10000000000000 // 100k with 8 decimal digits + TinyTokenSupplyUpperBound int64 = 1000000000000 + MaxTokenURILength = 2048 TinyRangeType SupplyRangeType = 1 MiniRangeType SupplyRangeType = 2 @@ -64,26 +64,18 @@ type MiniToken struct { var _ IToken = &MiniToken{} -func NewMiniToken(name, symbol string, supplyRangeType SupplyRangeType, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken, error) { - // double check that the symbol is suffixed - if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { - return nil, err - } - parts, err := splitSuffixedMiniTokenSymbol(symbol) - if err != nil { - return nil, err - } +func NewMiniToken(name, origSymbol, symbol string, supplyRangeType SupplyRangeType, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken) { return &MiniToken{ - Token{Name: name, + Token: Token{Name: name, Symbol: symbol, - OrigSymbol: parts[0], + OrigSymbol: origSymbol, TotalSupply: utils.Fixed8(totalSupply), Owner: owner, Mintable: mintable, }, - supplyRangeType, - tokenURI, - }, nil + TokenType: supplyRangeType, + TokenURI: tokenURI, + } } //check if it's mini token by last letter without validation diff --git a/plugins/api/routes.go b/plugins/api/routes.go index b30c43418..8e259ab6e 100644 --- a/plugins/api/routes.go +++ b/plugins/api/routes.go @@ -44,7 +44,7 @@ func (s *server) bindRoutes() *server { Queries("address", "{address}", "symbol", "{symbol}"). Methods("GET") - r.HandleFunc(prefix+"/mini-token/markets", s.handleMiniPairsReq(s.cdc, s.ctx)). + r.HandleFunc(prefix+"/mini/markets", s.handleMiniPairsReq(s.cdc, s.ctx)). Methods("GET") // tokens routes @@ -58,9 +58,9 @@ func (s *server) bindRoutes() *server { Methods("GET") // mini tokens routes - r.HandleFunc(prefix+"/mini-token/tokens", s.handleMiniTokensReq(s.cdc, s.ctx)). + r.HandleFunc(prefix+"/mini/tokens", s.handleMiniTokensReq(s.cdc, s.ctx)). Methods("GET") - r.HandleFunc(prefix+"/mini-token/tokens/{symbol}", s.handleMiniTokenReq(s.cdc, s.ctx)). + r.HandleFunc(prefix+"/mini/tokens/{symbol}", s.handleMiniTokenReq(s.cdc, s.ctx)). Methods("GET") // fee params diff --git a/plugins/dex/list/handler_mini_test.go b/plugins/dex/list/handler_mini_test.go index 1102fb062..50d8531f7 100644 --- a/plugins/dex/list/handler_mini_test.go +++ b/plugins/dex/list/handler_mini_test.go @@ -43,14 +43,13 @@ func setupForMini(ctx sdk.Context, tokenMapper tokenStore.Mapper, t *testing.T) }) require.Nil(t, err, "new token error") - miniToken, _ := types.NewMiniToken("Bitcoin Mini", "BTC-000M", types.MiniRangeType, 100000e8, sdk.AccAddress("testacc"), false, "") + miniToken := types.NewMiniToken("Bitcoin Mini","BTC", "BTC-000M", types.MiniRangeType, 100000e8, sdk.AccAddress("testacc"), false, "") err = tokenMapper.NewToken(ctx, miniToken) require.Nil(t, err, "new token error") - tinyToken, _ := types.NewMiniToken("Bitcoin Mini", "ETH-000M", types.TinyRangeType, 10000e8, sdk.AccAddress("testacc"), true, "abc") + tinyToken := types.NewMiniToken("Bitcoin Mini", "ETH", "ETH-000M", types.TinyRangeType, 10000e8, sdk.AccAddress("testacc"), true, "abc") err = tokenMapper.NewToken(ctx, tinyToken) require.Nil(t, err, "new token error") - } func TestHandleListMiniIdenticalSymbols(t *testing.T) { diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index 19f6703c7..46cc31429 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -49,13 +49,13 @@ func validateQtyAndLockBalance(ctx sdk.Context, keeper *DexKeeper, acc common.Na if sdk.IsUpgrade(sdk.BEP8) && isMiniSymbolPair(baseAssetSymbol, quoteAssetSymbol) { var quantityBigEnough bool if msg.Side == Side.BUY { - quantityBigEnough = msg.Quantity >= common.MiniTokenMinTotalSupply + quantityBigEnough = msg.Quantity >= common.MiniTokenMinExecutionAmount } else if msg.Side == Side.SELL { - quantityBigEnough = (msg.Quantity >= common.MiniTokenMinTotalSupply) || freeBalance.AmountOf(symbol) == msg.Quantity + quantityBigEnough = (msg.Quantity >= common.MiniTokenMinExecutionAmount) || freeBalance.AmountOf(symbol) == msg.Quantity } if !quantityBigEnough { return fmt.Errorf("quantity is too small, the min quantity is %d or total free balance of the mini token", - common.MiniTokenMinTotalSupply) + common.MiniTokenMinExecutionAmount) } } @@ -102,8 +102,6 @@ func validateQtyAndLockBalance(ctx sdk.Context, keeper *DexKeeper, acc common.Na func handleNewOrder( ctx sdk.Context, cdc *wire.Codec, dexKeeper *DexKeeper, msg NewOrderMsg, ) sdk.Result { - // TODO: the below is mostly copied from FreezeToken. It should be rewritten once "locked" becomes a field on account - // this check costs least. if _, ok := dexKeeper.OrderExists(msg.Symbol, msg.Id); ok { errString := fmt.Sprintf("Duplicated order [%v] on symbol [%v]", msg.Id, msg.Symbol) return sdk.NewError(types.DefaultCodespace, types.CodeDuplicatedOrder, errString).Result() diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index f88bd4e4d..ccf4004e5 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -114,7 +114,7 @@ func (kp *DexKeeper) EnablePublish() { func (kp *DexKeeper) getOrderKeeper(symbol string) (DexOrderKeeper, error) { pairType, ok := kp.pairsType[symbol] if !ok { - err := fmt.Errorf("order doesn't exist [%v]", symbol) + err := fmt.Errorf("invalid symbol: %s", symbol) kp.logger.Debug(err.Error()) return nil, err } @@ -123,7 +123,7 @@ func (kp *DexKeeper) getOrderKeeper(symbol string) (DexOrderKeeper, error) { return kp.OrderKeepers[i], nil } } - err := fmt.Errorf("failed to find orderKeeper for symbol pair [%v]", symbol) + err := fmt.Errorf("failed to find orderKeeper for symbol pair [%s]", symbol) kp.logger.Error(err.Error()) return nil, err } diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 89b82b5a6..4f364c901 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -48,11 +48,10 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { useAllBalance := coins.AmountOf(symbol) == burnAmount - - if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinTotalSupply)) { - logger.Info("burn token failed", "reason", "burn amount doesn't reach the min supply") + if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinExecutionAmount)) { + logger.Info("burn token failed", "reason", "burn amount doesn't reach the min amount") return sdk.ErrInvalidCoins(fmt.Sprintf("burn amount is too small, the min amount is %d or total free balance", - common.MiniTokenMinTotalSupply)).Result() + common.MiniTokenMinExecutionAmount)).Result() } } diff --git a/plugins/tokens/burn/handler_test.go b/plugins/tokens/burn/handler_test.go index aa406c285..f38447ea6 100644 --- a/plugins/tokens/burn/handler_test.go +++ b/plugins/tokens/burn/handler_test.go @@ -62,8 +62,8 @@ func TestHandleBurnMini(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken := types.NewMiniToken("New BNB", "NNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) ctx = ctx.WithValue(baseapp.TxHashKey, "002") burnMsg := NewMsg(acc.GetAddress(), "NNB-000M", 10001e8+1) @@ -78,8 +78,8 @@ func TestHandleBurnMini(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 2, 1e8-1, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken = types.NewMiniToken("New BNB", "NNB", "NNB-000M", 2, 1e8-1, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) amount := account.GetCoins().AmountOf("NNB-000M") @@ -97,8 +97,8 @@ func TestHandleBurnMini(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 2, 0, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken = types.NewMiniToken("New BNB", "NNB", "NNB-000M", 2, 0, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "002") @@ -144,7 +144,7 @@ func TestHandleBurn(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000") require.NoError(t, err) expectedToken, err := types.NewToken("New BNB", "NNB-000", 1e8-1, acc.GetAddress(), false) - require.Equal(t, *expectedToken, *(token.(*types.Token))) + require.Equal(t, expectedToken, token) account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) amount := account.GetCoins().AmountOf("NNB-000") diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index 3e0de28cc..24aa779a8 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -41,7 +41,6 @@ func (msg BurnMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAdd // ValidateBasic does a simple validation check that // doesn't require access to any other information. func (msg BurnMsg) ValidateBasic() sdk.Error { - if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } diff --git a/plugins/tokens/client/cli/issue.go b/plugins/tokens/client/cli/issue.go index b24011f14..58a5647d8 100644 --- a/plugins/tokens/client/cli/issue.go +++ b/plugins/tokens/client/cli/issue.go @@ -114,7 +114,7 @@ func checkSupplyAmount(amount int64) error { return nil } func checkMiniTokenSupplyAmount(amount int64) error { - if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenSupplyUpperBound { + if amount <= types.MiniTokenMinExecutionAmount || amount > types.MiniTokenSupplyUpperBound { return errors.New("invalid supply amount") } diff --git a/plugins/tokens/client/cli/issue_mini.go b/plugins/tokens/client/cli/issue_mini.go index 73f851a08..a3a47e248 100644 --- a/plugins/tokens/client/cli/issue_mini.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -70,7 +70,7 @@ func (c Commander) issueMiniToken(cmd *cobra.Command, args []string) error { } func checkMiniSupplyAmount(amount int64, tokenType int8) error { - if amount <= types.MiniTokenMinTotalSupply || amount > types.MiniTokenSupplyUpperBound { + if amount <= types.MiniTokenMinExecutionAmount || amount > types.MiniTokenSupplyUpperBound { return errors.New("invalid supply amount") } if amount > types.SupplyRangeType(tokenType).UpperBound() { diff --git a/plugins/tokens/client/rest/gettoken.go b/plugins/tokens/client/rest/gettoken.go index 53e5b9b24..19f7443c6 100644 --- a/plugins/tokens/client/rest/gettoken.go +++ b/plugins/tokens/client/rest/gettoken.go @@ -14,7 +14,7 @@ import ( "github.com/binance-chain/node/wire" ) -func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini bool) (interface{}, error) { +func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini bool) (types.IToken, error) { var abciPrefix string if isMini { abciPrefix = "mini-tokens" @@ -26,21 +26,13 @@ func getTokenInfo(ctx context.CLIContext, cdc *wire.Codec, symbol string, isMini return nil, err } - if isMini { - var token types.MiniToken - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &token) - if err != nil { - fmt.Println(err) - } - return token, nil - } else { - var token types.Token - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &token) - if err != nil { - fmt.Println(err) - } - return token, nil + var token types.IToken + err = cdc.UnmarshalBinaryLengthPrefixed(bz, token) + if err != nil { + fmt.Println(err) + return nil, err } + return token, nil } // GetTokenReqHandler creates an http request handler to get info for an individual token diff --git a/plugins/tokens/client/rest/gettokens.go b/plugins/tokens/client/rest/gettokens.go index df0aef894..986b2d359 100644 --- a/plugins/tokens/client/rest/gettokens.go +++ b/plugins/tokens/client/rest/gettokens.go @@ -33,9 +33,9 @@ func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit in err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) if err != nil { fmt.Println(err) + return nil, err } return tokens, nil - } // GetTokensReqHandler creates an http request handler to get the list of tokens in the token mapper diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 05a3ba4b6..42db63d59 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -43,10 +43,10 @@ func handleFreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper auth if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { useAllBalance := coins.AmountOf(symbol) == freezeAmount - if msg.Amount <= 0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinTotalSupply)) { + if msg.Amount <= 0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinExecutionAmount)) { logger.Info("freeze token failed", "reason", "freeze amount doesn't reach the min supply") return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", - common.MiniTokenMinTotalSupply)).Result() + common.MiniTokenMinExecutionAmount)).Result() } } @@ -79,10 +79,10 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { useAllFrozenBalance := frozenAmount == unfreezeAmount - if unfreezeAmount <= 0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinTotalSupply)) { + if unfreezeAmount <= 0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinExecutionAmount)) { logger.Info("unfreeze token failed", "reason", "unfreeze amount doesn't reach the min supply") return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", - common.MiniTokenMinTotalSupply)).Result() + common.MiniTokenMinExecutionAmount)).Result() } } diff --git a/plugins/tokens/freeze/handler_test.go b/plugins/tokens/freeze/handler_test.go index 565567039..eac894eff 100644 --- a/plugins/tokens/freeze/handler_test.go +++ b/plugins/tokens/freeze/handler_test.go @@ -63,8 +63,8 @@ func TestHandleFreezeMini(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken := types.NewMiniToken("New BNB", "NNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) account := accountKeeper.GetAccount(ctx, msg.From).(types.NamedAccount) amount := account.GetCoins().AmountOf("NNB-000M") @@ -108,8 +108,8 @@ func TestHandleFreezeMini(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken = types.NewMiniToken("New BNB", "NNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) ctx = ctx.WithValue(baseapp.TxHashKey, "003") unfreezeMsg := NewUnfreezeMsg(acc.GetAddress(), "NNB-000M", 1e8-1) @@ -190,7 +190,7 @@ func TestHandleFreeze(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000") require.NoError(t, err) expectedToken, err := types.NewToken("New BNB", "NNB-000", 10000e8, acc.GetAddress(), false) - require.Equal(t, *expectedToken, *(token.(*types.Token))) + require.Equal(t, expectedToken, token) ctx = ctx.WithValue(baseapp.TxHashKey, "003") unfreezeMsg := NewUnfreezeMsg(acc.GetAddress(), "NNB-000", 1) diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 6aa01809d..5fbeade5d 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -8,10 +8,10 @@ import ( "strings" "github.com/binance-chain/node/common/upgrade" - "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" + tmlog "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" @@ -42,28 +42,14 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank errLogMsg := "issue token failed" symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) - var suffix string - - // TxHashKey is set in BaseApp's runMsgs - txHash := ctx.Value(baseapp.TxHashKey) - if txHashStr, ok := txHash.(string); ok { - if len(txHashStr) >= types.TokenSymbolTxHashSuffixLen { - suffix = txHashStr[:types.TokenSymbolTxHashSuffixLen] - } else { - logger.Error(errLogMsg, - "reason", fmt.Sprintf("%s on Context had a length of %d, expected >= %d", - baseapp.TxHashKey, len(txHashStr), types.TokenSymbolTxHashSuffixLen)) - return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() - } - } else { - logger.Error(errLogMsg, - "reason", fmt.Sprintf("%s on Context is not a string as expected", baseapp.TxHashKey)) + suffix, err := getTokenSuffix(ctx) + if err != nil { + logger.Error(errLogMsg, "reason", err.Error()) return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() } // the symbol is suffixed with the first n bytes of the tx hash symbol = fmt.Sprintf("%s-%s", symbol, suffix) - if exists := tokenMapper.Exists(ctx, symbol); exists { logger.Info(errLogMsg, "reason", "already exists") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) already exists", msg.Symbol)).Result() @@ -74,33 +60,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank logger.Error(errLogMsg, "reason", "create token failed: "+err.Error()) return sdk.ErrInternal(fmt.Sprintf("unable to create token struct: %s", err.Error())).Result() } - - if err := tokenMapper.NewToken(ctx, token); err != nil { - logger.Error(errLogMsg, "reason", "add token failed: "+err.Error()) - return sdk.ErrInvalidCoins(err.Error()).Result() - } - - if _, _, sdkError := bankKeeper.AddCoins(ctx, token.Owner, - sdk.Coins{{ - Denom: token.Symbol, - Amount: token.TotalSupply.ToInt64(), - }}); sdkError != nil { - logger.Error(errLogMsg, "reason", "update balance failed: "+sdkError.Error()) - return sdkError.Result() - } - - serialized, err := json.Marshal(token) - if err != nil { - logger.Error(errLogMsg, "reason", "fatal! unable to json serialize token: "+err.Error()) - panic(err) // fatal, the sky is falling in goland - } - - logger.Info("finished issuing token") - - return sdk.Result{ - Data: serialized, - Log: fmt.Sprintf("Issued %s", token.Symbol), - } + return issue(ctx, logger, tokenMapper, bankKeeper, token) } //Mint MiniToken is also handled by this function @@ -134,10 +94,10 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { miniToken := token.(*types.MiniToken) - if msg.Amount < common.MiniTokenMinTotalSupply { + if msg.Amount < common.MiniTokenMinExecutionAmount { logger.Info(errLogMsg, "reason", "mint amount doesn't reach the min supply") return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %d", - common.MiniTokenMinTotalSupply)).Result() + common.MiniTokenMinExecutionAmount)).Result() } // use minus to prevent overflow if msg.Amount > miniToken.TokenType.UpperBound()-miniToken.TotalSupply.ToInt64() { @@ -175,3 +135,50 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. Data: []byte(strconv.FormatInt(newTotalSupply, 10)), } } + +func issue(ctx sdk.Context, logger tmlog.Logger, tokenMapper store.Mapper, bankKeeper bank.Keeper, token common.IToken) sdk.Result { + errLogMsg := "issue token failed" + if err := tokenMapper.NewToken(ctx, token); err != nil { + logger.Error(errLogMsg, "reason", "add token failed: "+err.Error()) + return sdk.ErrInvalidCoins(err.Error()).Result() + } + + if _, _, sdkError := bankKeeper.AddCoins(ctx, token.GetOwner(), + sdk.Coins{{ + Denom: token.GetSymbol(), + Amount: token.GetTotalSupply().ToInt64(), + }}); sdkError != nil { + logger.Error(errLogMsg, "reason", "update balance failed: "+sdkError.Error()) + return sdkError.Result() + } + + serialized, err := json.Marshal(token) + if err != nil { + logger.Error(errLogMsg, "reason", "fatal! unable to json serialize token: "+err.Error()) + panic(err) // fatal, the sky is falling in goland + } + + logger.Info("finished issuing token") + + return sdk.Result{ + Data: serialized, + Log: fmt.Sprintf("Issued %s", token.GetSymbol()), + }} + +func getTokenSuffix(ctx sdk.Context) (suffix string, err error) { + // TxHashKey is set in BaseApp's runMsgs + txHash := ctx.Value(baseapp.TxHashKey) + if txHashStr, ok := txHash.(string); ok { + if len(txHashStr) >= types.TokenSymbolTxHashSuffixLen { + suffix = txHashStr[:types.TokenSymbolTxHashSuffixLen] + return suffix, nil + } else { + err = fmt.Errorf("%s on Context had a length of %d, expected >= %d", + baseapp.TxHashKey, len(txHashStr), types.TokenSymbolTxHashSuffixLen) + return "", err + } + } else { + err = fmt.Errorf("%s on Context is not a string as expected", baseapp.TxHashKey) + return "", err + } +} diff --git a/plugins/tokens/issue/handler_mini.go b/plugins/tokens/issue/handler_mini.go index f0886ce58..1aa85dd83 100644 --- a/plugins/tokens/issue/handler_mini.go +++ b/plugins/tokens/issue/handler_mini.go @@ -1,101 +1,34 @@ package issue import ( - "encoding/json" "fmt" "strings" - "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/tokens/store" ) func (msg IssueMiniMsg) handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, tokenType common.SupplyRangeType) sdk.Result { errLogMsg := "issue miniToken failed" - symbol := strings.ToUpper(msg.Symbol) - logger := log.With("module", "mini-token", "symbol", symbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) - var suffix string + origSymbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "mini-token", "symbol", origSymbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) - if !sdk.IsUpgrade(upgrade.BEP8) { - return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")).Result() - } - - // TxHashKey is set in BaseApp's runMsgs - txHash := ctx.Value(baseapp.TxHashKey) - if txHashStr, ok := txHash.(string); ok { - if len(txHashStr) >= common.MiniTokenSymbolTxHashSuffixLen { - suffix = txHashStr[:common.MiniTokenSymbolTxHashSuffixLen] + common.MiniTokenSymbolMSuffix - } else { - logger.Error(errLogMsg, - "reason", fmt.Sprintf("%s on Context had a length of %d, expected >= %d", - baseapp.TxHashKey, len(txHashStr), common.MiniTokenSymbolTxHashSuffixLen)) - return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() - } - } else { - logger.Error(errLogMsg, - "reason", fmt.Sprintf("%s on Context is not a string as expected", baseapp.TxHashKey)) - return sdk.ErrInternal(fmt.Sprintf("unable to get the %s from Context", baseapp.TxHashKey)).Result() - } - - if msg.TotalSupply < common.MiniTokenMinTotalSupply { - logger.Info(errLogMsg, "reason", "total supply doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too small, the min amount is %d", - common.MiniTokenMinTotalSupply)).Result() - } - - if msg.TotalSupply > tokenType.UpperBound() { - logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply is too large, the max total supply is %d", - tokenType.UpperBound())).Result() - } - // the symbol is suffixed with the first n bytes of the tx hash - symbol = fmt.Sprintf("%s-%s", symbol, suffix) - - if !common.IsValidMiniTokenSymbol(symbol) { - logger.Info(errLogMsg, "reason", "symbol not valid") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) is not valid for mini-token", symbol)).Result() + suffix, err := getTokenSuffix(ctx) + if err != nil { + logger.Error(errLogMsg, "reason", err.Error()) } + suffix += common.MiniTokenSymbolMSuffix + symbol := fmt.Sprintf("%s-%s", origSymbol, suffix) if exists := tokenMapper.Exists(ctx, symbol); exists { logger.Info(errLogMsg, "reason", "already exists") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) already exists", msg.Symbol)).Result() } - token, err := common.NewMiniToken(msg.Name, symbol, tokenType, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) - if err != nil { - logger.Error(errLogMsg, "reason", "create token failed: "+err.Error()) - return sdk.ErrInternal(fmt.Sprintf("unable to create token struct: %s", err.Error())).Result() - } - - if err := tokenMapper.NewToken(ctx, token); err != nil { - logger.Error(errLogMsg, "reason", "add token failed: "+err.Error()) - return sdk.ErrInvalidCoins(err.Error()).Result() - } - - if _, _, sdkError := bankKeeper.AddCoins(ctx, token.Owner, - sdk.Coins{{ - Denom: token.Symbol, - Amount: token.TotalSupply.ToInt64(), - }}); sdkError != nil { - logger.Error(errLogMsg, "reason", "update balance failed: "+sdkError.Error()) - return sdkError.Result() - } - - serialized, err := json.Marshal(token) - if err != nil { - logger.Error(errLogMsg, "reason", "fatal! unable to json serialize token: "+err.Error()) - panic(err) // fatal, the sky is falling in goland - } - - logger.Info("finished issuing token") - - return sdk.Result{ - Data: serialized, - Log: fmt.Sprintf("Issued %s", token.Symbol), - } + token := common.NewMiniToken(msg.Name, origSymbol, symbol, tokenType, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) + return issue(ctx, logger, tokenMapper, bankKeeper, token) } diff --git a/plugins/tokens/issue/handler_mini_test.go b/plugins/tokens/issue/handler_mini_test.go index 2cbd5dee8..877c7268d 100644 --- a/plugins/tokens/issue/handler_mini_test.go +++ b/plugins/tokens/issue/handler_mini_test.go @@ -47,9 +47,9 @@ func TestHandleIssueMiniToken(t *testing.T) { ctx = ctx.WithValue(baseapp.TxHashKey, "000") msg := NewIssueTinyMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8+100, false, "http://www.xyz.com/nnb.json") - sdkResult := handler(ctx, msg) + sdkResult := msg.ValidateBasic().Result() require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") + require.Contains(t, sdkResult.Log, fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinExecutionAmount, types.TinyRangeType.UpperBound())) ctx = ctx.WithValue(baseapp.TxHashKey, "000") msg = NewIssueTinyMsg(acc.GetAddress(), "New BNB", "NNB", 10000e8, false, "http://www.xyz.com/nnb.json") @@ -58,17 +58,17 @@ func TestHandleIssueMiniToken(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken := types.NewMiniToken("New BNB", "NNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) sdkResult = handler(ctx, msg) require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") ctx = ctx.WithValue(baseapp.TxHashKey, "002") msgMini := NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 100000e8+100, false, "http://www.xyz.com/nnb.json") - sdkResult = handler(ctx, msgMini) + sdkResult = msgMini.ValidateBasic().Result() require.Equal(t, false, sdkResult.Code.IsOK()) - require.Contains(t, sdkResult.Log, "total supply is too large, the max total supply ") + require.Contains(t, sdkResult.Log, fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinExecutionAmount, types.MiniRangeType.UpperBound())) ctx = ctx.WithValue(baseapp.TxHashKey, "002") msgMini = NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 10000e8+100, false, "http://www.xyz.com/nnb.json") @@ -77,8 +77,8 @@ func TestHandleIssueMiniToken(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NBB-002M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BB", "NBB-002M", 2, 10000e8+100, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken = types.NewMiniToken("New BB", "NBB", "NBB-002M", 2, 10000e8+100, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) } func TestHandleMintMiniToken(t *testing.T) { @@ -101,8 +101,8 @@ func TestHandleMintMiniToken(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 1, 9000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken := types.NewMiniToken("New BNB", "NNB", "NNB-000M", 1, 9000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) _, err = tokenMapper.GetToken(ctx, "NNB-000") require.NotNil(t, err) @@ -116,8 +116,8 @@ func TestHandleMintMiniToken(t *testing.T) { sdkResult = handler(ctx, validMintMsg) require.Equal(t, true, sdkResult.Code.IsOK()) token, err = tokenMapper.GetToken(ctx, "NNB-000M") - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken = types.NewMiniToken("New BNB", "NNB", "NNB-000M", 1, 10000e8, acc.GetAddress(), true, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) invalidMintMsg := NewMintMsg(acc2.GetAddress(), "NNB-000M", 100e8) diff --git a/plugins/tokens/issue/handler_test.go b/plugins/tokens/issue/handler_test.go index 16d8e5827..7ef4277c2 100644 --- a/plugins/tokens/issue/handler_test.go +++ b/plugins/tokens/issue/handler_test.go @@ -57,7 +57,7 @@ func TestHandleIssueToken(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000") require.NoError(t, err) expectedToken, err := types.NewToken("New BNB", "NNB-000", 100000e8, acc.GetAddress(), false) - require.Equal(t, *expectedToken, *token.(*types.Token)) + require.Equal(t, expectedToken, token) sdkResult = handler(ctx, msg) require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") @@ -81,7 +81,7 @@ func TestHandleMintToken(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000") require.NoError(t, err) expectedToken, err := types.NewToken("New BNB", "NNB-000", 110000e8, acc.GetAddress(), true) - require.Equal(t, *expectedToken, *token.(*types.Token)) + require.Equal(t, expectedToken, token) invalidMintMsg := NewMintMsg(acc.GetAddress(), "NNB-000", types.TokenMaxTotalSupply) sdkResult = handler(ctx, invalidMintMsg) diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index e29a2b2a9..b4f39816b 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -125,8 +125,8 @@ func (msg MintMsg) validateMiniTokenBasic() sdk.Error { } // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply - if msg.Amount < types.MiniTokenMinTotalSupply || msg.Amount > types.MiniTokenSupplyUpperBound { - return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d and %d", types.MiniTokenMinTotalSupply, types.MiniTokenSupplyUpperBound)) + if msg.Amount < types.MiniTokenMinExecutionAmount || msg.Amount > types.MiniTokenSupplyUpperBound { + return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d and %d", types.MiniTokenMinExecutionAmount, types.MiniTokenSupplyUpperBound)) } return nil diff --git a/plugins/tokens/issue/msg_mini.go b/plugins/tokens/issue/msg_mini.go index e3f4f170d..d109acd7a 100644 --- a/plugins/tokens/issue/msg_mini.go +++ b/plugins/tokens/issue/msg_mini.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" ) // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash @@ -41,10 +40,6 @@ func NewIssueMiniMsg(from sdk.AccAddress, name, symbol string, supply int64, min // ValidateBasic does a simple validation check that // doesn't require access to any other information. func (msg IssueMiniMsg) ValidateBasic() sdk.Error { - if !sdk.IsUpgrade(upgrade.BEP8) { - return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")) - } - if msg.From == nil { return sdk.ErrInvalidAddress("sender address cannot be empty") } @@ -61,8 +56,8 @@ func (msg IssueMiniMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidCoins(fmt.Sprintf("token seturi should not exceed %v characters", types.MaxTokenURILength)) } - if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.MiniRangeType.UpperBound() { - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinTotalSupply, types.MiniRangeType.UpperBound())) + if msg.TotalSupply < types.MiniTokenMinExecutionAmount || msg.TotalSupply > types.MiniRangeType.UpperBound() { + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinExecutionAmount, types.MiniRangeType.UpperBound())) } return nil diff --git a/plugins/tokens/issue/msg_tiny.go b/plugins/tokens/issue/msg_tiny.go index 6335344b7..32b621c7b 100644 --- a/plugins/tokens/issue/msg_tiny.go +++ b/plugins/tokens/issue/msg_tiny.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" ) // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash @@ -37,10 +36,6 @@ func NewIssueTinyMsg(from sdk.AccAddress, name, symbol string, supply int64, min // ValidateBasic does a simple validation check that // doesn't require access to any other information. func (msg IssueTinyMsg) ValidateBasic() sdk.Error { - if !sdk.IsUpgrade(upgrade.BEP8) { - return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")) - } - if msg.From == nil { return sdk.ErrInvalidAddress("sender address cannot be empty") } @@ -57,8 +52,8 @@ func (msg IssueTinyMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidCoins(fmt.Sprintf("token seturi should not exceed %v characters", types.MaxTokenURILength)) } - if msg.TotalSupply < types.MiniTokenMinTotalSupply || msg.TotalSupply > types.TinyRangeType.UpperBound() { - return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinTotalSupply, types.TinyRangeType.UpperBound())) + if msg.TotalSupply < types.MiniTokenMinExecutionAmount || msg.TotalSupply > types.TinyRangeType.UpperBound() { + return sdk.ErrInvalidCoins(fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinExecutionAmount, types.TinyRangeType.UpperBound())) } return nil diff --git a/plugins/tokens/seturi/handler_test.go b/plugins/tokens/seturi/handler_test.go index a55ef3da7..b008dd540 100644 --- a/plugins/tokens/seturi/handler_test.go +++ b/plugins/tokens/seturi/handler_test.go @@ -63,8 +63,8 @@ func TestHandleSetURI(t *testing.T) { token, err := tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err := types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken := types.NewMiniToken("New BNB", "NNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.xyz.com/nnb.json") + require.Equal(t, expectedToken, token) ctx = ctx.WithValue(baseapp.TxHashKey, "002") setUriMsg := NewSetUriMsg(acc.GetAddress(), "NBB", "http://www.123.com/nnb_new.json") @@ -79,8 +79,8 @@ func TestHandleSetURI(t *testing.T) { token, err = tokenMapper.GetToken(ctx, "NNB-000M") require.NoError(t, err) - expectedToken, err = types.NewMiniToken("New BNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.123.com/nnb_new.json") - require.Equal(t, *expectedToken, *(token.(*types.MiniToken))) + expectedToken = types.NewMiniToken("New BNB", "NNB", "NNB-000M", 2, 10000e8, acc.GetAddress(), false, "http://www.123.com/nnb_new.json") + require.Equal(t, expectedToken, token) _, acc2 := testutils.NewAccount(ctx, accountKeeper, 100e8) ctx = ctx.WithValue(baseapp.TxHashKey, "002") diff --git a/plugins/tokens/seturi/msg.go b/plugins/tokens/seturi/msg.go index 960133591..684204c60 100644 --- a/plugins/tokens/seturi/msg.go +++ b/plugins/tokens/seturi/msg.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" ) const SetURIRoute = "miniTokensSetURI" @@ -29,9 +28,6 @@ func NewSetUriMsg(from sdk.AccAddress, symbol string, tokenURI string) SetURIMsg } func (msg SetURIMsg) ValidateBasic() sdk.Error { - if !sdk.IsUpgrade(upgrade.BEP8) { - return sdk.ErrInternal(fmt.Sprint("issue miniToken is not supported at current height")) - } if msg.From == nil || len(msg.From) == 0 { return sdk.ErrInvalidAddress("sender address cannot be empty") } diff --git a/plugins/tokens/store/mapper.go b/plugins/tokens/store/mapper.go index 98600cab3..079108f6d 100644 --- a/plugins/tokens/store/mapper.go +++ b/plugins/tokens/store/mapper.go @@ -71,18 +71,6 @@ func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.IToken, error) { return nil, fmt.Errorf("token(%v) not found", symbol) } -func (m mapper) GetTokenCC(ctx context.CLIContext, symbol string) (types.IToken, error) { - key := []byte(strings.ToUpper(symbol)) - bz, err := ctx.QueryStore(key, common.TokenStoreName) - if err != nil { - return nil, err - } - if bz != nil { - return m.decodeIToken(bz), nil - } - return nil, fmt.Errorf("token(%v) not found", symbol) -} - func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool, isMini bool) ITokens { var res ITokens store := ctx.KVStore(m.key) From a057234bd3af4d805dc459490de09f6adae43acd Mon Sep 17 00:00:00 2001 From: rickyyangz Date: Thu, 28 May 2020 18:18:58 +0800 Subject: [PATCH 83/96] msg&handler refactor --- common/types/mini_token.go | 104 +++++++++++++++-------- common/types/token.go | 22 ++--- common/types/token_test.go | 27 +++--- plugins/dex/client/cli/list.go | 6 +- plugins/dex/list/handler.go | 4 +- plugins/dex/list/handler_mini.go | 1 - plugins/dex/list/hooks.go | 4 +- plugins/dex/list/msg.go | 4 +- plugins/dex/list/msg_mini.go | 19 +++-- plugins/dex/list/msg_mini_test.go | 3 + plugins/dex/order/keeper.go | 4 - plugins/dex/store/mapper.go | 4 +- plugins/dex/store/utils.go | 11 +-- plugins/tokens/burn/handler.go | 6 +- plugins/tokens/burn/msg.go | 2 +- plugins/tokens/client/cli/helper.go | 2 +- plugins/tokens/client/cli/issue.go | 4 +- plugins/tokens/client/cli/issue_mini.go | 2 +- plugins/tokens/client/cli/issue_tiny.go | 2 +- plugins/tokens/client/cli/seturi_mini.go | 2 +- plugins/tokens/freeze/handler.go | 14 ++- plugins/tokens/freeze/msg.go | 7 +- plugins/tokens/issue/handler.go | 35 +++----- plugins/tokens/issue/handler_mini.go | 27 +++++- plugins/tokens/issue/msg.go | 32 +++---- plugins/tokens/issue/msg_mini.go | 9 +- plugins/tokens/issue/msg_tiny.go | 19 +++-- plugins/tokens/seturi/msg.go | 2 +- plugins/tokens/store/mapper.go | 37 +++++--- plugins/tokens/store/mapper_mini.go | 4 +- plugins/tokens/swap/handler.go | 15 ---- plugins/tokens/swap/msg.go | 15 ++++ plugins/tokens/timelock/handler.go | 10 --- plugins/tokens/timelock/msgs.go | 14 +++ 34 files changed, 251 insertions(+), 222 deletions(-) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 9f419ddb8..8449257af 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "errors" "fmt" "regexp" @@ -57,29 +58,74 @@ var SupplyRange = struct { }{TinyRangeType, MiniRangeType} type MiniToken struct { - Token - TokenType SupplyRangeType `json:"token_type"` - TokenURI string `json:"token_uri"` //TODO set max length + Name string `json:"name"` + Symbol string `json:"symbol"` + OrigSymbol string `json:"original_symbol"` + TotalSupply utils.Fixed8 `json:"total_supply"` + Owner sdk.AccAddress `json:"owner"` + Mintable bool `json:"mintable"` + TokenType SupplyRangeType `json:"token_type"` + TokenURI string `json:"token_uri"` //TODO set max length } var _ IToken = &MiniToken{} -func NewMiniToken(name, origSymbol, symbol string, supplyRangeType SupplyRangeType, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) (*MiniToken) { +func NewMiniToken(name, origSymbol, symbol string, supplyRangeType SupplyRangeType, totalSupply int64, owner sdk.AccAddress, mintable bool, tokenURI string) *MiniToken { return &MiniToken{ - Token: Token{Name: name, - Symbol: symbol, - OrigSymbol: origSymbol, - TotalSupply: utils.Fixed8(totalSupply), - Owner: owner, - Mintable: mintable, - }, - TokenType: supplyRangeType, - TokenURI: tokenURI, + Name: name, + Symbol: symbol, + OrigSymbol: origSymbol, + TotalSupply: utils.Fixed8(totalSupply), + Owner: owner, + Mintable: mintable, + TokenType: supplyRangeType, + TokenURI: tokenURI, } } +func (token MiniToken) GetName() string { + return token.Name +} + +func (token MiniToken) GetSymbol() string { + return token.Symbol +} + +func (token MiniToken) GetOrigSymbol() string { + return token.OrigSymbol +} + +func (token MiniToken) GetTotalSupply() utils.Fixed8 { + return token.TotalSupply +} + +func (token *MiniToken) SetTotalSupply(totalSupply utils.Fixed8) { + token.TotalSupply = totalSupply +} + +func (token MiniToken) GetOwner() sdk.AccAddress { + return token.Owner +} + +func (token MiniToken) IsMintable() bool { + return token.Mintable +} + +func (token *MiniToken) IsOwner(addr sdk.AccAddress) bool { + return bytes.Equal(token.Owner, addr) +} + +func (token MiniToken) String() string { + return fmt.Sprintf("{Name: %v, Symbol: %v, TokenType: %v, TotalSupply: %v, Owner: %X, Mintable: %v, TokenURI: %v}", + token.Name, token.Symbol, token.TokenType, token.TotalSupply, token.Owner, token.Mintable, token.TokenURI) +} + //check if it's mini token by last letter without validation func IsMiniTokenSymbol(symbol string) bool { + if symbol == NativeTokenSymbol || + symbol == NativeTokenSymbolDotBSuffixed { + return false + } parts, err := splitSuffixedMiniTokenSymbol(symbol) if err != nil { return false @@ -91,35 +137,23 @@ func IsMiniTokenSymbol(symbol string) bool { //Validate and check if it's mini token func IsValidMiniTokenSymbol(symbol string) bool { - if err := ValidateMapperMiniTokenSymbol(symbol); err != nil { + if err := ValidateMiniTokenSymbol(symbol); err != nil { return false } return true } -//func (token *MiniToken) IsOwner(addr sdk.AccAddress) bool { return bytes.Equal(token.Owner, addr) } -func (token MiniToken) String() string { - return fmt.Sprintf("{Name: %v, Symbol: %v, TokenType: %v, TotalSupply: %v, Owner: %X, Mintable: %v, TokenURI: %v}", - token.Name, token.Symbol, token.TokenType, token.TotalSupply, token.Owner, token.Mintable, token.TokenURI) -} - -// Token Validation - -func ValidateMiniToken(token IToken) error { - if err := ValidateMapperMiniTokenSymbol(token.GetSymbol()); err != nil { - return err - } - if err := ValidateIssueMsgMiniTokenSymbol(token.GetOrigSymbol()); err != nil { - return err - } - return nil -} - -func ValidateIssueMsgMiniTokenSymbol(symbol string) error { +func ValidateIssueMiniSymbol(symbol string) error { if len(symbol) == 0 { return errors.New("token symbol cannot be empty") } + // since the native token was given a suffix exception above, do not allow it to have a suffix + if symbol == NativeTokenSymbol || + symbol == NativeTokenSymbolDotBSuffixed { + return errors.New("symbol cannot be the same as native token") + } + // check len without suffix if symbolLen := len(symbol); symbolLen > MiniTokenSymbolMaxLen || symbolLen < MiniTokenSymbolMinLen { return errors.New("length of token symbol is limited to 3~8") @@ -132,7 +166,7 @@ func ValidateIssueMsgMiniTokenSymbol(symbol string) error { return nil } -func ValidateMapperMiniTokenSymbol(symbol string) error { +func ValidateMiniTokenSymbol(symbol string) error { if len(symbol) == 0 { return errors.New("suffixed token symbol cannot be empty") } @@ -143,7 +177,6 @@ func ValidateMapperMiniTokenSymbol(symbol string) error { } symbolPart := parts[0] - // check len without suffix if len(symbolPart) < MiniTokenSymbolMinLen { return fmt.Errorf("mini-token symbol part is too short, got %d chars", len(symbolPart)) @@ -157,7 +190,6 @@ func ValidateMapperMiniTokenSymbol(symbol string) error { } suffixPart := parts[1] - if len(suffixPart) != MiniTokenSymbolSuffixLen { return fmt.Errorf("mini-token symbol suffix must be %d chars in length, got %d", MiniTokenSymbolSuffixLen, len(suffixPart)) } diff --git a/common/types/token.go b/common/types/token.go index cffeb1c5d..a3c1ae974 100644 --- a/common/types/token.go +++ b/common/types/token.go @@ -79,7 +79,7 @@ func (token Token) IsMintable() bool { func NewToken(name, symbol string, totalSupply int64, owner sdk.AccAddress, mintable bool) (*Token, error) { // double check that the symbol is suffixed - if err := ValidateMapperTokenSymbol(symbol); err != nil { + if err := ValidateTokenSymbol(symbol); err != nil { return nil, err } parts, err := splitSuffixedTokenSymbol(symbol) @@ -102,19 +102,7 @@ func (token Token) String() string { token.Name, token.Symbol, token.TotalSupply, token.Owner, token.Mintable) } -// Token Validation - -func ValidateToken(token IToken) error { - if err := ValidateMapperTokenSymbol(token.GetSymbol()); err != nil { - return err - } - if err := ValidateIssueMsgTokenSymbol(token.GetOrigSymbol()); err != nil { - return err - } - return nil -} - -func ValidateIssueMsgTokenSymbol(symbol string) error { +func ValidateIssueSymbol(symbol string) error { if len(symbol) == 0 { return errors.New("token symbol cannot be empty") } @@ -135,9 +123,9 @@ func ValidateIssueMsgTokenSymbol(symbol string) error { return nil } -func ValidateMapperTokenCoins(coins sdk.Coins) error { +func ValidateTokenSymbols(coins sdk.Coins) error { for _, coin := range coins { - err := ValidateMapperTokenSymbol(coin.Denom) + err := ValidateTokenSymbol(coin.Denom) if err != nil { return err } @@ -145,7 +133,7 @@ func ValidateMapperTokenCoins(coins sdk.Coins) error { return nil } -func ValidateMapperTokenSymbol(symbol string) error { +func ValidateTokenSymbol(symbol string) error { if len(symbol) == 0 { return errors.New("suffixed token symbol cannot be empty") } diff --git a/common/types/token_test.go b/common/types/token_test.go index b5fb83353..d1136776a 100644 --- a/common/types/token_test.go +++ b/common/types/token_test.go @@ -3,9 +3,8 @@ package types_test import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/binance-chain/node/common/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) var issueMsgSymbolTestCases = []struct { @@ -79,30 +78,30 @@ func TestNewToken(t *testing.T) { } } -func TestValidateIssueMsgTokenSymbol(t *testing.T) { +func TestValidateIssueSymbol(t *testing.T) { for _, tt := range issueMsgSymbolTestCases { t.Run(tt.symbol, func(t *testing.T) { - if err := types.ValidateIssueMsgTokenSymbol(tt.symbol); (err == nil) != tt.correct { - t.Errorf("ValidateIssueMsgTokenSymbol() error = %v, correct %v", err, tt.correct) + if err := types.ValidateIssueSymbol(tt.symbol); (err == nil) != tt.correct { + t.Errorf("ValidateIssueSymbol() error = %v, correct %v", err, tt.correct) } }) } - // extra test. an issued symbol that is valid in NewToken and ValidateMapperTokenSymbol but not here - if err := types.ValidateIssueMsgTokenSymbol("XYZ-000"); err == nil { - t.Errorf("ValidateIssueMsgTokenSymbol() error = %v, expected XYZ-000 to be invalid", err) + // extra test. an issued symbol that is valid in NewToken and ValidateTokenSymbol but not here + if err := types.ValidateIssueSymbol("XYZ-000"); err == nil { + t.Errorf("ValidateIssueSymbol() error = %v, expected XYZ-000 to be invalid", err) } } -func TestValidateMapperTokenSymbol(t *testing.T) { +func TestValidateTokenSymbol(t *testing.T) { for _, tt := range tokenMapperSymbolTestCases { t.Run(tt.symbol, func(t *testing.T) { - if err := types.ValidateMapperTokenSymbol(tt.symbol); (err == nil) != tt.correct { - t.Errorf("ValidateMapperTokenSymbol() error = %v, correct %v", err, tt.correct) + if err := types.ValidateTokenSymbol(tt.symbol); (err == nil) != tt.correct { + t.Errorf("ValidateTokenSymbol() error = %v, correct %v", err, tt.correct) } }) } - // extra test. an issued symbol that is valid in ValidateIssueMsgTokenSymbol but not here - if err := types.ValidateMapperTokenSymbol("XYZ"); err == nil { - t.Errorf("ValidateIssueMsgTokenSymbol() error = %v, expected XYZ to be invalid", err) + // extra test. an issued symbol that is valid in ValidateIssueSymbol but not here + if err := types.ValidateTokenSymbol("XYZ"); err == nil { + t.Errorf("ValidateIssueSymbol() error = %v, expected XYZ to be invalid", err) } } diff --git a/plugins/dex/client/cli/list.go b/plugins/dex/client/cli/list.go index 49fc647e8..d1a254f1d 100644 --- a/plugins/dex/client/cli/list.go +++ b/plugins/dex/client/cli/list.go @@ -32,13 +32,13 @@ func listTradingPairCmd(cdc *wire.Codec) *cobra.Command { } baseAsset := viper.GetString(flagBaseAsset) - err = types.ValidateMapperTokenSymbol(baseAsset) + err = types.ValidateTokenSymbol(baseAsset) if err != nil { return err } quoteAsset := viper.GetString(flagQuoteAsset) - err = types.ValidateMapperTokenSymbol(quoteAsset) + err = types.ValidateTokenSymbol(quoteAsset) if err != nil { return err } @@ -88,7 +88,7 @@ func listMiniTradingPairCmd(cdc *wire.Codec) *cobra.Command { } baseAsset := viper.GetString(flagBaseAsset) - err = types.ValidateMapperMiniTokenSymbol(baseAsset) + err = types.ValidateMiniTokenSymbol(baseAsset) if err != nil { return err } diff --git a/plugins/dex/list/handler.go b/plugins/dex/list/handler.go index a8118ff4b..7aced6b44 100644 --- a/plugins/dex/list/handler.go +++ b/plugins/dex/list/handler.go @@ -105,12 +105,12 @@ func handleList(ctx sdk.Context, keeper *order.DexKeeper, tokenMapper tokens.Map return sdk.ErrUnauthorized("only the owner of the token can list the token").Result() } - if !tokenMapper.Exists(ctx, msg.QuoteAssetSymbol) { + if !tokenMapper.ExistsBEP2(ctx, msg.QuoteAssetSymbol) { return sdk.ErrInvalidCoins("quote token does not exist").Result() } } - if !tokenMapper.Exists(ctx, msg.QuoteAssetSymbol) { + if !tokenMapper.ExistsBEP2(ctx, msg.QuoteAssetSymbol) { return sdk.ErrInvalidCoins("quote token does not exist").Result() } diff --git a/plugins/dex/list/handler_mini.go b/plugins/dex/list/handler_mini.go index fc8cb46be..317cf6063 100644 --- a/plugins/dex/list/handler_mini.go +++ b/plugins/dex/list/handler_mini.go @@ -30,7 +30,6 @@ func handleListMini(ctx sdk.Context, dexKeeper *order.DexKeeper, tokenMapper tok } lotSize := dexKeeper.DetermineLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice) - pair := types.NewTradingPairWithLotSize(msg.BaseAssetSymbol, msg.QuoteAssetSymbol, msg.InitPrice, lotSize) err = dexKeeper.PairMapper.AddTradingPair(ctx, pair) if err != nil { diff --git a/plugins/dex/list/hooks.go b/plugins/dex/list/hooks.go index 180d60fb8..bce51f7f7 100644 --- a/plugins/dex/list/hooks.go +++ b/plugins/dex/list/hooks.go @@ -58,11 +58,11 @@ func (hooks ListHooks) OnProposalSubmitted(ctx sdk.Context, proposal gov.Proposa return errors.New("expire time should after now") } - if !hooks.tokenMapper.Exists(ctx, listParams.BaseAssetSymbol) { + if !hooks.tokenMapper.ExistsBEP2(ctx, listParams.BaseAssetSymbol) { return errors.New("base token does not exist") } - if !hooks.tokenMapper.Exists(ctx, listParams.QuoteAssetSymbol) { + if !hooks.tokenMapper.ExistsBEP2(ctx, listParams.QuoteAssetSymbol) { return errors.New("quote token does not exist") } diff --git a/plugins/dex/list/msg.go b/plugins/dex/list/msg.go index 286687846..9845366c7 100644 --- a/plugins/dex/list/msg.go +++ b/plugins/dex/list/msg.go @@ -40,11 +40,11 @@ func (msg ListMsg) ValidateBasic() sdk.Error { if msg.ProposalId <= 0 { return sdk.ErrInvalidCoins("proposal id should be positive") } - err := types.ValidateMapperTokenSymbol(msg.BaseAssetSymbol) + err := types.ValidateTokenSymbol(msg.BaseAssetSymbol) if err != nil { return sdk.ErrInvalidCoins("base token: " + err.Error()) } - err = types.ValidateMapperTokenSymbol(msg.QuoteAssetSymbol) + err = types.ValidateTokenSymbol(msg.QuoteAssetSymbol) if err != nil { return sdk.ErrInvalidCoins("quote token: " + err.Error()) } diff --git a/plugins/dex/list/msg_mini.go b/plugins/dex/list/msg_mini.go index c940dc0bd..b619c7a54 100644 --- a/plugins/dex/list/msg_mini.go +++ b/plugins/dex/list/msg_mini.go @@ -4,10 +4,11 @@ import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/plugins/dex/order" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/dex/order" ) const MiniMsg = "dexListMini" @@ -36,17 +37,25 @@ func (msg ListMiniMsg) String() string { return fmt.Sprintf("MsgLi func (msg ListMiniMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } func (msg ListMiniMsg) ValidateBasic() sdk.Error { - - err := types.ValidateMapperMiniTokenSymbol(msg.BaseAssetSymbol) + err := types.ValidateMiniTokenSymbol(msg.BaseAssetSymbol) if err != nil { return sdk.ErrInvalidCoins("base token: " + err.Error()) } if len(msg.QuoteAssetSymbol) == 0 { return sdk.ErrInvalidCoins("quote token is empty ") } - if types.NativeTokenSymbol != msg.QuoteAssetSymbol && order.BUSDSymbol != msg.QuoteAssetSymbol { - return sdk.ErrInvalidCoins("quote token is not valid ") + + // before BEP70 upgraded, we only support listing mini token against NativeToken + if sdk.IsUpgrade(upgrade.BEP70) { + if types.NativeTokenSymbol != msg.QuoteAssetSymbol && order.BUSDSymbol != msg.QuoteAssetSymbol { + return sdk.ErrInvalidCoins("quote token is not valid ") + } + } else { + if types.NativeTokenSymbol != msg.QuoteAssetSymbol { + return sdk.ErrInvalidCoins("quote token is not valid ") + } } + if msg.InitPrice <= 0 { return sdk.ErrInvalidCoins("price should be positive") } diff --git a/plugins/dex/list/msg_mini_test.go b/plugins/dex/list/msg_mini_test.go index 351406b70..d2989367e 100644 --- a/plugins/dex/list/msg_mini_test.go +++ b/plugins/dex/list/msg_mini_test.go @@ -57,8 +57,11 @@ func TestMiniBUSDQuote(t *testing.T) { require.NotNil(t, err, "msg should be error") require.Contains(t, err.Error(), "quote token is not valid") + setChainVersion() + defer resetChainVersion() order.BUSDSymbol = "BUSD-000" msg = NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BUSD-000", 1000) err = msg.ValidateBasic() require.Nil(t, err, "msg should not be error") + } diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index ccf4004e5..70ce36b9c 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -1017,10 +1017,6 @@ func (kp *DexKeeper) CanListTradingPair(ctx sdk.Context, baseAsset, quoteAsset s } } - if types.NativeTokenSymbol != quoteAsset && isMiniSymbolPair(baseAsset, quoteAsset) { - return errors.New("quote token is not valid for mini symbol pair: " + quoteAsset) - } - return nil } diff --git a/plugins/dex/store/mapper.go b/plugins/dex/store/mapper.go index 0db474fc0..5919f0a4a 100644 --- a/plugins/dex/store/mapper.go +++ b/plugins/dex/store/mapper.go @@ -46,12 +46,12 @@ func (m mapper) AddTradingPair(ctx sdk.Context, pair types.TradingPair) error { baseAsset := pair.BaseAssetSymbol quoteAsset := pair.QuoteAssetSymbol if !cmn.IsValidMiniTokenSymbol(baseAsset) { - if err := cmn.ValidateMapperTokenSymbol(baseAsset); err != nil { + if err := cmn.ValidateTokenSymbol(baseAsset); err != nil { return err } } if !cmn.IsValidMiniTokenSymbol(quoteAsset) { - if err := cmn.ValidateMapperTokenSymbol(quoteAsset); err != nil { + if err := cmn.ValidateTokenSymbol(quoteAsset); err != nil { return err } } diff --git a/plugins/dex/store/utils.go b/plugins/dex/store/utils.go index 2f1bce529..2e2910351 100644 --- a/plugins/dex/store/utils.go +++ b/plugins/dex/store/utils.go @@ -12,14 +12,7 @@ func ValidatePairSymbol(symbol string) error { if len(symbol) == 0 { return errors.New("symbol pair must not be empty") } - // TokenSymbolMaxLen: BTC00000 - // TokenSymbolTxHashSuffixLen: 000 - // + 2: ".B" - // * 2: BTC00000.B, ETH00000.B - // + 3: 2x `-` and 1x `_` - if len(symbol) > ((types.TokenSymbolMaxLen+types.TokenSymbolTxHashSuffixLen+2)*2)+3 { - return errors.New("symbol pair is too long") - } + tokenSymbols := strings.SplitN(strings.ToUpper(symbol), "_", 2) if len(tokenSymbols) != 2 { return errors.New("invalid symbol: trading pair must contain an underscore ('_')") @@ -28,7 +21,7 @@ func ValidatePairSymbol(symbol string) error { if types.IsValidMiniTokenSymbol(tokenSymbol) { continue } - if err := types.ValidateMapperTokenSymbol(tokenSymbol); err != nil { + if err := types.ValidateTokenSymbol(tokenSymbol); err != nil { return err } } diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 4f364c901..35033ab21 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -40,15 +40,15 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep } coins := keeper.GetCoins(ctx, token.GetOwner()) - if coins.AmountOf(symbol) < burnAmount || + balance := coins.AmountOf(symbol) + if balance < burnAmount || token.GetTotalSupply().ToInt64() < burnAmount { logger.Info("burn token failed", "reason", "no enough tokens to burn") return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() } if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { - useAllBalance := coins.AmountOf(symbol) == burnAmount - if burnAmount <= 0 || (!useAllBalance && (burnAmount < common.MiniTokenMinExecutionAmount)) { + if burnAmount < common.MiniTokenMinExecutionAmount && balance != burnAmount { logger.Info("burn token failed", "reason", "burn amount doesn't reach the min amount") return sdk.ErrInvalidCoins(fmt.Sprintf("burn amount is too small, the min amount is %d or total free balance", common.MiniTokenMinExecutionAmount)).Result() diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index 24aa779a8..fce23520b 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -45,7 +45,7 @@ func (msg BurnMsg) ValidateBasic() sdk.Error { return msg.validateMiniTokenBasic() } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") - err := types.ValidateMapperTokenSymbol(msg.Symbol) + err := types.ValidateTokenSymbol(msg.Symbol) if err != nil { return sdk.ErrInvalidCoins(err.Error()) } diff --git a/plugins/tokens/client/cli/helper.go b/plugins/tokens/client/cli/helper.go index 0de87bac8..07fd494f3 100644 --- a/plugins/tokens/client/cli/helper.go +++ b/plugins/tokens/client/cli/helper.go @@ -34,7 +34,7 @@ func (c Commander) checkAndSendTx(cmd *cobra.Command, args []string, builder msg symbol := viper.GetString(flagSymbol) if !types.IsValidMiniTokenSymbol(symbol) { - err = types.ValidateMapperTokenSymbol(symbol) + err = types.ValidateTokenSymbol(symbol) if err != nil { return err } diff --git a/plugins/tokens/client/cli/issue.go b/plugins/tokens/client/cli/issue.go index 58a5647d8..222e51a8b 100644 --- a/plugins/tokens/client/cli/issue.go +++ b/plugins/tokens/client/cli/issue.go @@ -59,7 +59,7 @@ func (c Commander) issueToken(cmd *cobra.Command, args []string) error { } symbol := viper.GetString(flagSymbol) - err = types.ValidateIssueMsgTokenSymbol(symbol) + err = types.ValidateIssueSymbol(symbol) if err != nil { return err } @@ -93,7 +93,7 @@ func (c Commander) mintToken(cmd *cobra.Command, args []string) error { return err } } else { - err = types.ValidateMapperTokenSymbol(symbol) + err = types.ValidateTokenSymbol(symbol) if err != nil { return err } diff --git a/plugins/tokens/client/cli/issue_mini.go b/plugins/tokens/client/cli/issue_mini.go index a3a47e248..80190062c 100644 --- a/plugins/tokens/client/cli/issue_mini.go +++ b/plugins/tokens/client/cli/issue_mini.go @@ -45,7 +45,7 @@ func (c Commander) issueMiniToken(cmd *cobra.Command, args []string) error { } symbol := viper.GetString(flagSymbol) - err = types.ValidateIssueMsgMiniTokenSymbol(symbol) + err = types.ValidateIssueMiniSymbol(symbol) if err != nil { return err } diff --git a/plugins/tokens/client/cli/issue_tiny.go b/plugins/tokens/client/cli/issue_tiny.go index 294d60f44..b0fb3a9e5 100644 --- a/plugins/tokens/client/cli/issue_tiny.go +++ b/plugins/tokens/client/cli/issue_tiny.go @@ -39,7 +39,7 @@ func (c Commander) issueTinyToken(cmd *cobra.Command, args []string) error { } symbol := viper.GetString(flagSymbol) - err = types.ValidateIssueMsgMiniTokenSymbol(symbol) + err = types.ValidateIssueMiniSymbol(symbol) if err != nil { return err } diff --git a/plugins/tokens/client/cli/seturi_mini.go b/plugins/tokens/client/cli/seturi_mini.go index 838f5643f..b92bb496c 100644 --- a/plugins/tokens/client/cli/seturi_mini.go +++ b/plugins/tokens/client/cli/seturi_mini.go @@ -28,7 +28,7 @@ func (c Commander) setTokenURI(cmd *cobra.Command, args []string) error { return err } symbol := viper.GetString(flagSymbol) - err = types.ValidateMapperMiniTokenSymbol(symbol) + err = types.ValidateMiniTokenSymbol(symbol) if err != nil { return err } diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 42db63d59..255eb9591 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -35,16 +35,15 @@ func handleFreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper auth symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "token", "symbol", symbol, "amount", freezeAmount, "addr", msg.From) coins := keeper.GetCoins(ctx, msg.From) - if coins.AmountOf(symbol) < freezeAmount { + balance := coins.AmountOf(symbol) + if balance < freezeAmount { logger.Info("freeze token failed", "reason", "no enough free tokens to freeze") return sdk.ErrInsufficientCoins("do not have enough token to freeze").Result() } if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { - useAllBalance := coins.AmountOf(symbol) == freezeAmount - - if msg.Amount <= 0 || (!useAllBalance && (msg.Amount < common.MiniTokenMinExecutionAmount)) { - logger.Info("freeze token failed", "reason", "freeze amount doesn't reach the min supply") + if msg.Amount < common.MiniTokenMinExecutionAmount && balance != freezeAmount { + logger.Info("freeze token failed", "reason", "freeze amount doesn't reach the min amount") return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", common.MiniTokenMinExecutionAmount)).Result() } @@ -78,9 +77,8 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au } if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { - useAllFrozenBalance := frozenAmount == unfreezeAmount - if unfreezeAmount <= 0 || (!useAllFrozenBalance && (unfreezeAmount < common.MiniTokenMinExecutionAmount)) { - logger.Info("unfreeze token failed", "reason", "unfreeze amount doesn't reach the min supply") + if unfreezeAmount < common.MiniTokenMinExecutionAmount && frozenAmount != unfreezeAmount { + logger.Info("unfreeze token failed", "reason", "unfreeze amount doesn't reach the min amount") return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", common.MiniTokenMinExecutionAmount)).Result() } diff --git a/plugins/tokens/freeze/msg.go b/plugins/tokens/freeze/msg.go index a534da456..92d2757d9 100644 --- a/plugins/tokens/freeze/msg.go +++ b/plugins/tokens/freeze/msg.go @@ -46,7 +46,7 @@ func (msg FreezeMsg) ValidateBasic() sdk.Error { return msg.validateMiniTokenBasic() } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") - err := types.ValidateMapperTokenSymbol(msg.Symbol) + err := types.ValidateTokenSymbol(msg.Symbol) if err != nil { return sdk.ErrInvalidCoins(err.Error()) } @@ -94,12 +94,11 @@ func (msg UnfreezeMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetS func (msg UnfreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } func (msg UnfreezeMsg) ValidateBasic() sdk.Error { - if types.IsValidMiniTokenSymbol(msg.Symbol) { return msg.validateMiniTokenBasic() } // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") - err := types.ValidateMapperTokenSymbol(msg.Symbol) + err := types.ValidateTokenSymbol(msg.Symbol) if err != nil { return sdk.ErrInvalidCoins(err.Error()) } @@ -120,7 +119,7 @@ func (msg UnfreezeMsg) GetSignBytes() []byte { func (msg UnfreezeMsg) validateMiniTokenBasic() sdk.Error { // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") - err := types.ValidateMapperMiniTokenSymbol(msg.Symbol) + err := types.ValidateMiniTokenSymbol(msg.Symbol) if err != nil { return sdk.ErrInvalidCoins(err.Error()) } diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 5fbeade5d..72fb14e19 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -28,9 +28,9 @@ func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { case MintMsg: return handleMintToken(ctx, tokenMapper, keeper, msg) case IssueMiniMsg: - return msg.handleIssueMiniToken(ctx, tokenMapper, keeper, common.MiniRangeType) + return handleIssueMiniToken(ctx, tokenMapper, keeper, msg) case IssueTinyMsg: - return msg.handleIssueMiniToken(ctx, tokenMapper, keeper, common.TinyRangeType) + return handleIssueTinyToken(ctx, tokenMapper, keeper, msg) default: errMsg := "Unrecognized msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -50,7 +50,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank // the symbol is suffixed with the first n bytes of the tx hash symbol = fmt.Sprintf("%s-%s", symbol, suffix) - if exists := tokenMapper.Exists(ctx, symbol); exists { + if exists := tokenMapper.ExistsBEP2(ctx, symbol); exists { logger.Info(errLogMsg, "reason", "already exists") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) already exists", msg.Symbol)).Result() } @@ -85,34 +85,27 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can mint token %s", msg.Symbol)).Result() } - // use minus to prevent overflow - if msg.Amount > common.TokenMaxTotalSupply-token.GetTotalSupply().ToInt64() { - logger.Info(errLogMsg, "reason", "exceed the max total supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %ds", - common.TokenMaxTotalSupply)).Result() - } - - if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + if common.IsMiniTokenSymbol(symbol) { miniToken := token.(*types.MiniToken) - if msg.Amount < common.MiniTokenMinExecutionAmount { - logger.Info(errLogMsg, "reason", "mint amount doesn't reach the min supply") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too small, the min amount is %d", - common.MiniTokenMinExecutionAmount)).Result() - } // use minus to prevent overflow if msg.Amount > miniToken.TokenType.UpperBound()-miniToken.TotalSupply.ToInt64() { logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply") return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %d", miniToken.TokenType.UpperBound())).Result() } - - if msg.Amount > common.MiniTokenSupplyUpperBound-miniToken.TotalSupply.ToInt64() { - logger.Info(errLogMsg, "reason", "total supply exceeds the max total supply upper bound") - return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply upper bound is %d", - common.MiniTokenSupplyUpperBound)).Result() + } else { + // use minus to prevent overflow + if msg.Amount > common.TokenMaxTotalSupply-token.GetTotalSupply().ToInt64() { + logger.Info(errLogMsg, "reason", "exceed the max total supply") + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount is too large, the max total supply is %ds", + common.TokenMaxTotalSupply)).Result() } } + + if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + + } newTotalSupply := token.GetTotalSupply().ToInt64() + msg.Amount err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) if err != nil { diff --git a/plugins/tokens/issue/handler_mini.go b/plugins/tokens/issue/handler_mini.go index 1aa85dd83..55b21ec12 100644 --- a/plugins/tokens/issue/handler_mini.go +++ b/plugins/tokens/issue/handler_mini.go @@ -12,7 +12,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/store" ) -func (msg IssueMiniMsg) handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, tokenType common.SupplyRangeType) sdk.Result { +func handleIssueMiniToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg IssueMiniMsg) sdk.Result { errLogMsg := "issue miniToken failed" origSymbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "mini-token", "symbol", origSymbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) @@ -24,11 +24,32 @@ func (msg IssueMiniMsg) handleIssueMiniToken(ctx sdk.Context, tokenMapper store. suffix += common.MiniTokenSymbolMSuffix symbol := fmt.Sprintf("%s-%s", origSymbol, suffix) - if exists := tokenMapper.Exists(ctx, symbol); exists { + if exists := tokenMapper.ExistsMini(ctx, symbol); exists { logger.Info(errLogMsg, "reason", "already exists") return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) already exists", msg.Symbol)).Result() } - token := common.NewMiniToken(msg.Name, origSymbol, symbol, tokenType, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) + token := common.NewMiniToken(msg.Name, origSymbol, symbol, common.MiniRangeType, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) + return issue(ctx, logger, tokenMapper, bankKeeper, token) +} + +func handleIssueTinyToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg IssueTinyMsg) sdk.Result { + errLogMsg := "issue tinyToken failed" + origSymbol := strings.ToUpper(msg.Symbol) + logger := log.With("module", "mini-token", "symbol", origSymbol, "name", msg.Name, "total_supply", msg.TotalSupply, "issuer", msg.From) + + suffix, err := getTokenSuffix(ctx) + if err != nil { + logger.Error(errLogMsg, "reason", err.Error()) + } + suffix += common.MiniTokenSymbolMSuffix + symbol := fmt.Sprintf("%s-%s", origSymbol, suffix) + + if exists := tokenMapper.ExistsMini(ctx, symbol); exists { + logger.Info(errLogMsg, "reason", "already exists") + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) already exists", msg.Symbol)).Result() + } + + token := common.NewMiniToken(msg.Name, origSymbol, symbol, common.TinyRangeType, msg.TotalSupply, msg.From, msg.Mintable, msg.TokenURI) return issue(ctx, logger, tokenMapper, bankKeeper, token) } diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index b4f39816b..1fe9758d2 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" ) // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash @@ -47,7 +47,7 @@ func (msg IssueMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidAddress("sender address cannot be empty") } - if err := types.ValidateIssueMsgTokenSymbol(msg.Symbol); err != nil { + if err := types.ValidateIssueSymbol(msg.Symbol); err != nil { return sdk.ErrInvalidCoins(err.Error()) } @@ -93,16 +93,18 @@ func NewMintMsg(from sdk.AccAddress, symbol string, amount int64) MintMsg { } func (msg MintMsg) ValidateBasic() sdk.Error { - - if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { - return msg.validateMiniTokenBasic() - } - if msg.From == nil { return sdk.ErrInvalidAddress("sender address cannot be empty") } - if err := types.ValidateMapperTokenSymbol(msg.Symbol); err != nil { + if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { + if msg.Amount < types.MiniTokenMinExecutionAmount { + return sdk.ErrInvalidCoins(fmt.Sprintf("mint amount should be no less than %d", types.MiniTokenMinExecutionAmount)) + } + return nil + } + + if err := types.ValidateTokenSymbol(msg.Symbol); err != nil { return sdk.ErrInvalidCoins(err.Error()) } @@ -118,20 +120,6 @@ func (msg MintMsg) ValidateBasic() sdk.Error { return nil } -func (msg MintMsg) validateMiniTokenBasic() sdk.Error { - - if msg.From == nil { - return sdk.ErrInvalidAddress("sender address cannot be empty") - } - - // handler will check: msg.Amount + token.TotalSupply <= types.MaxTotalSupply - if msg.Amount < types.MiniTokenMinExecutionAmount || msg.Amount > types.MiniTokenSupplyUpperBound { - return sdk.ErrInvalidCoins(fmt.Sprintf("Mint amount should be between %d and %d", types.MiniTokenMinExecutionAmount, types.MiniTokenSupplyUpperBound)) - } - - return nil -} - // Implements MintMsg. func (msg MintMsg) Route() string { return Route } func (msg MintMsg) Type() string { return MintMsgType } diff --git a/plugins/tokens/issue/msg_mini.go b/plugins/tokens/issue/msg_mini.go index d109acd7a..ba322b0f6 100644 --- a/plugins/tokens/issue/msg_mini.go +++ b/plugins/tokens/issue/msg_mini.go @@ -44,7 +44,7 @@ func (msg IssueMiniMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidAddress("sender address cannot be empty") } - if err := types.ValidateIssueMsgMiniTokenSymbol(msg.Symbol); err != nil { + if err := types.ValidateIssueMiniSymbol(msg.Symbol); err != nil { return sdk.ErrInvalidCoins(err.Error()) } @@ -64,11 +64,8 @@ func (msg IssueMiniMsg) ValidateBasic() sdk.Error { } // Implements IssueMiniMsg. -func (msg IssueMiniMsg) Route() string { return Route } -func (msg IssueMiniMsg) Type() string { - return IssueMiniMsgType -} - +func (msg IssueMiniMsg) Route() string { return Route } +func (msg IssueMiniMsg) Type() string { return IssueMiniMsgType } func (msg IssueMiniMsg) String() string { return fmt.Sprintf("IssueMiniMsg{%#v}", msg) } func (msg IssueMiniMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } func (msg IssueMiniMsg) GetSignBytes() []byte { diff --git a/plugins/tokens/issue/msg_tiny.go b/plugins/tokens/issue/msg_tiny.go index 32b621c7b..eda4ac925 100644 --- a/plugins/tokens/issue/msg_tiny.go +++ b/plugins/tokens/issue/msg_tiny.go @@ -18,18 +18,22 @@ const ( var _ sdk.Msg = IssueTinyMsg{} type IssueTinyMsg struct { - IssueMiniMsg + From sdk.AccAddress `json:"from"` + Name string `json:"name"` + Symbol string `json:"symbol"` + TotalSupply int64 `json:"total_supply"` + Mintable bool `json:"mintable"` + TokenURI string `json:"token_uri"` } func NewIssueTinyMsg(from sdk.AccAddress, name, symbol string, supply int64, mintable bool, tokenURI string) IssueTinyMsg { - return IssueTinyMsg{IssueMiniMsg{ + return IssueTinyMsg{ From: from, Name: name, Symbol: symbol, TotalSupply: supply, Mintable: mintable, TokenURI: tokenURI, - }, } } @@ -40,7 +44,7 @@ func (msg IssueTinyMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidAddress("sender address cannot be empty") } - if err := types.ValidateIssueMsgMiniTokenSymbol(msg.Symbol); err != nil { + if err := types.ValidateIssueMiniSymbol(msg.Symbol); err != nil { return sdk.ErrInvalidCoins(err.Error()) } @@ -60,11 +64,8 @@ func (msg IssueTinyMsg) ValidateBasic() sdk.Error { } // Implements IssueTinyMsg. -func (msg IssueTinyMsg) Route() string { return Route } -func (msg IssueTinyMsg) Type() string { - return IssueTinyMsgType -} - +func (msg IssueTinyMsg) Route() string { return Route } +func (msg IssueTinyMsg) Type() string { return IssueTinyMsgType } func (msg IssueTinyMsg) String() string { return fmt.Sprintf("IssueTinyMsg{%#v}", msg) } func (msg IssueTinyMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } func (msg IssueTinyMsg) GetSignBytes() []byte { diff --git a/plugins/tokens/seturi/msg.go b/plugins/tokens/seturi/msg.go index 684204c60..c3e161a3d 100644 --- a/plugins/tokens/seturi/msg.go +++ b/plugins/tokens/seturi/msg.go @@ -32,7 +32,7 @@ func (msg SetURIMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidAddress("sender address cannot be empty") } - if err := types.ValidateMapperMiniTokenSymbol(msg.Symbol); err != nil { + if err := types.ValidateMiniTokenSymbol(msg.Symbol); err != nil { return sdk.ErrInvalidCoins(err.Error()) } diff --git a/plugins/tokens/store/mapper.go b/plugins/tokens/store/mapper.go index 079108f6d..932184cb0 100644 --- a/plugins/tokens/store/mapper.go +++ b/plugins/tokens/store/mapper.go @@ -31,7 +31,8 @@ func (t Tokens) GetSymbols() *[]string { type Mapper interface { NewToken(ctx sdk.Context, token types.IToken) error - Exists(ctx sdk.Context, symbol string) bool + ExistsBEP2(ctx sdk.Context, symbol string) bool + ExistsMini(ctx sdk.Context, symbol string) bool ExistsCC(ctx context.CLIContext, symbol string) bool GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool, isMini bool) ITokens GetToken(ctx sdk.Context, symbol string) (types.IToken, error) @@ -65,7 +66,7 @@ func (m mapper) GetToken(ctx sdk.Context, symbol string) (types.IToken, error) { bz := store.Get(key) if bz != nil { - return m.decodeIToken(bz), nil + return m.decodeToken(bz), nil } return nil, fmt.Errorf("token(%v) not found", symbol) @@ -81,7 +82,7 @@ func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool, isMini if !isValid { continue } - token := m.decodeIToken(iter.Value()) + token := m.decodeToken(iter.Value()) if !showZeroSupplyTokens && token.GetTotalSupply().ToInt64() == 0 { continue } @@ -90,10 +91,18 @@ func (m mapper) GetTokenList(ctx sdk.Context, showZeroSupplyTokens bool, isMini return res } -func (m mapper) Exists(ctx sdk.Context, symbol string) bool { +func (m mapper) ExistsBEP2(ctx sdk.Context, symbol string) bool { + return m.exists(ctx, symbol, false) +} + +func (m mapper) ExistsMini(ctx sdk.Context, symbol string) bool { + return m.exists(ctx, symbol, true) +} + +func (m mapper) exists(ctx sdk.Context, symbol string, isMini bool) bool { store := ctx.KVStore(m.key) var key []byte - if types.IsMiniTokenSymbol(symbol) { + if isMini { key = m.calcMiniTokenKey(strings.ToUpper(symbol)) } else { key = []byte(strings.ToUpper(symbol)) @@ -122,19 +131,19 @@ func (m mapper) NewToken(ctx sdk.Context, token types.IToken) error { symbol := token.GetSymbol() var key []byte if types.IsMiniTokenSymbol(symbol) { - if err := types.ValidateMiniToken(token); err != nil { - return err - } key = m.calcMiniTokenKey(strings.ToUpper(symbol)) } else { - if err := types.ValidateToken(token); err != nil { + if err := types.ValidateTokenSymbol(token.GetSymbol()); err != nil { + return err + } + if err := types.ValidateIssueSymbol(token.GetOrigSymbol()); err != nil { return err } key = []byte(strings.ToUpper(symbol)) } store := ctx.KVStore(m.key) - value := m.encodeIToken(token) + value := m.encodeToken(token) store.Set(key, value) return nil } @@ -155,16 +164,16 @@ func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) return errors.New("token does not exist") } - toBeUpdated := m.decodeIToken(bz) + toBeUpdated := m.decodeToken(bz) if toBeUpdated.GetTotalSupply().ToInt64() != supply { toBeUpdated.SetTotalSupply(utils.Fixed8(supply)) - store.Set(key, m.encodeIToken(toBeUpdated)) + store.Set(key, m.encodeToken(toBeUpdated)) } return nil } -func (m mapper) encodeIToken(token types.IToken) []byte { +func (m mapper) encodeToken(token types.IToken) []byte { bz, err := m.cdc.MarshalBinaryBare(token) if err != nil { panic(err) @@ -172,7 +181,7 @@ func (m mapper) encodeIToken(token types.IToken) []byte { return bz } -func (m mapper) decodeIToken(bz []byte) types.IToken { +func (m mapper) decodeToken(bz []byte) types.IToken { var token types.IToken err := m.cdc.UnmarshalBinaryBare(bz, &token) if err != nil { diff --git a/plugins/tokens/store/mapper_mini.go b/plugins/tokens/store/mapper_mini.go index 9ac1e8735..58a6dfe93 100644 --- a/plugins/tokens/store/mapper_mini.go +++ b/plugins/tokens/store/mapper_mini.go @@ -30,7 +30,7 @@ func (m mapper) UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) e return errors.New("token does not exist") } - decodedToken := m.decodeIToken(bz) + decodedToken := m.decodeToken(bz) toBeUpdated, ok := decodedToken.(*types.MiniToken) if !ok { @@ -39,7 +39,7 @@ func (m mapper) UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) e if toBeUpdated.TokenURI != uri { toBeUpdated.TokenURI = uri - store.Set(key, m.encodeIToken(toBeUpdated)) + store.Set(key, m.encodeToken(toBeUpdated)) } return nil } diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index b6950b564..57562cb73 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -6,9 +6,6 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" ) func NewHandler(kp Keeper) sdk.Handler { @@ -30,12 +27,6 @@ func NewHandler(kp Keeper) sdk.Handler { } func handleHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg HTLTMsg) sdk.Result { - if sdk.IsUpgrade(upgrade.BEP8) { - symbolError := types.ValidateMapperTokenCoins(msg.Amount) - if symbolError != nil { - return sdk.ErrInvalidCoins(symbolError.Error()).Result() - } - } blockTime := ctx.BlockHeader().Time.Unix() if msg.Timestamp < blockTime-ThirtyMinutes || msg.Timestamp > blockTime+FifteenMinutes { return ErrInvalidTimestamp(fmt.Sprintf("Timestamp (%d) can neither be 15 minutes ahead of the current time (%d), nor 30 minutes later", msg.Timestamp, ctx.BlockHeader().Time.Unix())).Result() @@ -70,12 +61,6 @@ func handleHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg HTLTMsg) sdk. } func handleDepositHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg DepositHTLTMsg) sdk.Result { - if sdk.IsUpgrade(upgrade.BEP8) { - symbolError := types.ValidateMapperTokenCoins(msg.Amount) - if symbolError != nil { - return sdk.ErrInvalidCoins(symbolError.Error()).Result() - } - } swap := kp.GetSwap(ctx, msg.SwapID) if swap == nil { return ErrNonExistSwapID(fmt.Sprintf("No matched swap with swapID %v", msg.SwapID)).Result() diff --git a/plugins/tokens/swap/msg.go b/plugins/tokens/swap/msg.go index d1706c96a..fc3ef4b60 100644 --- a/plugins/tokens/swap/msg.go +++ b/plugins/tokens/swap/msg.go @@ -4,6 +4,8 @@ import ( "encoding/json" "fmt" + "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -99,6 +101,13 @@ func (msg HTLTMsg) ValidateBasic() sdk.Error { if msg.HeightSpan < MinimumHeightSpan || msg.HeightSpan > MaximumHeightSpan { return ErrInvalidHeightSpan("The height span should be no less than 360 and no greater than 518400") } + + if sdk.IsUpgrade(upgrade.BEP8) { + symbolError := types.ValidateTokenSymbols(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()) + } + } return nil } @@ -148,6 +157,12 @@ func (msg DepositHTLTMsg) ValidateBasic() sdk.Error { if !msg.Amount.IsPositive() { return sdk.ErrInvalidCoins("The swapped out coins must be positive") } + if sdk.IsUpgrade(upgrade.BEP8) { + symbolError := types.ValidateTokenSymbols(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()) + } + } return nil } diff --git a/plugins/tokens/timelock/handler.go b/plugins/tokens/timelock/handler.go index 2231e318b..5be0fca45 100644 --- a/plugins/tokens/timelock/handler.go +++ b/plugins/tokens/timelock/handler.go @@ -5,8 +5,6 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/common/types" ) func NewHandler(keeper Keeper) sdk.Handler { @@ -26,10 +24,6 @@ func NewHandler(keeper Keeper) sdk.Handler { } func handleTimeLock(ctx sdk.Context, keeper Keeper, msg TimeLockMsg) sdk.Result { - symbolError := types.ValidateMapperTokenCoins(msg.Amount) - if symbolError != nil { - return sdk.ErrInvalidCoins(symbolError.Error()).Result() - } record, err := keeper.TimeLock(ctx, msg.From, msg.Description, msg.Amount, time.Unix(msg.LockTime, 0)) if err != nil { return err.Result() @@ -42,10 +36,6 @@ func handleTimeLock(ctx sdk.Context, keeper Keeper, msg TimeLockMsg) sdk.Result } func handleTimeRelock(ctx sdk.Context, keeper Keeper, msg TimeRelockMsg) sdk.Result { - symbolError := types.ValidateMapperTokenCoins(msg.Amount) - if symbolError != nil { - return sdk.ErrInvalidCoins(symbolError.Error()).Result() - } newRecord := TimeLockRecord{ Description: msg.Description, Amount: msg.Amount, diff --git a/plugins/tokens/timelock/msgs.go b/plugins/tokens/timelock/msgs.go index 46fc46f8f..4152031d1 100644 --- a/plugins/tokens/timelock/msgs.go +++ b/plugins/tokens/timelock/msgs.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/binance-chain/node/common/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -67,6 +68,13 @@ func (msg TimeLockMsg) ValidateBasic() sdk.Error { return sdk.ErrInvalidCoins(msg.Amount.String()) } + if sdk.IsUpgrade(sdk.BEP8) { + symbolError := types.ValidateTokenSymbols(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()) + } + } + return nil } @@ -141,6 +149,12 @@ func (msg TimeRelockMsg) ValidateBasic() sdk.Error { return ErrInvalidRelock(DefaultCodespace, fmt.Sprintf("nothing to update for time lock")) } + if sdk.IsUpgrade(sdk.BEP8) { + symbolError := types.ValidateTokenSymbols(msg.Amount) + if symbolError != nil { + return sdk.ErrInvalidCoins(symbolError.Error()) + } + } return nil } From c64d30a963d487c6e8434e8b67eb50fb7f33060b Mon Sep 17 00:00:00 2001 From: rickyyangz Date: Thu, 28 May 2020 18:50:50 +0800 Subject: [PATCH 84/96] fix msg compatible issue --- common/types/mini_token.go | 24 +++++++--------------- plugins/dex/list/msg_mini.go | 4 ++-- plugins/dex/list/msg_mini_test.go | 2 +- plugins/tokens/burn/msg.go | 13 +++++------- plugins/tokens/freeze/msg.go | 34 ++++++++++--------------------- 5 files changed, 26 insertions(+), 51 deletions(-) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 8449257af..541c7d3be 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -126,7 +126,7 @@ func IsMiniTokenSymbol(symbol string) bool { symbol == NativeTokenSymbolDotBSuffixed { return false } - parts, err := splitSuffixedMiniTokenSymbol(symbol) + parts, err := splitSuffixedTokenSymbol(symbol) if err != nil { return false } @@ -148,7 +148,6 @@ func ValidateIssueMiniSymbol(symbol string) error { return errors.New("token symbol cannot be empty") } - // since the native token was given a suffix exception above, do not allow it to have a suffix if symbol == NativeTokenSymbol || symbol == NativeTokenSymbolDotBSuffixed { return errors.New("symbol cannot be the same as native token") @@ -171,7 +170,12 @@ func ValidateMiniTokenSymbol(symbol string) error { return errors.New("suffixed token symbol cannot be empty") } - parts, err := splitSuffixedMiniTokenSymbol(symbol) + if symbol == NativeTokenSymbol || + symbol == NativeTokenSymbolDotBSuffixed { + return errors.New("symbol cannot be the same as native token") + } + + parts, err := splitSuffixedTokenSymbol(symbol) if err != nil { return err } @@ -209,17 +213,3 @@ func ValidateMiniTokenSymbol(symbol string) error { return nil } - -func splitSuffixedMiniTokenSymbol(suffixed string) ([]string, error) { - split := strings.SplitN(suffixed, "-", 2) - - if len(split) != 2 { - return nil, errors.New("suffixed mini-token symbol must contain a hyphen ('-')") - } - - if strings.Contains(split[1], "-") { - return nil, errors.New("suffixed mini-token symbol must contain just one hyphen ('-')") - } - - return split, nil -} diff --git a/plugins/dex/list/msg_mini.go b/plugins/dex/list/msg_mini.go index b619c7a54..31835900d 100644 --- a/plugins/dex/list/msg_mini.go +++ b/plugins/dex/list/msg_mini.go @@ -4,11 +4,11 @@ import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" - "github.com/binance-chain/node/plugins/dex/order" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" + "github.com/binance-chain/node/plugins/dex/order" ) const MiniMsg = "dexListMini" diff --git a/plugins/dex/list/msg_mini_test.go b/plugins/dex/list/msg_mini_test.go index d2989367e..fcd1c8608 100644 --- a/plugins/dex/list/msg_mini_test.go +++ b/plugins/dex/list/msg_mini_test.go @@ -21,7 +21,7 @@ func TestMiniWrongBaseAssetSymbol(t *testing.T) { msg := NewMiniMsg(sdk.AccAddress{}, "BTC", "BTC-000", 1000) err := msg.ValidateBasic() require.NotNil(t, err, "msg should be error") - require.Contains(t, err.Error(), "base token: suffixed mini-token symbol must contain a hyphen") + require.Contains(t, err.Error(), "base token: suffixed token symbol must contain a hyphen ('-')") } func TestMiniWrongBaseAssetSymbolNotMiniToken(t *testing.T) { diff --git a/plugins/tokens/burn/msg.go b/plugins/tokens/burn/msg.go index fce23520b..884ca6266 100644 --- a/plugins/tokens/burn/msg.go +++ b/plugins/tokens/burn/msg.go @@ -42,8 +42,12 @@ func (msg BurnMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAdd // doesn't require access to any other information. func (msg BurnMsg) ValidateBasic() sdk.Error { if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { - return msg.validateMiniTokenBasic() + if msg.Amount <= 0 { + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil } + // if BEP8 not upgraded, we rely on `ValidateTokenSymbol` rejecting the MiniToken. // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") err := types.ValidateTokenSymbol(msg.Symbol) if err != nil { @@ -63,10 +67,3 @@ func (msg BurnMsg) GetSignBytes() []byte { } return b } - -func (msg BurnMsg) validateMiniTokenBasic() sdk.Error { - if msg.Amount <= 0 { - return sdk.ErrInsufficientFunds("amount should be more than 0") - } - return nil -} diff --git a/plugins/tokens/freeze/msg.go b/plugins/tokens/freeze/msg.go index 92d2757d9..59ee7c7ea 100644 --- a/plugins/tokens/freeze/msg.go +++ b/plugins/tokens/freeze/msg.go @@ -41,10 +41,13 @@ func (msg FreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccA // ValidateBasic does a simple validation check that // doesn't require access to any other information. func (msg FreezeMsg) ValidateBasic() sdk.Error { - if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { - return msg.validateMiniTokenBasic() + if msg.Amount <= 0 { + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil } + // if BEP8 not upgraded, we rely on `ValidateTokenSymbol` rejecting the MiniToken. // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") err := types.ValidateTokenSymbol(msg.Symbol) if err != nil { @@ -65,13 +68,6 @@ func (msg FreezeMsg) GetSignBytes() []byte { return b } -func (msg FreezeMsg) validateMiniTokenBasic() sdk.Error { - if msg.Amount <= 0 { - return sdk.ErrInsufficientFunds("amount should be more than 0") - } - return nil -} - var _ sdk.Msg = UnfreezeMsg{} type UnfreezeMsg struct { @@ -94,9 +90,13 @@ func (msg UnfreezeMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetS func (msg UnfreezeMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } func (msg UnfreezeMsg) ValidateBasic() sdk.Error { - if types.IsValidMiniTokenSymbol(msg.Symbol) { - return msg.validateMiniTokenBasic() + if sdk.IsUpgrade(upgrade.BEP8) && types.IsValidMiniTokenSymbol(msg.Symbol) { + if msg.Amount <= 0 { + return sdk.ErrInsufficientFunds("amount should be more than 0") + } + return nil } + // if BEP8 not upgraded, we rely on `ValidateTokenSymbol` rejecting the MiniToken. // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") err := types.ValidateTokenSymbol(msg.Symbol) if err != nil { @@ -116,15 +116,3 @@ func (msg UnfreezeMsg) GetSignBytes() []byte { } return b } - -func (msg UnfreezeMsg) validateMiniTokenBasic() sdk.Error { - // expect all msgs that reference a token after issue to use the suffixed form (e.g. "BNB-ABC") - err := types.ValidateMiniTokenSymbol(msg.Symbol) - if err != nil { - return sdk.ErrInvalidCoins(err.Error()) - } - if msg.Amount <= 0 { - return sdk.ErrInsufficientFunds("amount should be more than 0") - } - return nil -} From c5d4f752c02363757c09368f0dcbb4d92cae4789 Mon Sep 17 00:00:00 2001 From: rickyyangz Date: Thu, 28 May 2020 19:31:24 +0800 Subject: [PATCH 85/96] format & tidy handler --- common/types/token_test.go | 3 ++- plugins/tokens/burn/handler.go | 3 +-- plugins/tokens/freeze/handler.go | 5 ++--- plugins/tokens/issue/handler.go | 5 ----- plugins/tokens/issue/msg.go | 1 + 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/common/types/token_test.go b/common/types/token_test.go index d1136776a..f92ceaca6 100644 --- a/common/types/token_test.go +++ b/common/types/token_test.go @@ -3,8 +3,9 @@ package types_test import ( "testing" - "github.com/binance-chain/node/common/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" ) var issueMsgSymbolTestCases = []struct { diff --git a/plugins/tokens/burn/handler.go b/plugins/tokens/burn/handler.go index 35033ab21..fe05a1905 100644 --- a/plugins/tokens/burn/handler.go +++ b/plugins/tokens/burn/handler.go @@ -10,7 +10,6 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/tokens/store" ) @@ -47,7 +46,7 @@ func handleBurnToken(ctx sdk.Context, tokenMapper store.Mapper, keeper bank.Keep return sdk.ErrInsufficientCoins("do not have enough token to burn").Result() } - if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + if common.IsMiniTokenSymbol(symbol) { if burnAmount < common.MiniTokenMinExecutionAmount && balance != burnAmount { logger.Info("burn token failed", "reason", "burn amount doesn't reach the min amount") return sdk.ErrInvalidCoins(fmt.Sprintf("burn amount is too small, the min amount is %d or total free balance", diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 255eb9591..05abbbfc4 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -11,7 +11,6 @@ import ( "github.com/binance-chain/node/common/log" common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/tokens/store" ) @@ -41,7 +40,7 @@ func handleFreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper auth return sdk.ErrInsufficientCoins("do not have enough token to freeze").Result() } - if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + if common.IsMiniTokenSymbol(symbol) { if msg.Amount < common.MiniTokenMinExecutionAmount && balance != freezeAmount { logger.Info("freeze token failed", "reason", "freeze amount doesn't reach the min amount") return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total account balance", @@ -76,7 +75,7 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au return sdk.ErrInsufficientCoins("do not have enough token to unfreeze").Result() } - if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { + if common.IsMiniTokenSymbol(symbol) { if unfreezeAmount < common.MiniTokenMinExecutionAmount && frozenAmount != unfreezeAmount { logger.Info("unfreeze token failed", "reason", "unfreeze amount doesn't reach the min amount") return sdk.ErrInvalidCoins(fmt.Sprintf("freeze amount is too small, the min amount is %d or total frozen balance", diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 72fb14e19..450f83b0a 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -7,7 +7,6 @@ import ( "strconv" "strings" - "github.com/binance-chain/node/common/upgrade" "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" @@ -102,10 +101,6 @@ func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank. } } - - if sdk.IsUpgrade(upgrade.BEP8) && common.IsMiniTokenSymbol(symbol) { - - } newTotalSupply := token.GetTotalSupply().ToInt64() + msg.Amount err = tokenMapper.UpdateTotalSupply(ctx, symbol, newTotalSupply) if err != nil { diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index 1fe9758d2..a351131f2 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -104,6 +104,7 @@ func (msg MintMsg) ValidateBasic() sdk.Error { return nil } + // if BEP8 not upgraded, we rely on `ValidateTokenSymbol` rejecting the MiniToken. if err := types.ValidateTokenSymbol(msg.Symbol); err != nil { return sdk.ErrInvalidCoins(err.Error()) } From a2b1ef077c89e5f8bac2165a7972216b851697cc Mon Sep 17 00:00:00 2001 From: rickyyangz Date: Thu, 28 May 2020 19:38:32 +0800 Subject: [PATCH 86/96] format --- plugins/tokens/issue/msg.go | 2 +- plugins/tokens/swap/msg.go | 3 ++- plugins/tokens/timelock/msgs.go | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/tokens/issue/msg.go b/plugins/tokens/issue/msg.go index a351131f2..412cd17f5 100644 --- a/plugins/tokens/issue/msg.go +++ b/plugins/tokens/issue/msg.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/binance-chain/node/common/upgrade" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" ) // TODO: "route expressions can only contain alphanumeric characters", we need to change the cosmos sdk to support slash diff --git a/plugins/tokens/swap/msg.go b/plugins/tokens/swap/msg.go index fc3ef4b60..2fee4581e 100644 --- a/plugins/tokens/swap/msg.go +++ b/plugins/tokens/swap/msg.go @@ -4,9 +4,10 @@ import ( "encoding/json" "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" ) const ( diff --git a/plugins/tokens/timelock/msgs.go b/plugins/tokens/timelock/msgs.go index 4152031d1..5a57e15e8 100644 --- a/plugins/tokens/timelock/msgs.go +++ b/plugins/tokens/timelock/msgs.go @@ -5,8 +5,9 @@ import ( "fmt" "time" - "github.com/binance-chain/node/common/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/types" ) const ( From 79c4ba50b06b37493e06839056a67b07d07fac45 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Fri, 29 May 2020 15:32:32 +0800 Subject: [PATCH 87/96] use sdk's BEP8 --- common/upgrade/upgrade.go | 6 +++--- go.mod | 2 +- go.sum | 4 ++-- plugins/dex/list/handler_mini_test.go | 2 +- plugins/dex/store/utils.go | 2 +- plugins/tokens/issue/handler.go | 3 ++- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/common/upgrade/upgrade.go b/common/upgrade/upgrade.go index d4efa0e8f..41ac806bd 100644 --- a/common/upgrade/upgrade.go +++ b/common/upgrade/upgrade.go @@ -25,9 +25,9 @@ const ( FixZeroBalance = "FixZeroBalance" //Nightingale upgrade - BEP8 = "BEP8" // https://github.com/binance-chain/BEPs/pull/69 Mini token upgrade - BEP67 = "BEP67" // https://github.com/binance-chain/BEPs/pull/67 Expiry time upgrade - BEP70 = "BEP70" // https://github.com/binance-chain/BEPs/pull/70 BUSD Pair Upgrade + BEP8 = sdk.BEP8 // https://github.com/binance-chain/BEPs/pull/69 Mini token upgrade + BEP67 = "BEP67" // https://github.com/binance-chain/BEPs/pull/67 Expiry time upgrade + BEP70 = "BEP70" // https://github.com/binance-chain/BEPs/pull/70 BUSD Pair Upgrade ) func UpgradeBEP10(before func(), after func()) { diff --git a/go.mod b/go.mod index b902b01a8..1416427c6 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200518113745-f65c39d47c64 + github.com/cosmos/cosmos-sdk => github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200529110602-b9a19ff527bf github.com/tendermint/go-amino => github.com/binance-chain/bnc-go-amino v0.14.1-binance.2 github.com/tendermint/iavl => github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3 github.com/tendermint/tendermint => github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 diff --git a/go.sum b/go.sum index 099d6597b..b398a2641 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200518113745-f65c39d47c64 h1:Yj7cjdynPeThZBR7P5zyUaztzU0neuSjDXcBElSKHY0= -github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200518113745-f65c39d47c64/go.mod h1:Qd+w7Vm2WGxOqPquawShZ8KsHtA8PVDnx6XvZobloYg= +github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200529110602-b9a19ff527bf h1:N2+Vm1EaHgMar3wraQxxXh11VMQKYk3iOSwtM7OIAoY= +github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200529110602-b9a19ff527bf/go.mod h1:Qd+w7Vm2WGxOqPquawShZ8KsHtA8PVDnx6XvZobloYg= github.com/binance-chain/bnc-go-amino v0.14.1-binance.2 h1:XcbcfisVItk92UKoGbtNT8nbcfadj3H3ayuM2srAfVs= github.com/binance-chain/bnc-go-amino v0.14.1-binance.2/go.mod h1:yaElUUxWtv/TC/ldGtlKAvS1vKwokxgJ1d97I+6is80= github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 h1:LDGvORYLSwsTEQM0W7yrbdgjrAZxQDe18WUTLNuFOEc= diff --git a/plugins/dex/list/handler_mini_test.go b/plugins/dex/list/handler_mini_test.go index 50d8531f7..a5b7cac48 100644 --- a/plugins/dex/list/handler_mini_test.go +++ b/plugins/dex/list/handler_mini_test.go @@ -43,7 +43,7 @@ func setupForMini(ctx sdk.Context, tokenMapper tokenStore.Mapper, t *testing.T) }) require.Nil(t, err, "new token error") - miniToken := types.NewMiniToken("Bitcoin Mini","BTC", "BTC-000M", types.MiniRangeType, 100000e8, sdk.AccAddress("testacc"), false, "") + miniToken := types.NewMiniToken("Bitcoin Mini", "BTC", "BTC-000M", types.MiniRangeType, 100000e8, sdk.AccAddress("testacc"), false, "") err = tokenMapper.NewToken(ctx, miniToken) require.Nil(t, err, "new token error") diff --git a/plugins/dex/store/utils.go b/plugins/dex/store/utils.go index 2e2910351..3f39a594b 100644 --- a/plugins/dex/store/utils.go +++ b/plugins/dex/store/utils.go @@ -12,7 +12,7 @@ func ValidatePairSymbol(symbol string) error { if len(symbol) == 0 { return errors.New("symbol pair must not be empty") } - + tokenSymbols := strings.SplitN(strings.ToUpper(symbol), "_", 2) if len(tokenSymbols) != 2 { return errors.New("invalid symbol: trading pair must contain an underscore ('_')") diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index 450f83b0a..c784cc6da 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -151,7 +151,8 @@ func issue(ctx sdk.Context, logger tmlog.Logger, tokenMapper store.Mapper, bankK return sdk.Result{ Data: serialized, Log: fmt.Sprintf("Issued %s", token.GetSymbol()), - }} + } +} func getTokenSuffix(ctx sdk.Context) (suffix string, err error) { // TxHashKey is set in BaseApp's runMsgs From d0e008f087a0cf2247d38efee3e76c2958da72a3 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 1 Jun 2020 10:59:38 +0800 Subject: [PATCH 88/96] config default upgrade height --- app/config/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/config/config.go b/app/config/config.go index 1275bd62d..12228fb60 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -398,9 +398,9 @@ func defaultUpgradeConfig() *UpgradeConfig { LotSizeUpgradeHeight: math.MaxInt64, ListingRuleUpgradeHeight: math.MaxInt64, FixZeroBalanceHeight: math.MaxInt64, - BEP8Height: 1, - BEP67Height: 1, - BEP70Height: 1, + BEP8Height: math.MaxInt64, + BEP67Height: math.MaxInt64, + BEP70Height: math.MaxInt64, } } From 1b26233ddd9da14c6e13c07643fc915ce08ea317 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 1 Jun 2020 14:34:45 +0800 Subject: [PATCH 89/96] change mini token max cap to 1000000e8 --- common/types/mini_token.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index 541c7d3be..a2f43d3ca 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -20,7 +20,7 @@ const ( MiniTokenSymbolMSuffix = "M" MiniTokenMinExecutionAmount int64 = 100000000 // 1 with 8 decimal digits - MiniTokenSupplyUpperBound int64 = 10000000000000 // 100k with 8 decimal digits + MiniTokenSupplyUpperBound int64 = 100000000000000 // 100k with 8 decimal digits TinyTokenSupplyUpperBound int64 = 1000000000000 MaxTokenURILength = 2048 From 465f71ecb9abf1fcfcd55dfbca4f5b80a52e74fc Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 1 Jun 2020 17:35:14 +0800 Subject: [PATCH 90/96] fix comment --- common/types/mini_token.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index a2f43d3ca..cec88c938 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -19,9 +19,9 @@ const ( MiniTokenSymbolTxHashSuffixLen = 3 // probably enough. if it collides (unlikely) the issuer can just use another tx. MiniTokenSymbolMSuffix = "M" - MiniTokenMinExecutionAmount int64 = 100000000 // 1 with 8 decimal digits - MiniTokenSupplyUpperBound int64 = 100000000000000 // 100k with 8 decimal digits - TinyTokenSupplyUpperBound int64 = 1000000000000 + MiniTokenMinExecutionAmount int64 = 100000000 // 1 with 8 decimal digits + MiniTokenSupplyUpperBound int64 = 100000000000000 // 1m with 8 decimal digits + TinyTokenSupplyUpperBound int64 = 1000000000000 // 10k with 8 decimal digits MaxTokenURILength = 2048 TinyRangeType SupplyRangeType = 1 From 9c41029f3224883a3114531d42b29a1730a8795a Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 1 Jun 2020 20:49:17 +0800 Subject: [PATCH 91/96] change mini token fee --- go.mod | 4 ++-- go.sum | 8 ++++---- plugins/param/genesis.go | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 1416427c6..4d256f838 100644 --- a/go.mod +++ b/go.mod @@ -29,9 +29,9 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200529110602-b9a19ff527bf + github.com/cosmos/cosmos-sdk => github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.22 github.com/tendermint/go-amino => github.com/binance-chain/bnc-go-amino v0.14.1-binance.2 - github.com/tendermint/iavl => github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3 + github.com/tendermint/iavl => github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.4 github.com/tendermint/tendermint => github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 github.com/zondax/ledger-cosmos-go => github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.3 golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20190823143015-45b1026d81ae diff --git a/go.sum b/go.sum index b398a2641..bfdcf35ae 100644 --- a/go.sum +++ b/go.sum @@ -26,14 +26,14 @@ github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200529110602-b9a19ff527bf h1:N2+Vm1EaHgMar3wraQxxXh11VMQKYk3iOSwtM7OIAoY= -github.com/binance-chain/bnc-cosmos-sdk v0.19.1-0.20200529110602-b9a19ff527bf/go.mod h1:Qd+w7Vm2WGxOqPquawShZ8KsHtA8PVDnx6XvZobloYg= +github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.22 h1:AYJZDs9H3DN/tETOMtRQOpMv2JVxCpxhciSttofQJY0= +github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.22/go.mod h1:lE+RVRYNWqO8xUa/SjiqyDGiII5BtjMSwovI/lcbSuM= github.com/binance-chain/bnc-go-amino v0.14.1-binance.2 h1:XcbcfisVItk92UKoGbtNT8nbcfadj3H3ayuM2srAfVs= github.com/binance-chain/bnc-go-amino v0.14.1-binance.2/go.mod h1:yaElUUxWtv/TC/ldGtlKAvS1vKwokxgJ1d97I+6is80= github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 h1:LDGvORYLSwsTEQM0W7yrbdgjrAZxQDe18WUTLNuFOEc= github.com/binance-chain/bnc-tendermint v0.32.3-binance.1/go.mod h1:kN5dNxE8voFtDqx2HjbM8sBIH5cUuMtLg0XEHjqzUiY= -github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3 h1:OyTJet9aGz+c2WKpTf5cAvJNiQeqVFYP4AV9cPpro2M= -github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3/go.mod h1:Zmh8GRdNJB8DULIOBar3JCZp6tSpcvM1NGKfE9U2EzA= +github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.4 h1:BhaV2iiGWfRC6iB8HHOYJeUDwtQMB2pUA4ah+KCbBhI= +github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.4/go.mod h1:Zmh8GRdNJB8DULIOBar3JCZp6tSpcvM1NGKfE9U2EzA= github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.3 h1:FFpFbkzlP2HUyxQCm0eoU6mkfgMNynfqZRbeWqlaLdQ= github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.3/go.mod h1:TULULYTvPuWBxFIZFy6KjJaxJzbHeUderYNB1YhD6N0= github.com/binance-chain/tss v0.1.2 h1:AyTedSG5HG/WAvM9PDPWjTXQ+dvNdHg3x1c+1a584PQ= diff --git a/plugins/param/genesis.go b/plugins/param/genesis.go index c4a0330ff..27f10ce16 100644 --- a/plugins/param/genesis.go +++ b/plugins/param/genesis.go @@ -54,10 +54,10 @@ const ( IOCExpireFeeNative = 5e3 //MiniToken fee - TinyIssueFee = 10e8 - MiniIssueFee = 20e8 - MiniSetUriFee = 1e8 - MiniListingFee = 100e8 + TinyIssueFee = 2e8 + MiniIssueFee = 4e8 + MiniSetUriFee = 37500 + MiniListingFee = 10e8 ) var DefaultGenesisState = param.GenesisState{ From 919c17b099ad776f9b4baa31502305c65adec670 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Mon, 1 Jun 2020 20:59:31 +0800 Subject: [PATCH 92/96] fix test --- plugins/tokens/issue/handler_mini_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tokens/issue/handler_mini_test.go b/plugins/tokens/issue/handler_mini_test.go index 877c7268d..a1e1f0abd 100644 --- a/plugins/tokens/issue/handler_mini_test.go +++ b/plugins/tokens/issue/handler_mini_test.go @@ -65,7 +65,7 @@ func TestHandleIssueMiniToken(t *testing.T) { require.Contains(t, sdkResult.Log, "symbol(NNB) already exists") ctx = ctx.WithValue(baseapp.TxHashKey, "002") - msgMini := NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 100000e8+100, false, "http://www.xyz.com/nnb.json") + msgMini := NewIssueMiniMsg(acc.GetAddress(), "New BB", "NBB", 1000000e8+100, false, "http://www.xyz.com/nnb.json") sdkResult = msgMini.ValidateBasic().Result() require.Equal(t, false, sdkResult.Code.IsOK()) require.Contains(t, sdkResult.Log, fmt.Sprintf("total supply should be between %d and %d", types.MiniTokenMinExecutionAmount, types.MiniRangeType.UpperBound())) From fe23b1d9d029dbb20f4f310bd996c212bd922f1e Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 2 Jun 2020 11:52:10 +0800 Subject: [PATCH 93/96] refactor --- app/app.go | 2 +- app/pub/helpers.go | 11 ++++++----- app/pub/publisher.go | 4 ++-- common/types/mini_token.go | 11 ++++------- plugins/dex/client/cli/list.go | 2 +- plugins/dex/list/handler_mini_test.go | 4 ++-- plugins/dex/list/handler_test.go | 5 ++--- plugins/dex/list/msg_mini.go | 2 +- plugins/dex/list/msg_mini_test.go | 16 ++++++++-------- plugins/dex/matcheng/engine_new.go | 8 ++++---- plugins/dex/matcheng/match_new_test.go | 14 +++++++------- plugins/dex/order/symbol_selector.go | 5 +---- plugins/tokens/tokens.go | 1 + 13 files changed, 40 insertions(+), 45 deletions(-) diff --git a/app/app.go b/app/app.go index 08a3913ee..d25b5e5f6 100644 --- a/app/app.go +++ b/app/app.go @@ -786,7 +786,7 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublis duration := pub.Timer(app.Logger, fmt.Sprintf("collect publish information, height=%d", height), func() { if app.publicationConfig.PublishAccountBalance { txRelatedAccounts := app.Pool.TxRelatedAddrs() - tradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(app.DexKeeper, tradesToPublish, orderChanges, orderInfoForPublish) + tradeRelatedAccounts := pub.GetTradeAndOrdersRelatedAccounts(tradesToPublish, orderChanges, orderInfoForPublish) accountsToPublish = pub.GetAccountBalances( app.AccountKeeper, ctx, diff --git a/app/pub/helpers.go b/app/pub/helpers.go index 863030f92..c01dc541c 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -8,6 +8,8 @@ import ( "sync" "time" + abci "github.com/tendermint/tendermint/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" @@ -21,11 +23,10 @@ import ( "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" "github.com/binance-chain/node/plugins/tokens/seturi" - abci "github.com/tendermint/tendermint/abci/types" ) -func GetTradeAndOrdersRelatedAccounts(kp *orderPkg.DexKeeper, tradesToPublish []*Trade, orderChanges orderPkg.OrderChanges, orderInfosForPublish orderPkg.OrderInfoForPublish) []string { - res := make([]string, 0, len(tradesToPublish)*2+len(kp.GetAllOrderChanges())) +func GetTradeAndOrdersRelatedAccounts(tradesToPublish []*Trade, orderChanges orderPkg.OrderChanges, orderInfosForPublish orderPkg.OrderInfoForPublish) []string { + res := make([]string, 0, len(tradesToPublish)*2+len(orderChanges)) for _, t := range tradesToPublish { @@ -531,7 +532,7 @@ func collectOrdersToPublish( opensToPublish, closedToPublish = collectOrders(orderChanges, orderInfos, timestamp, chargedCancels, chargedExpires) // update C and E fields in serialized fee string - updateCancelExpireOrderNum(closedToPublish, orderInfos, feeToPublish, chargedCancels, chargedExpires, feeHolder) + updateCancelExpireOrderNumInFees(closedToPublish, orderInfos, feeToPublish, chargedCancels, chargedExpires, feeHolder) // update fee and collect orders from trades opensToPublish, closedToPublish = convertTradesToOrders(trades, orderInfos, timestamp, feeHolder, feeToPublish, opensToPublish, closedToPublish) @@ -566,7 +567,7 @@ func convertTradesToOrders(trades []*Trade, orderInfos orderPkg.OrderInfoForPubl return opensToPublish, closedToPublish } -func updateCancelExpireOrderNum(closedToPublish []*Order, orderInfos orderPkg.OrderInfoForPublish, feeToPublish map[string]string, chargedCancels map[string]int, chargedExpires map[string]int, feeHolder orderPkg.FeeHolder) { +func updateCancelExpireOrderNumInFees(closedToPublish []*Order, orderInfos orderPkg.OrderInfoForPublish, feeToPublish map[string]string, chargedCancels map[string]int, chargedExpires map[string]int, feeHolder orderPkg.FeeHolder) { for _, order := range closedToPublish { if orderInfo, ok := orderInfos[order.OrderId]; ok { senderBytesStr := string(orderInfo.Sender) diff --git a/app/pub/publisher.go b/app/pub/publisher.go index 25b326e54..eb17b44c4 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -172,8 +172,8 @@ func Publish( } func addClosedOrder(closedToPublish []*Order, toRemoveOrderIdCh chan OrderSymbolId) { - for _, o := range closedToPublish { - if toRemoveOrderIdCh != nil { + if toRemoveOrderIdCh != nil { + for _, o := range closedToPublish { Logger.Debug( "going to delete order from order changes map", "orderId", o.OrderId, "status", o.Status) diff --git a/common/types/mini_token.go b/common/types/mini_token.go index cec88c938..0ffba0569 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -19,9 +19,9 @@ const ( MiniTokenSymbolTxHashSuffixLen = 3 // probably enough. if it collides (unlikely) the issuer can just use another tx. MiniTokenSymbolMSuffix = "M" - MiniTokenMinExecutionAmount int64 = 100000000 // 1 with 8 decimal digits - MiniTokenSupplyUpperBound int64 = 100000000000000 // 1m with 8 decimal digits - TinyTokenSupplyUpperBound int64 = 1000000000000 // 10k with 8 decimal digits + MiniTokenMinExecutionAmount int64 = 1e8 // 1 with 8 decimal digits + MiniTokenSupplyUpperBound int64 = 1000000e8 // 1m with 8 decimal digits + TinyTokenSupplyUpperBound int64 = 10000e8 // 10k with 8 decimal digits MaxTokenURILength = 2048 TinyRangeType SupplyRangeType = 1 @@ -137,10 +137,7 @@ func IsMiniTokenSymbol(symbol string) bool { //Validate and check if it's mini token func IsValidMiniTokenSymbol(symbol string) bool { - if err := ValidateMiniTokenSymbol(symbol); err != nil { - return false - } - return true + return ValidateMiniTokenSymbol(symbol) == nil } func ValidateIssueMiniSymbol(symbol string) error { diff --git a/plugins/dex/client/cli/list.go b/plugins/dex/client/cli/list.go index d1a254f1d..9c515a8cd 100644 --- a/plugins/dex/client/cli/list.go +++ b/plugins/dex/client/cli/list.go @@ -107,7 +107,7 @@ func listMiniTradingPairCmd(cdc *wire.Codec) *cobra.Command { return err } - msg := list.NewMiniMsg(from, baseAsset, quoteAsset, initPrice) + msg := list.NewListMiniMsg(from, baseAsset, quoteAsset, initPrice) err = client.SendOrPrintTx(cliCtx, txbldr, msg) if err != nil { return err diff --git a/plugins/dex/list/handler_mini_test.go b/plugins/dex/list/handler_mini_test.go index a5b7cac48..99b83d253 100644 --- a/plugins/dex/list/handler_mini_test.go +++ b/plugins/dex/list/handler_mini_test.go @@ -12,7 +12,7 @@ import ( "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" - tokenStore "github.com/binance-chain/node/plugins/tokens/store" + "github.com/binance-chain/node/plugins/tokens" ) func setChainVersion() { @@ -24,7 +24,7 @@ func resetChainVersion() { upgrade.Mgr.Config.HeightMap = nil } -func setupForMini(ctx sdk.Context, tokenMapper tokenStore.Mapper, t *testing.T) { +func setupForMini(ctx sdk.Context, tokenMapper tokens.Mapper, t *testing.T) { err := tokenMapper.NewToken(ctx, &types.Token{ Name: "Bitcoin", Symbol: "BTC-000", diff --git a/plugins/dex/list/handler_test.go b/plugins/dex/list/handler_test.go index a8e4a2081..aec312a94 100644 --- a/plugins/dex/list/handler_test.go +++ b/plugins/dex/list/handler_test.go @@ -27,7 +27,6 @@ import ( "github.com/binance-chain/node/plugins/dex/store" dexTypes "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/plugins/tokens" - tokenStore "github.com/binance-chain/node/plugins/tokens/store" ) func MakeCodec() *codec.Codec { @@ -42,7 +41,7 @@ func MakeCodec() *codec.Codec { return cdc } -func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, dexKeeper *order.DexKeeper, tokenMapper tokenStore.Mapper, govKeeper gov.Keeper) { +func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, dexKeeper *order.DexKeeper, tokenMapper tokens.Mapper, govKeeper gov.Keeper) { accKey := sdk.NewKVStoreKey("acc") pairKey := sdk.NewKVStoreKey("pair") tokenKey := sdk.NewKVStoreKey("token") @@ -67,7 +66,7 @@ func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, dexKeeper *ord pairMapper := store.NewTradingPairMapper(cdc, pairKey) dexKeeper = order.NewDexKeeper(common.DexStoreKey, accKeeper, pairMapper, codespacer.RegisterNext(dexTypes.DefaultCodespace), 2, cdc, false) - tokenMapper = tokenStore.NewMapper(cdc, tokenKey) + tokenMapper = tokens.NewMapper(cdc, tokenKey) paramsKeeper := params.NewKeeper(cdc, paramKey, paramTKey) bankKeeper := bank.NewBaseKeeper(accKeeper) diff --git a/plugins/dex/list/msg_mini.go b/plugins/dex/list/msg_mini.go index 31835900d..09c0111ba 100644 --- a/plugins/dex/list/msg_mini.go +++ b/plugins/dex/list/msg_mini.go @@ -22,7 +22,7 @@ type ListMiniMsg struct { InitPrice int64 `json:"init_price"` } -func NewMiniMsg(from sdk.AccAddress, baseAssetSymbol string, quoteAssetSymbol string, initPrice int64) ListMiniMsg { +func NewListMiniMsg(from sdk.AccAddress, baseAssetSymbol string, quoteAssetSymbol string, initPrice int64) ListMiniMsg { return ListMiniMsg{ From: from, BaseAssetSymbol: baseAssetSymbol, diff --git a/plugins/dex/list/msg_mini_test.go b/plugins/dex/list/msg_mini_test.go index fcd1c8608..b399247c3 100644 --- a/plugins/dex/list/msg_mini_test.go +++ b/plugins/dex/list/msg_mini_test.go @@ -11,48 +11,48 @@ import ( ) func TestMiniIdenticalBaseAssetAndQuoteAsset(t *testing.T) { - msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BTC-000M", 1000) + msg := NewListMiniMsg(sdk.AccAddress{}, "BTC-000M", "BTC-000M", 1000) err := msg.ValidateBasic() require.NotNil(t, err, "msg should be error") require.Contains(t, err.Error(), "quote token is not valid") } func TestMiniWrongBaseAssetSymbol(t *testing.T) { - msg := NewMiniMsg(sdk.AccAddress{}, "BTC", "BTC-000", 1000) + msg := NewListMiniMsg(sdk.AccAddress{}, "BTC", "BTC-000", 1000) err := msg.ValidateBasic() require.NotNil(t, err, "msg should be error") require.Contains(t, err.Error(), "base token: suffixed token symbol must contain a hyphen ('-')") } func TestMiniWrongBaseAssetSymbolNotMiniToken(t *testing.T) { - msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000", "BTC-000", 1000) + msg := NewListMiniMsg(sdk.AccAddress{}, "BTC-000", "BTC-000", 1000) err := msg.ValidateBasic() require.NotNil(t, err, "msg should be error") require.Contains(t, err.Error(), "base token: mini-token symbol suffix must be 4 chars in length, got 3") } func TestMiniWrongQuoteAssetSymbol(t *testing.T) { - msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "ETH-123", 1000) + msg := NewListMiniMsg(sdk.AccAddress{}, "BTC-000M", "ETH-123", 1000) err := msg.ValidateBasic() require.NotNil(t, err, "msg should be error") require.Contains(t, err.Error(), "quote token is not valid") } func TestMiniWrongInitPrice(t *testing.T) { - msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BNB", -1000) + msg := NewListMiniMsg(sdk.AccAddress{}, "BTC-000M", "BNB", -1000) err := msg.ValidateBasic() require.NotNil(t, err, "msg should be error") require.Contains(t, err.Error(), "price should be positive") } func TestMiniRightMsg(t *testing.T) { - msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BNB", 1000) + msg := NewListMiniMsg(sdk.AccAddress{}, "BTC-000M", "BNB", 1000) err := msg.ValidateBasic() require.Nil(t, err, "msg should not be error") } func TestMiniBUSDQuote(t *testing.T) { - msg := NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BUSD-000", 1000) + msg := NewListMiniMsg(sdk.AccAddress{}, "BTC-000M", "BUSD-000", 1000) err := msg.ValidateBasic() require.NotNil(t, err, "msg should be error") require.Contains(t, err.Error(), "quote token is not valid") @@ -60,7 +60,7 @@ func TestMiniBUSDQuote(t *testing.T) { setChainVersion() defer resetChainVersion() order.BUSDSymbol = "BUSD-000" - msg = NewMiniMsg(sdk.AccAddress{}, "BTC-000M", "BUSD-000", 1000) + msg = NewListMiniMsg(sdk.AccAddress{}, "BTC-000M", "BUSD-000", 1000) err = msg.ValidateBasic() require.Nil(t, err, "msg should not be error") diff --git a/plugins/dex/matcheng/engine_new.go b/plugins/dex/matcheng/engine_new.go index 5d4ec36df..937511a78 100644 --- a/plugins/dex/matcheng/engine_new.go +++ b/plugins/dex/matcheng/engine_new.go @@ -40,7 +40,7 @@ func (me *MatchEng) runMatch(height int64) bool { return false } //If order height > the last Match height, then it's maker. - takerSide, err := me.determineTakerSide(me.LastMatchHeight, index) + takerSide, err := me.determineTakerSide(index) if err != nil { me.logger.Error("determineTakerSide failed", "error", err) return false @@ -134,11 +134,11 @@ func findTakerStartIdx(lastMatchHeight int64, orders []OrderPart) (idx int, make return i, makerTotal } -func (me *MatchEng) determineTakerSide(lastMatchHeight int64, tradePriceIdx int) (int8, error) { +func (me *MatchEng) determineTakerSide(tradePriceIdx int) (int8, error) { makerSide := UNKNOWN for i := 0; i <= tradePriceIdx; i++ { l := &me.overLappedLevel[i] - l.BuyTakerStartIdx, l.BuyMakerTotal = findTakerStartIdx(lastMatchHeight, l.BuyOrders) + l.BuyTakerStartIdx, l.BuyMakerTotal = findTakerStartIdx(me.LastMatchHeight, l.BuyOrders) if l.HasBuyMaker() { makerSide = BUYSIDE } @@ -146,7 +146,7 @@ func (me *MatchEng) determineTakerSide(lastMatchHeight int64, tradePriceIdx int) for i := len(me.overLappedLevel) - 1; i >= tradePriceIdx; i-- { l := &me.overLappedLevel[i] - l.SellTakerStartIdx, l.SellMakerTotal = findTakerStartIdx(lastMatchHeight, l.SellOrders) + l.SellTakerStartIdx, l.SellMakerTotal = findTakerStartIdx(me.LastMatchHeight, l.SellOrders) if l.HasSellMaker() { if makerSide == BUYSIDE { return UNKNOWN, errors.New("both buy side and sell side have maker orders.") diff --git a/plugins/dex/matcheng/match_new_test.go b/plugins/dex/matcheng/match_new_test.go index ced74a2b7..4198fab33 100644 --- a/plugins/dex/matcheng/match_new_test.go +++ b/plugins/dex/matcheng/match_new_test.go @@ -485,8 +485,8 @@ func TestMatchEng_determineTakerSide(t *testing.T) { assert.Equal(sellMakerTotal, l.SellMakerTotal) l.BuyTakerStartIdx, l.BuyMakerTotal, l.SellTakerStartIdx, l.SellMakerTotal = 0, 0, 0, 0 } - - takerSide, err := me.determineTakerSide(99, 0) + me.LastMatchHeight = 99 + takerSide, err := me.determineTakerSide(0) assert.NoError(err) assert.Equal(BUYSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 2, 200) @@ -494,7 +494,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { checkAndClear(&me.overLappedLevel[2], 0, 0, 0, 0) checkAndClear(&me.overLappedLevel[3], 0, 0, 0, 0) - takerSide, err = me.determineTakerSide(99, 1) + takerSide, err = me.determineTakerSide(1) assert.NoError(err) assert.Equal(BUYSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 0, 0) @@ -502,7 +502,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { checkAndClear(&me.overLappedLevel[2], 0, 0, 0, 0) checkAndClear(&me.overLappedLevel[3], 0, 0, 0, 0) - takerSide, err = me.determineTakerSide(99, 2) + takerSide, err = me.determineTakerSide(2) assert.NoError(err) assert.Equal(SELLSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 0, 0) @@ -510,7 +510,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { checkAndClear(&me.overLappedLevel[2], 2, 200, 0, 0) checkAndClear(&me.overLappedLevel[3], 0, 0, 0, 0) - takerSide, err = me.determineTakerSide(99, 3) + takerSide, err = me.determineTakerSide(3) assert.NoError(err) assert.Equal(SELLSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 0, 0) @@ -527,7 +527,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { {"2", 100, 100, 0, 100}, }, }} - takerSide, err = me.determineTakerSide(99, 0) + takerSide, err = me.determineTakerSide(0) assert.NoError(err) assert.Equal(BUYSIDE, takerSide) checkAndClear(&me.overLappedLevel[0], 0, 0, 0, 0) @@ -541,7 +541,7 @@ func TestMatchEng_determineTakerSide(t *testing.T) { {"2", 99, 100, 0, 100}, }, }} - takerSide, err = me.determineTakerSide(99, 0) + takerSide, err = me.determineTakerSide(0) assert.EqualError(err, "both buy side and sell side have maker orders.") assert.Equal(UNKNOWN, takerSide) } diff --git a/plugins/dex/order/symbol_selector.go b/plugins/dex/order/symbol_selector.go index 352cafe90..91ae115de 100644 --- a/plugins/dex/order/symbol_selector.go +++ b/plugins/dex/order/symbol_selector.go @@ -29,10 +29,7 @@ type MiniSymbolSelector struct { roundSelectedSymbols []string //mini token pairs to match in this round } -var _ SymbolSelector = &MiniSymbolSelector{ - make(map[string]uint32), - make([]string, 0), -} +var _ SymbolSelector = &MiniSymbolSelector{} func (mss *MiniSymbolSelector) addSymbolHash(symbol string) { mss.symbolsHash[symbol] = crc32.ChecksumIEEE([]byte(symbol)) diff --git a/plugins/tokens/tokens.go b/plugins/tokens/tokens.go index 29e93afe3..7a9547342 100644 --- a/plugins/tokens/tokens.go +++ b/plugins/tokens/tokens.go @@ -3,3 +3,4 @@ package tokens import "github.com/binance-chain/node/plugins/tokens/store" type Mapper = store.Mapper +var NewMapper = store.NewMapper From ef982cda6855ae1544e0decf3ddba71a8d8d3b57 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 2 Jun 2020 12:06:55 +0800 Subject: [PATCH 94/96] change mini token fee distribution --- plugins/param/plugin.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go index 22be84db8..101973ed3 100644 --- a/plugins/param/plugin.go +++ b/plugins/param/plugin.go @@ -63,10 +63,10 @@ func RegisterUpgradeBeginBlocker(paramHub *ParamHub) { }) upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP8, func(ctx sdk.Context) { miniTokenFeeParams := []param.FeeParam{ - ¶m.FixedFeeParams{MsgType: issue.IssueTinyMsgType, Fee: TinyIssueFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: issue.IssueMiniMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: issue.IssueTinyMsgType, Fee: TinyIssueFee, FeeFor: types.FeeForAll}, + ¶m.FixedFeeParams{MsgType: issue.IssueMiniMsgType, Fee: MiniIssueFee, FeeFor: types.FeeForAll}, ¶m.FixedFeeParams{MsgType: miniURI.SetURIMsg{}.Type(), Fee: MiniSetUriFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: list.ListMiniMsg{}.Type(), Fee: MiniListingFee, FeeFor: types.FeeForProposer}, + ¶m.FixedFeeParams{MsgType: list.ListMiniMsg{}.Type(), Fee: MiniListingFee, FeeFor: types.FeeForAll}, } paramHub.UpdateFeeParams(ctx, miniTokenFeeParams) }) From ebc2fa335b4f055cd7b7d3dd4e210a63eab9ba02 Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 2 Jun 2020 14:23:39 +0800 Subject: [PATCH 95/96] refactor --- app/app.go | 2 +- app/app_pub_test.go | 4 ++-- plugins/dex/abci.go | 9 +++------ plugins/dex/order/handler.go | 7 +++---- plugins/dex/order/keeper.go | 12 ++++++++++++ plugins/dex/plugin.go | 8 +++----- plugins/dex/route.go | 7 ++----- 7 files changed, 26 insertions(+), 23 deletions(-) diff --git a/app/app.go b/app/app.go index d25b5e5f6..d6064e909 100644 --- a/app/app.go +++ b/app/app.go @@ -346,7 +346,7 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { func (app *BinanceChain) initPlugins() { tokens.InitPlugin(app, app.TokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) - dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.AccountKeeper, app.govKeeper) + dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.govKeeper) param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) } diff --git a/app/app_pub_test.go b/app/app_pub_test.go index fc9ecf31b..f4853ff70 100644 --- a/app/app_pub_test.go +++ b/app/app_pub_test.go @@ -140,7 +140,7 @@ func TestAppPub_MatchOrder(t *testing.T) { ctx := app.DeliverState.Ctx msg := orderPkg.NewNewOrderMsg(buyerAcc.GetAddress(), orderPkg.GenerateOrderID(1, buyerAcc.GetAddress()), orderPkg.Side.BUY, "XYZ-000_BNB", 102000, 300000000) - handler := orderPkg.NewHandler(app.GetCodec(), app.DexKeeper) + handler := orderPkg.NewHandler(app.DexKeeper) app.DeliverState.Ctx = app.DeliverState.Ctx.WithBlockHeight(41).WithBlockTime(time.Unix(0, 100)) buyerAcc.SetSequence(1) app.AccountKeeper.SetAccount(ctx, buyerAcc) @@ -214,7 +214,7 @@ func TestAppPub_MatchOrder(t *testing.T) { func TestAppPub_MatchAndCancelFee(t *testing.T) { assert, require, app, buyerAcc, sellerAcc := setupAppTest(t) - handler := orderPkg.NewHandler(app.GetCodec(), app.DexKeeper) + handler := orderPkg.NewHandler(app.DexKeeper) ctx := app.DeliverState.Ctx // ==== Place a to-be-matched sell order and a to-be-cancelled buy order (in different symbol) diff --git a/plugins/dex/abci.go b/plugins/dex/abci.go index bfefcf87d..76bbc9173 100644 --- a/plugins/dex/abci.go +++ b/plugins/dex/abci.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" app "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/store" "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/plugins/dex/utils" @@ -200,7 +201,7 @@ func listPairs(keeper *DexKeeper, ctx sdk.Context, abciPrefix string) []types.Tr pairs := keeper.PairMapper.ListAllTradingPairs(ctx) rs := make([]types.TradingPair, 0, len(pairs)) for _, pair := range pairs { - if isMiniPair(pair) { + if keeper.GetPairType(pair.GetSymbol()) == order.PairType.MINI { if abciPrefix == DexMiniAbciQueryPrefix { rs = append(rs, pair) } @@ -211,8 +212,4 @@ func listPairs(keeper *DexKeeper, ctx sdk.Context, abciPrefix string) []types.Tr } } return rs -} - -func isMiniPair(pair types.TradingPair) bool { - return app.IsMiniTokenSymbol(pair.BaseAssetSymbol) || app.IsMiniTokenSymbol(pair.QuoteAssetSymbol) -} +} \ No newline at end of file diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index 46cc31429..7903575a5 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -16,7 +16,6 @@ import ( me "github.com/binance-chain/node/plugins/dex/matcheng" "github.com/binance-chain/node/plugins/dex/types" "github.com/binance-chain/node/plugins/dex/utils" - "github.com/binance-chain/node/wire" ) type NewOrderResponse struct { @@ -24,11 +23,11 @@ type NewOrderResponse struct { } // NewHandler - returns a handler for dex type messages. -func NewHandler(cdc *wire.Codec, dexKeeper *DexKeeper) sdk.Handler { +func NewHandler(dexKeeper *DexKeeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case NewOrderMsg: - return handleNewOrder(ctx, cdc, dexKeeper, msg) + return handleNewOrder(ctx, dexKeeper, msg) case CancelOrderMsg: return handleCancelOrder(ctx, dexKeeper, msg) default: @@ -100,7 +99,7 @@ func validateQtyAndLockBalance(ctx sdk.Context, keeper *DexKeeper, acc common.Na } func handleNewOrder( - ctx sdk.Context, cdc *wire.Codec, dexKeeper *DexKeeper, msg NewOrderMsg, + ctx sdk.Context, dexKeeper *DexKeeper, msg NewOrderMsg, ) sdk.Result { if _, ok := dexKeeper.OrderExists(msg.Symbol, msg.Id); ok { errString := fmt.Sprintf("Duplicated order [%v] on symbol [%v]", msg.Id, msg.Symbol) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index bf00290ac..b90c84e5f 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -111,6 +111,18 @@ func (kp *DexKeeper) EnablePublish() { } } +func (kp *DexKeeper) GetPairType(symbol string) SymbolPairType { + pairType, ok := kp.pairsType[symbol] + if !ok { + if dexUtils.IsMiniTokenTradingPair(symbol) { + pairType = PairType.MINI + } else { + pairType = PairType.BEP2 + } + } + return pairType +} + func (kp *DexKeeper) getOrderKeeper(symbol string) (DexOrderKeeper, error) { pairType, ok := kp.pairsType[symbol] if !ok { diff --git a/plugins/dex/plugin.go b/plugins/dex/plugin.go index d03e0f2c4..42a6d161a 100644 --- a/plugins/dex/plugin.go +++ b/plugins/dex/plugin.go @@ -6,14 +6,13 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/binance-chain/node/app/pub" bnclog "github.com/binance-chain/node/common/log" app "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/dex/utils" - tkstore "github.com/binance-chain/node/plugins/tokens/store" + "github.com/binance-chain/node/plugins/tokens" ) const DexAbciQueryPrefix = "dex" @@ -22,12 +21,11 @@ const DelayedDaysForDelist = 3 // InitPlugin initializes the dex plugin. func InitPlugin( - appp app.ChainApp, dexKeeper *DexKeeper, tokenMapper tkstore.Mapper, accMapper auth.AccountKeeper, govKeeper gov.Keeper, + appp app.ChainApp, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, govKeeper gov.Keeper, ) { - cdc := appp.GetCodec() // add msg handlers - for route, handler := range Routes(cdc, dexKeeper, tokenMapper, accMapper, govKeeper) { + for route, handler := range Routes(dexKeeper, tokenMapper, govKeeper) { appp.GetRouter().AddRoute(route, handler) } diff --git a/plugins/dex/route.go b/plugins/dex/route.go index 88ea04933..2b9eeb9df 100644 --- a/plugins/dex/route.go +++ b/plugins/dex/route.go @@ -2,20 +2,17 @@ package dex import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/tokens" - "github.com/binance-chain/node/wire" ) // Routes exports dex message routes -func Routes(cdc *wire.Codec, dexKeeper *DexKeeper, tokenMapper tokens.Mapper, - accKeeper auth.AccountKeeper, govKeeper gov.Keeper) map[string]sdk.Handler { +func Routes(dexKeeper *DexKeeper, tokenMapper tokens.Mapper, govKeeper gov.Keeper) map[string]sdk.Handler { routes := make(map[string]sdk.Handler) - orderHandler := order.NewHandler(cdc, dexKeeper) + orderHandler := order.NewHandler(dexKeeper) routes[order.RouteNewOrder] = orderHandler routes[order.RouteCancelOrder] = orderHandler routes[list.Route] = list.NewHandler(dexKeeper, tokenMapper, govKeeper) From e53f6378ecffa656a1819bc707e975be284d28ca Mon Sep 17 00:00:00 2001 From: Erheng Lu Date: Tue, 2 Jun 2020 16:44:29 +0800 Subject: [PATCH 96/96] refactor --- app/app.go | 5 ++--- plugins/api/server.go | 6 +++--- plugins/tokens/client/rest/gettokens.go | 1 - plugins/tokens/freeze/handler.go | 5 ----- plugins/tokens/route.go | 2 +- 5 files changed, 6 insertions(+), 13 deletions(-) diff --git a/app/app.go b/app/app.go index d6064e909..b47136951 100644 --- a/app/app.go +++ b/app/app.go @@ -45,7 +45,6 @@ import ( "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/plugins/tokens/issue" "github.com/binance-chain/node/plugins/tokens/seturi" - tkstore "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" "github.com/binance-chain/node/wire" @@ -82,7 +81,7 @@ type BinanceChain struct { CoinKeeper bank.Keeper DexKeeper *dex.DexKeeper AccountKeeper auth.AccountKeeper - TokenMapper tkstore.Mapper + TokenMapper tokens.Mapper ValAddrCache *ValAddrCache stakeKeeper stake.Keeper govKeeper gov.Keeper @@ -132,7 +131,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp // mappers app.AccountKeeper = auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) - app.TokenMapper = tkstore.NewMapper(cdc, common.TokenStoreKey) + app.TokenMapper = tokens.NewMapper(cdc, common.TokenStoreKey) app.CoinKeeper = bank.NewBaseKeeper(app.AccountKeeper) app.ParamHub = paramhub.NewKeeper(cdc, common.ParamsStoreKey, common.TParamsStoreKey) tradingPairMapper := dex.NewTradingPairMapper(app.Codec, common.PairStoreKey) diff --git a/plugins/api/server.go b/plugins/api/server.go index 5e8523e1d..64c6a0810 100644 --- a/plugins/api/server.go +++ b/plugins/api/server.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/binance-chain/node/common" - tkstore "github.com/binance-chain/node/plugins/tokens/store" + "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/wire" ) @@ -27,7 +27,7 @@ type server struct { // stores for handlers keyBase keys.Keybase - tokens tkstore.Mapper + tokens tokens.Mapper accStoreName string } @@ -45,7 +45,7 @@ func newServer(ctx context.CLIContext, cdc *wire.Codec) *server { ctx: ctx, cdc: cdc, keyBase: kb, - tokens: tkstore.NewMapper(cdc, common.TokenStoreKey), + tokens: tokens.NewMapper(cdc, common.TokenStoreKey), accStoreName: common.AccountStoreName, } } diff --git a/plugins/tokens/client/rest/gettokens.go b/plugins/tokens/client/rest/gettokens.go index 986b2d359..93253f436 100644 --- a/plugins/tokens/client/rest/gettokens.go +++ b/plugins/tokens/client/rest/gettokens.go @@ -32,7 +32,6 @@ func listAllTokens(ctx context.CLIContext, cdc *wire.Codec, offset int, limit in tokens := make([]types.IToken, 0) err = cdc.UnmarshalBinaryLengthPrefixed(bz, &tokens) if err != nil { - fmt.Println(err) return nil, err } return tokens, nil diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 05abbbfc4..89bb0be0b 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -63,11 +63,6 @@ func handleUnfreezeToken(ctx sdk.Context, tokenMapper store.Mapper, accKeeper au symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "token", "symbol", symbol, "amount", unfreezeAmount, "addr", msg.From) - _, err := tokenMapper.GetToken(ctx, symbol) - if err != nil { - logger.Info("unfreeze token failed", "reason", "symbol not exist") - return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() - } account := accKeeper.GetAccount(ctx, msg.From).(common.NamedAccount) frozenAmount := account.GetFrozenCoins().AmountOf(symbol) if frozenAmount < unfreezeAmount { diff --git a/plugins/tokens/route.go b/plugins/tokens/route.go index b084fdda3..11ae1f784 100644 --- a/plugins/tokens/route.go +++ b/plugins/tokens/route.go @@ -1,7 +1,6 @@ package tokens import ( - "github.com/binance-chain/node/plugins/tokens/seturi" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" @@ -9,6 +8,7 @@ import ( "github.com/binance-chain/node/plugins/tokens/burn" "github.com/binance-chain/node/plugins/tokens/freeze" "github.com/binance-chain/node/plugins/tokens/issue" + "github.com/binance-chain/node/plugins/tokens/seturi" "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock"