diff --git a/CHANGELOG.md b/CHANGELOG.md index a3d1cba3f..5aea44962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ # Changelog +## 0.8.0 +FEATURES +[Stake] import stake module for side chain +[Slashing] import slashing module for side chain +[Token] support cross chain transfer + +IMPROVEMENTS +[Pub] import pubsub server for publishing message + + ## 0.7.2-hf.1 BUG FIXES * [\#766](https://github.com/binance-chain/node/pull/766)[Dex] remove orderInfo from orderInfoForPub when publish anything diff --git a/app/app.go b/app/app.go index 067b54e82..dc59e7382 100644 --- a/app/app.go +++ b/app/app.go @@ -4,18 +4,29 @@ import ( "encoding/json" "fmt" "io" + "math" "os" "runtime/debug" "sort" "time" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/pubsub" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/oracle" + "github.com/cosmos/cosmos-sdk/x/paramHub" + param "github.com/cosmos/cosmos-sdk/x/paramHub/keeper" + paramTypes "github.com/cosmos/cosmos-sdk/x/paramHub/types" + "github.com/cosmos/cosmos-sdk/x/sidechain" + "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/keeper" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/tmhash" @@ -28,21 +39,20 @@ import ( "github.com/binance-chain/node/admin" "github.com/binance-chain/node/app/config" "github.com/binance-chain/node/app/pub" + appsub "github.com/binance-chain/node/app/pub/sub" "github.com/binance-chain/node/common" - "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/runtime" "github.com/binance-chain/node/common/tx" "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/account" + "github.com/binance-chain/node/plugins/bridge" + bTypes "github.com/binance-chain/node/plugins/bridge/types" "github.com/binance-chain/node/plugins/dex" "github.com/binance-chain/node/plugins/dex/list" "github.com/binance-chain/node/plugins/dex/order" dextypes "github.com/binance-chain/node/plugins/dex/types" - "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" "github.com/binance-chain/node/plugins/tokens/issue" "github.com/binance-chain/node/plugins/tokens/seturi" @@ -85,17 +95,25 @@ type BinanceChain struct { TokenMapper tokens.Mapper ValAddrCache *ValAddrCache stakeKeeper stake.Keeper + slashKeeper slashing.Keeper govKeeper gov.Keeper timeLockKeeper timelock.Keeper swapKeeper swap.Keeper + oracleKeeper oracle.Keeper + bridgeKeeper bridge.Keeper + ibcKeeper ibc.Keeper + scKeeper sidechain.Keeper // keeper to process param store and update - ParamHub *param.ParamHub + ParamHub *param.Keeper baseConfig *config.BaseConfig upgradeConfig *config.UpgradeConfig + crossChainConfig *config.CrossChainConfig abciQueryBlackList map[string]bool publicationConfig *config.PublicationConfig publisher pub.MarketDataPublisher + psServer *pubsub.Server + subscriber *pubsub.Subscriber dexConfig *config.DexConfig @@ -121,6 +139,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp queryHandlers: make(map[string]types.AbciQueryHandler), baseConfig: ServerContext.BaseConfig, upgradeConfig: ServerContext.UpgradeConfig, + crossChainConfig: ServerContext.CrossChainConfig, abciQueryBlackList: getABCIQueryBlackList(ServerContext.QueryConfig), publicationConfig: ServerContext.PublicationConfig, dexConfig: ServerContext.DexConfig, @@ -134,8 +153,17 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp app.AccountKeeper = auth.NewAccountKeeper(cdc, common.AccountStoreKey, types.ProtoAppAccount) 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) + app.ParamHub = param.NewKeeper(cdc, common.ParamsStoreKey, common.TParamsStoreKey) + app.scKeeper = sidechain.NewKeeper(common.SideChainStoreKey, app.ParamHub.Subspace(sidechain.DefaultParamspace), app.Codec) + app.ibcKeeper = ibc.NewKeeper(common.IbcStoreKey, app.ParamHub.Subspace(ibc.DefaultParamspace), app.RegisterCodespace(ibc.DefaultCodespace), app.scKeeper) + + app.slashKeeper = slashing.NewKeeper( + cdc, + common.SlashingStoreKey, &app.stakeKeeper, + app.ParamHub.Subspace(slashing.DefaultParamspace), + app.RegisterCodespace(slashing.DefaultCodespace), + app.CoinKeeper, + ) app.stakeKeeper = stake.NewKeeper( cdc, @@ -143,6 +171,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp app.CoinKeeper, app.Pool, app.ParamHub.Subspace(stake.DefaultParamspace), app.RegisterCodespace(stake.DefaultCodespace), ) + app.ValAddrCache = NewValAddrCache(app.stakeKeeper) app.govKeeper = gov.NewKeeper( @@ -152,26 +181,15 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp app.RegisterCodespace(gov.DefaultCodespace), app.Pool, ) - app.ParamHub.SetGovKeeper(app.govKeeper) app.timeLockKeeper = timelock.NewKeeper(cdc, common.TimeLockStoreKey, app.CoinKeeper, app.AccountKeeper, timelock.DefaultCodespace) app.swapKeeper = swap.NewKeeper(cdc, common.AtomicSwapStoreKey, app.CoinKeeper, app.Pool, swap.DefaultCodespace) - - // legacy bank route (others moved to plugin init funcs) - app.Router(). - AddRoute("bank", bank.NewHandler(app.CoinKeeper)). - AddRoute("stake", stake.NewHandler(app.stakeKeeper, app.govKeeper)). - AddRoute("gov", gov.NewHandler(app.govKeeper)) - - app.QueryRouter().AddRoute("gov", gov.NewQuerier(app.govKeeper)) - app.QueryRouter().AddRoute("stake", stake.NewQuerier(app.stakeKeeper, cdc)) - app.QueryRouter().AddRoute("timelock", timelock.NewQuerier(app.timeLockKeeper)) - app.QueryRouter().AddRoute(swap.AtomicSwapRoute, swap.NewQuerier(app.swapKeeper)) - - app.RegisterQueryHandler("account", app.AccountHandler) - app.RegisterQueryHandler("admin", admin.GetHandler(ServerContext.Config)) + app.oracleKeeper = oracle.NewKeeper(cdc, common.OracleStoreKey, app.ParamHub.Subspace(oracle.DefaultParamSpace), + app.stakeKeeper, app.scKeeper, app.ibcKeeper, app.CoinKeeper, app.Pool) + app.bridgeKeeper = bridge.NewKeeper(cdc, common.BridgeStoreKey, app.AccountKeeper, app.TokenMapper, app.scKeeper, app.CoinKeeper, + app.ibcKeeper, app.Pool, sdk.ChainID(app.crossChainConfig.BscIbcChainId), app.crossChainConfig.BscChainId) if ServerContext.Config.Instrumentation.Prometheus { app.metrics = pub.PrometheusMetrics() // TODO(#246): make it an aggregated wrapper of all component metrics (i.e. DexKeeper, StakeKeeper) @@ -181,6 +199,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp pub.Logger = logger.With("module", "pub") pub.Cfg = app.publicationConfig pub.ToPublishCh = make(chan pub.BlockInfoToPublish, app.publicationConfig.PublicationChannelSize) + pub.ToPublishEventCh = make(chan *appsub.ToPublishEvent, app.publicationConfig.PublicationChannelSize) publishers := make([]pub.MarketDataPublisher, 0, 1) if app.publicationConfig.PublishKafka { @@ -200,8 +219,12 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp } go pub.Publish(app.publisher, app.metrics, logger, app.publicationConfig, pub.ToPublishCh) + go pub.PublishEvent(app.publisher, logger, app.publicationConfig, pub.ToPublishEventCh) pub.IsLive = true } + + app.startPubSub(logger) + app.subscribeEvent(logger) } // finish app initialization @@ -217,9 +240,14 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp common.PairStoreKey, common.ParamsStoreKey, common.StakeStoreKey, + common.SlashingStoreKey, common.GovStoreKey, common.TimeLockStoreKey, common.AtomicSwapStoreKey, + common.SideChainStoreKey, + common.BridgeStoreKey, + common.OracleStoreKey, + common.IbcStoreKey, ) app.SetAnteHandler(tx.NewAnteHandler(app.AccountKeeper)) app.SetPreChecker(tx.NewTxPreChecker()) @@ -243,18 +271,37 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp } // remaining plugin init - app.initDex(tradingPairMapper) - app.initGovHooks() app.initPlugins() - app.initParams() + if ServerContext.Config.StateSyncReactor { lastBreatheBlockHeight := app.getLastBreatheBlockHeight() app.StateSyncHelper = store.NewStateSyncHelper(app.Logger.With("module", "statesync"), db, app.GetCommitMultiStore(), app.Codec) app.StateSyncHelper.Init(lastBreatheBlockHeight) } + return app } +func (app *BinanceChain) startPubSub(logger log.Logger) { + pubLogger := logger.With("module", "bnc_pubsub") + app.psServer = pubsub.NewServer(pubLogger) + if err := app.psServer.Start(); err != nil { + panic(err) + } +} + +func (app *BinanceChain) subscribeEvent(logger log.Logger) { + subLogger := logger.With("module", "bnc_sub") + sub, err := app.psServer.NewSubscriber(pubsub.ClientID("bnc_app"), subLogger) + if err != nil { + panic(err) + } + if err = appsub.SubscribeEvent(sub, app.publicationConfig); err != nil { + panic(err) + } + app.subscriber = sub +} + // setUpgradeConfig will overwrite default upgrade config func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // register upgrade height @@ -268,6 +315,7 @@ 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.LaunchBscUpgrade, upgradeConfig.LaunchBscUpgradeHeight) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP8, upgradeConfig.BEP8Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP67, upgradeConfig.BEP67Height) @@ -276,6 +324,8 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { // 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.LaunchBscUpgrade, common.IbcStoreKey.Name(), common.SideChainStoreKey.Name(), + common.SlashingStoreKey.Name(), common.BridgeStoreKey.Name(), common.OracleStoreKey.Name()) // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP9, @@ -283,8 +333,6 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { timelock.TimeRelockMsg{}.Type(), timelock.TimeUnlockMsg{}.Type(), ) - - // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP12, account.SetAccountFlagsMsg{}.Type()) upgrade.Mgr.RegisterMsgTypes(upgrade.BEP3, swap.HTLTMsg{}.Type(), @@ -292,6 +340,22 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { swap.ClaimHTLTMsg{}.Type(), swap.RefundHTLTMsg{}.Type(), ) + upgrade.Mgr.RegisterMsgTypes(upgrade.LaunchBscUpgrade, + stake.MsgCreateSideChainValidator{}.Type(), + stake.MsgEditSideChainValidator{}.Type(), + stake.MsgSideChainDelegate{}.Type(), + stake.MsgSideChainRedelegate{}.Type(), + stake.MsgSideChainUndelegate{}.Type(), + slashing.MsgBscSubmitEvidence{}.Type(), + slashing.MsgSideChainUnjail{}.Type(), + gov.MsgSideChainSubmitProposal{}.Type(), + gov.MsgSideChainDeposit{}.Type(), + gov.MsgSideChainVote{}.Type(), + bridge.BindMsg{}.Type(), + bridge.UnbindMsg{}.Type(), + bridge.TransferOutMsg{}.Type(), + oracle.ClaimMsg{}.Type(), + ) // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, issue.IssueMiniMsg{}.Type(), @@ -316,9 +380,11 @@ func (app *BinanceChain) initRunningMode() { } } -func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { - - app.DexKeeper = dex.NewDexKeeper(common.DexStoreKey, app.AccountKeeper, pairMapper, app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec, app.publicationConfig.ShouldPublishAny()) +func (app *BinanceChain) initDex() { + pairMapper := dex.NewTradingPairMapper(app.Codec, common.PairStoreKey) + 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) @@ -345,26 +411,195 @@ func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) { } func (app *BinanceChain) initPlugins() { + app.initSideChain() + app.initIbc() + app.initDex() + app.initGov() + app.initGovHooks() + app.initStaking() + app.initSlashing() + app.initOracle() + app.initParamHub() + app.initBridge() tokens.InitPlugin(app, app.TokenMapper, app.AccountKeeper, app.CoinKeeper, app.timeLockKeeper, app.swapKeeper) dex.InitPlugin(app, app.DexKeeper, app.TokenMapper, app.govKeeper) - param.InitPlugin(app, app.ParamHub) account.InitPlugin(app, app.AccountKeeper) + bridge.InitPlugin(app, app.bridgeKeeper) + app.initParams() + + // add handlers from bnc-cosmos-sdk (others moved to plugin init funcs) + // we need to add handlers after all keepers initialized + app.Router(). + AddRoute("bank", bank.NewHandler(app.CoinKeeper)). + AddRoute("stake", stake.NewHandler(app.stakeKeeper, app.govKeeper)). + AddRoute("slashing", slashing.NewHandler(app.slashKeeper)). + AddRoute("gov", gov.NewHandler(app.govKeeper)). + AddRoute(oracle.RouteOracle, oracle.NewHandler(app.oracleKeeper)) + + app.QueryRouter().AddRoute("gov", gov.NewQuerier(app.govKeeper)) + app.QueryRouter().AddRoute("stake", stake.NewQuerier(app.stakeKeeper, app.Codec)) + app.QueryRouter().AddRoute("slashing", slashing.NewQuerier(app.slashKeeper, app.Codec)) + app.QueryRouter().AddRoute("timelock", timelock.NewQuerier(app.timeLockKeeper)) + app.QueryRouter().AddRoute(swap.AtomicSwapRoute, swap.NewQuerier(app.swapKeeper)) + app.QueryRouter().AddRoute("param", paramHub.NewQuerier(app.ParamHub, app.Codec)) + app.QueryRouter().AddRoute("sideChain", sidechain.NewQuerier(app.scKeeper)) + + app.RegisterQueryHandler("account", app.AccountHandler) + app.RegisterQueryHandler("admin", admin.GetHandler(ServerContext.Config)) + +} + +func (app *BinanceChain) initSideChain() { + app.scKeeper.SetGovKeeper(&app.govKeeper) + app.scKeeper.SetIbcKeeper(&app.ibcKeeper) + upgrade.Mgr.RegisterBeginBlocker(sdk.LaunchBscUpgrade, func(ctx sdk.Context) { + bscStorePrefix := []byte{0x99} + app.scKeeper.SetSideChainIdAndStorePrefix(ctx, ServerContext.BscChainId, bscStorePrefix) + app.scKeeper.SetParams(ctx, sidechain.Params{ + BscSideChainId: ServerContext.BscChainId, + }) + }) +} + +func (app *BinanceChain) initOracle() { + app.oracleKeeper.SetPbsbServer(app.psServer) + if ServerContext.Config.Instrumentation.Prometheus { + app.oracleKeeper.EnablePrometheusMetrics() + } + app.oracleKeeper.SubscribeParamChange(app.ParamHub) + oracle.RegisterUpgradeBeginBlocker(app.oracleKeeper) +} + +func (app *BinanceChain) initBridge() { + app.bridgeKeeper.SetPbsbServer(app.psServer) + upgrade.Mgr.RegisterBeginBlocker(sdk.LaunchBscUpgrade, func(ctx sdk.Context) { + app.scKeeper.SetChannelSendPermission(ctx, sdk.ChainID(ServerContext.BscIbcChainId), bTypes.BindChannelID, sdk.ChannelAllow) + app.scKeeper.SetChannelSendPermission(ctx, sdk.ChainID(ServerContext.BscIbcChainId), bTypes.TransferOutChannelID, sdk.ChannelAllow) + app.scKeeper.SetChannelSendPermission(ctx, sdk.ChainID(ServerContext.BscIbcChainId), bTypes.TransferInChannelID, sdk.ChannelAllow) + }) +} + +func (app *BinanceChain) initParamHub() { + app.ParamHub.SetGovKeeper(&app.govKeeper) + app.ParamHub.SetupForSideChain(&app.scKeeper, &app.ibcKeeper) + + paramHub.RegisterUpgradeBeginBlocker(app.ParamHub) + upgrade.Mgr.RegisterBeginBlocker(sdk.LaunchBscUpgrade, func(ctx sdk.Context) { + app.scKeeper.SetChannelSendPermission(ctx, sdk.ChainID(ServerContext.BscIbcChainId), param.ChannelId, sdk.ChannelAllow) + storePrefix := app.scKeeper.GetSideChainStorePrefix(ctx, ServerContext.BscChainId) + newCtx := ctx.WithSideChainKeyPrefix(storePrefix) + app.ParamHub.SetLastSCParamChangeProposalId(newCtx, paramTypes.LastProposalID{ProposalID: 0}) + }) + handler := paramHub.CreateAbciQueryHandler(app.ParamHub) + // paramHub used to be a plugin of node, we still keep the old api here. + app.RegisterQueryHandler(paramHub.AbciQueryPrefix, func(app types.ChainApp, req abci.RequestQuery, path []string) (res *abci.ResponseQuery) { + return handler(app.GetContextForCheckState(), req, path) + }) +} + +func (app *BinanceChain) initStaking() { + app.stakeKeeper.SetupForSideChain(&app.scKeeper, &app.ibcKeeper) + app.stakeKeeper.SetPbsbServer(app.psServer) + upgrade.Mgr.RegisterBeginBlocker(sdk.LaunchBscUpgrade, func(ctx sdk.Context) { + stake.MigratePowerRankKey(ctx, app.stakeKeeper) + app.scKeeper.SetChannelSendPermission(ctx, sdk.ChainID(ServerContext.BscIbcChainId), keeper.ChannelId, sdk.ChannelAllow) + storePrefix := app.scKeeper.GetSideChainStorePrefix(ctx, ServerContext.BscChainId) + newCtx := ctx.WithSideChainKeyPrefix(storePrefix) + app.stakeKeeper.SetParams(newCtx, stake.Params{ + UnbondingTime: 60 * 60 * 24 * 7 * time.Second, // 7 days + MaxValidators: 21, + BondDenom: types.NativeTokenSymbol, + MinSelfDelegation: 20000e8, + MinDelegationChange: 1e8, + }) + app.stakeKeeper.SetPool(newCtx, stake.Pool{ + // TODO: optimize these parameters + LooseTokens: sdk.NewDec(5e15), + }) + }) + app.stakeKeeper.SubscribeParamChange(app.ParamHub) + app.stakeKeeper = app.stakeKeeper.WithHooks(app.slashKeeper.Hooks()) +} + +func (app *BinanceChain) initGov() { + app.govKeeper.SetupForSideChain(&app.scKeeper) + upgrade.Mgr.RegisterBeginBlocker(sdk.LaunchBscUpgrade, func(ctx sdk.Context) { + storePrefix := app.scKeeper.GetSideChainStorePrefix(ctx, ServerContext.BscChainId) + newCtx := ctx.WithSideChainKeyPrefix(storePrefix) + err := app.govKeeper.SetInitialProposalID(newCtx, 1) + if err != nil { + panic(err) + } + app.govKeeper.SetDepositParams(newCtx, gov.DepositParams{ + MinDeposit: sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 2000e8)}, + MaxDepositPeriod: time.Duration(2*24) * time.Hour, // 2 days + }) + app.govKeeper.SetTallyParams(newCtx, gov.TallyParams{ + Quorum: sdk.NewDecWithPrec(5, 1), + Threshold: sdk.NewDecWithPrec(5, 1), + Veto: sdk.NewDecWithPrec(334, 3), + }) + }) +} + +func (app *BinanceChain) initSlashing() { + app.slashKeeper.SetPbsbServer(app.psServer) + app.slashKeeper.SetSideChain(&app.scKeeper) + app.slashKeeper.SubscribeParamChange(app.ParamHub) + upgrade.Mgr.RegisterBeginBlocker(sdk.LaunchBscUpgrade, func(ctx sdk.Context) { + app.scKeeper.SetChannelSendPermission(ctx, sdk.ChainID(ServerContext.BscIbcChainId), slashing.ChannelId, sdk.ChannelAllow) + storePrefix := app.scKeeper.GetSideChainStorePrefix(ctx, ServerContext.BscChainId) + newCtx := ctx.WithSideChainKeyPrefix(storePrefix) + app.slashKeeper.SetParams(newCtx, slashing.Params{ + MaxEvidenceAge: 60 * 60 * 24 * 3 * time.Second, // 3 days + DoubleSignUnbondDuration: math.MaxInt64, // forever + DowntimeUnbondDuration: 60 * 60 * 24 * 2 * time.Second, // 2 days + TooLowDelUnbondDuration: 60 * 60 * 24 * time.Second, // 1 day + DoubleSignSlashAmount: 10000e8, + SubmitterReward: 1000e8, + DowntimeSlashAmount: 50e8, + DowntimeSlashFee: 10e8, + }) + }) +} + +func (app *BinanceChain) initIbc() { + // set up IBC chainID for BBC + app.scKeeper.SetSrcChainID(sdk.ChainID(ServerContext.IbcChainId)) + // set up IBC chainID for BSC + err := app.scKeeper.RegisterDestChain(ServerContext.BscChainId, sdk.ChainID(ServerContext.BscIbcChainId)) + if err != nil { + panic(fmt.Sprintf("register IBC chainID error: chainID=%s, err=%s", ServerContext.BscChainId, err.Error())) + } + app.ibcKeeper.SubscribeParamChange(app.ParamHub) + upgrade.Mgr.RegisterBeginBlocker(sdk.LaunchBscUpgrade, func(ctx sdk.Context) { + storePrefix := app.scKeeper.GetSideChainStorePrefix(ctx, ServerContext.BscChainId) + newCtx := ctx.WithSideChainKeyPrefix(storePrefix) + app.ibcKeeper.SetParams(newCtx, ibc.Params{ + RelayerFee: ibc.DefaultRelayerFeeParam, + }) + }) } func (app *BinanceChain) initGovHooks() { listHooks := list.NewListHooks(app.DexKeeper, app.TokenMapper) - feeChangeHooks := param.NewFeeChangeHooks(app.Codec) + feeChangeHooks := paramHub.NewFeeChangeHooks(app.Codec) + cscParamChangeHooks := paramHub.NewCSCParamsChangeHook(app.Codec) + scParamChangeHooks := paramHub.NewSCParamsChangeHook(app.Codec) + chanPermissionHooks := sidechain.NewChanPermissionSettingHook(app.Codec, &app.scKeeper) delistHooks := list.NewDelistHooks(app.DexKeeper) app.govKeeper.AddHooks(gov.ProposalTypeListTradingPair, listHooks) app.govKeeper.AddHooks(gov.ProposalTypeFeeChange, feeChangeHooks) + app.govKeeper.AddHooks(gov.ProposalTypeCSCParamsChange, cscParamChangeHooks) + app.govKeeper.AddHooks(gov.ProposalTypeSCParamsChange, scParamChangeHooks) app.govKeeper.AddHooks(gov.ProposalTypeDelistTradingPair, delistHooks) + app.govKeeper.AddHooks(gov.ProposalTypeManageChanPermission, chanPermissionHooks) } func (app *BinanceChain) initParams() { - if app.CheckState == nil || app.CheckState.Ctx.BlockHeight() == 0 { - return + if app.CheckState != nil && app.CheckState.Ctx.BlockHeight() != 0 { + app.ParamHub.Load(app.CheckState.Ctx) } - app.ParamHub.Load(app.CheckState.Ctx) } // initChainerFn performs custom logic for chain initialization. @@ -414,7 +649,7 @@ func (app *BinanceChain) initChainerFn() sdk.InitChainer { panic(res.Log) } } - validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + _, validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx) } // sanity check @@ -477,7 +712,7 @@ func (app *BinanceChain) CheckTx(req abci.RequestCheckTx) (res abci.ResponseChec Code: uint32(result.Code), Data: result.Data, Log: result.Log, - Events: result.Tags.ToEvents(), + Events: result.GetEvents(), } } @@ -488,10 +723,16 @@ func (app *BinanceChain) DeliverTx(req abci.RequestDeliverTx) (res abci.Response if res.IsOK() { // commit or panic fees.Pool.CommitFee(txHash) + if app.psServer != nil { + app.psServer.Publish(appsub.TxDeliverSuccEvent{}) + } } else { if app.publicationConfig.PublishOrderUpdates { app.processErrAbciResponseForPub(req.Tx) } + if app.psServer != nil { + app.psServer.Publish(appsub.TxDeliverFailEvent{}) + } } if app.publicationConfig.PublishBlock { pub.Pool.AddTxRes(txHash, res) @@ -534,7 +775,7 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a lastBlockTime := app.CheckState.Ctx.BlockHeader().Time blockTime := ctx.BlockHeader().Time height := ctx.BlockHeader().Height - + ctx = ctx.WithEventManager(sdk.NewEventManager()) isBreatheBlock := app.isBreatheBlock(height, lastBlockTime, blockTime) var tradesToPublish []*pub.Trade if sdk.IsUpgrade(upgrade.BEP19) || !isBreatheBlock { @@ -550,12 +791,10 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a app.Logger.Info("Start Breathe Block Handling", "height", height, "lastBlockTime", lastBlockTime, "newBlockTime", blockTime) app.takeSnapshotHeight = height - icoDone := ico.EndBlockAsync(ctx) + fmt.Println(ctx.BlockHeight()) dex.EndBreatheBlock(ctx, app.DexKeeper, app.govKeeper, height, blockTime) - param.EndBreatheBlock(ctx, app.ParamHub) + paramHub.EndBreatheBlock(ctx, app.ParamHub) tokens.EndBreatheBlock(ctx, app.swapKeeper) - // other end blockers - <-icoDone } else { app.Logger.Debug("normal block", "height", height) } @@ -564,21 +803,24 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a blockFee := distributeFee(ctx, app.AccountKeeper, app.ValAddrCache, app.publicationConfig.PublishBlockFee) - tags, passed, failed := gov.EndBlocker(ctx, app.govKeeper) + passed, failed := gov.EndBlocker(ctx, app.govKeeper) var proposals pub.Proposals - - if app.publicationConfig.PublishOrderUpdates { - proposals = pub.CollectProposalsForPublish(passed, failed) + var sideProposals pub.SideProposals + if app.publicationConfig.PublishOrderUpdates || app.publicationConfig.PublishSideProposal { + proposals, sideProposals = pub.CollectProposalsForPublish(passed, failed) } - + paramHub.EndBlock(ctx, app.ParamHub) + sidechain.EndBlock(ctx, app.scKeeper) var completedUbd []stake.UnbondingDelegation var validatorUpdates abci.ValidatorUpdates - if isBreatheBlock || ctx.RouterCallRecord()["stake"] { - // some endblockers without fees will execute after publish to make publication run as early as possible. + if isBreatheBlock { + validatorUpdates, completedUbd = stake.EndBreatheBlock(ctx, app.stakeKeeper) + } else if ctx.RouterCallRecord()["stake"] { validatorUpdates, completedUbd = stake.EndBlocker(ctx, app.stakeKeeper) - if len(validatorUpdates) != 0 { - app.ValAddrCache.ClearCache() - } + } + ibc.EndBlocker(ctx, app.ibcKeeper) + if len(validatorUpdates) != 0 { + app.ValAddrCache.ClearCache() } if app.publicationConfig.ShouldPublishAny() && @@ -586,12 +828,19 @@ 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, &proposals, &sideProposals, &stakeUpdates, blockFee, ctx, height, blockTime.UnixNano()) + + appsub.SetMeta(height, blockTime, isBreatheBlock) + app.subscriber.Wait() + app.publishEvent() } // clean up intermediate cached data app.DexKeeper.ClearOrderChanges() app.DexKeeper.ClearRoundFee() + + // clean up intermediate cached data used to be published + appsub.Clear() } fees.Pool.Clear() // just clean it, no matter use it or not. @@ -601,7 +850,7 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a //future TODO: add failure info. return abci.ResponseEndBlock{ ValidatorUpdates: validatorUpdates, - Events: tags.ToEvents(), + Events: ctx.EventManager().ABCIEvents(), } } @@ -761,18 +1010,29 @@ func MakeCodec() *wire.Codec { wire.RegisterCrypto(cdc) // Register crypto. bank.RegisterCodec(cdc) sdk.RegisterCodec(cdc) // Register Msgs + paramHub.RegisterWire(cdc) dex.RegisterWire(cdc) tokens.RegisterWire(cdc) account.RegisterWire(cdc) types.RegisterWire(cdc) tx.RegisterWire(cdc) stake.RegisterCodec(cdc) + slashing.RegisterCodec(cdc) gov.RegisterCodec(cdc) - param.RegisterWire(cdc) + bridge.RegisterWire(cdc) + oracle.RegisterWire(cdc) + ibc.RegisterWire(cdc) 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) publishEvent() { + if appsub.ToPublish() != nil && appsub.ToPublish().EventData != nil { + pub.ToPublishEventCh <- appsub.ToPublish() + } + +} + +func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublish *pub.Proposals, sideProposalsToPublish *pub.SideProposals, 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 @@ -819,6 +1079,8 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublis len(orderChanges), "numOfProposals", proposalsToPublish.NumOfMsgs, + "numOfSideProposals", + sideProposalsToPublish.NumOfMsgs, "numOfStakeUpdates", stakeUpdates.NumOfMsgs, "numOfAccounts", @@ -830,6 +1092,7 @@ func (app *BinanceChain) publish(tradesToPublish []*pub.Trade, proposalsToPublis blockTime, tradesToPublish, proposalsToPublish, + sideProposalsToPublish, stakeUpdates, orderChanges, // thread-safety is guarded by the signal from RemoveDoneCh orderInfoForPublish, // thread-safety is guarded by the signal from RemoveDoneCh diff --git a/app/app_paramhub_test.go b/app/app_paramhub_test.go new file mode 100644 index 000000000..17de01d83 --- /dev/null +++ b/app/app_paramhub_test.go @@ -0,0 +1,502 @@ +package app + +import ( + "bytes" + "encoding/hex" + "fmt" + "os" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/tendermint/go-amino" + abcicli "github.com/tendermint/tendermint/abci/client" + "github.com/tendermint/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/tendermint/tendermint/crypto/tmhash" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/bsc/rlp" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkFees "github.com/cosmos/cosmos-sdk/types/fees" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/mock" + otypes "github.com/cosmos/cosmos-sdk/x/oracle/types" + pHub "github.com/cosmos/cosmos-sdk/x/paramHub" + paramHub "github.com/cosmos/cosmos-sdk/x/paramHub/keeper" + ptypes "github.com/cosmos/cosmos-sdk/x/paramHub/types" + sTypes "github.com/cosmos/cosmos-sdk/x/sidechain/types" + "github.com/cosmos/cosmos-sdk/x/slashing" + "github.com/cosmos/cosmos-sdk/x/stake" + + ctypes "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/dex" + "github.com/binance-chain/node/plugins/tokens" + "github.com/binance-chain/node/wire" +) + +// util objects +var ( + memDB = dbm.NewMemDB() + logger = log.NewTMLogger(os.Stdout) + genAccs, addrs, pubKeys, privKeys = mock.CreateGenAccounts(4, + sdk.Coins{sdk.NewCoin("BNB", 500000e8), sdk.NewCoin("BTC-000", 200e8)}) + testScParams = `[{"type": "params/StakeParamSet","value": {"unbonding_time": "604800000000000","max_validators": 11,"bond_denom": "BNB","min_self_delegation": "5000000000000","min_delegation_change": "100000000"}},{"type": "params/SlashParamSet","value": {"max_evidence_age": "259200000000000","signed_blocks_window": "0","min_signed_per_window": "0","double_sign_unbond_duration": "9223372036854775807","downtime_unbond_duration": "172800000000000","too_low_del_unbond_duration": "86400000000000","slash_fraction_double_sign": "0","slash_fraction_downtime": "0","double_sign_slash_amount": "1000000000000","downtime_slash_amount": "5000000000","submitter_reward": "100000000000","downtime_slash_fee": "1000000000"}},{"type": "params/OracleParamSet","value": {"ConsensusNeeded": "70000000"}},{"type": "params/IbcParamSet","value": {"relayer_fee": "1000000"}}]` + testClient *TestClient + testApp *BinanceChain +) + +func init() { + ServerContext.UpgradeConfig.LaunchBscUpgradeHeight = 1 + testApp = NewBinanceChain(logger, memDB, os.Stdout) + testClient = NewTestClient(testApp) +} + +func TestCSCParamUpdatesSuccess(t *testing.T) { + valAddr, ctx, accounts := setupTest() + sideValAddr := accounts[0].GetAddress().Bytes() + tNow := time.Now() + + ctx = UpdateContext(valAddr, ctx, 3, tNow.AddDate(0, 0, 1)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + + cscParam := ptypes.CSCParamChange{ + Key: "testa", + Value: hex.EncodeToString([]byte(hex.EncodeToString([]byte("testValue")))), + Target: hex.EncodeToString(cmn.RandBytes(20)), + } + cscParam.Check() + cscParamsBz, err := Codec.MarshalJSON(cscParam) + proposeMsg := gov.NewMsgSideChainSubmitProposal("testSideProposal", string(cscParamsBz), gov.ProposalTypeCSCParamsChange, sideValAddr, sdk.Coins{sdk.Coin{"BNB", 2000e8}}, time.Second, "bsc") + res, err := testClient.DeliverTxSync(&proposeMsg, testApp.Codec) + fmt.Println(res) + assert.NoError(t, err, "failed to submit side chain parameters change") + + voteMsg := gov.NewMsgSideChainVote(sideValAddr, 1, gov.OptionYes, "bsc") + _, err = testClient.DeliverTxSync(&voteMsg, testApp.Codec) + assert.NoError(t, err, "failed to vote side chain parameters change") + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + ctx = UpdateContext(valAddr, ctx, 4, tNow.AddDate(0, 0, 1).Add(5*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(5 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + packageBz, err := testApp.ibcKeeper.GetIBCPackage(ctx, "bsc", paramHub.ChannelName, uint64(0)) + assert.NoError(t, err) + expectedBz, _ := rlp.EncodeToBytes(cscParam) + assert.NoError(t, err) + assert.True(t, bytes.Compare(expectedBz, packageBz[sTypes.PackageHeaderLength:]) == 0, "package bytes not equal") +} + +func TestCSCParamUpdatesSequenceCorrect(t *testing.T) { + valAddr, ctx, accounts := setupTest() + sideValAddr := accounts[0].GetAddress().Bytes() + tNow := time.Now() + + cscParams := []ptypes.CSCParamChange{ + { + Key: "testA", + Value: hex.EncodeToString([]byte(hex.EncodeToString([]byte("testValueA")))), + Target: hex.EncodeToString(cmn.RandBytes(20)), + }, + { + Key: "testB", + Value: hex.EncodeToString([]byte(hex.EncodeToString([]byte("testValueB")))), + Target: hex.EncodeToString(cmn.RandBytes(20)), + }, + { + Key: "testC", + Value: hex.EncodeToString([]byte(hex.EncodeToString([]byte("testValueC")))), + Target: hex.EncodeToString(cmn.RandBytes(20)), + }, + } + for idx, c := range cscParams { + c.Check() + cscParams[idx] = c + } + + ctx = UpdateContext(valAddr, ctx, 3, tNow.AddDate(0, 0, 1)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + for idx, cscParam := range cscParams { + cscParamsBz, err := Codec.MarshalJSON(cscParam) + proposeMsg := gov.NewMsgSideChainSubmitProposal("testSideProposal", string(cscParamsBz), gov.ProposalTypeCSCParamsChange, sideValAddr, sdk.Coins{sdk.Coin{"BNB", 2000e8}}, time.Second, "bsc") + _, err = testClient.DeliverTxSync(&proposeMsg, testApp.Codec) + assert.NoError(t, err, "failed to submit side chain parameters change") + + voteMsg := gov.NewMsgSideChainVote(sideValAddr, int64(idx+1), gov.OptionYes, "bsc") + _, err = testClient.DeliverTxSync(&voteMsg, testApp.Codec) + assert.NoError(t, err, "failed to vote side chain parameters change") + } + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + ctx = UpdateContext(valAddr, ctx, 4, tNow.AddDate(0, 0, 1).Add(5*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(5 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + for idx, cscParam := range cscParams { + packageBz, err := testApp.ibcKeeper.GetIBCPackage(ctx, "bsc", paramHub.ChannelName, uint64(idx)) + expectedBz, _ := rlp.EncodeToBytes(cscParam) + assert.NoError(t, err) + assert.True(t, bytes.Compare(expectedBz, packageBz[sTypes.PackageHeaderLength:]) == 0, "package bytes not equal") + } + + // expire proposal + ctx = UpdateContext(valAddr, ctx, 5, tNow.AddDate(0, 0, 1).Add(6*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(6 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + for _, cscParam := range cscParams { + cscParamsBz, err := Codec.MarshalJSON(cscParam) + proposeMsg := gov.NewMsgSideChainSubmitProposal("testSideProposal", string(cscParamsBz), gov.ProposalTypeCSCParamsChange, sideValAddr, sdk.Coins{sdk.Coin{"BNB", 2000e8}}, time.Second, "bsc") + _, err = testClient.DeliverTxSync(&proposeMsg, testApp.Codec) + assert.NoError(t, err, "failed to submit side chain parameters change") + } + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + ctx = UpdateContext(valAddr, ctx, 6, tNow.AddDate(0, 0, 1).Add(10*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(10 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + packageBz, err := testApp.ibcKeeper.GetIBCPackage(ctx, "bsc", paramHub.ChannelName, uint64(3)) + assert.NoError(t, err) + assert.True(t, len(packageBz) == 0, "write package unexpected") + + // still in order + + ctx = UpdateContext(valAddr, ctx, 7, tNow.AddDate(0, 0, 1).Add(12*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(12 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + for idx, cscParam := range cscParams { + cscParamsBz, err := Codec.MarshalJSON(cscParam) + proposeMsg := gov.NewMsgSideChainSubmitProposal("testSideProposal", string(cscParamsBz), gov.ProposalTypeCSCParamsChange, sideValAddr, sdk.Coins{sdk.Coin{"BNB", 2000e8}}, time.Second, "bsc") + _, err = testClient.DeliverTxSync(&proposeMsg, testApp.Codec) + assert.NoError(t, err, "failed to submit side chain parameters change") + + voteMsg := gov.NewMsgSideChainVote(sideValAddr, int64(idx+7), gov.OptionYes, "bsc") + _, err = testClient.DeliverTxSync(&voteMsg, testApp.Codec) + assert.NoError(t, err, "failed to vote side chain parameters change") + } + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + ctx = UpdateContext(valAddr, ctx, 8, tNow.AddDate(0, 0, 1).Add(15*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(15 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + for idx, cscParam := range cscParams { + packageBz, err := testApp.ibcKeeper.GetIBCPackage(ctx, "bsc", paramHub.ChannelName, uint64(idx+3)) + expectedBz, _ := rlp.EncodeToBytes(cscParam) + assert.NoError(t, err) + assert.True(t, bytes.Compare(expectedBz, packageBz[sTypes.PackageHeaderLength:]) == 0, "package bytes not equal") + } +} + +func TestSubmitCSCParamUpdatesFail(t *testing.T) { + valAddr, ctx, accounts := setupTest() + sideValAddr := accounts[0].GetAddress().Bytes() + tNow := time.Now() + + ctx = UpdateContext(valAddr, ctx, 3, tNow.AddDate(0, 0, 1)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + + cscParams := []ptypes.CSCParamChange{ + { + Key: "", + Value: hex.EncodeToString([]byte("testValue")), + Target: hex.EncodeToString(cmn.RandBytes(20)), + }, + { + Key: "testKey", + Value: "", + Target: hex.EncodeToString(cmn.RandBytes(20)), + }, + { + Key: "testKey", + Value: hex.EncodeToString([]byte("testValue")), + Target: hex.EncodeToString(cmn.RandBytes(10)), + }, + { + Key: cmn.RandStr(256), + Value: hex.EncodeToString([]byte("testValue")), + Target: hex.EncodeToString(cmn.RandBytes(20)), + }, + } + + for idx, c := range cscParams { + c.Check() + cscParams[idx] = c + } + + for _, cscParam := range cscParams { + cscParamsBz, err := Codec.MarshalJSON(cscParam) + proposeMsg := gov.NewMsgSideChainSubmitProposal("testSideProposal", string(cscParamsBz), gov.ProposalTypeCSCParamsChange, sideValAddr, sdk.Coins{sdk.Coin{"BNB", 2000e8}}, time.Second, "bsc") + resp, err := testClient.DeliverTxSync(&proposeMsg, testApp.Codec) + assert.NoError(t, err, "failed to submit side chain parameters change") + assert.True(t, strings.Contains(resp.Log, "Invalid proposal")) + } +} + +func TestSCParamUpdatesSuccess(t *testing.T) { + valAddr, ctx, accounts := setupTest() + sideValAddr := accounts[0].GetAddress().Bytes() + tNow := time.Now() + + ctx = UpdateContext(valAddr, ctx, 3, tNow.AddDate(0, 0, 1)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + + scParams := ptypes.SCChangeParams{ + SCParams: []ptypes.SCParam{ + generatSCParamChange(nil, 0).SCParams[0], + generatSCParamChange(nil, 0).SCParams[1], + &otypes.Params{ConsensusNeeded: sdk.NewDecWithPrec(9, 1)}, + generatSCParamChange(nil, 0).SCParams[3], + }} + scParamsBz, err := Codec.MarshalJSON(scParams) + proposeMsg := gov.NewMsgSideChainSubmitProposal("testSideProposal", string(scParamsBz), gov.ProposalTypeSCParamsChange, sideValAddr, sdk.Coins{sdk.Coin{"BNB", 2000e8}}, time.Second, "bsc") + res, err := testClient.DeliverTxSync(&proposeMsg, testApp.Codec) + fmt.Println(res) + assert.NoError(t, err, "failed to submit side chain parameters change") + + voteMsg := gov.NewMsgSideChainVote(sideValAddr, 1, gov.OptionYes, "bsc") + _, err = testClient.DeliverTxSync(&voteMsg, testApp.Codec) + assert.NoError(t, err, "failed to vote side chain parameters change") + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + // endblock + ctx = UpdateContext(valAddr, ctx, 4, tNow.AddDate(0, 0, 1).Add(5*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(5 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + // breath block + ctx = UpdateContext(valAddr, ctx, 5, tNow.AddDate(0, 0, 2).Add(5*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(5 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + p := testApp.oracleKeeper.GetConsensusNeeded(ctx) + assert.True(t, p.Equal(sdk.NewDecWithPrec(9, 1))) + storePrefix := testApp.scKeeper.GetSideChainStorePrefix(ctx, ServerContext.BscChainId) + sideChainCtx := ctx.WithSideChainKeyPrefix(storePrefix) + s := testApp.stakeKeeper.GetParams(sideChainCtx) + assert.True(t, s.Equal(*(scParams.SCParams[0].(*stake.Params)))) +} + +func TestSCParamMultiUpdatesSuccess(t *testing.T) { + valAddr, ctx, accounts := setupTest() + sideValAddr := accounts[0].GetAddress().Bytes() + tNow := time.Now() + + ctx = UpdateContext(valAddr, ctx, 3, tNow.AddDate(0, 0, 1)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + + scParamses := []ptypes.SCChangeParams{ + generatSCParamChange(&otypes.Params{ConsensusNeeded: sdk.NewDecWithPrec(6, 1)}, 2), + generatSCParamChange(&otypes.Params{ConsensusNeeded: sdk.NewDecWithPrec(8, 1)}, 2), + generatSCParamChange(&otypes.Params{ConsensusNeeded: sdk.NewDecWithPrec(9, 1)}, 2), + } + for idx, scParams := range scParamses { + scParamsBz, err := Codec.MarshalJSON(scParams) + proposeMsg := gov.NewMsgSideChainSubmitProposal("testSideProposal", string(scParamsBz), gov.ProposalTypeSCParamsChange, sideValAddr, sdk.Coins{sdk.Coin{"BNB", 2000e8}}, time.Second, "bsc") + _, err = testClient.DeliverTxSync(&proposeMsg, testApp.Codec) + assert.NoError(t, err, "failed to submit side chain parameters change") + + voteMsg := gov.NewMsgSideChainVote(sideValAddr, int64(idx+1), gov.OptionYes, "bsc") + _, err = testClient.DeliverTxSync(&voteMsg, testApp.Codec) + assert.NoError(t, err, "failed to vote side chain parameters change") + } + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + // endblock + ctx = UpdateContext(valAddr, ctx, 4, tNow.AddDate(0, 0, 1).Add(5*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(5 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + // breath block + ctx = UpdateContext(valAddr, ctx, 5, tNow.AddDate(0, 0, 2).Add(5*time.Second)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1).Add(5 * time.Second)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{Height: ctx.BlockHeader().Height}) + + p := testApp.oracleKeeper.GetConsensusNeeded(ctx) + assert.True(t, p.Equal(sdk.NewDecWithPrec(9, 1))) +} + +func TestSCParamUpdatesFail(t *testing.T) { + valAddr, ctx, accounts := setupTest() + sideValAddr := accounts[0].GetAddress().Bytes() + tNow := time.Now() + + ctx = UpdateContext(valAddr, ctx, 3, tNow.AddDate(0, 0, 1)) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, 1)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + + scParamses := []ptypes.SCChangeParams{ + generatSCParamChange(&stake.Params{UnbondingTime: 24 * time.Hour, MaxValidators: 10, BondDenom: "", MinSelfDelegation: 100e8}, 0), + generatSCParamChange(&otypes.Params{ConsensusNeeded: sdk.NewDecWithPrec(2, 0)}, 2), + {SCParams: []ptypes.SCParam{ + nil, + }}, + {SCParams: nil}, + } + for _, scParams := range scParamses { + scParamsBz, err := Codec.MarshalJSON(scParams) + proposeMsg := gov.NewMsgSideChainSubmitProposal("testSideProposal", string(scParamsBz), gov.ProposalTypeSCParamsChange, sideValAddr, sdk.Coins{sdk.Coin{"BNB", 2000e8}}, time.Second, "bsc") + res, err := testClient.DeliverTxSync(&proposeMsg, testApp.Codec) + assert.NoError(t, err) + assert.True(t, strings.Contains(res.Log, "Invalid proposal")) + } + +} + +// =========== setup for test cases ==== + +func NewTestClient(a *BinanceChain) *TestClient { + a.SetDeliverState(types.Header{}) + a.SetAnteHandler(newMockAnteHandler(a.Codec)) // clear AnteHandler to skip the signature verification step + return &TestClient{abcicli.NewLocalClient(nil, a), MakeCodec()} +} + +type TestClient struct { + cl abcicli.Client + cdc *wire.Codec +} + +func (tc *TestClient) DeliverTxSync(msg sdk.Msg, cdc *wire.Codec) (*types.ResponseDeliverTx, error) { + stdtx := auth.NewStdTx([]sdk.Msg{msg}, nil, "test", 0, nil) + tx, _ := tc.cdc.MarshalBinaryLengthPrefixed(stdtx) + + return tc.cl.DeliverTxSync(abci.RequestDeliverTx{Tx: tx}) +} + +func newMockAnteHandler(cdc *wire.Codec) sdk.AnteHandler { + return func(ctx sdk.Context, tx sdk.Tx, runTxMode sdk.RunTxMode) (sdk.Context, sdk.Result, bool) { + msg := tx.GetMsgs()[0] + fee := sdkFees.GetCalculator(msg.Type())(msg) + + if ctx.IsDeliverTx() { + // add fee to pool, even it's free + stdTx := tx.(auth.StdTx) + txHash := cmn.HexBytes(tmhash.Sum(cdc.MustMarshalBinaryLengthPrefixed(stdTx))).String() + sdkFees.Pool.AddFee(txHash, fee) + } + return ctx, sdk.Result{}, false + } +} + +func UpdateContext(addr crypto.Address, ctx sdk.Context, height int64, tNow time.Time) sdk.Context { + ctx = ctx.WithBlockHeader(abci.Header{ProposerAddress: addr, Height: height, Time: tNow}).WithVoteInfos([]abci.VoteInfo{ + {Validator: abci.Validator{Address: addr, Power: 10}, SignedLastBlock: true}, + }).WithBlockHash([]byte("testhash")) + + testApp.DeliverState.Ctx = ctx + return ctx +} + +func setupTest() (crypto.Address, sdk.Context, []sdk.Account) { + // for old match engine + addr := secp256k1.GenPrivKey().PubKey().Address() + accAddr := sdk.AccAddress(addr) + baseAcc := auth.BaseAccount{Address: accAddr} + genTokens := []tokens.GenesisToken{{"BNB", "BNB", 100000000e8, accAddr, false}} + appAcc := &ctypes.AppAccount{baseAcc, "baseAcc", sdk.Coins(nil), sdk.Coins(nil), 0} + genAccs := make([]GenesisAccount, 1) + valAddr := ed25519.GenPrivKey().PubKey().Address() + genAccs[0] = NewGenesisAccount(appAcc, valAddr) + genesisState := GenesisState{ + Tokens: genTokens, + Accounts: genAccs, + DexGenesis: dex.DefaultGenesis, + ParamGenesis: pHub.DefaultGenesisState, + } + stateBytes, err := wire.MarshalJSONIndent(testApp.Codec, genesisState) + if err != nil { + panic(err) + } + testApp.SetCheckState(abci.Header{}) + testApp.InitChain(abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + AppStateBytes: stateBytes}) + // it is required in fee distribution during end block + testApp.ValAddrCache.SetAccAddr(sdk.ConsAddress(valAddr), appAcc.Address) + ctx := testApp.DeliverState.Ctx + coins := sdk.Coins{sdk.NewCoin("BNB", 1e13)} + var accs []sdk.Account + for i := 0; i < 10; i++ { + privKey := ed25519.GenPrivKey() + pubKey := privKey.PubKey() + addr := sdk.AccAddress(pubKey.Address()) + acc := &auth.BaseAccount{ + Address: addr, + Coins: coins, + } + appAcc := &ctypes.AppAccount{BaseAccount: *acc} + if testApp.AccountKeeper.GetAccount(ctx, acc.GetAddress()) == nil { + appAcc.BaseAccount.AccountNumber = testApp.AccountKeeper.GetNextAccountNumber(ctx) + } + testApp.AccountKeeper.SetAccount(ctx, appAcc) + accs = append(accs, acc) + } + + sideValAddr := accs[0].GetAddress().Bytes() + tNow := time.Now() + + // empty first block + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, -2)}) + ctx = UpdateContext(valAddr, ctx, 1, tNow.AddDate(0, 0, -2)) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + testClient.cl.EndBlockSync(abci.RequestEndBlock{}) + + // second breath block to create side chain validator + ctx = UpdateContext(valAddr, ctx, 2, tNow) + testApp.SetCheckState(abci.Header{Time: tNow.AddDate(0, 0, -2)}) + testClient.cl.BeginBlockSync(abci.RequestBeginBlock{Header: ctx.BlockHeader()}) + msg := stake.NewMsgCreateSideChainValidator(sdk.ValAddress(sideValAddr), sdk.NewCoin("BNB", 5000000000000), + stake.NewDescription("m", "i", "w", "d"), + stake.NewCommissionMsg(sdk.NewDecWithPrec(1, 4), sdk.NewDecWithPrec(1, 4), sdk.NewDecWithPrec(1, 4)), + "bsc", sideValAddr, sideValAddr) + + _, err = testClient.DeliverTxSync(&msg, testApp.Codec) + if err != nil { + panic(err) + } + testClient.cl.EndBlockSync(abci.RequestEndBlock{}) + return valAddr, ctx, accs +} + +func generatSCParamChange(s ptypes.SCParam, idx int) ptypes.SCChangeParams { + iScPrams := make([]ptypes.SCParam, 0) + cdc := amino.NewCodec() + testRegisterWire(cdc) + cdc.UnmarshalJSON([]byte(testScParams), &iScPrams) + if s != nil { + iScPrams[idx] = s + } + return ptypes.SCChangeParams{SCParams: iScPrams, Description: "test"} +} + +// Register concrete types on wire codec +func testRegisterWire(cdc *wire.Codec) { + cdc.RegisterInterface((*ptypes.SCParam)(nil), nil) + cdc.RegisterConcrete(&ibc.Params{}, "params/IbcParamSet", nil) + cdc.RegisterConcrete(&otypes.Params{}, "params/OracleParamSet", nil) + cdc.RegisterConcrete(&slashing.Params{}, "params/SlashParamSet", nil) + cdc.RegisterConcrete(&stake.Params{}, "params/StakeParamSet", nil) +} diff --git a/app/app_pub_test.go b/app/app_pub_test.go index f4853ff70..4a787f729 100644 --- a/app/app_pub_test.go +++ b/app/app_pub_test.go @@ -7,13 +7,16 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/stake" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" @@ -22,7 +25,7 @@ import ( "github.com/binance-chain/node/app/config" "github.com/binance-chain/node/app/pub" - "github.com/binance-chain/node/common/fees" + appsub "github.com/binance-chain/node/app/pub/sub" "github.com/binance-chain/node/common/testutils" orderPkg "github.com/binance-chain/node/plugins/dex/order" dextypes "github.com/binance-chain/node/plugins/dex/types" @@ -93,9 +96,13 @@ func setupAppTest(t *testing.T) (*assert.Assertions, *require.Assertions, *Binan pub.Logger = logger.With("module", "pub") pub.Cfg = app.publicationConfig pub.ToPublishCh = make(chan pub.BlockInfoToPublish, app.publicationConfig.PublicationChannelSize) + pub.ToPublishEventCh = make(chan *appsub.ToPublishEvent, app.publicationConfig.PublicationChannelSize) app.publisher = pub.NewMockMarketDataPublisher() go pub.Publish(app.publisher, app.metrics, logger, app.publicationConfig, pub.ToPublishCh) pub.IsLive = true + go pub.PublishEvent(app.publisher, logger, app.publicationConfig, pub.ToPublishEventCh) + app.startPubSub(logger) + app.subscribeEvent(logger) keeper := app.DexKeeper keeper.EnablePublish() diff --git a/app/apptest/base_test.go b/app/apptest/base_test.go index 7c5e33475..60377471e 100644 --- a/app/apptest/base_test.go +++ b/app/apptest/base_test.go @@ -4,15 +4,19 @@ import ( "os" "testing" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkfees "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/mock" - "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/x/paramHub" + abcicli "github.com/tendermint/tendermint/abci/client" "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types" cfg "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/crypto/ed25519" + . "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/tendermint/tendermint/crypto/tmhash" cmn "github.com/tendermint/tendermint/libs/common" @@ -21,10 +25,8 @@ import ( "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/app" - "github.com/binance-chain/node/common/fees" common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/dex" - "github.com/binance-chain/node/plugins/param" "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/wire" ) @@ -37,13 +39,13 @@ type TestClient struct { func NewMockAnteHandler(cdc *wire.Codec) sdk.AnteHandler { return func(ctx sdk.Context, tx sdk.Tx, runTxMode sdk.RunTxMode) (newCtx sdk.Context, result sdk.Result, abort bool) { msg := tx.GetMsgs()[0] - fee := fees.GetCalculator(msg.Type())(msg) + fee := sdkfees.GetCalculator(msg.Type())(msg) if ctx.IsDeliverTx() { // add fee to pool, even it's free stdTx := tx.(auth.StdTx) txHash := cmn.HexBytes(tmhash.Sum(cdc.MustMarshalBinaryLengthPrefixed(stdTx))).String() - fees.Pool.AddFee(txHash, fee) + sdkfees.Pool.AddFee(txHash, fee) } return newCtx, sdk.Result{}, false @@ -137,7 +139,7 @@ func GetLocked(ctx sdk.Context, add sdk.AccAddress, ccy string) int64 { func setGenesis(bapp *app.BinanceChain, tokens []tokens.GenesisToken, accs ...*common.AppAccount) error { genaccs := make([]app.GenesisAccount, len(accs)) for i, acc := range accs { - pk := ed25519.GenPrivKey().PubKey() + pk := GenPrivKey().PubKey() valAddr := pk.Address() genaccs[i] = app.NewGenesisAccount(acc, valAddr) } @@ -146,7 +148,7 @@ func setGenesis(bapp *app.BinanceChain, tokens []tokens.GenesisToken, accs ...*c Tokens: tokens, Accounts: genaccs, DexGenesis: dex.DefaultGenesis, - ParamGenesis: param.DefaultGenesisState, + ParamGenesis: paramHub.DefaultGenesisState, } stateBytes, err := wire.MarshalJSONIndent(bapp.Codec, genesisState) diff --git a/app/apptest/match_allocation_test.go b/app/apptest/match_allocation_test.go index 5c9dbd936..78e6ceb1e 100644 --- a/app/apptest/match_allocation_test.go +++ b/app/apptest/match_allocation_test.go @@ -9,6 +9,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + param "github.com/cosmos/cosmos-sdk/x/paramHub" + "github.com/stretchr/testify/assert" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" @@ -21,7 +23,6 @@ import ( "github.com/binance-chain/node/plugins/dex" "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/types" - "github.com/binance-chain/node/plugins/param" "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/wire" ) diff --git a/app/apptest/ordertx_test.go b/app/apptest/ordertx_test.go index c84b36752..63779a00a 100644 --- a/app/apptest/ordertx_test.go +++ b/app/apptest/ordertx_test.go @@ -9,9 +9,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/utils" o "github.com/binance-chain/node/plugins/dex/order" "github.com/binance-chain/node/plugins/dex/types" diff --git a/app/config/config.go b/app/config/config.go index 12228fb60..d9493c3ca 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -6,12 +6,10 @@ import ( "path/filepath" "text/template" + "github.com/cosmos/cosmos-sdk/server" "github.com/spf13/viper" - "github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/libs/common" - - "github.com/cosmos/cosmos-sdk/server" ) var configTemplate *template.Template @@ -67,6 +65,8 @@ LotSizeUpgradeHeight = {{ .UpgradeConfig.LotSizeUpgradeHeight }} ListingRuleUpgradeHeight = {{ .UpgradeConfig.ListingRuleUpgradeHeight }} # Block height of FixZeroBalanceHeight upgrade FixZeroBalanceHeight = {{ .UpgradeConfig.FixZeroBalanceHeight }} +# Block height of smart chain upgrade +LaunchBscUpgradeHeight = {{ .UpgradeConfig.LaunchBscUpgradeHeight }} # Block height of BEP8 upgrade BEP8Height = {{ .UpgradeConfig.BEP8Height }} # Block height of BEP67 upgrade @@ -125,6 +125,36 @@ publishBlock = {{ .PublicationConfig.PublishBlock }} blockTopic = "{{ .PublicationConfig.BlockTopic }}" blockKafka = "{{ .PublicationConfig.BlockKafka }}" +# Whether we want publish distribution +publishDistributeReward = {{ .PublicationConfig.PublishDistributeReward }} +distributeRewardTopic = "{{ .PublicationConfig.DistributeRewardTopic }}" +distributeRewardKafka = "{{ .PublicationConfig.DistributeRewardKafka }}" + +# Whether we want publish staking +publishStaking = {{ .PublicationConfig.PublishStaking }} +stakingTopic = "{{ .PublicationConfig.StakingTopic }}" +stakingKafka = "{{ .PublicationConfig.StakingKafka }}" + +# Whether we want publish slashing +publishSlashing = {{ .PublicationConfig.PublishSlashing }} +slashingTopic = "{{ .PublicationConfig.SlashingTopic }}" +slashingKafka = "{{ .PublicationConfig.SlashingKafka }}" + +# Whether we want publish cross transfer +publishCrossTransfer = {{ .PublicationConfig.PublishCrossTransfer }} +crossTransferTopic = "{{ .PublicationConfig.CrossTransferTopic }}" +crossTransferKafka = "{{ .PublicationConfig.CrossTransferKafka }}" + +# Whether we want publish side proposals +publishSideProposal = {{ .PublicationConfig.PublishSideProposal }} +sideProposalTopic = "{{ .PublicationConfig.SideProposalTopic }}" +sideProposalKafka = "{{ .PublicationConfig.SideProposalKafka }}" + +# Whether we want publish breatheBlock +publishBreatheBlock = {{ .PublicationConfig.PublishBreatheBlock }} +breatheBlockTopic = "{{ .PublicationConfig.BreatheBlockTopic }}" +breatheBlockKafka = "{{ .PublicationConfig.BreatheBlockKafka }}" + # Global setting publicationChannelSize = {{ .PublicationConfig.PublicationChannelSize }} publishKafka = {{ .PublicationConfig.PublishKafka }} @@ -159,6 +189,14 @@ logFilePath = "{{ .LogConfig.LogFilePath }}" # Number of logs keep in memory before writing to file logBuffSize = {{ .LogConfig.LogBuffSize }} +[cross_chain] +# IBC chain-id for current chain +ibcChainId = {{ .CrossChainConfig.IbcChainId }} +# chain-id for bsc chain +bscChainId = "{{ .CrossChainConfig.BscChainId }}" +# IBC chain-id for bsc chain +bscIbcChainId = {{ .CrossChainConfig.BscIbcChainId }} + [dex] # The suffixed symbol of BUSD BUSDSymbol = "{{ .DexConfig.BUSDSymbol }}" @@ -188,6 +226,7 @@ type BinanceChainConfig struct { *BaseConfig `mapstructure:"base"` *UpgradeConfig `mapstructure:"upgrade"` *QueryConfig `mapstructure:"query"` + *CrossChainConfig `mapstructure:"cross_chain"` *DexConfig `mapstructure:"dex"` } @@ -199,6 +238,7 @@ func DefaultBinanceChainConfig() *BinanceChainConfig { BaseConfig: defaultBaseConfig(), UpgradeConfig: defaultUpgradeConfig(), QueryConfig: defaultQueryConfig(), + CrossChainConfig: defaultCrossChainConfig(), DexConfig: defaultGovConfig(), } } @@ -248,6 +288,30 @@ type PublicationConfig struct { BlockTopic string `mapstructure:"blockTopic"` BlockKafka string `mapstructure:"blockKafka"` + PublishDistributeReward bool `mapstructure:"publishDistributeReward"` + DistributeRewardTopic string `mapstructure:"distributeRewardTopic"` + DistributeRewardKafka string `mapstructure:"distributeRewardKafka"` + + PublishStaking bool `mapstructure:"publishStaking"` + StakingTopic string `mapstructure:"stakingTopic"` + StakingKafka string `mapstructure:"stakingKafka"` + + PublishSlashing bool `mapstructure:"publishSlashing"` + SlashingTopic string `mapstructure:"slashingTopic"` + SlashingKafka string `mapstructure:"slashingKafka"` + + PublishCrossTransfer bool `mapstructure:"publishCrossTransfer"` + CrossTransferTopic string `mapstructure:"crossTransferTopic"` + CrossTransferKafka string `mapstructure:"crossTransferKafka"` + + PublishSideProposal bool `mapstructure:"publishSideProposal"` + SideProposalTopic string `mapstructure:"sideProposalTopic"` + SideProposalKafka string `mapstructure:"sideProposalKafka"` + + PublishBreatheBlock bool `mapstructure:"publichBreatheBlock"` + BreatheBlockTopic string `mapstructure:"breatheBlockTopic"` + BreatheBlockKafka string `mapstructure:"breatheBlockKafka"` + PublicationChannelSize int `mapstructure:"publicationChannelSize"` // DO NOT put this option in config file @@ -299,6 +363,30 @@ func defaultPublicationConfig() *PublicationConfig { BlockTopic: "block", BlockKafka: "127.0.0.1:9092", + PublishDistributeReward: false, + DistributeRewardTopic: "distribution", + DistributeRewardKafka: "127.0.0.1:9092", + + PublishStaking: false, + StakingTopic: "staking", + StakingKafka: "127.0.0.1:9092", + + PublishSlashing: false, + SlashingTopic: "slashing", + SlashingKafka: "127.0.0.1:9092", + + PublishCrossTransfer: false, + CrossTransferTopic: "crossTransfer", + CrossTransferKafka: "127.0.0.1:9092", + + PublishSideProposal: false, + SideProposalTopic: "sideProposal", + SideProposalKafka: "127.0.0.1:9092", + + PublishBreatheBlock: false, + BreatheBlockTopic: "breatheBlock", + BreatheBlockKafka: "127.0.0.1:9092", + PublicationChannelSize: 10000, FromHeightInclusive: 1, PublishKafka: false, @@ -322,7 +410,29 @@ func (pubCfg PublicationConfig) ShouldPublishAny() bool { pubCfg.PublishOrderBook || pubCfg.PublishBlockFee || pubCfg.PublishTransfer || - pubCfg.PublishBlock + pubCfg.PublishBlock || + pubCfg.PublishDistributeReward || + pubCfg.PublishStaking || + pubCfg.PublishSlashing || + pubCfg.PublishCrossTransfer || + pubCfg.PublishSideProposal || + pubCfg.PublishBreatheBlock +} + +type CrossChainConfig struct { + IbcChainId uint16 `mapstructure:"ibcChainId"` + + BscChainId string `mapstructure:"bscChainId"` + BscIbcChainId uint16 `mapstructure:"bscIBCChainId"` +} + +func defaultCrossChainConfig() *CrossChainConfig { + return &CrossChainConfig{ + IbcChainId: 1, + + BscChainId: "bsc", + BscIbcChainId: 2, + } } type LogConfig struct { @@ -362,7 +472,6 @@ func defaultBaseConfig() *BaseConfig { } type UpgradeConfig struct { - // Galileo Upgrade BEP6Height int64 `mapstructure:"BEP6Height"` BEP9Height int64 `mapstructure:"BEP9Height"` @@ -372,12 +481,13 @@ type UpgradeConfig struct { BEP12Height int64 `mapstructure:"BEP12Height"` // Archimedes Upgrade BEP3Height int64 `mapstructure:"BEP3Height"` - - // TODO: add upgrade name + // Heisenberg Upgrade FixSignBytesOverflowHeight int64 `mapstructure:"FixSignBytesOverflowHeight"` LotSizeUpgradeHeight int64 `mapstructure:"LotSizeUpgradeHeight"` ListingRuleUpgradeHeight int64 `mapstructure:"ListingRuleUpgradeHeight"` FixZeroBalanceHeight int64 `mapstructure:"FixZeroBalanceHeight"` + // TODO: add upgrade name + LaunchBscUpgradeHeight int64 `mapstructure:"LaunchBscUpgradeHeight"` // TODO: add upgrade name BEP8Height int64 `mapstructure:"BEP8Height"` @@ -394,13 +504,14 @@ func defaultUpgradeConfig() *UpgradeConfig { BEP19Height: 1, BEP12Height: 1, BEP3Height: 1, - FixSignBytesOverflowHeight: math.MaxInt64, - LotSizeUpgradeHeight: math.MaxInt64, - ListingRuleUpgradeHeight: math.MaxInt64, - FixZeroBalanceHeight: math.MaxInt64, - BEP8Height: math.MaxInt64, - BEP67Height: math.MaxInt64, - BEP70Height: math.MaxInt64, + FixSignBytesOverflowHeight: 1, + LotSizeUpgradeHeight: 1, + ListingRuleUpgradeHeight: 1, + FixZeroBalanceHeight: 1, + BEP8Height: 1, + BEP67Height: 1, + BEP70Height: 1, + LaunchBscUpgradeHeight: math.MaxInt64, } } diff --git a/app/fee_distribution.go b/app/fee_distribution.go index b1d295cf4..25a5601db 100644 --- a/app/fee_distribution.go +++ b/app/fee_distribution.go @@ -5,13 +5,12 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/binance-chain/node/app/pub" - "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/common/types" ) func NewValAddrCache(stakeKeeper stake.Keeper) *ValAddrCache { @@ -67,12 +66,12 @@ func distributeFee(ctx sdk.Context, am auth.AccountKeeper, valAddrCache *ValAddr validators = append(validators, string(proposerAccAddr)) // the first validator to publish should be proposer } - if fee.Type == types.FeeForProposer { + if fee.Type == sdk.FeeForProposer { // The proposer's account must be initialized before it becomes a proposer. proposerAcc := am.GetAccount(ctx, proposerAccAddr) proposerAcc.SetCoins(proposerAcc.GetCoins().Plus(fee.Tokens)) am.SetAccount(ctx, proposerAcc) - } else if fee.Type == types.FeeForAll { + } else if fee.Type == sdk.FeeForAll { log.Info("Distributing the fees to all the validators", "totalFees", fee.Tokens, "validatorSize", valSize) avgTokens := sdk.Coins{} diff --git a/app/fee_distribution_test.go b/app/fee_distribution_test.go index 1487b9151..1cb924e15 100644 --- a/app/fee_distribution_test.go +++ b/app/fee_distribution_test.go @@ -3,17 +3,19 @@ package app import ( "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/stake" - "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/app/pub" - "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/wire" @@ -83,7 +85,7 @@ func TestNoFeeDistribution(t *testing.T) { func TestFeeDistribution2Proposer(t *testing.T) { // setup am, valAddrCache, ctx, proposerAcc, _, _, _ := setup() - fees.Pool.AddAndCommitFee("DIST", types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, types.FeeForProposer)) + fees.Pool.AddAndCommitFee("DIST", sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, sdk.FeeForProposer)) blockFee := distributeFee(ctx, am, valAddrCache, true) fees.Pool.Clear() require.Equal(t, pub.BlockFee{0, "BNB:10", []string{string(proposerAcc.GetAddress())}}, blockFee) @@ -94,7 +96,7 @@ func TestFeeDistribution2AllValidators(t *testing.T) { // setup am, valAddrCache, ctx, proposerAcc, valAcc1, valAcc2, valAcc3 := setup() // fee amount can be divided evenly - fees.Pool.AddAndCommitFee("DIST", types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 40)}, types.FeeForAll)) + fees.Pool.AddAndCommitFee("DIST", sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 40)}, sdk.FeeForAll)) blockFee := distributeFee(ctx, am, valAddrCache, true) // Notice: clean the pool after distributeFee fees.Pool.Clear() @@ -102,7 +104,7 @@ func TestFeeDistribution2AllValidators(t *testing.T) { checkBalance(t, ctx, am, valAddrCache, []int64{110, 110, 110, 110}) // cannot be divided evenly - fees.Pool.AddAndCommitFee("DIST", types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 50)}, types.FeeForAll)) + fees.Pool.AddAndCommitFee("DIST", sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 50)}, sdk.FeeForAll)) blockFee = distributeFee(ctx, am, valAddrCache, true) fees.Pool.Clear() require.Equal(t, pub.BlockFee{0, "BNB:50", []string{string(proposerAcc.GetAddress()), string(valAcc1.GetAddress()), string(valAcc2.GetAddress()), string(valAcc3.GetAddress())}}, blockFee) diff --git a/app/genesis.go b/app/genesis.go index fb29d6beb..54ef912d5 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -10,13 +10,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/paramHub" + paramtypes "github.com/cosmos/cosmos-sdk/x/paramHub/types" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/tendermint/tendermint/crypto" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/plugins/dex" - "github.com/binance-chain/node/plugins/param" - paramtypes "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/plugins/tokens" "github.com/binance-chain/node/wire" ) @@ -137,7 +137,7 @@ func BinanceAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState Tokens: []tokens.GenesisToken{nativeToken}, Accounts: genAccounts, DexGenesis: dex.DefaultGenesis, - ParamGenesis: param.DefaultGenesisState, + ParamGenesis: paramHub.DefaultGenesisState, StakeData: stakeData, GenTxs: appGenTxs, GovData: govData, diff --git a/app/pub/helpers.go b/app/pub/helpers.go index c01dc541c..b048f070a 100644 --- a/app/pub/helpers.go +++ b/app/pub/helpers.go @@ -11,12 +11,12 @@ import ( abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/stake" - "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/tokens/burn" @@ -368,16 +368,24 @@ func DelistTradingPairForPublish(ctx sdk.Context, dexKeeper *orderPkg.DexKeeper, return } -func CollectProposalsForPublish(passed, failed []int64) Proposals { - totalProposals := len(passed) + len(failed) - ps := make([]*Proposal, 0, totalProposals) +func CollectProposalsForPublish(passed, failed []gov.SimpleProposal) (Proposals, SideProposals) { + ps := make([]*Proposal, 0) + sidePs := make([]*SideProposal, 0) for _, p := range passed { - ps = append(ps, &Proposal{p, Succeed}) + if p.ChainID == "" { + ps = append(ps, &Proposal{p.Id, Succeed}) + } else { + sidePs = append(sidePs, &SideProposal{p.Id, p.ChainID, Succeed}) + } } for _, p := range failed { - ps = append(ps, &Proposal{p, Failed}) + if p.ChainID == "" { + ps = append(ps, &Proposal{p.Id, Failed}) + } else { + sidePs = append(sidePs, &SideProposal{p.Id, p.ChainID, Failed}) + } } - return Proposals{totalProposals, ps} + return Proposals{len(ps), ps}, SideProposals{NumOfMsgs: len(sidePs), Proposals: sidePs} } func CollectStakeUpdatesForPublish(unbondingDelegations []stake.UnbondingDelegation) StakeUpdates { diff --git a/app/pub/metrics.go b/app/pub/metrics.go index 869d9d011..9bd6b1cba 100644 --- a/app/pub/metrics.go +++ b/app/pub/metrics.go @@ -39,6 +39,8 @@ type Metrics struct { PublishTransfersTimeMs metricsPkg.Gauge // Time used to publish block PublishBlockTimeMs metricsPkg.Gauge + // Time used to publish sideProposal + PublishSideProposalTimeMs metricsPkg.Gauge // num of trade NumTrade metricsPkg.Gauge @@ -117,6 +119,11 @@ func PrometheusMetrics() *Metrics { Name: "block_pub_time", Help: "Time to publish block info (ms)", }, []string{}), + PublishSideProposalTimeMs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{ + Subsystem: "publication", + Name: "side_proposal_pub_time", + Help: "Time to publish sideProposal (ms)", + }, []string{}), NumTrade: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{ Subsystem: "publication", diff --git a/app/pub/msgs.go b/app/pub/msgs.go index b97ca0897..a85b37f84 100644 --- a/app/pub/msgs.go +++ b/app/pub/msgs.go @@ -5,10 +5,9 @@ import ( "fmt" "strings" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/binance-chain/node/common/types" orderPkg "github.com/binance-chain/node/plugins/dex/order" + sdk "github.com/cosmos/cosmos-sdk/types" ) type msgType int8 @@ -20,6 +19,12 @@ const ( blockFeeTpe transferTpe blockTpe + stakingTpe + distributionTpe + slashingTpe + crossTransferTpe + sideProposalType + breatheBlockTpe ) var ( @@ -43,6 +48,18 @@ func (this msgType) String() string { return "Transfers" case blockTpe: return "Block" + case stakingTpe: + return "Staking" + case distributionTpe: + return "Distribution" + case slashingTpe: + return "Slashing" + case crossTransferTpe: + return "CrossTransfer" + case sideProposalType: + return "SideProposal" + case breatheBlockTpe: + return "BreatheBlock" default: return "Unknown" } @@ -59,6 +76,12 @@ var latestSchemaVersions = map[msgType]int{ blockFeeTpe: 0, transferTpe: 1, blockTpe: 0, + stakingTpe: 0, + distributionTpe: 0, + slashingTpe: 0, + crossTransferTpe: 0, + sideProposalType: 0, + breatheBlockTpe: 0, } type AvroOrJsonMsg interface { @@ -353,6 +376,30 @@ func (msg *Proposals) ToNativeMap() map[string]interface{} { return native } +type SideProposals struct { + Height int64 + Timestamp int64 + NumOfMsgs int + Proposals []*SideProposal +} + +func (msg *SideProposals) String() string { + return fmt.Sprintf("SideProposals in block: %d, numOfMsgs: %d", msg.Height, msg.NumOfMsgs) +} + +func (msg *SideProposals) ToNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["numOfMsgs"] = msg.NumOfMsgs + native["height"] = msg.Height + native["timestamp"] = msg.Timestamp + ps := make([]map[string]interface{}, len(msg.Proposals), len(msg.Proposals)) + for idx, p := range msg.Proposals { + ps[idx] = p.toNativeMap() + } + native["proposals"] = ps + return native +} + type ProposalStatus uint8 const ( @@ -387,6 +434,24 @@ func (msg *Proposal) toNativeMap() map[string]interface{} { return native } +type SideProposal struct { + Id int64 + ChainId string + Status ProposalStatus +} + +func (msg *SideProposal) String() string { + return fmt.Sprintf("SideProposal: %v", msg.toNativeMap()) +} + +func (msg *SideProposal) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["id"] = msg.Id + native["chainid"] = msg.ChainId + native["status"] = msg.Status.String() + return native +} + type StakeUpdates struct { NumOfMsgs int CompletedUnbondingDelegations []*CompletedUnbondingDelegation @@ -407,24 +472,6 @@ func (msg *StakeUpdates) ToNativeMap() map[string]interface{} { return native } -type CompletedUnbondingDelegation struct { - Validator sdk.ValAddress - Delegator sdk.AccAddress - Amount Coin -} - -func (msg *CompletedUnbondingDelegation) String() string { - return fmt.Sprintf("CompletedUnbondingDelegation: %v", msg.toNativeMap()) -} - -func (msg *CompletedUnbondingDelegation) toNativeMap() map[string]interface{} { - var native = make(map[string]interface{}) - native["validator"] = msg.Validator.String() - native["delegator"] = msg.Delegator.String() - native["amount"] = msg.Amount.ToNativeMap() - return native -} - type PriceLevel struct { Price int64 LastQty int64 @@ -891,3 +938,234 @@ func (msg NativeTransaction) ToNativeMap() map[string]interface{} { native["proposalId"] = msg.ProposalId return native } + +// distribution message +type DistributionMsg struct { + NumOfMsgs int + Height int64 + Timestamp int64 + Distributions map[string][]*Distribution +} + +func (msg *DistributionMsg) ToNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["numOfMsgs"] = msg.NumOfMsgs + native["height"] = msg.Height + native["timestamp"] = msg.Timestamp + + distributions := make(map[string]interface{}) + for chainId, v := range msg.Distributions { + items := make([]map[string]interface{}, len(v), len(v)) + for idx, item := range v { + items[idx] = item.toNativeMap() + } + distributions[chainId] = items + } + native["distributions"] = distributions + return native +} + +func (msg *DistributionMsg) String() string { + return fmt.Sprintf("DistributionMsg at height: %d, numOfMsgs: %d", msg.Height, msg.NumOfMsgs) +} + +func (msg *DistributionMsg) EssentialMsg() string { + builder := strings.Builder{} + fmt.Fprintf(&builder, "height:%d\n", msg.Height) + for chainId, diss := range msg.Distributions { + fmt.Fprintf(&builder, "chainId:%s\n", chainId) + for _, dis := range diss { + fmt.Fprintf(&builder, "validator:%s,rewards count:%d\n", dis.Validator.String(), len(dis.Rewards)) + } + } + return builder.String() +} + +func (msg *DistributionMsg) EmptyCopy() AvroOrJsonMsg { + return &DistributionMsg{ + msg.NumOfMsgs, + msg.Height, + msg.Timestamp, + make(map[string][]*Distribution), + } +} + +type Distribution struct { + Validator sdk.ValAddress + SelfDelegator sdk.AccAddress + DistributeAddr sdk.AccAddress + ValTokens int64 + TotalReward int64 + Commission int64 + Rewards []*Reward +} + +func (msg *Distribution) String() string { + return fmt.Sprintf("Distribution: %v", msg.toNativeMap()) +} + +func (msg *Distribution) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["validator"] = msg.Validator.String() + native["selfDelegator"] = msg.SelfDelegator.String() + native["distributeAddr"] = msg.DistributeAddr.String() + native["valTokens"] = msg.ValTokens + native["totalReward"] = msg.TotalReward + native["commission"] = msg.Commission + as := make([]map[string]interface{}, len(msg.Rewards), len(msg.Rewards)) + for idx, reward := range msg.Rewards { + as[idx] = reward.toNativeMap() + } + native["rewards"] = as + return native +} + +type Reward struct { + Delegator sdk.AccAddress + Tokens int64 + Amount int64 +} + +func (msg *Reward) String() string { + return fmt.Sprintf("Reward: %v", msg.toNativeMap()) +} + +func (msg *Reward) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["delegator"] = msg.Delegator.String() + native["delegationTokens"] = msg.Tokens + native["reward"] = msg.Amount + return native +} + +// slash message +type SlashMsg struct { + NumOfMsgs int + Height int64 + Timestamp int64 + SlashData map[string][]*Slash +} + +func (msg *SlashMsg) String() string { + return fmt.Sprintf("SlashMsg at height: %d, numOfMsgs: %d, slashData: %v", msg.Height, msg.NumOfMsgs, msg.SlashData) +} + +func (msg *SlashMsg) ToNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["numOfMsgs"] = msg.NumOfMsgs + native["height"] = msg.Height + native["timestamp"] = msg.Timestamp + + slashData := make(map[string]interface{}) + for chainId, v := range msg.SlashData { + items := make([]map[string]interface{}, len(v), len(v)) + for idx, item := range v { + items[idx] = item.toNativeMap() + } + slashData[chainId] = items + } + native["slashData"] = slashData + return native +} + +func (msg *SlashMsg) EssentialMsg() string { + builder := strings.Builder{} + fmt.Fprintf(&builder, "height:%d\n", msg.Height) + for chainId, slash := range msg.SlashData { + fmt.Fprintf(&builder, "chainId:%s\n, slash count: %d\n", chainId, len(slash)) + } + return builder.String() +} + +func (msg *SlashMsg) EmptyCopy() AvroOrJsonMsg { + return &SlashMsg{ + msg.NumOfMsgs, + msg.Height, + msg.Timestamp, + make(map[string][]*Slash), + } +} + +type Slash struct { + Validator sdk.ValAddress + InfractionType byte + InfractionHeight int64 + JailUtil int64 + SlashAmount int64 + ToFeePool int64 + Submitter sdk.AccAddress + SubmitterReward int64 + ValidatorsCompensation []*AllocatedAmt +} + +func (msg *Slash) String() string { + return fmt.Sprintf("Slash: %v", msg.toNativeMap()) +} + +func (msg *Slash) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["validator"] = msg.Validator.String() + native["infractionType"] = int(msg.InfractionType) + native["infractionHeight"] = msg.InfractionHeight + native["jailUtil"] = msg.JailUtil + native["slashAmount"] = msg.SlashAmount + native["toFeePool"] = msg.ToFeePool + if msg.Submitter != nil { + native["submitter"] = msg.Submitter.String() + } else { + native["submitter"] = "" + } + native["submitterReward"] = msg.SubmitterReward + + vsc := make([]map[string]interface{}, len(msg.ValidatorsCompensation), len(msg.ValidatorsCompensation)) + for idx, compensation := range msg.ValidatorsCompensation { + vsc[idx] = compensation.toNativeMap() + } + native["validatorsCompensation"] = vsc + return native +} + +type AllocatedAmt struct { + Address string + Amount int64 +} + +func (msg *AllocatedAmt) String() string { + return fmt.Sprintf("AllocatedAmt: %v", msg.toNativeMap()) +} + +func (msg *AllocatedAmt) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["address"] = msg.Address + native["amount"] = msg.Amount + return native +} + +type BreatheBlockMsg struct { + Height int64 + Timestamp int64 +} + +func (msg *BreatheBlockMsg) String() string { + return fmt.Sprintf("BreatheBlockMsg at height: %d", msg.Height) +} + +func (msg *BreatheBlockMsg) ToNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["height"] = msg.Height + native["timestamp"] = msg.Timestamp + return native +} + +func (msg *BreatheBlockMsg) EssentialMsg() string { + builder := strings.Builder{} + fmt.Fprintf(&builder, "height:%d\n", msg.Height) + return builder.String() +} + +func (msg *BreatheBlockMsg) EmptyCopy() AvroOrJsonMsg { + return &BreatheBlockMsg{ + msg.Height, + msg.Timestamp, + } +} diff --git a/app/pub/msgs_cross.go b/app/pub/msgs_cross.go new file mode 100644 index 000000000..619cd391d --- /dev/null +++ b/app/pub/msgs_cross.go @@ -0,0 +1,78 @@ +package pub + +import "fmt" + +type CrossReceiver struct { + Addr string + Amount int64 +} + +func (msg CrossReceiver) String() string { + return fmt.Sprintf("Transfer receiver %s get coin %d", msg.Addr, msg.Amount) +} + +func (msg CrossReceiver) ToNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["addr"] = msg.Addr + native["amount"] = msg.Amount + return native +} + +type CrossTransfer struct { + TxHash string + ChainId string + RelayerFee int64 + Type string + From string + Denom string + Contract string + Decimals int + To []CrossReceiver +} + +func (msg CrossTransfer) String() string { + return fmt.Sprintf("CrossTransfer: txHash: %s, from: %s, to: %v", msg.TxHash, msg.From, msg.To) +} + +func (msg CrossTransfer) ToNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["txhash"] = msg.TxHash + native["type"] = msg.Type + native["chainid"] = msg.ChainId + native["from"] = msg.From + native["denom"] = msg.Denom + native["contract"] = msg.Contract + native["decimals"] = msg.Decimals + native["relayerFee"] = msg.RelayerFee + to := make([]map[string]interface{}, len(msg.To), len(msg.To)) + for idx, t := range msg.To { + to[idx] = t.ToNativeMap() + } + native["to"] = to + return native +} + +// deliberated not implemented Ess +type CrossTransfers struct { + Height int64 + Num int + Timestamp int64 + Transfers []CrossTransfer +} + +func (msg CrossTransfers) String() string { + return fmt.Sprintf("CrossTransfers in block %d, num: %d", msg.Height, msg.Num) +} + +func (msg CrossTransfers) ToNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["height"] = msg.Height + transfers := make([]map[string]interface{}, len(msg.Transfers), len(msg.Transfers)) + for idx, t := range msg.Transfers { + transfers[idx] = t.ToNativeMap() + } + native["timestamp"] = msg.Timestamp + native["num"] = msg.Num + native["transfers"] = transfers + return native +} diff --git a/app/pub/msgs_staking.go b/app/pub/msgs_staking.go new file mode 100644 index 000000000..d26c12a36 --- /dev/null +++ b/app/pub/msgs_staking.go @@ -0,0 +1,447 @@ +package pub + +import ( + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake" +) + +// staking message +type StakingMsg struct { + NumOfMsgs int + Height int64 + Timestamp int64 + + Validators []*Validator + RemovedValidators map[string][]sdk.ValAddress + Delegations map[string][]*Delegation + UnbondingDelegations map[string][]*UnbondingDelegation + ReDelegations map[string][]*ReDelegation + CompletedUBDs map[string][]*CompletedUnbondingDelegation + CompletedREDs map[string][]*CompletedReDelegation + DelegateEvents map[string][]*DelegateEvent + UndelegateEvents map[string][]*UndelegateEvent + RedelegateEvents map[string][]*RedelegateEvent + ElectedValidators map[string][]*Validator +} + +func (msg *StakingMsg) String() string { + return fmt.Sprintf("StakingMsg at height: %d, numOfMsgs: %d", msg.Height, msg.NumOfMsgs) +} + +func (msg *StakingMsg) ToNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["numOfMsgs"] = msg.NumOfMsgs + native["height"] = msg.Height + native["timestamp"] = msg.Timestamp + + validators := make([]map[string]interface{}, len(msg.Validators)) + for id, v := range msg.Validators { + validators[id] = v.toNativeMap() + } + //native["validators"] = validators + native["validators"] = map[string]interface{}{"array": validators} + + removedValidators := make(map[string]interface{}) + for id, v := range msg.RemovedValidators { + rvs := make([]string, len(v), len(v)) + for id, rv := range v { + rvs[id] = rv.String() + } + removedValidators[id] = rvs + } + native["removedValidators"] = map[string]interface{}{"map": removedValidators} + + delegations := make(map[string]interface{}) + for chainId, v := range msg.Delegations { + dels := make([]map[string]interface{}, len(v), len(v)) + for id, vv := range v { + dels[id] = vv.toNativeMap() + } + delegations[chainId] = dels + } + //native["delegations"] = delegations + native["delegations"] = map[string]interface{}{"map": delegations} + + unBondingDelegations := make(map[string]interface{}) + for chainId, v := range msg.UnbondingDelegations { + ubds := make([]map[string]interface{}, len(v), len(v)) + for id, vv := range v { + ubds[id] = vv.toNativeMap() + } + unBondingDelegations[chainId] = ubds + } + //native["unBondingDelegations"] = unBondingDelegations + native["unBondingDelegations"] = map[string]interface{}{"map": unBondingDelegations} + + reDelegations := make(map[string]interface{}) + for chainId, v := range msg.ReDelegations { + reds := make([]map[string]interface{}, len(v), len(v)) + for id, vv := range v { + reds[id] = vv.toNativeMap() + } + reDelegations[chainId] = reds + } + //native["reDelegations"] = reDelegations + native["reDelegations"] = map[string]interface{}{"map": reDelegations} + + completedUBDs := make(map[string]interface{}) + for chainId, v := range msg.CompletedUBDs { + cubds := make([]map[string]interface{}, len(v), len(v)) + for id, vv := range v { + cubds[id] = vv.toNativeMap() + } + completedUBDs[chainId] = cubds + } + //native["completedUBDs"] = completedUBDs + native["completedUBDs"] = map[string]interface{}{"map": completedUBDs} + + completedREDs := make(map[string]interface{}) + for chainId, v := range msg.CompletedREDs { + creds := make([]map[string]interface{}, len(v), len(v)) + for id, vv := range v { + creds[id] = vv.toNativeMap() + } + completedREDs[chainId] = creds + } + //native["completedREDs"] = completedREDs + native["completedREDs"] = map[string]interface{}{"map": completedREDs} + + delegateEvents := make(map[string]interface{}) + for chainId, v := range msg.DelegateEvents { + deles := make([]map[string]interface{}, len(v), len(v)) + for id, vv := range v { + deles[id] = vv.toNativeMap() + } + delegateEvents[chainId] = deles + } + native["delegateEvents"] = map[string]interface{}{"map": delegateEvents} + + unDelegateEvents := make(map[string]interface{}) + for chainId, v := range msg.UndelegateEvents { + undeles := make([]map[string]interface{}, len(v), len(v)) + for id, vv := range v { + undeles[id] = vv.toNativeMap() + } + unDelegateEvents[chainId] = undeles + } + native["unDelegateEvents"] = map[string]interface{}{"map": unDelegateEvents} + + reDelegateEvents := make(map[string]interface{}) + for chainId, v := range msg.RedelegateEvents { + redeles := make([]map[string]interface{}, len(v), len(v)) + for id, vv := range v { + redeles[id] = vv.toNativeMap() + } + reDelegateEvents[chainId] = redeles + } + native["reDelegateEvents"] = map[string]interface{}{"map": reDelegateEvents} + + electedValidators := make(map[string]interface{}) + for id, v := range msg.ElectedValidators { + evs := make([]map[string]interface{}, len(v), len(v)) + for id, ev := range v { + evs[id] = ev.toNativeMap() + } + electedValidators[id] = evs + } + native["electedValidators"] = map[string]interface{}{"map": electedValidators} + + return native +} + +func (msg *StakingMsg) EssentialMsg() string { + builder := strings.Builder{} + fmt.Fprintf(&builder, "height:%d\n", msg.Height) + if len(msg.Validators) > 0 { + fmt.Fprintf(&builder, "validators: numOfMsg: %d\n", len(msg.Validators)) + } + if len(msg.RemovedValidators) > 0 { + fmt.Fprintf(&builder, "removed validators: numOfMsg: %d\n", len(msg.RemovedValidators)) + } + if len(msg.Delegations) > 0 { + fmt.Fprintf(&builder, "delegations:\n") + for chainId, v := range msg.Delegations { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(v)) + } + } + if len(msg.UnbondingDelegations) > 0 { + fmt.Fprintf(&builder, "unbondingDelegations:\n") + for chainId, v := range msg.UnbondingDelegations { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(v)) + } + } + if len(msg.ReDelegations) > 0 { + fmt.Fprintf(&builder, "reDelegations:\n") + for chainId, v := range msg.ReDelegations { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(v)) + } + } + if len(msg.CompletedREDs) > 0 { + fmt.Fprintf(&builder, "completedREDs:\n") + for chainId, v := range msg.CompletedREDs { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(v)) + } + } + if len(msg.CompletedUBDs) > 0 { + fmt.Fprintf(&builder, "completedUBDs:\n") + for chainId, ubds := range msg.CompletedUBDs { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(ubds)) + } + } + if len(msg.DelegateEvents) > 0 { + fmt.Fprintf(&builder, "delegateEvents:\n") + for chainId, dels := range msg.DelegateEvents { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(dels)) + } + } + if len(msg.UndelegateEvents) > 0 { + fmt.Fprintf(&builder, "undelegateEvents:\n") + for chainId, udes := range msg.UndelegateEvents { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(udes)) + } + } + if len(msg.RedelegateEvents) > 0 { + fmt.Fprintf(&builder, "redelegateEvents:\n") + for chainId, rdes := range msg.RedelegateEvents { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(rdes)) + } + } + if len(msg.ElectedValidators) > 0 { + fmt.Fprintf(&builder, "electedValidators:\n") + for chainId, evs := range msg.ElectedValidators { + fmt.Fprintf(&builder, "chainId:%s, numOfMsg: %d\n", chainId, len(evs)) + } + } + return builder.String() +} + +func (msg *StakingMsg) EmptyCopy() AvroOrJsonMsg { + return &StakingMsg{ + msg.NumOfMsgs, + msg.Height, + msg.Timestamp, + make([]*Validator, 0), + make(map[string][]sdk.ValAddress), + make(map[string][]*Delegation), + make(map[string][]*UnbondingDelegation), + make(map[string][]*ReDelegation), + make(map[string][]*CompletedUnbondingDelegation), + make(map[string][]*CompletedReDelegation), + make(map[string][]*DelegateEvent), + make(map[string][]*UndelegateEvent), + make(map[string][]*RedelegateEvent), + make(map[string][]*Validator), + } +} + +type Validator stake.Validator + +func (msg *Validator) String() string { + return fmt.Sprintf("NewValidator: %v", msg.toNativeMap()) +} + +func (msg *Validator) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["feeAddr"] = msg.FeeAddr.String() + native["operatorAddr"] = msg.OperatorAddr.String() + if msg.ConsPubKey != nil { + native["consAddr"] = sdk.ConsAddress(msg.ConsPubKey.Address()).String() + } + native["jailed"] = msg.Jailed + + native["status"] = sdk.BondStatusToString(msg.Status) + native["tokens"] = msg.Tokens.RawInt() + native["delegatorShares"] = msg.DelegatorShares.RawInt() + + description := make(map[string]interface{}) + description["moniker"] = msg.Description.Moniker + description["identity"] = msg.Description.Identity + description["website"] = msg.Description.Website + description["details"] = msg.Description.Details + native["description"] = description + + native["bondHeight"] = msg.BondHeight + native["bondIntraTxCounter"] = int(msg.BondIntraTxCounter) + + commission := make(map[string]interface{}) + commission["rate"] = msg.Commission.Rate.RawInt() + commission["maxRate"] = msg.Commission.MaxRate.RawInt() + commission["maxChangeRate"] = msg.Commission.MaxChangeRate.RawInt() + commission["updateTime"] = msg.Commission.UpdateTime.Unix() + native["commission"] = commission + + native["distributionAddr"] = msg.DistributionAddr.String() + native["sideChainId"] = msg.SideChainId + native["sideConsAddr"] = sdk.HexAddress(msg.SideConsAddr) + native["sideFeeAddr"] = sdk.HexAddress(msg.SideFeeAddr) + + return native +} + +type Delegation stake.Delegation + +func (msg *Delegation) String() string { + return fmt.Sprintf("Delegate: %v", msg.toNativeMap()) +} + +func (msg *Delegation) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["delegator"] = msg.DelegatorAddr.String() + native["validator"] = msg.ValidatorAddr.String() + native["shares"] = msg.Shares.RawInt() + return native +} + +type UnbondingDelegation stake.UnbondingDelegation + +func (msg *UnbondingDelegation) String() string { + return fmt.Sprintf("UnDelegate: %v", msg.toNativeMap()) +} + +func (msg *UnbondingDelegation) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["delegator"] = msg.DelegatorAddr.String() + native["validator"] = msg.ValidatorAddr.String() + native["creationHeight"] = msg.CreationHeight + initialBalance := Coin{ + Denom: msg.InitialBalance.Denom, + Amount: msg.InitialBalance.Amount, + } + native["initialBalance"] = initialBalance.ToNativeMap() + balance := Coin{ + Denom: msg.Balance.Denom, + Amount: msg.Balance.Amount, + } + native["balance"] = balance.ToNativeMap() + native["minTime"] = msg.MinTime.Unix() + return native +} + +type ReDelegation stake.Redelegation + +func (msg *ReDelegation) String() string { + return fmt.Sprintf("ReDelegate: %v", msg.toNativeMap()) +} + +func (msg *ReDelegation) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["delegator"] = msg.DelegatorAddr.String() + native["srcValidator"] = msg.ValidatorSrcAddr.String() + native["dstValidator"] = msg.ValidatorDstAddr.String() + native["creationHeight"] = msg.CreationHeight + native["sharesSrc"] = msg.SharesSrc.RawInt() + native["sharesDst"] = msg.SharesDst.RawInt() + initialBalance := Coin{ + Denom: msg.InitialBalance.Denom, + Amount: msg.InitialBalance.Amount, + } + native["initialBalance"] = initialBalance.ToNativeMap() + balance := Coin{ + Denom: msg.Balance.Denom, + Amount: msg.Balance.Amount, + } + native["balance"] = balance.ToNativeMap() + native["minTime"] = msg.MinTime.Unix() + return native +} + +type CompletedUnbondingDelegation struct { + Validator sdk.ValAddress + Delegator sdk.AccAddress + Amount Coin +} + +func (msg *CompletedUnbondingDelegation) String() string { + return fmt.Sprintf("CompletedUnbondingDelegation: %v", msg.toNativeMap()) +} + +func (msg *CompletedUnbondingDelegation) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["validator"] = msg.Validator.String() + native["delegator"] = msg.Delegator.String() + native["amount"] = msg.Amount.ToNativeMap() + return native +} + +type CompletedReDelegation struct { + Delegator sdk.AccAddress + ValidatorSrc sdk.ValAddress + ValidatorDst sdk.ValAddress +} + +func (msg *CompletedReDelegation) String() string { + return fmt.Sprintf("CompletedReDelegation: %v", msg.toNativeMap()) +} + +func (msg *CompletedReDelegation) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["delegator"] = msg.Delegator.String() + native["srcValidator"] = msg.ValidatorSrc.String() + native["dstValidator"] = msg.ValidatorDst.String() + return native +} + +type DelegateEvent struct { + Delegator sdk.AccAddress + Validator sdk.ValAddress + Amount Coin + TxHash string +} + +func (msg *DelegateEvent) String() string { + return fmt.Sprintf("DelegateEvent: %v", msg.toNativeMap()) +} + +func (msg *DelegateEvent) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["delegator"] = msg.Delegator.String() + native["validator"] = msg.Validator.String() + native["amount"] = msg.Amount.ToNativeMap() + native["txHash"] = msg.TxHash + return native +} + +type UndelegateEvent struct { + Delegator sdk.AccAddress + Validator sdk.ValAddress + Amount Coin + TxHash string +} + +func (msg *UndelegateEvent) String() string { + return fmt.Sprintf("UndelegateEvent: %v", msg.toNativeMap()) +} + +func (msg *UndelegateEvent) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["delegator"] = msg.Delegator.String() + native["validator"] = msg.Validator.String() + native["amount"] = msg.Amount.ToNativeMap() + native["txHash"] = msg.TxHash + return native +} + +type RedelegateEvent struct { + Delegator sdk.AccAddress + ValidatorSrc sdk.ValAddress + ValidatorDst sdk.ValAddress + Amount Coin + TxHash string +} + +func (msg *RedelegateEvent) String() string { + return fmt.Sprintf("RedelegateEvent: %v", msg.toNativeMap()) +} + +func (msg *RedelegateEvent) toNativeMap() map[string]interface{} { + var native = make(map[string]interface{}) + native["delegator"] = msg.Delegator.String() + native["srcValidator"] = msg.ValidatorSrc.String() + native["dstValidator"] = msg.ValidatorDst.String() + native["amount"] = msg.Amount.ToNativeMap() + native["txHash"] = msg.TxHash + return native +} diff --git a/app/pub/publisher.go b/app/pub/publisher.go index 653ec0f0d..3283682a9 100644 --- a/app/pub/publisher.go +++ b/app/pub/publisher.go @@ -4,9 +4,12 @@ import ( "fmt" "time" + sdk "github.com/cosmos/cosmos-sdk/types" + tmlog "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/app/config" + "github.com/binance-chain/node/app/pub/sub" orderPkg "github.com/binance-chain/node/plugins/dex/order" ) @@ -29,6 +32,8 @@ var ( ToPublishCh chan BlockInfoToPublish ToRemoveOrderIdCh chan OrderSymbolId // order symbol and ids to remove from keeper.OrderInfoForPublish IsLive bool + + ToPublishEventCh chan *sub.ToPublishEvent ) type MarketDataPublisher interface { @@ -36,6 +41,360 @@ type MarketDataPublisher interface { Stop() } +func PublishEvent( + publisher MarketDataPublisher, + Logger tmlog.Logger, + cfg *config.PublicationConfig, + ToPublishEventCh <-chan *sub.ToPublishEvent) { + for toPublish := range ToPublishEventCh { + eventData := toPublish.EventData + Logger.Debug("publisher queue status", "size", len(ToPublishCh)) + if cfg.PublishStaking { + var msgNum int + var validators []*Validator + var removedValidators map[string][]sdk.ValAddress + var delegationsMap map[string][]*Delegation + var ubdsMap map[string][]*UnbondingDelegation + var redsMap map[string][]*ReDelegation + var completedUBDsMap map[string][]*CompletedUnbondingDelegation + var completedREDsMap map[string][]*CompletedReDelegation + var delegateEventsMap map[string][]*DelegateEvent + var undelegateEventsMap map[string][]*UndelegateEvent + var redelegateEventsMap map[string][]*RedelegateEvent + var electedValidatorsMap map[string][]*Validator + + if eventData.StakeData != nil { + if len(eventData.StakeData.Validators) > 0 { + validators = make([]*Validator, len(eventData.StakeData.Validators), len(eventData.StakeData.Validators)) + msgNum += len(eventData.StakeData.Validators) + var i int + for _, val := range eventData.StakeData.Validators { + v := Validator(val) + validators[i] = &v + i++ + } + } + if len(eventData.StakeData.RemovedValidators) > 0 { + removedValidators = make(map[string][]sdk.ValAddress) + for chainId, removedVals := range eventData.StakeData.RemovedValidators { + vals := make([]sdk.ValAddress, len(removedVals), len(removedVals)) + msgNum += len(removedVals) + var i int + for _, val := range removedVals { + vals[i] = val + i++ + } + removedValidators[chainId] = vals + } + } + if len(eventData.StakeData.Delegations) > 0 || len(eventData.StakeData.RemovedDelegations) > 0 { + delegationsMap = make(map[string][]*Delegation) + for chainId, dels := range eventData.StakeData.Delegations { + delegations := make([]*Delegation, len(dels), len(dels)) + msgNum += len(dels) + var i int + for _, del := range dels { + d := Delegation(del) + delegations[i] = &d + i++ + } + delegationsMap[chainId] = delegations + } + + for chainId, removedDels := range eventData.StakeData.RemovedDelegations { + if delegationsMap[chainId] == nil { + delegationsMap[chainId] = make([]*Delegation, 0) + } + msgNum += len(removedDels) + for _, dvPair := range removedDels { + d := Delegation{ + DelegatorAddr: dvPair.DelegatorAddr, + ValidatorAddr: dvPair.ValidatorAddr, + Shares: sdk.ZeroDec(), + } + delegationsMap[chainId] = append(delegationsMap[chainId], &d) + } + + } + } + if len(eventData.StakeData.UnbondingDelegations) > 0 { + ubdsMap = make(map[string][]*UnbondingDelegation) + for chainId, ubds := range eventData.StakeData.UnbondingDelegations { + unbondingDelegations := make([]*UnbondingDelegation, len(ubds), len(ubds)) + msgNum += len(ubds) + var i int + for _, ubd := range ubds { + u := UnbondingDelegation(ubd) + unbondingDelegations[i] = &u + i++ + } + ubdsMap[chainId] = unbondingDelegations + } + } + if len(eventData.StakeData.ReDelegations) > 0 { + redsMap = make(map[string][]*ReDelegation) + for chainId, reds := range eventData.StakeData.ReDelegations { + redelgations := make([]*ReDelegation, len(reds), len(reds)) + msgNum += len(reds) + var i int + for _, red := range reds { + r := ReDelegation(red) + redelgations[i] = &r + i++ + } + redsMap[chainId] = redelgations + } + } + if len(eventData.StakeData.CompletedUBDs) > 0 { + completedUBDsMap = make(map[string][]*CompletedUnbondingDelegation) + for chainId, ubds := range eventData.StakeData.CompletedUBDs { + comUBDs := make([]*CompletedUnbondingDelegation, len(ubds), len(ubds)) + msgNum += len(ubds) + for i, ubd := range ubds { + comUBDs[i] = &CompletedUnbondingDelegation{ + Validator: ubd.Validator, + Delegator: ubd.Delegator, + Amount: Coin{Denom: ubd.Amount.Denom, Amount: ubd.Amount.Amount}, + } + } + completedUBDsMap[chainId] = comUBDs + } + } + if len(eventData.StakeData.CompletedREDs) > 0 { + completedREDsMap = make(map[string][]*CompletedReDelegation) + for chainId, reds := range eventData.StakeData.CompletedREDs { + comREDs := make([]*CompletedReDelegation, len(reds), len(reds)) + msgNum += len(reds) + for i, red := range reds { + comREDs[i] = &CompletedReDelegation{ + Delegator: red.DelegatorAddr, + ValidatorSrc: red.ValidatorSrcAddr, + ValidatorDst: red.ValidatorDstAddr, + } + } + completedREDsMap[chainId] = comREDs + } + } + if len(eventData.StakeData.DelegateEvents) > 0 { + delegateEventsMap = make(map[string][]*DelegateEvent) + for chainId, des := range eventData.StakeData.DelegateEvents { + dess := make([]*DelegateEvent, len(des), len(des)) + msgNum += len(des) + for i, de := range des { + dess[i] = &DelegateEvent{ + Delegator: de.Delegator, + Validator: de.Validator, + Amount: Coin{ + Denom: de.Denom, + Amount: de.Amount, + }, + TxHash: de.TxHash, + } + } + delegateEventsMap[chainId] = dess + } + } + if len(eventData.StakeData.UndelegateEvents) > 0 { + undelegateEventsMap = make(map[string][]*UndelegateEvent) + for chainId, v := range eventData.StakeData.UndelegateEvents { + vv := make([]*UndelegateEvent, len(v), len(v)) + msgNum += len(v) + for i, ude := range v { + vv[i] = &UndelegateEvent{ + Delegator: ude.Delegator, + Validator: ude.Validator, + Amount: Coin{ + Denom: ude.Denom, + Amount: ude.Amount, + }, + TxHash: ude.TxHash, + } + } + undelegateEventsMap[chainId] = vv + } + } + if len(eventData.StakeData.RedelegateEvents) > 0 { + redelegateEventsMap = make(map[string][]*RedelegateEvent) + for chainId, v := range eventData.StakeData.RedelegateEvents { + vv := make([]*RedelegateEvent, len(v), len(v)) + msgNum += len(v) + for i, ude := range v { + vv[i] = &RedelegateEvent{ + Delegator: ude.Delegator, + ValidatorSrc: ude.SrcValidator, + ValidatorDst: ude.DstValidator, + Amount: Coin{ + Denom: ude.Denom, + Amount: ude.Amount, + }, + TxHash: ude.TxHash, + } + } + redelegateEventsMap[chainId] = vv + } + } + if len(eventData.StakeData.ElectedValidators) > 0 { + electedValidatorsMap = make(map[string][]*Validator) + for chainId, vals := range eventData.StakeData.ElectedValidators { + msgNum += len(vals) + electedVals := make([]*Validator, len(vals), len(vals)) + for i := range vals { + val := Validator(vals[i]) + electedVals[i] = &val + } + electedValidatorsMap[chainId] = electedVals + } + } + } + + msg := StakingMsg{ + NumOfMsgs: msgNum, + Height: toPublish.Height, + Timestamp: toPublish.Timestamp.Unix(), + + Validators: validators, + RemovedValidators: removedValidators, + Delegations: delegationsMap, + UnbondingDelegations: ubdsMap, + ReDelegations: redsMap, + CompletedUBDs: completedUBDsMap, + CompletedREDs: completedREDsMap, + DelegateEvents: delegateEventsMap, + UndelegateEvents: undelegateEventsMap, + RedelegateEvents: redelegateEventsMap, + ElectedValidators: electedValidatorsMap, + } + publisher.publish(&msg, stakingTpe, toPublish.Height, toPublish.Timestamp.UnixNano()) + } + + if cfg.PublishDistributeReward { + var msgNum int + distributions := make(map[string][]*Distribution) + if eventData.StakeData != nil { + for chainId, disData := range eventData.StakeData.Distribution { + dis := make([]*Distribution, len(disData), len(disData)) + for i, disData := range disData { + rewards := make([]*Reward, len(disData.Rewards), len(disData.Rewards)) + for i, reward := range disData.Rewards { + delegatorTokens, err := sdk.MulQuoDec(disData.ValTokens, reward.Shares, disData.ValShares) + if err != nil { + Logger.Error("error convert shares to tokens, delegator: %s", reward.AccAddr) + continue + } + rewardMsg := &Reward{ + Delegator: reward.AccAddr, + Amount: reward.Amount, + Tokens: delegatorTokens.RawInt(), + } + rewards[i] = rewardMsg + } + dis[i] = &Distribution{ + Validator: disData.Validator, + SelfDelegator: disData.SelfDelegator, + DistributeAddr: disData.DistributeAddr, + ValTokens: disData.ValTokens.RawInt(), + TotalReward: disData.TotalReward.RawInt(), + Commission: disData.Commission.RawInt(), + Rewards: rewards, + } + msgNum += len(disData.Rewards) + } + distributions[chainId] = dis + } + } + + distributionMsg := DistributionMsg{ + NumOfMsgs: msgNum, + Height: toPublish.Height, + Timestamp: toPublish.Timestamp.Unix(), + Distributions: distributions, + } + publisher.publish(&distributionMsg, distributionTpe, toPublish.Height, toPublish.Timestamp.UnixNano()) + } + + if cfg.PublishSlashing { + var msgNum int + slashData := make(map[string][]*Slash) + for chainId, slashes := range eventData.SlashData { + slashDataPerChain := make([]*Slash, len(slashes), len(slashes)) + for i, slash := range slashes { + + vc := make([]*AllocatedAmt, len(slash.ValidatorsCompensation)) + var idx int + for address, amount := range slash.ValidatorsCompensation { + vc[idx] = &AllocatedAmt{Address: sdk.AccAddress([]byte(address)).String(), Amount: amount} + idx++ + } + + slashDataPerChain[i] = &Slash{ + Validator: slash.Validator, + InfractionType: slash.InfractionType, + InfractionHeight: slash.InfractionHeight, + JailUtil: slash.JailUtil.Unix(), + SlashAmount: slash.SlashAmount, + ToFeePool: slash.ToFeePool, + Submitter: slash.Submitter, + SubmitterReward: slash.SubmitterReward, + ValidatorsCompensation: vc, + } + msgNum++ + } + slashData[chainId] = slashDataPerChain + } + + slashMsg := SlashMsg{ + NumOfMsgs: msgNum, + Height: toPublish.Height, + Timestamp: toPublish.Timestamp.Unix(), + SlashData: slashData, + } + publisher.publish(&slashMsg, slashingTpe, toPublish.Height, toPublish.Timestamp.UnixNano()) + + } + + if cfg.PublishCrossTransfer { + var msgNum int + crossTransfers := make([]CrossTransfer, 0) + + for _, crossTransfer := range eventData.CrossTransferData { + msgNum++ + ct := CrossTransfer{ + TxHash: crossTransfer.TxHash, + ChainId: crossTransfer.ChainId, + RelayerFee: crossTransfer.RelayerFee, + Type: crossTransfer.Type, + From: crossTransfer.From, + Denom: crossTransfer.Denom, + Contract: crossTransfer.Contract, + Decimals: crossTransfer.Decimals, + } + for _, receive := range crossTransfer.To { + ct.To = append(ct.To, CrossReceiver{ + Addr: receive.Addr, + Amount: receive.Amount, + }) + } + crossTransfers = append(crossTransfers, ct) + } + crossTransferMsg := CrossTransfers{ + Num: msgNum, + Height: toPublish.Height, + Timestamp: toPublish.Timestamp.Unix(), + Transfers: crossTransfers, + } + publisher.publish(&crossTransferMsg, crossTransferTpe, toPublish.Height, toPublish.Timestamp.UnixNano()) + } + + if cfg.PublishBreatheBlock && toPublish.IsBreatheBlock { + breatheBlockMsg := BreatheBlockMsg{ + Height: toPublish.Height, + Timestamp: toPublish.Timestamp.UnixNano(), + } + publisher.publish(&breatheBlockMsg, breatheBlockTpe, toPublish.Height, toPublish.Timestamp.UnixNano()) + } + } +} + func Publish( publisher MarketDataPublisher, metrics *Metrics, @@ -156,6 +515,15 @@ func Publish( } } + if cfg.PublishSideProposal { + duration := Timer(Logger, "publish side chain proposal", func() { + publishSideProposals(publisher, marketData.height, marketData.timestamp, marketData.sideProposals) + }) + if metrics != nil { + metrics.PublishSideProposalTimeMs.Set(float64(duration)) + } + } + if metrics != nil { metrics.PublicationHeight.Set(float64(marketData.height)) blockInterval := time.Since(lastPublishedTime) @@ -269,6 +637,14 @@ func publishTransfers(publisher MarketDataPublisher, height, timestamp int64, tr } } +func publishSideProposals(publisher MarketDataPublisher, height, timestamp int64, sideProposals *SideProposals) { + if sideProposals != nil { + sideProposals.Height = height + sideProposals.Timestamp = timestamp + publisher.publish(sideProposals, sideProposalType, height, timestamp) + } +} + func publishBlock(publisher MarketDataPublisher, height, timestamp int64, block *Block) { if block != nil { publisher.publish(block, blockTpe, height, timestamp) diff --git a/app/pub/publisher_kafka.go b/app/pub/publisher_kafka.go index 0deb6b62c..ec8f2943d 100644 --- a/app/pub/publisher_kafka.go +++ b/app/pub/publisher_kafka.go @@ -31,6 +31,12 @@ type KafkaMarketDataPublisher struct { blockFeeCodec *goavro.Codec transfersCodec *goavro.Codec blockCodec *goavro.Codec + stakingCodec *goavro.Codec + distributionCodec *goavro.Codec + slashingCodec *goavro.Codec + crossTransferCodec *goavro.Codec + sideProposalCodec *goavro.Codec + breatheBlockCodec *goavro.Codec failFast bool essentialLogPath string // the path (default to db dir) we write essential file to make up data on kafka error @@ -138,6 +144,66 @@ func (publisher *KafkaMarketDataPublisher) newProducers() (config *sarama.Config return } } + if Cfg.PublishStaking { + if _, ok := publisher.producers[Cfg.StakingTopic]; !ok { + publisher.producers[Cfg.StakingTopic], err = + publisher.connectWithRetry(strings.Split(Cfg.StakingKafka, KafkaBrokerSep), config) + } + if err != nil { + Logger.Error("failed to create staking producer", "err", err) + return + } + } + if Cfg.PublishDistributeReward { + if _, ok := publisher.producers[Cfg.DistributeRewardTopic]; !ok { + publisher.producers[Cfg.DistributeRewardTopic], err = + publisher.connectWithRetry(strings.Split(Cfg.DistributeRewardKafka, KafkaBrokerSep), config) + } + if err != nil { + Logger.Error("failed to create distribution producer", "err", err) + return + } + } + if Cfg.PublishSlashing { + if _, ok := publisher.producers[Cfg.SlashingTopic]; !ok { + publisher.producers[Cfg.SlashingTopic], err = + publisher.connectWithRetry(strings.Split(Cfg.SlashingKafka, KafkaBrokerSep), config) + } + if err != nil { + Logger.Error("failed to create slashing producer", "err", err) + return + } + } + if Cfg.PublishCrossTransfer { + if _, ok := publisher.producers[Cfg.CrossTransferTopic]; !ok { + publisher.producers[Cfg.CrossTransferTopic], err = + publisher.connectWithRetry(strings.Split(Cfg.CrossTransferKafka, KafkaBrokerSep), config) + } + if err != nil { + Logger.Error("failed to create crossTransfer producer", "err", err) + return + } + } + if Cfg.PublishSideProposal { + if _, ok := publisher.producers[Cfg.SideProposalTopic]; !ok { + publisher.producers[Cfg.SideProposalTopic], err = + publisher.connectWithRetry(strings.Split(Cfg.SideProposalKafka, KafkaBrokerSep), config) + } + if err != nil { + Logger.Error("failed to create crossTransfer producer", "err", err) + return + } + } + if Cfg.PublishBreatheBlock { + if _, ok := publisher.producers[Cfg.BreatheBlockTopic]; !ok { + publisher.producers[Cfg.BreatheBlockTopic], err = + publisher.connectWithRetry(strings.Split(Cfg.BreatheBlockKafka, KafkaBrokerSep), config) + } + if err != nil { + Logger.Error("failed to create breathe block producer", "err", err) + return + } + } return } @@ -221,6 +287,18 @@ func (publisher KafkaMarketDataPublisher) resolveTopic(tpe msgType) (topic strin topic = Cfg.TransferTopic case blockTpe: topic = Cfg.BlockTopic + case stakingTpe: + topic = Cfg.StakingTopic + case distributionTpe: + topic = Cfg.DistributeRewardTopic + case slashingTpe: + topic = Cfg.SlashingTopic + case crossTransferTpe: + topic = Cfg.CrossTransferTopic + case sideProposalType: + topic = Cfg.SideProposalTopic + case breatheBlockTpe: + topic = Cfg.BreatheBlockTopic } return } @@ -299,6 +377,18 @@ func (publisher *KafkaMarketDataPublisher) marshal(msg AvroOrJsonMsg, tpe msgTyp codec = publisher.transfersCodec case blockTpe: codec = publisher.blockCodec + case stakingTpe: + codec = publisher.stakingCodec + case distributionTpe: + codec = publisher.distributionCodec + case slashingTpe: + codec = publisher.slashingCodec + case crossTransferTpe: + codec = publisher.crossTransferCodec + case sideProposalType: + codec = publisher.sideProposalCodec + case breatheBlockTpe: + codec = publisher.breatheBlockCodec default: return nil, fmt.Errorf("doesn't support marshal kafka msg tpe: %s", tpe.String()) } @@ -322,6 +412,18 @@ func (publisher *KafkaMarketDataPublisher) initAvroCodecs() (err error) { return err } else if publisher.blockCodec, err = goavro.NewCodec(blockDatasSchema); err != nil { return err + } else if publisher.stakingCodec, err = goavro.NewCodec(stakingSchema); err != nil { + return err + } else if publisher.distributionCodec, err = goavro.NewCodec(distributionSchema); err != nil { + return err + } else if publisher.slashingCodec, err = goavro.NewCodec(slashingSchema); err != nil { + return err + } else if publisher.crossTransferCodec, err = goavro.NewCodec(crossTransferSchema); err != nil { + return err + } else if publisher.sideProposalCodec, err = goavro.NewCodec(sideProposalsSchema); err != nil { + return err + } else if publisher.breatheBlockCodec, err = goavro.NewCodec(breatheBlockSchema); err != nil { + return err } return nil } diff --git a/app/pub/schema_test.go b/app/pub/schema_test.go index bcf3987e5..b8da53e7e 100644 --- a/app/pub/schema_test.go +++ b/app/pub/schema_test.go @@ -4,6 +4,9 @@ import ( "encoding/json" "os" "testing" + "time" + + "github.com/linkedin/goavro" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" @@ -126,3 +129,121 @@ func TestBlockMarsha(t *testing.T) { t.Fatal(err) } } + +func TestCrossTransferMarsha(t *testing.T) { + publisher := NewKafkaMarketDataPublisher(Logger, "", false) + msg := CrossTransfers{ + Height: 10, + Num: 2, + Timestamp: time.Now().Unix(), + Transfers: []CrossTransfer{ + {TxHash: "xxxx", ChainId: "rialto", Type: "xx", From: "xxxx", RelayerFee: 1, Denom: "BNB", To: []CrossReceiver{{Addr: "xxxx", Amount: 100}}}, + {TxHash: "xxxx", ChainId: "rialto", Type: "xx", From: "xxxx", RelayerFee: 0, Denom: "BNB", To: []CrossReceiver{{Addr: "xxxx", Amount: 100}}}, + }, + } + _, err := publisher.marshal(&msg, crossTransferTpe) + if err != nil { + t.Fatal(err) + } +} + +func TestSideProposalMarsha(t *testing.T) { + publisher := NewKafkaMarketDataPublisher(Logger, "", false) + msg := SideProposals{ + Height: 10, + NumOfMsgs: 2, + Timestamp: time.Now().Unix(), + Proposals: []*SideProposal{ + {Id: 100, ChainId: "rialto", Status: Succeed}, + {Id: 101, ChainId: "rialto", Status: Failed}, + }, + } + _, err := publisher.marshal(&msg, sideProposalType) + if err != nil { + t.Fatal(err) + } +} + +func TestStakingMarshaling(t *testing.T) { + publisher := NewKafkaMarketDataPublisher(Logger, "", false) + valAddr, _ := sdk.ValAddressFromBech32("bva1e2y8w2rz957lahwy0y5h3w53sm8d78qexkn3rh") + delAddr, _ := sdk.AccAddressFromBech32("bnb1e2y8w2rz957lahwy0y5h3w53sm8d78qex2jpan") + + dels := make(map[string][]*Delegation) + dels["chain-id-1"] = []*Delegation{{ + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, + Shares: sdk.NewDecWithoutFra(1), + }} + + removedVals := make(map[string][]sdk.ValAddress) + removedVals["chain-id-1"] = []sdk.ValAddress{sdk.ValAddress(valAddr)} + + msg := StakingMsg{ + NumOfMsgs: 42, Height: 20, Timestamp: 1000, + Validators: []*Validator{{ + FeeAddr: delAddr, + OperatorAddr: valAddr, + Status: 1, + DelegatorShares: sdk.NewDecWithoutFra(10000), + }}, + RemovedValidators: removedVals, + Delegations: dels, + DelegateEvents: map[string][]*DelegateEvent{"chain-id-1": {&DelegateEvent{delAddr, valAddr, Coin{Denom: "BNB", Amount: 99999999}, "0xadkjgege"}}}, + ElectedValidators: map[string][]*Validator{"chain-id-1": {&Validator{ + FeeAddr: delAddr, + OperatorAddr: valAddr, + Status: 1, + DelegatorShares: sdk.NewDecWithoutFra(10000), + }}}, + } + bz, err := publisher.marshal(&msg, stakingTpe) + if err != nil { + t.Fatal(err) + } + + codec, err := goavro.NewCodec(stakingSchema) + _, _, err = codec.NativeFromBinary(bz) + if err != nil { + t.Fatal(err) + } +} + +func TestSlashMarshaling(t *testing.T) { + publisher := NewKafkaMarketDataPublisher(Logger, "", false) + valAddr, _ := sdk.ValAddressFromBech32("bva1e2y8w2rz957lahwy0y5h3w53sm8d78qexkn3rh") + submitterAddr, _ := sdk.AccAddressFromBech32("bnb1e2y8w2rz957lahwy0y5h3w53sm8d78qex2jpan") + slash := make(map[string][]*Slash) + slashItem := &Slash{ + Validator: valAddr, + InfractionType: 1, + InfractionHeight: 100, + JailUtil: 100000, + SlashAmount: 100, + ToFeePool: 10, + Submitter: submitterAddr, + SubmitterReward: 80, + ValidatorsCompensation: []*AllocatedAmt{{ + Address: submitterAddr.String(), + Amount: 10, + }}, + } + slash["chain-id-1"] = []*Slash{slashItem} + + msg := SlashMsg{ + NumOfMsgs: 1, + Height: 100, + Timestamp: 100000, + SlashData: slash, + } + bz, err := publisher.marshal(&msg, slashingTpe) + if err != nil { + t.Fatal(err) + } + + codec, err := goavro.NewCodec(slashingSchema) + _, _, err = codec.NativeFromBinary(bz) + if err != nil { + t.Fatal(err) + } +} diff --git a/app/pub/schemas.go b/app/pub/schemas.go index 2165dcb1e..d01d825f7 100644 --- a/app/pub/schemas.go +++ b/app/pub/schemas.go @@ -528,4 +528,404 @@ const ( ] } ` + + stakingSchema = ` + { + "type": "record", + "name": "Staking", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "height", "type": "long"}, + {"name": "timestamp", "type": "long" }, + {"name": "numOfMsgs", "type": "int" }, + {"name": "validators", "type": ["null", { + "type": "array", + "items": { + "type": "record", + "name": "Validator", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "feeAddr", "type": "string"}, + {"name": "operatorAddr", "type": "string"}, + {"name": "consAddr", "type": ["null","string"], "default": "null"}, + {"name": "jailed", "type": "boolean"}, + {"name": "status", "type": "string"}, + {"name": "tokens", "type": "long"}, + {"name": "delegatorShares", "type": "long"}, + {"name": "description", "type": { + "type": "record", + "name": "Description", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "moniker", "type": "string"}, + {"name": "identity", "type": "string"}, + {"name": "website", "type": "string"}, + {"name": "details", "type": "string"} + ] + }}, + {"name": "bondHeight", "type": "long"}, + {"name": "bondIntraTxCounter", "type": "int"}, + {"name": "commission", "type": { + "type": "record", + "name": "Commission", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "rate", "type": "long"}, + {"name": "maxRate", "type": "long"}, + {"name": "maxChangeRate", "type": "long"}, + {"name": "updateTime", "type": "long"} + ] + }}, + {"name": "distributionAddr", "type": "string"}, + {"name": "sideChainId", "type": "string"}, + {"name": "sideConsAddr", "type": "string"}, + {"name": "sideFeeAddr", "type": "string"} + ] + } + }], "default": "null"}, + {"name": "removedValidators", "type": ["null", { + "type": "map", + "values": { + "type": "array", + "items": {"type": "string"} + } + }], "default": null}, + {"name": "delegations", "type": ["null",{ + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "Delegation", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "delegator", "type": "string"}, + {"name": "validator", "type": "string"}, + {"name": "shares", "type": "long"} + ] + } + } + }], "default": null}, + {"name": "unBondingDelegations", "type": ["null",{ + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "UnBondingDelgation", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "delegator", "type": "string"}, + {"name": "validator", "type": "string"}, + {"name": "creationHeight", "type": "long"}, + {"name": "minTime", "type": "long"}, + {"name": "initialBalance", "type": { + "type": "record", + "name": "Coin", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "denom", "type": "string" }, + { "name": "amount", "type": "long" } + ] + }}, + {"name": "balance", "type": "org.binance.dex.model.avro.Coin"} + ] + } + } + }], "default": null}, + {"name": "reDelegations", "type": ["null",{ + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "ReDelegation", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "delegator", "type": "string"}, + {"name": "srcValidator", "type": "string"}, + {"name": "dstValidator", "type": "string"}, + {"name": "creationHeight", "type": "long"}, + {"name": "sharesSrc", "type": "long"}, + {"name": "sharesDst", "type": "long"}, + {"name": "initialBalance", "type": "org.binance.dex.model.avro.Coin" }, + {"name": "balance", "type": "org.binance.dex.model.avro.Coin" }, + {"name": "minTime", "type": "long"} + ] + } + } + }], "default": null}, + {"name": "completedUBDs", "type": ["null",{ + "type": "map", + "values": { + "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": "org.binance.dex.model.avro.Coin"} + ] + } + } + }], "default": null}, + {"name": "completedREDs", "type": ["null",{ + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "CompletedReDelegation", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "delegator", "type": "string" }, + { "name": "srcValidator", "type": "string" }, + { "name": "dstValidator", "type": "string" } + ] + } + } + }], "default": null}, + {"name": "delegateEvents", "type": ["null", { + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "DelegateEvent", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "delegator", "type": "string"}, + {"name": "validator", "type": "string"}, + {"name": "amount", "type": "org.binance.dex.model.avro.Coin"}, + {"name": "txHash", "type": "string"} + ] + } + } + }], "default": null}, + {"name": "unDelegateEvents", "type": ["null", { + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "UndelegateEvent", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "delegator", "type": "string"}, + {"name": "validator", "type": "string"}, + {"name": "amount", "type": "org.binance.dex.model.avro.Coin"}, + {"name": "txHash", "type": "string"} + ] + } + } + }], "default": null}, + {"name": "reDelegateEvents", "type": ["null", { + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "RedelegateEvent", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "delegator", "type": "string"}, + {"name": "srcValidator", "type": "string"}, + {"name": "dstValidator", "type": "string"}, + {"name": "amount", "type": "org.binance.dex.model.avro.Coin"}, + {"name": "txHash", "type": "string"} + ] + } + } + }], "default": null}, + {"name": "electedValidators", "type": ["null", { + "type": "map", + "values": { + "type": "array", + "items": "org.binance.dex.model.avro.Validator" + } + }], "default": null} + ] + } + ` + + distributionSchema = ` + { + "type": "record", + "name": "Distribution", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "height", "type": "long" }, + { "name": "timestamp", "type": "long" }, + { "name": "numOfMsgs", "type": "int" }, + { "name": "distributions", "type": { + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "DistributionData", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "validator", "type": "string"}, + {"name": "selfDelegator","type": "string"}, + {"name": "distributeAddr","type": "string"}, + {"name": "valTokens", "type": "long"}, + {"name": "totalReward", "type": "long"}, + {"name": "commission", "type": "long"}, + {"name": "rewards", "type":{ + "type": "array", + "items": { + "type": "record", + "name": "Reward", + "namespace": "org.binance.dex.model.avro", + "fields":[ + {"name": "delegator", "type": "string"}, + {"name": "delegationTokens", "type": "long"}, + {"name": "reward", "type": "long"} + ] + } + }} + ] + } + } + } + } + ] + } + ` + + slashingSchema = ` + { + "type": "record", + "name": "Slashing", + "namespace": "org.binance.dex.model.avro", + "fields": [ + { "name": "height", "type": "long" }, + { "name": "timestamp", "type": "long" }, + { "name": "numOfMsgs", "type": "int" }, + { "name": "slashData", "type": { + "type": "map", + "values": { + "type": "array", + "items": { + "type": "record", + "name": "SlashData", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "validator", "type": "string"}, + {"name": "infractionType", "type": "int"}, + {"name": "infractionHeight", "type": "long"}, + {"name": "jailUtil", "type": "long"}, + {"name": "slashAmount", "type": "long"}, + {"name": "toFeePool", "type": "long"}, + {"name": "submitter", "type": "string"}, + {"name": "submitterReward", "type": "long"}, + {"name": "validatorsCompensation", "type":{ + "type": "array", + "items": { + "type": "record", + "name": "AllocatedAmt", + "namespace": "org.binance.dex.model.avro", + "fields":[ + {"name": "address", "type": "string"}, + {"name": "amount", "type": "long"} + ] + } + }} + ] + } + } + }} + ] + } + ` + + crossTransferSchema = ` + { + "type": "record", + "name": "CrossTransfers", + "namespace": "com.company", + "fields": [ + { "name": "height", "type": "long"}, + { "name": "num", "type": "int" }, + { "name": "timestamp", "type": "long" }, + { "name": "transfers", + "type": { + "type": "array", + "items": { + "type": "record", + "name": "Transfer", + "namespace": "com.company", + "fields": [ + { "name": "txhash", "type": "string" }, + { "name": "type", "type": "string" }, + { "name": "relayerFee", "type": "long" }, + { "name": "chainid", "type": "string" }, + { "name": "from", "type": "string" }, + { "name": "denom", "type": "string" }, + { "name": "contract", "type": "string" }, + { "name": "decimals", "type": "int" }, + { "name": "to", + "type": { + "type": "array", + "items": { + "type": "record", + "name": "Receiver", + "namespace": "com.company", + "fields": [ + { "name": "addr", "type": "string" }, + { "name": "amount", "type": "long" } + ] + } + } + } + ] + } + } + } + ] + } + ` + + sideProposalsSchema = ` + { + "type": "record", + "name": "SideProposals", + "namespace": "com.company", + "fields": [ + { "name": "height", "type": "long" }, + { "name": "timestamp", "type": "long" }, + { "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": "chainid", "type": "string" }, + { "name": "status", "type": "string" } + ] + } + } + } + ] + } + ` + + breatheBlockSchema = ` + { + "type": "record", + "name": "BreatheBlock", + "namespace": "org.binance.dex.model.avro", + "fields": [ + {"name": "height", "type": "long"}, + {"name": "timestamp", "type": "long"} + ] + } + ` ) diff --git a/app/pub/sub/cross.go b/app/pub/sub/cross.go new file mode 100644 index 000000000..e864a68af --- /dev/null +++ b/app/pub/sub/cross.go @@ -0,0 +1,59 @@ +package sub + +import ( + "github.com/cosmos/cosmos-sdk/pubsub" + oTypes "github.com/cosmos/cosmos-sdk/x/oracle/types" + + "github.com/binance-chain/node/plugins/bridge" +) + +func SubscribeCrossTransferEvent(sub *pubsub.Subscriber) error { + err := sub.Subscribe(bridge.Topic, func(event pubsub.Event) { + switch event.(type) { + case bridge.CrossTransferEvent: + crossTransferEvent := event.(bridge.CrossTransferEvent) + if stagingArea.CrossTransferData == nil { + stagingArea.CrossTransferData = make([]bridge.CrossTransferEvent, 0, 1) + } + stagingArea.CrossTransferData = append(stagingArea.CrossTransferData, crossTransferEvent) + + default: + sub.Logger.Info("unknown event type") + } + }) + return err +} + +func SubscribeOracleEvent(sub *pubsub.Subscriber) error { + + err := sub.Subscribe(oTypes.Topic, func(event pubsub.Event) { + switch event.(type) { + case oTypes.CrossAppFailEvent: + crossFailEvent := event.(oTypes.CrossAppFailEvent) + sub.Logger.Info("do have crossFailEvent") + + // no need to publish into CrossTransferData if no balance change. + if crossFailEvent.RelayerFee > 0 { + if stagingArea.CrossTransferData == nil { + stagingArea.CrossTransferData = make([]bridge.CrossTransferEvent, 0, 1) + } + stagingArea.CrossTransferData = append(stagingArea.CrossTransferData, bridge.CrossTransferEvent{ + TxHash: crossFailEvent.TxHash, + ChainId: crossFailEvent.ChainId, + Type: bridge.CrossAppFailedType, + RelayerFee: crossFailEvent.RelayerFee, + From: crossFailEvent.From, + }) + } + default: + sub.Logger.Info("unknown event type") + } + }) + return err +} + +func commitCrossTransfer() { + if len(stagingArea.CrossTransferData) > 0 { + toPublish.EventData.CrossTransferData = append(toPublish.EventData.CrossTransferData, stagingArea.CrossTransferData...) + } +} diff --git a/app/pub/sub/slash.go b/app/pub/sub/slash.go new file mode 100644 index 000000000..7fca7ce4f --- /dev/null +++ b/app/pub/sub/slash.go @@ -0,0 +1,50 @@ +package sub + +import ( + "time" + + "github.com/cosmos/cosmos-sdk/pubsub" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/slashing" +) + +type SlashData struct { + Validator sdk.ValAddress + InfractionType byte + InfractionHeight int64 + JailUtil time.Time + SlashAmount int64 + ToFeePool int64 + Submitter sdk.AccAddress + SubmitterReward int64 + ValidatorsCompensation map[string]int64 +} + +func SubscribeSlashEvent(sub *pubsub.Subscriber) error { + err := sub.Subscribe(slashing.Topic, func(event pubsub.Event) { + switch event.(type) { + case slashing.SideSlashEvent: + sideSlashEvent := event.(slashing.SideSlashEvent) + if toPublish.EventData.SlashData == nil { + toPublish.EventData.SlashData = make(map[string][]SlashData) + } + if _, ok := toPublish.EventData.SlashData[sideSlashEvent.SideChainId]; !ok { + toPublish.EventData.SlashData[sideSlashEvent.SideChainId] = make([]SlashData, 0) + } + toPublish.EventData.SlashData[sideSlashEvent.SideChainId] = append(toPublish.EventData.SlashData[sideSlashEvent.SideChainId], SlashData{ + Validator: sideSlashEvent.Validator, + InfractionType: sideSlashEvent.InfractionType, + InfractionHeight: sideSlashEvent.InfractionHeight, + JailUtil: sideSlashEvent.JailUtil, + ToFeePool: sideSlashEvent.ToFeePool, + SlashAmount: sideSlashEvent.SlashAmt, + Submitter: sideSlashEvent.Submitter, + SubmitterReward: sideSlashEvent.SubmitterReward, + ValidatorsCompensation: sideSlashEvent.ValidatorsCompensation, + }) + default: + sub.Logger.Info("unknown event type") + } + }) + return err +} diff --git a/app/pub/sub/stake.go b/app/pub/sub/stake.go new file mode 100644 index 000000000..21a7b172e --- /dev/null +++ b/app/pub/sub/stake.go @@ -0,0 +1,370 @@ +package sub + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/pubsub" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/types" +) + +type CompletedUBD struct { + Validator sdk.ValAddress + Delegator sdk.AccAddress + Amount sdk.Coin +} + +func SubscribeStakeEvent(sub *pubsub.Subscriber) error { + err := sub.Subscribe(stake.Topic, func(event pubsub.Event) { + if toPublish.EventData.StakeData == nil { + toPublish.EventData.StakeData = &StakeData{} + } + if stagingArea.StakeData == nil { + stagingArea.StakeData = &StakeData{} + } + switch e := event.(type) { + case stake.SideDistributionEvent: + sub.Logger.Debug(fmt.Sprintf("distribution event: %v \n", e)) + toPublish.EventData.StakeData.appendDistribution(e.SideChainId, e.Data) + case stake.SideCompletedUBDEvent: + sub.Logger.Debug(fmt.Sprintf("completed UBD event: %v \n", e)) + ubds := make([]CompletedUBD, len(e.CompUBDs)) + for i, ubd := range e.CompUBDs { + cUBD := CompletedUBD{ + Validator: ubd.ValidatorAddr, + Delegator: ubd.DelegatorAddr, + Amount: ubd.Balance, + } + ubds[i] = cUBD + } + toPublish.EventData.StakeData.appendCompletedUBD(e.SideChainId, ubds) + case stake.SideCompletedREDEvent: + sub.Logger.Debug(fmt.Sprintf("completed RED event: %v \n", e)) + toPublish.EventData.StakeData.appendCompletedRED(e.SideChainId, e.CompREDs) + case stake.ValidatorUpdateEvent: + sub.Logger.Debug(fmt.Sprintf("validator update event: %v \n", e)) + if len(e.Validator.SideChainId) == 0 { // ignore bbc validator update events + return + } + if e.IsFromTx { + stagingArea.StakeData.appendValidator(e.Validator) + } else { + toPublish.EventData.StakeData.appendValidator(e.Validator) + } + case stake.ValidatorRemovedEvent: + sub.Logger.Debug(fmt.Sprintf("validator removed event: %v \n", e)) + chainId := e.SideChainId + if len(chainId) == 0 { + return // ignore bbc validator + } + if e.IsFromTx { + stagingArea.StakeData.appendRemovedValidator(chainId, e.Operator) + } else { + toPublish.EventData.StakeData.appendRemovedValidator(chainId, e.Operator) + } + case stake.SideDelegationUpdateEvent: + sub.Logger.Debug(fmt.Sprintf("delegation update event: %v \n", e)) + key := string(append(e.Delegation.DelegatorAddr.Bytes(), e.Delegation.ValidatorAddr.Bytes()...)) + if e.IsFromTx { + stagingArea.StakeData.appendDelegation(e.SideChainId, key, e.Delegation) + } else { + toPublish.EventData.StakeData.appendDelegation(e.SideChainId, key, e.Delegation) + } + case stake.SideDelegationRemovedEvent: + sub.Logger.Debug(fmt.Sprintf("delegation removed event: %v \n", e)) + if e.IsFromTx { + stagingArea.StakeData.appendRemovedDelegation(e.SideChainId, e.DvPair) + } else { + toPublish.EventData.StakeData.appendRemovedDelegation(e.SideChainId, e.DvPair) + } + case stake.SideUBDUpdateEvent: + sub.Logger.Debug(fmt.Sprintf("unbonding delegation update event: %v \n", e)) + key := string(append(e.UBD.DelegatorAddr.Bytes(), e.UBD.ValidatorAddr.Bytes()...)) + if e.IsFromTx { + stagingArea.StakeData.appendUBD(e.SideChainId, key, e.UBD) + } else { + toPublish.EventData.StakeData.appendUBD(e.SideChainId, key, e.UBD) + } + case stake.SideREDUpdateEvent: + sub.Logger.Debug(fmt.Sprintf("redelegation update event: %v \n", e)) + key := string(append(e.RED.DelegatorAddr.Bytes(), append(e.RED.ValidatorSrcAddr.Bytes(), e.RED.ValidatorDstAddr.Bytes()...)...)) + if e.IsFromTx { + stagingArea.StakeData.appendRED(e.SideChainId, key, e.RED) + } else { + toPublish.EventData.StakeData.appendRED(e.SideChainId, key, e.RED) + } + case stake.SideDelegateEvent: + sub.Logger.Debug(fmt.Sprintf("delegate event: %v \n", e)) + stagingArea.StakeData.appendDelegateEvent(e.SideChainId, e.DelegateEvent) + case stake.SideUndelegateEvent: + sub.Logger.Debug(fmt.Sprintf("undelegate event: %v \n", e)) + stagingArea.StakeData.appendUnDelegateEvent(e.SideChainId, e.UndelegateEvent) + case stake.SideRedelegateEvent: + sub.Logger.Debug(fmt.Sprintf("redelegate event: %v \n", e)) + stagingArea.StakeData.appendReDelegateEvent(e.SideChainId, e.RedelegateEvent) + case stake.SideElectedValidatorsEvent: + sub.Logger.Debug(fmt.Sprintf("elected validators event: %v \n", e)) + validators := make(map[string][]stake.Validator) + validators[e.SideChainId] = e.Validators + toPublish.EventData.StakeData.ElectedValidators = validators + default: + sub.Logger.Info("unknown event type") + } + }) + return err +} + +type StakeData struct { + // stash for stake topic + Distribution map[string][]stake.DistributionData // ChainId -> []DistributionData + CompletedUBDs map[string][]CompletedUBD // ChainId -> []CompletedUBD + CompletedREDs map[string][]types.DVVTriplet // ChainId -> []DVVTriplet + Validators map[string]stake.Validator // operator(string) -> validator + RemovedValidators map[string][]sdk.ValAddress // ChainId -> []sdk.ValAddress + Delegations map[string]map[string]stake.Delegation // ChainId -> delegator+validator -> Delegation + RemovedDelegations map[string][]types.DVPair // ChainId -> []DVPair + UnbondingDelegations map[string]map[string]stake.UnbondingDelegation // ChainId -> delegator+validator -> UBD + ReDelegations map[string]map[string]stake.Redelegation // ChainId -> delegator+srcValidator+dstValidator -> RED + DelegateEvents map[string][]stake.DelegateEvent // ChainId -> delegate event + UndelegateEvents map[string][]stake.UndelegateEvent // ChainId -> undelegate event + RedelegateEvents map[string][]stake.RedelegateEvent // ChainId -> redelegate event + ElectedValidators map[string][]stake.Validator // ChainId -> elected validators +} + +func (e *StakeData) appendDelegateEvent(chainId string, event stake.DelegateEvent) { + if e.DelegateEvents == nil { + e.DelegateEvents = make(map[string][]stake.DelegateEvent) + } + if _, ok := e.DelegateEvents[chainId]; !ok { + e.DelegateEvents[chainId] = make([]stake.DelegateEvent, 0) + } + e.DelegateEvents[chainId] = append(e.DelegateEvents[chainId], event) +} + +func (e *StakeData) appendDelegateEvents(chainId string, events []stake.DelegateEvent) { + if e.DelegateEvents == nil { + e.DelegateEvents = make(map[string][]stake.DelegateEvent) + } + if _, ok := e.DelegateEvents[chainId]; !ok { + e.DelegateEvents[chainId] = make([]stake.DelegateEvent, 0) + } + e.DelegateEvents[chainId] = append(e.DelegateEvents[chainId], events...) +} + +func (e *StakeData) appendUnDelegateEvent(chainId string, event stake.UndelegateEvent) { + if e.UndelegateEvents == nil { + e.UndelegateEvents = make(map[string][]stake.UndelegateEvent) + } + if _, ok := e.UndelegateEvents[chainId]; !ok { + e.UndelegateEvents[chainId] = make([]stake.UndelegateEvent, 0) + } + e.UndelegateEvents[chainId] = append(e.UndelegateEvents[chainId], event) +} + +func (e *StakeData) appendUnDelegateEvents(chainId string, events []stake.UndelegateEvent) { + if e.UndelegateEvents == nil { + e.UndelegateEvents = make(map[string][]stake.UndelegateEvent) + } + if _, ok := e.UndelegateEvents[chainId]; !ok { + e.UndelegateEvents[chainId] = make([]stake.UndelegateEvent, 0) + } + e.UndelegateEvents[chainId] = append(e.UndelegateEvents[chainId], events...) +} + +func (e *StakeData) appendReDelegateEvent(chainId string, event stake.RedelegateEvent) { + if e.RedelegateEvents == nil { + e.RedelegateEvents = make(map[string][]stake.RedelegateEvent) + } + if _, ok := e.RedelegateEvents[chainId]; !ok { + e.RedelegateEvents[chainId] = make([]stake.RedelegateEvent, 0) + } + e.RedelegateEvents[chainId] = append(e.RedelegateEvents[chainId], event) +} + +func (e *StakeData) appendReDelegateEvents(chainId string, events []stake.RedelegateEvent) { + if e.RedelegateEvents == nil { + e.RedelegateEvents = make(map[string][]stake.RedelegateEvent) + } + if _, ok := e.RedelegateEvents[chainId]; !ok { + e.RedelegateEvents[chainId] = make([]stake.RedelegateEvent, 0) + } + e.RedelegateEvents[chainId] = append(e.RedelegateEvents[chainId], events...) +} + +func (e *StakeData) appendDistribution(chainId string, data []stake.DistributionData) { + if e.Distribution == nil { + e.Distribution = make(map[string][]stake.DistributionData) + } + if _, ok := e.Distribution[chainId]; !ok { + e.Distribution[chainId] = make([]stake.DistributionData, 0) + } + e.Distribution[chainId] = append(e.Distribution[chainId], data...) +} + +func (e *StakeData) appendCompletedUBD(chainId string, ubds []CompletedUBD) { + if e.CompletedUBDs == nil { + e.CompletedUBDs = make(map[string][]CompletedUBD) + } + if _, ok := e.CompletedUBDs[chainId]; !ok { + e.CompletedUBDs[chainId] = make([]CompletedUBD, 0) + } + e.CompletedUBDs[chainId] = append(e.CompletedUBDs[chainId], ubds...) +} + +func (e *StakeData) appendCompletedRED(chainId string, reds []stake.DVVTriplet) { + if e.CompletedREDs == nil { + e.CompletedREDs = make(map[string][]stake.DVVTriplet) + } + if _, ok := e.CompletedREDs[chainId]; !ok { + e.CompletedREDs[chainId] = make([]stake.DVVTriplet, 0) + } + e.CompletedREDs[chainId] = append(e.CompletedREDs[chainId], reds...) +} + +func (e *StakeData) appendValidators(validators map[string]stake.Validator) { + for _, v := range validators { + e.appendValidator(v) + } +} + +func (e *StakeData) appendValidator(validator stake.Validator) { + if e.Validators == nil { + e.Validators = make(map[string]stake.Validator) + } + e.Validators[string(validator.OperatorAddr)] = validator +} + +func (e *StakeData) appendRemovedValidators(chainId string, operators []sdk.ValAddress) { + for _, v := range operators { + e.appendRemovedValidator(chainId, v) + } +} + +func (e *StakeData) appendRemovedValidator(chainId string, operator sdk.ValAddress) { + if e.RemovedValidators == nil { + e.RemovedValidators = make(map[string][]sdk.ValAddress) + } + if e.RemovedValidators[chainId] == nil { + e.RemovedValidators[chainId] = make([]sdk.ValAddress, 0) + } + e.RemovedValidators[chainId] = append(e.RemovedValidators[chainId], operator) +} + +func (e *StakeData) appendDelegations(chainId string, delegations map[string]stake.Delegation) { + for k, v := range delegations { + e.appendDelegation(chainId, k, v) + } +} + +func (e *StakeData) appendDelegation(chainId string, key string, delegation stake.Delegation) { + if e.Delegations == nil { + e.Delegations = make(map[string]map[string]stake.Delegation) + } + if e.Delegations[chainId] == nil { + e.Delegations[chainId] = make(map[string]stake.Delegation) + } + e.Delegations[chainId][key] = delegation +} + +func (e *StakeData) appendRemovedDelegations(chainId string, pairs []stake.DVPair) { + for _, pair := range pairs { + e.appendRemovedDelegation(chainId, pair) + } +} + +func (e *StakeData) appendRemovedDelegation(chainId string, pair stake.DVPair) { + if e.RemovedDelegations == nil { + e.RemovedDelegations = make(map[string][]stake.DVPair) + } + if _, ok := e.RemovedDelegations[chainId]; !ok { + e.RemovedDelegations[chainId] = make([]stake.DVPair, 0) + } + e.RemovedDelegations[chainId] = append(e.RemovedDelegations[chainId], pair) +} + +func (e *StakeData) appendUBDs(chainId string, ubds map[string]stake.UnbondingDelegation) { + for k, v := range ubds { + e.appendUBD(chainId, k, v) + } +} + +func (e *StakeData) appendUBD(chainId string, key string, ubd stake.UnbondingDelegation) { + if e.UnbondingDelegations == nil { + e.UnbondingDelegations = make(map[string]map[string]stake.UnbondingDelegation) + } + if e.UnbondingDelegations[chainId] == nil { + e.UnbondingDelegations[chainId] = make(map[string]stake.UnbondingDelegation) + } + e.UnbondingDelegations[chainId][key] = ubd +} + +func (e *StakeData) appendREDs(chainId string, reds map[string]stake.Redelegation) { + for k, v := range reds { + e.appendRED(chainId, k, v) + } +} + +func (e *StakeData) appendRED(chainId string, key string, red stake.Redelegation) { + if e.ReDelegations == nil { + e.ReDelegations = make(map[string]map[string]stake.Redelegation) + } + if e.ReDelegations[chainId] == nil { + e.ReDelegations[chainId] = make(map[string]stake.Redelegation) + } + e.ReDelegations[chainId][key] = red +} + +func commitStake() { + if stagingArea.StakeData == nil { + return + } + if len(stagingArea.StakeData.Distribution) > 0 { + for chainId, v := range stagingArea.StakeData.Distribution { + toPublish.EventData.StakeData.appendDistribution(chainId, v) + } + } + if len(stagingArea.StakeData.DelegateEvents) > 0 { + for chainId, v := range stagingArea.StakeData.DelegateEvents { + toPublish.EventData.StakeData.appendDelegateEvents(chainId, v) + } + } + if len(stagingArea.StakeData.UndelegateEvents) > 0 { + for chainId, v := range stagingArea.StakeData.UndelegateEvents { + toPublish.EventData.StakeData.appendUnDelegateEvents(chainId, v) + } + } + if len(stagingArea.StakeData.RedelegateEvents) > 0 { + for chainId, v := range stagingArea.StakeData.RedelegateEvents { + toPublish.EventData.StakeData.appendReDelegateEvents(chainId, v) + } + } + if len(stagingArea.StakeData.Validators) > 0 { + toPublish.EventData.StakeData.appendValidators(stagingArea.StakeData.Validators) + } + if len(stagingArea.StakeData.RemovedValidators) > 0 { + for chainId, v := range stagingArea.StakeData.RemovedValidators { + toPublish.EventData.StakeData.appendRemovedValidators(chainId, v) + } + } + if len(stagingArea.StakeData.Delegations) > 0 { + for chainId, v := range stagingArea.StakeData.Delegations { + toPublish.EventData.StakeData.appendDelegations(chainId, v) + } + } + if len(stagingArea.StakeData.RemovedDelegations) > 0 { + for chainId, v := range stagingArea.StakeData.RemovedDelegations { + toPublish.EventData.StakeData.appendRemovedDelegations(chainId, v) + } + } + if len(stagingArea.StakeData.UnbondingDelegations) > 0 { + for chainId, v := range stagingArea.StakeData.UnbondingDelegations { + toPublish.EventData.StakeData.appendUBDs(chainId, v) + } + } + if len(stagingArea.StakeData.ReDelegations) > 0 { + for chainId, v := range stagingArea.StakeData.ReDelegations { + toPublish.EventData.StakeData.appendREDs(chainId, v) + } + } +} diff --git a/app/pub/sub/sub.go b/app/pub/sub/sub.go new file mode 100644 index 000000000..37c3e635d --- /dev/null +++ b/app/pub/sub/sub.go @@ -0,0 +1,124 @@ +package sub + +import ( + "time" + + "github.com/binance-chain/node/app/config" + "github.com/binance-chain/node/plugins/bridge" + + "github.com/cosmos/cosmos-sdk/pubsub" +) + +func SubscribeEvent(sub *pubsub.Subscriber, cfg *config.PublicationConfig) error { + if cfg.PublishStaking { + if err := SubscribeStakeEvent(sub); err != nil { + return err + } + } + + if cfg.PublishSlashing { + if err := SubscribeSlashEvent(sub); err != nil { + return err + } + } + + if cfg.PublishCrossTransfer { + if err := SubscribeCrossTransferEvent(sub); err != nil { + return err + } + if err := SubscribeOracleEvent(sub); err != nil { + return err + } + } + + // commit events data from staging area to 'toPublish' when receiving `TxDeliverEvent`, represents the tx is successfully delivered. + if err := sub.Subscribe(TxDeliverTopic, func(event pubsub.Event) { + switch event.(type) { + case TxDeliverSuccEvent: + commit(cfg) + case TxDeliverFailEvent: + discard() + default: + sub.Logger.Debug("unknown event") + } + }); err != nil { + return err + } + + return nil +} + +//----------------------------------------------------- +var ( + // events to be published, should be cleaned up each block + toPublish = &ToPublishEvent{EventData: newEventStore()} + // staging area for accepting events to store + // should be moved to 'toPublish' when related tx successfully delivered + stagingArea = &EventStore{} +) + +type ToPublishEvent struct { + Height int64 + Timestamp time.Time + IsBreatheBlock bool + EventData *EventStore +} + +type EventStore struct { + // store for stake topic + StakeData *StakeData + // store for slash topic + SlashData map[string][]SlashData + // store for cross chain transfer topic + CrossTransferData []bridge.CrossTransferEvent +} + +func newEventStore() *EventStore { + return &EventStore{} +} + +func Clear() { + toPublish = &ToPublishEvent{EventData: newEventStore()} + stagingArea = newEventStore() +} + +func ToPublish() *ToPublishEvent { + return toPublish +} + +func SetMeta(height int64, timestamp time.Time, isBreatheBlock bool) { + toPublish.Height = height + toPublish.Timestamp = timestamp + toPublish.IsBreatheBlock = isBreatheBlock +} + +func commit(cfg *config.PublicationConfig) { + if cfg.PublishStaking { + commitStake() + } + if cfg.PublishCrossTransfer { + commitCrossTransfer() + } + // clear stagingArea data + stagingArea = newEventStore() +} + +func discard() { + stagingArea = newEventStore() +} + +//--------------------------------------------------------------------- +const TxDeliverTopic = pubsub.Topic("TxDeliver") + +type TxDeliverEvent struct{} + +func (event TxDeliverEvent) GetTopic() pubsub.Topic { + return TxDeliverTopic +} + +type TxDeliverSuccEvent struct { + TxDeliverEvent +} +type TxDeliverFailEvent struct { + TxDeliverEvent +} diff --git a/app/pub/types.go b/app/pub/types.go index 562162836..6461dec70 100644 --- a/app/pub/types.go +++ b/app/pub/types.go @@ -10,6 +10,7 @@ type BlockInfoToPublish struct { timestamp int64 tradesToPublish []*Trade proposalsToPublish *Proposals + sideProposals *SideProposals stakeUpdates *StakeUpdates orderChanges orderPkg.OrderChanges orderInfos orderPkg.OrderInfoForPublish @@ -26,6 +27,7 @@ func NewBlockInfoToPublish( timestamp int64, tradesToPublish []*Trade, proposalsToPublish *Proposals, + sideProposalsToPublish *SideProposals, stakeUpdates *StakeUpdates, orderChanges orderPkg.OrderChanges, orderInfos orderPkg.OrderInfoForPublish, @@ -38,6 +40,7 @@ func NewBlockInfoToPublish( timestamp, tradesToPublish, proposalsToPublish, + sideProposalsToPublish, stakeUpdates, orderChanges, orderInfos, diff --git a/cmd/bnbcli/main.go b/cmd/bnbcli/main.go index 7b4ba81b3..c294f0c12 100644 --- a/cmd/bnbcli/main.go +++ b/cmd/bnbcli/main.go @@ -1,6 +1,8 @@ package main import ( + "github.com/spf13/cobra" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/rpc" @@ -9,8 +11,11 @@ import ( authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" govcmd "github.com/cosmos/cosmos-sdk/x/gov/client/cli" + sidecmd "github.com/cosmos/cosmos-sdk/x/sidechain/client/cli" + + paramcmd "github.com/cosmos/cosmos-sdk/x/paramHub/client/cli" + slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli" stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli" - "github.com/spf13/cobra" "github.com/tendermint/tendermint/libs/cli" @@ -20,8 +25,8 @@ import ( "github.com/binance-chain/node/common/types" accountcmd "github.com/binance-chain/node/plugins/account/client/cli" apiserv "github.com/binance-chain/node/plugins/api" + bridgecmd "github.com/binance-chain/node/plugins/bridge/client/cli" dexcmd "github.com/binance-chain/node/plugins/dex/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,17 +93,12 @@ func main() { dexcmd.AddCommands(rootCmd, cdc) paramcmd.AddCommands(rootCmd, cdc) - // stake cmds - rootCmd.AddCommand( - - client.PostCommands( - stakecmd.GetCmdCreateValidator(cdc), - stakecmd.GetCmdRemoveValidator(cdc), - stakecmd.GetCmdQueryValidators("stake", cdc), - stakecmd.GetCmdQueryUnbondingDelegations("stake", cdc), - )...) + stakecmd.AddCommands(rootCmd, cdc) + slashingcmd.AddCommands(rootCmd, cdc) govcmd.AddCommands(rootCmd, cdc) admin.AddCommands(rootCmd, cdc) + bridgecmd.AddCommands(rootCmd, cdc) + sidecmd.AddCommands(rootCmd, cdc) // prepare and add flags executor := cli.PrepareMainCmd(rootCmd, "BC", app.DefaultCLIHome) diff --git a/cmd/pressuremaker/utils/utils.go b/cmd/pressuremaker/utils/utils.go index a35b71358..b120115c2 100644 --- a/cmd/pressuremaker/utils/utils.go +++ b/cmd/pressuremaker/utils/utils.go @@ -149,6 +149,7 @@ func (mg MessageGenerator) Publish(height, timePub int64, tradesToPublish []*pub timePub, tradesToPublish, new(pub.Proposals), + new(pub.SideProposals), new(pub.StakeUpdates), orderChanges, orderChangesCopy, diff --git a/common/fees/fee_calculator.go b/common/fees/fee_calculator.go deleted file mode 100644 index 60436f787..000000000 --- a/common/fees/fee_calculator.go +++ /dev/null @@ -1,60 +0,0 @@ -package fees - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/common/types" - param "github.com/binance-chain/node/plugins/param/types" -) - -type FeeCalculator func(msg sdk.Msg) types.Fee -type FeeCalculatorGenerator func(params param.FeeParam) FeeCalculator - -var calculators = make(map[string]FeeCalculator) -var CalculatorsGen = make(map[string]FeeCalculatorGenerator) - -func RegisterCalculator(msgType string, feeCalc FeeCalculator) { - calculators[msgType] = feeCalc -} - -func GetCalculatorGenerator(msgType string) FeeCalculatorGenerator { - return CalculatorsGen[msgType] -} - -func GetCalculator(msgType string) FeeCalculator { - return calculators[msgType] -} - -func UnsetAllCalculators() { - for key := range calculators { - delete(calculators, key) - } -} - -func FixedFeeCalculator(amount int64, feeType types.FeeDistributeType) FeeCalculator { - if feeType == types.FeeFree { - return FreeFeeCalculator() - } - return func(msg sdk.Msg) types.Fee { - return types.NewFee(append(sdk.Coins{}, sdk.NewCoin(types.NativeTokenSymbol, amount)), feeType) - } -} - -func FreeFeeCalculator() FeeCalculator { - return func(msg sdk.Msg) types.Fee { - return types.NewFee(append(sdk.Coins{}), types.FeeFree) - } -} - -var FixedFeeCalculatorGen = func(params param.FeeParam) FeeCalculator { - if defaultParam, ok := params.(*param.FixedFeeParams); ok { - if defaultParam.Fee <= 0 || defaultParam.FeeFor == types.FeeFree { - return FreeFeeCalculator() - } else { - return FixedFeeCalculator(defaultParam.Fee, defaultParam.FeeFor) - } - } else { - panic("Generator receive unexpected param type") - } - -} diff --git a/common/fees/fee_calculator_test.go b/common/fees/fee_calculator_test.go deleted file mode 100644 index 69ff341db..000000000 --- a/common/fees/fee_calculator_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package fees_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" - - "github.com/binance-chain/node/common/fees" - "github.com/binance-chain/node/common/testutils" - "github.com/binance-chain/node/common/types" -) - -func TestFixedFeeCalculator(t *testing.T) { - _, addr := testutils.PrivAndAddr() - msg := sdk.NewTestMsg(addr) - calculator := fees.FixedFeeCalculator(10, types.FeeFree) - fee := calculator(msg) - require.Equal(t, types.FeeFree, fee.Type) - require.Equal(t, sdk.Coins{}, fee.Tokens) - - calculator = fees.FixedFeeCalculator(10, types.FeeForAll) - fee = calculator(msg) - require.Equal(t, types.FeeForAll, fee.Type) - require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, fee.Tokens) - - calculator = fees.FixedFeeCalculator(10, types.FeeForProposer) - fee = calculator(msg) - require.Equal(t, types.FeeForProposer, fee.Type) - require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, fee.Tokens) -} - -func TestFreeFeeCalculator(t *testing.T) { - _, addr := testutils.PrivAndAddr() - msg := sdk.NewTestMsg(addr) - - calculator := fees.FreeFeeCalculator() - fee := calculator(msg) - require.Equal(t, types.FeeFree, fee.Type) - require.Equal(t, sdk.Coins{}, fee.Tokens) -} - -func TestRegisterAndGetCalculators(t *testing.T) { - _, addr := testutils.PrivAndAddr() - msg := sdk.NewTestMsg(addr) - - fees.RegisterCalculator(msg.Type(), fees.FixedFeeCalculator(10, types.FeeForProposer)) - calculator := fees.GetCalculator(msg.Type()) - require.NotNil(t, calculator) - fee := calculator(msg) - require.Equal(t, types.FeeForProposer, fee.Type) - require.Equal(t, sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, fee.Tokens) - - fees.UnsetAllCalculators() - require.Nil(t, fees.GetCalculator(msg.Type())) -} diff --git a/common/fees/pool.go b/common/fees/pool.go deleted file mode 100644 index 5192af6a9..000000000 --- a/common/fees/pool.go +++ /dev/null @@ -1,56 +0,0 @@ -package fees - -import ( - "fmt" - - "github.com/binance-chain/node/common/types" -) - -// block level pool -var Pool pool = newPool() - -type pool struct { - fees map[string]types.Fee // TxHash -> fee - committedFees types.Fee -} - -func newPool() pool { - return pool{ - fees: map[string]types.Fee{}, - committedFees: types.Fee{}, - } -} - -func (p *pool) AddFee(txHash string, fee types.Fee) { - p.fees[txHash] = fee -} - -func (p *pool) AddAndCommitFee(txHash string, fee types.Fee) { - p.fees[txHash] = fee - p.committedFees.AddFee(fee) -} - -func (p *pool) CommitFee(txHash string) { - if fee, ok := p.fees[txHash]; ok { - p.committedFees.AddFee(fee) - } else { - panic(fmt.Errorf("commit fee for an invalid TxHash(%s)", txHash)) - } -} - -func (p pool) BlockFees() types.Fee { - return p.committedFees -} - -func (p *pool) Clear() { - p.fees = map[string]types.Fee{} - p.committedFees = types.Fee{} -} - -func (p *pool) GetFee(txHash string) *types.Fee { - if fee, ok := p.fees[txHash]; ok { - return &fee - } else { - return nil - } -} diff --git a/common/stores.go b/common/stores.go index b39b69381..b9b7c01a9 100644 --- a/common/stores.go +++ b/common/stores.go @@ -10,10 +10,15 @@ const ( DexStoreName = "dex" PairStoreName = "pairs" StakeStoreName = "stake" + SlashingStoreName = "slashing" ParamsStoreName = "params" GovStoreName = "gov" TimeLockStoreName = "time_lock" AtomicSwapStoreName = "atomic_swap" + BridgeStoreName = "bridge" + OracleStoreName = "oracle" + IbcStoreName = "ibc" + SideChainStoreName = "sc" StakeTransientStoreName = "transient_stake" ParamsTransientStoreName = "transient_params" @@ -28,10 +33,15 @@ var ( DexStoreKey = sdk.NewKVStoreKey(DexStoreName) PairStoreKey = sdk.NewKVStoreKey(PairStoreName) StakeStoreKey = sdk.NewKVStoreKey(StakeStoreName) + SlashingStoreKey = sdk.NewKVStoreKey(SlashingStoreName) ParamsStoreKey = sdk.NewKVStoreKey(ParamsStoreName) GovStoreKey = sdk.NewKVStoreKey(GovStoreName) TimeLockStoreKey = sdk.NewKVStoreKey(TimeLockStoreName) AtomicSwapStoreKey = sdk.NewKVStoreKey(AtomicSwapStoreName) + BridgeStoreKey = sdk.NewKVStoreKey(BridgeStoreName) + OracleStoreKey = sdk.NewKVStoreKey(OracleStoreName) + IbcStoreKey = sdk.NewKVStoreKey(IbcStoreName) + SideChainStoreKey = sdk.NewKVStoreKey(SideChainStoreName) TStakeStoreKey = sdk.NewTransientStoreKey(StakeTransientStoreName) TParamsStoreKey = sdk.NewTransientStoreKey(ParamsTransientStoreName) @@ -44,10 +54,15 @@ var ( DexStoreName: DexStoreKey, PairStoreName: PairStoreKey, StakeStoreName: StakeStoreKey, + SlashingStoreName: SlashingStoreKey, ParamsStoreName: ParamsStoreKey, GovStoreName: GovStoreKey, TimeLockStoreName: TimeLockStoreKey, AtomicSwapStoreName: AtomicSwapStoreKey, + IbcStoreName: IbcStoreKey, + SideChainStoreName: SideChainStoreKey, + BridgeStoreName: BridgeStoreKey, + OracleStoreName: OracleStoreKey, StakeTransientStoreName: TStakeStoreKey, ParamsTransientStoreName: TParamsStoreKey, } @@ -60,10 +75,15 @@ var ( DexStoreName, PairStoreName, StakeStoreName, + SlashingStoreName, ParamsStoreName, GovStoreName, TimeLockStoreName, AtomicSwapStoreName, + IbcStoreName, + SideChainStoreName, + BridgeStoreName, + OracleStoreName, } ) diff --git a/common/tx/ante.go b/common/tx/ante.go index 79949a7ae..57ba46984 100644 --- a/common/tx/ante.go +++ b/common/tx/ante.go @@ -4,18 +4,19 @@ import ( "bytes" "fmt" + lru "github.com/hashicorp/golang-lru" + "github.com/pkg/errors" + "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" + sdkfees "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" - lru "github.com/hashicorp/golang-lru" - "github.com/pkg/errors" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/libs/common" - "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/common/types" ) const ( @@ -329,7 +330,7 @@ func calcAndCollectFees(ctx sdk.Context, am auth.AccountKeeper, acc sdk.Account, return sdk.ErrInternal("calculate fees error").Result() } - if fee.Type != types.FeeFree && !fee.Tokens.IsZero() { + if fee.Type != sdk.FeeFree && !fee.Tokens.IsZero() { fee.Tokens.Sort() res := deductFees(ctx, acc, fee, am) if !res.IsOK() { @@ -339,20 +340,20 @@ func calcAndCollectFees(ctx sdk.Context, am auth.AccountKeeper, acc sdk.Account, if ctx.IsDeliverTx() { // add fee to pool, even it's free - fees.Pool.AddFee(txHash, fee) + sdkfees.Pool.AddFee(txHash, fee) } return sdk.Result{} } -func calculateFees(msg sdk.Msg) (types.Fee, error) { - calculator := fees.GetCalculator(msg.Type()) +func calculateFees(msg sdk.Msg) (sdk.Fee, error) { + calculator := sdkfees.GetCalculator(msg.Type()) if calculator == nil { - return types.Fee{}, errors.New("missing calculator for msgType:" + msg.Type()) + return sdk.Fee{}, errors.New("missing calculator for msgType:" + msg.Type()) } return calculator(msg), nil } -func checkSufficientFunds(acc sdk.Account, fee types.Fee) sdk.Result { +func checkSufficientFunds(acc sdk.Account, fee sdk.Fee) sdk.Result { coins := acc.GetCoins() newCoins := coins.Minus(fee.Tokens.Sort()) @@ -364,7 +365,7 @@ func checkSufficientFunds(acc sdk.Account, fee types.Fee) sdk.Result { return sdk.Result{} } -func deductFees(ctx sdk.Context, acc sdk.Account, fee types.Fee, am auth.AccountKeeper) sdk.Result { +func deductFees(ctx sdk.Context, acc sdk.Account, fee sdk.Fee, am auth.AccountKeeper) sdk.Result { if res := checkSufficientFunds(acc, fee); !res.IsOK() { return res } diff --git a/common/tx/ante_test.go b/common/tx/ante_test.go index d5a7e3c5e..e6d709af1 100644 --- a/common/tx/ante_test.go +++ b/common/tx/ante_test.go @@ -4,11 +4,14 @@ import ( "fmt" "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkfees "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/tmhash" @@ -16,7 +19,6 @@ import ( "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/app" - "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/tx" "github.com/binance-chain/node/common/types" @@ -24,16 +26,16 @@ import ( ) func newTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg { - fees.UnsetAllCalculators() + sdkfees.UnsetAllCalculators() testMsg := sdk.NewTestMsg(addrs...) - fees.RegisterCalculator(testMsg.Type(), fees.FreeFeeCalculator()) + sdkfees.RegisterCalculator(testMsg.Type(), sdkfees.FreeFeeCalculator()) return testMsg } -func newTestMsgWithFeeCalculator(calculator fees.FeeCalculator, addrs ...sdk.AccAddress) *sdk.TestMsg { - fees.UnsetAllCalculators() +func newTestMsgWithFeeCalculator(calculator sdkfees.FeeCalculator, addrs ...sdk.AccAddress) *sdk.TestMsg { + sdkfees.UnsetAllCalculators() testMsg := sdk.NewTestMsg(addrs...) - fees.RegisterCalculator(testMsg.Type(), calculator) + sdkfees.RegisterCalculator(testMsg.Type(), calculator) return testMsg } @@ -483,7 +485,7 @@ func setup() (mapper auth.AccountKeeper, ctx sdk.Context, anteHandler sdk.AnteHa return } -func runAnteHandlerWithMultiTxFees(ctx sdk.Context, anteHandler sdk.AnteHandler, priv crypto.PrivKey, addr sdk.AccAddress, feeCalculators ...fees.FeeCalculator) sdk.Context { +func runAnteHandlerWithMultiTxFees(ctx sdk.Context, anteHandler sdk.AnteHandler, priv crypto.PrivKey, addr sdk.AccAddress, feeCalculators ...sdkfees.FeeCalculator) sdk.Context { for i := 0; i < len(feeCalculators); i++ { msg := newTestMsgWithFeeCalculator(feeCalculators[i], addr) txn := newTestTx(ctx, []sdk.Msg{msg}, []crypto.PrivKey{priv}, []int64{0}, []int64{int64(i)}) @@ -491,7 +493,7 @@ func runAnteHandlerWithMultiTxFees(ctx sdk.Context, anteHandler sdk.AnteHandler, txHash := cmn.HexBytes(tmhash.Sum(txBytes)).String() ctx, _, _ = anteHandler(ctx.WithValue(baseapp.TxHashKey, txHash), txn, sdk.RunTxModeCheck) if ctx.IsDeliverTx() { - fees.Pool.CommitFee(txHash) + sdkfees.Pool.CommitFee(txHash) } } @@ -503,10 +505,10 @@ func checkBalance(t *testing.T, am auth.AccountKeeper, ctx sdk.Context, addr sdk require.Equal(t, accNewBalance, newBalance) } -func checkFee(t *testing.T, expectFee types.Fee) { - fee := fees.Pool.BlockFees() +func checkFee(t *testing.T, expectFee sdk.Fee) { + fee := sdkfees.Pool.BlockFees() require.Equal(t, expectFee, fee) - fees.Pool.Clear() + sdkfees.Pool.Clear() } // Test logic around fee deduction. @@ -516,32 +518,32 @@ func TestAnteHandlerFeesInCheckTx(t *testing.T) { priv1, acc1 := testutils.NewAccount(ctx, am, 100) ctx = ctx.WithRunTxMode(sdk.RunTxModeCheck) - ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), fees.FixedFeeCalculator(10, types.FeeForProposer)) + ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), sdkfees.FixedFeeCalculator(10, sdk.FeeForProposer)) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 90)}) - checkFee(t, types.Fee{}) + checkFee(t, sdk.Fee{}) } func TestAnteHandlerOneTxFee(t *testing.T) { // one tx, FeeFree am, ctx, anteHandler := setup() priv1, acc1 := testutils.NewAccount(ctx, am, 100) - ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), fees.FreeFeeCalculator()) + ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), sdkfees.FreeFeeCalculator()) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 100)}) - checkFee(t, types.Fee{}) + checkFee(t, sdk.Fee{}) // one tx, FeeForProposer am, ctx, anteHandler = setup() priv1, acc1 = testutils.NewAccount(ctx, am, 100) - ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), fees.FixedFeeCalculator(10, types.FeeForProposer)) + ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), sdkfees.FixedFeeCalculator(10, sdk.FeeForProposer)) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 90)}) - checkFee(t, types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, types.FeeForProposer)) + checkFee(t, sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, sdk.FeeForProposer)) // one tx, FeeForAll am, ctx, anteHandler = setup() priv1, acc1 = testutils.NewAccount(ctx, am, 100) - ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), fees.FixedFeeCalculator(10, types.FeeForAll)) + ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), sdkfees.FixedFeeCalculator(10, sdk.FeeForAll)) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 90)}) - checkFee(t, types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, types.FeeForAll)) + checkFee(t, sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, sdk.FeeForAll)) } func TestAnteHandlerMultiTxFees(t *testing.T) { @@ -549,47 +551,47 @@ func TestAnteHandlerMultiTxFees(t *testing.T) { am, ctx, anteHandler := setup() priv1, acc1 := testutils.NewAccount(ctx, am, 100) ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), - fees.FreeFeeCalculator(), - fees.FixedFeeCalculator(10, types.FeeForProposer)) + sdkfees.FreeFeeCalculator(), + sdkfees.FixedFeeCalculator(10, sdk.FeeForProposer)) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 90)}) - checkFee(t, types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, types.FeeForProposer)) + checkFee(t, sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, sdk.FeeForProposer)) // two txs, 1. FeeProposer 2. FeeFree am, ctx, anteHandler = setup() priv1, acc1 = testutils.NewAccount(ctx, am, 100) ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), - fees.FixedFeeCalculator(10, types.FeeForProposer), - fees.FreeFeeCalculator()) + sdkfees.FixedFeeCalculator(10, sdk.FeeForProposer), + sdkfees.FreeFeeCalculator()) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 90)}) - checkFee(t, types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, types.FeeForProposer)) + checkFee(t, sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 10)}, sdk.FeeForProposer)) // two txs, 1. FeeProposer 2. FeeForAll am, ctx, anteHandler = setup() priv1, acc1 = testutils.NewAccount(ctx, am, 100) ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), - fees.FixedFeeCalculator(10, types.FeeForProposer), - fees.FixedFeeCalculator(10, types.FeeForAll)) + sdkfees.FixedFeeCalculator(10, sdk.FeeForProposer), + sdkfees.FixedFeeCalculator(10, sdk.FeeForAll)) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 80)}) - checkFee(t, types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 20)}, types.FeeForAll)) + checkFee(t, sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 20)}, sdk.FeeForAll)) // two txs, 1. FeeForAll 2. FeeProposer am, ctx, anteHandler = setup() priv1, acc1 = testutils.NewAccount(ctx, am, 100) ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), - fees.FixedFeeCalculator(10, types.FeeForAll), - fees.FixedFeeCalculator(10, types.FeeForProposer)) + sdkfees.FixedFeeCalculator(10, sdk.FeeForAll), + sdkfees.FixedFeeCalculator(10, sdk.FeeForProposer)) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 80)}) - checkFee(t, types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 20)}, types.FeeForAll)) + checkFee(t, sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 20)}, sdk.FeeForAll)) // three txs, 1. FeeForAll 2. FeeProposer 3. FeeFree am, ctx, anteHandler = setup() priv1, acc1 = testutils.NewAccount(ctx, am, 100) ctx = runAnteHandlerWithMultiTxFees(ctx, anteHandler, priv1, acc1.GetAddress(), - fees.FixedFeeCalculator(10, types.FeeForAll), - fees.FixedFeeCalculator(10, types.FeeForProposer), - fees.FreeFeeCalculator()) + sdkfees.FixedFeeCalculator(10, sdk.FeeForAll), + sdkfees.FixedFeeCalculator(10, sdk.FeeForProposer), + sdkfees.FreeFeeCalculator()) checkBalance(t, am, ctx, acc1.GetAddress(), sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 80)}) - checkFee(t, types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 20)}, types.FeeForAll)) + checkFee(t, sdk.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, 20)}, sdk.FeeForAll)) } func TestNewTxPreCheckerEmptySigner(t *testing.T) { diff --git a/common/types/fee.go b/common/types/fee.go deleted file mode 100644 index 424f2a4e7..000000000 --- a/common/types/fee.go +++ /dev/null @@ -1,91 +0,0 @@ -package types - -import ( - "bytes" - "fmt" - "strconv" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type FeeDistributeType int8 - -const ( - FeeForProposer = FeeDistributeType(0x01) - FeeForAll = FeeDistributeType(0x02) - FeeFree = FeeDistributeType(0x03) - - ZeroFee = 0 - - canceledCharacter = "#Cxl" - expiredCharacter = "#Exp" - serializeSeparator = ";" - amountDenomSeparator = ":" -) - -type Fee struct { - Tokens sdk.Coins - Type FeeDistributeType -} - -func NewFee(tokens sdk.Coins, distributeType FeeDistributeType) Fee { - return Fee{ - Tokens: tokens, - Type: distributeType, - } -} - -func (fee *Fee) AddFee(other Fee) { - if other.IsEmpty() { - return - } - - if fee.Tokens == nil { - fee.Tokens = other.Tokens - fee.Type = other.Type - } else { - fee.Tokens = fee.Tokens.Plus(other.Tokens) - if other.Type == FeeForAll { - fee.Type = FeeForAll - } - } -} - -func (fee Fee) IsEmpty() bool { - return fee.Tokens == nil || fee.Tokens.IsEqual(sdk.Coins{}) -} - -// Any change of this method should communicate with services (query, explorer) developers -// More detail can be found: -// https://github.com/binance-chain/docs-site/wiki/Fee-Calculation,-Collection-and-Distribution#publication -func (fee Fee) SerializeForPub(canceled, expired int) string { - if fee.IsEmpty() { - return "" - } else { - res := fee.serialize() - if canceled > 0 { - res += fmt.Sprintf("%s%s%s%d", serializeSeparator, canceledCharacter, amountDenomSeparator, canceled) - } - if expired > 0 { - res += fmt.Sprintf("%s%s%s%d", serializeSeparator, expiredCharacter, amountDenomSeparator, expired) - } - return res - } -} - -func (fee Fee) String() string { - return fee.serialize() -} - -func (fee Fee) serialize() string { - if fee.IsEmpty() { - return "" - } else { - var buffer bytes.Buffer - for _, coin := range fee.Tokens { - buffer.WriteString(fmt.Sprintf("%s%s%s%s", coin.Denom, amountDenomSeparator, strconv.FormatInt(coin.Amount, 10), serializeSeparator)) - } - res := buffer.String() - return res[:len(res)-1] - } -} diff --git a/common/types/mini_token.go b/common/types/mini_token.go index fd3c1850a..e02227a7b 100644 --- a/common/types/mini_token.go +++ b/common/types/mini_token.go @@ -58,14 +58,16 @@ var SupplyRange = struct { }{TinyRangeType, MiniRangeType} type MiniToken struct { - 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 + 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 + ContractAddress string `json:"contract_address,omitempty"` + ContractDecimals int8 `json:"contract_decimals,omitempty"` } var _ IToken = &MiniToken{} @@ -103,6 +105,22 @@ func (token *MiniToken) SetTotalSupply(totalSupply utils.Fixed8) { token.TotalSupply = totalSupply } +func (token *MiniToken) SetContractDecimals(decimal int8) { + token.ContractDecimals = decimal +} + +func (token MiniToken) GetContractDecimals() int8 { + return token.ContractDecimals +} + +func (token *MiniToken) SetContractAddress(addr string) { + token.ContractAddress = addr +} + +func (token *MiniToken) GetContractAddress() string { + return token.ContractAddress +} + func (token MiniToken) GetOwner() sdk.AccAddress { return token.Owner } diff --git a/common/types/token.go b/common/types/token.go index a3c1ae974..8e4be05d9 100644 --- a/common/types/token.go +++ b/common/types/token.go @@ -32,6 +32,11 @@ type IToken interface { GetOrigSymbol() string GetTotalSupply() utils.Fixed8 SetTotalSupply(totalSupply utils.Fixed8) + SetContractAddress(addr string) + GetContractAddress() string + SetContractDecimals(decimal int8) + GetContractDecimals() int8 + GetOwner() sdk.AccAddress IsMintable() bool IsOwner(addr sdk.AccAddress) bool @@ -41,18 +46,36 @@ type IToken interface { var _ IToken = &Token{} type Token struct { - 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"` + 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"` + ContractAddress string `json:"contract_address,omitempty"` + ContractDecimals int8 `json:"contract_decimals,omitempty"` } func (token Token) GetName() string { return token.Name } +func (token *Token) SetContractDecimals(decimal int8) { + token.ContractDecimals = decimal +} + +func (token Token) GetContractDecimals() int8 { + return token.ContractDecimals +} + +func (token *Token) SetContractAddress(addr string) { + token.ContractAddress = addr +} + +func (token *Token) GetContractAddress() string { + return token.ContractAddress +} + func (token Token) GetSymbol() string { return token.Symbol } diff --git a/common/types/token_test.go b/common/types/token_test.go index f92ceaca6..e0e1f34da 100644 --- a/common/types/token_test.go +++ b/common/types/token_test.go @@ -1,11 +1,14 @@ package types_test import ( + "encoding/json" "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/utils" ) var issueMsgSymbolTestCases = []struct { @@ -106,3 +109,40 @@ func TestValidateTokenSymbol(t *testing.T) { t.Errorf("ValidateIssueSymbol() error = %v, expected XYZ to be invalid", err) } } + +func TestMarshalToken(t *testing.T) { + type beforeToken struct { + 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"` + } + + type beforeMiniToken struct { + 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 types.SupplyRangeType `json:"token_type"` + TokenURI string `json:"token_uri"` //TODO set max length + } + + emptyBeforeToken, err := json.Marshal(beforeToken{}) + require.Nil(t, err, "error should be nil") + + emptyBeforeMiniToken, err := json.Marshal(beforeMiniToken{}) + require.Nil(t, err, "error should be nil") + + emptyToken, err := json.Marshal(types.Token{}) + require.Nil(t, err, "error should be nil") + + emptyMiniToken, err := json.Marshal(types.MiniToken{}) + require.Nil(t, err, "error should be nil") + + require.Equal(t, string(emptyBeforeToken), string(emptyToken)) + require.Equal(t, string(emptyBeforeMiniToken), string(emptyMiniToken)) +} diff --git a/common/upgrade/upgrade.go b/common/upgrade/upgrade.go index 41ac806bd..cb75de802 100644 --- a/common/upgrade/upgrade.go +++ b/common/upgrade/upgrade.go @@ -9,21 +9,23 @@ var Mgr = sdk.UpgradeMgr // improvement: (maybe bep ?) const ( // Galileo Upgrade - BEP6 = "BEP6" // https://github.com/binance-chain/BEPs/pull/6 - BEP9 = "BEP9" // https://github.com/binance-chain/BEPs/pull/9 - BEP10 = "BEP10" // https://github.com/binance-chain/BEPs/pull/10 - BEP19 = "BEP19" // https://github.com/binance-chain/BEPs/pull/19 match engine revision + BEP6 = "BEP6" // https://github.com/binance-chain/BEPs/pull/6 + BEP9 = sdk.BEP9 // https://github.com/binance-chain/BEPs/pull/9 + BEP10 = "BEP10" // https://github.com/binance-chain/BEPs/pull/10 + BEP19 = "BEP19" // https://github.com/binance-chain/BEPs/pull/19 match engine revision // Hubble Upgrade - BEP12 = "BEP12" // https://github.com/binance-chain/BEPs/pull/17 + BEP12 = sdk.BEP12 // https://github.com/binance-chain/BEPs/pull/17 // Archimedes Upgrade - BEP3 = "BEP3" // https://github.com/binance-chain/BEPs/pull/30 - - // TODO: add upgrade name + BEP3 = sdk.BEP3 // https://github.com/binance-chain/BEPs/pull/30 + // Heisenberg Upgrade FixSignBytesOverflow = sdk.FixSignBytesOverflow LotSizeOptimization = "LotSizeOptimization" ListingRuleUpgrade = "ListingRuleUpgrade" // Remove restriction that only the owner of base asset can list trading pair FixZeroBalance = "FixZeroBalance" + // TODO: add upgrade name + LaunchBscUpgrade = sdk.LaunchBscUpgrade + //Nightingale 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 diff --git a/go.mod b/go.mod index 4d256f838..c8b0d28f3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.12 require ( github.com/Shopify/sarama v1.21.0 github.com/cosmos/cosmos-sdk v0.25.0 - github.com/deathowl/go-metrics-prometheus v0.0.0-20170731161557-091131e49c33 + github.com/deathowl/go-metrics-prometheus v0.0.0-20200518174047-74482eab5bfb github.com/eapache/go-resiliency v1.1.0 github.com/go-kit/kit v0.9.0 github.com/google/btree v1.0.0 @@ -15,11 +15,10 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/natefinch/lumberjack v2.0.0+incompatible github.com/pkg/errors v0.8.1 - github.com/prometheus/client_golang v0.9.3 + github.com/prometheus/client_golang v1.1.0 github.com/spf13/cobra v0.0.5 github.com/spf13/viper v1.4.0 github.com/stretchr/testify v1.4.0 - github.com/syndtr/goleveldb v1.0.1-0.20190625080220-02440ea7a285 // indirect github.com/tendermint/go-amino v0.15.0 github.com/tendermint/iavl v0.12.4 github.com/tendermint/tendermint v0.32.3 @@ -29,10 +28,10 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.22 + github.com/cosmos/cosmos-sdk => github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.23 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.4 - github.com/tendermint/tendermint => github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 + github.com/tendermint/tendermint => github.com/binance-chain/bnc-tendermint v0.32.3-binance.3 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 + golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae ) diff --git a/go.sum b/go.sum index bfdcf35ae..f4444b600 100644 --- a/go.sum +++ b/go.sum @@ -20,18 +20,19 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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.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-cosmos-sdk v0.25.0-binance.23 h1:lD8uAYAJX6ZjLf3vdvqRK7X31pmd4RObuwg6LhxBNhQ= +github.com/binance-chain/bnc-cosmos-sdk v0.25.0-binance.23/go.mod h1:25UaVXWOjzVAmL4I6szOdC4SQz4wsBG6wpv68V2vK7w= 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 v0.32.3-binance.3 h1:b8SqtWmtHPhPQ2ADzUgO9sr+ChKL9ho4dTorBjGAAyY= +github.com/binance-chain/bnc-tendermint v0.32.3-binance.3/go.mod h1:kN5dNxE8voFtDqx2HjbM8sBIH5cUuMtLg0XEHjqzUiY= 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= @@ -40,7 +41,6 @@ github.com/binance-chain/tss v0.1.2 h1:AyTedSG5HG/WAvM9PDPWjTXQ+dvNdHg3x1c+1a584 github.com/binance-chain/tss v0.1.2/go.mod h1:p6u8c5+JQI46aytQFQY7qg2FPwVjcS6Dwaui0U6WrRw= github.com/binance-chain/tss-lib v1.0.0 h1:r6Yj8g8zwiVwOAdVBu2D36Nvbxeq9qPWdVi+pqGkqQI= github.com/binance-chain/tss-lib v1.0.0/go.mod h1:5mmPQOOkBIjHxyGVesSUB2AemcZj5YkMJ+HPZY4Jd38= -github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d h1:xG8Pj6Y6J760xwETNmMzmlt38QSwz0BLp1cZ09g27uw= github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= @@ -48,7 +48,6 @@ github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcug github.com/btcsuite/btcd v0.20.0-beta h1:PamBMopnHxO2nEIsU89ibVVnqnXR2yFTgGNc+PdG68o= github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a h1:RQMUrEILyYJEoAT34XS/kLu40vC0+po/UfxrBBA4qZE= github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= @@ -77,8 +76,8 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deathowl/go-metrics-prometheus v0.0.0-20170731161557-091131e49c33 h1:hNPSOmTF8nz+l1NJfG+uFnDNMxD1w6+xSCh49GpZ2rc= -github.com/deathowl/go-metrics-prometheus v0.0.0-20170731161557-091131e49c33/go.mod h1:HyiO0WRMVDmaYgeKx/frAiip/fVpUwteTT/RkjwiA0Q= +github.com/deathowl/go-metrics-prometheus v0.0.0-20200518174047-74482eab5bfb h1:vhS5LxjRvIc6ptzKtTjzYV2rEsuAvTtez27UJkKIrjc= +github.com/deathowl/go-metrics-prometheus v0.0.0-20200518174047-74482eab5bfb/go.mod h1:kZ9Xvhj+PTMJ415unU/sutrnWDVqG0PDS/Sl4Rt3xkE= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -102,19 +101,16 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-kit/kit v0.6.0 h1:wTifptAGIyIuir4bRyN4h7+kAa2a4eepLYVmRe5qqQ8= github.com/go-kit/kit v0.6.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -141,11 +137,8 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -158,7 +151,6 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= @@ -212,6 +204,8 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -324,7 +318,6 @@ github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/linkedin/goavro v0.0.0-20180427201934-fa8f6a30176c h1:5VZFnez+6M7nwhbIT8L4DtViRFR8GpYpZj97EVAphuk= github.com/linkedin/goavro v0.0.0-20180427201934-fa8f6a30176c/go.mod h1:dGGt/b0JBWmQoI1Zfa2H/QIsh/viOpE0nHAvUgqJUf8= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -334,7 +327,6 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -354,6 +346,10 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= @@ -385,17 +381,13 @@ github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4 github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.2 h1:uqH7bpe+ERSiDa34FDOF7RikN6RzXgduUF8yarlZp94= github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -410,7 +402,6 @@ github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/primes v0.0.0-20180210170552-f6d2a1ba97c4 h1:blMAhTXF6uL1+e3eVSajjLT43Cc0U8mU1gcigbbolJM= github.com/otiai10/primes v0.0.0-20180210170552-f6d2a1ba97c4/go.mod h1:UmSP7QeU3XmAdGu5+dnrTJqjBc+IscpVZkQzk473cjM= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= @@ -422,28 +413,35 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1 h1:K47Rk0v/fkEfwfQet2KWhscE0cJzjgCCDBG2KHZoVno= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 h1:Cto4X6SVMWRPBkJ/3YHn1iDGDGc/Z+sW+AEMKHMVvN4= github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.5/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -458,23 +456,19 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.1 h1:zZh3X5aZbdnoj+4XkaBxKfhO4ot82icYdhhREIAXIj8= github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I= github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= @@ -483,7 +477,6 @@ github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -491,12 +484,10 @@ github.com/syndtr/goleveldb v0.0.0-20181105012736-f9080354173f/go.mod h1:Z4AUp2K github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= -github.com/syndtr/goleveldb v1.0.1-0.20190625080220-02440ea7a285 h1:ZFIZvI27BCjHCv5nFLGgED1psRde8qpEjDOJyox+JC0= -github.com/syndtr/goleveldb v1.0.1-0.20190625080220-02440ea7a285/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= -github.com/tendermint/crypto v0.0.0-20190823143015-45b1026d81ae h1:lZSEYT71aSTaLfHo7W+N4289p45SO4dac+JHJHXRX+c= -github.com/tendermint/crypto v0.0.0-20190823143015-45b1026d81ae/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= +github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae h1:AOXNM7c2Vvo45SjAgeWF8Wy+NS7/NCqzRNpUc+HPAec= +github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -546,8 +537,8 @@ golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc= golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+Tw6seqJz1EbqbnzHrc8= golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -565,7 +556,6 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -573,10 +563,10 @@ golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -596,7 +586,6 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2 h1:67iHsV9djwGdZpdZNbLuQj6FOzCaZe3w+vhLjn5AcFA= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8bXiwHqAN5Rv3/qDCcRk0/Otx73BY= @@ -607,7 +596,6 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= @@ -624,7 +612,6 @@ gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFab gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= diff --git a/plugins/api/handlers.go b/plugins/api/handlers.go index 45c8ad6b3..bda81d3e0 100644 --- a/plugins/api/handlers.go +++ b/plugins/api/handlers.go @@ -5,11 +5,11 @@ import ( "strings" "github.com/cosmos/cosmos-sdk/client/context" + paramapi "github.com/cosmos/cosmos-sdk/x/paramHub/client/rest" 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" tkstore "github.com/binance-chain/node/plugins/tokens/store" "github.com/binance-chain/node/wire" diff --git a/plugins/bridge/alias.go b/plugins/bridge/alias.go new file mode 100644 index 000000000..550148a04 --- /dev/null +++ b/plugins/bridge/alias.go @@ -0,0 +1,18 @@ +package bridge + +import ( + "github.com/binance-chain/node/plugins/bridge/keeper" + "github.com/binance-chain/node/plugins/bridge/types" +) + +var ( + NewKeeper = keeper.NewKeeper +) + +type ( + Keeper = keeper.Keeper + + TransferOutMsg = types.TransferOutMsg + BindMsg = types.BindMsg + UnbindMsg = types.UnbindMsg +) diff --git a/plugins/bridge/client/cli/commands.go b/plugins/bridge/client/cli/commands.go new file mode 100644 index 000000000..cc8612acf --- /dev/null +++ b/plugins/bridge/client/cli/commands.go @@ -0,0 +1,30 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/spf13/cobra" +) + +func AddCommands(cmd *cobra.Command, cdc *codec.Codec) { + bridgeCmd := &cobra.Command{ + Use: "bridge", + Short: "bridge commands", + } + + bridgeCmd.AddCommand( + client.PostCommands( + BindCmd(cdc), + TransferOutCmd(cdc), + UnbindCmd(cdc), + )..., + ) + + bridgeCmd.AddCommand(client.LineBreak) + + bridgeCmd.AddCommand( + client.GetCommands( + QueryProphecy(cdc))..., + ) + cmd.AddCommand(bridgeCmd) +} diff --git a/plugins/bridge/client/cli/tx.go b/plugins/bridge/client/cli/tx.go new file mode 100644 index 000000000..7f2664d35 --- /dev/null +++ b/plugins/bridge/client/cli/tx.go @@ -0,0 +1,205 @@ +package cli + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" + "github.com/cosmos/cosmos-sdk/x/oracle" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/binance-chain/node/common" + "github.com/binance-chain/node/common/client" + "github.com/binance-chain/node/plugins/bridge/types" + "github.com/binance-chain/node/wire" +) + +const ( + flagSequence = "channel-sequence" + flagSideChainId = "side-chain-id" + flagContractAddress = "contract-address" + flagAmount = "amount" + flagSymbol = "symbol" + flagContractDecimals = "contract-decimals" + flagToAddress = "to" + flagExpireTime = "expire-time" + + flagChannelId = "channel-id" +) + +func BindCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "bind", + Short: "bind smart chain token to bep2 token", + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) + + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + contractAddressStr := viper.GetString(flagContractAddress) + contractDecimals := viper.GetInt(flagContractDecimals) + amount := viper.GetInt64(flagAmount) + symbol := viper.GetString(flagSymbol) + expireTime := viper.GetInt64(flagExpireTime) + + // build message + contractAddress, err := types.NewSmartChainAddress(contractAddressStr) + if err != nil { + return err + } + msg := types.NewBindMsg(from, symbol, amount, contractAddress, int8(contractDecimals), expireTime) + + sdkErr := msg.ValidateBasic() + if sdkErr != nil { + return fmt.Errorf("%v", sdkErr.Data()) + } + return client.SendOrPrintTx(cliCtx, txBldr, msg) + }, + } + + cmd.Flags().String(flagContractAddress, "", "contract address") + cmd.Flags().Int(flagContractDecimals, 0, "contract token decimals") + cmd.Flags().Int64(flagAmount, 0, "amount to bind") + cmd.Flags().String(flagSymbol, "", "symbol") + cmd.Flags().Int64(flagExpireTime, 0, "expire timestamp(s)") + + return cmd +} + +func UnbindCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "unbind", + Short: "unbind smart chain token to bep2 token", + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) + + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + symbol := viper.GetString(flagSymbol) + + // build message + msg := types.NewUnbindMsg(from, symbol) + + sdkErr := msg.ValidateBasic() + if sdkErr != nil { + return fmt.Errorf("%v", sdkErr.Data()) + } + return client.SendOrPrintTx(cliCtx, txBldr, msg) + }, + } + + cmd.Flags().String(flagSymbol, "", "symbol") + return cmd +} + +func TransferOutCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "transfer-out", + Short: "transfer bep2 token to smart chain", + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) + + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + toAddressStr := viper.GetString(flagToAddress) + amount := viper.GetString(flagAmount) + expireTime := viper.GetInt64(flagExpireTime) + + amountToTransfer, err := sdk.ParseCoin(amount) + if err != nil { + return err + } + + // build message + toAddress, err := types.NewSmartChainAddress(toAddressStr) + if err != nil { + return err + } + msg := types.NewTransferOutMsg(from, toAddress, amountToTransfer, expireTime) + + sdkErr := msg.ValidateBasic() + if sdkErr != nil { + return fmt.Errorf("%v", sdkErr.Data()) + } + return client.SendOrPrintTx(cliCtx, txBldr, msg) + }, + } + + cmd.Flags().String(flagToAddress, "", "smart chain address") + cmd.Flags().String(flagAmount, "", "amount") + cmd.Flags().Int64(flagExpireTime, 0, "expire timestamp(s)") + + return cmd +} + +func QueryProphecy(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "query-prophecy", + Short: "query oracle prophecy", + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + sequence := viper.GetInt64(flagSequence) + chainId := viper.GetUint(flagSideChainId) + channelId := viper.GetUint(flagChannelId) + + key := oracle.GetClaimId(sdk.ChainID(chainId), sdk.ChannelID(channelId), uint64(sequence)) + res, err := cliCtx.QueryStore([]byte(key), common.OracleStoreName) + if err != nil { + return err + } + + if len(res) == 0 { + fmt.Printf("No such claim exists\n") + return nil + } + + dbProphecy := new(oracle.DBProphecy) + err = cdc.UnmarshalBinaryBare(res, &dbProphecy) + if err != nil { + return err + } + + prophecy, err := dbProphecy.DeserializeFromDB() + if err != nil { + return err + } + + output, err := wire.MarshalJSONIndent(cdc, prophecy) + if err != nil { + return err + } + fmt.Println(string(output)) + + return nil + }, + } + + cmd.Flags().Int64(flagSequence, 0, "sequence of channel") + cmd.Flags().Int(flagChannelId, 0, "channel id") + cmd.Flags().Uint16(flagSideChainId, 0, "side chain id") + + return cmd +} diff --git a/plugins/bridge/cross_app.go b/plugins/bridge/cross_app.go new file mode 100644 index 000000000..313da845f --- /dev/null +++ b/plugins/bridge/cross_app.go @@ -0,0 +1,406 @@ +package bridge + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/common/log" + "github.com/binance-chain/node/plugins/bridge/types" +) + +var _ sdk.CrossChainApplication = &BindApp{} + +type BindApp struct { + bridgeKeeper Keeper +} + +func NewBindApp(bridgeKeeper Keeper) *BindApp { + return &BindApp{ + bridgeKeeper: bridgeKeeper, + } +} + +func (app *BindApp) ExecuteAckPackage(ctx sdk.Context, payload []byte) sdk.ExecuteResult { + log.With("module", "bridge").Info("received bind ack package") + return sdk.ExecuteResult{} +} + +func (app *BindApp) ExecuteFailAckPackage(ctx sdk.Context, payload []byte) sdk.ExecuteResult { + log.With("module", "bridge").Info("received bind fail ack package") + bindPackage, sdkErr := types.DeserializeBindSynPackage(payload) + if sdkErr != nil { + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + symbol := types.BytesToSymbol(bindPackage.TokenSymbol) + bindRequest, sdkErr := app.bridgeKeeper.GetBindRequest(ctx, symbol) + if sdkErr != nil { + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + _, sdkErr = app.bridgeKeeper.BankKeeper.SendCoins(ctx, types.PegAccount, bindRequest.From, + sdk.Coins{sdk.Coin{Denom: bindRequest.Symbol, Amount: bindRequest.DeductedAmount}}) + if sdkErr != nil { + log.With("module", "bridge").Error("send coins error", "err", sdkErr.Error()) + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + app.bridgeKeeper.DeleteBindRequest(ctx, symbol) + + if ctx.IsDeliverTx() { + app.bridgeKeeper.Pool.AddAddrs([]sdk.AccAddress{types.PegAccount, bindRequest.From}) + publishCrossChainEvent(ctx, app.bridgeKeeper, types.PegAccount.String(), []CrossReceiver{ + {bindRequest.From.String(), bindRequest.DeductedAmount}}, symbol, TransferFailBindType, 0) + } + return sdk.ExecuteResult{} +} + +func (app *BindApp) ExecuteSynPackage(ctx sdk.Context, payload []byte, relayerFee int64) sdk.ExecuteResult { + approvePackage, sdkErr := types.DeserializeApproveBindSynPackage(payload) + if sdkErr != nil { + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + symbol := types.BytesToSymbol(approvePackage.TokenSymbol) + + bindRequest, sdkErr := app.bridgeKeeper.GetBindRequest(ctx, symbol) + if sdkErr != nil { + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + if bindRequest.Symbol != symbol { + return sdk.ExecuteResult{ + Err: types.ErrInvalidClaim(fmt.Sprintf("approve symbol(%s) is not identical to bind request symbol(%s)", symbol, bindRequest.Symbol)), + } + } + + log.With("module", "bridge").Info("update bind status", "status", approvePackage.Status.String(), "symbol", symbol) + if approvePackage.Status == types.BindStatusSuccess { + sdkErr := app.bridgeKeeper.TokenMapper.UpdateBind(ctx, bindRequest.Symbol, + bindRequest.ContractAddress.String(), bindRequest.ContractDecimals) + + if sdkErr != nil { + log.With("module", "bridge").Error("update token info error", "err", sdkErr.Error(), "symbol", symbol) + return sdk.ExecuteResult{ + Err: sdk.ErrInternal(fmt.Sprintf("update token bind info error")), + } + } + + app.bridgeKeeper.SetContractDecimals(ctx, bindRequest.ContractAddress, bindRequest.ContractDecimals) + if ctx.IsDeliverTx() { + publishBindSuccessEvent(ctx, app.bridgeKeeper, sdk.PegAccount.String(), []CrossReceiver{}, symbol, TransferApproveBindType, relayerFee, bindRequest.ContractAddress.String(), bindRequest.ContractDecimals) + } + log.With("module", "bridge").Info("bind token success", "symbol", symbol, "contract_addr", bindRequest.ContractAddress.String()) + } else { + _, sdkErr = app.bridgeKeeper.BankKeeper.SendCoins(ctx, types.PegAccount, bindRequest.From, + sdk.Coins{sdk.Coin{Denom: bindRequest.Symbol, Amount: bindRequest.DeductedAmount}}) + if sdkErr != nil { + log.With("module", "bridge").Error("send coins error", "err", sdkErr.Error()) + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + if ctx.IsDeliverTx() { + app.bridgeKeeper.Pool.AddAddrs([]sdk.AccAddress{types.PegAccount, bindRequest.From}) + publishBindSuccessEvent(ctx, app.bridgeKeeper, types.PegAccount.String(), []CrossReceiver{ + {bindRequest.From.String(), bindRequest.DeductedAmount}}, symbol, TransferFailBindType, relayerFee, bindRequest.ContractAddress.String(), bindRequest.ContractDecimals) + } + } + + app.bridgeKeeper.DeleteBindRequest(ctx, symbol) + return sdk.ExecuteResult{} +} + +var _ sdk.CrossChainApplication = &TransferOutApp{} + +type TransferOutApp struct { + bridgeKeeper Keeper +} + +func NewTransferOutApp(bridgeKeeper Keeper) *TransferOutApp { + return &TransferOutApp{ + bridgeKeeper: bridgeKeeper, + } +} + +func (app *TransferOutApp) checkPackage(refundPackage *types.TransferOutRefundPackage) sdk.Error { + if len(refundPackage.RefundAddr) != sdk.AddrLen { + return sdk.ErrInvalidAddress(refundPackage.RefundAddr.String()) + } + + if refundPackage.RefundAmount.Int64() < 0 { + return types.ErrInvalidAmount("amount to refund should be positive") + } + return nil +} + +func (app *TransferOutApp) ExecuteAckPackage(ctx sdk.Context, payload []byte) sdk.ExecuteResult { + if len(payload) == 0 { + log.With("module", "bridge").Info("receive transfer out ack package") + return sdk.ExecuteResult{} + } + + log.With("module", "bridge").Info("receive transfer out refund ack package") + + refundPackage, sdkErr := types.DeserializeTransferOutRefundPackage(payload) + if sdkErr != nil { + log.With("module", "bridge").Error("unmarshal transfer out refund claim error", "err", sdkErr.Error(), "claim", string(payload)) + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + sdkErr = app.checkPackage(refundPackage) + if sdkErr != nil { + log.With("module", "bridge").Error("check transfer out refund package error", "err", sdkErr.Error(), "claim", string(payload)) + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + symbol := types.BytesToSymbol(refundPackage.TokenSymbol) + _, sdkErr = app.bridgeKeeper.BankKeeper.SendCoins(ctx, types.PegAccount, refundPackage.RefundAddr, + sdk.Coins{ + sdk.Coin{ + Denom: symbol, + Amount: refundPackage.RefundAmount.Int64(), + }, + }, + ) + if sdkErr != nil { + log.With("module", "bridge").Error("send coins error", "err", sdkErr.Error()) + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + if ctx.IsDeliverTx() { + app.bridgeKeeper.Pool.AddAddrs([]sdk.AccAddress{types.PegAccount, refundPackage.RefundAddr}) + publishCrossChainEvent(ctx, app.bridgeKeeper, types.PegAccount.String(), []CrossReceiver{ + {refundPackage.RefundAddr.String(), refundPackage.RefundAmount.Int64()}}, symbol, TransferAckRefundType, 0) + } + return sdk.ExecuteResult{ + Tags: sdk.Tags{sdk.GetPegOutTag(symbol, refundPackage.RefundAmount.Int64())}, + } +} + +func (app *TransferOutApp) ExecuteFailAckPackage(ctx sdk.Context, payload []byte) sdk.ExecuteResult { + log.With("module", "bridge").Info("received transfer out fail ack package") + + transferOutPackage, sdkErr := types.DeserializeTransferOutSynPackage(payload) + if sdkErr != nil { + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + contractDecimals := app.bridgeKeeper.GetContractDecimals(ctx, transferOutPackage.ContractAddress) + bcAmount, sdkErr := types.ConvertBSCAmountToBCAmount(contractDecimals, sdk.NewIntFromBigInt(transferOutPackage.Amount)) + if sdkErr != nil { + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + symbol := types.BytesToSymbol(transferOutPackage.TokenSymbol) + _, sdkErr = app.bridgeKeeper.BankKeeper.SendCoins(ctx, types.PegAccount, transferOutPackage.RefundAddress, + sdk.Coins{ + sdk.Coin{ + Denom: symbol, + Amount: bcAmount, + }, + }, + ) + + if sdkErr != nil { + log.With("module", "bridge").Error("send coins error", "err", sdkErr.Error()) + return sdk.ExecuteResult{ + Err: sdkErr, + } + } + + if ctx.IsDeliverTx() { + app.bridgeKeeper.Pool.AddAddrs([]sdk.AccAddress{types.PegAccount, transferOutPackage.RefundAddress}) + publishCrossChainEvent(ctx, app.bridgeKeeper, types.PegAccount.String(), []CrossReceiver{ + {transferOutPackage.RefundAddress.String(), bcAmount}}, symbol, TransferFailAckRefundType, 0) + } + + return sdk.ExecuteResult{ + Tags: sdk.Tags{sdk.GetPegOutTag(symbol, bcAmount)}, + } +} + +func (app *TransferOutApp) ExecuteSynPackage(ctx sdk.Context, payload []byte, _ int64) sdk.ExecuteResult { + log.With("module", "bridge").Error("received transfer out syn package ") + return sdk.ExecuteResult{} +} + +var _ sdk.CrossChainApplication = &TransferInApp{} + +type TransferInApp struct { + bridgeKeeper Keeper +} + +func NewTransferInApp(bridgeKeeper Keeper) *TransferInApp { + return &TransferInApp{ + bridgeKeeper: bridgeKeeper, + } +} + +func (app *TransferInApp) checkTransferInSynPackage(transferInPackage *types.TransferInSynPackage) sdk.Error { + if len(transferInPackage.Amounts) == 0 { + return types.ErrInvalidLength("length of Amounts should not be 0") + } + + if len(transferInPackage.RefundAddresses) != len(transferInPackage.ReceiverAddresses) || + len(transferInPackage.RefundAddresses) != len(transferInPackage.Amounts) { + return types.ErrInvalidLength("length of RefundAddresses, ReceiverAddresses, Amounts should be the same") + } + + for _, addr := range transferInPackage.RefundAddresses { + if addr.IsEmpty() { + return types.ErrInvalidEthereumAddress("refund address should not be empty") + } + } + + for _, addr := range transferInPackage.ReceiverAddresses { + if len(addr) != sdk.AddrLen { + return sdk.ErrInvalidAddress(fmt.Sprintf("length of receiver addreess should be %d", sdk.AddrLen)) + } + } + + for _, amount := range transferInPackage.Amounts { + if amount.Int64() <= 0 { + return types.ErrInvalidAmount("amount to send should be positive") + } + } + + return nil +} + +func (app *TransferInApp) ExecuteAckPackage(ctx sdk.Context, payload []byte) sdk.ExecuteResult { + log.With("module", "bridge").Error("received transfer in ack package ") + return sdk.ExecuteResult{} +} + +func (app *TransferInApp) ExecuteFailAckPackage(ctx sdk.Context, payload []byte) sdk.ExecuteResult { + log.With("module", "bridge").Error("received transfer in fail ack package ") + return sdk.ExecuteResult{} +} + +func (app *TransferInApp) ExecuteSynPackage(ctx sdk.Context, payload []byte, relayerFee int64) sdk.ExecuteResult { + transferInPackage, sdkErr := types.DeserializeTransferInSynPackage(payload) + if sdkErr != nil { + log.With("module", "bridge").Error("unmarshal transfer in claim error", "err", sdkErr.Error(), "claim", string(payload)) + panic("unmarshal transfer in claim error") + } + + sdkErr = app.checkTransferInSynPackage(transferInPackage) + if sdkErr != nil { + log.With("module", "bridge").Error("check transfer in package error", "err", sdkErr.Error(), "claim", string(payload)) + panic(sdkErr) + } + + symbol := types.BytesToSymbol(transferInPackage.TokenSymbol) + tokenInfo, err := app.bridgeKeeper.TokenMapper.GetToken(ctx, symbol) + if err != nil { + panic(err) + } + + if tokenInfo.GetContractAddress() != transferInPackage.ContractAddress.String() { + // check decimals of contract + contractDecimals := app.bridgeKeeper.GetContractDecimals(ctx, transferInPackage.ContractAddress) + if contractDecimals < 0 { + log.With("module", "bridge").Error("decimals of contract does not exist", "contract_addr", transferInPackage.ContractAddress.String()) + panic(fmt.Sprintf("decimals of contract does not exist, contract_addr=%s", + transferInPackage.ContractAddress.String())) + } + + refundPackage, sdkErr := app.bridgeKeeper.RefundTransferIn(contractDecimals, transferInPackage, types.UnboundToken) + if sdkErr != nil { + log.With("module", "bridge").Error("refund transfer in error", "err", sdkErr.Error()) + panic(sdkErr) + } + return sdk.ExecuteResult{ + Payload: refundPackage, + Err: types.ErrTokenBindRelationChanged("contract addr mismatch"), + } + } + + if int64(transferInPackage.ExpireTime) < ctx.BlockHeader().Time.Unix() { + refundPackage, sdkErr := app.bridgeKeeper.RefundTransferIn(tokenInfo.GetContractDecimals(), transferInPackage, types.Timeout) + if sdkErr != nil { + log.With("module", "bridge").Error("refund transfer in error", "err", sdkErr.Error()) + panic(sdkErr) + } + return sdk.ExecuteResult{ + Payload: refundPackage, + Err: types.ErrTransferInExpire("the package is expired"), + } + } + + balance := app.bridgeKeeper.BankKeeper.GetCoins(ctx, types.PegAccount) + var totalTransferInAmount sdk.Coins + for idx := range transferInPackage.ReceiverAddresses { + amount := sdk.NewCoin(symbol, transferInPackage.Amounts[idx].Int64()) + totalTransferInAmount = sdk.Coins{amount}.Plus(totalTransferInAmount) + } + + if !balance.IsGTE(totalTransferInAmount) { + refundPackage, sdkErr := app.bridgeKeeper.RefundTransferIn(tokenInfo.GetContractDecimals(), transferInPackage, types.InsufficientBalance) + if sdkErr != nil { + log.With("module", "bridge").Error("refund transfer in error", "err", sdkErr.Error()) + panic(sdkErr) + } + return sdk.ExecuteResult{ + Payload: refundPackage, + Err: sdk.ErrInsufficientFunds("balance of peg account is insufficient"), + } + } + + for idx, receiverAddr := range transferInPackage.ReceiverAddresses { + amount := sdk.NewCoin(symbol, transferInPackage.Amounts[idx].Int64()) + _, sdkErr = app.bridgeKeeper.BankKeeper.SendCoins(ctx, types.PegAccount, receiverAddr, sdk.Coins{amount}) + if sdkErr != nil { + log.With("module", "bridge").Error("send coins error", "err", sdkErr.Error()) + panic(sdkErr) + } + } + + if ctx.IsDeliverTx() { + addressesChanged := append(transferInPackage.ReceiverAddresses, types.PegAccount) + app.bridgeKeeper.Pool.AddAddrs(addressesChanged) + to := make([]CrossReceiver, 0, len(transferInPackage.ReceiverAddresses)) + for idx, receiverAddr := range transferInPackage.ReceiverAddresses { + to = append(to, CrossReceiver{ + Addr: receiverAddr.String(), + Amount: transferInPackage.Amounts[idx].Int64(), + }) + } + publishCrossChainEvent(ctx, app.bridgeKeeper, types.PegAccount.String(), to, symbol, TransferInType, relayerFee) + } + + // emit peg related event + var totalAmount int64 = 0 + var tags sdk.Tags + if totalTransferInAmount != nil { + totalAmount = totalTransferInAmount.AmountOf(symbol) + tags = sdk.Tags{sdk.GetPegOutTag(symbol, totalAmount)} + } + + return sdk.ExecuteResult{ + Tags: tags, + } +} diff --git a/plugins/bridge/handler.go b/plugins/bridge/handler.go new file mode 100644 index 000000000..c4d61f500 --- /dev/null +++ b/plugins/bridge/handler.go @@ -0,0 +1,322 @@ +package bridge + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/bsc/rlp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" + + "github.com/binance-chain/node/common/log" + cmmtypes "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/bridge/types" +) + +func NewHandler(keeper Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case TransferOutMsg: + return handleTransferOutMsg(ctx, keeper, msg) + case BindMsg: + return handleBindMsg(ctx, keeper, msg) + case UnbindMsg: + return handleUnbindMsg(ctx, keeper, msg) + default: + errMsg := "Unrecognized bridge msg type" + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleUnbindMsg(ctx sdk.Context, keeper Keeper, msg UnbindMsg) sdk.Result { + // check is native symbol + if msg.Symbol == cmmtypes.NativeTokenSymbol { + return types.ErrInvalidSymbol("can not unbind native symbol").Result() + } + + token, err := keeper.TokenMapper.GetToken(ctx, msg.Symbol) + if err != nil { + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + if token.GetContractAddress() == "" { + return types.ErrTokenBound(fmt.Sprintf("token %s is not bound", msg.Symbol)).Result() + } + + if !token.IsOwner(msg.From) { + return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can unbind token %s", msg.Symbol)).Result() + } + + relayFee, sdkErr := types.GetFee(types.UnbindRelayFeeName) + if sdkErr != nil { + return sdkErr.Result() + } + + bscRelayFee, sdkErr := types.ConvertBCAmountToBSCAmount(types.BSCBNBDecimals, relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol)) + if sdkErr != nil { + return sdkErr.Result() + } + + _, sdkErr = keeper.BankKeeper.SendCoins(ctx, msg.From, types.PegAccount, relayFee.Tokens) + if sdkErr != nil { + log.With("module", "bridge").Error("send coins error", "err", sdkErr.Error()) + return sdkErr.Result() + } + + unbindPackage := types.BindSynPackage{ + PackageType: types.BindTypeUnbind, + TokenSymbol: types.SymbolToBytes(msg.Symbol), + } + + encodedPackage, err := rlp.EncodeToBytes(unbindPackage) + if err != nil { + log.With("module", "bridge").Error("encode unbind package error", "err", err.Error()) + return sdk.ErrInternal("encode unbind package error").Result() + } + + sendSeq, sdkErr := keeper.IbcKeeper.CreateRawIBCPackageByIdWithFee(ctx, keeper.DestChainId, types.BindChannelID, sdk.SynCrossChainPackageType, + encodedPackage, *bscRelayFee.BigInt()) + if sdkErr != nil { + log.With("module", "bridge").Error("create unbind ibc package error", "err", sdkErr.Error()) + return sdkErr.Result() + } + + err = keeper.TokenMapper.UpdateBind(ctx, msg.Symbol, "", 0) + if err != nil { + log.With("module", "bridge").Error("update token info error", "err", err.Error()) + return sdk.ErrInternal(fmt.Sprintf("update token error, err=%s", err.Error())).Result() + } + + log.With("module", "bridge").Info("unbind token success", "symbol", msg.Symbol, "contract_addr", token.GetContractDecimals()) + if ctx.IsDeliverTx() { + keeper.Pool.AddAddrs([]sdk.AccAddress{types.PegAccount, msg.From}) + publishBindSuccessEvent(ctx, keeper, msg.From.String(), []CrossReceiver{}, msg.Symbol, TransferUnBindType, relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol), + token.GetContractAddress(), token.GetContractDecimals()) + } + + tags := sdk.NewTags( + types.TagSendSequence, []byte(strconv.FormatUint(sendSeq, 10)), + types.TagChannel, []byte{uint8(types.BindChannelID)}, + types.TagRelayerFee, []byte(strconv.FormatInt(relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol), 10)), + ) + return sdk.Result{ + Tags: tags, + } +} + +func handleBindMsg(ctx sdk.Context, keeper Keeper, msg BindMsg) sdk.Result { + if !time.Unix(msg.ExpireTime, 0).After(ctx.BlockHeader().Time.Add(types.MinBindExpireTimeGap)) { + return types.ErrInvalidExpireTime(fmt.Sprintf("expire time should be %d seconds after now(%s)", + int64(types.MinBindExpireTimeGap.Seconds()), ctx.BlockHeader().Time.UTC().String())).Result() + } + + symbol := strings.ToUpper(msg.Symbol) + + // check is native symbol + if symbol == cmmtypes.NativeTokenSymbol { + return types.ErrInvalidSymbol("can not bind native symbol").Result() + } + + token, err := keeper.TokenMapper.GetToken(ctx, symbol) + if err != nil { + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", msg.Symbol)).Result() + } + + if token.GetContractAddress() != "" { + return types.ErrTokenBound(fmt.Sprintf("token %s is already bound", symbol)).Result() + } + + if !token.IsOwner(msg.From) { + return sdk.ErrUnauthorized(fmt.Sprintf("only the owner can bind token %s", msg.Symbol)).Result() + } + + // if token owner has bound token before, decimals should be the same as the original when contract address is the same. + existsContractDecimals := keeper.GetContractDecimals(ctx, msg.ContractAddress) + if existsContractDecimals >= 0 && existsContractDecimals != msg.ContractDecimals { + return types.ErrInvalidDecimals(fmt.Sprintf("decimals should be %d", existsContractDecimals)).Result() + } + + tokenAmount := keeper.BankKeeper.GetCoins(ctx, types.PegAccount).AmountOf(symbol) + if msg.Amount < tokenAmount { + return sdk.ErrInvalidCoins(fmt.Sprintf("bind amount should be no less than %d", tokenAmount)).Result() + } + + peggyAmount := sdk.Coins{ + sdk.Coin{Denom: symbol, Amount: msg.Amount - tokenAmount}, + } + + relayFee, sdkErr := types.GetFee(types.BindRelayFeeName) + if sdkErr != nil { + return sdkErr.Result() + } + transferAmount := peggyAmount.Plus(relayFee.Tokens) + + bscTotalSupply, sdkErr := types.ConvertBCAmountToBSCAmount(msg.ContractDecimals, token.GetTotalSupply().ToInt64()) + if sdkErr != nil { + return sdkErr.Result() + } + bscAmount, sdkErr := types.ConvertBCAmountToBSCAmount(msg.ContractDecimals, msg.Amount) + if sdkErr != nil { + return sdkErr.Result() + } + bscRelayFee, sdkErr := types.ConvertBCAmountToBSCAmount(types.BSCBNBDecimals, relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol)) + if sdkErr != nil { + return sdkErr.Result() + } + + _, sdkErr = keeper.BankKeeper.SendCoins(ctx, msg.From, types.PegAccount, transferAmount) + if sdkErr != nil { + log.With("module", "bridge").Error("send coins error", "err", sdkErr.Error()) + return sdkErr.Result() + } + + bindRequest := types.BindRequest{ + From: msg.From, + Symbol: symbol, + Amount: msg.Amount, + DeductedAmount: msg.Amount - tokenAmount, + ContractAddress: msg.ContractAddress, + ContractDecimals: msg.ContractDecimals, + ExpireTime: msg.ExpireTime, + } + sdkErr = keeper.CreateBindRequest(ctx, bindRequest) + if sdkErr != nil { + log.With("module", "bridge").Error("create bind request error", "err", sdkErr.Error()) + return sdkErr.Result() + } + + bindPackage := types.BindSynPackage{ + PackageType: types.BindTypeBind, + TokenSymbol: types.SymbolToBytes(msg.Symbol), + ContractAddr: msg.ContractAddress, + TotalSupply: bscTotalSupply.BigInt(), + PeggyAmount: bscAmount.BigInt(), + Decimals: uint8(msg.ContractDecimals), + ExpireTime: uint64(msg.ExpireTime), + } + + encodedPackage, err := rlp.EncodeToBytes(bindPackage) + if err != nil { + log.With("module", "bridge").Error("encode unbind package error", "err", err.Error()) + return sdk.ErrInternal("encode unbind package error").Result() + } + + sendSeq, sdkErr := keeper.IbcKeeper.CreateRawIBCPackageByIdWithFee(ctx, keeper.DestChainId, types.BindChannelID, sdk.SynCrossChainPackageType, encodedPackage, + *bscRelayFee.BigInt()) + if sdkErr != nil { + log.With("module", "bridge").Error("create bind ibc package error", "err", sdkErr.Error()) + return sdkErr.Result() + } + + if ctx.IsDeliverTx() { + keeper.Pool.AddAddrs([]sdk.AccAddress{types.PegAccount, msg.From}) + publishCrossChainEvent(ctx, keeper, msg.From.String(), []CrossReceiver{ + {types.PegAccount.String(), bindRequest.DeductedAmount}}, symbol, TransferBindType, relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol)) + } + pegTags := sdk.Tags{} + for _, coin := range transferAmount { + if coin.Amount > 0 { + pegTags = append(pegTags, sdk.GetPegInTag(coin.Denom, coin.Amount)) + } + } + pegTags = append(pegTags, sdk.MakeTag(types.TagSendSequence, []byte(strconv.FormatUint(sendSeq, 10)))) + pegTags = append(pegTags, sdk.MakeTag(types.TagChannel, []byte{uint8(types.BindChannelID)})) + pegTags = append(pegTags, sdk.MakeTag(types.TagRelayerFee, []byte(strconv.FormatInt(relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol), 10)))) + return sdk.Result{ + Tags: pegTags, + } +} + +func handleTransferOutMsg(ctx sdk.Context, keeper Keeper, msg TransferOutMsg) sdk.Result { + if !time.Unix(msg.ExpireTime, 0).After(ctx.BlockHeader().Time.Add(types.MinTransferOutExpireTimeGap)) { + return types.ErrInvalidExpireTime(fmt.Sprintf("expire time should be %d seconds after now(%s)", + int64(types.MinTransferOutExpireTimeGap.Seconds()), ctx.BlockHeader().Time.UTC().String())).Result() + } + + symbol := msg.Amount.Denom + token, err := keeper.TokenMapper.GetToken(ctx, symbol) + if err != nil { + return sdk.ErrInvalidCoins(fmt.Sprintf("symbol(%s) does not exist", symbol)).Result() + } + + if token.GetContractAddress() == "" { + return types.ErrTokenNotBound(fmt.Sprintf("token %s is not bound", symbol)).Result() + } + + // check mini token + sdkErr := bank.CheckAndValidateMiniTokenCoins(ctx, keeper.AccountKeeper, msg.From, sdk.Coins{msg.Amount}) + if sdkErr != nil { + return sdkErr.Result() + } + + relayFee, sdkErr := types.GetFee(types.TransferOutRelayFeeName) + if sdkErr != nil { + log.With("module", "bridge").Error("get transfer out syn fee error", "err", sdkErr.Error()) + return sdkErr.Result() + } + transferAmount := sdk.Coins{msg.Amount}.Plus(relayFee.Tokens) + + bscTransferAmount, sdkErr := types.ConvertBCAmountToBSCAmount(token.GetContractDecimals(), msg.Amount.Amount) + if sdkErr != nil { + return sdkErr.Result() + } + + bscRelayFee, sdkErr := types.ConvertBCAmountToBSCAmount(types.BSCBNBDecimals, relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol)) + if sdkErr != nil { + return sdkErr.Result() + } + + _, sdkErr = keeper.BankKeeper.SendCoins(ctx, msg.From, types.PegAccount, transferAmount) + if sdkErr != nil { + log.With("module", "bridge").Error("send coins error", "err", sdkErr.Error()) + return sdkErr.Result() + } + + contractAddr, err := types.NewSmartChainAddress(token.GetContractAddress()) + if err != nil { + return types.ErrInvalidContractAddress(fmt.Sprintf("contract address is invalid, addr=%s", contractAddr)).Result() + } + transferPackage := types.TransferOutSynPackage{ + TokenSymbol: types.SymbolToBytes(symbol), + ContractAddress: contractAddr, + RefundAddress: msg.From.Bytes(), + Recipient: msg.To, + Amount: bscTransferAmount.BigInt(), + ExpireTime: uint64(msg.ExpireTime), + } + + encodedPackage, err := rlp.EncodeToBytes(transferPackage) + if err != nil { + log.With("module", "bridge").Error("encode transfer out package error", "err", err.Error()) + return sdk.ErrInternal("encode unbind package error").Result() + } + + sendSeq, sdkErr := keeper.IbcKeeper.CreateRawIBCPackageByIdWithFee(ctx, keeper.DestChainId, types.TransferOutChannelID, sdk.SynCrossChainPackageType, + encodedPackage, *bscRelayFee.BigInt()) + if sdkErr != nil { + log.With("module", "bridge").Error("create transfer out ibc package error", "err", sdkErr.Error()) + return sdkErr.Result() + } + + if ctx.IsDeliverTx() { + keeper.Pool.AddAddrs([]sdk.AccAddress{types.PegAccount, msg.From}) + publishCrossChainEvent(ctx, keeper, msg.From.String(), []CrossReceiver{ + {types.PegAccount.String(), msg.Amount.Amount}}, symbol, TransferOutType, relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol)) + } + + pegTags := sdk.Tags{} + for _, coin := range transferAmount { + if coin.Amount > 0 { + pegTags = append(pegTags, sdk.GetPegInTag(coin.Denom, coin.Amount)) + } + } + pegTags = append(pegTags, sdk.MakeTag(types.TagSendSequence, []byte(strconv.FormatUint(sendSeq, 10)))) + pegTags = append(pegTags, sdk.MakeTag(types.TagChannel, []byte{uint8(types.TransferOutChannelID)})) + pegTags = append(pegTags, sdk.MakeTag(types.TagRelayerFee, []byte(strconv.FormatInt(relayFee.Tokens.AmountOf(cmmtypes.NativeTokenSymbol), 10)))) + return sdk.Result{ + Tags: pegTags, + } +} diff --git a/plugins/bridge/keeper/keeper.go b/plugins/bridge/keeper/keeper.go new file mode 100644 index 000000000..63e5e6945 --- /dev/null +++ b/plugins/bridge/keeper/keeper.go @@ -0,0 +1,151 @@ +package keeper + +import ( + "encoding/json" + "fmt" + "math/big" + + "github.com/cosmos/cosmos-sdk/bsc/rlp" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/pubsub" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/sidechain" + + "github.com/binance-chain/node/plugins/bridge/types" + "github.com/binance-chain/node/plugins/tokens/store" +) + +// Keeper maintains the link to data storage and +// exposes getter/setter methods for the various parts of the state machine +type Keeper struct { + cdc *codec.Codec // The wire codec for binary encoding/decoding. + + storeKey sdk.StoreKey + Pool *sdk.Pool + DestChainId sdk.ChainID + DestChainName string + + ScKeeper sidechain.Keeper + BankKeeper bank.Keeper + TokenMapper store.Mapper + AccountKeeper auth.AccountKeeper + IbcKeeper ibc.Keeper + + PbsbServer *pubsub.Server +} + +// NewKeeper creates new instances of the bridge Keeper +func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, accountKeeper auth.AccountKeeper, tokenMapper store.Mapper, scKeeper sidechain.Keeper, + bankKeeper bank.Keeper, ibcKeeper ibc.Keeper, pool *sdk.Pool, destChainId sdk.ChainID, destChainName string) Keeper { + return Keeper{ + cdc: cdc, + storeKey: storeKey, + Pool: pool, + BankKeeper: bankKeeper, + TokenMapper: tokenMapper, + AccountKeeper: accountKeeper, + IbcKeeper: ibcKeeper, + DestChainId: destChainId, + DestChainName: destChainName, + ScKeeper: scKeeper, + } +} + +func (k Keeper) RefundTransferIn(decimals int8, transferInClaim *types.TransferInSynPackage, refundReason types.RefundReason) ([]byte, sdk.Error) { + refundBscAmounts := make([]*big.Int, 0, len(transferInClaim.RefundAddresses)) + for idx := range transferInClaim.RefundAddresses { + bscAmount, sdkErr := types.ConvertBCAmountToBSCAmount(decimals, transferInClaim.Amounts[idx].Int64()) + if sdkErr != nil { + return nil, sdkErr + } + + refundBscAmounts = append(refundBscAmounts, bscAmount.BigInt()) + } + + refundPackage := &types.TransferInRefundPackage{ + ContractAddr: transferInClaim.ContractAddress, + RefundAddresses: transferInClaim.RefundAddresses, + RefundAmounts: refundBscAmounts, + RefundReason: refundReason, + } + + encodedBytes, err := rlp.EncodeToBytes(refundPackage) + if err != nil { + return nil, sdk.ErrInternal("encode refund package error") + } + return encodedBytes, nil +} + +func (k Keeper) CreateBindRequest(ctx sdk.Context, req types.BindRequest) sdk.Error { + key := types.GetBindRequestKey(req.Symbol) + + kvStore := ctx.KVStore(k.storeKey) + bz := kvStore.Get(key) + if bz != nil { + return types.ErrBindRequestExists(fmt.Sprintf("bind request of %s already exists", req.Symbol)) + } + + reqBytes, err := json.Marshal(req) + if err != nil { + return sdk.ErrInternal(fmt.Sprintf("marshal bind request error, err=%s", err.Error())) + } + + kvStore.Set(key, reqBytes) + return nil +} + +func (k Keeper) DeleteBindRequest(ctx sdk.Context, symbol string) { + key := types.GetBindRequestKey(symbol) + + kvStore := ctx.KVStore(k.storeKey) + kvStore.Delete(key) +} + +func (k Keeper) GetBindRequest(ctx sdk.Context, symbol string) (types.BindRequest, sdk.Error) { + key := types.GetBindRequestKey(symbol) + + kvStore := ctx.KVStore(k.storeKey) + bz := kvStore.Get(key) + if bz == nil { + return types.BindRequest{}, types.ErrBindRequestNotExists(fmt.Sprintf("bind request of %s doest not exist", symbol)) + } + + var bindRequest types.BindRequest + err := json.Unmarshal(bz, &bindRequest) + if err != nil { + return types.BindRequest{}, sdk.ErrInternal(fmt.Sprintf("unmarshal bind request error, err=%s", err.Error())) + } + + return bindRequest, nil +} + +func (k Keeper) SetContractDecimals(ctx sdk.Context, contractAddr types.SmartChainAddress, decimals int8) { + key := types.GetContractDecimalsKey(contractAddr[:]) + + kvStore := ctx.KVStore(k.storeKey) + bz := kvStore.Get(key) + if bz != nil { + return + } + + kvStore.Set(key, []byte{byte(decimals)}) +} + +func (k Keeper) GetContractDecimals(ctx sdk.Context, contractAddr types.SmartChainAddress) int8 { + key := types.GetContractDecimalsKey(contractAddr[:]) + + kvStore := ctx.KVStore(k.storeKey) + bz := kvStore.Get(key) + if bz == nil { + return -1 + } + + return int8(bz[0]) +} + +func (k *Keeper) SetPbsbServer(server *pubsub.Server) { + k.PbsbServer = server +} diff --git a/plugins/bridge/plugin.go b/plugins/bridge/plugin.go new file mode 100644 index 000000000..a4932c456 --- /dev/null +++ b/plugins/bridge/plugin.go @@ -0,0 +1,34 @@ +package bridge + +import ( + app "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/plugins/bridge/types" +) + +func InitPlugin(chainApp app.ChainApp, keeper Keeper) { + for route, handler := range Routes(keeper) { + chainApp.GetRouter().AddRoute(route, handler) + } + + RegisterCrossApps(keeper) +} + +func RegisterCrossApps(keeper Keeper) { + updateBindApp := NewBindApp(keeper) + err := keeper.ScKeeper.RegisterChannel(types.BindChannel, types.BindChannelID, updateBindApp) + if err != nil { + panic(err) + } + + transferOutRefundApp := NewTransferOutApp(keeper) + err = keeper.ScKeeper.RegisterChannel(types.TransferOutChannel, types.TransferOutChannelID, transferOutRefundApp) + if err != nil { + panic(err) + } + + transferInApp := NewTransferInApp(keeper) + err = keeper.ScKeeper.RegisterChannel(types.TransferInChannel, types.TransferInChannelID, transferInApp) + if err != nil { + panic(err) + } +} diff --git a/plugins/bridge/pub.go b/plugins/bridge/pub.go new file mode 100644 index 000000000..f3d29ee81 --- /dev/null +++ b/plugins/bridge/pub.go @@ -0,0 +1,88 @@ +package bridge + +import ( + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/pubsub" + "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/plugins/bridge/keeper" +) + +const ( + Topic = pubsub.Topic("cross-transfer") + + TransferOutType string = "TO" + TransferInType string = "TI" + TransferAckRefundType string = "TAR" + TransferFailAckRefundType string = "TFAR" + + TransferBindType string = "TB" + TransferUnBindType string = "TUB" + TransferFailBindType string = "TFB" + TransferApproveBindType string = "TPB" + + CrossAppFailedType string = "CF" +) + +type CrossTransferEvent struct { + TxHash string + ChainId string + Type string + RelayerFee int64 + From string + Denom string + Contract string + Decimals int + To []CrossReceiver +} + +type CrossReceiver struct { + Addr string + Amount int64 +} + +func (event CrossTransferEvent) GetTopic() pubsub.Topic { + return Topic +} + +func publishCrossChainEvent(ctx types.Context, keeper keeper.Keeper, from string, to []CrossReceiver, symbol string, eventType string, relayerFee int64) { + if keeper.PbsbServer != nil { + txHash := ctx.Value(baseapp.TxHashKey) + if txHashStr, ok := txHash.(string); ok { + event := CrossTransferEvent{ + TxHash: txHashStr, + ChainId: keeper.DestChainName, + RelayerFee: relayerFee, + Type: eventType, + From: from, + Denom: symbol, + To: to, + } + keeper.PbsbServer.Publish(event) + } else { + ctx.Logger().With("module", "bridge").Error("failed to get txhash, will not publish cross transfer event ") + } + } +} + +func publishBindSuccessEvent(ctx types.Context, keeper keeper.Keeper, from string, to []CrossReceiver, symbol string, eventType string, relayerFee int64, contract string, decimals int8) { + if keeper.PbsbServer != nil { + txHash := ctx.Value(baseapp.TxHashKey) + if txHashStr, ok := txHash.(string); ok { + event := CrossTransferEvent{ + TxHash: txHashStr, + ChainId: keeper.DestChainName, + RelayerFee: relayerFee, + Type: eventType, + From: from, + Denom: symbol, + Contract: contract, + Decimals: int(decimals), + To: to, + } + keeper.PbsbServer.Publish(event) + } else { + ctx.Logger().With("module", "bridge").Error("failed to get txhash, will not publish cross transfer event ") + } + } +} diff --git a/plugins/bridge/route.go b/plugins/bridge/route.go new file mode 100644 index 000000000..d67c96728 --- /dev/null +++ b/plugins/bridge/route.go @@ -0,0 +1,13 @@ +package bridge + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/binance-chain/node/plugins/bridge/types" +) + +func Routes(keeper Keeper) map[string]sdk.Handler { + routes := make(map[string]sdk.Handler) + routes[types.RouteBridge] = NewHandler(keeper) + return routes +} diff --git a/plugins/bridge/types/account.go b/plugins/bridge/types/account.go new file mode 100644 index 000000000..0778cdc57 --- /dev/null +++ b/plugins/bridge/types/account.go @@ -0,0 +1,12 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/crypto" +) + +var ( + // bnb prefix address: bnb1v8vkkymvhe2sf7gd2092ujc6hweta38xadu2pj + // tbnb prefix address: tbnb1v8vkkymvhe2sf7gd2092ujc6hweta38xnc4wpr + PegAccount = sdk.AccAddress(crypto.AddressHash([]byte("BinanceChainPegAccount"))) +) diff --git a/plugins/bridge/types/address.go b/plugins/bridge/types/address.go new file mode 100644 index 000000000..6af7b5e0a --- /dev/null +++ b/plugins/bridge/types/address.go @@ -0,0 +1,70 @@ +package types + +import ( + "encoding/hex" + "fmt" + "math/big" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + SmartChainAddressLength = 20 +) + +// SmartChainAddress defines a standard smart chain address +type SmartChainAddress [SmartChainAddressLength]byte + +// NewSmartChainAddress is a constructor function for SmartChainAddress +func NewSmartChainAddress(addr string) (SmartChainAddress, error) { + addr = strings.ToLower(addr) + if len(addr) >= 2 && addr[:2] == "0x" { + addr = addr[2:] + } + if length := len(addr); length != 2*SmartChainAddressLength { + return SmartChainAddress{}, fmt.Errorf("invalid address hex length: %v != %v", length, 2*SmartChainAddressLength) + } + + bin, err := hex.DecodeString(addr) + if err != nil { + return SmartChainAddress{}, err + } + var address SmartChainAddress + address.SetBytes(bin) + return address, nil +} + +func (addr *SmartChainAddress) SetBytes(b []byte) { + if len(b) > len(addr) { + b = b[len(b)-20:] + } + copy(addr[20-len(b):], b) +} + +func (addr SmartChainAddress) IsEmpty() bool { + addrValue := big.NewInt(0) + addrValue.SetBytes(addr[:]) + + return addrValue.Cmp(big.NewInt(0)) == 0 +} + +// Route should return the name of the module +func (addr SmartChainAddress) String() string { + return sdk.HexAddress(addr[:]) +} + +// MarshalJSON marshals the smart chain address to JSON +func (addr SmartChainAddress) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("\"%v\"", addr.String())), nil +} + +// UnmarshalJSON unmarshals an smart chain address +func (addr *SmartChainAddress) UnmarshalJSON(input []byte) error { + hexBytes, err := sdk.HexDecode(string(input[1 : len(input)-1])) + if err != nil { + return err + } + addr.SetBytes(hexBytes) + return nil +} diff --git a/plugins/bridge/types/address_test.go b/plugins/bridge/types/address_test.go new file mode 100644 index 000000000..c4d1ee10e --- /dev/null +++ b/plugins/bridge/types/address_test.go @@ -0,0 +1,23 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAddress(t *testing.T) { + addrStr := "0x43121d597656E398473b992f0dF667fF0fc0791C" + address, err := NewSmartChainAddress(addrStr) + require.Nil(t, err, "err should be nil") + convertedAddrStr := address.String() + require.Equal(t, addrStr, convertedAddrStr, "address should be equal") + + addrStr = "0x43121d597656E398473b992f0dF667fF0fc0791C1" + _, err = NewSmartChainAddress(addrStr) + require.NotNil(t, err, "err should not be nil") + + addrStr = "0x43121d597656E398473b992f0dF667fF0fc0791" + _, err = NewSmartChainAddress(addrStr) + require.NotNil(t, err, "err should not be nil") +} diff --git a/plugins/bridge/types/amount.go b/plugins/bridge/types/amount.go new file mode 100644 index 000000000..1bfbbadc2 --- /dev/null +++ b/plugins/bridge/types/amount.go @@ -0,0 +1,49 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + cmmtypes "github.com/binance-chain/node/common/types" +) + +func ConvertBSCAmountToBCAmount(contractDecimals int8, bscAmount sdk.Int) (int64, sdk.Error) { + if contractDecimals == cmmtypes.TokenDecimals { + return bscAmount.Int64(), nil + } + + var bcAmount sdk.Int + if contractDecimals >= cmmtypes.TokenDecimals { + decimals := sdk.NewIntWithDecimal(1, int(contractDecimals-cmmtypes.TokenDecimals)) + if !bscAmount.Mod(decimals).IsZero() { + return 0, ErrInvalidAmount(fmt.Sprintf("can't convert bep2(decimals: 8) bscAmount to ERC20(decimals: %d) bscAmount", contractDecimals)) + } + bcAmount = bscAmount.Div(decimals) + } else { + decimals := sdk.NewIntWithDecimal(1, int(cmmtypes.TokenDecimals-contractDecimals)) + bcAmount = bscAmount.Mul(decimals) + } + // since we only convert bsc amount in transfer out package to bc amount, + // so it should not overflow + return bcAmount.Int64(), nil +} + +func ConvertBCAmountToBSCAmount(contractDecimals int8, bcAmount int64) (sdk.Int, sdk.Error) { + if contractDecimals == cmmtypes.TokenDecimals { + return sdk.NewInt(bcAmount), nil + } + + var bscAmount sdk.Int + if contractDecimals >= cmmtypes.TokenDecimals { + decimals := sdk.NewIntWithDecimal(1, int(contractDecimals-cmmtypes.TokenDecimals)) + bscAmount = sdk.NewInt(bcAmount).Mul(decimals) + } else { + decimals := sdk.NewIntWithDecimal(1, int(cmmtypes.TokenDecimals-contractDecimals)) + if !sdk.NewInt(bcAmount).Mod(decimals).IsZero() { + return sdk.Int{}, ErrInvalidAmount(fmt.Sprintf("can't convert bep2(decimals: 8) amount to ERC20(decimals: %d) amount", contractDecimals)) + } + bscAmount = sdk.NewInt(bcAmount).Div(decimals) + } + return bscAmount, nil +} diff --git a/plugins/bridge/types/amount_test.go b/plugins/bridge/types/amount_test.go new file mode 100644 index 000000000..c61144964 --- /dev/null +++ b/plugins/bridge/types/amount_test.go @@ -0,0 +1,87 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestConvertBSCAmountToBCAmount(t *testing.T) { + tests := []struct { + contractDecimals int8 + bscAmount sdk.Int + bcAmount int64 + expectedError bool + }{ + { + 10, + sdk.NewInt(88), + 0, + true, + }, { + 10, + sdk.NewInt(1000), + 10, + false, + }, { + 8, + sdk.NewInt(1000), + 1000, + false, + }, { + 7, + sdk.NewInt(1000), + 10000, + false, + }, + } + for i, test := range tests { + bcAmount, err := ConvertBSCAmountToBCAmount(test.contractDecimals, test.bscAmount) + if test.expectedError { + require.NotNil(t, err, "test: %d should return error", i) + } else { + require.Equal(t, bcAmount, test.bcAmount) + } + } +} + +func TestConvertBCAmountToBSCAmount(t *testing.T) { + tests := []struct { + contractDecimals int8 + bcAmount int64 + bscAmount sdk.Int + expectedError bool + }{ + { + 10, + 10, + sdk.NewInt(1000), + false, + }, { + 8, + 10, + sdk.NewInt(10), + false, + }, { + 6, + 90, + sdk.NewInt(0), + true, + }, { + 6, + 900, + sdk.NewInt(9), + false, + }, + } + for i, test := range tests { + bscAmount, err := ConvertBCAmountToBSCAmount(test.contractDecimals, test.bcAmount) + if test.expectedError { + require.NotNil(t, err, "test: %d should return error", i) + } else { + require.Equal(t, true, bscAmount.Equal(test.bscAmount)) + } + } +} diff --git a/plugins/bridge/types/bind.go b/plugins/bridge/types/bind.go new file mode 100644 index 000000000..c96b3f126 --- /dev/null +++ b/plugins/bridge/types/bind.go @@ -0,0 +1,13 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +type BindRequest struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + Amount int64 `json:"amount"` + DeductedAmount int64 `json:"deducted_amount"` + ContractAddress SmartChainAddress `json:"contract_address"` + ContractDecimals int8 `json:"contract_decimals"` + ExpireTime int64 `json:"expire_time"` +} diff --git a/plugins/bridge/types/const.go b/plugins/bridge/types/const.go new file mode 100644 index 000000000..a2adef0b9 --- /dev/null +++ b/plugins/bridge/types/const.go @@ -0,0 +1,22 @@ +package types + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + BSCBNBDecimals int8 = 18 + + BindChannel = "bind" + TransferOutChannel = "transferOut" + TransferInChannel = "transferIn" + + BindChannelID sdk.ChannelID = 1 + TransferOutChannelID sdk.ChannelID = 2 + TransferInChannelID sdk.ChannelID = 3 + + MinTransferOutExpireTimeGap = 60 * time.Second + MinBindExpireTimeGap = 600 * time.Second +) diff --git a/plugins/bridge/types/errors.go b/plugins/bridge/types/errors.go new file mode 100644 index 000000000..621d0f8ba --- /dev/null +++ b/plugins/bridge/types/errors.go @@ -0,0 +1,93 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + DefaultCodespace sdk.CodespaceType = 12 + + CodeInvalidAmount sdk.CodeType = 1 + CodeInvalidEthereumAddress sdk.CodeType = 2 + CodeInvalidDecimals sdk.CodeType = 3 + CodeInvalidContractAddress sdk.CodeType = 4 + CodeTokenNotBound sdk.CodeType = 5 + CodeInvalidSymbol sdk.CodeType = 6 + CodeInvalidExpireTime sdk.CodeType = 7 + CodeBindRequestExists sdk.CodeType = 8 + CodeBindRequestNotExists sdk.CodeType = 9 + CodeTokenBound sdk.CodeType = 10 + CodeInvalidLength sdk.CodeType = 11 + CodeFeeNotFound sdk.CodeType = 12 + CodeInvalidClaim sdk.CodeType = 13 + CodeDeserializePackageFailed sdk.CodeType = 14 + CodeTokenBindRelationChanged sdk.CodeType = 15 + CodeTransferInExpire sdk.CodeType = 16 +) + +//---------------------------------------- +// Error constructors + +func ErrInvalidAmount(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeInvalidAmount, msg) +} + +func ErrInvalidEthereumAddress(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeInvalidEthereumAddress, msg) +} + +func ErrInvalidDecimals(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeInvalidDecimals, msg) +} + +func ErrInvalidContractAddress(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeInvalidContractAddress, msg) +} + +func ErrTokenNotBound(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeTokenNotBound, msg) +} + +func ErrInvalidSymbol(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeInvalidSymbol, msg) +} + +func ErrInvalidExpireTime(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeInvalidExpireTime, msg) +} + +func ErrDeserializePackageFailed(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeDeserializePackageFailed, msg) +} + +func ErrBindRequestExists(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeBindRequestExists, msg) +} + +func ErrBindRequestNotExists(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeBindRequestNotExists, msg) +} + +func ErrTokenBound(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeTokenBound, msg) +} + +func ErrInvalidLength(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeInvalidLength, msg) +} + +func ErrFeeNotFound(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeFeeNotFound, msg) +} + +func ErrInvalidClaim(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeInvalidClaim, msg) +} + +func ErrTokenBindRelationChanged(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeTokenBindRelationChanged, msg) +} + +func ErrTransferInExpire(msg string) sdk.Error { + return sdk.NewError(DefaultCodespace, CodeTransferInExpire, msg) +} diff --git a/plugins/bridge/types/fees.go b/plugins/bridge/types/fees.go new file mode 100644 index 000000000..ab0c5e21e --- /dev/null +++ b/plugins/bridge/types/fees.go @@ -0,0 +1,20 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" +) + +const ( + BindRelayFeeName = "crossBindRelayFee" + UnbindRelayFeeName = "crossUnbindRelayFee" + TransferOutRelayFeeName = "crossTransferOutRelayFee" +) + +func GetFee(feeName string) (sdk.Fee, sdk.Error) { + calculator := fees.GetCalculator(feeName) + if calculator == nil { + return sdk.Fee{}, ErrFeeNotFound("missing calculator for fee type:" + feeName) + } + return calculator(nil), nil +} diff --git a/plugins/bridge/types/keys.go b/plugins/bridge/types/keys.go new file mode 100644 index 000000000..fdfcf6fb1 --- /dev/null +++ b/plugins/bridge/types/keys.go @@ -0,0 +1,18 @@ +package types + +import ( + "fmt" +) + +const ( + keyBindRequest = "bindReq:%s" + keyContractDecimals = "decs:" +) + +func GetBindRequestKey(symbol string) []byte { + return []byte(fmt.Sprintf(keyBindRequest, symbol)) +} + +func GetContractDecimalsKey(contractAddr []byte) []byte { + return append([]byte(keyContractDecimals), contractAddr...) +} diff --git a/plugins/bridge/types/msgs.go b/plugins/bridge/types/msgs.go new file mode 100644 index 000000000..bd4f79871 --- /dev/null +++ b/plugins/bridge/types/msgs.go @@ -0,0 +1,219 @@ +package types + +import ( + "encoding/json" + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + RouteBridge = "bridge" + + BindMsgType = "crossBind" + UnbindMsgType = "crossUnbind" + TransferOutMsgType = "crossTransferOut" +) + +const ( + MaxSymbolLength = 32 +) + +var _ sdk.Msg = BindMsg{} + +type BindMsg struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` + Amount int64 `json:"amount"` + ContractAddress SmartChainAddress `json:"contract_address"` + ContractDecimals int8 `json:"contract_decimals"` + ExpireTime int64 `json:"expire_time"` +} + +func NewBindMsg(from sdk.AccAddress, symbol string, amount int64, contractAddress SmartChainAddress, contractDecimals int8, expireTime int64) BindMsg { + return BindMsg{ + From: from, + Amount: amount, + Symbol: symbol, + ContractAddress: contractAddress, + ContractDecimals: contractDecimals, + ExpireTime: expireTime, + } +} + +func (msg BindMsg) Route() string { return RouteBridge } +func (msg BindMsg) Type() string { return BindMsgType } +func (msg BindMsg) String() string { + return fmt.Sprintf("Bind{%v#%s#%d$%s#%d#%d}", msg.From, msg.Symbol, msg.Amount, msg.ContractAddress.String(), msg.ContractDecimals, msg.ExpireTime) +} +func (msg BindMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } +func (msg BindMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } + +func (msg BindMsg) ValidateBasic() sdk.Error { + if len(msg.From) != sdk.AddrLen { + return sdk.ErrInvalidAddress(fmt.Sprintf("address length should be %d", sdk.AddrLen)) + } + + if len(msg.Symbol) == 0 { + return ErrInvalidSymbol("symbol should not be empty") + } + + if len(msg.Symbol) > MaxSymbolLength { + return ErrInvalidSymbol(fmt.Sprintf("symbol length should not be larger than %d", MaxSymbolLength)) + } + + if msg.Amount < 0 { + return ErrInvalidAmount("amount should be no less than 0") + } + + if msg.ContractAddress.IsEmpty() { + return ErrInvalidContractAddress("contract address should not be empty") + } + + if msg.ContractDecimals < 0 { + return ErrInvalidDecimals(fmt.Sprintf("decimals should be no less than 0")) + } + + if msg.ExpireTime <= 0 { + return ErrInvalidExpireTime("expire time should be larger than 0") + } + + return nil +} + +func (msg BindMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} + +var _ sdk.Msg = UnbindMsg{} + +type UnbindMsg struct { + From sdk.AccAddress `json:"from"` + Symbol string `json:"symbol"` +} + +func NewUnbindMsg(from sdk.AccAddress, symbol string) UnbindMsg { + return UnbindMsg{ + From: from, + Symbol: symbol, + } +} + +func (msg UnbindMsg) Route() string { return RouteBridge } +func (msg UnbindMsg) Type() string { return UnbindMsgType } +func (msg UnbindMsg) String() string { + return fmt.Sprintf("Unbind{%v#%s}", msg.From, msg.Symbol) +} +func (msg UnbindMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } +func (msg UnbindMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } + +func (msg UnbindMsg) ValidateBasic() sdk.Error { + if len(msg.From) != sdk.AddrLen { + return sdk.ErrInvalidAddress(fmt.Sprintf("address length should be %d", sdk.AddrLen)) + } + + if len(msg.Symbol) == 0 { + return ErrInvalidSymbol("symbol should not be empty") + } + + if len(msg.Symbol) > MaxSymbolLength { + return ErrInvalidSymbol(fmt.Sprintf("symbol length should not be larger than %d", MaxSymbolLength)) + } + + return nil +} + +func (msg UnbindMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} + +func (status BindStatus) String() string { + switch status { + case BindStatusSuccess: + return "UnboundToken" + case BindStatusRejected: + return "Timeout" + case BindStatusTimeout: + return "InsufficientBalance" + case BindStatusInvalidParameter: + return "InsufficientBalance" + default: + return "" + } +} + +func ParseBindStatus(input string) (BindStatus, error) { + switch strings.ToLower(input) { + case "success": + return BindStatusSuccess, nil + case "rejected": + return BindStatusRejected, nil + case "timeout": + return BindStatusTimeout, nil + case "invalidparameter": + return BindStatusInvalidParameter, nil + default: + return BindStatus(0), fmt.Errorf("unrecognized bind status") + } +} + +var _ sdk.Msg = TransferOutMsg{} + +type TransferOutMsg struct { + From sdk.AccAddress `json:"from"` + To SmartChainAddress `json:"to"` + Amount sdk.Coin `json:"amount"` + ExpireTime int64 `json:"expire_time"` +} + +func NewTransferOutMsg(from sdk.AccAddress, to SmartChainAddress, amount sdk.Coin, expireTime int64) TransferOutMsg { + return TransferOutMsg{ + From: from, + To: to, + Amount: amount, + ExpireTime: expireTime, + } +} + +func (msg TransferOutMsg) Route() string { return RouteBridge } +func (msg TransferOutMsg) Type() string { return TransferOutMsgType } +func (msg TransferOutMsg) String() string { + return fmt.Sprintf("TransferOut{%v#%s#%s#%d}", msg.From, msg.To.String(), msg.Amount.String(), msg.ExpireTime) +} +func (msg TransferOutMsg) GetInvolvedAddresses() []sdk.AccAddress { return msg.GetSigners() } +func (msg TransferOutMsg) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.From} } +func (msg TransferOutMsg) ValidateBasic() sdk.Error { + if len(msg.From) != sdk.AddrLen { + return sdk.ErrInvalidAddress(fmt.Sprintf("address length should be %d", sdk.AddrLen)) + } + + if msg.To.IsEmpty() { + return ErrInvalidContractAddress("to address should not be empty") + } + + if !msg.Amount.IsPositive() { + return sdk.ErrInvalidCoins("amount should be positive") + } + + if msg.ExpireTime <= 0 { + return ErrInvalidExpireTime("expire time should be larger than 0") + } + + return nil +} +func (msg TransferOutMsg) GetSignBytes() []byte { + b, err := json.Marshal(msg) // XXX: ensure some canonical form + if err != nil { + panic(err) + } + return b +} diff --git a/plugins/bridge/types/msgs_test.go b/plugins/bridge/types/msgs_test.go new file mode 100644 index 000000000..81c207f45 --- /dev/null +++ b/plugins/bridge/types/msgs_test.go @@ -0,0 +1,83 @@ +package types + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/mock" + "github.com/stretchr/testify/require" +) + +func BytesToAddress(b []byte) SmartChainAddress { + var a SmartChainAddress + a.SetBytes(b) + return a +} + +func TestBindMsg(t *testing.T) { + _, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{}) + + nonEmptySmartChainAddr := SmartChainAddress(BytesToAddress([]byte{1})) + emptySmartChainAddr := SmartChainAddress(BytesToAddress([]byte{0})) + + tests := []struct { + bindMsg BindMsg + expectedPass bool + }{ + { + NewBindMsg(addrs[0], "BNB", 1, nonEmptySmartChainAddr, 1, 100), + true, + }, { + NewBindMsg(addrs[0], "", 1, nonEmptySmartChainAddr, 1, 100), + false, + }, { + NewBindMsg(addrs[0], "BNB", -1, nonEmptySmartChainAddr, 1, 100), + false, + }, { + NewBindMsg(sdk.AccAddress{0, 1}, "BNB", 1, nonEmptySmartChainAddr, 1, 100), + false, + }, { + NewBindMsg(addrs[0], "BNB", 1, emptySmartChainAddr, 1, 100), + false, + }, { + NewBindMsg(addrs[0], "BNB", 1, nonEmptySmartChainAddr, -1, 100), + false, + }, + } + + for i, test := range tests { + if test.expectedPass { + require.Nil(t, test.bindMsg.ValidateBasic(), "test: %v", i) + } else { + require.NotNil(t, test.bindMsg.ValidateBasic(), "test: %v", i) + } + } +} + +func TestUnbindMsg(t *testing.T) { + _, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{}) + + tests := []struct { + unbindMsg UnbindMsg + expectedPass bool + }{ + { + NewUnbindMsg(addrs[0], "BNB"), + true, + }, { + NewUnbindMsg(addrs[0], ""), + false, + }, { + NewUnbindMsg(sdk.AccAddress{0, 1}, "BNB"), + false, + }, + } + + for i, test := range tests { + if test.expectedPass { + require.Nil(t, test.unbindMsg.ValidateBasic(), "test: %v", i) + } else { + require.NotNil(t, test.unbindMsg.ValidateBasic(), "test: %v", i) + } + } +} diff --git a/plugins/bridge/types/serialize.go b/plugins/bridge/types/serialize.go new file mode 100644 index 000000000..eb7dd80e4 --- /dev/null +++ b/plugins/bridge/types/serialize.go @@ -0,0 +1,147 @@ +package types + +import ( + "bytes" + "math/big" + + "github.com/cosmos/cosmos-sdk/bsc/rlp" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type BindPackageType uint8 + +const ( + BindTypeBind BindPackageType = 0 + BindTypeUnbind BindPackageType = 1 +) + +type BindSynPackage struct { + PackageType BindPackageType + TokenSymbol [32]byte + ContractAddr SmartChainAddress + TotalSupply *big.Int + PeggyAmount *big.Int + Decimals uint8 + ExpireTime uint64 +} + +func DeserializeBindSynPackage(serializedPackage []byte) (*BindSynPackage, sdk.Error) { + var pack BindSynPackage + err := rlp.DecodeBytes(serializedPackage, &pack) + if err != nil { + return nil, ErrDeserializePackageFailed("deserialize bind syn package failed") + } + return &pack, nil +} + +type BindAckPackage struct { + TokenSymbol [32]byte +} + +type BindStatus uint32 + +const ( + BindStatusSuccess BindStatus = 0 + BindStatusRejected BindStatus = 1 + BindStatusTimeout BindStatus = 2 + BindStatusInvalidParameter BindStatus = 3 +) + +type ApproveBindSynPackage struct { + Status BindStatus + TokenSymbol [32]byte +} + +func DeserializeApproveBindSynPackage(serializedPackage []byte) (*ApproveBindSynPackage, sdk.Error) { + var pack ApproveBindSynPackage + err := rlp.DecodeBytes(serializedPackage, &pack) + if err != nil { + return nil, ErrDeserializePackageFailed("deserialize approve bind package failed") + } + return &pack, nil +} + +type ApproveBindAckPackage struct { + TokenSymbol [32]byte +} + +type TransferInSynPackage struct { + TokenSymbol [32]byte + ContractAddress SmartChainAddress + Amounts []*big.Int + ReceiverAddresses []sdk.AccAddress + RefundAddresses []SmartChainAddress + ExpireTime uint64 +} + +func DeserializeTransferInSynPackage(serializedPackage []byte) (*TransferInSynPackage, sdk.Error) { + var tp TransferInSynPackage + err := rlp.DecodeBytes(serializedPackage, &tp) + if err != nil { + return nil, ErrDeserializePackageFailed("deserialize transfer in package failed") + } + return &tp, nil +} + +type TransferInRefundPackage struct { + ContractAddr SmartChainAddress + RefundAmounts []*big.Int + RefundAddresses []SmartChainAddress + RefundReason RefundReason +} + +type TransferOutSynPackage struct { + TokenSymbol [32]byte + ContractAddress SmartChainAddress + Amount *big.Int + Recipient SmartChainAddress + RefundAddress sdk.AccAddress + ExpireTime uint64 +} + +func DeserializeTransferOutSynPackage(serializedPackage []byte) (*TransferOutSynPackage, sdk.Error) { + var tp TransferOutSynPackage + err := rlp.DecodeBytes(serializedPackage, &tp) + if err != nil { + return nil, ErrDeserializePackageFailed("deserialize transfer out package failed") + } + return &tp, nil +} + +type RefundReason uint32 + +const ( + UnboundToken RefundReason = 1 + Timeout RefundReason = 2 + InsufficientBalance RefundReason = 3 + Unknown RefundReason = 4 +) + +type TransferOutRefundPackage struct { + TokenSymbol [32]byte + RefundAmount *big.Int + RefundAddr sdk.AccAddress + RefundReason RefundReason +} + +func DeserializeTransferOutRefundPackage(serializedPackage []byte) (*TransferOutRefundPackage, sdk.Error) { + var tp TransferOutRefundPackage + err := rlp.DecodeBytes(serializedPackage, &tp) + if err != nil { + return nil, ErrDeserializePackageFailed("deserialize transfer out refund package failed") + } + return &tp, nil +} + +func SymbolToBytes(symbol string) [32]byte { + // length of bound token symbol length should not be larger than 32 + serializedBytes := [32]byte{} + copy(serializedBytes[:], symbol) + return serializedBytes +} + +func BytesToSymbol(symbolBytes [32]byte) string { + tokenSymbolBytes := make([]byte, 32, 32) + copy(tokenSymbolBytes[:], symbolBytes[:]) + return string(bytes.Trim(tokenSymbolBytes, "\x00")) +} diff --git a/plugins/bridge/types/tags.go b/plugins/bridge/types/tags.go new file mode 100644 index 000000000..71420659b --- /dev/null +++ b/plugins/bridge/types/tags.go @@ -0,0 +1,7 @@ +package types + +const ( + TagSendSequence = "SendSequence" + TagChannel = "Channel" + TagRelayerFee = "relayerFee" +) diff --git a/plugins/bridge/wire.go b/plugins/bridge/wire.go new file mode 100644 index 000000000..531414bbf --- /dev/null +++ b/plugins/bridge/wire.go @@ -0,0 +1,12 @@ +package bridge + +import ( + "github.com/binance-chain/node/wire" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterConcrete(BindMsg{}, "bridge/BindMsg", nil) + cdc.RegisterConcrete(UnbindMsg{}, "bridge/UnbindMsg", nil) + cdc.RegisterConcrete(TransferOutMsg{}, "bridge/TransferOutMsg", nil) +} diff --git a/plugins/dex/matcheng/types.go b/plugins/dex/matcheng/types.go index 913c988f4..fbf87e3a0 100644 --- a/plugins/dex/matcheng/types.go +++ b/plugins/dex/matcheng/types.go @@ -6,7 +6,7 @@ import ( bt "github.com/google/btree" - "github.com/binance-chain/node/common/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) const ( @@ -41,8 +41,8 @@ type Trade struct { SellCumQty int64 // cumulative executed quantity for the sell order Bid string // buy order Id TickType int8 - SellerFee *types.Fee // seller's fee - BuyerFee *types.Fee // buyer's fee + SellerFee *sdk.Fee // seller's fee + BuyerFee *sdk.Fee // buyer's fee } type OrderPart struct { diff --git a/plugins/dex/order/fee.go b/plugins/dex/order/fee.go index c5674d8b5..60cb1475f 100644 --- a/plugins/dex/order/fee.go +++ b/plugins/dex/order/fee.go @@ -6,17 +6,16 @@ import ( "math" "math/big" - "github.com/binance-chain/node/common/upgrade" - sdk "github.com/cosmos/cosmos-sdk/types" + param "github.com/cosmos/cosmos-sdk/x/paramHub/types" tmlog "github.com/tendermint/tendermint/libs/log" "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" cmnUtils "github.com/binance-chain/node/common/utils" "github.com/binance-chain/node/plugins/dex/matcheng" "github.com/binance-chain/node/plugins/dex/utils" - param "github.com/binance-chain/node/plugins/param/types" "github.com/binance-chain/node/wire" ) @@ -70,8 +69,8 @@ func (m *FeeManager) GetConfig() FeeConfig { return m.FeeConfig } -func (m *FeeManager) CalcTradesFee(balances sdk.Coins, tradeTransfers TradeTransfers, engines map[string]*matcheng.MatchEng) types.Fee { - var fees types.Fee +func (m *FeeManager) CalcTradesFee(balances sdk.Coins, tradeTransfers TradeTransfers, engines map[string]*matcheng.MatchEng) sdk.Fee { + var fees sdk.Fee if tradeTransfers == nil { return fees } @@ -90,8 +89,8 @@ func (m *FeeManager) CalcTradesFee(balances sdk.Coins, tradeTransfers TradeTrans return fees } -func (m *FeeManager) CalcExpiresFee(balances sdk.Coins, expireType transferEventType, expireTransfers ExpireTransfers, engines map[string]*matcheng.MatchEng, expireTransferHandler func(tran Transfer)) types.Fee { - var fees types.Fee +func (m *FeeManager) CalcExpiresFee(balances sdk.Coins, expireType transferEventType, expireTransfers ExpireTransfers, engines map[string]*matcheng.MatchEng, expireTransferHandler func(tran Transfer)) sdk.Fee { + var fees sdk.Fee if expireTransfers == nil { return fees } @@ -108,7 +107,7 @@ func (m *FeeManager) CalcExpiresFee(balances sdk.Coins, expireType transferEvent return fees } -func (m *FeeManager) calcTradeFeeFromTransfer(balances sdk.Coins, tran *Transfer, engines map[string]*matcheng.MatchEng) types.Fee { +func (m *FeeManager) calcTradeFeeFromTransfer(balances sdk.Coins, tran *Transfer, engines map[string]*matcheng.MatchEng) sdk.Fee { var feeToken sdk.Coin nativeFee, isOverflow := m.calcNativeFee(tran, engines) @@ -154,7 +153,7 @@ func (m *FeeManager) calcNativeFee(tran *Transfer, engines map[string]*matcheng. } notional, pairExist = m.calcNotional(BUSDSymbol, qty, types.NativeTokenSymbol, engines) - if pairExist { + if !pairExist { // must not happen m.logger.Error(BUSDSymbol + " must be listed against " + types.NativeTokenSymbol) } @@ -191,7 +190,7 @@ func (m *FeeManager) calcNotional(asset string, qty int64, quoteAsset string, en // Note2: even though the function is called in multiple threads, // `engines` map would stay the same as no other function may change it in fee calculation stage, // so no race condition concern -func (m *FeeManager) CalcTradeFee(balances sdk.Coins, tradeIn sdk.Coin, engines map[string]*matcheng.MatchEng) types.Fee { +func (m *FeeManager) CalcTradeFee(balances sdk.Coins, tradeIn sdk.Coin, engines map[string]*matcheng.MatchEng) sdk.Fee { var feeToken sdk.Coin inSymbol := tradeIn.Denom inAmt := tradeIn.Amount @@ -235,7 +234,7 @@ func (m *FeeManager) CalcTradeFee(balances sdk.Coins, tradeIn sdk.Coin, engines // 1. transfer the "inAsset" to the balance, i.e. call doTransfer() // 2. call this method // 3. deduct the fee right away -func (m *FeeManager) CalcFixedFee(balances sdk.Coins, eventType transferEventType, inAsset string, engines map[string]*matcheng.MatchEng) types.Fee { +func (m *FeeManager) CalcFixedFee(balances sdk.Coins, eventType transferEventType, inAsset string, engines map[string]*matcheng.MatchEng) sdk.Fee { var feeAmountNative int64 var feeAmount int64 if eventType == eventFullyExpire { @@ -247,7 +246,7 @@ func (m *FeeManager) CalcFixedFee(balances sdk.Coins, eventType transferEventTyp } else { // should not be here m.logger.Error("Invalid expire eventType", "eventType", eventType) - return types.Fee{} + return sdk.Fee{} } nativeTokenBalance := balances.AmountOf(types.NativeTokenSymbol) @@ -293,8 +292,8 @@ func (m *FeeManager) CalcFixedFee(balances sdk.Coins, eventType transferEventTyp } // for each trade, the fee only contains one kind of token. And distribution type is always FeeForProposer -func dexFeeWrap(fee sdk.Coin) types.Fee { - return types.NewFee(sdk.Coins{fee}, types.FeeForProposer) +func dexFeeWrap(fee sdk.Coin) sdk.Fee { + return sdk.NewFee(sdk.Coins{fee}, sdk.FeeForProposer) } func isNativeToken(symbol string) bool { diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index 7903575a5..ba58629da 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -9,8 +9,8 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" - "github.com/binance-chain/node/common/fees" common "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" me "github.com/binance-chain/node/plugins/dex/matcheng" @@ -199,7 +199,7 @@ func handleCancelOrder( if sdkError != nil { return sdkError.Result() } - fee := common.Fee{} + fee := sdk.Fee{} if !transfer.FeeFree() { acc := dexKeeper.am.GetAccount(ctx, msg.Sender) fee = dexKeeper.FeeManager.CalcFixedFee(acc.GetCoins(), transfer.eventType, transfer.inAsset, dexKeeper.GetEngines()) diff --git a/plugins/dex/order/keeper.go b/plugins/dex/order/keeper.go index 49482c7c8..dc487f206 100644 --- a/plugins/dex/order/keeper.go +++ b/plugins/dex/order/keeper.go @@ -9,14 +9,16 @@ import ( "sync" "time" - 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" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" + "github.com/cosmos/cosmos-sdk/x/auth" + paramhub "github.com/cosmos/cosmos-sdk/x/paramHub/keeper" + paramTypes "github.com/cosmos/cosmos-sdk/x/paramHub/types" + bnclog "github.com/binance-chain/node/common/log" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" @@ -25,8 +27,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" ) @@ -45,7 +45,7 @@ var PairType = struct { var BUSDSymbol string -type FeeHandler func(map[string]*types.Fee) +type FeeHandler func(map[string]*sdk.Fee) type TransferHandler func(Transfer) type DexKeeper struct { @@ -79,7 +79,7 @@ func NewDexKeeper(key sdk.StoreKey, am auth.AccountKeeper, tradingPairMapper sto codespace: codespace, recentPrices: make(map[string]*utils.FixedSizeRing, 256), am: am, - RoundOrderFees: make(map[string]*types.Fee, 256), + RoundOrderFees: make(map[string]*sdk.Fee, 256), FeeManager: NewFeeManager(cdc, logger), CollectOrderInfoForPublish: collectOrderInfoForPublish, engines: make(map[string]*me.MatchEng), @@ -348,25 +348,29 @@ func channelHash(accAddress sdk.AccAddress, bucketNumber int) int { 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(_ sdk.Context, iChange interface{}) { + switch change := iChange.(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 ") + nil, + func(context sdk.Context, iState interface{}) { + switch state := iState.(type) { + case paramTypes.GenesisState: + feeConfig := ParamToFeeConfig(state.FeeGenesis) + if feeConfig != nil { + kp.FeeManager.UpdateConfig(*feeConfig) + } else { + panic("Genesis with no dex fee config ") + } + default: + kp.logger.Debug("Receive param genesis state that not interested.") } }, func(context sdk.Context, iLoad interface{}) { @@ -522,7 +526,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) { + sdk.Fee, map[string]*sdk.Fee) { if !sdk.IsUpgrade(upgrade.BEP19) { return kp.allocateBeforeGalileo(ctx, tranCh, postAllocateHandler) } @@ -534,7 +538,7 @@ func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAlloc 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 + var totalFee sdk.Fee for tran := range tranCh { kp.doTransfer(ctx, &tran) if !tran.FeeFree() { @@ -562,7 +566,7 @@ func (kp *DexKeeper) allocate(ctx sdk.Context, tranCh <-chan Transfer, postAlloc } } - feesPerAcc := make(map[string]*types.Fee) + feesPerAcc := make(map[string]*sdk.Fee) for addrStr, trans := range tradeTransfers { addr := sdk.AccAddress(addrStr) acc := kp.am.GetAccount(ctx, addr) @@ -596,7 +600,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)) ( - types.Fee, map[string]*types.Fee) { + sdk.Fee, map[string]*sdk.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) @@ -604,7 +608,7 @@ func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transf 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 + var totalFee sdk.Fee for tran := range tranCh { kp.doTransfer(ctx, &tran) if !tran.FeeFree() { @@ -632,13 +636,13 @@ func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transf } } - feesPerAcc := make(map[string]*types.Fee) - collectFee := func(assetsMap map[string]*sortedAsset, calcFeeAndDeduct func(acc sdk.Account, in sdk.Coin) types.Fee) { + feesPerAcc := make(map[string]*sdk.Fee) + collectFee := func(assetsMap map[string]*sortedAsset, calcFeeAndDeduct func(acc sdk.Account, in sdk.Coin) sdk.Fee) { for addrStr, assets := range assetsMap { addr := sdk.AccAddress(addrStr) acc := kp.am.GetAccount(ctx, addr) - var fees types.Fee + var fees sdk.Fee if exists, ok := feesPerAcc[addrStr]; ok { fees = *exists } @@ -658,14 +662,14 @@ func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transf } } } - collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) types.Fee { + collectFee(tradeInAsset, func(acc sdk.Account, in sdk.Coin) sdk.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 { + collectFee(expireInAsset, func(acc sdk.Account, in sdk.Coin) sdk.Fee { var i int64 = 0 - var fees types.Fee + var fees sdk.Fee for ; i < in.Amount; i++ { fee := kp.FeeManager.CalcFixedFee(acc.GetCoins(), expireEventType, in.Denom, kp.engines) acc.SetCoins(acc.GetCoins().Minus(fee.Tokens)) @@ -679,12 +683,12 @@ func (kp *DexKeeper) allocateBeforeGalileo(ctx sdk.Context, tranCh <-chan Transf func (kp *DexKeeper) allocateAndCalcFee( ctx sdk.Context, tradeOuts []chan Transfer, - postAlloTransHandler TransferHandler) types.Fee { + postAlloTransHandler TransferHandler) sdk.Fee { concurrency := len(tradeOuts) var wg sync.WaitGroup wg.Add(concurrency) - feesPerCh := make([]types.Fee, concurrency) - feesPerAcc := make([]map[string]*types.Fee, concurrency) + feesPerCh := make([]sdk.Fee, concurrency) + feesPerAcc := make([]map[string]*sdk.Fee, concurrency) allocatePerCh := func(index int, tranCh <-chan Transfer) { defer wg.Done() fee, feeByAcc := kp.allocate(ctx, tranCh, postAlloTransHandler) @@ -696,7 +700,7 @@ func (kp *DexKeeper) allocateAndCalcFee( go allocatePerCh(i, tradeTranCh) } wg.Wait() - totalFee := types.Fee{} + totalFee := sdk.Fee{} for i := 0; i < concurrency; i++ { totalFee.AddFee(feesPerCh[i]) } @@ -879,7 +883,7 @@ func (kp *DexKeeper) GetLastBreatheBlockHeight(ctx sdk.Context, latestBlockHeigh // 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) { +func (kp *DexKeeper) updateRoundOrderFee(addr string, fee sdk.Fee) { if existingFee, ok := kp.RoundOrderFees[addr]; ok { existingFee.AddFee(fee) } else { @@ -888,7 +892,7 @@ func (kp *DexKeeper) updateRoundOrderFee(addr string, fee types.Fee) { } func (kp *DexKeeper) ClearRoundFee() { - kp.RoundOrderFees = make(map[string]*types.Fee, 256) + kp.RoundOrderFees = make(map[string]*sdk.Fee, 256) } func (kp *DexKeeper) CanDelistTradingPair(ctx sdk.Context, baseAsset, quoteAsset string) error { diff --git a/plugins/dex/order/keeper_match.go b/plugins/dex/order/keeper_match.go index fbe530df8..d5ab68c97 100644 --- a/plugins/dex/order/keeper_match.go +++ b/plugins/dex/order/keeper_match.go @@ -2,8 +2,8 @@ package order import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" - "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/keeper_test.go b/plugins/dex/order/keeper_test.go index 946f4d385..3e986f180 100644 --- a/plugins/dex/order/keeper_test.go +++ b/plugins/dex/order/keeper_test.go @@ -5,14 +5,16 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/codec" sdkstore "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/fees" "github.com/cosmos/cosmos-sdk/x/auth" txbuilder "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/secp256k1" @@ -23,7 +25,6 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/binance-chain/node/common" - "github.com/binance-chain/node/common/fees" "github.com/binance-chain/node/common/testutils" "github.com/binance-chain/node/common/types" "github.com/binance-chain/node/common/upgrade" @@ -592,10 +593,10 @@ func TestKeeper_ExpireOrders(t *testing.T) { require.Len(t, buys[0].Orders, 1) require.Equal(t, int64(2e6), buys[0].TotalLeavesQty()) require.Len(t, keeper.GetAllOrdersForPair("XYZ-000_BNB"), 1) - expectFees := types.NewFee(sdk.Coins{ + expectFees := sdk.NewFee(sdk.Coins{ sdk.NewCoin("BNB", 6e4), sdk.NewCoin("ABC-000", 1e7), - }.Sort(), types.FeeForProposer) + }.Sort(), sdk.FeeForProposer) require.Equal(t, expectFees, fees.Pool.BlockFees()) acc = am.GetAccount(ctx, acc.GetAddress()) require.Equal(t, sdk.Coins{ @@ -920,10 +921,10 @@ func TestKeeper_DelistTradingPair(t *testing.T) { assert.Equal(0, len(keeper.engines)) assert.Equal(0, len(keeper.PairMapper.GetRecentPrices(ctx, pricesStoreEvery, numPricesStored))) - expectFees := types.NewFee(sdk.Coins{ + expectFees := sdk.NewFee(sdk.Coins{ sdk.NewCoin("BNB", 10e4), sdk.NewCoin("XYZ-000", 4e5), - }.Sort(), types.FeeForProposer) + }.Sort(), sdk.FeeForProposer) require.Equal(t, expectFees, fees.Pool.BlockFees()) } @@ -978,10 +979,10 @@ func TestKeeper_DelistMiniTradingPair(t *testing.T) { assert.Equal(0, len(keeper.GetAllOrders())) assert.Equal(0, len(keeper.engines)) - expectFees := types.NewFee(sdk.Coins{ + expectFees := sdk.NewFee(sdk.Coins{ sdk.NewCoin("BNB", 10e4), sdk.NewCoin("XYZ-000M", 4e5), - }.Sort(), types.FeeForProposer) + }.Sort(), sdk.FeeForProposer) require.Equal(t, expectFees, fees.Pool.BlockFees()) } @@ -1004,7 +1005,7 @@ func TestKeeper_DelistTradingPair_Empty(t *testing.T) { assert.Equal(0, len(keeper.GetAllOrders())) assert.Equal(0, len(keeper.engines)) - expectFees := types.NewFee(sdk.Coins(nil), types.ZeroFee) + expectFees := sdk.NewFee(sdk.Coins(nil), sdk.ZeroFee) require.Equal(t, expectFees, fees.Pool.BlockFees()) } diff --git a/plugins/dex/order/transfer.go b/plugins/dex/order/transfer.go index 60692759d..71f16e1fc 100644 --- a/plugins/dex/order/transfer.go +++ b/plugins/dex/order/transfer.go @@ -34,7 +34,7 @@ type Transfer struct { outAsset string out int64 unlock int64 - Fee types.Fee + Fee sdk.Fee Trade *me.Trade Symbol string } @@ -92,7 +92,7 @@ func TransferFromTrade(trade *me.Trade, symbol string, orderMap map[string]*Orde outAsset: baseAsset, out: trade.LastQty, unlock: trade.LastQty, - Fee: types.Fee{}, + Fee: sdk.Fee{}, Trade: trade, Symbol: symbol, }, Transfer{ @@ -104,7 +104,7 @@ func TransferFromTrade(trade *me.Trade, symbol string, orderMap map[string]*Orde outAsset: quoteAsset, out: quoteQty, unlock: unlock, - Fee: types.Fee{}, + Fee: sdk.Fee{}, Trade: trade, Symbol: symbol, } diff --git a/plugins/dex/order/types.go b/plugins/dex/order/types.go index d3cbefbff..981cfe320 100644 --- a/plugins/dex/order/types.go +++ b/plugins/dex/order/types.go @@ -3,7 +3,7 @@ package order import ( "fmt" - "github.com/binance-chain/node/common/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) // The types here are shared between order and pub package @@ -129,4 +129,4 @@ type SymbolWithOrderNumber struct { numberOfOrders int } -type FeeHolder map[string]*types.Fee +type FeeHolder map[string]*sdk.Fee diff --git a/plugins/ico/endblock.go b/plugins/ico/endblock.go deleted file mode 100644 index acdcd07f4..000000000 --- a/plugins/ico/endblock.go +++ /dev/null @@ -1,19 +0,0 @@ -package ico - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// TODO: just a template -func EndBlockAsync(ctx sdk.Context) chan interface{} { - // scan and clearing. - finish := make(chan interface{}) - go func() { - fmt.Println(ctx.BlockHeight()) - finish <- struct{}{} - }() - - return finish -} diff --git a/plugins/param/abci.go b/plugins/param/abci.go deleted file mode 100644 index 09f2fea6f..000000000 --- a/plugins/param/abci.go +++ /dev/null @@ -1,43 +0,0 @@ -package param - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/tendermint/abci/types" - - app "github.com/binance-chain/node/common/types" -) - -func createAbciQueryHandler(paramHub *ParamHub) 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 "fees": - ctx := app.GetContextForCheckState() - fp := paramHub.GetFeeParams(ctx) - bz, err := app.GetCodec().MarshalBinaryLengthPrefixed(fp) - 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.CodeOK), - Info: fmt.Sprintf( - "Unknown `%s` query path: %v", - AbciQueryPrefix, path), - } - } - } -} diff --git a/plugins/param/abci_test.go b/plugins/param/abci_test.go deleted file mode 100644 index a9d090d90..000000000 --- a/plugins/param/abci_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package param_test - -import ( - "bytes" - "os" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/assert" - abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/libs/log" - - bca "github.com/binance-chain/node/app" - "github.com/binance-chain/node/plugins/param" -) - -// util objects -var ( - db = dbm.NewMemDB() - logger = log.NewTMLogger(os.Stdout) - app = bca.NewBinanceChain(logger, db, os.Stdout) -) - -func Test_Get_Operate_Fee_OK(t *testing.T) { - path := "/param/fees" - - ctx := app.NewContext(sdk.RunTxModeCheck, abci.Header{}) - testParam := param.DefaultGenesisState - - app.ParamHub.InitGenesis(ctx, testParam) - - query := abci.RequestQuery{ - Path: path, - Data: []byte(""), - } - res := app.Query(query) - - assert.True(t, sdk.ABCICodeType(res.Code).IsOK()) - output, err := app.GetCodec().MarshalJSON(testParam) - assert.NoError(t, err) - bytes.Equal(res.GetValue(), output) -} diff --git a/plugins/param/aliases.go b/plugins/param/aliases.go deleted file mode 100644 index 81930a889..000000000 --- a/plugins/param/aliases.go +++ /dev/null @@ -1,7 +0,0 @@ -package param - -import ( - "github.com/binance-chain/node/plugins/param/paramhub" -) - -type ParamHub = paramhub.Keeper diff --git a/plugins/param/client/cli/command.go b/plugins/param/client/cli/command.go deleted file mode 100644 index 111222507..000000000 --- a/plugins/param/client/cli/command.go +++ /dev/null @@ -1,23 +0,0 @@ -package cli - -import ( - "github.com/cosmos/cosmos-sdk/client" - "github.com/spf13/cobra" - - "github.com/binance-chain/node/wire" -) - -func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { - - dexCmd := &cobra.Command{ - Use: "params", - Short: "params commands", - } - dexCmd.AddCommand( - client.PostCommands( - SubmitFeeChangeProposalCmd(cdc))...) - dexCmd.AddCommand( - client.GetCommands( - ShowFeeParamsCmd(cdc))...) - cmd.AddCommand(dexCmd) -} diff --git a/plugins/param/client/cli/fees.go b/plugins/param/client/cli/fees.go deleted file mode 100644 index cb834bf4a..000000000 --- a/plugins/param/client/cli/fees.go +++ /dev/null @@ -1,152 +0,0 @@ -package cli - -import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "time" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/utils" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" - authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" - "github.com/cosmos/cosmos-sdk/x/gov" - - "github.com/binance-chain/node/app" - "github.com/binance-chain/node/plugins/param" - "github.com/binance-chain/node/plugins/param/types" - "github.com/binance-chain/node/wire" -) - -const ( - flagTitle = "title" - flagDescription = "description" - flagDeposit = "deposit" - flagVotingPeriod = "voting-period" - - //Fee flag - flagFeeParamFile = "fee-param-file" - flagFormat = "format" -) - -func SubmitFeeChangeProposalCmd(cdc *codec.Codec) *cobra.Command { - feeParam := types.FeeChangeParams{[]types.FeeParam{}, ""} - cmd := &cobra.Command{ - Use: "submit-fee-change-proposal", - Short: "Submit a fee or fee rate change proposal", - RunE: func(cmd *cobra.Command, args []string) error { - txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) - cliCtx := context.NewCLIContext(). - WithCodec(cdc). - WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - title := viper.GetString(flagTitle) - initialDeposit := viper.GetString(flagDeposit) - feeParamFile := viper.GetString(flagFeeParamFile) - feeParam.Description = viper.GetString(flagDescription) - votingPeriodInSeconds := viper.GetInt64(flagVotingPeriod) - if feeParamFile == "" { - return errors.New("fee-param-file is missing") - } - - bz, err := ioutil.ReadFile(feeParamFile) - if err != nil { - return err - } - err = cdc.UnmarshalJSON(bz, &(feeParam.FeeParams)) - if err != nil { - return err - } - err = feeParam.Check() - if err != nil { - return err - } - fromAddr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - amount, err := sdk.ParseCoins(initialDeposit) - if err != nil { - return err - } - // feeParam get interface field, use amino - feeParamsBz, err := app.Codec.MarshalJSON(feeParam) - if err != nil { - return err - } - - if votingPeriodInSeconds <= 0 { - return errors.New("voting period should be positive") - } - - votingPeriod := time.Duration(votingPeriodInSeconds) * time.Second - if votingPeriod > gov.MaxVotingPeriod { - return fmt.Errorf("voting period should less than %d seconds", gov.MaxVotingPeriod/time.Second) - } - - msg := gov.NewMsgSubmitProposal(title, string(feeParamsBz), gov.ProposalTypeFeeChange, fromAddr, amount, votingPeriod) - err = msg.ValidateBasic() - if err != nil { - return err - } - if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) - } - cliCtx.PrintResponse = true - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) - }, - } - cmd.Flags().String(flagFeeParamFile, "", "the file of fee params (json format)") - cmd.Flags().String(flagTitle, "", "title of proposal") - cmd.Flags().Int64(flagVotingPeriod, 7*24*60*60, "voting period in seconds") - cmd.Flags().String(flagDescription, "", "description of proposal") - cmd.Flags().String(flagDeposit, "", "deposit of proposal") - return cmd -} - -func ShowFeeParamsCmd(cdc *wire.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "show-fees", - Short: "Show order book of the listed currency pair", - RunE: func(cmd *cobra.Command, args []string) error { - - cliCtx := context.NewCLIContext(). - WithCodec(cdc). - WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - format := viper.GetString(flagFormat) - if format != types.JSONFORMAT && format != types.AMINOFORMAT { - return fmt.Errorf("format %s is not supported, options [%s, %s] ", format, types.JSONFORMAT, types.AMINOFORMAT) - } - - bz, err := cliCtx.Query(fmt.Sprintf("%s/fees", param.AbciQueryPrefix), nil) - if err != nil { - return err - } - var fees []types.FeeParam - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &fees) - if err != nil { - return err - } - - var output []byte - if format == types.JSONFORMAT { - output, err = json.MarshalIndent(fees, "", "\t") - } else if format == types.AMINOFORMAT { - output, err = cdc.MarshalJSONIndent(fees, "", "\t") - } - if err != nil { - return err - } - fmt.Println(string(output)) - return nil - }, - } - - cmd.Flags().String(flagFormat, types.AMINOFORMAT, fmt.Sprintf("the response format, options: [%s, %s]", types.AMINOFORMAT, types.JSONFORMAT)) - return cmd -} diff --git a/plugins/param/client/rest/getfees.go b/plugins/param/client/rest/getfees.go deleted file mode 100644 index 2994bc4c7..000000000 --- a/plugins/param/client/rest/getfees.go +++ /dev/null @@ -1,68 +0,0 @@ -package rest - -import ( - "encoding/json" - "errors" - "fmt" - "net/http" - - "github.com/cosmos/cosmos-sdk/client/context" - - "github.com/binance-chain/node/plugins/param" - "github.com/binance-chain/node/plugins/param/types" - "github.com/binance-chain/node/wire" -) - -func GetFeesParamHandler(cdc *wire.Codec, ctx context.CLIContext) http.HandlerFunc { - - responseType := "application/json" - - throw := func(w http.ResponseWriter, status int, err error) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(status) - w.Write([]byte(err.Error())) - return - } - - return func(w http.ResponseWriter, r *http.Request) { - - bz, err := ctx.Query(fmt.Sprintf("%s/fees", param.AbciQueryPrefix), nil) - if err != nil { - throw(w, http.StatusInternalServerError, err) - return - } - var fees []types.FeeParam - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &fees) - if err != nil { - throw(w, http.StatusInternalServerError, err) - return - } - formats, exist := r.URL.Query()["format"] - format := types.JSONFORMAT - if exist { - if len(formats) < 1 { - throw(w, http.StatusBadRequest, errors.New(fmt.Sprintf("Format parameter is invalid"))) - return - } - format = formats[0] - if format != types.JSONFORMAT && format != types.AMINOFORMAT { - throw(w, http.StatusBadRequest, errors.New(fmt.Sprintf("Format %s is not supported, options [%s, %s]", format, types.JSONFORMAT, types.AMINOFORMAT))) - return - } - } - var output []byte - if format == types.JSONFORMAT { - output, err = json.Marshal(fees) - } else if format == types.AMINOFORMAT { - output, err = cdc.MarshalJSON(fees) - } - if err != nil { - throw(w, http.StatusInternalServerError, err) - return - } - - w.Header().Set("Content-Type", responseType) - w.WriteHeader(http.StatusOK) - w.Write(output) - } -} diff --git a/plugins/param/genesis.go b/plugins/param/genesis.go deleted file mode 100644 index c2867de91..000000000 --- a/plugins/param/genesis.go +++ /dev/null @@ -1,110 +0,0 @@ -package param - -import ( - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/stake" - - sdk "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/dex/order" - "github.com/binance-chain/node/plugins/dex/types" - param "github.com/binance-chain/node/plugins/param/types" - "github.com/binance-chain/node/plugins/tokens/burn" - "github.com/binance-chain/node/plugins/tokens/freeze" - "github.com/binance-chain/node/plugins/tokens/issue" -) - -const ( - // Operate fee - ProposeFee = 10e8 - DepositFee = 125e3 - ListingFee = 2000e8 - IssueFee = 1000e8 - MintFee = 200e8 - BurnFee = 1e8 - FreezeFee = 1e6 - TimeLockFee = 1e6 - TimeUnlockFee = 1e6 - TimeRelockFee = 1e6 - - SetAccountFlagsFee = 1e8 - - HTLTFee = 37500 - DepositHTLTFee = 37500 - ClaimHTLTFee = 37500 - RefundHTLTFee = 37500 - - // stake fee - CreateValidatorFee = 10e8 - RemoveValidatorFee = 1e8 - - // Transfer fee - TransferFee = 62500 - MultiTransferFee = 50000 // discount 80% - LowerLimitAsMulti = 2 - - // Dex fee - ExpireFee = 5e4 - ExpireFeeNative = 1e4 - CancelFee = 5e4 - CancelFeeNative = 1e4 - FeeRate = 1000 - FeeRateNative = 400 - IOCExpireFee = 25e3 - IOCExpireFeeNative = 5e3 - - //MiniToken fee - TinyIssueFee = 2e8 - MiniIssueFee = 3e8 - MiniSetUriFee = 37500 - MiniListingFee = 8e8 -) - -var DefaultGenesisState = param.GenesisState{ - FeeGenesis: FeeGenesisState, - - //Add other param genesis here -} - -// --------- Definition about fee prams ------------------- // -var FeeGenesisState = []param.FeeParam{ - // Operate - ¶m.FixedFeeParams{gov.MsgSubmitProposal{}.Type(), ProposeFee, sdk.FeeForProposer}, - ¶m.FixedFeeParams{gov.MsgDeposit{}.Type(), DepositFee, sdk.FeeForProposer}, - ¶m.FixedFeeParams{gov.MsgVote{}.Type(), sdk.ZeroFee, sdk.FeeFree}, - ¶m.FixedFeeParams{stake.MsgCreateValidator{}.Type(), CreateValidatorFee, sdk.FeeForProposer}, - ¶m.FixedFeeParams{stake.MsgRemoveValidator{}.Type(), RemoveValidatorFee, sdk.FeeForProposer}, - ¶m.FixedFeeParams{types.ListRoute, ListingFee, sdk.FeeForAll}, - ¶m.FixedFeeParams{order.RouteNewOrder, sdk.ZeroFee, sdk.FeeFree}, - ¶m.FixedFeeParams{order.RouteCancelOrder, sdk.ZeroFee, sdk.FeeFree}, - ¶m.FixedFeeParams{issue.IssueMsgType, IssueFee, sdk.FeeForAll}, - ¶m.FixedFeeParams{issue.MintMsgType, MintFee, sdk.FeeForAll}, - ¶m.FixedFeeParams{burn.BurnRoute, BurnFee, sdk.FeeForProposer}, - ¶m.FixedFeeParams{freeze.FreezeRoute, FreezeFee, sdk.FeeForProposer}, - - // Transfer - ¶m.TransferFeeParam{ - FixedFeeParams: param.FixedFeeParams{ - MsgType: bank.MsgSend{}.Type(), - Fee: TransferFee, - FeeFor: sdk.FeeForProposer}, - MultiTransferFee: MultiTransferFee, - LowerLimitAsMulti: LowerLimitAsMulti, - }, - - // Dex - ¶m.DexFeeParam{ - DexFeeFields: []param.DexFeeField{ - {order.ExpireFeeField, ExpireFee}, - {order.ExpireFeeNativeField, ExpireFeeNative}, - {order.CancelFeeField, CancelFee}, - {order.CancelFeeNativeField, CancelFeeNative}, - {order.FeeRateField, FeeRate}, - {order.FeeRateNativeField, FeeRateNative}, - {order.IOCExpireFee, IOCExpireFee}, - {order.IOCExpireFeeNative, IOCExpireFeeNative}, - }, - }, -} - -//---------- End definition about fee param ---------------- // diff --git a/plugins/param/hooks.go b/plugins/param/hooks.go deleted file mode 100644 index 95770643d..000000000 --- a/plugins/param/hooks.go +++ /dev/null @@ -1,35 +0,0 @@ -package param - -import ( - "fmt" - - "github.com/binance-chain/node/plugins/param/types" - "github.com/binance-chain/node/wire" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/gov" -) - -type FeeChangeHooks struct { - cdc *wire.Codec -} - -func NewFeeChangeHooks(cdc *wire.Codec) FeeChangeHooks { - return FeeChangeHooks{cdc} -} - -var _ gov.GovHooks = FeeChangeHooks{} - -func (hooks FeeChangeHooks) OnProposalSubmitted(ctx sdk.Context, proposal gov.Proposal) error { - if proposal.GetProposalType() != gov.ProposalTypeFeeChange { - panic(fmt.Sprintf("received wrong type of proposal %x", proposal.GetProposalType())) - } - - feeParams := types.FeeChangeParams{} - err := hooks.cdc.UnmarshalJSON([]byte(proposal.GetDescription()), &feeParams) - if err != nil { - return fmt.Errorf("unmarshal feeParam error, err=%s", err.Error()) - } - - return feeParams.Check() -} diff --git a/plugins/param/paramhub/fees.go b/plugins/param/paramhub/fees.go deleted file mode 100644 index fc7a8eef6..000000000 --- a/plugins/param/paramhub/fees.go +++ /dev/null @@ -1,108 +0,0 @@ -package paramhub - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/binance-chain/node/common/fees" - "github.com/binance-chain/node/plugins/param/types" -) - -func (keeper *Keeper) initFeeGenesis(ctx sdk.Context, state types.GenesisState) { - keeper.SetFeeParams(ctx, state.FeeGenesis) -} - -func (keeper *Keeper) GetFeeParams(ctx sdk.Context) []types.FeeParam { - feeParams := make([]types.FeeParam, 0) - keeper.paramSpace.Get(ctx, ParamStoreKeyFees, &feeParams) - return feeParams -} - -func (keeper *Keeper) SetFeeParams(ctx sdk.Context, fp []types.FeeParam) { - keeper.paramSpace.Set(ctx, ParamStoreKeyFees, fp) - return -} - -func (keeper *Keeper) UpdateFeeParams(ctx sdk.Context, updates []types.FeeParam) { - origin := keeper.GetFeeParams(ctx) - opFeeMap := make(map[string]int, len(updates)) - dexFeeLoc := 0 - for index, update := range origin { - switch update := update.(type) { - case types.MsgFeeParams: - opFeeMap[update.GetMsgType()] = index - case *types.DexFeeParam: - dexFeeLoc = index - default: - keeper.logger.Debug("Origin Fee param not supported ", "feeParam", update) - } - } - for _, update := range updates { - switch update := update.(type) { - case types.MsgFeeParams: - if index, exist := opFeeMap[update.GetMsgType()]; exist { - origin[index] = update - } else { - opFeeMap[update.GetMsgType()] = len(origin) - origin = append(origin, update) - } - case *types.DexFeeParam: - origin[dexFeeLoc] = update - default: - keeper.logger.Info("Update fee param not supported ", "feeParam", update) - } - } - keeper.updateFeeCalculator(origin) - keeper.SetFeeParams(ctx, origin) - return -} - -func (keeper *Keeper) loadFeeParam(ctx sdk.Context) { - fp := keeper.GetFeeParams(ctx) - keeper.notifyOnLoad(ctx, fp) -} - -func (keeper *Keeper) registerFeeParamCallBack() { - keeper.SubscribeParamChange( - func(context sdk.Context, changes []interface{}) { - for _, c := range changes { - switch change := c.(type) { - case []types.FeeParam: - keeper.UpdateFeeParams(context, change) - default: - keeper.logger.Debug("Receive param changes that not interested.") - } - } - }, - func(context sdk.Context, state types.GenesisState) { - keeper.SetFeeParams(context, state.FeeGenesis) - keeper.updateFeeCalculator(state.FeeGenesis) - }, - func(context sdk.Context, iLoad interface{}) { - switch load := iLoad.(type) { - case []types.FeeParam: - keeper.updateFeeCalculator(load) - default: - keeper.logger.Debug("Receive load param that not interested.") - } - - }, - ) -} - -func (keeper *Keeper) updateFeeCalculator(updates []types.FeeParam) { - fees.UnsetAllCalculators() - for _, u := range updates { - if u, ok := u.(types.MsgFeeParams); ok { - generator := fees.GetCalculatorGenerator(u.GetMsgType()) - if generator == nil { - continue - } else { - err := u.Check() - if err != nil { - panic(err) - } - fees.RegisterCalculator(u.GetMsgType(), generator(u)) - } - } - } -} diff --git a/plugins/param/paramhub/keeper.go b/plugins/param/paramhub/keeper.go deleted file mode 100644 index 04ea45a70..000000000 --- a/plugins/param/paramhub/keeper.go +++ /dev/null @@ -1,166 +0,0 @@ -package paramhub - -import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/params" - tmlog "github.com/tendermint/tendermint/libs/log" - - bnclog "github.com/binance-chain/node/common/log" - "github.com/binance-chain/node/plugins/param/types" -) - -var ( - ParamStoreKeyLastFeeChangeProposalID = []byte("lastFeeChangeProposalID") - ParamStoreKeyFees = []byte("fees") - //Add other parameter store key here -) - -const ( - DefaultParamSpace = "paramhub" -) - -func ParamTypeTable() params.TypeTable { - return params.NewTypeTable( - ParamStoreKeyLastFeeChangeProposalID, types.LastProposalID{}, - ParamStoreKeyFees, []types.FeeParam{}, - ) -} - -type Keeper struct { - params.Keeper - cdc *codec.Codec - paramSpace params.Subspace - codespace sdk.CodespaceType - - govKeeper gov.Keeper - - updateCallbacks []func(sdk.Context, []interface{}) - genesisCallbacks []func(sdk.Context, types.GenesisState) - loadCallBacks []func(sdk.Context, interface{}) - - logger tmlog.Logger -} - -func NewKeeper(cdc *codec.Codec, key *sdk.KVStoreKey, tkey *sdk.TransientStoreKey) *Keeper { - logger := bnclog.With("module", "paramHub") - keeper := Keeper{ - Keeper: params.NewKeeper(cdc, key, tkey), - cdc: cdc, - updateCallbacks: make([]func(sdk.Context, []interface{}), 0), - genesisCallbacks: make([]func(sdk.Context, types.GenesisState), 0), - logger: logger, - } - keeper.paramSpace = keeper.Subspace(DefaultParamSpace).WithTypeTable(ParamTypeTable()) - // Add global callback(belongs to no other plugin) here - keeper.registerFeeParamCallBack() - return &keeper -} - -func (keeper *Keeper) SetGovKeeper(govKeeper gov.Keeper) { - keeper.govKeeper = govKeeper -} - -func (keeper *Keeper) EndBreatheBlock(ctx sdk.Context) { - keeper.logger.Info("Sync params proposals.") - changes := make([]interface{}, 0) - feeChange := keeper.getLastFeeChangeParam(ctx) - if feeChange != nil { - changes = append(changes, feeChange) - } - // Add other param change here - if len(changes) != 0 { - keeper.notifyOnUpdate(ctx, changes) - } - return -} - -func (keeper *Keeper) notifyOnUpdate(ctx sdk.Context, changes []interface{}) { - for _, c := range keeper.updateCallbacks { - c(ctx, changes) - } -} - -func (keeper *Keeper) notifyOnLoad(ctx sdk.Context, load interface{}) { - for _, c := range keeper.loadCallBacks { - c(ctx, load) - } -} - -func (keeper *Keeper) notifyOnGenesis(ctx sdk.Context, state types.GenesisState) { - for _, c := range keeper.genesisCallbacks { - c(ctx, state) - } -} - -func (keeper *Keeper) InitGenesis(ctx sdk.Context, params types.GenesisState) { - keeper.initFeeGenesis(ctx, params) - keeper.notifyOnGenesis(ctx, params) - keeper.setLastFeeChangeProposalId(ctx, types.LastProposalID{0}) -} - -// For fee parameters -func (keeper *Keeper) getLastFeeChangeProposalId(ctx sdk.Context) types.LastProposalID { - var id types.LastProposalID - keeper.paramSpace.Get(ctx, ParamStoreKeyLastFeeChangeProposalID, &id) - return id -} - -func (keeper *Keeper) setLastFeeChangeProposalId(ctx sdk.Context, id types.LastProposalID) { - keeper.paramSpace.Set(ctx, ParamStoreKeyLastFeeChangeProposalID, &id) - return -} - -func (keeper *Keeper) getLastFeeChangeParam(ctx sdk.Context) []types.FeeParam { - var latestProposal *gov.Proposal - lastProposalId := keeper.getLastFeeChangeProposalId(ctx) - keeper.govKeeper.Iterate(ctx, nil, nil, gov.StatusPassed, lastProposalId.ProposalID, true, func(proposal gov.Proposal) bool { - if proposal.GetProposalType() == gov.ProposalTypeFeeChange { - latestProposal = &proposal - return true - } - return false - }) - if latestProposal != nil { - var changeParam types.FeeChangeParams - strProposal := (*latestProposal).GetDescription() - err := keeper.cdc.UnmarshalJSON([]byte(strProposal), &changeParam) - if err != nil { - panic(fmt.Sprintf("Get broken data when unmarshal FeeChangeParams msg. %v", err)) - } - // setLastFeeProposal first. If invalid, the proposal before it will not been processed too. - keeper.setLastFeeChangeProposalId(ctx, types.LastProposalID{(*latestProposal).GetProposalID()}) - if err := changeParam.Check(); err != nil { - keeper.logger.Error("The latest fee param change proposal is invalid.", "proposalId", (*latestProposal).GetProposalID(), "param", changeParam, "err", err) - return nil - } - return changeParam.FeeParams - } - return nil -} - -func (keeper *Keeper) Load(ctx sdk.Context) { - keeper.loadFeeParam(ctx) - // Add other param load here -} - -func (keeper *Keeper) SubscribeParamChange(u func(sdk.Context, []interface{}), g func(sdk.Context, types.GenesisState), l func(sdk.Context, interface{})) { - keeper.SubscribeUpdateEvent(u) - keeper.SubscribeGenesisEvent(g) - keeper.SubscribeLoadEvent(l) -} - -func (keeper *Keeper) SubscribeUpdateEvent(c func(sdk.Context, []interface{})) { - keeper.updateCallbacks = append(keeper.updateCallbacks, c) -} - -func (keeper *Keeper) SubscribeGenesisEvent(c func(sdk.Context, types.GenesisState)) { - keeper.genesisCallbacks = append(keeper.genesisCallbacks, c) -} - -func (keeper *Keeper) SubscribeLoadEvent(c func(sdk.Context, interface{})) { - keeper.loadCallBacks = append(keeper.loadCallBacks, c) -} diff --git a/plugins/param/plugin.go b/plugins/param/plugin.go deleted file mode 100644 index e3b4dc060..000000000 --- a/plugins/param/plugin.go +++ /dev/null @@ -1,110 +0,0 @@ -package param - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/stake" - - "github.com/binance-chain/node/common/fees" - "github.com/binance-chain/node/common/types" - app "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/upgrade" - "github.com/binance-chain/node/plugins/account" - "github.com/binance-chain/node/plugins/dex/order" - dextypes "github.com/binance-chain/node/plugins/dex/types" - "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" - 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" -) - -const AbciQueryPrefix = "param" - -// InitPlugin initializes the param plugin. -func InitPlugin(app app.ChainApp, hub *paramhub.Keeper) { - handler := createQueryHandler(hub) - app.RegisterQueryHandler(AbciQueryPrefix, handler) - RegisterUpgradeBeginBlocker(hub) -} - -func createQueryHandler(keeper *paramhub.Keeper) app.AbciQueryHandler { - return createAbciQueryHandler(keeper) -} - -func RegisterUpgradeBeginBlocker(paramHub *ParamHub) { - upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP9, func(ctx sdk.Context) { - timeLockFeeParams := []param.FeeParam{ - ¶m.FixedFeeParams{MsgType: timelock.TimeLockMsg{}.Type(), Fee: TimeLockFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: timelock.TimeUnlockMsg{}.Type(), Fee: TimeUnlockFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: timelock.TimeRelockMsg{}.Type(), Fee: TimeRelockFee, FeeFor: types.FeeForProposer}, - } - paramHub.UpdateFeeParams(ctx, timeLockFeeParams) - }) - upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP12, func(ctx sdk.Context) { - accountFlagsFeeParams := []param.FeeParam{ - ¶m.FixedFeeParams{MsgType: account.SetAccountFlagsMsg{}.Type(), Fee: SetAccountFlagsFee, FeeFor: types.FeeForProposer}, - } - paramHub.UpdateFeeParams(ctx, accountFlagsFeeParams) - }) - upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP3, func(ctx sdk.Context) { - swapFeeParams := []param.FeeParam{ - ¶m.FixedFeeParams{MsgType: swap.HTLTMsg{}.Type(), Fee: HTLTFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: swap.DepositHTLTMsg{}.Type(), Fee: DepositHTLTFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: swap.ClaimHTLTMsg{}.Type(), Fee: ClaimHTLTFee, FeeFor: types.FeeForProposer}, - ¶m.FixedFeeParams{MsgType: swap.RefundHTLTMsg{}.Type(), Fee: RefundHTLTFee, FeeFor: types.FeeForProposer}, - } - paramHub.UpdateFeeParams(ctx, swapFeeParams) - }) - upgrade.Mgr.RegisterBeginBlocker(upgrade.BEP8, func(ctx sdk.Context) { - miniTokenFeeParams := []param.FeeParam{ - ¶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: dextypes.ListMiniMsg{}.Type(), Fee: MiniListingFee, FeeFor: types.FeeForAll}, - } - paramHub.UpdateFeeParams(ctx, miniTokenFeeParams) - }) -} - -func EndBreatheBlock(ctx sdk.Context, paramHub *ParamHub) { - paramHub.EndBreatheBlock(ctx) - return -} - -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.MsgDeposit{}.Type(): fees.FixedFeeCalculatorGen, - gov.MsgVote{}.Type(): fees.FixedFeeCalculatorGen, - stake.MsgCreateValidator{}.Type(): fees.FixedFeeCalculatorGen, - stake.MsgRemoveValidator{}.Type(): fees.FixedFeeCalculatorGen, - dextypes.ListMsg{}.Type(): fees.FixedFeeCalculatorGen, - order.RouteNewOrder: fees.FixedFeeCalculatorGen, - order.RouteCancelOrder: fees.FixedFeeCalculatorGen, - issue.IssueMsgType: fees.FixedFeeCalculatorGen, - issue.MintMsgType: fees.FixedFeeCalculatorGen, - 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, - dextypes.ListMiniMsg{}.Type(): fees.FixedFeeCalculatorGen, - } -} diff --git a/plugins/param/types/types.go b/plugins/param/types/types.go deleted file mode 100644 index 4acab6873..000000000 --- a/plugins/param/types/types.go +++ /dev/null @@ -1,198 +0,0 @@ -package types - -import ( - "encoding/json" - "fmt" - - "github.com/binance-chain/node/common/types" -) - -const ( - OperateFeeType = "operate" - TransferFeeType = "transfer" - DexFeeType = "dex" - - JSONFORMAT = "json" - AMINOFORMAT = "amino" -) - -var ( - // To avoid cycle import , use literal key. Please update here when new type message is introduced. - ValidFixedFeeMsgTypes = map[string]struct{}{ - "submit_proposal": {}, - "deposit": {}, - "vote": {}, - "dexList": {}, - "orderNew": {}, - "orderCancel": {}, - "issueMsg": {}, - "mintMsg": {}, - "tokensBurn": {}, - "setAccountFlags": {}, - "tokensFreeze": {}, - "create_validator": {}, - "remove_validator": {}, - "timeLock": {}, - "timeUnlock": {}, - "timeRelock": {}, - - "HTLT": {}, - "depositHTLT": {}, - "claimHTLT": {}, - "refundHTLT": {}, - - "tinyIssueMsg": {}, - "miniIssueMsg": {}, - "miniTokensSetURI": {}, - "dexListMini": {}, - } - - ValidTransferFeeMsgTypes = map[string]struct{}{ - "send": {}, - } -) - -type LastProposalID struct { - ProposalID int64 `json:"proposal_id"` -} - -type GenesisState struct { - FeeGenesis []FeeParam `json:"fees"` -} - -// --------- Definition about fee prams ------------------- // - -type FeeChangeParams struct { - FeeParams []FeeParam `json:"fee_params"` - Description string `json:"description"` -} - -type FeeParam interface { - GetParamType() string - Check() error -} - -var _ FeeParam = MsgFeeParams(nil) - -type MsgFeeParams interface { - FeeParam - GetMsgType() string -} - -var _ MsgFeeParams = (*FixedFeeParams)(nil) - -type FixedFeeParams struct { - MsgType string `json:"msg_type"` - Fee int64 `json:"fee"` - FeeFor types.FeeDistributeType `json:"fee_for"` -} - -func (p *FixedFeeParams) GetParamType() string { - return OperateFeeType -} - -func (p *FixedFeeParams) GetMsgType() string { - return p.MsgType -} - -func (p *FixedFeeParams) Check() error { - if p.FeeFor != types.FeeForProposer && p.FeeFor != types.FeeForAll && p.FeeFor != types.FeeFree { - return fmt.Errorf("fee_for %d is invalid", p.FeeFor) - } - if p.Fee < 0 { - return fmt.Errorf("fee(%d) should not be negative", p.Fee) - } - if _, ok := ValidFixedFeeMsgTypes[p.GetMsgType()]; !ok { - return fmt.Errorf("msg type %s can't be fixedFeeParams", p.GetMsgType()) - } - return nil -} - -var _ MsgFeeParams = (*TransferFeeParam)(nil) - -type TransferFeeParam struct { - FixedFeeParams `json:"fixed_fee_params"` - MultiTransferFee int64 `json:"multi_transfer_fee"` - LowerLimitAsMulti int64 `json:"lower_limit_as_multi"` -} - -func (p *TransferFeeParam) GetParamType() string { - return TransferFeeType -} - -func (p *TransferFeeParam) Check() error { - if p.FeeFor != types.FeeForProposer && p.FeeFor != types.FeeForAll && p.FeeFor != types.FeeFree { - return fmt.Errorf("fee_for %d is invalid", p.FeeFor) - } - if p.Fee <= 0 || p.MultiTransferFee <= 0 { - return fmt.Errorf("both fee(%d) and multi_transfer_fee(%d) should be positive", p.Fee, p.MultiTransferFee) - } - if p.MultiTransferFee > p.Fee { - return fmt.Errorf("multi_transfer_fee(%d) should not be bigger than fee(%d)", p.MultiTransferFee, p.Fee) - } - if p.LowerLimitAsMulti <= 1 { - return fmt.Errorf("lower_limit_as_multi should > 1") - } - if _, ok := ValidTransferFeeMsgTypes[p.GetMsgType()]; !ok { - return fmt.Errorf("msg type %s can't be transferFeeParam", p.GetMsgType()) - } - return nil -} - -type DexFeeField struct { - FeeName string `json:"fee_name"` - FeeValue int64 `json:"fee_value"` -} - -type DexFeeParam struct { - DexFeeFields []DexFeeField `json:"dex_fee_fields"` -} - -func (p *DexFeeParam) isNil() bool { - for _, d := range p.DexFeeFields { - if d.FeeValue < 0 { - return true - } - } - return false -} - -func (p *DexFeeParam) GetParamType() string { - return DexFeeType -} - -func (p *DexFeeParam) Check() error { - if p.isNil() { - return fmt.Errorf("Dex fee param is less than 0 ") - } - return nil -} - -func (f *FeeChangeParams) Check() error { - return checkFeeParams(f.FeeParams) -} - -func (f *FeeChangeParams) String() string { - bz, err := json.Marshal(f) - if err != nil { - return "" - } - return string(bz) -} - -func checkFeeParams(fees []FeeParam) error { - numDexFeeParams := 0 - for _, c := range fees { - err := c.Check() - if err != nil { - return err - } - if _, ok := c.(*DexFeeParam); ok { - numDexFeeParams++ - } - } - if numDexFeeParams > 1 { - return fmt.Errorf("have more than one DexFeeParam, actural %d", numDexFeeParams) - } - return nil -} diff --git a/plugins/param/types/types_test.go b/plugins/param/types/types_test.go deleted file mode 100644 index 411e7313b..000000000 --- a/plugins/param/types/types_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package types - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/binance-chain/node/common/types" -) - -func TestFixedFeeParamTypeCheck(t *testing.T) { - testCases := []struct { - fp FixedFeeParams - expectError bool - }{ - {FixedFeeParams{"send", 0, types.FeeForProposer}, true}, - {FixedFeeParams{"submit_proposal", 0, types.FeeForProposer}, false}, - {FixedFeeParams{"remove_validator", 0, 0}, true}, - {FixedFeeParams{"tokensBurn", -1, types.FeeForProposer}, true}, - {FixedFeeParams{"tokensBurn", 100, types.FeeForProposer}, false}, - } - for _, testCase := range testCases { - err := testCase.fp.Check() - if testCase.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - } -} - -func TestTransferFeeParamTypeCheck(t *testing.T) { - testCases := []struct { - fp TransferFeeParam - expectError bool - }{ - {TransferFeeParam{FixedFeeParams{"send", 100, types.FeeForProposer}, 1, 2}, false}, - {TransferFeeParam{FixedFeeParams{"wrong type", 100, types.FeeForProposer}, 1, 2}, true}, - {TransferFeeParam{FixedFeeParams{"send", -1, types.FeeForProposer}, 1, 2}, true}, - {TransferFeeParam{FixedFeeParams{"send", 100, types.FeeForProposer}, 1, 1}, true}, - } - for _, testCase := range testCases { - err := testCase.fp.Check() - if testCase.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - } -} - -func TestDexFeeParamTypeCheck(t *testing.T) { - testCases := []struct { - fp DexFeeParam - expectError bool - }{ - {DexFeeParam{[]DexFeeField{{"ExpireFee", 1000}}}, false}, - {DexFeeParam{[]DexFeeField{{"ExpireFee", -1}}}, true}, - } - for _, testCase := range testCases { - err := testCase.fp.Check() - if testCase.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - } -} - -func TestFeeChangeParamsCheck(t *testing.T) { - testCases := []struct { - fp FeeChangeParams - expectError bool - }{ - {FeeChangeParams{FeeParams: []FeeParam{&DexFeeParam{[]DexFeeField{{"ExpireFee", 1000}}}, &TransferFeeParam{FixedFeeParams{"send", 100, types.FeeForProposer}, 1, 2}}}, false}, - {FeeChangeParams{FeeParams: []FeeParam{&DexFeeParam{[]DexFeeField{{"ExpireFee", 1000}}}, &FixedFeeParams{"send", 100, types.FeeForProposer}}}, true}, - {FeeChangeParams{FeeParams: []FeeParam{&DexFeeParam{[]DexFeeField{{"ExpireFee", 1000}}}, &DexFeeParam{[]DexFeeField{{"ExpireFee", 1000}}}}}, true}, - } - for _, testCase := range testCases { - err := testCase.fp.Check() - if testCase.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - } -} diff --git a/plugins/param/wire.go b/plugins/param/wire.go deleted file mode 100644 index 021aee0ab..000000000 --- a/plugins/param/wire.go +++ /dev/null @@ -1,15 +0,0 @@ -package param - -import ( - "github.com/binance-chain/node/plugins/param/types" - "github.com/binance-chain/node/wire" -) - -// Register concrete types on wire codec -func RegisterWire(cdc *wire.Codec) { - cdc.RegisterInterface((*types.FeeParam)(nil), nil) - cdc.RegisterInterface((*types.MsgFeeParams)(nil), nil) - cdc.RegisterConcrete(&types.FixedFeeParams{}, "params/FixedFeeParams", nil) - cdc.RegisterConcrete(&types.TransferFeeParam{}, "params/TransferFeeParams", nil) - cdc.RegisterConcrete(&types.DexFeeParam{}, "params/DexFeeParam", nil) -} diff --git a/plugins/tokens/client/cli/commands.go b/plugins/tokens/client/cli/commands.go index 67de8c4f6..4118c2630 100644 --- a/plugins/tokens/client/cli/commands.go +++ b/plugins/tokens/client/cli/commands.go @@ -35,7 +35,8 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { initiateHTLTCmd(cmdr), depositHTLTCmd(cmdr), claimHTLTCmd(cmdr), - refundHTLTCmd(cmdr))...) + refundHTLTCmd(cmdr), + )...) tokenCmd.AddCommand( client.GetCommands( diff --git a/plugins/tokens/fee.go b/plugins/tokens/fee.go deleted file mode 100644 index 275eac73d..000000000 --- a/plugins/tokens/fee.go +++ /dev/null @@ -1,44 +0,0 @@ -package tokens - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" - - "github.com/binance-chain/node/common/fees" - "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/common/utils" - param "github.com/binance-chain/node/plugins/param/types" -) - -var TransferFeeCalculatorGen = fees.FeeCalculatorGenerator(func(params param.FeeParam) fees.FeeCalculator { - transferFeeParam, ok := params.(*param.TransferFeeParam) - if !ok { - panic("Generator received unexpected param type") - } - - return fees.FeeCalculator(func(msg sdk.Msg) types.Fee { - transferMsg, ok := msg.(bank.MsgSend) - if !ok { - panic("unexpected msg for TransferFeeCalculator") - } - - totalFee := transferFeeParam.Fee - var inputNum int64 = 0 - for _, input := range transferMsg.Inputs { - inputNum += int64(len(input.Coins)) - } - var outputNum int64 = 0 - for _, output := range transferMsg.Outputs { - outputNum += int64(len(output.Coins)) - } - num := utils.MaxInt(inputNum, outputNum) - if num >= transferFeeParam.LowerLimitAsMulti { - if num > types.TokenMaxTotalSupply/transferFeeParam.MultiTransferFee { - totalFee = types.TokenMaxTotalSupply - } else { - totalFee = transferFeeParam.MultiTransferFee * num - } - } - return types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, totalFee)}, transferFeeParam.FeeFor) - }) -}) diff --git a/plugins/tokens/fee_test.go b/plugins/tokens/fee_test.go index acf054b9e..6b009d436 100644 --- a/plugins/tokens/fee_test.go +++ b/plugins/tokens/fee_test.go @@ -9,11 +9,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/paramHub/types" "github.com/binance-chain/node/common/testutils" common "github.com/binance-chain/node/common/types" - "github.com/binance-chain/node/plugins/param/types" - "github.com/binance-chain/node/plugins/tokens" ) func newAddr() sdk.AccAddress { @@ -21,9 +20,9 @@ func newAddr() sdk.AccAddress { return addr } -func checkFee(t *testing.T, fee common.Fee, expected int64) { +func checkFee(t *testing.T, fee sdk.Fee, expected int64) { require.Equal(t, - common.NewFee(sdk.Coins{sdk.NewCoin(common.NativeTokenSymbol, expected)}, common.FeeForProposer), + sdk.NewFee(sdk.Coins{sdk.NewCoin(common.NativeTokenSymbol, expected)}, sdk.FeeForProposer), fee) } @@ -32,13 +31,13 @@ func TestTransferFeeGen(t *testing.T) { FixedFeeParams: types.FixedFeeParams{ MsgType: bank.MsgSend{}.Type(), Fee: 1e6, - FeeFor: common.FeeForProposer, + FeeFor: sdk.FeeForProposer, }, MultiTransferFee: 8e5, LowerLimitAsMulti: 2, } - calculator := tokens.TransferFeeCalculatorGen(¶ms) + calculator := bank.TransferFeeCalculatorGen(¶ms) // (1 addr, 1 coin) : (1 addr, 1 coin) msg := bank.MsgSend{ @@ -100,7 +99,7 @@ func TestTransferFeeParams_JsonFormat(t *testing.T) { FixedFeeParams: types.FixedFeeParams{ MsgType: bank.MsgSend{}.Type(), Fee: 250000, - FeeFor: common.FeeForProposer, + FeeFor: sdk.FeeForProposer, }, MultiTransferFee: 200000, LowerLimitAsMulti: 2, diff --git a/plugins/tokens/plugin.go b/plugins/tokens/plugin.go index c54c52bf9..9b8e997b6 100644 --- a/plugins/tokens/plugin.go +++ b/plugins/tokens/plugin.go @@ -9,7 +9,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" bnclog "github.com/binance-chain/node/common/log" + "github.com/binance-chain/node/common/types" app "github.com/binance-chain/node/common/types" + "github.com/binance-chain/node/common/upgrade" "github.com/binance-chain/node/plugins/tokens/swap" "github.com/binance-chain/node/plugins/tokens/timelock" ) @@ -22,7 +24,8 @@ func InitPlugin( 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, accKeeper, coinKeeper, timeLockKeeper, swapKeeper) { + for route, handler := range Routes(mapper, accKeeper, coinKeeper, timeLockKeeper, + swapKeeper) { appp.GetRouter().AddRoute(route, handler) } @@ -31,6 +34,17 @@ func InitPlugin( miniTokenHandler := createQueryHandler(mapper, miniAbciQueryPrefix) appp.RegisterQueryHandler(abciQueryPrefix, tokenHandler) appp.RegisterQueryHandler(miniAbciQueryPrefix, miniTokenHandler) + RegisterUpgradeBeginBlocker(mapper) +} + +func RegisterUpgradeBeginBlocker(mapper Mapper) { + // bind bnb smart chain contract address to bnb token + upgrade.Mgr.RegisterBeginBlocker(upgrade.LaunchBscUpgrade, func(ctx sdk.Context) { + err := mapper.UpdateBind(ctx, types.NativeTokenSymbol, "0x0000000000000000000000000000000000000000", 18) + if err != nil { + panic(err) + } + }) } func createQueryHandler(mapper Mapper, queryPrefix string) app.AbciQueryHandler { diff --git a/plugins/tokens/store/mapper.go b/plugins/tokens/store/mapper.go index 932184cb0..5a65b25a2 100644 --- a/plugins/tokens/store/mapper.go +++ b/plugins/tokens/store/mapper.go @@ -38,6 +38,7 @@ type Mapper interface { 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 + UpdateBind(ctx sdk.Context, symbol string, contractAddress string, decimals int8) error UpdateMiniTokenURI(ctx sdk.Context, symbol string, uri string) error } @@ -173,6 +174,31 @@ func (m mapper) UpdateTotalSupply(ctx sdk.Context, symbol string, supply int64) return nil } +func (m mapper) UpdateBind(ctx sdk.Context, symbol string, contractAddress string, decimals int8) error { + if len(symbol) == 0 { + return errors.New("symbol cannot be empty") + } + + 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 { + return errors.New("token does not exist") + } + + toBeUpdated := m.decodeToken(bz) + toBeUpdated.SetContractDecimals(decimals) + toBeUpdated.SetContractAddress(contractAddress) + + store.Set(key, m.encodeToken(toBeUpdated)) + return nil +} + func (m mapper) encodeToken(token types.IToken) []byte { bz, err := m.cdc.MarshalBinaryBare(token) if err != nil { diff --git a/version/version.go b/version/version.go index f0c801353..7d940e69c 100644 --- a/version/version.go +++ b/version/version.go @@ -12,7 +12,7 @@ var ( Version string ) -const NodeVersion = "0.7.2-hf.1" +const NodeVersion = "v0.8.0" func init() { Version = fmt.Sprintf("Binance Chain Release: %s;", NodeVersion)