diff --git a/CHANGELOG.md b/CHANGELOG.md index a8043f554..4e2c5532d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## v0.10.17 +This is the release for the sunset of BNB Beacon Chain. + +FEATURES +* [\#977](https://github.com/bnb-chain/node/pull/1003) [BEP] feat: implement BEP-333(BNB Chain Fusion) + + ## v0.10.16 FEATURES * [\#977](https://github.com/bnb-chain/node/pull/977) [BEP] asset: add bep255 upgrade height for mainnet diff --git a/app/app.go b/app/app.go index 7670c42c8..c101bf248 100644 --- a/app/app.go +++ b/app/app.go @@ -55,6 +55,8 @@ import ( "github.com/bnb-chain/node/plugins/dex/list" "github.com/bnb-chain/node/plugins/dex/order" dextypes "github.com/bnb-chain/node/plugins/dex/types" + migrate "github.com/bnb-chain/node/plugins/migrate" + tokenRecover "github.com/bnb-chain/node/plugins/recover" "github.com/bnb-chain/node/plugins/tokens" "github.com/bnb-chain/node/plugins/tokens/issue" "github.com/bnb-chain/node/plugins/tokens/ownership" @@ -62,6 +64,7 @@ import ( "github.com/bnb-chain/node/plugins/tokens/swap" "github.com/bnb-chain/node/plugins/tokens/timelock" "github.com/bnb-chain/node/wire" + stakeMigration "github.com/cosmos/cosmos-sdk/x/stake/stake_migration" ) const ( @@ -359,6 +362,9 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { upgrade.Mgr.AddUpgradeHeight(upgrade.FixDoubleSignChainId, upgradeConfig.FixDoubleSignChainIdHeight) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP126, upgradeConfig.BEP126Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP255, upgradeConfig.BEP255Height) + upgrade.Mgr.AddUpgradeHeight(upgrade.FirstSunset, upgradeConfig.FirstSunsetHeight) + upgrade.Mgr.AddUpgradeHeight(upgrade.SecondSunset, upgradeConfig.SecondSunsetHeight) + upgrade.Mgr.AddUpgradeHeight(upgrade.FinalSunset, upgradeConfig.FinalSunsetHeight) // register store keys of upgrade upgrade.Mgr.RegisterStoreKeys(upgrade.BEP9, common.TimeLockStoreKey.Name()) @@ -619,6 +625,11 @@ func (app *BNBBeaconChain) initStaking() { newCtx := ctx.WithSideChainKeyPrefix(storePrefix) app.stakeKeeper.ClearUpSideVoteAddrs(newCtx) }) + upgrade.Mgr.RegisterBeginBlocker(sdk.FirstSunsetFork, func(ctx sdk.Context) { + chainId := sdk.ChainID(ServerContext.BscIbcChainId) + // enable channel but not send cross chain msg + app.scKeeper.SetChannelSendPermission(ctx, chainId, sTypes.StakeMigrationChannelID, sdk.ChannelAllow) + }) app.stakeKeeper.SubscribeParamChange(app.ParamHub) app.stakeKeeper.SubscribeBCParamChange(app.ParamHub) app.stakeKeeper = app.stakeKeeper.WithHooks(app.slashKeeper.Hooks()) @@ -629,6 +640,13 @@ func (app *BNBBeaconChain) initStaking() { if err != nil { panic(err) } + + // register stake migration channel + stakeMigrationApp := stakeMigration.NewStakeMigrationApp(app.stakeKeeper) + err = app.scKeeper.RegisterChannel(sTypes.StakeMigrationChannel, sTypes.StakeMigrationChannelID, stakeMigrationApp) + if err != nil { + panic(err) + } } func (app *BNBBeaconChain) initGov() { @@ -880,7 +898,7 @@ func (app *BNBBeaconChain) isBreatheBlock(height int64, lastBlockTime time.Time, // lastBlockTime is zero if this blockTime is for the first block (first block doesn't mean height = 1, because after // state sync from breathe block, the height is breathe block + 1) if app.baseConfig.BreatheBlockInterval > 0 { - return height%int64(app.baseConfig.BreatheBlockInterval) == 0 + return !lastBlockTime.IsZero() && !utils.SamePeriodInUTC(lastBlockTime, blockTime, int64(app.baseConfig.BreatheBlockInterval)) } else { return !lastBlockTime.IsZero() && !utils.SameDayInUTC(lastBlockTime, blockTime) } @@ -918,6 +936,7 @@ func (app *BNBBeaconChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) tokens.EndBreatheBlock(ctx, app.swapKeeper) } else { app.Logger.Debug("normal block", "height", height) + tokens.EndBlocker(ctx, app.timeLockKeeper, app.swapKeeper) } app.DexKeeper.StoreTradePrices(ctx) @@ -945,6 +964,9 @@ func (app *BNBBeaconChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) } else if ctx.RouterCallRecord()["stake"] || sdk.IsUpgrade(upgrade.BEP128) { validatorUpdates, completedUbd = stake.EndBlocker(ctx, app.stakeKeeper) } + + // That is no deep copy when New IBC Keeper. need to set it again. + app.ibcKeeper.SetSideChainKeeper(app.scKeeper) ibc.EndBlocker(ctx, app.ibcKeeper) if len(validatorUpdates) != 0 { app.ValAddrCache.ClearCache() @@ -1156,6 +1178,8 @@ func MakeCodec() *wire.Codec { bridge.RegisterWire(cdc) oracle.RegisterWire(cdc) ibc.RegisterWire(cdc) + tokenRecover.RegisterWire(cdc) + migrate.RegisterWire(cdc) return cdc } diff --git a/app/config/config.go b/app/config/config.go index 63df8ce91..5a0285cb5 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -103,6 +103,12 @@ FixDoubleSignChainIdHeight = {{ .UpgradeConfig.FixDoubleSignChainIdHeight }} BEP126Height = {{ .UpgradeConfig.BEP126Height }} # Block height of BEP255 upgrade BEP255Height = {{ .UpgradeConfig.BEP255Height }} +# Block height of FirstSunset upgrade +FirstSunsetHeight = {{ .UpgradeConfig.FirstSunsetHeight }} +# Block height of SecondSunset upgrade +SecondSunsetHeight = {{ .UpgradeConfig.SecondSunsetHeight }} +# Block height of FinalSunset upgrade +FinalSunsetHeight = {{ .UpgradeConfig.FinalSunsetHeight }} [query] # ABCI query interface black list, suggested value: ["custom/gov/proposals", "custom/timelock/timelocks", "custom/atomicSwap/swapcreator", "custom/atomicSwap/swaprecipient"] @@ -552,6 +558,9 @@ type UpgradeConfig struct { FixDoubleSignChainIdHeight int64 `mapstructure:"FixDoubleSignChainIdHeight"` BEP126Height int64 `mapstructure:"BEP126Height"` BEP255Height int64 `mapstructure:"BEP255Height"` + FirstSunsetHeight int64 `mapstructure:"FirstSunsetHeight"` + SecondSunsetHeight int64 `mapstructure:"SecondSunsetHeight"` + FinalSunsetHeight int64 `mapstructure:"FinalSunsetHeight"` } func defaultUpgradeConfig() *UpgradeConfig { @@ -586,7 +595,10 @@ func defaultUpgradeConfig() *UpgradeConfig { BEP171Height: math.MaxInt64, FixFailAckPackageHeight: math.MaxInt64, EnableAccountScriptsForCrossChainTransferHeight: math.MaxInt64, - BEP255Height: math.MaxInt64, + BEP255Height: math.MaxInt64, + FirstSunsetHeight: math.MaxInt64, + SecondSunsetHeight: math.MaxInt64, + FinalSunsetHeight: math.MaxInt64, } } diff --git a/app/fee_distribution_test.go b/app/fee_distribution_test.go index a4bf0e982..15ba679c4 100644 --- a/app/fee_distribution_test.go +++ b/app/fee_distribution_test.go @@ -11,7 +11,6 @@ import ( 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/mock" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/stretchr/testify/require" @@ -286,182 +285,182 @@ func ApplyToBreathBlocks(t *testing.T, app *BNBBeaconChain, ctx sdk.Context, bre return ApplyEmptyBlocks(t, app, ctx, blockNum) } -func TestBEP159Distribution(t *testing.T) { - app, ctx, accs := setupTestForBEP159Test() - // check genesis validators - validators := app.stakeKeeper.GetAllValidators(ctx) - //logger.Info("validators", "validators", validators) - require.Equal(t, 11, len(validators)) - require.True(t, len(validators[0].DistributionAddr) == 0, "distribution address should be empty") - // active BEP159 - ctx = ApplyEmptyBlocks(t, app, ctx, 6) - validators = app.stakeKeeper.GetAllValidators(ctx) - require.Equal(t, 11, len(validators)) - // logger.Info("validators", "validators", validators) - // migrate validator to add distribution address - require.True(t, len(validators[0].DistributionAddr) != 0, "distribution address should not be empty") - require.Lenf(t, validators[0].StakeSnapshots, 0, "no snapshot yet") - require.True(t, validators[0].AccumulatedStake.IsZero(), "no AccumulatedStake yet") - snapshotVals, h, found := app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) - logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) - require.False(t, found, "no validators snapshot yet") - // no fee got at the beginning of BEP159 activation - require.True(t, app.CoinKeeper.GetCoins(ctx, validators[0].DistributionAddr).IsZero()) - require.True(t, app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr).IsZero()) - // transfer tx to make some fees - transferCoin := sdk.NewCoin("BNB", 100000000) - inputs := bank.NewInput(accs[0].Address, sdk.Coins{transferCoin}) - outputs := bank.NewOutput(accs[1].Address, sdk.Coins{transferCoin}) - transferMsg := bank.NewMsgSend([]bank.Input{inputs}, []bank.Output{outputs}) - txs := GenSimTxs(app, []sdk.Msg{transferMsg}, true, accs[0].Priv) - ctx = ApplyBlock(t, app, ctx, txs) - // pass breath block - ctx = ApplyToBreathBlocks(t, app, ctx, 1) - validators = app.stakeKeeper.GetAllValidators(ctx) - require.Lenf(t, validators[0].StakeSnapshots, 1, "1 snapshot from one breath block") - require.False(t, validators[0].AccumulatedStake.IsZero(), "had AccumulatedStake") - snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) - logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) - require.True(t, found, "get snapshot in the first breath block after active BEP159") - snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 2) - require.False(t, found, "only one snapshot") - // pass 28 breath blocks - ctx = ApplyToBreathBlocks(t, app, ctx, 28) - snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) - logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) - require.True(t, found) - require.Len(t, snapshotVals[0].StakeSnapshots, 29) - // try to create validator - bondCoin := sdk.NewCoin("BNB", sdk.NewDecWithoutFra(10000*16).RawInt()) - commissionMsg := stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) - description := stake.NewDescription("validator0", "", "", "") - createValidatorMsg := stake.MsgCreateValidatorOpen{ - Description: description, - Commission: commissionMsg, - DelegatorAddr: accs[0].Address, - ValidatorAddr: sdk.ValAddress(accs[0].Address), - PubKey: sdk.MustBech32ifyConsPub(accs[0].Priv.PubKey()), - Delegation: bondCoin, - } - require.Panics(t, func() { - txs = GenSimTxs(app, []sdk.Msg{createValidatorMsg}, true, accs[0].Priv) - }) - // pass one more breath block, activate BEP159Phase2 - ctx = ApplyToBreathBlocks(t, app, ctx, 2) - snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) - require.True(t, found) - require.Len(t, snapshotVals[0].StakeSnapshots, 30) - require.True(t, app.CoinKeeper.GetCoins(ctx, validators[0].DistributionAddr).IsZero()) - require.Equal(t, app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr), sdk.Coins{sdk.NewCoin("BNB", 8)}) - // create new validators, stake number is 16 times of original validators - createValidatorMsg = stake.MsgCreateValidatorOpen{ - Description: description, - Commission: commissionMsg, - DelegatorAddr: accs[0].Address, - ValidatorAddr: sdk.ValAddress(accs[0].Address), - PubKey: sdk.MustBech32ifyConsPub(accs[0].Priv.PubKey()), - Delegation: bondCoin, - } - txs = GenSimTxs(app, []sdk.Msg{createValidatorMsg}, true, accs[0].Priv) - ctx = ApplyBlock(t, app, ctx, txs) - require.Equal(t, int64(12), app.stakeKeeper.GetAllValidatorsCount(ctx)) - validators = app.stakeKeeper.GetSortedBondedValidators(ctx) - // check fees - ctx = ApplyBlock(t, app, ctx, []auth.StdTx{}) - logger.Debug("feeAddrs", "validator0", validators[0].DistributionAddr, "feeForAll", stake.FeeForAllAccAddr) - validator0Balance := app.CoinKeeper.GetCoins(ctx, validators[0].DistributionAddr) - feeForAllBalance := app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr) - logger.Debug("feeBalances", "validator0", validator0Balance, "feeForAll", feeForAllBalance) - require.Equal(t, sdk.Coins{sdk.NewCoin("BNB", 50000000)}, app.CoinKeeper.GetCoins(ctx, validators[0].DistributionAddr)) - require.Equal(t, sdk.Coins{sdk.NewCoin("BNB", 950000008)}, app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr)) +// func TestBEP159Distribution(t *testing.T) { +// app, ctx, accs := setupTestForBEP159Test() +// // check genesis validators +// validators := app.stakeKeeper.GetAllValidators(ctx) +// //logger.Info("validators", "validators", validators) +// require.Equal(t, 11, len(validators)) +// require.True(t, len(validators[0].DistributionAddr) == 0, "distribution address should be empty") +// // active BEP159 +// ctx = ApplyEmptyBlocks(t, app, ctx, 6) +// validators = app.stakeKeeper.GetAllValidators(ctx) +// require.Equal(t, 11, len(validators)) +// // logger.Info("validators", "validators", validators) +// // migrate validator to add distribution address +// require.True(t, len(validators[0].DistributionAddr) != 0, "distribution address should not be empty") +// require.Lenf(t, validators[0].StakeSnapshots, 0, "no snapshot yet") +// require.True(t, validators[0].AccumulatedStake.IsZero(), "no AccumulatedStake yet") +// snapshotVals, h, found := app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) +// logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) +// require.False(t, found, "no validators snapshot yet") +// // no fee got at the beginning of BEP159 activation +// require.True(t, app.CoinKeeper.GetCoins(ctx, validators[0].DistributionAddr).IsZero()) +// require.True(t, app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr).IsZero()) +// // transfer tx to make some fees +// transferCoin := sdk.NewCoin("BNB", 100000000) +// inputs := bank.NewInput(accs[0].Address, sdk.Coins{transferCoin}) +// outputs := bank.NewOutput(accs[1].Address, sdk.Coins{transferCoin}) +// transferMsg := bank.NewMsgSend([]bank.Input{inputs}, []bank.Output{outputs}) +// txs := GenSimTxs(app, []sdk.Msg{transferMsg}, true, accs[0].Priv) +// ctx = ApplyBlock(t, app, ctx, txs) +// // pass breath block +// ctx = ApplyToBreathBlocks(t, app, ctx, 1) +// validators = app.stakeKeeper.GetAllValidators(ctx) +// require.Lenf(t, validators[0].StakeSnapshots, 1, "1 snapshot from one breath block") +// require.False(t, validators[0].AccumulatedStake.IsZero(), "had AccumulatedStake") +// snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) +// logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) +// require.True(t, found, "get snapshot in the first breath block after active BEP159") +// snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 2) +// require.False(t, found, "only one snapshot") +// // pass 28 breath blocks +// ctx = ApplyToBreathBlocks(t, app, ctx, 28) +// snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) +// logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) +// require.True(t, found) +// require.Len(t, snapshotVals[0].StakeSnapshots, 29) +// // try to create validator +// bondCoin := sdk.NewCoin("BNB", sdk.NewDecWithoutFra(10000*16).RawInt()) +// commissionMsg := stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) +// description := stake.NewDescription("validator0", "", "", "") +// createValidatorMsg := stake.MsgCreateValidatorOpen{ +// Description: description, +// Commission: commissionMsg, +// DelegatorAddr: accs[0].Address, +// ValidatorAddr: sdk.ValAddress(accs[0].Address), +// PubKey: sdk.MustBech32ifyConsPub(accs[0].Priv.PubKey()), +// Delegation: bondCoin, +// } +// require.Panics(t, func() { +// txs = GenSimTxs(app, []sdk.Msg{createValidatorMsg}, true, accs[0].Priv) +// }) +// // pass one more breath block, activate BEP159Phase2 +// ctx = ApplyToBreathBlocks(t, app, ctx, 2) +// snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) +// require.True(t, found) +// require.Len(t, snapshotVals[0].StakeSnapshots, 30) +// require.True(t, app.CoinKeeper.GetCoins(ctx, validators[0].DistributionAddr).IsZero()) +// require.Equal(t, app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr), sdk.Coins{sdk.NewCoin("BNB", 8)}) +// // create new validators, stake number is 16 times of original validators +// createValidatorMsg = stake.MsgCreateValidatorOpen{ +// Description: description, +// Commission: commissionMsg, +// DelegatorAddr: accs[0].Address, +// ValidatorAddr: sdk.ValAddress(accs[0].Address), +// PubKey: sdk.MustBech32ifyConsPub(accs[0].Priv.PubKey()), +// Delegation: bondCoin, +// } +// txs = GenSimTxs(app, []sdk.Msg{createValidatorMsg}, true, accs[0].Priv) +// ctx = ApplyBlock(t, app, ctx, txs) +// require.Equal(t, int64(12), app.stakeKeeper.GetAllValidatorsCount(ctx)) +// validators = app.stakeKeeper.GetSortedBondedValidators(ctx) +// // check fees +// ctx = ApplyBlock(t, app, ctx, []auth.StdTx{}) +// logger.Debug("feeAddrs", "validator0", validators[0].DistributionAddr, "feeForAll", stake.FeeForAllAccAddr) +// validator0Balance := app.CoinKeeper.GetCoins(ctx, validators[0].DistributionAddr) +// feeForAllBalance := app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr) +// logger.Debug("feeBalances", "validator0", validator0Balance, "feeForAll", feeForAllBalance) +// require.Equal(t, sdk.Coins{sdk.NewCoin("BNB", 50000000)}, app.CoinKeeper.GetCoins(ctx, validators[0].DistributionAddr)) +// require.Equal(t, sdk.Coins{sdk.NewCoin("BNB", 950000008)}, app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr)) - // check validator just staked - newValidator, found := app.stakeKeeper.GetValidator(ctx, sdk.ValAddress(accs[0].Address)) - require.True(t, found) - logger.Info("newValidator", "newValidator", newValidator) - require.True(t, len(newValidator.DistributionAddr) != 0, "newValidator distribution address should not be empty") - require.False(t, newValidator.IsBonded(), "newValidator should not be bonded") - require.Lenf(t, newValidator.StakeSnapshots, 0, "no snapshot yet") - require.True(t, newValidator.AccumulatedStake.IsZero(), "no AccumulatedStake yet") - snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) - logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) - require.True(t, found) - require.Equal(t, int64(160), h) +// // check validator just staked +// newValidator, found := app.stakeKeeper.GetValidator(ctx, sdk.ValAddress(accs[0].Address)) +// require.True(t, found) +// logger.Info("newValidator", "newValidator", newValidator) +// require.True(t, len(newValidator.DistributionAddr) != 0, "newValidator distribution address should not be empty") +// require.False(t, newValidator.IsBonded(), "newValidator should not be bonded") +// require.Lenf(t, newValidator.StakeSnapshots, 0, "no snapshot yet") +// require.True(t, newValidator.AccumulatedStake.IsZero(), "no AccumulatedStake yet") +// snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) +// logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) +// require.True(t, found) +// require.Equal(t, int64(160), h) - // apply to next breath block, validator0 accumulated stake not enough, not bounded - ctx = ApplyToBreathBlocks(t, app, ctx, 1) - snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) - logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) - require.True(t, found, "found validators snapshot") - require.Len(t, snapshotVals, 11) - require.Equal(t, int64(165), h) - require.NotEqual(t, snapshotVals[0].OperatorAddr, accs[0].ValAddress) +// // apply to next breath block, validator0 accumulated stake not enough, not bounded +// ctx = ApplyToBreathBlocks(t, app, ctx, 1) +// snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) +// logger.Debug("GetHeightValidatorsByIndex", "snapshotVals", snapshotVals, "h", h, "found", found) +// require.True(t, found, "found validators snapshot") +// require.Len(t, snapshotVals, 11) +// require.Equal(t, int64(165), h) +// require.NotEqual(t, snapshotVals[0].OperatorAddr, accs[0].ValAddress) - // check fees after distribution - feeForAllBalance = app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr) - logger.Debug("feeBalances", "validator0", validator0Balance, "feeForAll", feeForAllBalance) - require.Equal(t, app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr), sdk.Coins{sdk.NewCoin("BNB", 1)}) +// // check fees after distribution +// feeForAllBalance = app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr) +// logger.Debug("feeBalances", "validator0", validator0Balance, "feeForAll", feeForAllBalance) +// require.Equal(t, app.CoinKeeper.GetCoins(ctx, stake.FeeForAllAccAddr), sdk.Coins{sdk.NewCoin("BNB", 1)}) - // iter all validators, check their fees - distributionAddrBalanceSum := feeForAllBalance - var expectedBalance sdk.Coin - for i, validator := range snapshotVals { - distributionAddrBalance := app.CoinKeeper.GetCoins(ctx, validator.DistributionAddr) - feeAddrBalance := app.CoinKeeper.GetCoins(ctx, validator.FeeAddr) - logger.Debug("distributionAddrBalance", "name", validator.Description.Moniker, "distributionAddrBalance", distributionAddrBalance, "feeAddrBalance", feeAddrBalance) - require.Lenf(t, distributionAddrBalance, 1, "distributionAddrBalance should have 1 coin") - distributionAddrBalanceSum = distributionAddrBalanceSum.Plus(distributionAddrBalance) - if i == 0 { - expectedBalance = distributionAddrBalance[0].Minus(sdk.NewCoin("BNB", 50000000)) - } else { - require.False(t, feeAddrBalance.IsZero(), "feeAddrBalance should be zero") - require.Equal(t, expectedBalance, distributionAddrBalance[0]) - } - } - logger.Debug("distributionAddrBalanceSum", "distributionAddrBalanceSum", distributionAddrBalanceSum) - require.Equal(t, sdk.NewCoin("BNB", 1000000008), distributionAddrBalanceSum[0]) +// // iter all validators, check their fees +// distributionAddrBalanceSum := feeForAllBalance +// var expectedBalance sdk.Coin +// for i, validator := range snapshotVals { +// distributionAddrBalance := app.CoinKeeper.GetCoins(ctx, validator.DistributionAddr) +// feeAddrBalance := app.CoinKeeper.GetCoins(ctx, validator.FeeAddr) +// logger.Debug("distributionAddrBalance", "name", validator.Description.Moniker, "distributionAddrBalance", distributionAddrBalance, "feeAddrBalance", feeAddrBalance) +// require.Lenf(t, distributionAddrBalance, 1, "distributionAddrBalance should have 1 coin") +// distributionAddrBalanceSum = distributionAddrBalanceSum.Plus(distributionAddrBalance) +// if i == 0 { +// expectedBalance = distributionAddrBalance[0].Minus(sdk.NewCoin("BNB", 50000000)) +// } else { +// require.False(t, feeAddrBalance.IsZero(), "feeAddrBalance should be zero") +// require.Equal(t, expectedBalance, distributionAddrBalance[0]) +// } +// } +// logger.Debug("distributionAddrBalanceSum", "distributionAddrBalanceSum", distributionAddrBalanceSum) +// require.Equal(t, sdk.NewCoin("BNB", 1000000008), distributionAddrBalanceSum[0]) - // apply to next breath block, validator0 become bonded, the first one - ctx = ApplyToBreathBlocks(t, app, ctx, 1) - snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) - require.Equal(t, int64(170), h) - require.Equal(t, snapshotVals[0].OperatorAddr, accs[0].ValAddress) - for _, validator := range snapshotVals { - distributionAddrBalance := app.CoinKeeper.GetCoins(ctx, validator.DistributionAddr) - feeAddrBalance := app.CoinKeeper.GetCoins(ctx, validator.FeeAddr) - logger.Debug("distributionAddrBalance", "name", validator.Description.Moniker, "distributionAddrBalance", distributionAddrBalance, "feeAddrBalance", feeAddrBalance) - require.True(t, distributionAddrBalance.IsZero()) - require.False(t, feeAddrBalance.IsZero(), "feeAddrBalance should be zero") - } +// // apply to next breath block, validator0 become bonded, the first one +// ctx = ApplyToBreathBlocks(t, app, ctx, 1) +// snapshotVals, h, found = app.stakeKeeper.GetHeightValidatorsByIndex(ctx, 1) +// require.Equal(t, int64(170), h) +// require.Equal(t, snapshotVals[0].OperatorAddr, accs[0].ValAddress) +// for _, validator := range snapshotVals { +// distributionAddrBalance := app.CoinKeeper.GetCoins(ctx, validator.DistributionAddr) +// feeAddrBalance := app.CoinKeeper.GetCoins(ctx, validator.FeeAddr) +// logger.Debug("distributionAddrBalance", "name", validator.Description.Moniker, "distributionAddrBalance", distributionAddrBalance, "feeAddrBalance", feeAddrBalance) +// require.True(t, distributionAddrBalance.IsZero()) +// require.False(t, feeAddrBalance.IsZero(), "feeAddrBalance should be zero") +// } - // open this when delegate opens - //// two more breath block, one for delegator to get into snapshot, one to get rewards - //// validator1 delegate to validator0 - //delegateMsg := stake.NewMsgDelegate(accs[1].Address, sdk.ValAddress(accs[0].Address), sdk.NewCoin("BNB", sdk.NewDecWithoutFra(10000*16).RawInt())) - //txs = GenSimTxs(app, []sdk.Msg{delegateMsg}, true, accs[1].Priv) - //ctx = ApplyBlock(t, app, ctx, txs) - //delegatorBalance := app.CoinKeeper.GetCoins(ctx, accs[1].Address) - //logger.Debug("delegatorBalance", "delegatorBalance", delegatorBalance) - // - //// need 1 breath block to get into snapshot - //ctx = ApplyToBreathBlocks(t, app, ctx, 1) - //require.Equal(t, delegatorBalance, app.CoinKeeper.GetCoins(ctx, accs[1].Address)) - //delegatorBalance = app.CoinKeeper.GetCoins(ctx, accs[1].Address) - //logger.Debug("delegatorBalance", "delegatorBalance", delegatorBalance) - //// validator2 delegate to validator0 - //delegateMsg = stake.NewMsgDelegate(accs[2].Address, sdk.ValAddress(accs[0].Address), sdk.NewCoin("BNB", sdk.NewDecWithoutFra(10000*16).RawInt())) - //txs = GenSimTxs(app, []sdk.Msg{delegateMsg}, true, accs[2].Priv) - //ctx = ApplyBlock(t, app, ctx, txs) - // - //// need 1 breath block to get into distribution addr - //ctx = ApplyToBreathBlocks(t, app, ctx, 1) - //require.Equal(t, delegatorBalance, app.CoinKeeper.GetCoins(ctx, accs[1].Address)) - //delegatorBalance = app.CoinKeeper.GetCoins(ctx, accs[1].Address) - //logger.Debug("delegatorBalance", "delegatorBalance", delegatorBalance) - // - //// need 1 more block to distribute rewards - //ctx = ApplyEmptyBlocks(t, app, ctx, 1) - //require.NotEqual(t, delegatorBalance, app.CoinKeeper.GetCoins(ctx, accs[1].Address)) - //delegatorBalance = app.CoinKeeper.GetCoins(ctx, accs[1].Address) - //logger.Debug("delegatorBalance", "delegatorBalance", delegatorBalance) -} +// // open this when delegate opens +// //// two more breath block, one for delegator to get into snapshot, one to get rewards +// //// validator1 delegate to validator0 +// //delegateMsg := stake.NewMsgDelegate(accs[1].Address, sdk.ValAddress(accs[0].Address), sdk.NewCoin("BNB", sdk.NewDecWithoutFra(10000*16).RawInt())) +// //txs = GenSimTxs(app, []sdk.Msg{delegateMsg}, true, accs[1].Priv) +// //ctx = ApplyBlock(t, app, ctx, txs) +// //delegatorBalance := app.CoinKeeper.GetCoins(ctx, accs[1].Address) +// //logger.Debug("delegatorBalance", "delegatorBalance", delegatorBalance) +// // +// //// need 1 breath block to get into snapshot +// //ctx = ApplyToBreathBlocks(t, app, ctx, 1) +// //require.Equal(t, delegatorBalance, app.CoinKeeper.GetCoins(ctx, accs[1].Address)) +// //delegatorBalance = app.CoinKeeper.GetCoins(ctx, accs[1].Address) +// //logger.Debug("delegatorBalance", "delegatorBalance", delegatorBalance) +// //// validator2 delegate to validator0 +// //delegateMsg = stake.NewMsgDelegate(accs[2].Address, sdk.ValAddress(accs[0].Address), sdk.NewCoin("BNB", sdk.NewDecWithoutFra(10000*16).RawInt())) +// //txs = GenSimTxs(app, []sdk.Msg{delegateMsg}, true, accs[2].Priv) +// //ctx = ApplyBlock(t, app, ctx, txs) +// // +// //// need 1 breath block to get into distribution addr +// //ctx = ApplyToBreathBlocks(t, app, ctx, 1) +// //require.Equal(t, delegatorBalance, app.CoinKeeper.GetCoins(ctx, accs[1].Address)) +// //delegatorBalance = app.CoinKeeper.GetCoins(ctx, accs[1].Address) +// //logger.Debug("delegatorBalance", "delegatorBalance", delegatorBalance) +// // +// //// need 1 more block to distribute rewards +// //ctx = ApplyEmptyBlocks(t, app, ctx, 1) +// //require.NotEqual(t, delegatorBalance, app.CoinKeeper.GetCoins(ctx, accs[1].Address)) +// //delegatorBalance = app.CoinKeeper.GetCoins(ctx, accs[1].Address) +// //logger.Debug("delegatorBalance", "delegatorBalance", delegatorBalance) +// } diff --git a/asset/testnet/app.toml b/asset/testnet/app.toml index 441478382..948090568 100644 --- a/asset/testnet/app.toml +++ b/asset/testnet/app.toml @@ -76,6 +76,7 @@ BEP171Height = 37691120 BEP126Height = 38931600 # Block height of BEP255 upgrade BEP255Height = 41650000 +FirstSunsetHeight = 50121232 [query] # ABCI query interface black list, suggested value: ["custom/gov/proposals", "custom/timelock/timelocks", "custom/atomicSwap/swapcreator", "custom/atomicSwap/swaprecipient"] diff --git a/cmd/bnbcli/main.go b/cmd/bnbcli/main.go index f53d16aa1..6261d4f93 100644 --- a/cmd/bnbcli/main.go +++ b/cmd/bnbcli/main.go @@ -13,6 +13,7 @@ import ( sidecmd "github.com/cosmos/cosmos-sdk/x/sidechain/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" @@ -25,6 +26,8 @@ import ( apiserv "github.com/bnb-chain/node/plugins/api" bridgecmd "github.com/bnb-chain/node/plugins/bridge/client/cli" dexcmd "github.com/bnb-chain/node/plugins/dex/client/cli" + migratecmd "github.com/bnb-chain/node/plugins/migrate/client/cli" + recovercmd "github.com/bnb-chain/node/plugins/recover/client/cli" tokencmd "github.com/bnb-chain/node/plugins/tokens/client/cli" "github.com/bnb-chain/node/version" ) @@ -98,6 +101,8 @@ func main() { admin.AddCommands(rootCmd, cdc) bridgecmd.AddCommands(rootCmd, cdc) sidecmd.AddCommands(rootCmd, cdc) + recovercmd.AddCommands(rootCmd, cdc) + migratecmd.AddCommands(rootCmd, cdc) // prepare and add flags executor := cli.PrepareMainCmd(rootCmd, "BC", app.DefaultCLIHome) diff --git a/common/upgrade/upgrade.go b/common/upgrade/upgrade.go index d304e4c32..cb52b401c 100644 --- a/common/upgrade/upgrade.go +++ b/common/upgrade/upgrade.go @@ -49,7 +49,10 @@ const ( BEP171 = sdk.BEP171 // https://github.com/bnb-chain/BEPs/pull/171 Security Enhancement for Cross-Chain Module BEP173 = sdk.BEP173 // https://github.com/bnb-chain/BEPs/pull/173 Text Proposal FixDoubleSignChainId = sdk.FixDoubleSignChainId - BEP255 = sdk.BEP255 // https://github.com/bnb-chain/BEPs/pull/255 Asset Reconciliation for Security Enhancement + BEP255 = sdk.BEP255 // https://github.com/bnb-chain/BEPs/pull/255 Asset Reconciliation for Security Enhancement + FirstSunset = sdk.FirstSunsetFork // https://github.com/bnb-chain/BEPs/pull/333 BNB Chain Fusion + SecondSunset = sdk.SecondSunsetFork // https://github.com/bnb-chain/BEPs/pull/333 BNB Chain Fusion + FinalSunset = sdk.FinalSunsetFork // https://github.com/bnb-chain/BEPs/pull/333 BNB Chain Fusion ) func UpgradeBEP10(before func(), after func()) { diff --git a/common/utils/times.go b/common/utils/times.go index ba8d9f1ec..788fe200e 100644 --- a/common/utils/times.go +++ b/common/utils/times.go @@ -12,3 +12,7 @@ func Now() time.Time { func SameDayInUTC(first, second time.Time) bool { return first.Unix()/SecondsPerDay == second.Unix()/SecondsPerDay } + +func SamePeriodInUTC(first, second time.Time, period int64) bool { + return first.Unix()/period == second.Unix()/period +} diff --git a/go.mod b/go.mod index ebf902b3f..0fb951438 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/cosmos/cosmos-sdk v0.25.0 github.com/deathowl/go-metrics-prometheus v0.0.0-20200518174047-74482eab5bfb github.com/eapache/go-resiliency v1.1.0 + github.com/ethereum/go-ethereum v1.11.3 github.com/go-kit/kit v0.10.0 github.com/google/btree v1.0.0 github.com/gorilla/mux v1.8.0 @@ -48,7 +49,6 @@ require ( github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/etcd-io/bbolt v1.3.3 // indirect - github.com/ethereum/go-ethereum v1.11.3 // indirect github.com/ferranbt/fastssz v0.0.0-20210526181520-7df50c8568f8 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect @@ -165,7 +165,7 @@ require ( replace ( github.com/Shopify/sarama v1.26.1 => github.com/Shopify/sarama v1.21.0 - github.com/cosmos/cosmos-sdk => github.com/bnb-chain/bnc-cosmos-sdk v0.26.6 + github.com/cosmos/cosmos-sdk => github.com/bnb-chain/bnc-cosmos-sdk v0.26.7 github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tendermint/go-amino => github.com/bnb-chain/bnc-go-amino v0.14.1-binance.2 diff --git a/go.sum b/go.sum index df36bf095..df68f4090 100644 --- a/go.sum +++ b/go.sum @@ -178,8 +178,8 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/bnb-chain/bnc-cosmos-sdk v0.26.6 h1:5NrdUXplI2cqWZlLOovSqm+xO5ja03ZPCPT4bQqCD1Y= -github.com/bnb-chain/bnc-cosmos-sdk v0.26.6/go.mod h1:OjdXpDHofs6gcPLM9oGD+mm8DPc6Lsevz0Kia53zt3Q= +github.com/bnb-chain/bnc-cosmos-sdk v0.26.7 h1:6dnRDvX5Q31+uJSvw3OhK8zb5kUeEX+dWvw9XbR4IEg= +github.com/bnb-chain/bnc-cosmos-sdk v0.26.7/go.mod h1:OjdXpDHofs6gcPLM9oGD+mm8DPc6Lsevz0Kia53zt3Q= github.com/bnb-chain/bnc-go-amino v0.14.1-binance.2 h1:iAlp9gqG0f2LGAauf3ZiijWlT6NI+W2r9y70HH9LI3k= github.com/bnb-chain/bnc-go-amino v0.14.1-binance.2/go.mod h1:LiCO7jev+3HwLGAiN9gpD0z+jTz95RqgSavbse55XOY= github.com/bnb-chain/bnc-tendermint v0.32.3-bc.10 h1:E4iSwEbJCLYchHiHE1gnOM3jjmJXLBxARhy/RCl8CpI= diff --git a/plugins/dex/order/handler.go b/plugins/dex/order/handler.go index ac3ea9e22..a0d198696 100644 --- a/plugins/dex/order/handler.go +++ b/plugins/dex/order/handler.go @@ -104,6 +104,7 @@ func validateQtyAndLockBalance(ctx sdk.Context, keeper *DexKeeper, acc common.Na func handleNewOrder( ctx sdk.Context, dexKeeper *DexKeeper, msg NewOrderMsg, ) sdk.Result { + if _, ok := dexKeeper.OrderExists(msg.Symbol, msg.Id); ok { errString := fmt.Sprintf("Duplicated order [%v] on symbol [%v]", msg.Id, msg.Symbol) return sdk.NewError(types.DefaultCodespace, types.CodeDuplicatedOrder, errString).Result() diff --git a/plugins/migrate/client/cli/commands.go b/plugins/migrate/client/cli/commands.go new file mode 100644 index 000000000..0b98caf12 --- /dev/null +++ b/plugins/migrate/client/cli/commands.go @@ -0,0 +1,28 @@ +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) { + ownerShipCmd := &cobra.Command{ + Use: "validator-ownership", + Short: "validator-ownership commands", + Long: `validator-ownership commands is a tool to help BSC validator operator create a mapping signature to New Validator on BSC + # For example: + bnbcli validator-ownership sign-validator-ownership \ + --bsc-operator-address 0x45737bAf95D995a963ab3a7c9AC66fC7A63ad76E \ + --from bsc-operator \ + --chain-id Binance-Chain-Tigris`, + } + + ownerShipCmd.AddCommand( + client.PostCommands( + SignValidatorOwnerShipCmd(cdc), + )..., + ) + + cmd.AddCommand(ownerShipCmd) +} diff --git a/plugins/migrate/client/cli/tx.go b/plugins/migrate/client/cli/tx.go new file mode 100644 index 000000000..fb4c4fc25 --- /dev/null +++ b/plugins/migrate/client/cli/tx.go @@ -0,0 +1,94 @@ +package cli + +import ( + "encoding/hex" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/secp256k1" + + "github.com/bnb-chain/node/plugins/migrate" +) + +const ( + flagBSCOperatorAddress = "bsc-operator-address" +) + +func SignValidatorOwnerShipCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "sign-validator-ownership", + Short: "get validator ownership sign data", + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) + bscOperator := viper.GetString(flagBSCOperatorAddress) + + return SignAndPrint(cliCtx, txBldr, common.HexToAddress(bscOperator)) + }, + } + + cmd.Flags().String(flagBSCOperatorAddress, "", "bsc operator address") + + return cmd +} + +func SignAndPrint(ctx context.CLIContext, builder authtxb.TxBuilder, bscOperator common.Address) error { + name, err := ctx.GetFromName() + if err != nil { + return err + } + + passphrase, err := keys.GetPassphrase(name) + if err != nil { + return err + } + + msg := migrate.NewValidatorOwnerShipMsg(bscOperator) + + // build and sign the transaction + stdMsg, err := builder.Build([]sdk.Msg{msg}) + if err != nil { + return err + } + txBytes, err := builder.Sign(name, passphrase, stdMsg) + if err != nil { + return err + } + + var tx auth.StdTx + err = builder.Codec.UnmarshalBinaryLengthPrefixed(txBytes, &tx) + if err != nil { + return err + } + json, err := builder.Codec.MarshalJSON(tx) + if err != nil { + return err + } + + fmt.Printf("TX JSON: %s\n", json) + fmt.Println("Sign Message: ", string(stdMsg.Bytes())) + fmt.Println("Sign Message Hash: ", "0x"+hex.EncodeToString(crypto.Sha256(stdMsg.Bytes()))) + sig := tx.GetSignatures()[0] + fmt.Printf("Signature: %s\n", "0x"+hex.EncodeToString(sig.Signature)) + var originPubKey secp256k1.PubKeySecp256k1 + err = builder.Codec.UnmarshalBinaryBare(sig.PubKey.Bytes(), &originPubKey) + if err != nil { + return err + } + fmt.Printf("PubKey: %s\n", "0x"+hex.EncodeToString(originPubKey)) + return nil +} diff --git a/plugins/migrate/msg.go b/plugins/migrate/msg.go new file mode 100644 index 000000000..35c5e2067 --- /dev/null +++ b/plugins/migrate/msg.go @@ -0,0 +1,75 @@ +package migrate + +import ( + "encoding/json" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +const ( + Route = "recover" + MsgType = "validator_ownership" +) + +var _ sdk.Msg = ValidatorOwnerShip{} + +func NewValidatorOwnerShipMsg( + bscOperatorAddress common.Address, +) ValidatorOwnerShip { + return ValidatorOwnerShip{ + BSCOperatorAddress: bscOperatorAddress, + } +} + +func newValidatorOwnerShipSignData( + bscOperatorAddress common.Address) ValidatorOwnerShipSignData { + return ValidatorOwnerShipSignData{ + BSCOperatorAddress: strings.ToLower(bscOperatorAddress.Hex()), + } +} + +type ValidatorOwnerShipSignData struct { + BSCOperatorAddress string `json:"bsc_operator_address"` +} + +type ValidatorOwnerShip struct { + BSCOperatorAddress common.Address `json:"bsc_operator_address"` +} + +// GetInvolvedAddresses implements types.Msg. +func (msg ValidatorOwnerShip) GetInvolvedAddresses() []sdk.AccAddress { + return msg.GetSigners() +} + +// GetSignBytes implements types.Msg. +func (msg ValidatorOwnerShip) GetSignBytes() []byte { + b, err := json.Marshal(newValidatorOwnerShipSignData(msg.BSCOperatorAddress)) + if err != nil { + panic(err) + } + return b +} + +// GetSigners implements types.Msg. +func (m ValidatorOwnerShip) GetSigners() []sdk.AccAddress { + // This is not a real on-chain transaction + // We can get signer from the public key. + return []sdk.AccAddress{} +} + +// Route implements types.Msg. +func (ValidatorOwnerShip) Route() string { + return Route +} + +// Type implements types.Msg. +func (ValidatorOwnerShip) Type() string { + return MsgType +} + +// ValidateBasic implements types.Msg. +func (msg ValidatorOwnerShip) ValidateBasic() sdk.Error { + return nil +} diff --git a/plugins/migrate/wire.go b/plugins/migrate/wire.go new file mode 100644 index 000000000..58c35d972 --- /dev/null +++ b/plugins/migrate/wire.go @@ -0,0 +1,10 @@ +package migrate + +import ( + "github.com/bnb-chain/node/wire" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterConcrete(ValidatorOwnerShip{}, "migrate/ValidatorOwnerShip", nil) +} diff --git a/plugins/recover/client/cli/commands.go b/plugins/recover/client/cli/commands.go new file mode 100644 index 000000000..931b80ef0 --- /dev/null +++ b/plugins/recover/client/cli/commands.go @@ -0,0 +1,31 @@ +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) { + recoverCmd := &cobra.Command{ + Use: "recover", + Short: "recover commands", + Long: `recover commands is a tool for users to sign a request to recover their tokens from Binance Chain to Binance Smart Chain + # For example: + bnbcli recover sign-token-recover-request \ + --amount 19999999000000000 \ + --token-symbol BNB \ + --recipient 0x5b38da6a701c568545dcfcb03fcb875f56beddc4 \ + --from user1 \ + --chain-id Binance-Chain-Tigris + `, + } + + recoverCmd.AddCommand( + client.PostCommands( + SignTokenRecoverRequestCmd(cdc), + )..., + ) + + cmd.AddCommand(recoverCmd) +} diff --git a/plugins/recover/client/cli/tx.go b/plugins/recover/client/cli/tx.go new file mode 100644 index 000000000..d7a46eec3 --- /dev/null +++ b/plugins/recover/client/cli/tx.go @@ -0,0 +1,105 @@ +package cli + +import ( + "encoding/hex" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/secp256k1" + + airdrop "github.com/bnb-chain/node/plugins/recover" +) + +const ( + flagAmount = "amount" + flagTokenSymbol = "token-symbol" + flagRecipient = "recipient" +) + +func SignTokenRecoverRequestCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "sign-token-recover-request", + Short: "get token recover request sign data", + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) + + amount := viper.GetInt64(flagAmount) + tokenSymbol := viper.GetString(flagTokenSymbol) + recipient := viper.GetString(flagRecipient) + msg := airdrop.NewTokenRecoverRequestMsg(tokenSymbol, uint64(amount), strings.ToLower(common.HexToAddress(recipient).Hex())) + + sdkErr := msg.ValidateBasic() + if sdkErr != nil { + return fmt.Errorf("%v", sdkErr.Data()) + } + return SignAndPrint(cliCtx, txBldr, msg) + }, + } + + cmd.Flags().String(flagTokenSymbol, "", "owner token symbol") + cmd.Flags().Int64(flagAmount, 0, "amount of token") + cmd.Flags().String(flagRecipient, "", "bsc recipient address") + + return cmd +} + +func SignAndPrint(ctx context.CLIContext, builder authtxb.TxBuilder, msg sdk.Msg) error { + name, err := ctx.GetFromName() + if err != nil { + return err + } + + passphrase, err := keys.GetPassphrase(name) + if err != nil { + return err + } + + // build and sign the transaction + stdMsg, err := builder.Build([]sdk.Msg{msg}) + if err != nil { + return err + } + txBytes, err := builder.Sign(name, passphrase, stdMsg) + if err != nil { + return err + } + + var tx auth.StdTx + err = builder.Codec.UnmarshalBinaryLengthPrefixed(txBytes, &tx) + if err != nil { + return err + } + json, err := builder.Codec.MarshalJSON(tx) + if err != nil { + return err + } + + fmt.Printf("TX JSON: %s\n", json) + fmt.Println("Sign Message: ", string(stdMsg.Bytes())) + fmt.Println("Sign Message Hash: ", "0x"+hex.EncodeToString(crypto.Sha256(stdMsg.Bytes()))) + sig := tx.GetSignatures()[0] + fmt.Printf("Signature: %s\n", "0x"+hex.EncodeToString(sig.Signature)) + var originPubKey secp256k1.PubKeySecp256k1 + err = builder.Codec.UnmarshalBinaryBare(sig.PubKey.Bytes(), &originPubKey) + if err != nil { + return err + } + fmt.Printf("PubKey: %s\n", "0x"+hex.EncodeToString(originPubKey)) + return nil +} diff --git a/plugins/recover/msg.go b/plugins/recover/msg.go new file mode 100644 index 000000000..7c87b3b2f --- /dev/null +++ b/plugins/recover/msg.go @@ -0,0 +1,96 @@ +package recover + +import ( + "encoding/hex" + "encoding/json" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +const ( + Route = "recover" + MsgType = "request_token" +) + +var _ sdk.Msg = TokenRecoverRequest{} + +func NewTokenRecoverRequestMsg(tokenSymbol string, amount uint64, recipient string) TokenRecoverRequest { + return TokenRecoverRequest{ + TokenSymbol: tokenSymbol, + Amount: amount, + Recipient: recipient, + } +} + +func newTokenRecoverRequestSignData(tokenSymbol string, amount uint64, recipient string) tokenRecoverRequestSignData { + var tokenSymbolBytes [32]byte + copy(tokenSymbolBytes[:], []byte(tokenSymbol)) + + return tokenRecoverRequestSignData{ + TokenSymbol: hex.EncodeToString(tokenSymbolBytes[:]), + Amount: hex.EncodeToString(big.NewInt(int64(amount)).FillBytes(make([]byte, 32))), + Recipient: recipient, + } +} + +type tokenRecoverRequestSignData struct { + TokenSymbol string `json:"token_symbol"` // hex string(32 bytes) + Amount string `json:"amount"` // hex string(32 bytes) + Recipient string `json:"recipient"` // eth address(20 bytes) +} + +type TokenRecoverRequest struct { + TokenSymbol string `json:"token_symbol"` + Amount uint64 `json:"amount"` + Recipient string `json:"recipient"` // eth address +} + +// GetInvolvedAddresses implements types.Msg. +func (msg TokenRecoverRequest) GetInvolvedAddresses() []sdk.AccAddress { + return msg.GetSigners() +} + +// GetSignBytes implements types.Msg. +func (msg TokenRecoverRequest) GetSignBytes() []byte { + b, err := json.Marshal(newTokenRecoverRequestSignData(msg.TokenSymbol, msg.Amount, msg.Recipient)) + if err != nil { + panic(err) + } + return b +} + +// GetSigners implements types.Msg. +func (m TokenRecoverRequest) GetSigners() []sdk.AccAddress { + // This is not a real on-chain transaction + // We can get signer from the public key. + return []sdk.AccAddress{} +} + +// Route implements types.Msg. +func (TokenRecoverRequest) Route() string { + return Route +} + +// Type implements types.Msg. +func (TokenRecoverRequest) Type() string { + return MsgType +} + +// ValidateBasic implements types.Msg. +func (msg TokenRecoverRequest) ValidateBasic() sdk.Error { + if msg.TokenSymbol == "" { + return sdk.ErrUnknownRequest("Invalid token symbol") + } + + if msg.Amount == 0 { + return sdk.ErrUnknownRequest("Invalid amount, should be greater than 0") + } + + if !common.IsHexAddress(msg.Recipient) { + return sdk.ErrInvalidAddress("Invalid recipient address") + } + + return nil +} diff --git a/plugins/recover/wire.go b/plugins/recover/wire.go new file mode 100644 index 000000000..0624360a5 --- /dev/null +++ b/plugins/recover/wire.go @@ -0,0 +1,10 @@ +package recover + +import ( + "github.com/bnb-chain/node/wire" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterConcrete(TokenRecoverRequest{}, "recover/TokenRecoverRequest", nil) +} diff --git a/plugins/tokens/freeze/handler.go b/plugins/tokens/freeze/handler.go index 70a3fb952..b6cabb117 100644 --- a/plugins/tokens/freeze/handler.go +++ b/plugins/tokens/freeze/handler.go @@ -19,6 +19,9 @@ func NewHandler(tokenMapper store.Mapper, accKeeper auth.AccountKeeper, keeper b return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case FreezeMsg: + if sdk.IsUpgrade(sdk.FirstSunsetFork) { + return sdk.ErrMsgNotSupported("").Result() + } return handleFreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) case UnfreezeMsg: return handleUnfreezeToken(ctx, tokenMapper, accKeeper, keeper, msg) diff --git a/plugins/tokens/issue/handler.go b/plugins/tokens/issue/handler.go index db8fa3d04..82ef70444 100644 --- a/plugins/tokens/issue/handler.go +++ b/plugins/tokens/issue/handler.go @@ -21,6 +21,9 @@ import ( // NewHandler creates a new token issue message handler func NewHandler(tokenMapper store.Mapper, keeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + if sdk.IsUpgrade(sdk.FirstSunsetFork) { + return sdk.ErrMsgNotSupported("").Result() + } switch msg := msg.(type) { case IssueMsg: return handleIssueToken(ctx, tokenMapper, keeper, msg) @@ -62,7 +65,7 @@ func handleIssueToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank return issue(ctx, logger, tokenMapper, bankKeeper, token) } -//Mint MiniToken is also handled by this function +// Mint MiniToken is also handled by this function func handleMintToken(ctx sdk.Context, tokenMapper store.Mapper, bankKeeper bank.Keeper, msg MintMsg) sdk.Result { symbol := strings.ToUpper(msg.Symbol) logger := log.With("module", "token", "symbol", symbol, "amount", msg.Amount, "minter", msg.From) diff --git a/plugins/tokens/plugin.go b/plugins/tokens/plugin.go index a19acd0aa..fd9c14398 100644 --- a/plugins/tokens/plugin.go +++ b/plugins/tokens/plugin.go @@ -51,6 +51,76 @@ func createQueryHandler(mapper Mapper, queryPrefix string) app.AbciQueryHandler return createAbciQueryHandler(mapper, queryPrefix) } +const ( + MaxUnlockItems = 10 +) + +func EndBlocker(ctx sdk.Context, timelockKeeper timelock.Keeper, swapKeeper swap.Keeper) { + if !sdk.IsUpgrade(sdk.SecondSunsetFork) { + return + } + logger := bnclog.With("module", "tokens") + logger.Info("unlock the time locks", "blockHeight", ctx.BlockHeight()) + + iterator := timelockKeeper.GetTimeLockRecordIterator(ctx) + defer iterator.Close() + i := 0 + failedCount := 0 + for ; iterator.Valid(); iterator.Next() { + addr, id, err := timelock.ParseKeyRecord(iterator.Key()) + if err != nil { + logger.Error("failed to parse timelock record", "error", err) + failedCount++ + continue + } + err = timelockKeeper.TimeUnlock(ctx, addr, id, true) + if err != nil { + logger.Error("failed to unlock the time locks", "error", err) + failedCount++ + continue + } + logger.Info("succeed to unlock the time locks", "addr", addr, "id", id) + i++ + if i >= MaxUnlockItems { + break + } + } + logger.Info("unlock the time locks done", "blockHeight", ctx.BlockHeight(), "succeed", i, "failed", failedCount) + + swapIterator := swapKeeper.GetSwapIterator(ctx) + defer swapIterator.Close() + i = 0 + failedCount = 0 + for ; swapIterator.Valid(); swapIterator.Next() { + var automaticSwap swap.AtomicSwap + swapKeeper.CDC().MustUnmarshalBinaryBare(swapIterator.Value(), &automaticSwap) + swapID := swapIterator.Key()[len(swap.HashKey):] + swapItem := swapKeeper.GetSwap(ctx, swapID) + if swapItem == nil { + continue + } + if swapItem.Status != swap.Open { + continue + } + result := swap.HandleRefundHashTimerLockedTransferAfterBCFusion(ctx, swapKeeper, swap.RefundHTLTMsg{ + From: automaticSwap.From, + SwapID: swapID, + }) + if !result.IsOK() { + logger.Error("failed to refund swap", "swapId", swapID, "result", fmt.Sprintf("%+v", result)) + failedCount++ + continue + } + + logger.Info("succeed to refund swap", "swapId", swapID, "swap", fmt.Sprintf("%+v", swapItem)) + i++ + if i >= MaxUnlockItems { + break + } + } + logger.Info("refund the swaps done", "blockHeight", ctx.BlockHeight(), "succeed", i, "failed", failedCount) +} + // EndBreatheBlock processes the breathe block lifecycle event. func EndBreatheBlock(ctx sdk.Context, swapKeeper swap.Keeper) { logger := bnclog.With("module", "tokens") diff --git a/plugins/tokens/swap/handler.go b/plugins/tokens/swap/handler.go index 4c740500f..4ac933448 100644 --- a/plugins/tokens/swap/handler.go +++ b/plugins/tokens/swap/handler.go @@ -12,13 +12,19 @@ func NewHandler(kp Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case HTLTMsg: + if sdk.IsUpgrade(sdk.FirstSunsetFork) { + return sdk.ErrMsgNotSupported("").Result() + } return handleHashTimerLockedTransfer(ctx, kp, msg) case DepositHTLTMsg: + if sdk.IsUpgrade(sdk.FirstSunsetFork) { + return sdk.ErrMsgNotSupported("").Result() + } return handleDepositHashTimerLockedTransfer(ctx, kp, msg) case ClaimHTLTMsg: return handleClaimHashTimerLockedTransfer(ctx, kp, msg) case RefundHTLTMsg: - return handleRefundHashTimerLockedTransfer(ctx, kp, msg) + return handleRefundHashTimerLockedTransfer(ctx, kp, msg, false) default: errMsg := fmt.Sprintf("unrecognized message type: %T", msg) return sdk.ErrUnknownRequest(errMsg).Result() @@ -158,7 +164,11 @@ func handleClaimHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg ClaimHTL return sdk.Result{Tags: tags} } -func handleRefundHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg RefundHTLTMsg) sdk.Result { +func HandleRefundHashTimerLockedTransferAfterBCFusion(ctx sdk.Context, kp Keeper, msg RefundHTLTMsg) sdk.Result { + return handleRefundHashTimerLockedTransfer(ctx, kp, msg, true) +} + +func handleRefundHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg RefundHTLTMsg, isBCFusionRefund bool) sdk.Result { swap := kp.GetSwap(ctx, msg.SwapID) if swap == nil { return ErrNonExistSwapID(fmt.Sprintf("No matched swap with swapID %v", msg.SwapID)).Result() @@ -166,8 +176,10 @@ func handleRefundHashTimerLockedTransfer(ctx sdk.Context, kp Keeper, msg RefundH if swap.Status != Open { return ErrUnexpectedSwapStatus(fmt.Sprintf("Expected swap status is Open, actually it is %s", swap.Status.String())).Result() } - if ctx.BlockHeight() < swap.ExpireHeight { - return ErrRefundUnexpiredSwap(fmt.Sprintf("Current block height is %d, the expire height (%d) is still not reached", ctx.BlockHeight(), swap.ExpireHeight)).Result() + if !isBCFusionRefund { + if ctx.BlockHeight() < swap.ExpireHeight { + return ErrRefundUnexpiredSwap(fmt.Sprintf("Current block height is %d, the expire height (%d) is still not reached", ctx.BlockHeight(), swap.ExpireHeight)).Result() + } } tags := sdk.EmptyTags() diff --git a/plugins/tokens/swap/keeper.go b/plugins/tokens/swap/keeper.go index e781af106..060f77473 100644 --- a/plugins/tokens/swap/keeper.go +++ b/plugins/tokens/swap/keeper.go @@ -41,6 +41,10 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck bank.Keeper, addrPool *sdk } } +func (keeper Keeper) CDC() *codec.Codec { + return keeper.cdc +} + func (kp *Keeper) CreateSwap(ctx sdk.Context, swapID SwapBytes, swap *AtomicSwap) sdk.Error { if swap == nil { return sdk.ErrInternal("empty atomic swap pointer") @@ -137,6 +141,11 @@ func (kp *Keeper) GetSwap(ctx sdk.Context, swapID SwapBytes) *AtomicSwap { return &swap } +func (kp *Keeper) GetSwapIterator(ctx sdk.Context) (iterator store.Iterator) { + kvStore := ctx.KVStore(kp.storeKey) + return sdk.KVStorePrefixIterator(kvStore, HashKey) +} + func (kp *Keeper) GetSwapCreatorIterator(ctx sdk.Context, addr sdk.AccAddress) (iterator store.Iterator) { kvStore := ctx.KVStore(kp.storeKey) return sdk.KVStorePrefixIterator(kvStore, BuildSwapCreatorQueueKey(addr)) diff --git a/plugins/tokens/timelock/handler.go b/plugins/tokens/timelock/handler.go index 5be0fca45..ee03c8f4c 100644 --- a/plugins/tokens/timelock/handler.go +++ b/plugins/tokens/timelock/handler.go @@ -11,10 +11,16 @@ func NewHandler(keeper Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case TimeLockMsg: + if sdk.IsUpgrade(sdk.FirstSunsetFork) { + return sdk.ErrMsgNotSupported("").Result() + } return handleTimeLock(ctx, keeper, msg) case TimeUnlockMsg: return handleTimeUnlock(ctx, keeper, msg) case TimeRelockMsg: + if sdk.IsUpgrade(sdk.FirstSunsetFork) { + return sdk.ErrMsgNotSupported("").Result() + } return handleTimeRelock(ctx, keeper, msg) default: errMsg := fmt.Sprintf("unrecognized time lock message type: %T", msg) @@ -54,7 +60,7 @@ func handleTimeRelock(ctx sdk.Context, keeper Keeper, msg TimeRelockMsg) sdk.Res } func handleTimeUnlock(ctx sdk.Context, keeper Keeper, msg TimeUnlockMsg) sdk.Result { - err := keeper.TimeUnlock(ctx, msg.From, msg.Id) + err := keeper.TimeUnlock(ctx, msg.From, msg.Id, false) if err != nil { return err.Result() } diff --git a/plugins/tokens/timelock/keeper.go b/plugins/tokens/timelock/keeper.go index 17b33b2e3..260ddc4a5 100644 --- a/plugins/tokens/timelock/keeper.go +++ b/plugins/tokens/timelock/keeper.go @@ -6,6 +6,7 @@ import ( "time" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" @@ -88,6 +89,11 @@ func (keeper Keeper) GetTimeLockRecords(ctx sdk.Context, addr sdk.AccAddress) [] return records } +func (kp *Keeper) GetTimeLockRecordIterator(ctx sdk.Context) (iterator store.Iterator) { + kvStore := ctx.KVStore(kp.storeKey) + return sdk.KVStorePrefixIterator(kvStore, []byte{}) +} + func (keeper Keeper) getTimeLockId(ctx sdk.Context, from sdk.AccAddress) int64 { acc := keeper.ak.GetAccount(ctx, from) return acc.GetSequence() @@ -121,13 +127,13 @@ func (keeper Keeper) TimeLock(ctx sdk.Context, from sdk.AccAddress, description return record, nil } -func (keeper Keeper) TimeUnlock(ctx sdk.Context, from sdk.AccAddress, recordId int64) sdk.Error { +func (keeper Keeper) TimeUnlock(ctx sdk.Context, from sdk.AccAddress, recordId int64, isBCFusionRefund bool) sdk.Error { record, found := keeper.GetTimeLockRecord(ctx, from, recordId) if !found { return ErrTimeLockRecordDoesNotExist(DefaultCodespace, from, recordId) } - if ctx.BlockHeader().Time.Before(record.LockTime) { + if !isBCFusionRefund && ctx.BlockHeader().Time.Before(record.LockTime) { return ErrCanNotUnlock(DefaultCodespace, fmt.Sprintf("lock time(%s) is after now(%s)", record.LockTime.UTC().String(), ctx.BlockHeader().Time.UTC().String())) } diff --git a/plugins/tokens/timelock/keeper_test.go b/plugins/tokens/timelock/keeper_test.go index a973eed04..4f53c8fce 100644 --- a/plugins/tokens/timelock/keeper_test.go +++ b/plugins/tokens/timelock/keeper_test.go @@ -142,7 +142,7 @@ func TestKeeper_TimeUnlock_RecordNotExist(t *testing.T) { _, acc := testutils.NewAccount(ctx, accKeeper, 0) - err := keeper.TimeUnlock(ctx, acc.GetAddress(), 1) + err := keeper.TimeUnlock(ctx, acc.GetAddress(), 1, false) require.NotNil(t, err) require.Equal(t, err.Code(), CodeTimeLockRecordDoesNotExist) } @@ -169,7 +169,7 @@ func TestKeeper_TimeUnlock_ErrLockTime(t *testing.T) { record, err := keeper.TimeLock(ctx, acc.GetAddress(), "Test", lockCoins, time.Now().Add(1000*time.Second)) require.Nil(t, err) - err = keeper.TimeUnlock(ctx, acc.GetAddress(), record.Id) + err = keeper.TimeUnlock(ctx, acc.GetAddress(), record.Id, false) require.NotNil(t, err) require.Equal(t, err.Code(), CodeCanNotUnlock) } @@ -197,7 +197,7 @@ func TestKeeper_TimeUnlock_Success(t *testing.T) { require.Nil(t, err) ctx = ctx.WithBlockTime(time.Now().Add(2000 * time.Second)) - err = keeper.TimeUnlock(ctx, acc.GetAddress(), record.Id) + err = keeper.TimeUnlock(ctx, acc.GetAddress(), record.Id, false) require.Nil(t, err) } diff --git a/plugins/tokens/timelock/keys.go b/plugins/tokens/timelock/keys.go index 0b55b4968..dd306a60b 100644 --- a/plugins/tokens/timelock/keys.go +++ b/plugins/tokens/timelock/keys.go @@ -1,7 +1,10 @@ package timelock import ( + "bytes" + "encoding/hex" "fmt" + "strconv" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,3 +16,19 @@ func KeyRecord(addr sdk.AccAddress, id int64) []byte { func KeyRecordSubSpace(addr sdk.AccAddress) []byte { return []byte(fmt.Sprintf("record:%d", addr)) } + +func ParseKeyRecord(key []byte) (sdk.AccAddress, int64, error) { + key = bytes.TrimPrefix(key, []byte("record:")) + accKeyStr := key[:sdk.AddrLen*2] + accKeyBytes, err := hex.DecodeString(string(accKeyStr)) + if err != nil { + return []byte{}, 0, err + } + addr := sdk.AccAddress(accKeyBytes) + + id, err := strconv.ParseInt(string(key[sdk.AddrLen*2+1:]), 10, 64) + if err != nil { + return []byte{}, 0, err + } + return addr, id, nil +} diff --git a/plugins/tokens/timelock/keys_test.go b/plugins/tokens/timelock/keys_test.go new file mode 100644 index 000000000..146ac5bf3 --- /dev/null +++ b/plugins/tokens/timelock/keys_test.go @@ -0,0 +1,32 @@ +package timelock + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestParseKeyRecord(t *testing.T) { + account, err := sdk.AccAddressFromHex("5B38Da6a701c568545dCfcB03FcB875f56beddC4") + if err != nil { + t.Fatal(err) + return + } + accId := int64(1513) + key := KeyRecord(account, accId) + + acc, id, err := ParseKeyRecord([]byte(key)) + if err != nil { + t.Fatal(err) + return + } + + if !acc.Equals(account) { + t.Fatal("parse account error") + return + } + if id != accId { + t.Fatal("parse id error") + return + } +} diff --git a/scripts/bep159_cli_integration_test.sh b/scripts/bep159_cli_integration_test.sh index 54e73c76c..06a132d40 100755 --- a/scripts/bep159_cli_integration_test.sh +++ b/scripts/bep159_cli_integration_test.sh @@ -45,7 +45,7 @@ function prepare_node() { $(cd "./${home}/config" && sed -i -e "s/BEP153Height = 9223372036854775807/BEP153Height = 2/g" app.toml) $(cd "./${home}/config" && sed -i -e "s/BEP159Height = 9223372036854775807/BEP159Height = 3/g" app.toml) $(cd "./${home}/config" && sed -i -e "s/BEP159Phase2Height = 9223372036854775807/BEP159Phase2Height = 11/g" app.toml) - $(cd "./${home}/config" && sed -i -e "s/breatheBlockInterval = 0/breatheBlockInterval = 5/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/breatheBlockInterval = 0/breatheBlockInterval = 3/g" app.toml) # stop and start node ps -ef | grep bnbchaind | grep testnoded | awk '{print $2}' | xargs kill -9 diff --git a/scripts/bep159_integration_test.sh b/scripts/bep159_integration_test.sh index 8496e9a8f..c72d9637c 100755 --- a/scripts/bep159_integration_test.sh +++ b/scripts/bep159_integration_test.sh @@ -46,7 +46,7 @@ function prepare_node() { $(cd "./${home}/config" && sed -i -e "s/BEP159Height = 9223372036854775807/BEP159Height = 3/g" app.toml) $(cd "./${home}/config" && sed -i -e "s/BEP159Phase2Height = 9223372036854775807/BEP159Phase2Height = 11/g" app.toml) $(cd "./${home}/config" && sed -i -e "s/LimitConsAddrUpdateIntervalHeight = 9223372036854775807/LimitConsAddrUpdateIntervalHeight = 11/g" app.toml) - $(cd "./${home}/config" && sed -i -e "s/breatheBlockInterval = 0/breatheBlockInterval = 5/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/breatheBlockInterval = 0/breatheBlockInterval = 3/g" app.toml) # $(cd "./${home}/config" && sed -i -e "s/publishStaking = false/publishStaking = true/g" app.toml) # $(cd "./${home}/config" && sed -i -e "s/publishKafka = false/publishKafka = true/g" app.toml) # $(cd "./${home}/config" && sed -i -e "s/publishLocal = false/publishLocal = true/g" app.toml) diff --git a/scripts/recon_integration_test.sh b/scripts/recon_integration_test.sh index d8978bf2a..f7e2f2a42 100644 --- a/scripts/recon_integration_test.sh +++ b/scripts/recon_integration_test.sh @@ -46,7 +46,7 @@ function prepare_node() { $(cd "./${home}/config" && sed -i -e "s/BEP159Height = 9223372036854775807/BEP159Height = 3/g" app.toml) $(cd "./${home}/config" && sed -i -e "s/BEP159Phase2Height = 9223372036854775807/BEP159Phase2Height = 11/g" app.toml) $(cd "./${home}/config" && sed -i -e "s/LimitConsAddrUpdateIntervalHeight = 9223372036854775807/LimitConsAddrUpdateIntervalHeight = 11/g" app.toml) - $(cd "./${home}/config" && sed -i -e "s/breatheBlockInterval = 0/breatheBlockInterval = 5/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/breatheBlockInterval = 0/breatheBlockInterval = 3/g" app.toml) $(cd "./${home}/config" && sed -i -e "s/BEP255Height = 9223372036854775807/BEP255Height = 3/g" app.toml) # stop and start node