diff --git a/.dockerignore b/.dockerignore index 22d0d82f8..181546de8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,2 @@ vendor +build diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index f99a6f8f8..07b1b5700 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.16 + go-version: 1.17 - uses: actions/checkout@v3 - uses: actions/cache@v2 with: @@ -25,7 +25,5 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - run: git config --global url."https://${{ secrets.GH_ACCESS_TOKEN }}@github.com".insteadOf "https://github.com" - - run: go env -w GOPRIVATE="github.com/bnb-chain/*" - name: golangci-lint run: make lint diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ad1f00d3e..edac58c99 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -5,16 +5,12 @@ on: ["push", "pull_request", "workflow_dispatch"] jobs: integration-test: runs-on: ubuntu-latest - env: - GH_ACCESS_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }} steps: - uses: actions/checkout@v3 - name: Setup go uses: actions/setup-go@v3 with: - go-version: 1.16 - - name: Checkout - uses: actions/checkout@v2 + go-version: 1.17 - uses: actions/cache@v2 with: path: ~/go/bin @@ -28,10 +24,31 @@ jobs: restore-keys: | ${{ runner.os }}-go- - run: sudo apt-get update -y && sudo apt-get install -y expect - - run: git config --global url."https://${{ secrets.GH_ACCESS_TOKEN }}@github.com".insteadOf "https://github.com" - - run: go env -w GOPRIVATE="github.com/bnb-chain/*" # used to debug workflow # - name: Setup tmate session # uses: mxschmitt/action-tmate@v3 - - run: make integration_test + - run: make bep159_integration_test integration_test + coverage-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup go + uses: actions/setup-go@v3 + with: + go-version: 1.17 + - uses: actions/cache@v2 + with: + path: ~/go/bin + key: tools-v0 + - uses: actions/cache@v2 + with: + path: | + ~/go/pkg/mod + ~/.cache/go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- - run: make test + - run: make test_coverage + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 diff --git a/.github/workflows/multi-nodes-test.yml b/.github/workflows/multi-nodes-test.yml new file mode 100644 index 000000000..ffe8ba319 --- /dev/null +++ b/.github/workflows/multi-nodes-test.yml @@ -0,0 +1,21 @@ +name: multi-nodes-test + +on: ["push", "pull_request", "workflow_dispatch"] + +jobs: + multi-nodes-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup go + uses: actions/setup-go@v3 + with: + go-version: 1.17 + - run: make docker.build docker.generate docker.start + # fix docker permission issue + - run: chmod 777 -R ~/work/node/node/build/devnet + - run: sleep 20 + # used to debug workflow +# - name: Setup tmate session +# uses: mxschmitt/action-tmate@v3 + - run: make multi-nodes-test diff --git a/Makefile b/Makefile index 0fb92b4fa..5a8e6374e 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,7 @@ install_c: format: @echo "-->Formatting" $(shell go fmt ./...) - $(shell find . -name "*.go" | grep -v "vendor/" | xargs -n 1 goimports -w) + bash scripts/importssort.sh ######################################## ### Lint @@ -194,13 +194,20 @@ test_unit: @echo "--> Running go test" @go test $(PACKAGES) +test_coverage: + @echo "--> Running go test" + @go test $(PACKAGES) -race -coverprofile=coverage.txt -covermode=atomic + integration_test: build @echo "-->Integration Test" @./integration_test.sh +bep159_integration_test: build + @echo "-->BEP159 Integration Test" + @bash ./scripts/bep159_integration_test.sh ######################################## ### Pre Commit -pre_commit: build test format lint +pre_commit: build test_unit bep159_integration_test integration_test format lint multi-nodes-test ######################################## ### Local validator nodes using docker and docker-compose @@ -230,6 +237,25 @@ localnet-start: localnet-stop localnet-stop: docker-compose down +# docker commands +docker.build: + docker build -t binance/bnbdnode . + +docker.generate: + go run ./cmd/gen_devnet + +docker.start: + docker compose -f build/devnet/docker-compose.yml up -d + +docker.stop: + docker compose -f build/devnet/docker-compose.yml down + +docker.clean: + rm -rf build/devnet + +multi-nodes-test: + STAKE_ENV=multi go run ./cmd/test_client + # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html diff --git a/app/app.go b/app/app.go index e65e5b601..d5ecde986 100644 --- a/app/app.go +++ b/app/app.go @@ -30,7 +30,6 @@ import ( cStake "github.com/cosmos/cosmos-sdk/x/stake/cross_stake" "github.com/cosmos/cosmos-sdk/x/stake/keeper" sTypes "github.com/cosmos/cosmos-sdk/x/stake/types" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/tmhash" cmn "github.com/tendermint/tendermint/libs/common" @@ -335,6 +334,8 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { upgrade.Mgr.AddUpgradeHeight(upgrade.BEP128, upgradeConfig.BEP128Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP151, upgradeConfig.BEP151Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP153, upgradeConfig.BEP153Height) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP159, upgradeConfig.BEP159Height) + upgrade.Mgr.AddUpgradeHeight(upgrade.BEP159Phase2, upgradeConfig.BEP159Phase2Height) upgrade.Mgr.AddUpgradeHeight(upgrade.BEP173, upgradeConfig.BEP173Height) // register store keys of upgrade @@ -373,6 +374,13 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) { bridge.TransferOutMsg{}.Type(), oracle.ClaimMsg{}.Type(), ) + upgrade.Mgr.RegisterMsgTypes(upgrade.BEP159, + stake.MsgCreateValidatorOpen{}.Type(), + stake.MsgEditValidator{}.Type(), + stake.MsgDelegate{}.Type(), + stake.MsgUndelegate{}.Type(), + slashing.MsgUnjail{}.Type(), + ) // register msg types of upgrade upgrade.Mgr.RegisterMsgTypes(upgrade.BEP8, issue.IssueMiniMsg{}.Type(), @@ -558,16 +566,24 @@ func (app *BinanceChain) initStaking() { panic(err) } }) - - if sdk.IsUpgrade(sdk.BEP153) { - crossStakeApp := cStake.NewCrossStakeApp(app.stakeKeeper) - err := app.scKeeper.RegisterChannel(sTypes.CrossStakeChannel, sTypes.CrossStakeChannelID, crossStakeApp) - if err != nil { - panic(err) - } - } - + upgrade.Mgr.RegisterBeginBlocker(sdk.BEP159, func(ctx sdk.Context) { + stake.MigrateValidatorDistributionAddr(ctx, app.stakeKeeper) + params := app.stakeKeeper.GetParams(ctx) + params.RewardDistributionBatchSize = 1000 + params.MinSelfDelegation = 20000e8 + params.MinDelegationChange = 1e8 + params.MaxStakeSnapshots = 30 + params.MaxValidators = 11 + params.BaseProposerRewardRatio = sdk.NewDec(1e6) // 1% + params.BonusProposerRewardRatio = sdk.NewDec(4e6) // 4% + params.FeeFromBscToBcRatio = sdk.NewDec(1e7) // 10% + app.stakeKeeper.SetParams(ctx, params) + }) + upgrade.Mgr.RegisterBeginBlocker(sdk.BEP159Phase2, func(ctx sdk.Context) { + stake.MigrateWhiteLabelOracleRelayer(ctx, app.stakeKeeper) + }) app.stakeKeeper.SubscribeParamChange(app.ParamHub) + app.stakeKeeper.SubscribeBCParamChange(app.ParamHub) app.stakeKeeper = app.stakeKeeper.WithHooks(app.slashKeeper.Hooks()) } @@ -611,6 +627,19 @@ func (app *BinanceChain) initSlashing() { DowntimeSlashFee: 10e8, }) }) + upgrade.Mgr.RegisterBeginBlocker(sdk.BEP159, func(ctx sdk.Context) { + // write slash params to beacon chain when upgrade to BEP159 + app.slashKeeper.SetParams(ctx, 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() { @@ -644,6 +673,8 @@ func (app *BinanceChain) initGovHooks() { app.govKeeper.AddHooks(gov.ProposalTypeSCParamsChange, scParamChangeHooks) app.govKeeper.AddHooks(gov.ProposalTypeDelistTradingPair, delistHooks) app.govKeeper.AddHooks(gov.ProposalTypeManageChanPermission, chanPermissionHooks) + bcParamChangeHooks := paramHub.NewBCParamsChangeHook(app.Codec) + app.govKeeper.AddHooks(gov.ProposalTypeParameterChange, bcParamChangeHooks) } func (app *BinanceChain) initParams() { @@ -847,7 +878,12 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a app.DexKeeper.StoreTradePrices(ctx) - blockFee := distributeFee(ctx, app.AccountKeeper, app.ValAddrCache, app.publicationConfig.PublishBlockFee) + var blockFee pub.BlockFee + if sdk.IsUpgrade(upgrade.BEP159) { + blockFee = distributeFeeBEP159(ctx, app.AccountKeeper, app.ValAddrCache, app.publicationConfig.PublishBlockFee, app.stakeKeeper) + } else { + blockFee = distributeFee(ctx, app.AccountKeeper, app.ValAddrCache, app.publicationConfig.PublishBlockFee) + } passed, failed := gov.EndBlocker(ctx, app.govKeeper) var proposals pub.Proposals @@ -859,6 +895,7 @@ func (app *BinanceChain) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a sidechain.EndBlock(ctx, app.scKeeper) var completedUbd []stake.UnbondingDelegation var validatorUpdates abci.ValidatorUpdates + // todo: get validatorUpdates in slashing EndBlocker if isBreatheBlock { validatorUpdates, completedUbd = stake.EndBreatheBlock(ctx, app.stakeKeeper) } else if ctx.RouterCallRecord()["stake"] || sdk.IsUpgrade(upgrade.BEP128) { diff --git a/app/app_paramhub_test.go b/app/app_paramhub_test.go index 001f3bf3c..7cdc28942 100644 --- a/app/app_paramhub_test.go +++ b/app/app_paramhub_test.go @@ -9,22 +9,6 @@ import ( "testing" "time" - "github.com/bnb-chain/node/common/upgrade" - - "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" @@ -39,8 +23,21 @@ import ( sTypes "github.com/cosmos/cosmos-sdk/x/sidechain/types" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" + "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" ctypes "github.com/bnb-chain/node/common/types" + "github.com/bnb-chain/node/common/upgrade" "github.com/bnb-chain/node/plugins/dex" "github.com/bnb-chain/node/plugins/tokens" "github.com/bnb-chain/node/wire" @@ -49,7 +46,7 @@ import ( // util objects var ( memDB = dbm.NewMemDB() - logger = log.NewTMLogger(os.Stdout) + logger = log.NewTMLogger(log.NewSyncWriter(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","reward_distribution_batch_size":"1000"}},{"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"}}]` diff --git a/app/config/config.go b/app/config/config.go index e1727c6bc..9d6930210 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -7,9 +7,7 @@ import ( "text/template" "github.com/cosmos/cosmos-sdk/server" - "github.com/spf13/viper" - "github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/libs/common" ) @@ -91,6 +89,10 @@ BEP128Height = {{ .UpgradeConfig.BEP128Height }} BEP151Height = {{ .UpgradeConfig.BEP151Height }} # Block height of BEP153 upgrade BEP153Height = {{ .UpgradeConfig.BEP153Height }} +# Block height of BEP159 upgrade +BEP159Height = {{ .UpgradeConfig.BEP159Height }} +# Block height of BEP159Phase2 upgrade +BEP159Phase2Height = {{ .UpgradeConfig.BEP159Phase2Height }} # Block height of BEP173 upgrade BEP173Height = {{ .UpgradeConfig.BEP173Height }} @@ -534,6 +536,8 @@ type UpgradeConfig struct { BEP128Height int64 `mapstructure:"BEP128Height"` BEP151Height int64 `mapstructure:"BEP151Height"` BEP153Height int64 `mapstructure:"BEP153Height"` + BEP159Height int64 `mapstructure:"BEP159Height"` + BEP159Phase2Height int64 `mapstructure:"BEP159Phase2Height"` BEP173Height int64 `mapstructure:"BEP173Height"` } @@ -557,6 +561,8 @@ func defaultUpgradeConfig() *UpgradeConfig { BEP128Height: math.MaxInt64, BEP151Height: math.MaxInt64, BEP153Height: math.MaxInt64, + BEP159Height: math.MaxInt64, + BEP159Phase2Height: math.MaxInt64, BEP173Height: math.MaxInt64, BEP82Height: math.MaxInt64, BEP84Height: math.MaxInt64, diff --git a/app/fee_distribution.go b/app/fee_distribution.go index b5c59bae5..705bb721e 100644 --- a/app/fee_distribution.go +++ b/app/fee_distribution.go @@ -15,20 +15,23 @@ import ( func NewValAddrCache(stakeKeeper stake.Keeper) *ValAddrCache { cache := &ValAddrCache{ - cache: make(map[string]sdk.AccAddress), - stakeKeeper: stakeKeeper, + cache: make(map[string]sdk.AccAddress), + distributionAddrCache: make(map[string]sdk.AccAddress), + stakeKeeper: stakeKeeper, } return cache } type ValAddrCache struct { - cache map[string]sdk.AccAddress - stakeKeeper stake.Keeper + cache map[string]sdk.AccAddress + distributionAddrCache map[string]sdk.AccAddress + stakeKeeper stake.Keeper } func (vac *ValAddrCache) ClearCache() { vac.cache = make(map[string]sdk.AccAddress) + vac.distributionAddrCache = make(map[string]sdk.AccAddress) } func (vac *ValAddrCache) SetAccAddr(consAddr sdk.ConsAddress, accAddr sdk.AccAddress) { @@ -48,6 +51,90 @@ func (vac *ValAddrCache) GetAccAddr(ctx sdk.Context, consAddr sdk.ConsAddress) s return accAddr } +func (vac *ValAddrCache) SetDistributionAddr(consAddr sdk.ConsAddress, accAddr sdk.AccAddress) { + vac.distributionAddrCache[string(consAddr)] = accAddr +} + +func (vac *ValAddrCache) GetDistributionAddr(ctx sdk.Context, consAddr sdk.ConsAddress) sdk.AccAddress { + if value, ok := vac.distributionAddrCache[string(consAddr)]; ok { + return value + } + validator, found := vac.stakeKeeper.GetValidatorByConsAddr(ctx, consAddr) + if !found { + panic(fmt.Errorf("can't load validator with consensus address %s", consAddr.String())) + } + distributionAddr := validator.DistributionAddr + vac.SetDistributionAddr(consAddr, distributionAddr) + return distributionAddr +} + +func distributeFeeBEP159(ctx sdk.Context, am auth.AccountKeeper, valAddrCache *ValAddrCache, publishBlockFee bool, stakeKeeper stake.Keeper) (blockFee pub.BlockFee) { + blockFee = pub.BlockFee{Height: ctx.BlockHeader().Height} + prevBlockFee := stakeKeeper.BankKeeper.GetCoins(ctx, stake.FeeCollectorAddr) + prevProposerDistributionAddr := stakeKeeper.GetPrevProposerDistributionAddr(ctx) + ctx.Logger().Info("FeeCalculation distributeFeeBEP159", "height", ctx.BlockHeader().Height, "prevBlockFee", prevBlockFee) + // set fee in current block + currentBlockFee := fees.Pool.BlockFees().Tokens + if !currentBlockFee.IsZero() { + if _, _, err := stakeKeeper.BankKeeper.AddCoins(ctx, stake.FeeCollectorAddr, currentBlockFee); err != nil { + panic(err) + } + proposerValAddr := ctx.BlockHeader().ProposerAddress + proposerDistributionAddr := valAddrCache.GetDistributionAddr(ctx, proposerValAddr) + stakeKeeper.SetPrevProposerDistributionAddr(ctx, proposerDistributionAddr) + } + // distribute previous block fee + if prevBlockFee.IsZero() { + return + } + + // distrubute proposer rewards + proposerRewards := sdk.Coins{} + feeForAllRewards := sdk.Coins{} + var baseProposerRewardRatio sdk.Dec = stakeKeeper.BaseProposerRewardRatio(ctx) + var bonusProposerRewardRatio sdk.Dec = stakeKeeper.BonusProposerRewardRatio(ctx) + validatorNum := int64(len(ctx.VoteInfos())) + var voteNum int64 = 0 + for _, voteInfo := range ctx.VoteInfos() { + if voteInfo.SignedLastBlock { + voteNum++ + } + } + ctx.Logger().Info("FeeCalculation distributeFeeBEP159", "voteNum", voteNum, "validatorNum", validatorNum, "baseProposerRewardRatio", baseProposerRewardRatio, "bonusProposerRewardRatio", bonusProposerRewardRatio) + for _, token := range prevBlockFee { + amount := sdk.NewDec(token.Amount) + baseProposerReward := amount.Mul(baseProposerRewardRatio) + var bonusProposerReward sdk.Dec + if validatorNum == 0 { + // at the first breath block after BEP159 activation, the validator snapshot is empty + // we distribute the bonusProposerReward to proposer directly (voteNum should never be 0) + bonusProposerReward = amount.Mul(bonusProposerRewardRatio) + } else { + bonusProposerReward = amount.Mul(bonusProposerRewardRatio).MulInt(voteNum).QuoInt(validatorNum) + } + proposerAmount := baseProposerReward.Add(bonusProposerReward) + proposerRewards = append(proposerRewards, sdk.NewCoin(token.Denom, proposerAmount.RawInt())) + feeForAllRewards = append(feeForAllRewards, sdk.NewCoin(token.Denom, amount.Sub(proposerAmount).RawInt())) + } + var err error + if _, err = stakeKeeper.BankKeeper.SendCoins(ctx, stake.FeeCollectorAddr, stake.FeeForAllAccAddr, feeForAllRewards); err != nil { + panic(err) + } + if _, err = stakeKeeper.BankKeeper.SendCoins(ctx, stake.FeeCollectorAddr, prevProposerDistributionAddr, proposerRewards); err != nil { + panic(err) + } + ctx.Logger().Info("FeeCalculation distributeFeeBEP159", "prevProposerDistributionAddr", prevProposerDistributionAddr, "proposerRewards", proposerRewards, "feeForAllRewards", feeForAllRewards) + + // TODO: design event for fee distribution + //if publishBlockFee { + // blockFee.Fee = fee.String() + // for _, validator := range currentValidators { + // blockFee.Validators = append(blockFee.Validators, validator.ConsAddress().String()) + // } + //} + return +} + func distributeFee(ctx sdk.Context, am auth.AccountKeeper, valAddrCache *ValAddrCache, publishBlockFee bool) (blockFee pub.BlockFee) { fee := fees.Pool.BlockFees() blockFee = pub.BlockFee{Height: ctx.BlockHeader().Height} diff --git a/app/fee_distribution_test.go b/app/fee_distribution_test.go index 8ceb8db3c..0c7762ae4 100644 --- a/app/fee_distribution_test.go +++ b/app/fee_distribution_test.go @@ -1,26 +1,35 @@ package app import ( + "fmt" + "io" + "io/ioutil" + "os" "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/bank" + "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/stake" - + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/libs/log" + "github.com/tidwall/gjson" "github.com/bnb-chain/node/app/pub" "github.com/bnb-chain/node/common/testutils" "github.com/bnb-chain/node/common/types" + "github.com/bnb-chain/node/common/upgrade" "github.com/bnb-chain/node/wire" ) +const BREATHE_BLOCK_INTERVAL = 5 + func getAccountCache(cdc *codec.Codec, ms sdk.MultiStore, accountKey *sdk.KVStoreKey) sdk.AccountCache { accountStore := ms.GetKVStore(accountKey) accountStoreCache := auth.NewAccountStoreCache(cdc, accountStore, 10) @@ -110,3 +119,349 @@ func TestFeeDistribution2AllValidators(t *testing.T) { require.Equal(t, pub.BlockFee{0, "BNB:50", []string{string(proposerAcc.GetAddress()), string(valAcc1.GetAddress()), string(valAcc2.GetAddress()), string(valAcc3.GetAddress())}}, blockFee) checkBalance(t, ctx, am, valAddrCache, []int64{124, 122, 122, 122}) } + +type Account struct { + Priv crypto.PrivKey + CryptoAddress crypto.Address + Address sdk.AccAddress + ValAddress sdk.ValAddress + BaseAccount *auth.BaseAccount + AppAccount types.AppAccount + GenesisAccount GenesisAccount +} + +func GenAccounts(n int) (accounts []Account) { + for i := 0; i < n; i++ { + priv := ed25519.GenPrivKey() + address := priv.PubKey().Address() + accAddr := sdk.AccAddress(address) + genCoin := sdk.NewCoin("BNB", 10e13) + baseAccount := auth.BaseAccount{ + Address: accAddr, + Coins: sdk.Coins{genCoin}, + } + appAcc := types.AppAccount{BaseAccount: baseAccount} + genesisAccount := NewGenesisAccount(&appAcc, address) + accounts = append(accounts, Account{ + Priv: priv, + CryptoAddress: address, + Address: accAddr, + BaseAccount: &baseAccount, + AppAccount: appAcc, + ValAddress: sdk.ValAddress(address), + GenesisAccount: genesisAccount, + }) + } + return +} + +func setupTestForBEP159Test() (*BinanceChain, sdk.Context, []Account) { + // config + upgrade.Mgr.Reset() + context := ServerContext + ServerContext.BreatheBlockInterval = BREATHE_BLOCK_INTERVAL + ServerContext.LaunchBscUpgradeHeight = 1 + ServerContext.BEP128Height = 2 + ServerContext.BEP151Height = 3 + ServerContext.BEP153Height = 4 + ServerContext.BEP159Height = 6 + ServerContext.BEP159Phase2Height = 159 + ServerContext.Config.StateSyncReactor = false + config := sdk.GetConfig() + config.SetBech32PrefixForAccount(context.Bech32PrefixAccAddr, context.Bech32PrefixAccPub) + config.SetBech32PrefixForValidator(context.Bech32PrefixValAddr, context.Bech32PrefixValPub) + config.SetBech32PrefixForConsensusNode(context.Bech32PrefixConsAddr, context.Bech32PrefixConsPub) + config.Seal() + // create app + app := NewBinanceChain(logger, memDB, io.Discard) + logger.Info("BEP159Height", "BEP159Height", ServerContext.BEP159Height) + logger.Info("BEP159Phase2Height", "BEP159Phase2Height", ServerContext.BEP159Phase2Height) + logger.Info("BreatheBlockInterval", "BreatheBlockInterval", ServerContext.BreatheBlockInterval) + logger.Info("IbcChainId", "IbcChainId", ServerContext.IbcChainId) + logger.Info("BscChainId", "BscChainId", ServerContext.BscChainId) + logger.Info("BscIbcChainId", "BscIbcChainId", ServerContext.BscIbcChainId) + + // read genesis + genesisJsonFile, err := os.Open("../asset/mainnet/genesis.json") + if err != nil { + panic(err) + } + defer genesisJsonFile.Close() + genesisByteValue, err := ioutil.ReadAll(genesisJsonFile) + if err != nil { + panic(err) + } + stateBytes := gjson.Get(string(genesisByteValue), "app_state").String() + n := 100 + accounts := GenAccounts(n) + app.SetCheckState(abci.Header{}) + app.InitChain(abci.RequestInitChain{ + ChainId: "Binance-Chain-Tigris", + Validators: []abci.ValidatorUpdate{}, + AppStateBytes: []byte(stateBytes), + }) + ctx := app.BaseApp.DeliverState.Ctx + for i := 0; i < n; i++ { + appAcc := accounts[i].AppAccount + if app.AccountKeeper.GetAccount(ctx, accounts[i].Address) == nil { + appAcc.BaseAccount.AccountNumber = app.AccountKeeper.GetNextAccountNumber(ctx) + } + app.AccountKeeper.SetAccount(ctx, &appAcc) + } + app.Commit() + return app, ctx, accounts +} + +func GenSimTxs(app *BinanceChain, msgs []sdk.Msg, expSimPass bool, privs ...crypto.PrivKey, +) (txs []auth.StdTx) { + accSeqMap := make(map[string][2]int64) + ctx := app.CheckState.Ctx + for i, priv := range privs { + addr := sdk.AccAddress(priv.PubKey().Address()) + logger.Info("addr", "addr", addr) + accNumSeq, found := accSeqMap[addr.String()] + if !found { + acc := app.AccountKeeper.GetAccount(ctx, addr) + logger.Info("acc", "coins", acc.GetCoins()) + if acc == nil { + panic(fmt.Sprintf("account %s not found", addr)) + } + accNumSeq[0] = acc.GetAccountNumber() + accNumSeq[1] = acc.GetSequence() + } + tx := mock.GenTx(msgs[i:i+1], []int64{accNumSeq[0]}, []int64{accNumSeq[1]}, priv) + res := app.Simulate(nil, tx) + if expSimPass && !res.IsOK() { + panic(fmt.Sprintf("simulate failed: %+v", res)) + } + accSeqMap[addr.String()] = [2]int64{accNumSeq[0], accNumSeq[1] + 1} + txs = append(txs, tx) + } + return txs +} + +func ApplyBlock(t *testing.T, app *BinanceChain, ctx sdk.Context, txs []auth.StdTx) (newCtx sdk.Context) { + height := ctx.BlockHeader().Height + 1 + logger.Debug("ApplyBlock", "height", height) + header := abci.Header{Height: height} + validators := app.stakeKeeper.GetSortedBondedValidators(ctx) + //logger.Debug("ApplyBlock", "validators", validators) + header.ProposerAddress = validators[0].ConsAddress() + lastCommitInfo := abci.LastCommitInfo{ + Round: 0, + Votes: []abci.VoteInfo{}, + } + for _, validator := range validators { + lastCommitInfo.Votes = append(lastCommitInfo.Votes, abci.VoteInfo{ + Validator: abci.Validator{ + Address: validator.ConsAddress(), + Power: validator.Tokens.RawInt(), + }, + SignedLastBlock: true, + }) + } + app.BeginBlock(abci.RequestBeginBlock{Header: header, LastCommitInfo: lastCommitInfo}) + for _, tx := range txs { + bz := app.Codec.MustMarshalBinaryLengthPrefixed(tx) + res := app.DeliverTx(abci.RequestDeliverTx{Tx: bz}) + require.Equal(t, uint32(0), res.Code, res.Log) + } + app.EndBlock(abci.RequestEndBlock{Height: height}) + app.Commit() + newCtx = app.BaseApp.NewContext(sdk.RunTxModeCheck, header) + return +} + +func ApplyEmptyBlocks(t *testing.T, app *BinanceChain, ctx sdk.Context, blockNum int) (newCtx sdk.Context) { + currentCtx := ctx + for i := 0; i < blockNum; i++ { + currentCtx = ApplyBlock(t, app, currentCtx, []auth.StdTx{}) + } + return currentCtx +} + +func ApplyToBreathBlocks(t *testing.T, app *BinanceChain, ctx sdk.Context, breathBlockNum int) (newCtx sdk.Context) { + currentHeight := ctx.BlockHeader().Height + blockNum := BREATHE_BLOCK_INTERVAL*breathBlockNum - int(currentHeight%int64(BREATHE_BLOCK_INTERVAL)) + 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)) + + // 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) + + // 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]) + + // 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) +} diff --git a/app/pub/msgs_staking.go b/app/pub/msgs_staking.go index d84f1f574..8d26f9730 100644 --- a/app/pub/msgs_staking.go +++ b/app/pub/msgs_staking.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/linkedin/goavro" ) // staking message @@ -248,7 +249,7 @@ func (msg *Validator) toNativeMap() 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["consAddr"] = goavro.Union("string", sdk.ConsAddress(msg.ConsPubKey.Address()).String()) } native["jailed"] = msg.Jailed @@ -275,6 +276,9 @@ func (msg *Validator) toNativeMap() map[string]interface{} { native["distributionAddr"] = msg.DistributionAddr.String() native["sideChainId"] = msg.SideChainId + if msg.SideChainId == "" { + native["sideChainId"] = stake.ChainIDForBeaconChain + } native["sideConsAddr"] = sdk.HexAddress(msg.SideConsAddr) native["sideFeeAddr"] = sdk.HexAddress(msg.SideFeeAddr) diff --git a/app/pub/sub/stake.go b/app/pub/sub/stake.go index 21a7b172e..371871ccb 100644 --- a/app/pub/sub/stake.go +++ b/app/pub/sub/stake.go @@ -24,10 +24,10 @@ func SubscribeStakeEvent(sub *pubsub.Subscriber) error { stagingArea.StakeData = &StakeData{} } switch e := event.(type) { - case stake.SideDistributionEvent: + case stake.DistributionEvent: sub.Logger.Debug(fmt.Sprintf("distribution event: %v \n", e)) - toPublish.EventData.StakeData.appendDistribution(e.SideChainId, e.Data) - case stake.SideCompletedUBDEvent: + toPublish.EventData.StakeData.appendDistribution(e.ChainId, e.Data) + case stake.CompletedUBDEvent: sub.Logger.Debug(fmt.Sprintf("completed UBD event: %v \n", e)) ubds := make([]CompletedUBD, len(e.CompUBDs)) for i, ubd := range e.CompUBDs { @@ -38,15 +38,12 @@ func SubscribeStakeEvent(sub *pubsub.Subscriber) error { } ubds[i] = cUBD } - toPublish.EventData.StakeData.appendCompletedUBD(e.SideChainId, ubds) - case stake.SideCompletedREDEvent: + toPublish.EventData.StakeData.appendCompletedUBD(e.ChainId, ubds) + case stake.CompletedREDEvent: sub.Logger.Debug(fmt.Sprintf("completed RED event: %v \n", e)) - toPublish.EventData.StakeData.appendCompletedRED(e.SideChainId, e.CompREDs) + toPublish.EventData.StakeData.appendCompletedRED(e.ChainId, 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 { @@ -54,59 +51,59 @@ func SubscribeStakeEvent(sub *pubsub.Subscriber) error { } case stake.ValidatorRemovedEvent: sub.Logger.Debug(fmt.Sprintf("validator removed event: %v \n", e)) - chainId := e.SideChainId + chainId := e.ChainId if len(chainId) == 0 { - return // ignore bbc validator + chainId = stake.ChainIDForBeaconChain } if e.IsFromTx { stagingArea.StakeData.appendRemovedValidator(chainId, e.Operator) } else { toPublish.EventData.StakeData.appendRemovedValidator(chainId, e.Operator) } - case stake.SideDelegationUpdateEvent: + case stake.DelegationUpdateEvent: 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) + stagingArea.StakeData.appendDelegation(e.ChainId, key, e.Delegation) } else { - toPublish.EventData.StakeData.appendDelegation(e.SideChainId, key, e.Delegation) + toPublish.EventData.StakeData.appendDelegation(e.ChainId, key, e.Delegation) } - case stake.SideDelegationRemovedEvent: + case stake.DelegationRemovedEvent: sub.Logger.Debug(fmt.Sprintf("delegation removed event: %v \n", e)) if e.IsFromTx { - stagingArea.StakeData.appendRemovedDelegation(e.SideChainId, e.DvPair) + stagingArea.StakeData.appendRemovedDelegation(e.ChainId, e.DvPair) } else { - toPublish.EventData.StakeData.appendRemovedDelegation(e.SideChainId, e.DvPair) + toPublish.EventData.StakeData.appendRemovedDelegation(e.ChainId, e.DvPair) } - case stake.SideUBDUpdateEvent: + case stake.UBDUpdateEvent: 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) + stagingArea.StakeData.appendUBD(e.ChainId, key, e.UBD) } else { - toPublish.EventData.StakeData.appendUBD(e.SideChainId, key, e.UBD) + toPublish.EventData.StakeData.appendUBD(e.ChainId, key, e.UBD) } - case stake.SideREDUpdateEvent: + case stake.REDUpdateEvent: 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) + stagingArea.StakeData.appendRED(e.ChainId, key, e.RED) } else { - toPublish.EventData.StakeData.appendRED(e.SideChainId, key, e.RED) + toPublish.EventData.StakeData.appendRED(e.ChainId, key, e.RED) } - case stake.SideDelegateEvent: + case stake.ChainDelegateEvent: sub.Logger.Debug(fmt.Sprintf("delegate event: %v \n", e)) - stagingArea.StakeData.appendDelegateEvent(e.SideChainId, e.DelegateEvent) - case stake.SideUndelegateEvent: + stagingArea.StakeData.appendDelegateEvent(e.ChainId, e.DelegateEvent) + case stake.ChainUndelegateEvent: sub.Logger.Debug(fmt.Sprintf("undelegate event: %v \n", e)) - stagingArea.StakeData.appendUnDelegateEvent(e.SideChainId, e.UndelegateEvent) - case stake.SideRedelegateEvent: + stagingArea.StakeData.appendUnDelegateEvent(e.ChainId, e.UndelegateEvent) + case stake.ChainRedelegateEvent: sub.Logger.Debug(fmt.Sprintf("redelegate event: %v \n", e)) - stagingArea.StakeData.appendReDelegateEvent(e.SideChainId, e.RedelegateEvent) - case stake.SideElectedValidatorsEvent: + stagingArea.StakeData.appendReDelegateEvent(e.ChainId, e.RedelegateEvent) + case stake.ElectedValidatorsEvent: sub.Logger.Debug(fmt.Sprintf("elected validators event: %v \n", e)) validators := make(map[string][]stake.Validator) - validators[e.SideChainId] = e.Validators + validators[e.ChainId] = e.Validators toPublish.EventData.StakeData.ElectedValidators = validators default: sub.Logger.Info("unknown event type") diff --git a/cmd/bnbchaind/init/init.go b/cmd/bnbchaind/init/init.go index ee949ccba..61c3ea196 100644 --- a/cmd/bnbchaind/init/init.go +++ b/cmd/bnbchaind/init/init.go @@ -1,11 +1,10 @@ -package init - /* Why we overwrite the Init/Testnet functions in cosmos-sdk: 1. Cosmos moved init/testnet cmds to the gaia packages which we never and should not imports. 2. Cosmos has a different init/testnet workflow from ours. Also, the init cmd has some bugs. 3. After overwrite, the code is cleaner and easier to maintain. */ +package init import ( "encoding/json" @@ -29,6 +28,7 @@ import ( "github.com/tendermint/tendermint/libs/common" "github.com/bnb-chain/node/app" + "github.com/bnb-chain/node/common/types" "github.com/bnb-chain/node/common/utils" "github.com/bnb-chain/node/wire" ) @@ -90,9 +90,9 @@ enabled, and the genesis file will not be generated. return errors.New("must specify --name (validator moniker)") } - valOperAddr, secret := createValOperAccount(viper.GetString(flagClientHome), config.Moniker) + valOperAddr, secret := CreateValOperAccount(viper.GetString(flagClientHome), config.Moniker) memo := fmt.Sprintf("%s@%s:26656", nodeID, "127.0.0.1") - genTx := prepareCreateValidatorTx(cdc, chainID, config.Moniker, memo, valOperAddr, pubKey) + genTx := PrepareCreateValidatorTx(cdc, chainID, config.Moniker, memo, valOperAddr, pubKey) appState, err := appInit.AppGenState(cdc, []json.RawMessage{genTx}) if err != nil { return err @@ -102,7 +102,7 @@ enabled, and the genesis file will not be generated. return fmt.Errorf("genesis.json file already exists: %v", genFile) } ExportGenesisFileWithTime(genFile, chainID, nil, appState, utils.Now()) - writeConfigFile(config) + WriteConfigFile(config) bech32ifyPubKey, err := sdk.Bech32ifyConsPub(pubKey) if err != nil { @@ -131,13 +131,13 @@ enabled, and the genesis file will not be generated. return cmd } -func prepareCreateValidatorTx(cdc *codec.Codec, chainId, name, memo string, +func PrepareCreateValidatorTx(cdc *codec.Codec, chainId, name, memo string, valOperAddr sdk.ValAddress, valPubKey crypto.PubKey) json.RawMessage { msg := stake.MsgCreateValidatorProposal{ MsgCreateValidator: stake.NewMsgCreateValidator( valOperAddr, valPubKey, - app.DefaultSelfDelegationToken, + sdk.NewCoin(types.NativeTokenSymbol, 90000e8), stake.NewDescription(name, "", "", ""), stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), ), @@ -157,7 +157,7 @@ func prepareCreateValidatorTx(cdc *codec.Codec, chainId, name, memo string, return txBytes } -func writeConfigFile(config *cfg.Config) { +func WriteConfigFile(config *cfg.Config) { configFilePath := filepath.Join(config.RootDir, "config", "config.toml") cfg.WriteConfigFile(configFilePath, config) } diff --git a/cmd/bnbchaind/init/testnet.go b/cmd/bnbchaind/init/testnet.go index b6685dfdd..9f6140ec2 100644 --- a/cmd/bnbchaind/init/testnet.go +++ b/cmd/bnbchaind/init/testnet.go @@ -9,18 +9,16 @@ import ( "sort" "strings" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" "github.com/spf13/viper" - cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" cmn "github.com/tendermint/tendermint/libs/common" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/server" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/bnb-chain/node/app" appCfg "github.com/bnb-chain/node/app/config" "github.com/bnb-chain/node/common/utils" @@ -138,7 +136,7 @@ func initTestnet(config *cfg.Config, cdc *codec.Codec, appInit server.AppInit) e ip := getIP(i, viper.GetString(flagStartingIPAddress)) nodeId, valPubKey := InitializeNodeValidatorFiles(config) - addr, _ := createValOperAccount(clientDir, config.Moniker) + addr, _ := CreateValOperAccount(clientDir, config.Moniker) if bech32ifyPubKey, err := sdk.Bech32ifyConsPub(valPubKey); err != nil { return err } else { @@ -185,7 +183,7 @@ func prepareClientDir(clientDir string) { func prepareGenTx(cdc *codec.Codec, chainId, name, nodeId, ip, gentxsDir string, valOperAddr sdk.ValAddress, valPubKey crypto.PubKey) json.RawMessage { memo := fmt.Sprintf("%s@%s:26656", nodeId, ip) - txBytes := prepareCreateValidatorTx(cdc, chainId, name, memo, valOperAddr, valPubKey) + txBytes := PrepareCreateValidatorTx(cdc, chainId, name, memo, valOperAddr, valPubKey) err := writeFile(fmt.Sprintf("%v.json", name), gentxsDir, txBytes) if err != nil { panic(err) diff --git a/cmd/bnbchaind/init/utils.go b/cmd/bnbchaind/init/utils.go index 8027fe6c2..44ec29493 100644 --- a/cmd/bnbchaind/init/utils.go +++ b/cmd/bnbchaind/init/utils.go @@ -8,7 +8,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" - cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/common" @@ -86,7 +85,7 @@ func InitializeNodeValidatorFiles(config *cfg.Config) (nodeID string, valPubKey return nodeID, valPubKey } -func createValOperAccount(clientDir, keyName string) (sdk.ValAddress, string) { +func CreateValOperAccount(clientDir, keyName string) (sdk.ValAddress, string) { accAddr, secret, err := server.GenerateSaveCoinKey(clientDir, keyName, app.DefaultKeyPass, true) if err != nil { panic(err) diff --git a/cmd/gen_devnet/docker_compose.go b/cmd/gen_devnet/docker_compose.go new file mode 100644 index 000000000..ac109be33 --- /dev/null +++ b/cmd/gen_devnet/docker_compose.go @@ -0,0 +1,71 @@ +package main + +import ( + "bytes" + "fmt" + "text/template" + + cmn "github.com/tendermint/tendermint/libs/common" +) + +var configTemplate *template.Template + +func init() { + var err error + if configTemplate, err = template.New("configFileTemplate").Parse(defaultConfigTemplate); err != nil { + panic(err) + } +} + +type NodeTemplateParams struct { + Index int + PortIP int + PortExpose1 int + PortExpose2 int +} + +type DockerComposeTemplateParams struct { + Nodes []NodeTemplateParams +} + +// WriteConfigFile renders config using the template and writes it to configFilePath. +func WriteConfigFile(configFilePath string, config *DockerComposeTemplateParams) { + var buffer bytes.Buffer + fmt.Printf("Writing config %+v to %s\n", config, configFilePath) + if err := configTemplate.Execute(&buffer, config); err != nil { + panic(err) + } + + cmn.MustWriteFile(configFilePath, buffer.Bytes(), 0644) +} + +const defaultConfigTemplate = `version: '3' + +services: +{{- range .Nodes }} + + node{{ .Index }}: + container_name: node{{ .Index }} + image: "binance/bnbdnode" + restart: always + command: bnbchaind start --home /data/testnoded + ports: + - "{{ .PortExpose1 }}:26656" + - "{{ .PortExpose2 }}:26657" + volumes: + - ./node{{ .Index }}:/data:Z + networks: + localnet: + ipv4_address: 172.20.0.{{ .PortIP }} + +{{- end }} + +networks: + localnet: + driver: bridge + ipam: + driver: default + config: + - + subnet: 172.20.0.0/16 +` diff --git a/cmd/gen_devnet/main.go b/cmd/gen_devnet/main.go new file mode 100644 index 000000000..4cf002fae --- /dev/null +++ b/cmd/gen_devnet/main.go @@ -0,0 +1,114 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "path" + "path/filepath" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bnb-chain/node/app" + "github.com/bnb-chain/node/app/config" + bnbInit "github.com/bnb-chain/node/cmd/bnbchaind/init" + "github.com/bnb-chain/node/common/utils" +) + +var ( + chainID = "devnet-1000" + nodeNum = 4 +) + +func main() { + fmt.Println("start generate devnet configs") + cwd, _ := os.Getwd() + devnetHomeDir := path.Join(cwd, "build", "devnet") + fmt.Println("devnet home dir:", devnetHomeDir) + // clear devnetHomeDir + err := os.RemoveAll(devnetHomeDir) + if err != nil { + panic(err) + } + // init nodes + cdc := app.Codec + ctx := app.ServerContext + appInit := app.BinanceAppInit() + ctxConfig := ctx.Config + sdkConfig := sdk.GetConfig() + sdkConfig.SetBech32PrefixForAccount(ctx.Bech32PrefixAccAddr, ctx.Bech32PrefixAccPub) + sdkConfig.SetBech32PrefixForValidator(ctx.Bech32PrefixValAddr, ctx.Bech32PrefixValPub) + sdkConfig.SetBech32PrefixForConsensusNode(ctx.Bech32PrefixConsAddr, ctx.Bech32PrefixConsPub) + sdkConfig.Seal() + var appState json.RawMessage + var seeds string + genesisTime := utils.Now() + ServerContext := config.NewDefaultContext() + nodesTemplateParams := make([]NodeTemplateParams, nodeNum) + + for i := 0; i < nodeNum; i++ { + nodeName := fmt.Sprintf("node%d", i) + nodeDir := path.Join(devnetHomeDir, nodeName, "testnoded") + cliDir := path.Join(devnetHomeDir, nodeName, "testnodecli") + ctxConfig.SetRoot(nodeDir) + for _, subdir := range []string{"data", "config"} { + err = os.MkdirAll(path.Join(nodeDir, subdir), os.ModePerm) + if err != nil { + panic(err) + } + } + // app.toml + binanceChainConfig := ServerContext.BinanceChainConfig + binanceChainConfig.UpgradeConfig.BEP3Height = 1 + binanceChainConfig.UpgradeConfig.BEP8Height = 1 + binanceChainConfig.UpgradeConfig.BEP12Height = 1 + binanceChainConfig.UpgradeConfig.BEP67Height = 1 + binanceChainConfig.UpgradeConfig.BEP70Height = 1 + binanceChainConfig.UpgradeConfig.BEP82Height = 1 + binanceChainConfig.UpgradeConfig.BEP84Height = 1 + binanceChainConfig.UpgradeConfig.BEP87Height = 1 + binanceChainConfig.UpgradeConfig.FixFailAckPackageHeight = 1 + binanceChainConfig.UpgradeConfig.EnableAccountScriptsForCrossChainTransferHeight = 1 + binanceChainConfig.UpgradeConfig.BEP128Height = 1 + binanceChainConfig.UpgradeConfig.BEP151Height = 1 + binanceChainConfig.UpgradeConfig.BEP153Height = 2 + binanceChainConfig.UpgradeConfig.BEP159Height = 3 + binanceChainConfig.UpgradeConfig.BEP159Phase2Height = 6 + binanceChainConfig.BreatheBlockInterval = 5 + appConfigFilePath := filepath.Join(ctxConfig.RootDir, "config", "app.toml") + config.WriteConfigFile(appConfigFilePath, binanceChainConfig) + // pk + nodeID, pubKey := bnbInit.InitializeNodeValidatorFiles(ctxConfig) + ctxConfig.Moniker = nodeName + valOperAddr, secret := bnbInit.CreateValOperAccount(cliDir, ctxConfig.Moniker) + fmt.Printf("%v secret: %v\n", nodeName, secret) + if i == 0 { + memo := fmt.Sprintf("%s@%s:26656", nodeID, "127.0.0.1") + genTx := bnbInit.PrepareCreateValidatorTx(cdc, chainID, ctxConfig.Moniker, memo, valOperAddr, pubKey) + appState, err = appInit.AppGenState(cdc, []json.RawMessage{genTx}) + if err != nil { + panic(err) + } + seeds = fmt.Sprintf("%s@172.20.0.100:26656", nodeID) + } else { + ctxConfig.P2P.Seeds = seeds + } + genFile := ctxConfig.GenesisFile() + // genesis.json + err = bnbInit.ExportGenesisFileWithTime(genFile, chainID, nil, appState, genesisTime) + if err != nil { + panic(err) + } + // edit ctxConfig + ctxConfig.LogLevel = "*:debug" + // config.toml + bnbInit.WriteConfigFile(ctxConfig) + // docker_compose.yml params + node := NodeTemplateParams{Index: i, PortIP: i + 100, PortExpose1: 8000 + i, PortExpose2: 8100 + i} + nodesTemplateParams[i] = node + } + dockerComposeTemplateParams := DockerComposeTemplateParams{ + Nodes: nodesTemplateParams, + } + WriteConfigFile(filepath.Join(devnetHomeDir, "docker-compose.yml"), &dockerComposeTemplateParams) +} diff --git a/cmd/test_client/fee.go b/cmd/test_client/fee.go new file mode 100644 index 000000000..38fe3b5e3 --- /dev/null +++ b/cmd/test_client/fee.go @@ -0,0 +1,150 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + + "github.com/binance-chain/go-sdk/client/rpc" + sdkTypes "github.com/binance-chain/go-sdk/common/types" + "golang.org/x/xerrors" +) + +var ( + //c = rpc.NewRPCClient("http://172.22.42.52:27147", sdkTypes.TestNetwork) + c = rpc.NewRPCClient("http://127.0.0.1:26657", sdkTypes.ProdNetwork) +) + +//const sideChainId = "rialto" +const sideChainId = "bsc" + +type Validator struct { + OperatorAddr sdkTypes.ValAddress `json:"operator_addr"` + FeeAddr sdkTypes.AccAddress `json:"fee_addr"` + HexAddr string `json:"hex_addr"` + TotalShares sdkTypes.Dec `json:"total_shares"` + SelfShare sdkTypes.Dec `json:"self_share"` + Balance sdkTypes.TokenBalance `json:"balance"` + ComissionRate sdkTypes.Dec `json:"comission_rate"` + Status sdkTypes.BondStatus `json:"status"` +} + +type Data struct { + TotalTxs int64 `json:"total_txs"` + Validators []Validator `json:"validators"` + SideValidators []Validator `json:"side_validators"` +} + +type SnapShot struct { + Height int64 `json:"height"` + NumTxs int64 `json:"num_txs"` + Data Data `json:"data"` +} + +func changed(a, b *SnapShot) bool { + aJson, _ := json.Marshal(a.Data) + bJson, _ := json.Marshal(b.Data) + return string(aJson) != string(bJson) +} + +func GetSnapshot() (s *SnapShot, err error) { + s = &SnapShot{} + block, err := c.Block(nil) + if err != nil { + return nil, xerrors.Errorf("get block failed: %v", err) + } + s.Height = block.Block.Height + s.NumTxs = int64(len(block.Block.Txs)) + s.Data.TotalTxs = block.Block.Header.TotalTxs + // get all validators + validators, err := c.QueryTopValidators(50) + if err != nil { + return nil, xerrors.Errorf("get validators failed: %v", err) + } + //log.Printf("validators: %+v", validators) + for _, v := range validators { + delegation, err := c.QueryDelegation(v.FeeAddr, v.OperatorAddr) + if err != nil { + return nil, xerrors.Errorf("get delegation failed: %v", err) + } + //log.Printf("validator: %s", Pretty(v)) + //log.Printf("validator: %+v", v) + //log.Printf("delegation: %+v", delegation) + feeAddrBalance, err := c.GetBalance(v.FeeAddr, "BNB") + if err != nil { + return nil, xerrors.Errorf("get balance failed: %v", err) + } + //log.Printf("feeAddrBalance: %+v", feeAddrBalance) + validator := Validator{ + OperatorAddr: v.OperatorAddr, + FeeAddr: v.FeeAddr, + TotalShares: v.DelegatorShares, + SelfShare: delegation.Shares, + Balance: *feeAddrBalance, + ComissionRate: v.Commission.Rate, + Status: v.Status, + HexAddr: fmt.Sprintf("%X", v.FeeAddr.Bytes()), + } + s.Data.Validators = append(s.Data.Validators, validator) + } + // get all sidechain validators + sidechainValidators, err := c.QuerySideChainTopValidators(sideChainId, 50) + if err != nil { + return nil, xerrors.Errorf("get sidechain validators failed: %v", err) + } + for _, v := range sidechainValidators { + delegation, err := c.QuerySideChainDelegation(sideChainId, v.FeeAddr, v.OperatorAddr) + if err != nil { + return nil, xerrors.Errorf("get delegation failed: %v", err) + } + //log.Printf("validator: %+v", v) + //log.Printf("delegation: %+v", delegation) + feeAddrBalance, err := c.GetBalance(v.FeeAddr, "BNB") + if err != nil { + return nil, xerrors.Errorf("get balance failed: %v", err) + } + //log.Printf("feeAddrBalance: %+v", feeAddrBalance) + validator := Validator{ + OperatorAddr: v.OperatorAddr, + FeeAddr: v.FeeAddr, + TotalShares: v.DelegatorShares, + SelfShare: delegation.Shares, + Balance: *feeAddrBalance, + ComissionRate: v.Commission.Rate, + Status: v.Status, + HexAddr: fmt.Sprintf("%X", v.FeeAddr.Bytes()), + } + s.Data.SideValidators = append(s.Data.SideValidators, validator) + } + return s, nil +} + +func saveSnapshot(s *SnapShot, path string) error { + data, err := json.MarshalIndent(s, "", " ") + if err != nil { + return xerrors.Errorf("marshal snapshot failed: %v", err) + } + return ioutil.WriteFile(fmt.Sprintf("%s/%d.json", path, s.Height), data, 0644) +} + +//nolint +func TestFee() error { + latestSnap := &SnapShot{} + for { + snapshot, err := GetSnapshot() + if err != nil { + return xerrors.Errorf("get snapshot failed: %v", err) + } + changed := changed(latestSnap, snapshot) + log.Printf("height: %v, TxNum: %v, changed: %v", snapshot.Height, snapshot.NumTxs, changed) + if changed { + log.Printf("snapshot: %s", Pretty(snapshot)) + err = saveSnapshot(snapshot, "test") + if err != nil { + return xerrors.Errorf("save snapshot failed: %v", err) + } + } + latestSnap = snapshot + } +} diff --git a/cmd/test_client/main.go b/cmd/test_client/main.go new file mode 100644 index 000000000..b486ee605 --- /dev/null +++ b/cmd/test_client/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "log" +) + +func main() { + var err error + log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime) + log.Printf("----- start test -----") + err = ChangeParameterViaGov() + if err != nil { + log.Printf("%+v\n", err) + panic(err) + } + err = Staking() + if err != nil { + log.Printf("%+v\n", err) + panic(err) + } + //err = TestFee() + //if err != nil { + // log.Printf("TestFee failed: %v\n", err) + //} + log.Printf("----- end test -----") +} diff --git a/cmd/test_client/staking.go b/cmd/test_client/staking.go new file mode 100644 index 000000000..b60ea138b --- /dev/null +++ b/cmd/test_client/staking.go @@ -0,0 +1,684 @@ +package main + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "math/rand" + "os" + "path" + "strconv" + "strings" + "time" + + "github.com/binance-chain/go-sdk/client/rpc" + sdkTypes "github.com/binance-chain/go-sdk/common/types" + "github.com/binance-chain/go-sdk/keys" + "github.com/binance-chain/go-sdk/types/msg" + "github.com/binance-chain/go-sdk/types/tx" + cosmosTypes "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/go-amino" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" + "github.com/tendermint/tendermint/privval" + "github.com/tidwall/gjson" + "golang.org/x/xerrors" +) + +var ( + txWithChainID tx.Option +) + +type NodeInfo struct { + Mnemonic string + DelegatorAddr cosmosTypes.AccAddress `json:"delegator_address"` + ValidatorAddr cosmosTypes.ValAddress `json:"validator_address"` + Addr sdkTypes.AccAddress `json:"address"` + PubKey crypto.PubKey `json:"pubkey"` + KeyManager keys.KeyManager +} + +func GetNodeInfo(i int) (*NodeInfo, error) { + nodePath := path.Join("build", "devnet", fmt.Sprintf("node%d", i)) + seedPath := path.Join(nodePath, "testnodecli", "key_seed.json") + content, err := os.ReadFile(seedPath) + if err != nil { + return nil, xerrors.Errorf("read file %s failed: %w", seedPath, err) + } + mnemonic := gjson.GetBytes(content, "secret").String() + // key manager + keyManager, err := keys.NewMnemonicKeyManager(mnemonic) + if err != nil { + return nil, xerrors.Errorf("new key manager failed: %w", err) + } + // load validator key + privValKeyFile := path.Join(nodePath, "testnoded", "config", "priv_validator_key.json") + keyJSONBytes, err := os.ReadFile(privValKeyFile) + if err != nil { + return nil, xerrors.Errorf("read file %s failed: %w", privValKeyFile, err) + } + pvKey := privval.FilePVKey{} + cdc := amino.NewCodec() + cryptoAmino.RegisterAmino(cdc) + privval.RegisterRemoteSignerMsg(cdc) + err = cdc.UnmarshalJSON(keyJSONBytes, &pvKey) + if err != nil { + return nil, xerrors.Errorf("Error reading PrivValidator key from %v: %v", privValKeyFile, err) + } + pvKey.PubKey = pvKey.PrivKey.PubKey() + pvKey.Address = pvKey.PubKey.Address() + return &NodeInfo{ + Mnemonic: mnemonic, + ValidatorAddr: cosmosTypes.ValAddress(keyManager.GetAddr()), + DelegatorAddr: cosmosTypes.AccAddress(keyManager.GetAddr()), + Addr: keyManager.GetAddr(), + PubKey: pvKey.PrivKey.PubKey(), + KeyManager: keyManager, + }, nil +} + +func randomHex(n int) (string, error) { + bytes := make([]byte, n) + if _, err := rand.Read(bytes); err != nil { + return "", err + } + return hex.EncodeToString(bytes), nil +} + +func GenKeyManager() (km keys.KeyManager, err error) { + pk, err := randomHex(32) + log.Println("pk:", pk) + if err != nil { + return + } + return keys.NewPrivateKeyManager(pk) +} + +func GenKeyManagerWithBNB(client *rpc.HTTP, tokenFrom keys.KeyManager) (km keys.KeyManager, err error) { + km, err = GenKeyManager() + if err != nil { + return nil, xerrors.Errorf("GenKeyManager err: %w", err) + } + // send coin to the account + client.SetKeyManager(tokenFrom) + transfer := msg.Transfer{ToAddr: km.GetAddr(), Coins: sdkTypes.Coins{sdkTypes.Coin{ + Denom: "BNB", + Amount: 150e8, + }}} + txRes, err := client.SendToken([]msg.Transfer{transfer}, rpc.Commit, txWithChainID) + if err != nil { + return nil, xerrors.Errorf("send token error: %w", err) + } + assert(txRes.Code == 0, fmt.Sprintf("send token error, tx: %+v", txRes)) + return km, nil +} + +func getConfigFromEnv() Config { + env, ok := os.LookupEnv("STAKE_ENV") + if !ok { + env = "integration" // default env + } + switch env { + case "integration": + seedPath := path.Join("build", "testnoded", "secret") + content, err := os.ReadFile(seedPath) + if err != nil { + panic(err) + } + return Config{ + RPCAddr: "tcp://127.0.0.1:26657", + Secret: strings.TrimSpace(string(content)), + } + case "multi": + node, err := GetNodeInfo(0) + if err != nil { + panic(err) + } + return Config{ + RPCAddr: "tcp://127.0.0.1:8100", + Secret: node.Mnemonic, + } + default: + panic("unknown env") + } +} + +type Config struct { + RPCAddr string `json:"rpc_addr"` // rpc address to connect to + Secret string `json:"secret"` // account which has enough coin to send +} + +func ChangeParameterViaGov() error { + config := getConfigFromEnv() + node0RpcAddr := config.RPCAddr + c0 := rpc.NewRPCClient(node0RpcAddr, sdkTypes.ProdNetwork) + status, err := c0.Status() + chainId := status.NodeInfo.Network + txWithChainID = tx.WithChainID(chainId) + if err != nil { + return xerrors.Errorf("get status error: %w", err) + } + log.Printf("chainId: %s\n", chainId) + log.Printf("node0 status") + log.Println(Pretty(status)) + // validator + secret := config.Secret + log.Printf("secret: %s", secret) + validatorKm, err := keys.NewMnemonicKeyManager(secret) + if err != nil { + return xerrors.Errorf("new key manager failed: %w", err) + } + log.Printf("validator address: %s\n", validatorKm.GetAddr()) + // query params + params, err := c0.ABCIQuery("/param/params", []byte{}) + if err != nil { + return xerrors.Errorf("query params error: %w", err) + } + log.Println("params:", string(params.Response.Value)) + // submit proposal + depositCoins := sdkTypes.Coins{sdkTypes.Coin{Denom: "BNB", Amount: 1000e8}} + description := `{"description":"test","bc_params":[{"type":"params/StakeParamSet","value":{"unbonding_time":"600000000000","max_validators":11,"bond_denom":"BNB","min_self_delegation":"100000000","min_delegation_change":"100000000","reward_distribution_batch_size":"1000","max_stake_snapshots":30,"base_proposer_reward_ratio":"1000000","bonus_proposer_reward_ratio":"4000000","fee_from_bsc_to_bc_ratio":"10000000"}}]}` + c0.SetKeyManager(validatorKm) + txRes, err := c0.SubmitProposal("Change parameter", description, msg.ProposalTypeParameterChange, depositCoins, time.Second, rpc.Commit, txWithChainID) + log.Printf("submit proposal tx: %+v, err: %+v", txRes, err) + if err != nil { + return xerrors.Errorf("submit proposal error: %w", err) + } + proposals, err := c0.GetProposals(sdkTypes.StatusNil, 1) + if err != nil { + return xerrors.Errorf("get proposals error: %w", err) + } + proposal := proposals[0] + log.Printf("proposal: %+v", proposal) + txRes, err = c0.Vote(proposal.GetProposalID(), msg.OptionYes, rpc.Commit, txWithChainID) + log.Printf("vote tx: %+v, err: %+v", txRes, err) + if err != nil { + return xerrors.Errorf("vote error: %w", err) + } + // query proposal again + time.Sleep(3 * time.Second) + proposals, err = c0.GetProposals(sdkTypes.StatusNil, 1) + if err != nil { + return xerrors.Errorf("get proposals error: %w", err) + } + proposal = proposals[0] + log.Printf("proposal: %+v", proposal) + assert(proposal.GetStatus() == sdkTypes.StatusPassed, "proposal should be passed") + // query params + params, err = c0.ABCIQuery("/param/params", []byte{}) + if err != nil { + return xerrors.Errorf("query params error: %w", err) + } + log.Println("params:", string(params.Response.Value)) + assert(strings.Contains(string(params.Response.Value), `"unbonding_time":"600000000000"`), "params should be changed") + return nil +} + +func Staking() error { + rand.Seed(time.Now().UnixNano()) + // rpc client + config := getConfigFromEnv() + node0RpcAddr := config.RPCAddr + c0 := rpc.NewRPCClient(node0RpcAddr, sdkTypes.ProdNetwork) + status, err := c0.Status() + chainId := status.NodeInfo.Network + txWithChainID = tx.WithChainID(chainId) + if err != nil { + return xerrors.Errorf("get status error: %w", err) + } + log.Printf("chainId: %s\n", chainId) + log.Printf("node0 status") + log.Println(Pretty(status)) + // bob + validatorSecret := config.Secret + valKM, err := keys.NewMnemonicKeyManager(validatorSecret) + if err != nil { + return xerrors.Errorf("new key manager failed: %w", err) + } + log.Printf("bob address: %s\n", valKM.GetAddr()) + // create a random account + validator0, err := GenKeyManagerWithBNB(c0, valKM) + if err != nil { + return xerrors.Errorf("GenKeyManager err: %w", err) + } + log.Printf("validator0 address: %s\n", validator0.GetAddr()) + // validators + validators, err := c0.GetStakeValidators() + if err != nil { + return xerrors.Errorf("get validators error: %w", err) + } + log.Println(Pretty(validators)) + validatorsLenBeforeCreate := len(validators) + assert(validatorsLenBeforeCreate >= 1, "validators len should be >= 1") + assert(len(validators[0].StakeSnapshots) != 0, "validators stake snapshot should not be 0") + // query validators count (including jailed) + validatorsCount, err := c0.GetAllValidatorsCount(true) + if err != nil { + return xerrors.Errorf("get all validators count error: %w", err) + } + log.Printf("validators count: %d\n", validatorsCount) + // query validators count (excluding jailed) + validatorsCountWithoutJail, err := c0.GetAllValidatorsCount(false) + if err != nil { + return xerrors.Errorf("get all validators count error: %w", err) + } + log.Printf("validators count: %d\n", validatorsCountWithoutJail) + assert(validatorsCount == validatorsCountWithoutJail, "there is no jailed validators yet") + // create validator + amount := sdkTypes.Coin{Denom: "BNB", Amount: 123e8} + des := sdkTypes.Description{Moniker: "node1"} + rate, _ := sdkTypes.NewDecFromStr("1") + maxRate, _ := sdkTypes.NewDecFromStr("1") + maxChangeRate, _ := sdkTypes.NewDecFromStr("1") + consensusPrivKey := ed25519.GenPrivKey() + consensusPubKey := consensusPrivKey.PubKey() + // save consensus key to file for later usage + filePVKey := privval.FilePVKey{ + Address: consensusPubKey.Address(), + PubKey: consensusPubKey, + PrivKey: consensusPrivKey, + } + cdc := amino.NewCodec() + cryptoAmino.RegisterAmino(cdc) + privval.RegisterRemoteSignerMsg(cdc) + jsonBytes, err := cdc.MarshalJSONIndent(filePVKey, "", " ") + if err != nil { + return xerrors.Errorf("marshal json error: %w", err) + } + err = ioutil.WriteFile("priv_validator_key.json", jsonBytes, 0600) + if err != nil { + return xerrors.Errorf("write file error: %w", err) + } + commission := sdkTypes.CommissionMsg{ + Rate: rate, + MaxRate: maxRate, + MaxChangeRate: maxChangeRate, + } + c0.SetKeyManager(validator0) + txRes, err := c0.CreateValidatorOpen(amount, msg.Description(des), commission, sdkTypes.MustBech32ifyConsPub(consensusPubKey), rpc.Commit, tx.WithChainID(chainId)) + if err != nil { + return xerrors.Errorf("create validator error: %w", err) + } + log.Printf("create validator tx: %+v\n", txRes) + assert(txRes.Code == 0, "create validator tx return err") + // check validators change + validatorsCountAfterCreate, err := c0.GetAllValidatorsCount(true) + if err != nil { + return xerrors.Errorf("get all validators count error: %w", err) + } + log.Printf("validators count: %d\n", validatorsCountAfterCreate) + assert(validatorsCountAfterCreate == validatorsCount+1, "validators count should be +1") + // query top validators + topValidators, err := c0.QueryTopValidators(1) + if err != nil { + return xerrors.Errorf("query top validators error: %w", err) + } + log.Printf("top validators: %+v\n", topValidators) + assert(len(topValidators) == 1, "top validators should be 1") + //topValidator := topValidators[0] + // query validator + validator, err := c0.QueryValidator(sdkTypes.ValAddress(validator0.GetAddr())) + if err != nil { + return xerrors.Errorf("query validator error: %w", err) + } + log.Printf("query validator: %+v\n", validator) + assert(validator != nil, "validator should not be nil") + assert(bytes.Equal(validator.OperatorAddr, validator0.GetAddr()), "validator address should be equal") + assert(validator.Tokens.String() == "12300000000", "validator tokens should be 123e8") + assert(validator.Description == des, "validator description should be equal") + assert(validator.Commission.Rate.Equal(rate), "validator rate should be equal") + assert(validator.ConsPubKey == sdkTypes.MustBech32ifyConsPub(consensusPubKey), "validator cons pub key should be equal") + // edit validator + des2 := sdkTypes.Description{Moniker: "node1_v2"} + consensusPrivKey2 := ed25519.GenPrivKey() + consensusPubKey2 := consensusPrivKey2.PubKey() + consensusPubKey2Str := sdkTypes.MustBech32ifyConsPub(consensusPubKey2) + txRes, err = c0.EditValidator(msg.Description(des2), nil, consensusPubKey2Str, rpc.Commit, tx.WithChainID(chainId)) + if err != nil { + return xerrors.Errorf("edit validator error: %w", err) + } + assert(txRes.Code == 0, fmt.Sprintf("edit validator tx return err, tx: %+v", txRes)) + // check edit validator change + validator, err = c0.QueryValidator(sdkTypes.ValAddress(validator0.GetAddr())) + if err != nil { + return xerrors.Errorf("query validator error: %w", err) + } + log.Printf("query validator: %+v\n", validator) + assert(validator != nil, "validator should not be nil") + assert(bytes.Equal(validator.OperatorAddr, validator0.GetAddr()), "validator address should be equal") + assert(validator.Description == des2, "validator description should be equal") + assert(validator.ConsPubKey == consensusPubKey2Str, "validator cons pub key should be equal") + //tokenBeforeDelegate := validator.Tokens + //// delegate + //delegator, err := GenKeyManagerWithBNB(c0, valKM) + //if err != nil { + // return xerrors.Errorf("GenKeyManager err: %w", err) + //} + //c0.SetKeyManager(delegator) + //var delegateAmount int64 = 5e8 + //delegateCoin := sdkTypes.Coin{Denom: "BNB", Amount: delegateAmount} + //txRes, err = c0.Delegate(sdkTypes.ValAddress(validator0.GetAddr()), delegateCoin, rpc.Commit, tx.WithChainID(chainId)) + //if err != nil { + // return xerrors.Errorf("delegate error: %w", err) + //} + //assert(txRes.Code == 0, fmt.Sprintf("delegate tx return err, tx: %+v", txRes)) + //// check delegation + //validator, err = c0.QueryValidator(sdkTypes.ValAddress(validator0.GetAddr())) + //if err != nil { + // return xerrors.Errorf("query validator error: %w", err) + //} + //log.Printf("query validator: %+v\n", validator) + //tokenAfterDelegate := validator.Tokens + //assert(tokenAfterDelegate.Sub(tokenBeforeDelegate).Equal(sdkTypes.NewDec(delegateAmount)), "delegate tokens should be equal") + //// query delegation + //delegationQuery, err := c0.QueryDelegation(delegator.GetAddr(), sdkTypes.ValAddress(validator0.GetAddr())) + //if err != nil { + // return xerrors.Errorf("query delegation error: %w", err) + //} + //log.Printf("query delegation: %+v\n", delegationQuery) + //assert(delegationQuery.Delegation.Shares.Equal(sdkTypes.NewDec(delegateAmount)), "delegation shares should be equal") + //assert(delegationQuery.Balance.IsEqual(delegateCoin), "delegation balance should be equal") + //// query delegations + //delegations, err := c0.QueryDelegations(delegator.GetAddr()) + //if err != nil { + // return xerrors.Errorf("query delegations error: %w", err) + //} + //log.Printf("query delegations: %+v\n", delegations) + //// check redelegate preparation + //topValAddr := topValidator.OperatorAddr + //validator0Addr := sdkTypes.ValAddress(validator0.GetAddr()) + //topValidatorBeforeRedelegate, err := c0.QueryValidator(topValAddr) + //if err != nil { + // return xerrors.Errorf("query validator error: %w", err) + //} + //log.Printf("top validator before redelegate: %+v\n", topValidatorBeforeRedelegate) + //// redelegate from validator0 to top validator, should success immediately + //var redelegateAmount int64 = 2e8 + //redelegateCoin := sdkTypes.Coin{Denom: "BNB", Amount: redelegateAmount} + //c0.SetKeyManager(delegator) + //txRes, err = c0.Redelegate(validator0Addr, topValAddr, redelegateCoin, rpc.Commit, tx.WithChainID(chainId)) + //if err != nil { + // return xerrors.Errorf("redelegate error: %w", err) + //} + //assert(txRes.Code == 0, fmt.Sprintf("redelegate tx return err, tx: %+v", txRes)) + //topValidatorAfterRedelegate, err := c0.QueryValidator(topValAddr) + //if err != nil { + // return xerrors.Errorf("query validator error: %w", err) + //} + //log.Printf("top validator after redelegate: %+v\n", topValidatorAfterRedelegate) + //assert(topValidatorAfterRedelegate.Tokens.Sub(topValidatorBeforeRedelegate.Tokens).Equal(sdkTypes.NewDec(redelegateAmount)), "redelegate tokens should be equal") + //// undelegate + //c0.SetKeyManager(delegator) + //txRes, err = c0.Undelegate(topValAddr, redelegateCoin, rpc.Commit, tx.WithChainID(chainId)) + //if err != nil { + // return xerrors.Errorf("undelegate error: %w", err) + //} + //assert(txRes.Code == 0, fmt.Sprintf("undelegate tx return err, tx: %+v", txRes)) + //topValidatorAfterUndelegate, err := c0.QueryValidator(topValAddr) + //if err != nil { + // return xerrors.Errorf("query validator error: %w", err) + //} + //log.Printf("top validator after undelegate: %+v\n", topValidatorAfterUndelegate) + //assert(topValidatorAfterUndelegate.Tokens.Equal(topValidatorBeforeRedelegate.Tokens), "check undelegation token change") + //// query pool + //pool, err := c0.GetPool() + //if err != nil { + // return xerrors.Errorf("get pool error: %w", err) + //} + //log.Printf("pool: %+v\n", pool) + //// query unbonding delegation + //unbondingDelegation, err := c0.QueryUnbondingDelegation(topValAddr, delegator.GetAddr()) + //log.Printf("query unbonding delegation: %+v, err: %v\n", unbondingDelegation, err) + //if err != nil { + // return xerrors.Errorf("query unbonding delegation error: %w", err) + //} + //// query unbonding delegations + //unbondingDelegations, err := c0.QueryUnbondingDelegations(delegator.GetAddr()) + //log.Printf("query unbonding delegations: %+v, err: %v\n", unbondingDelegations, err) + //if err != nil { + // return xerrors.Errorf("query unbonding delegations error: %w", err) + //} + //// query unbonding delegations by validator + //unbondingDelegationsByValidator, err := c0.GetUnBondingDelegationsByValidator(topValAddr) + //log.Printf("query unbonding delegations by validator: %+v, err: %v\n", unbondingDelegationsByValidator, err) + //if err != nil { + // return xerrors.Errorf("query unbonding delegations by validator error: %w", err) + //} + //// delegate to top validator and then redelegate + //delegator0, err := GenKeyManagerWithBNB(c0, valKM) + //if err != nil { + // return xerrors.Errorf("GenKeyManager err: %w", err) + //} + //c0.SetKeyManager(delegator0) + //txRes, err = c0.Delegate(topValAddr, delegateCoin, rpc.Commit, tx.WithChainID(chainId)) + //log.Printf("delegate to top validator tx: %+v, err: %v\n", txRes, err) + //if err != nil { + // return xerrors.Errorf("delegate error: %w", err) + //} + //assert(txRes.Code == 0, fmt.Sprintf("delegate tx return err, tx: %+v", txRes)) + //c0.SetKeyManager(delegator0) + //log.Printf("dest validator: %+v\n", topValAddr) + //log.Printf("validator0 val address: %+v\n", sdkTypes.ValAddress(validator0.GetAddr())) + //log.Printf("delegator address: %+v\n", delegator0.GetAddr()) + //txRes, err = c0.Redelegate(topValAddr, sdkTypes.ValAddress(validator0.GetAddr()), delegateCoin, rpc.Commit, tx.WithChainID(chainId)) + //log.Printf("redelegate to validator0 tx: %+v, err: %v\n", txRes, err) + //if err != nil { + // return xerrors.Errorf("redelegate error: %w", err) + //} + //assert(txRes.Code == 0, fmt.Sprintf("redelegate tx return err, tx: %+v", txRes)) + //// query redelegation + //redelegation, err := c0.QueryRedelegation(delegator0.GetAddr(), topValAddr, sdkTypes.ValAddress(validator0.GetAddr())) + //log.Printf("query redelegation: %+v, err: %v\n", redelegation, err) + //if err != nil { + // return xerrors.Errorf("query redelegation error: %w", err) + //} + //assert(redelegation != nil, "redelegation should not be nil") + //// query redelegations + //redelegations, err := c0.QueryRedelegations(delegator0.GetAddr()) + //log.Printf("query redelegations: %+v, err: %v\n", redelegations, err) + //if err != nil { + // return xerrors.Errorf("query redelegations error: %w", err) + //} + //assert(len(redelegations) > 0, "redelegations should not be empty") + //// query redelegations by source validator + //redelegationsByValidator, err := c0.GetRedelegationsByValidator(topValAddr) + //log.Printf("query redelegations by validator: %+v, err: %v\n", redelegationsByValidator, err) + //if err != nil { + // return xerrors.Errorf("query redelegations by validator error: %w", err) + //} + //assert(len(redelegationsByValidator) > 0, "redelegations by validator should not be empty") + // validator self undelegate under selfMinDelegation + valAccAddr := validator0.GetAddr() + valValAddr := sdkTypes.ValAddress(valAccAddr) + val, err := c0.QueryDelegation(valAccAddr, valValAddr) + if err != nil { + return xerrors.Errorf("query delegation error: %w", err) + } + log.Printf("validator delegation: %+v", val) + amt, err := strconv.ParseInt(val.Shares.String(), 10, 64) + if err != nil { + return xerrors.Errorf("shares marshal error: %w", err) + } + coin := sdkTypes.Coin{Denom: "BNB", Amount: amt - 1} + c0.SetKeyManager(validator0) + txRes, err = c0.Undelegate(valValAddr, coin, rpc.Commit, tx.WithChainID(chainId)) + assert(err == nil, fmt.Sprintf("undelegate error: %v", err)) + assert(txRes.Code == 0, fmt.Sprintf("undelegate tx return err, tx: %+v", txRes)) + // check jailed + validator, err = c0.QueryValidator(valValAddr) + if err != nil { + return xerrors.Errorf("query validator error: %w", err) + } + log.Printf("validator: %+v", validator) + assert(validator.Jailed, "validator should be jailed") + // unjail + c0.SetKeyManager(validator0) + txRes, err = c0.Unjail(valValAddr, rpc.Commit, tx.WithChainID(chainId)) + log.Printf("unjail tx: %+v, err: %v\n", txRes, err) + assert(err == nil && txRes.Code != 0, "unjail should return error") + assert(strings.Contains(txRes.Log, "validator's self delegation less than minimum; cannot be unjailed"), "unjail should return error") + // delegate again + c0.SetKeyManager(valKM) + transfer := msg.Transfer{ToAddr: valAccAddr, Coins: sdkTypes.Coins{coin}} + txRes, err = c0.SendToken([]msg.Transfer{transfer}, rpc.Commit, tx.WithChainID(chainId)) + assert(err == nil && txRes.Code == 0, fmt.Sprintf("send token tx: %+v, error: %v", txRes, err)) + c0.SetKeyManager(validator0) + txRes, err = c0.Delegate(valValAddr, coin, rpc.Commit, tx.WithChainID(chainId)) + log.Printf("delegate to validator tx: %+v, err: %v\n", txRes, err) + assert(err == nil && txRes.Code == 0, "delegate should not return error") + // unjail again + txRes, err = c0.Unjail(valValAddr, rpc.Commit, tx.WithChainID(chainId)) + log.Printf("unjail tx: %+v, err: %v\n", txRes, err) + assert(err == nil && txRes.Code != 0, "unjail should return error") + assert(strings.Contains(txRes.Log, "validator still jailed, cannot yet be unjailed"), "unjail should return error") + // change parameter, wait enough time, unjail again should success + //time.Sleep(60 * time.Second) + //txRes, err = c0.Unjail(valValAddr, rpc.Commit, tx.WithChainID(chainId)) + //log.Printf("unjail tx: %+v, err: %v\n", txRes, err) + //assert(err == nil && txRes.Code == 0, "unjail should not return error") + //// check jailed again + //validator, err = c0.QueryValidator(valValAddr) + //if err != nil { + // return xerrors.Errorf("query validator error: %w", err) + //} + //log.Printf("validator: %+v", validator) + //assert(!validator.Jailed, "validator should not be jailed") + return nil +} + +//nolint +func UndelegateTest() error { + rand.Seed(time.Now().UnixNano()) + // rpc client + config := getConfigFromEnv() + node0RpcAddr := config.RPCAddr + c0 := rpc.NewRPCClient(node0RpcAddr, sdkTypes.ProdNetwork) + status, err := c0.Status() + chainId := status.NodeInfo.Network + txWithChainID = tx.WithChainID(chainId) + if err != nil { + return xerrors.Errorf("get status error: %w", err) + } + log.Printf("chainId: %s\n", chainId) + log.Printf("node0 status") + log.Println(Pretty(status)) + // bob + validatorSecret := config.Secret + valKM, err := keys.NewMnemonicKeyManager(validatorSecret) + if err != nil { + return xerrors.Errorf("new key manager failed: %w", err) + } + log.Printf("bob address: %s\n", valKM.GetAddr()) + validators, err := c0.QueryTopValidators(10) + if err != nil { + return xerrors.Errorf("query validators error: %w", err) + } + log.Printf("validators: %s", Pretty(validators)) + log.Printf("validator count: %d", len(validators)) + // create a random account + validator0, err := GenKeyManagerWithBNB(c0, valKM) + if err != nil { + return xerrors.Errorf("GenKeyManager err: %w", err) + } + log.Printf("validator0 address: %s\n", validator0.GetAddr()) + // create validator + amount := sdkTypes.Coin{Denom: "BNB", Amount: 123e8} + des := sdkTypes.Description{Moniker: "node1"} + rate, _ := sdkTypes.NewDecFromStr("1") + maxRate, _ := sdkTypes.NewDecFromStr("1") + maxChangeRate, _ := sdkTypes.NewDecFromStr("1") + consensusPrivKey := ed25519.GenPrivKey() + consensusPubKey := consensusPrivKey.PubKey() + // save consensus key to file for later usage + filePVKey := privval.FilePVKey{ + Address: consensusPubKey.Address(), + PubKey: consensusPubKey, + PrivKey: consensusPrivKey, + } + cdc := amino.NewCodec() + cryptoAmino.RegisterAmino(cdc) + privval.RegisterRemoteSignerMsg(cdc) + jsonBytes, err := cdc.MarshalJSONIndent(filePVKey, "", " ") + if err != nil { + return xerrors.Errorf("marshal json error: %w", err) + } + err = ioutil.WriteFile("priv_validator_key.json", jsonBytes, 0600) + if err != nil { + return xerrors.Errorf("write file error: %w", err) + } + commission := sdkTypes.CommissionMsg{ + Rate: rate, + MaxRate: maxRate, + MaxChangeRate: maxChangeRate, + } + c0.SetKeyManager(validator0) + txRes, err := c0.CreateValidatorOpen(amount, msg.Description(des), commission, sdkTypes.MustBech32ifyConsPub(consensusPubKey), rpc.Commit, tx.WithChainID(chainId)) + if err != nil { + return xerrors.Errorf("create validator error: %w", err) + } + log.Printf("create validator tx: %+v\n", txRes) + assert(txRes.Code == 0, "create validator tx return err") + err = BackgroundTx(c0, valKM, time.Minute) + if err != nil { + return xerrors.Errorf("BackgroundTx error: %w", err) + } + c0.SetKeyManager(validator0) + txRes, err = c0.Undelegate(sdkTypes.ValAddress(validator0.GetAddr()), amount, rpc.Commit, tx.WithChainID(chainId)) + if err != nil { + return xerrors.Errorf("undelegate error: %w", err) + } + log.Printf("undelegate tx: %+v\n", txRes) + err = BackgroundTx(c0, valKM, time.Minute) + if err != nil { + return xerrors.Errorf("BackgroundTx error: %w", err) + } + return nil +} + +func BackgroundTx(c0 *rpc.HTTP, km keys.KeyManager, duration time.Duration) error { + newKm, err := GenKeyManagerWithBNB(c0, km) + if err != nil { + return xerrors.Errorf("GenKeyManager err: %w", err) + } + startTime := time.Now() + for { + if time.Since(startTime) > 3*time.Minute { + return nil + } + c0.SetKeyManager(km) + transfer := msg.Transfer{ToAddr: newKm.GetAddr(), Coins: sdkTypes.Coins{sdkTypes.Coin{ + Denom: "BNB", + Amount: 10, + }}} + txRes, err := c0.SendToken([]msg.Transfer{transfer}, rpc.Commit, txWithChainID) + if err != nil { + return xerrors.Errorf("send token error: %w", err) + } + assert(txRes.Code == 0, fmt.Sprintf("send token error, tx: %+v", txRes)) + validators, err := c0.QueryTopValidators(10) + if err != nil { + return xerrors.Errorf("query validators error: %w", err) + } + log.Printf("validators: %s", Pretty(validators)) + log.Printf("validator count: %d", len(validators)) + time.Sleep(1 * time.Second) + } +} + +func assert(cond bool, msg string) { + if !cond { + panic(msg) + } +} + +func Pretty(v interface{}) string { + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + panic(err) + } + return string(b) +} diff --git a/common/upgrade/upgrade.go b/common/upgrade/upgrade.go index da3081024..cd281349d 100644 --- a/common/upgrade/upgrade.go +++ b/common/upgrade/upgrade.go @@ -1,6 +1,8 @@ package upgrade -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) var Mgr = sdk.UpgradeMgr @@ -37,10 +39,12 @@ const ( BEP87 = "BEP87" // https://github.com/bnb-chain/BEPs/pull/87 FixFailAckPackage = sdk.FixFailAckPackage - BEP128 = sdk.BEP128 // https://github.com/bnb-chain/BEPs/pull/128 Staking reward distribution upgrade - BEP151 = "BEP151" // https://github.com/bnb-chain/BEPs/pull/151 Decommission Decentralized Exchange - BEP153 = sdk.BEP153 // https://github.com/bnb-chain/BEPs/pull/153 Native Staking - BEP173 = sdk.BEP173 // https://github.com/bnb-chain/BEPs/pull/173 Text Proposal + BEP128 = sdk.BEP128 // https://github.com/bnb-chain/BEPs/pull/128 Staking reward distribution upgrade + BEP151 = "BEP151" // https://github.com/bnb-chain/BEPs/pull/151 Decommission Decentralized Exchange + BEP153 = sdk.BEP153 // https://github.com/bnb-chain/BEPs/pull/153 Native Staking + BEP159 = sdk.BEP159 // https://github.com/bnb-chain/BEPs/pull/159 New Staking Mechanism + BEP159Phase2 = sdk.BEP159Phase2 + BEP173 = sdk.BEP173 // https://github.com/bnb-chain/BEPs/pull/173 Text Proposal ) func UpgradeBEP10(before func(), after func()) { diff --git a/go.mod b/go.mod index ad43ab5df..4dc96e1c0 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.17 require ( github.com/Shopify/sarama v1.21.0 + github.com/binance-chain/go-sdk v1.2.7 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 @@ -14,15 +15,17 @@ require ( github.com/linkedin/goavro v0.0.0-20180427201934-fa8f6a30176c 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/pkg/errors v0.9.1 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/stretchr/testify v1.5.1 github.com/tendermint/go-amino v0.15.0 github.com/tendermint/iavl v0.12.4 github.com/tendermint/tendermint v0.32.3 + github.com/tidwall/gjson v1.14.3 go.uber.org/ratelimit v0.1.0 + golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f ) require ( @@ -30,6 +33,7 @@ require ( github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.1 // indirect github.com/btcsuite/btcd v0.20.1-beta // indirect github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d // indirect github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect @@ -67,12 +71,15 @@ require ( github.com/spf13/pflag v1.0.3 // indirect github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d // indirect github.com/tendermint/btcd v0.1.1 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/zondax/hid v0.9.0 // indirect github.com/zondax/ledger-cosmos-go v0.9.9 // indirect - golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect - golang.org/x/net v0.0.0-20191021144547-ec77196f6094 // indirect - golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect - golang.org/x/text v0.3.2 // indirect + github.com/zondax/ledger-go v0.9.0 // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/net v0.3.0 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb // indirect google.golang.org/grpc v1.23.0 // indirect gopkg.in/linkedin/goavro.v1 v1.0.5 // indirect @@ -81,10 +88,11 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/bnb-chain/bnc-cosmos-sdk v0.25.5 + github.com/binance-chain/go-sdk => github.com/owen-reorg/bnc-go-sdk v0.0.0-20221130201638-e8d0681a81e4 + github.com/cosmos/cosmos-sdk => github.com/bnb-chain/bnc-cosmos-sdk v0.25.4-0.20221221115251-f9e69ff1b273 github.com/tendermint/go-amino => github.com/bnb-chain/bnc-go-amino v0.14.1-binance.2 github.com/tendermint/iavl => github.com/bnb-chain/bnc-tendermint-iavl v0.12.0-binance.4 - github.com/tendermint/tendermint => github.com/bnb-chain/bnc-tendermint v0.32.3-binance.7 + github.com/tendermint/tendermint => github.com/bnb-chain/bnc-tendermint v0.32.3-binance.3.0.20221109023026-379ddbab19d1 github.com/zondax/ledger-cosmos-go => github.com/bnb-chain/ledger-cosmos-go v0.9.9-binance.3 golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae ) diff --git a/go.sum b/go.sum index 9ae275cff..15cd70780 100644 --- a/go.sum +++ b/go.sum @@ -22,12 +22,14 @@ 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/bnb-chain/bnc-cosmos-sdk v0.25.5 h1:DGVVWy4f/gmfpJErJpnmY04mSvL+kcoOu355/YGhaN8= -github.com/bnb-chain/bnc-cosmos-sdk v0.25.5/go.mod h1:+0MJRhSM5hb/ZvvoWOVt7LaihYM1Ax+PxnAMK/lHHUs= +github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.1 h1:8mAtw1Tp/BhhTrsXmXM60H1fihcvcKLfo2ZSxShaXKw= +github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.1/go.mod h1:FI6WAujuiBpoSavYreux2zTKyrUkngXDlRJczxsDK5M= +github.com/bnb-chain/bnc-cosmos-sdk v0.25.4-0.20221221115251-f9e69ff1b273 h1:kfUgCOr+C81J6mHJeR0JgFcHTH8/jiMuYCdYPMfIfWU= +github.com/bnb-chain/bnc-cosmos-sdk v0.25.4-0.20221221115251-f9e69ff1b273/go.mod h1:PwnW2N20xpAqZ8PW+BajCUTX/CHDkB90A3Hl7jT1CUU= 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-binance.7 h1:wJBrhLAm9P+Jjm/clTxynAZJl63xD7LatKmL5e3YzbY= -github.com/bnb-chain/bnc-tendermint v0.32.3-binance.7/go.mod h1:EJSMv0Dh5v91CiHn+2pOnl1a3sdRVjpdekJ20AyYmlQ= +github.com/bnb-chain/bnc-tendermint v0.32.3-binance.3.0.20221109023026-379ddbab19d1 h1:+Bv9DlvDYUMBXipfqyuvUJeuwkAzFFdQhxmalWj0+Lk= +github.com/bnb-chain/bnc-tendermint v0.32.3-binance.3.0.20221109023026-379ddbab19d1/go.mod h1:EJSMv0Dh5v91CiHn+2pOnl1a3sdRVjpdekJ20AyYmlQ= github.com/bnb-chain/bnc-tendermint-iavl v0.12.0-binance.4 h1:w8pAAx1N0lmVf0Lxs1prYuDikXwirOb9T7y2yw8zOBw= github.com/bnb-chain/bnc-tendermint-iavl v0.12.0-binance.4/go.mod h1:Zmh8GRdNJB8DULIOBar3JCZp6tSpcvM1NGKfE9U2EzA= github.com/bnb-chain/ledger-cosmos-go v0.9.9-binance.3 h1:a+QLVLaP32v9gfRDKHH2AcRkzYLTWbC8UxYTJkXRSec= @@ -148,6 +150,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/linkedin/goavro v0.0.0-20180427201934-fa8f6a30176c h1:5VZFnez+6M7nwhbIT8L4DtViRFR8GpYpZj97EVAphuk= @@ -178,17 +181,21 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/gomega v1.4.3/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= +github.com/owen-reorg/bnc-go-sdk v0.0.0-20221130201638-e8d0681a81e4 h1:R+oZ2pVJrf4vBzqO5pBkuQDoGCz7OfoS4acrvjd57/o= +github.com/owen-reorg/bnc-go-sdk v0.0.0-20221130201638-e8d0681a81e4/go.mod h1:Et944AMlNUod/ir1/P3kkvYY5xq4bcE6HF6LM+SiSN8= 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= github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.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/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= @@ -198,11 +205,13 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 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.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 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-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 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= @@ -242,23 +251,35 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ 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/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= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/syndtr/goleveldb v0.0.0-20181105012736-f9080354173f/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/tendermint/btcd v0.0.0-20180816174608-e5840949ff4f/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= 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-20190823183015-45b1026d81ae h1:AOXNM7c2Vvo45SjAgeWF8Wy+NS7/NCqzRNpUc+HPAec= github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= +github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= +github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= +github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 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= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-go v0.9.0 h1:oTrtFqPFA4VdCPRvqMaN45mQnJxkPc0JxoVZfCoUpjI= +github.com/zondax/ledger-go v0.9.0/go.mod h1:b2vIcu3u9gJoIx4kTWuXOgzGV7FPWeUktqRqVf6feG0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -272,18 +293,24 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/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-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -291,6 +318,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -299,14 +327,21 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h 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/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= 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= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -315,6 +350,11 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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= @@ -323,6 +363,7 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8 google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 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= @@ -336,6 +377,7 @@ gopkg.in/linkedin/goavro.v1 v1.0.5 h1:BJa69CDh0awSsLUmZ9+BowBdokpduDZSM9Zk8oKHfN gopkg.in/linkedin/goavro.v1 v1.0.5/go.mod h1:Aw5GdAbizjOEl0kAMHV9iHmA8reZzW/OKuJAl4Hb9F0= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.10.3/go.mod h1:nrgQYbPhkRfn2BfT32NNTLfq3K9NuHRB0MsAcA9weWY= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 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= diff --git a/networks/demo/create-validator-open.exp b/networks/demo/create-validator-open.exp new file mode 100644 index 000000000..d2845626c --- /dev/null +++ b/networks/demo/create-validator-open.exp @@ -0,0 +1,12 @@ +#!/usr/bin/expect + +set home [lindex $argv 0] +set from [lindex $argv 1] +set chain_id [lindex $argv 2] +set pubkey [lindex $argv 3] + +set timeout 30 + spawn ./bnbcli staking create-validator-open --home $home --from $from --chain-id=$chain_id --amount 2000000000000:BNB --pubkey $pubkey --moniker bob --commission-rate 1 --commission-max-rate 1 --commission-max-change-rate 1 + expect "Password*" + send "12345678\r" +expect eof diff --git a/networks/demo/delegate.exp b/networks/demo/delegate.exp new file mode 100644 index 000000000..40a9557f0 --- /dev/null +++ b/networks/demo/delegate.exp @@ -0,0 +1,13 @@ +#!/usr/bin/expect + +set home [lindex $argv 0] +set from [lindex $argv 1] +set chain_id [lindex $argv 2] +set amount [lindex $argv 3] +set validator_addr [lindex $argv 4] + +set timeout 30 + spawn ./bnbcli staking delegate --home $home --from $from --chain-id=$chain_id --amount $amount --validator $validator_addr + expect "Password*" + send "12345678\r" +expect eof diff --git a/networks/demo/edit-validator.exp b/networks/demo/edit-validator.exp new file mode 100644 index 000000000..46e0be40e --- /dev/null +++ b/networks/demo/edit-validator.exp @@ -0,0 +1,12 @@ +#!/usr/bin/expect + +set home [lindex $argv 0] +set from [lindex $argv 1] +set chain_id [lindex $argv 2] +set pubkey [lindex $argv 3] + +set timeout 30 + spawn ./bnbcli staking edit-validator --home $home --from $from --chain-id=$chain_id --moniker bob-new --pubkey $pubkey + expect "Password*" + send "12345678\r" +expect eof diff --git a/networks/demo/redelegate.exp b/networks/demo/redelegate.exp new file mode 100644 index 000000000..c232be4ef --- /dev/null +++ b/networks/demo/redelegate.exp @@ -0,0 +1,14 @@ +#!/usr/bin/expect + +set home [lindex $argv 0] +set from [lindex $argv 1] +set chain_id [lindex $argv 2] +set amount [lindex $argv 3] +set validator_addr_src [lindex $argv 4] +set validator_addr_dst [lindex $argv 5] + +set timeout 30 + spawn ./bnbcli staking redelegate --home $home --from $from --chain-id=$chain_id --amount $amount --addr-validator-source $validator_addr_src --addr-validator-dest $validator_addr_dst + expect "Password*" + send "12345678\r" +expect eof diff --git a/networks/demo/undelegate.exp b/networks/demo/undelegate.exp new file mode 100644 index 000000000..f53cf2085 --- /dev/null +++ b/networks/demo/undelegate.exp @@ -0,0 +1,13 @@ +#!/usr/bin/expect + +set home [lindex $argv 0] +set from [lindex $argv 1] +set chain_id [lindex $argv 2] +set amount [lindex $argv 3] +set validator_addr [lindex $argv 4] + +set timeout 30 + spawn ./bnbcli staking undelegate --home $home --from $from --chain-id=$chain_id --amount $amount --validator $validator_addr + expect "Password*" + send "12345678\r" +expect eof diff --git a/scripts/bep159_cli_integration_test.sh b/scripts/bep159_cli_integration_test.sh new file mode 100755 index 000000000..54e73c76c --- /dev/null +++ b/scripts/bep159_cli_integration_test.sh @@ -0,0 +1,213 @@ +#!/bin/bash + +set -ex + +cd ./build +if [ $? -ne 0 ]; then + echo "path build does not exists" + exit 1 +fi + +cli_home="./testnodecli" +home="./testnoded" +chain_id="bnbchain-1000" + +keys_operation_words="bnb" +chain_operation_words="Committed" + +function prepare_node() { + cp -f ../networks/demo/*.exp . + + rm -rf ${cli_home} + rm -rf ${home} + mkdir ${cli_home} + mkdir ${home} + + secret=$(./bnbchaind init --moniker testnode --home ${home} --home-client ${cli_home} --chain-id ${chain_id} | grep secret | grep -o ":.*" | grep -o "\".*" | sed "s/\"//g") + echo ${secret} > ${home}/secret + + $(cd "./${home}/config" && sed -i -e "s/BEP12Height = 9223372036854775807/BEP12Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP3Height = 9223372036854775807/BEP3Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/timeout_commit = \"1s\"/timeout_commit = \"500ms\"/g" config.toml) + $(cd "./${home}/config" && sed -i -e "s/log_level = \"main\:info,state\:info,\*\:error\"/log_level = \"*\:debug\"/g" config.toml) + $(cd "./${home}/config" && sed -i -e "s/\"min_self_delegation\": \"1000000000000\"/\"min_self_delegation\": \"10000000000\"/g" genesis.json) + $(cd "./${home}/config" && sed -i -e "s/BEP3Height = 9223372036854775807/BEP3Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP8Height = 9223372036854775807/BEP8Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP67Height = 9223372036854775807/BEP67Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP82Height = 9223372036854775807/BEP82Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP84Height = 9223372036854775807/BEP84Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP87Height = 9223372036854775807/BEP87Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/FixFailAckPackageHeight = 9223372036854775807/FixFailAckPackageHeight = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/EnableAccountScriptsForCrossChainTransferHeight = 9223372036854775807/EnableAccountScriptsForCrossChainTransferHeight = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP70Height = 9223372036854775807/BEP70Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP128Height = 9223372036854775807/BEP128Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP151Height = 9223372036854775807/BEP151Height = 1/g" app.toml) + $(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) + + # stop and start node + ps -ef | grep bnbchaind | grep testnoded | awk '{print $2}' | xargs kill -9 + ./bnbchaind start --home ${home} > ./testnoded/node.log 2>&1 & + + echo ${secret} +} + +function exit_test() { + # stop node + ps -ef | grep bnbchaind | grep testnoded | awk '{print $2}' | xargs kill -9 + exit $1 +} + +function check_operation() { + printf "\n=================== Checking $1 ===================\n" + echo "$2" + + echo "$2" | grep -q $3 + if [ $? -ne 0 ]; then + echo "Checking $1 Failed" + exit_test 1 + fi +} + +secret=$(prepare_node) +result=$(expect ./recover.exp "${secret}" "alice" true) +check_operation "Recover Key" "${result}" "${keys_operation_words}" + +bob_secret="bottom quick strong ranch section decide pepper broken oven demand coin run jacket curious business achieve mule bamboo remain vote kid rigid bench rubber" +bob_val_addr=bva1ddt3ls9fjcd8mh69ujdg3fxc89qle2a7k8spre +result=$(expect ./recover.exp "${bob_secret}" "bob" true) +check_operation "Add Key" "${result}" "${keys_operation_words}" +carl_secret="mad calm portion vendor fine weather thunder ensure simple fish enrich genre plate kind minor random where crop hero soda isolate pelican provide chimney" +result=$(expect ./recover.exp "${carl_secret}" "carl" true) +check_operation "Add Key" "${result}" "${keys_operation_words}" +# wait for the chain +sleep 10s + +alice_addr=$(./bnbcli keys list --home ${cli_home} | grep alice | grep -o "bnb1[0-9a-zA-Z]*") +bob_addr=$(./bnbcli keys list --home ${cli_home} | grep bob | grep -o "bnb1[0-9a-zA-Z]*") +carl_addr=$(./bnbcli keys list --home ${cli_home} | grep carl | grep -o "bnb1[0-9a-zA-Z]*") + +# send +result=$(expect ./send.exp ${cli_home} alice ${chain_id} "100000000000000:BNB" ${bob_addr}) +check_operation "Send Token" "${result}" "${chain_operation_words}" +sleep 2 +result=$(expect ./send.exp ${cli_home} alice ${chain_id} "10000000000:BNB" ${carl_addr}) +check_operation "Send Token" "${result}" "${chain_operation_words}" +sleep 2 + +#$ ./bnbcli --home ./testnodecli staking -h +#staking commands +# +#Usage: +# bnbcli staking [command] +# +#Available Commands: +# create-validator create new validator initialized with a self-delegation to it +# remove-validator remove validator +# edit-validator edit and existing validator account +# delegate delegate liquid tokens to a validator +# redelegate redelegate illiquid tokens from one validator to another +# unbond unbond shares from a validator +# +# validator Query a validator +# validators Query for all validators +# parameters Query the current staking parameters information +# delegation Query a delegation based on address and validator address +# delegations Query all delegations made from one delegator +# pool Query the current staking pool values +# redelegation Query a redelegation record based on delegator and a source and destination validator address +# redelegations Query all redelegations records for one delegator +# unbonding-delegation Query an unbonding-delegation record based on delegator and validator address +# unbonding-delegations Query all unbonding-delegations records for one delegator +# +#Flags: +# -h, --help help for staking +# +#Global Flags: +# -e, --encoding string Binary encoding (hex|b64|btc) (default "hex") +# --home string directory for config and data (default "/Users/owen/.bnbcli") +# -o, --output string Output format (text|json) (default "text") +# --trace print out full stack trace on errors +# +#Use "bnbcli staking [command] --help" for more information about a command. + +# get parameters +result=$(./bnbcli staking parameters --home ${cli_home} --trust-node) +check_operation "Query Staking Parameters" "${result}" "proposer" + +# get validators +result=$(./bnbcli staking validators --home ${cli_home} --trust-node) +check_operation "Get Validators" "${result}" "Operator" + +# get validator +operator_address=$(echo "${result}" | grep Operator | grep -o "bva[0-9a-zA-Z]*" | head -n1) +result=$(./bnbcli staking validator ${operator_address} --home ${cli_home} --trust-node) +check_operation "Get Validator" "${result}" "Operator" + +# get delegations +result=$(./bnbcli staking delegations ${alice_addr} --home ${cli_home} --trust-node) +check_operation "Get Delegations" "${result}" "Validator" + +# get delegation +validator_address=$(echo "${result}" | grep Validator | grep -o "bva[0-9a-zA-Z]*") +delegator_address=$(echo "${result}" | grep Delegator | grep -o "bnb1[0-9a-zA-Z]*") +result=$(./bnbcli staking delegation --address-delegator ${delegator_address} --validator ${validator_address} --home ${cli_home} --trust-node) +check_operation "Get Delegation" "${result}" "Validator" + +# get pool +result=$(./bnbcli staking pool --home ${cli_home} --trust-node) + +# create validator +result=$(expect ./create-validator-open.exp ${cli_home} bob ${chain_id}) +check_operation "create validator open" "${result}" "${chain_operation_words}" +sleep 2 +result=$(./bnbcli staking validator ${bob_val_addr} --home ${cli_home} --trust-node) +check_operation "Get Validators" "${result}" "bob" + +# edit validator +result=$(expect ./edit-validator.exp ${cli_home} bob ${chain_id}) +check_operation "edit validator" "${result}" "${chain_operation_words}" +sleep 2 +result=$(./bnbcli staking validator ${bob_val_addr} --home ${cli_home} --trust-node) +check_operation "Get Validators" "${result}" "bob-new" +bob_val_addr=$(echo "${result}" | grep Operator | grep -o "bva[0-9a-zA-Z]*") + +# delegate +result=$(expect ./delegate.exp ${cli_home} carl ${chain_id} "1000000000:BNB" ${validator_address}) +check_operation "delegate" "${result}" "${chain_operation_words}" +sleep 2 +result=$(./bnbcli staking delegation --address-delegator ${carl_addr} --validator ${validator_address} --home ${cli_home} --trust-node) +check_operation "Get Delegation" "${result}" "Validator" + +# redelegate +result=$(expect ./redelegate.exp ${cli_home} carl ${chain_id} "600000000:BNB" ${validator_address} ${bob_val_addr}) +check_operation "redelegate" "${result}" "${chain_operation_words}" +sleep 2 + +# undelegate +result=$(expect ./undelegate.exp ${cli_home} carl ${chain_id} "400000000:BNB" ${validator_address}) +check_operation "undelegate" "${result}" "${chain_operation_words}" +sleep 2 + +# get redelegations +result=$(./bnbcli staking redelegations ${carl_addr} --home ${cli_home} --trust-node) +check_operation "Get Redelegations" "${result}" "delegator_addr" + +# get redelegation +result=$(./bnbcli staking redelegation --address-delegator ${carl_addr} --addr-validator-source ${validator_address} --addr-validator-dest ${bob_val_addr} --home ${cli_home} --trust-node) +check_operation "Get Redelegation" "${result}" "Delegator" + +# get unbonding-delegations +result=$(./bnbcli staking unbonding-delegations ${carl_addr} --home ${cli_home} --trust-node) +check_operation "Get Unbonding-Delegations" "${result}" "delegator_addr" + +# get unbonding-delegation +result=$(./bnbcli staking unbonding-delegation --address-delegator ${carl_addr} --validator ${validator_address} --home ${cli_home} --trust-node) +check_operation "Get Unbonding-Delegation" "${result}" "Delegator" + +go run ../cmd/test_client + +echo '-----bep159 integration test done-----' +exit_test 0 diff --git a/scripts/bep159_integration_test.sh b/scripts/bep159_integration_test.sh new file mode 100755 index 000000000..0ab5db389 --- /dev/null +++ b/scripts/bep159_integration_test.sh @@ -0,0 +1,186 @@ +#!/bin/bash + +set -ex + +cd ./build +if [ $? -ne 0 ]; then + echo "path build does not exists" + exit 1 +fi + +cli_home="./testnodecli" +home="./testnoded" +chain_id="bnbchain-1000" + +keys_operation_words="bnb" +chain_operation_words="Committed" + +function prepare_node() { + cp -f ../networks/demo/*.exp . + + rm -rf ${cli_home} + rm -rf ${home} + mkdir ${cli_home} + mkdir ${home} + + secret=$(./bnbchaind init --moniker testnode --home ${home} --home-client ${cli_home} --chain-id ${chain_id} | grep secret | grep -o ":.*" | grep -o "\".*" | sed "s/\"//g") + echo ${secret} > ${home}/secret + + $(cd "./${home}/config" && sed -i -e "s/BEP12Height = 9223372036854775807/BEP12Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP3Height = 9223372036854775807/BEP3Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/timeout_commit = \"1s\"/timeout_commit = \"500ms\"/g" config.toml) + $(cd "./${home}/config" && sed -i -e "s/log_level = \"main\:info,state\:info,\*\:error\"/log_level = \"*\:debug\"/g" config.toml) + $(cd "./${home}/config" && sed -i -e "s/\"min_self_delegation\": \"1000000000000\"/\"min_self_delegation\": \"10000000000\"/g" genesis.json) + $(cd "./${home}/config" && sed -i -e "s/BEP3Height = 9223372036854775807/BEP3Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP8Height = 9223372036854775807/BEP8Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP67Height = 9223372036854775807/BEP67Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP82Height = 9223372036854775807/BEP82Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP84Height = 9223372036854775807/BEP84Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP87Height = 9223372036854775807/BEP87Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/FixFailAckPackageHeight = 9223372036854775807/FixFailAckPackageHeight = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/EnableAccountScriptsForCrossChainTransferHeight = 9223372036854775807/EnableAccountScriptsForCrossChainTransferHeight = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP70Height = 9223372036854775807/BEP70Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP128Height = 9223372036854775807/BEP128Height = 1/g" app.toml) + $(cd "./${home}/config" && sed -i -e "s/BEP151Height = 9223372036854775807/BEP151Height = 1/g" app.toml) + $(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/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) + + # stop and start node + ps -ef | grep bnbchaind | grep testnoded | awk '{print $2}' | xargs kill -9 + ./bnbchaind start --home ${home} > ./testnoded/node.log 2>&1 & + + echo ${secret} +} + +function exit_test() { + # stop node + ps -ef | grep bnbchaind | grep testnoded | awk '{print $2}' | xargs kill -9 + exit $1 +} + +function check_operation() { + printf "\n=================== Checking $1 ===================\n" + echo "$2" + + echo "$2" | grep -q $3 + if [ $? -ne 0 ]; then + echo "Checking $1 Failed" + exit_test 1 + fi +} + +secret=$(prepare_node) +result=$(expect ./recover.exp "${secret}" "alice" true) +check_operation "Recover Key" "${result}" "${keys_operation_words}" + +bob_secret="bottom quick strong ranch section decide pepper broken oven demand coin run jacket curious business achieve mule bamboo remain vote kid rigid bench rubber" +bob_val_addr=bva1ddt3ls9fjcd8mh69ujdg3fxc89qle2a7k8spre +bob_pubkey=bcap1zcjduepqes09r5x3kqnv7nlrcrveh5sxsrqxw222wu8999fa2wpnjher4yxst89v4a +bob_pubkey_new=bcap1zcjduepqcde4hk9kac248hqr3vqxle049f9l5zc58rcacy6nphuay5wt6c5q3ydes7 +result=$(expect ./recover.exp "${bob_secret}" "bob" true) +check_operation "Add Key" "${result}" "${keys_operation_words}" +carl_secret="mad calm portion vendor fine weather thunder ensure simple fish enrich genre plate kind minor random where crop hero soda isolate pelican provide chimney" +result=$(expect ./recover.exp "${carl_secret}" "carl" true) +check_operation "Add Key" "${result}" "${keys_operation_words}" +# wait for the chain +sleep 10s + +alice_addr=$(./bnbcli keys list --home ${cli_home} | grep alice | grep -o "bnb1[0-9a-zA-Z]*") +bob_addr=$(./bnbcli keys list --home ${cli_home} | grep bob | grep -o "bnb1[0-9a-zA-Z]*") +carl_addr=$(./bnbcli keys list --home ${cli_home} | grep carl | grep -o "bnb1[0-9a-zA-Z]*") + +# send +result=$(expect ./send.exp ${cli_home} alice ${chain_id} "100000000000000:BNB" ${bob_addr}) +check_operation "Send Token" "${result}" "${chain_operation_words}" +sleep 5s +result=$(expect ./send.exp ${cli_home} alice ${chain_id} "100000000000000:BNB" ${carl_addr}) +check_operation "Send Token" "${result}" "${chain_operation_words}" +sleep 5s + +# get parameters +result=$(./bnbcli staking parameters --home ${cli_home} --trust-node) +check_operation "Query Staking Parameters" "${result}" "proposer" + +# get validators +result=$(./bnbcli staking validators --home ${cli_home} --trust-node) +check_operation "Get Validators" "${result}" "Operator" + +# get validator +operator_address=$(echo "${result}" | grep Operator | grep -o "bva[0-9a-zA-Z]*" | head -n1) +result=$(./bnbcli staking validator ${operator_address} --home ${cli_home} --trust-node) +check_operation "Get Validator" "${result}" "Operator" + +# get delegations +result=$(./bnbcli staking delegations ${alice_addr} --home ${cli_home} --trust-node) +check_operation "Get Delegations" "${result}" "Validator" + +# get delegation +validator_address=$(echo "${result}" | grep Validator | grep -o "bva[0-9a-zA-Z]*") +delegator_address=$(echo "${result}" | grep Delegator | grep -o "bnb1[0-9a-zA-Z]*") +result=$(./bnbcli staking delegation --address-delegator ${delegator_address} --validator ${validator_address} --home ${cli_home} --trust-node) +check_operation "Get Delegation" "${result}" "Validator" + +# get pool +result=$(./bnbcli staking pool --home ${cli_home} --trust-node) + +# create validator +result=$(expect ./create-validator-open.exp ${cli_home} bob ${chain_id} ${bob_pubkey}) +check_operation "create validator open" "${result}" "${chain_operation_words}" +sleep 5s +result=$(./bnbcli staking validators --home ${cli_home} --trust-node) +check_operation "Get Validators" "${result}" "Operator" +result=$(./bnbcli staking validator ${bob_val_addr} --home ${cli_home} --trust-node) +check_operation "Get Validator" "${result}" "bob" +check_operation "Get Validator" "${result}" "${bob_pubkey}" + +# edit validator +result=$(expect ./edit-validator.exp ${cli_home} bob ${chain_id} ${bob_pubkey_new}) +check_operation "edit validator" "${result}" "${chain_operation_words}" +sleep 5s +result=$(./bnbcli staking validator ${bob_val_addr} --home ${cli_home} --trust-node) +check_operation "Get Validator" "${result}" "bob-new" +check_operation "Get Validator" "${result}" "${bob_pubkey_new}" +bob_val_addr=$(echo "${result}" | grep Operator | grep -o "bva[0-9a-zA-Z]*") + +## delegate +#result=$(expect ./delegate.exp ${cli_home} carl ${chain_id} "1000000000:BNB" ${validator_address}) +#check_operation "delegate" "${result}" "${chain_operation_words}" +#sleep 5s +#result=$(./bnbcli staking delegation --address-delegator ${carl_addr} --validator ${validator_address} --home ${cli_home} --trust-node) +#check_operation "Get Delegation" "${result}" "Validator" +# +## redelegate +#result=$(expect ./redelegate.exp ${cli_home} carl ${chain_id} "600000000:BNB" ${validator_address} ${bob_val_addr}) +#check_operation "redelegate" "${result}" "${chain_operation_words}" +#sleep 5s +# +## undelegate +#result=$(expect ./undelegate.exp ${cli_home} carl ${chain_id} "400000000:BNB" ${validator_address}) +#check_operation "undelegate" "${result}" "${chain_operation_words}" +#sleep 5s +# +## get redelegations +#result=$(./bnbcli staking redelegations ${carl_addr} --home ${cli_home} --trust-node) +#check_operation "Get Redelegations" "${result}" "delegator_addr" +# +## get redelegation +#result=$(./bnbcli staking redelegation --address-delegator ${carl_addr} --addr-validator-source ${validator_address} --addr-validator-dest ${bob_val_addr} --home ${cli_home} --trust-node) +#check_operation "Get Redelegation" "${result}" "Delegator" +# +## get unbonding-delegations +#result=$(./bnbcli staking unbonding-delegations ${carl_addr} --home ${cli_home} --trust-node) +#check_operation "Get Unbonding-Delegations" "${result}" "delegator_addr" +# +## get unbonding-delegation +#result=$(./bnbcli staking unbonding-delegation --address-delegator ${carl_addr} --validator ${validator_address} --home ${cli_home} --trust-node) +#check_operation "Get Unbonding-Delegation" "${result}" "Delegator" + +# run test with go-sdk +cd .. && go run ./cmd/test_client + +exit_test 0 diff --git a/scripts/importssort.sh b/scripts/importssort.sh new file mode 100644 index 000000000..521ce0eb0 --- /dev/null +++ b/scripts/importssort.sh @@ -0,0 +1,20 @@ +go get -u github.com/AanZee/goimportssort + +for entry in `git diff --name-only develop . | grep '\.go$'`; do + echo $entry + if grep -q "DO NOT EDIT" "$entry"; then + echo "xxxxxxxx==================================" + continue + fi + goimportssort -w -local github.com/bnb-chain/ $entry +done + +# change the whole file +#for entry in `find . -name "*.go"`; do +# echo $entry +# if grep -q "DO NOT EDIT" "$entry"; then +# echo "xxxxxxxx==================================" +# continue +# fi +# goimportssort -w -local github.com/bnb-chain/ $entry +#done