From eefd5ece513e9f70606f4837e4ba0860a9f39e67 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 11:17:06 -0500 Subject: [PATCH 01/24] Initial commit --- CHANGELOG.md | 9 + simapp/app.go | 6 +- simapp/genesis_account.go | 3 - simapp/test_helpers.go | 6 +- x/auth/ante/fee.go | 21 -- x/auth/exported/exported.go | 10 +- x/auth/simulation/genesis.go | 13 +- x/auth/types/account.go | 28 +- x/auth/types/genesis.go | 6 - x/auth/vesting/exported/exported.go | 16 +- x/auth/vesting/types/vesting_account.go | 124 +++--- x/bank/alias.go | 34 +- x/bank/client/rest/query.go | 28 +- x/bank/client/rest/rest.go | 12 + x/bank/client/rest/tx.go | 6 - x/bank/exported/exported.go | 12 + x/bank/genesis.go | 31 +- x/bank/internal/keeper/invariants.go | 33 +- x/bank/internal/keeper/keeper.go | 397 +++++++++++++------- x/bank/internal/keeper/querier.go | 36 +- x/bank/internal/types/genesis.go | 82 +++- x/bank/internal/types/key.go | 27 +- x/bank/internal/types/key_test.go | 26 ++ x/bank/internal/types/msgs.go | 3 - x/bank/internal/types/querier.go | 21 +- x/bank/module.go | 2 +- x/bank/simulation/genesis.go | 18 +- x/bank/simulation/operations.go | 34 +- x/genutil/client/cli/collect.go | 4 +- x/genutil/client/cli/gentx.go | 4 +- x/genutil/collect.go | 46 +-- x/genutil/gentx.go | 70 ++-- x/genutil/types/expected_keepers.go | 12 +- x/supply/genesis.go | 9 +- x/supply/internal/keeper/invariants.go | 5 +- x/supply/internal/types/account.go | 5 +- x/supply/internal/types/expected_keepers.go | 2 + x/supply/module.go | 6 +- 38 files changed, 767 insertions(+), 440 deletions(-) create mode 100644 x/bank/client/rest/rest.go create mode 100644 x/bank/exported/exported.go create mode 100644 x/bank/internal/types/key_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b1a9c20bcf..c1b48c8a79b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,15 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output. +### State Machine Breaking + +* (modules) [\#5539](https://github.com/cosmos/cosmos-sdk/pull/5539) Separate balance from accounts per ADR 004. + * Account balances are now persisted and retrieved via the `x/bank` module. + * Vesting account interface has been modified to account for changes. + * Callers to `NewBaseVestingAccount` are responsible for verifying account balance in relation to + the original vesting amount. + * The `SendKeeper` and `ViewKeeper` interfaces in `x/bank` have been modified to account for changes. + ## [v0.38.0] - 2020-01-23 ### State Machine Breaking diff --git a/simapp/app.go b/simapp/app.go index c074f8ccce0..ec1aebf2753 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -142,7 +142,7 @@ func NewSimApp( bApp.SetAppVersion(version.Version) keys := sdk.NewKVStoreKeys( - bam.MainStoreKey, auth.StoreKey, staking.StoreKey, + bam.MainStoreKey, auth.StoreKey, bank.StoreKey, staking.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey, ) @@ -174,7 +174,7 @@ func NewSimApp( app.cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, ) app.BankKeeper = bank.NewBaseKeeper( - app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), + app.cdc, keys[bank.StoreKey], app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), ) app.SupplyKeeper = supply.NewKeeper( app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, @@ -283,7 +283,7 @@ func NewSimApp( // initialize BaseApp app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) - app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, auth.DefaultSigVerificationGasConsumer)) + app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, auth.DefaultSigVerificationGasConsumer)) app.SetEndBlocker(app.EndBlocker) if loadLatest { diff --git a/simapp/genesis_account.go b/simapp/genesis_account.go index e6bc7f97c04..d995f7023e1 100644 --- a/simapp/genesis_account.go +++ b/simapp/genesis_account.go @@ -31,9 +31,6 @@ type SimGenesisAccount struct { // Validate checks for errors on the vesting and module account parameters func (sga SimGenesisAccount) Validate() error { if !sga.OriginalVesting.IsZero() { - if sga.OriginalVesting.IsAnyGT(sga.Coins) { - return errors.New("vesting amount cannot be greater than total amount") - } if sga.StartTime >= sga.EndTime { return errors.New("vesting start-time cannot be before end-time") } diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 5192e59feab..edadd7d749e 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -101,11 +101,9 @@ func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sd } // CheckBalance checks the balance of an account. -func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, exp sdk.Coins) { +func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, balances sdk.Coins) { ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) - res := app.AccountKeeper.GetAccount(ctxCheck, addr) - - require.True(t, exp.IsEqual(res.GetCoins())) + require.True(t, balances.IsEqual(app.BankKeeper.GetAllBalances(ctxCheck, addr))) } // SignCheckDeliver checks a generated signed transaction and simulates a diff --git a/x/auth/ante/fee.go b/x/auth/ante/fee.go index 3d81808b2d0..3283b4fcb08 100644 --- a/x/auth/ante/fee.go +++ b/x/auth/ante/fee.go @@ -113,32 +113,11 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo } // DeductFees deducts fees from the given account. -// -// NOTE: We could use the BankKeeper (in addition to the AccountKeeper, because -// the BankKeeper doesn't give us accounts), but it seems easier to do this. func DeductFees(supplyKeeper types.SupplyKeeper, ctx sdk.Context, acc exported.Account, fees sdk.Coins) error { - blockTime := ctx.BlockHeader().Time - coins := acc.GetCoins() - if !fees.IsValid() { return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) } - // verify the account has enough funds to pay for fees - _, hasNeg := coins.SafeSub(fees) - if hasNeg { - return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, - "insufficient funds to pay for fees; %s < %s", coins, fees) - } - - // Validate the account has enough "spendable" coins as this will cover cases - // such as vesting accounts. - spendableCoins := acc.SpendableCoins(blockTime) - if _, hasNeg := spendableCoins.SafeSub(fees); hasNeg { - return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, - "insufficient funds to pay for fees; %s < %s", spendableCoins, fees) - } - err := supplyKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) if err != nil { return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) diff --git a/x/auth/exported/exported.go b/x/auth/exported/exported.go index fe4fb16d833..7b97e8df179 100644 --- a/x/auth/exported/exported.go +++ b/x/auth/exported/exported.go @@ -1,8 +1,6 @@ package exported import ( - "time" - "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" @@ -27,13 +25,6 @@ type Account interface { GetSequence() uint64 SetSequence(uint64) error - GetCoins() sdk.Coins - SetCoins(sdk.Coins) error - - // Calculates the amount of coins that can be sent to other accounts given - // the current time. - SpendableCoins(blockTime time.Time) sdk.Coins - // Ensure that account implements stringer String() string } @@ -56,5 +47,6 @@ func (ga GenesisAccounts) Contains(addr sdk.Address) bool { // GenesisAccount defines a genesis account that embeds an Account with validation capabilities. type GenesisAccount interface { Account + Validate() error } diff --git a/x/auth/simulation/genesis.go b/x/auth/simulation/genesis.go index 808d81ac296..94fd8ec5ff3 100644 --- a/x/auth/simulation/genesis.go +++ b/x/auth/simulation/genesis.go @@ -97,17 +97,13 @@ func RandomizedGenState(simState *module.SimulationState) { // RandomGenesisAccounts returns randomly generated genesis accounts func RandomGenesisAccounts(simState *module.SimulationState) (genesisAccs exported.GenesisAccounts) { for i, acc := range simState.Accounts { - coins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(simState.InitialStake))} bacc := types.NewBaseAccountWithAddress(acc.Address) - if err := bacc.SetCoins(coins); err != nil { - panic(err) - } - var gacc exported.GenesisAccount = &bacc // Only consider making a vesting account once the initial bonded validator // set is exhausted due to needing to track DelegatedVesting. if int64(i) > simState.NumBonded && simState.Rand.Intn(100) < 50 { + initialVesting := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, simState.Rand.Int63n(simState.InitialStake))) var endTime int64 startTime := simState.GenTimestamp.Unix() @@ -119,12 +115,15 @@ func RandomGenesisAccounts(simState *module.SimulationState) (genesisAccs export endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*12)))) } + bva := vestingtypes.NewBaseVestingAccount(&bacc, initialVesting, endTime) + if simState.Rand.Intn(100) < 50 { - gacc = vestingtypes.NewContinuousVestingAccount(&bacc, startTime, endTime) + gacc = vestingtypes.NewContinuousVestingAccountRaw(bva, startTime) } else { - gacc = vestingtypes.NewDelayedVestingAccount(&bacc, endTime) + gacc = vestingtypes.NewDelayedVestingAccountRaw(bva) } } + genesisAccs = append(genesisAccs, gacc) } diff --git a/x/auth/types/account.go b/x/auth/types/account.go index a8d919a385e..643c33abd28 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "errors" - "time" "github.com/tendermint/tendermint/crypto" yaml "gopkg.in/yaml.v2" @@ -25,19 +24,15 @@ var _ exported.GenesisAccount = (*BaseAccount)(nil) // implements Account. type BaseAccount struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey crypto.PubKey `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` } // NewBaseAccount creates a new BaseAccount object -func NewBaseAccount(address sdk.AccAddress, coins sdk.Coins, - pubKey crypto.PubKey, accountNumber uint64, sequence uint64) *BaseAccount { - +func NewBaseAccount(address sdk.AccAddress, pubKey crypto.PubKey, accountNumber, sequence uint64) *BaseAccount { return &BaseAccount{ Address: address, - Coins: coins, PubKey: pubKey, AccountNumber: accountNumber, Sequence: sequence, @@ -81,17 +76,6 @@ func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error { return nil } -// GetCoins - Implements sdk.Account. -func (acc *BaseAccount) GetCoins() sdk.Coins { - return acc.Coins -} - -// SetCoins - Implements sdk.Account. -func (acc *BaseAccount) SetCoins(coins sdk.Coins) error { - acc.Coins = coins - return nil -} - // GetAccountNumber - Implements Account func (acc *BaseAccount) GetAccountNumber() uint64 { return acc.AccountNumber @@ -114,12 +98,6 @@ func (acc *BaseAccount) SetSequence(seq uint64) error { return nil } -// SpendableCoins returns the total set of spendable coins. For a base account, -// this is simply the base coins. -func (acc *BaseAccount) SpendableCoins(_ time.Time) sdk.Coins { - return acc.GetCoins() -} - // Validate checks for errors on the account fields func (acc BaseAccount) Validate() error { if acc.PubKey != nil && acc.Address != nil && @@ -132,7 +110,6 @@ func (acc BaseAccount) Validate() error { type baseAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -147,7 +124,6 @@ func (acc BaseAccount) String() string { func (acc BaseAccount) MarshalYAML() (interface{}, error) { alias := baseAccountPretty{ Address: acc.Address, - Coins: acc.Coins, AccountNumber: acc.AccountNumber, Sequence: acc.Sequence, } @@ -173,7 +149,6 @@ func (acc BaseAccount) MarshalYAML() (interface{}, error) { func (acc BaseAccount) MarshalJSON() ([]byte, error) { alias := baseAccountPretty{ Address: acc.Address, - Coins: acc.Coins, AccountNumber: acc.AccountNumber, Sequence: acc.Sequence, } @@ -207,7 +182,6 @@ func (acc *BaseAccount) UnmarshalJSON(bz []byte) error { } acc.Address = alias.Address - acc.Coins = alias.Coins acc.AccountNumber = alias.AccountNumber acc.Sequence = alias.Sequence diff --git a/x/auth/types/genesis.go b/x/auth/types/genesis.go index 78c4f5a5bd2..89999db447c 100644 --- a/x/auth/types/genesis.go +++ b/x/auth/types/genesis.go @@ -55,12 +55,6 @@ func SanitizeGenesisAccounts(genAccs exported.GenesisAccounts) exported.GenesisA return genAccs[i].GetAccountNumber() < genAccs[j].GetAccountNumber() }) - for _, acc := range genAccs { - if err := acc.SetCoins(acc.GetCoins().Sort()); err != nil { - panic(err) - } - } - return genAccs } diff --git a/x/auth/vesting/exported/exported.go b/x/auth/vesting/exported/exported.go index 16b07d3614f..c01d07234bb 100644 --- a/x/auth/vesting/exported/exported.go +++ b/x/auth/vesting/exported/exported.go @@ -11,9 +11,19 @@ import ( type VestingAccount interface { authexported.Account - // Delegation and undelegation accounting that returns the resulting base - // coins amount. - TrackDelegation(blockTime time.Time, amount sdk.Coins) + // LockedCoins returns the set of coins that are not spendable (i.e. locked) + // given the current account balance, only including tokens of vesting + // denominations, and the current block time. + LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins + + // TrackDelegation performs internal vesting accounting necessary when + // delegating from a vesting account. It accepts the current block time, the + // delegation amount and balance of all coins whose denomination exists in + // the account's original vesting balance. + TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) + + // TrackUndelegation performs internal vesting accounting necessary when a + // vesting account performs an undelegation. TrackUndelegation(amount sdk.Coins) GetVestedCoins(blockTime time.Time) sdk.Coins diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index 256c9d598fe..34af9a95cdc 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -41,56 +41,53 @@ type BaseVestingAccount struct { EndTime int64 `json:"end_time" yaml:"end_time"` // when the coins become unlocked } -// NewBaseVestingAccount creates a new BaseVestingAccount object -func NewBaseVestingAccount(baseAccount *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) (*BaseVestingAccount, error) { - if (baseAccount.Coins.IsZero() && !originalVesting.IsZero()) || originalVesting.IsAnyGT(baseAccount.Coins) { - return &BaseVestingAccount{}, errors.New("vesting amount cannot be greater than total amount") - } +// NewBaseVestingAccount creates a new BaseVestingAccount object. It is the +// callers responsibility to ensure the base account has sufficient funds with +// regards to the original vesting amount. +func NewBaseVestingAccount(baseAccount *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) *BaseVestingAccount { return &BaseVestingAccount{ BaseAccount: baseAccount, OriginalVesting: originalVesting, DelegatedFree: sdk.NewCoins(), DelegatedVesting: sdk.NewCoins(), EndTime: endTime, - }, nil + } } -// SpendableCoinsVestingAccount returns all the spendable coins for a vesting account given a -// set of vesting coins. +// LockedCoinsFromVesting returns all the coins that are not spendable (i.e. locked) +// for a vesting account given the current vesting coins and account balance, +// where the balance only includes tokens of vesting denomination. // -// CONTRACT: The account's coins, delegated vesting coins, vestingCoins must be -// sorted. -func (bva BaseVestingAccount) SpendableCoinsVestingAccount(vestingCoins sdk.Coins) sdk.Coins { - var spendableCoins sdk.Coins - bc := bva.GetCoins() - - for _, coin := range bc { - baseAmt := coin.Amount - vestingAmt := vestingCoins.AmountOf(coin.Denom) - delVestingAmt := bva.DelegatedVesting.AmountOf(coin.Denom) +// CONTRACT: Delegated vesting coins and vestingCoins must be sorted. +func (bva BaseVestingAccount) LockedCoinsFromVesting(balance, vestingCoins sdk.Coins) sdk.Coins { + var lockedCoins sdk.Coins + + for _, vestingCoin := range vestingCoins { + vestingAmt := vestingCoins.AmountOf(vestingCoin.Denom) + delVestingAmt := bva.DelegatedVesting.AmountOf(vestingCoin.Denom) + baseAmt := balance.AmountOf(vestingCoin.Denom) // compute min((BC + DV) - V, BC) per the specification min := sdk.MinInt(baseAmt.Add(delVestingAmt).Sub(vestingAmt), baseAmt) - spendableCoin := sdk.NewCoin(coin.Denom, min) + lockedCoin := sdk.NewCoin(vestingCoin.Denom, baseAmt.Sub(min)) - if !spendableCoin.IsZero() { - spendableCoins = spendableCoins.Add(spendableCoin) + if !lockedCoin.IsZero() { + lockedCoins = lockedCoins.Add(lockedCoin) } } - return spendableCoins + return lockedCoins } // TrackDelegation tracks a delegation amount for any given vesting account type -// given the amount of coins currently vesting. +// given the amount of coins currently vesting and the current account balance +// of the delegation denominations. // // CONTRACT: The account's coins, delegation coins, vesting coins, and delegated // vesting coins must be sorted. -func (bva *BaseVestingAccount) TrackDelegation(vestingCoins, amount sdk.Coins) { - bc := bva.GetCoins() - +func (bva *BaseVestingAccount) TrackDelegation(balance, vestingCoins, amount sdk.Coins) { for _, coin := range amount { - baseAmt := bc.AmountOf(coin.Denom) + baseAmt := balance.AmountOf(coin.Denom) vestingAmt := vestingCoins.AmountOf(coin.Denom) delVestingAmt := bva.DelegatedVesting.AmountOf(coin.Denom) @@ -187,7 +184,6 @@ func (bva BaseVestingAccount) Validate() error { type vestingAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -210,7 +206,6 @@ func (bva BaseVestingAccount) String() string { func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: bva.Address, - Coins: bva.Coins, AccountNumber: bva.AccountNumber, Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, @@ -240,7 +235,6 @@ func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: bva.Address, - Coins: bva.Coins, AccountNumber: bva.AccountNumber, Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, @@ -280,7 +274,7 @@ func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error { } } - bva.BaseAccount = authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence) + bva.BaseAccount = authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence) bva.OriginalVesting = alias.OriginalVesting bva.DelegatedFree = alias.DelegatedFree bva.DelegatedVesting = alias.DelegatedVesting @@ -312,10 +306,10 @@ func NewContinuousVestingAccountRaw(bva *BaseVestingAccount, startTime int64) *C } // NewContinuousVestingAccount returns a new ContinuousVestingAccount -func NewContinuousVestingAccount(baseAcc *authtypes.BaseAccount, startTime, endTime int64) *ContinuousVestingAccount { +func NewContinuousVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, startTime, endTime int64) *ContinuousVestingAccount { baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, - OriginalVesting: baseAcc.Coins, + OriginalVesting: originalVesting, EndTime: endTime, } @@ -358,17 +352,18 @@ func (cva ContinuousVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coi return cva.OriginalVesting.Sub(cva.GetVestedCoins(blockTime)) } -// SpendableCoins returns the total number of spendable coins per denom for a -// continuous vesting account. -func (cva ContinuousVestingAccount) SpendableCoins(blockTime time.Time) sdk.Coins { - return cva.BaseVestingAccount.SpendableCoinsVestingAccount(cva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked) +// given the current account balance, only including tokens of vesting +// denominations, and the current block time. +func (cva ContinuousVestingAccount) LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins { + return cva.BaseVestingAccount.LockedCoinsFromVesting(balance, cva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate // values for the amount of delegated vesting, delegated free, and reducing the // overall amount of base coins. -func (cva *ContinuousVestingAccount) TrackDelegation(blockTime time.Time, amount sdk.Coins) { - cva.BaseVestingAccount.TrackDelegation(cva.GetVestingCoins(blockTime), amount) +func (cva *ContinuousVestingAccount) TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) { + cva.BaseVestingAccount.TrackDelegation(balance, cva.GetVestingCoins(blockTime), amount) } // GetStartTime returns the time when vesting starts for a continuous vesting @@ -395,7 +390,6 @@ func (cva ContinuousVestingAccount) String() string { func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: cva.Address, - Coins: cva.Coins, AccountNumber: cva.AccountNumber, Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, @@ -426,7 +420,6 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: cva.Address, - Coins: cva.Coins, AccountNumber: cva.AccountNumber, Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, @@ -468,7 +461,7 @@ func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error { } cva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, @@ -503,14 +496,14 @@ func NewPeriodicVestingAccountRaw(bva *BaseVestingAccount, startTime int64, peri } // NewPeriodicVestingAccount returns a new PeriodicVestingAccount -func NewPeriodicVestingAccount(baseAcc *authtypes.BaseAccount, startTime int64, periods Periods) *PeriodicVestingAccount { +func NewPeriodicVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, startTime int64, periods Periods) *PeriodicVestingAccount { endTime := startTime for _, p := range periods { endTime += p.Length } baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, - OriginalVesting: baseAcc.Coins, + OriginalVesting: originalVesting, EndTime: endTime, } @@ -537,16 +530,20 @@ func (pva PeriodicVestingAccount) GetVestedCoins(blockTime time.Time) sdk.Coins // track the start time of the next period currentPeriodStartTime := pva.StartTime + // for each period, if the period is over, add those coins as vested and check the next period. for _, period := range pva.VestingPeriods { x := blockTime.Unix() - currentPeriodStartTime if x < period.Length { break } + vestedCoins = vestedCoins.Add(period.Amount...) - // Update the start time of the next period + + // update the start time of the next period currentPeriodStartTime += period.Length } + return vestedCoins } @@ -556,17 +553,18 @@ func (pva PeriodicVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins return pva.OriginalVesting.Sub(pva.GetVestedCoins(blockTime)) } -// SpendableCoins returns the total number of spendable coins per denom for a -// periodic vesting account. -func (pva PeriodicVestingAccount) SpendableCoins(blockTime time.Time) sdk.Coins { - return pva.BaseVestingAccount.SpendableCoinsVestingAccount(pva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked) +// given the current account balance, only including tokens of vesting +// denominations, and the current block time. +func (pva PeriodicVestingAccount) LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins { + return pva.BaseVestingAccount.LockedCoinsFromVesting(balance, pva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate // values for the amount of delegated vesting, delegated free, and reducing the // overall amount of base coins. -func (pva *PeriodicVestingAccount) TrackDelegation(blockTime time.Time, amount sdk.Coins) { - pva.BaseVestingAccount.TrackDelegation(pva.GetVestingCoins(blockTime), amount) +func (pva *PeriodicVestingAccount) TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) { + pva.BaseVestingAccount.TrackDelegation(balance, pva.GetVestingCoins(blockTime), amount) } // GetStartTime returns the time when vesting starts for a periodic vesting @@ -610,7 +608,6 @@ func (pva PeriodicVestingAccount) String() string { func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { alias := vestingAccountPretty{ Address: pva.Address, - Coins: pva.Coins, AccountNumber: pva.AccountNumber, Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, @@ -642,7 +639,6 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: pva.Address, - Coins: pva.Coins, AccountNumber: pva.AccountNumber, Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, @@ -685,7 +681,7 @@ func (pva *PeriodicVestingAccount) UnmarshalJSON(bz []byte) error { } pva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, @@ -718,10 +714,10 @@ func NewDelayedVestingAccountRaw(bva *BaseVestingAccount) *DelayedVestingAccount } // NewDelayedVestingAccount returns a DelayedVestingAccount -func NewDelayedVestingAccount(baseAcc *authtypes.BaseAccount, endTime int64) *DelayedVestingAccount { +func NewDelayedVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) *DelayedVestingAccount { baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, - OriginalVesting: baseAcc.Coins, + OriginalVesting: originalVesting, EndTime: endTime, } @@ -744,17 +740,18 @@ func (dva DelayedVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins return dva.OriginalVesting.Sub(dva.GetVestedCoins(blockTime)) } -// SpendableCoins returns the total number of spendable coins for a delayed -// vesting account. -func (dva DelayedVestingAccount) SpendableCoins(blockTime time.Time) sdk.Coins { - return dva.BaseVestingAccount.SpendableCoinsVestingAccount(dva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked) +// given the current account balance, only including tokens of vesting +// denominations, and the current block time. +func (dva DelayedVestingAccount) LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins { + return dva.BaseVestingAccount.LockedCoinsFromVesting(balance, dva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate // values for the amount of delegated vesting, delegated free, and reducing the // overall amount of base coins. -func (dva *DelayedVestingAccount) TrackDelegation(blockTime time.Time, amount sdk.Coins) { - dva.BaseVestingAccount.TrackDelegation(dva.GetVestingCoins(blockTime), amount) +func (dva *DelayedVestingAccount) TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) { + dva.BaseVestingAccount.TrackDelegation(balance, dva.GetVestingCoins(blockTime), amount) } // GetStartTime returns zero since a delayed vesting account has no start time. @@ -771,7 +768,6 @@ func (dva DelayedVestingAccount) Validate() error { func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { alias := vestingAccountPretty{ Address: dva.Address, - Coins: dva.Coins, AccountNumber: dva.AccountNumber, Sequence: dva.Sequence, OriginalVesting: dva.OriginalVesting, @@ -812,7 +808,7 @@ func (dva *DelayedVestingAccount) UnmarshalJSON(bz []byte) error { } dva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence), + BaseAccount: authtypes.NewBaseAccount(alias.Address, pk, alias.AccountNumber, alias.Sequence), OriginalVesting: alias.OriginalVesting, DelegatedFree: alias.DelegatedFree, DelegatedVesting: alias.DelegatedVesting, diff --git a/x/bank/alias.go b/x/bank/alias.go index 1ac7cecebd9..302a5ffdb76 100644 --- a/x/bank/alias.go +++ b/x/bank/alias.go @@ -8,10 +8,12 @@ import ( ) const ( - QueryBalance = keeper.QueryBalance + QueryBalance = types.QueryBalance + QueryAllBalances = types.QueryAllBalances ModuleName = types.ModuleName QuerierRoute = types.QuerierRoute RouterKey = types.RouterKey + StoreKey = types.StoreKey DefaultParamspace = types.DefaultParamspace DefaultSendEnabled = types.DefaultSendEnabled @@ -36,6 +38,7 @@ var ( NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState ValidateGenesis = types.ValidateGenesis + SanitizeGenesisBalances = types.SanitizeGenesisBalances NewMsgSend = types.NewMsgSend NewMsgMultiSend = types.NewMsgMultiSend NewInput = types.NewInput @@ -43,21 +46,26 @@ var ( ValidateInputsOutputs = types.ValidateInputsOutputs ParamKeyTable = types.ParamKeyTable NewQueryBalanceParams = types.NewQueryBalanceParams + NewQueryAllBalancesParams = types.NewQueryAllBalancesParams ModuleCdc = types.ModuleCdc ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled + BalancesPrefix = types.BalancesPrefix + AddressFromBalancesKey = types.AddressFromBalancesKey ) type ( - Keeper = keeper.Keeper - BaseKeeper = keeper.BaseKeeper - SendKeeper = keeper.SendKeeper - BaseSendKeeper = keeper.BaseSendKeeper - ViewKeeper = keeper.ViewKeeper - BaseViewKeeper = keeper.BaseViewKeeper - GenesisState = types.GenesisState - MsgSend = types.MsgSend - MsgMultiSend = types.MsgMultiSend - Input = types.Input - Output = types.Output - QueryBalanceParams = types.QueryBalanceParams + Keeper = keeper.Keeper + BaseKeeper = keeper.BaseKeeper + SendKeeper = keeper.SendKeeper + BaseSendKeeper = keeper.BaseSendKeeper + ViewKeeper = keeper.ViewKeeper + BaseViewKeeper = keeper.BaseViewKeeper + GenesisState = types.GenesisState + Balance = types.Balance + MsgSend = types.MsgSend + MsgMultiSend = types.MsgMultiSend + Input = types.Input + Output = types.Output + QueryBalanceParams = types.QueryBalanceParams + QueryAllBalancesParams = types.QueryAllBalancesParams ) diff --git a/x/bank/client/rest/query.go b/x/bank/client/rest/query.go index 97bb16df327..eb1f3463b7a 100644 --- a/x/bank/client/rest/query.go +++ b/x/bank/client/rest/query.go @@ -1,6 +1,7 @@ package rest import ( + "fmt" "net/http" "github.com/gorilla/mux" @@ -11,7 +12,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) -// query accountREST Handler +// QueryBalancesRequestHandlerFn returns a REST handler that queries for all +// account balances or a specific balance by denomination. func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -29,27 +31,33 @@ func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - params := types.NewQueryBalanceParams(addr) + var ( + params interface{} + route string + ) + + denom := r.FormValue("denom") + if denom == "" { + params = types.NewQueryAllBalancesParams(addr) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllBalances) + } else { + params = types.NewQueryBalanceParams(addr, denom) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBalance) + } + bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - res, height, err := cliCtx.QueryWithData("custom/bank/balances", bz) + res, height, err := cliCtx.QueryWithData(route, bz) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } cliCtx = cliCtx.WithHeight(height) - - // the query will return empty if there is no data for this account - if len(res) == 0 { - rest.PostProcessResponse(w, cliCtx, sdk.Coins{}) - return - } - rest.PostProcessResponse(w, cliCtx, res) } } diff --git a/x/bank/client/rest/rest.go b/x/bank/client/rest/rest.go new file mode 100644 index 00000000000..b2b1ff84c89 --- /dev/null +++ b/x/bank/client/rest/rest.go @@ -0,0 +1,12 @@ +package rest + +import ( + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/gorilla/mux" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/bank/accounts/{address}/transfers", SendRequestHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/bank/balances/{address}", QueryBalancesRequestHandlerFn(cliCtx)).Methods("GET") +} diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index fdf245430db..52fa9f25136 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -12,12 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) -// RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { - r.HandleFunc("/bank/accounts/{address}/transfers", SendRequestHandlerFn(cliCtx)).Methods("POST") - r.HandleFunc("/bank/balances/{address}", QueryBalancesRequestHandlerFn(cliCtx)).Methods("GET") -} - // SendReq defines the properties of a send request's body. type SendReq struct { BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` diff --git a/x/bank/exported/exported.go b/x/bank/exported/exported.go new file mode 100644 index 00000000000..c4f2e9f6da0 --- /dev/null +++ b/x/bank/exported/exported.go @@ -0,0 +1,12 @@ +package exported + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GenesisBalance defines a genesis balance interface that allows for account +// address and balance retrieval. +type GenesisBalance interface { + GetAddress() sdk.AccAddress + GetCoins() sdk.Coins +} diff --git a/x/bank/genesis.go b/x/bank/genesis.go index 641875e6dc8..f3141a64128 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -4,12 +4,33 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// InitGenesis sets distribution information for genesis. -func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { - keeper.SetSendEnabled(ctx, data.SendEnabled) +// InitGenesis initializes the bank module's state from a given genesis state. +func InitGenesis(ctx sdk.Context, keeper Keeper, genState GenesisState) { + keeper.SetSendEnabled(ctx, genState.SendEnabled) + + genState.Balances = SanitizeGenesisBalances(genState.Balances) + for _, balance := range genState.Balances { + keeper.SetBalances(ctx, balance.Address, balance.Coins) + } } -// ExportGenesis returns a GenesisState for a given context and keeper. +// ExportGenesis returns the bank module's genesis state. func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { - return NewGenesisState(keeper.GetSendEnabled(ctx)) + balancesSet := make(map[string]sdk.Coins) + + keeper.IterateAllBalances(ctx, func(addr sdk.AccAddress, balance sdk.Coin) bool { + balancesSet[addr.String()] = balancesSet[addr.String()].Add(balance) + return false + }) + + balances := []Balance{} + + for addr, coins := range balancesSet { + balances = append(balances, Balance{ + Address: sdk.AccAddress([]byte(addr)), + Coins: coins, + }) + } + + return NewGenesisState(keeper.GetSendEnabled(ctx), balances) } diff --git a/x/bank/internal/keeper/invariants.go b/x/bank/internal/keeper/invariants.go index 0be1e8f58f2..65730451261 100644 --- a/x/bank/internal/keeper/invariants.go +++ b/x/bank/internal/keeper/invariants.go @@ -8,30 +8,33 @@ import ( ) // RegisterInvariants registers the bank module invariants -func RegisterInvariants(ir sdk.InvariantRegistry, ak types.AccountKeeper) { +func RegisterInvariants(ir sdk.InvariantRegistry, bk ViewKeeper) { ir.RegisterRoute(types.ModuleName, "nonnegative-outstanding", - NonnegativeBalanceInvariant(ak)) + NonnegativeBalanceInvariant(bk)) } // NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances -func NonnegativeBalanceInvariant(ak types.AccountKeeper) sdk.Invariant { +func NonnegativeBalanceInvariant(bk ViewKeeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { - var msg string - var count int + var ( + msg string + count int + ) - accts := ak.GetAllAccounts(ctx) - for _, acc := range accts { - coins := acc.GetCoins() - if coins.IsAnyNegative() { + bk.IterateAllBalances(ctx, func(addr sdk.AccAddress, balance sdk.Coin) bool { + if balance.IsNegative() { count++ - msg += fmt.Sprintf("\t%s has a negative denomination of %s\n", - acc.GetAddress().String(), - coins.String()) + msg += fmt.Sprintf("\t%s has a negative balance of %s\n", addr, balance) } - } + + return false + }) + broken := count != 0 - return sdk.FormatInvariant(types.ModuleName, "nonnegative-outstanding", - fmt.Sprintf("amount of negative accounts found %d\n%s", count, msg)), broken + return sdk.FormatInvariant( + types.ModuleName, "nonnegative-outstanding", + fmt.Sprintf("amount of negative balances found %d\n%s", count, msg), + ), broken } } diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 25e47b07393..e32008951b2 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -6,9 +6,10 @@ import ( "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" "github.com/cosmos/cosmos-sdk/x/params" @@ -29,18 +30,18 @@ type Keeper interface { type BaseKeeper struct { BaseSendKeeper + storeKey sdk.StoreKey ak types.AccountKeeper paramSpace params.Subspace } -// NewBaseKeeper returns a new BaseKeeper func NewBaseKeeper( - ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, + cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, ) BaseKeeper { ps := paramSpace.WithKeyTable(types.ParamKeyTable()) return BaseKeeper{ - BaseSendKeeper: NewBaseSendKeeper(ak, ps, blacklistedAddrs), + BaseSendKeeper: NewBaseSendKeeper(cdc, storeKey, ak, ps, blacklistedAddrs), ak: ak, paramSpace: ps, } @@ -48,16 +49,11 @@ func NewBaseKeeper( // DelegateCoins performs delegation by deducting amt coins from an account with // address addr. For vesting accounts, delegations amounts are tracked for both -// vesting and vested coins. -// The coins are then transferred from the delegator address to a ModuleAccount address. -// If any of the delegation amounts are negative, an error is returned. -func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error { - delegatorAcc := keeper.ak.GetAccount(ctx, delegatorAddr) - if delegatorAcc == nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", delegatorAddr) - } - - moduleAcc := keeper.ak.GetAccount(ctx, moduleAccAddr) +// vesting and vested coins. The coins are then transferred from the delegator +// address to a ModuleAccount address. If any of the delegation amounts are negative, +// an error is returned. +func (k BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error { + moduleAcc := k.ak.GetAccount(ctx, moduleAccAddr) if moduleAcc == nil { return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleAccAddr) } @@ -66,22 +62,25 @@ func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAcc return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - oldCoins := delegatorAcc.GetCoins() + balances := sdk.NewCoins() - _, hasNeg := oldCoins.SafeSub(amt) - if hasNeg { - return sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, - ) + for _, coin := range amt { + balance := k.GetBalance(ctx, delegatorAddr, coin.Denom) + if balance.IsLT(coin) { + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "failed to delegate; %s < %s", balance, amt, + ) + } + + balances = balances.Add(balance) + k.SetBalance(ctx, delegatorAddr, balance.Sub(coin)) } - if err := trackDelegation(delegatorAcc, ctx.BlockHeader().Time, amt); err != nil { + if err := k.trackDelegation(ctx, delegatorAddr, ctx.BlockHeader().Time, balances, amt); err != nil { return sdkerrors.Wrap(err, "failed to track delegation") } - keeper.ak.SetAccount(ctx, delegatorAcc) - - _, err := keeper.AddCoins(ctx, moduleAccAddr, amt) + _, err := k.AddCoins(ctx, moduleAccAddr, amt) if err != nil { return err } @@ -91,16 +90,11 @@ func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAcc // UndelegateCoins performs undelegation by crediting amt coins to an account with // address addr. For vesting accounts, undelegation amounts are tracked for both -// vesting and vested coins. -// The coins are then transferred from a ModuleAccount address to the delegator address. -// If any of the undelegation amounts are negative, an error is returned. -func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error { - delegatorAcc := keeper.ak.GetAccount(ctx, delegatorAddr) - if delegatorAcc == nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", delegatorAddr) - } - - moduleAcc := keeper.ak.GetAccount(ctx, moduleAccAddr) +// vesting and vested coins. The coins are then transferred from a ModuleAccount +// address to the delegator address. If any of the undelegation amounts are +// negative, an error is returned. +func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error { + moduleAcc := k.ak.GetAccount(ctx, moduleAccAddr) if moduleAcc == nil { return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleAccAddr) } @@ -109,25 +103,21 @@ func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegat return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - oldCoins := moduleAcc.GetCoins() - - newCoins, hasNeg := oldCoins.SafeSub(amt) - if hasNeg { - return sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, - ) - } - - err := keeper.SetCoins(ctx, moduleAccAddr, newCoins) + // safe to call Substract coins as a moduleAcc shouldn't be vesting + _, err := k.SubtractCoins(ctx, moduleAccAddr, amt) if err != nil { return err } - if err := trackUndelegation(delegatorAcc, amt); err != nil { + if err := k.trackUndelegation(ctx, delegatorAddr, amt); err != nil { return sdkerrors.Wrap(err, "failed to track undelegation") } - keeper.ak.SetAccount(ctx, delegatorAcc) + _, err = k.AddCoins(ctx, delegatorAddr, amt) + if err != nil { + return err + } + return nil } @@ -141,7 +131,9 @@ type SendKeeper interface { SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) - SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error + + SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error GetSendEnabled(ctx sdk.Context) bool SetSendEnabled(ctx sdk.Context, enabled bool) @@ -156,28 +148,33 @@ var _ SendKeeper = (*BaseSendKeeper)(nil) type BaseSendKeeper struct { BaseViewKeeper + cdc *codec.Codec ak types.AccountKeeper + storeKey sdk.StoreKey paramSpace params.Subspace // list of addresses that are restricted from receiving transactions blacklistedAddrs map[string]bool } -// NewBaseSendKeeper returns a new BaseSendKeeper. func NewBaseSendKeeper( - ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, + cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, ) BaseSendKeeper { return BaseSendKeeper{ - BaseViewKeeper: NewBaseViewKeeper(ak), + BaseViewKeeper: NewBaseViewKeeper(cdc, storeKey, ak), + cdc: cdc, ak: ak, + storeKey: storeKey, paramSpace: paramSpace, blacklistedAddrs: blacklistedAddrs, } } -// InputOutputCoins handles a list of inputs and outputs -func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error { +// InputOutputCoins performs multi-send functionality. It accepts a series of +// inputs that correspond to a series of outputs. It returns an error if the +// inputs and outputs don't lineup or if any single transfer of tokens fails. +func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error { // Safety check ensuring that when sending coins the keeper must maintain the // Check supply invariant and validity of Coins. if err := types.ValidateInputsOutputs(inputs, outputs); err != nil { @@ -185,7 +182,7 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In } for _, in := range inputs { - _, err := keeper.SubtractCoins(ctx, in.Address, in.Coins) + _, err := k.SubtractCoins(ctx, in.Address, in.Coins) if err != nil { return err } @@ -199,7 +196,7 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In } for _, out := range outputs { - _, err := keeper.AddCoins(ctx, out.Address, out.Coins) + _, err := k.AddCoins(ctx, out.Address, out.Coins) if err != nil { return err } @@ -216,8 +213,9 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In return nil } -// SendCoins moves coins from one account to another -func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { +// SendCoins transfers amt coins from a sending account to a receiving account. +// An error is returned upon failure. +func (k BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeTransfer, @@ -230,12 +228,12 @@ func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, ), }) - _, err := keeper.SubtractCoins(ctx, fromAddr, amt) + _, err := k.SubtractCoins(ctx, fromAddr, amt) if err != nil { return err } - _, err = keeper.AddCoins(ctx, toAddr, amt) + _, err = k.AddCoins(ctx, toAddr, amt) if err != nil { return err } @@ -243,92 +241,129 @@ func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, return nil } -// SubtractCoins subtracts amt from the coins at the addr. -// -// CONTRACT: If the account is a vesting account, the amount has to be spendable. -func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { +// SubtractCoins removes amt coins the account by the given address. An error is +// returned if the resulting balance is negative or the initial amount is invalid. +func (k BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { if !amt.IsValid() { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - oldCoins, spendableCoins := sdk.NewCoins(), sdk.NewCoins() + resultCoins := sdk.NewCoins() + lockedCoins := k.LockedCoins(ctx, addr) - acc := keeper.ak.GetAccount(ctx, addr) - if acc != nil { - oldCoins = acc.GetCoins() - spendableCoins = acc.SpendableCoins(ctx.BlockHeader().Time) - } + for _, coin := range amt { + balance := k.GetBalance(ctx, addr, coin.Denom) + locked := sdk.NewCoin(coin.Denom, lockedCoins.AmountOf(coin.Denom)) + spendable := balance.Sub(locked) - // For non-vesting accounts, spendable coins will simply be the original coins. - // So the check here is sufficient instead of subtracting from oldCoins. - _, hasNeg := spendableCoins.SafeSub(amt) - if hasNeg { - return amt, sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", spendableCoins, amt, - ) - } + _, hasNeg := sdk.Coins{spendable}.SafeSub(sdk.Coins{coin}) + if hasNeg { + return nil, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "%s < %s", spendable, coin) + } - newCoins := oldCoins.Sub(amt) // should not panic as spendable coins was already checked - err := keeper.SetCoins(ctx, addr, newCoins) + newBalance := balance.Sub(coin) + resultCoins = resultCoins.Add(newBalance) - return newCoins, err + k.SetBalance(ctx, addr, newBalance) + } + + return resultCoins, nil } -// AddCoins adds amt to the coins at the addr. -func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { +// AddCoins adds amt to the account balance given by the provided address. An +// error is returned if the initial amount is invalid or if any resulting new +// balance is negative. +func (k BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { if !amt.IsValid() { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - oldCoins := keeper.GetCoins(ctx, addr) - newCoins := oldCoins.Add(amt...) + var resultCoins sdk.Coins - if newCoins.IsAnyNegative() { - return amt, sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, - ) + for _, coin := range amt { + balance := k.GetBalance(ctx, addr, coin.Denom) + + // newBalance should never be negative as the amount is already validated + newBalance := balance.Add(coin) + if newBalance.IsNegative() { + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "resulting balance %s is negative", newBalance, + ) + } + + resultCoins = resultCoins.Add(newBalance) + + k.SetBalance(ctx, addr, newBalance) } - err := keeper.SetCoins(ctx, addr, newCoins) - return newCoins, err + return resultCoins, nil } -// SetCoins sets the coins at the addr. -func (keeper BaseSendKeeper) SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { - if !amt.IsValid() { - sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) +// ClearBalances removes all balances for a given account by address. +func (k BaseSendKeeper) ClearBalances(ctx sdk.Context, addr sdk.AccAddress) { + keys := [][]byte{} + k.IterateAccountBalances(ctx, addr, func(balance sdk.Coin) bool { + keys = append(keys, []byte(balance.Denom)) + return false + }) + + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + for _, key := range keys { + accountStore.Delete(key) } +} - acc := keeper.ak.GetAccount(ctx, addr) - if acc == nil { - acc = keeper.ak.NewAccountWithAddress(ctx, addr) +// SetBalances sets the balance (multiple coins) for an account by address. It will +// clear out all balances prior to setting the new coins as to set existing balances +// to zero if they don't exist in amt. An error is returned upon failure. +func (k BaseSendKeeper) SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error { + k.ClearBalances(ctx, addr) + + for _, balance := range balances { + err := k.SetBalance(ctx, addr, balance) + if err != nil { + return err + } } - err := acc.SetCoins(amt) - if err != nil { - panic(err) + return nil +} + +// SetBalance sets the coin balance for an account by address. +func (k BaseSendKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error { + if !balance.IsValid() { + sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) } - keeper.ak.SetAccount(ctx, acc) + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + bz := k.cdc.MustMarshalBinaryBare(balance) + accountStore.Set([]byte(balance.Denom), bz) + return nil } // GetSendEnabled returns the current SendEnabled -func (keeper BaseSendKeeper) GetSendEnabled(ctx sdk.Context) bool { +func (k BaseSendKeeper) GetSendEnabled(ctx sdk.Context) bool { var enabled bool - keeper.paramSpace.Get(ctx, types.ParamStoreKeySendEnabled, &enabled) + k.paramSpace.Get(ctx, types.ParamStoreKeySendEnabled, &enabled) return enabled } // SetSendEnabled sets the send enabled -func (keeper BaseSendKeeper) SetSendEnabled(ctx sdk.Context, enabled bool) { - keeper.paramSpace.Set(ctx, types.ParamStoreKeySendEnabled, &enabled) +func (k BaseSendKeeper) SetSendEnabled(ctx sdk.Context, enabled bool) { + k.paramSpace.Set(ctx, types.ParamStoreKeySendEnabled, &enabled) } // BlacklistedAddr checks if a given address is blacklisted (i.e restricted from // receiving funds) -func (keeper BaseSendKeeper) BlacklistedAddr(addr sdk.AccAddress) bool { - return keeper.blacklistedAddrs[addr.String()] +func (k BaseSendKeeper) BlacklistedAddr(addr sdk.AccAddress) bool { + return k.blacklistedAddrs[addr.String()] } var _ ViewKeeper = (*BaseViewKeeper)(nil) @@ -336,57 +371,163 @@ var _ ViewKeeper = (*BaseViewKeeper)(nil) // ViewKeeper defines a module interface that facilitates read only access to // account balances. type ViewKeeper interface { - GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) bool + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + + IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(coin sdk.Coin) (stop bool)) + IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, coin sdk.Coin) (stop bool)) } // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { - ak types.AccountKeeper + cdc *codec.Codec + storeKey sdk.StoreKey + ak types.AccountKeeper } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper(ak types.AccountKeeper) BaseViewKeeper { - return BaseViewKeeper{ak: ak} +func NewBaseViewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper) BaseViewKeeper { + return BaseViewKeeper{ + cdc: cdc, + storeKey: storeKey, + ak: ak, + } } // Logger returns a module-specific logger. -func (keeper BaseViewKeeper) Logger(ctx sdk.Context) log.Logger { +func (k BaseViewKeeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -// GetCoins returns the coins at the addr. -func (keeper BaseViewKeeper) GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { - acc := keeper.ak.GetAccount(ctx, addr) - if acc == nil { - return sdk.NewCoins() +// HasBalance returns whether or not an account has at least amt balance. +func (k BaseViewKeeper) HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool { + return k.GetBalance(ctx, addr, amt.Denom).IsGTE(amt) +} + +// GetAllBalances returns all the account balances for the given account address. +func (k BaseViewKeeper) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + balances := sdk.NewCoins() + k.IterateAccountBalances(ctx, addr, func(balance sdk.Coin) bool { + balances = balances.Add(balance) + return false + }) + + return balances +} + +// GetBalance returns the balance of a specific denomination for a given account +// by address. +func (k BaseViewKeeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + bz := accountStore.Get([]byte(denom)) + if bz == nil { + return sdk.NewCoin(denom, sdk.ZeroInt()) } - return acc.GetCoins() + + var balance sdk.Coin + k.cdc.MustUnmarshalBinaryBare(bz, &balance) + + return balance } -// HasCoins returns whether or not an account has at least amt coins. -func (keeper BaseViewKeeper) HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) bool { - return keeper.GetCoins(ctx, addr).IsAllGTE(amt) +// IterateAccountBalances iterates over the balances of a single account and +// provides the token balance to a callback. If true is returned from the +// callback, iteration is halted. +func (k BaseViewKeeper) IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(sdk.Coin) bool) { + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + iterator := accountStore.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var balance sdk.Coin + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &balance) + + if cb(balance) { + break + } + } } -// CONTRACT: assumes that amt is valid. -func trackDelegation(acc authexported.Account, blockTime time.Time, amt sdk.Coins) error { +// IterateAllBalances iterates over all the balances of all accounts and +// denominations that are provided to a callback. If true is returned from the +// callback, iteration is halted. +func (k BaseViewKeeper) IterateAllBalances(ctx sdk.Context, cb func(sdk.AccAddress, sdk.Coin) bool) { + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + + iterator := balancesStore.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + address := types.AddressFromBalancesKey(iterator.Key()) + + var balance sdk.Coin + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &balance) + + if cb(address, balance) { + break + } + } +} + +// LockedCoins returns all the coins that are not spendable (i.e. locked) for an +// account by address. For standard accounts, the result will always be no coins. +// For vesting accounts, LockedCoins is delegated to the concrete vesting account +// type. +func (k BaseViewKeeper) LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + acc := k.ak.GetAccount(ctx, addr) + if acc != nil { + vacc, ok := acc.(vestexported.VestingAccount) + if ok { + vestingCoins := vacc.GetVestingCoins(ctx.BlockTime()) + balance := sdk.NewCoins() + + for _, vestingCoin := range vestingCoins { + balance := k.GetBalance(ctx, acc.GetAddress(), vestingCoin.Denom) + balance.Add(balance) + } + + return vacc.LockedCoins(balance, ctx.BlockTime()) + } + } + + return sdk.NewCoins() +} + +func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, blockTime time.Time, balance, amt sdk.Coins) error { + acc := k.ak.GetAccount(ctx, addr) + if acc == nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) + } + vacc, ok := acc.(vestexported.VestingAccount) if ok { // TODO: return error on account.TrackDelegation - vacc.TrackDelegation(blockTime, amt) + vacc.TrackDelegation(blockTime, balance, amt) } - return acc.SetCoins(acc.GetCoins().Sub(amt)) + return nil } -// CONTRACT: assumes that amt is valid. -func trackUndelegation(acc authexported.Account, amt sdk.Coins) error { +func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { + acc := k.ak.GetAccount(ctx, addr) + if acc == nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) + } + vacc, ok := acc.(vestexported.VestingAccount) if ok { // TODO: return error on account.TrackUndelegation vacc.TrackUndelegation(amt) } - return acc.SetCoins(acc.GetCoins().Add(amt...)) + return nil } diff --git a/x/bank/internal/keeper/querier.go b/x/bank/internal/keeper/querier.go index 165d0187962..072511b2d2a 100644 --- a/x/bank/internal/keeper/querier.go +++ b/x/bank/internal/keeper/querier.go @@ -9,26 +9,22 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) -const ( - // query balance path - QueryBalance = "balances" -) - // NewQuerier returns a new sdk.Keeper instance. func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { - case QueryBalance: + case types.QueryBalance: return queryBalance(ctx, req, k) + case types.QueryAllBalances: + return queryAllBalance(ctx, req, k) + default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -// queryBalance fetch an account's balance for the supplied height. -// Height and account address are passed as first and second path components respectively. func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBalanceParams @@ -36,12 +32,26 @@ func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, err return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } - coins := k.GetCoins(ctx, params.Address) - if coins == nil { - coins = sdk.NewCoins() + balance := k.GetBalance(ctx, params.Address, params.Denom) + + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, balance) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } - bz, err := codec.MarshalJSONIndent(types.ModuleCdc, coins) + return bz, nil +} + +func queryAllBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryAllBalancesParams + + if err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + balances := k.GetAllBalances(ctx, params.Address) + + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, balances) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } diff --git a/x/bank/internal/types/genesis.go b/x/bank/internal/types/genesis.go index 159b04f1f9a..1505f64da55 100644 --- a/x/bank/internal/types/genesis.go +++ b/x/bank/internal/types/genesis.go @@ -1,18 +1,88 @@ package types -// GenesisState is the bank state that must be provided at genesis. +import ( + "bytes" + "encoding/json" + "sort" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/exported" +) + +var _ exported.GenesisBalance = (*Balance)(nil) + +// GenesisState defines the bank module's genesis state. type GenesisState struct { - SendEnabled bool `json:"send_enabled" yaml:"send_enabled"` + SendEnabled bool `json:"send_enabled" yaml:"send_enabled"` + Balances []Balance `json:"balances" yaml:"balances"` +} + +// Balance defines an account address and balance pair used in the bank module's +// genesis state. +type Balance struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` +} + +// GetAddress returns the account address of the Balance object. +func (b Balance) GetAddress() sdk.AccAddress { + return b.Address +} + +// GetAddress returns the account coins of the Balance object. +func (b Balance) GetCoins() sdk.Coins { + return b.Coins +} + +// SanitizeGenesisAccounts sorts addresses and coin sets. +func SanitizeGenesisBalances(balances []Balance) []Balance { + sort.Slice(balances, func(i, j int) bool { + return bytes.Compare(balances[i].Address.Bytes(), balances[j].Address.Bytes()) < 0 + }) + + for _, balance := range balances { + balance.Coins = balance.Coins.Sort() + } + + return balances } // NewGenesisState creates a new genesis state. -func NewGenesisState(sendEnabled bool) GenesisState { - return GenesisState{SendEnabled: sendEnabled} +func NewGenesisState(sendEnabled bool, balances []Balance) GenesisState { + return GenesisState{SendEnabled: sendEnabled, Balances: balances} } -// DefaultGenesisState returns a default genesis state -func DefaultGenesisState() GenesisState { return NewGenesisState(true) } +// DefaultGenesisState returns a default bank module genesis state. +func DefaultGenesisState() GenesisState { return NewGenesisState(true, []Balance{}) } // ValidateGenesis performs basic validation of bank genesis data returning an // error for any failed validation criteria. func ValidateGenesis(data GenesisState) error { return nil } + +// GetGenesisStateFromAppState returns x/bank GenesisState given raw application +// genesis state. +func GetGenesisStateFromAppState(cdc *codec.Codec, appState map[string]json.RawMessage) GenesisState { + var genesisState GenesisState + if appState[ModuleName] != nil { + cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState) + } + + return genesisState +} + +// GenesisAccountIterator implements genesis account iteration. +type GenesisBalancesIterator struct{} + +// IterateGenesisAccounts iterates over all the genesis accounts found in +// appGenesis and invokes a callback on each genesis account. If any call +// returns true, iteration stops. +func (GenesisBalancesIterator) IterateGenesisBalances( + cdc *codec.Codec, appState map[string]json.RawMessage, cb func(exported.GenesisBalance) (stop bool), +) { + for _, balance := range GetGenesisStateFromAppState(cdc, appState).Balances { + if cb(balance) { + break + } + } +} diff --git a/x/bank/internal/types/key.go b/x/bank/internal/types/key.go index 7e38aeb5248..0a9e716f73a 100644 --- a/x/bank/internal/types/key.go +++ b/x/bank/internal/types/key.go @@ -1,7 +1,30 @@ package types +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + const ( - // module name - ModuleName = "bank" + // ModuleName defines the module name + ModuleName = "bank" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey defines the module's message routing key + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key QuerierRoute = ModuleName ) + +// KVStore key prefixes +var ( + BalancesPrefix = []byte("balances") +) + +// AddressFromBalancesKey returns an account address from a balances key which +// is used as an index to store balances per account. +func AddressFromBalancesKey(key []byte) sdk.AccAddress { + return sdk.AccAddress(key[len(BalancesPrefix) : len(BalancesPrefix)+sdk.AddrLen]) +} diff --git a/x/bank/internal/types/key_test.go b/x/bank/internal/types/key_test.go new file mode 100644 index 00000000000..5065794588e --- /dev/null +++ b/x/bank/internal/types/key_test.go @@ -0,0 +1,26 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/internal/types" + "github.com/stretchr/testify/require" +) + +func cloneAppend(bz []byte, tail []byte) (res []byte) { + res = make([]byte, len(bz)+len(tail)) + copy(res, bz) + copy(res[len(bz):], tail) + return +} + +func TestAddressFromBalancesKey(t *testing.T) { + addr, err := sdk.AccAddressFromBech32("cosmos1n88uc38xhjgxzw9nwre4ep2c8ga4fjxcar6mn7") + require.NoError(t, err) + + key := cloneAppend(types.BalancesPrefix, addr.Bytes()) + + res := types.AddressFromBalancesKey(key) + require.Equal(t, res, addr) +} diff --git a/x/bank/internal/types/msgs.go b/x/bank/internal/types/msgs.go index 50f8e3f06ff..83db26aaefd 100644 --- a/x/bank/internal/types/msgs.go +++ b/x/bank/internal/types/msgs.go @@ -5,9 +5,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// RouterKey is they name of the bank module -const RouterKey = ModuleName - // MsgSend - high level transaction of the coin module type MsgSend struct { FromAddress sdk.AccAddress `json:"from_address" yaml:"from_address"` diff --git a/x/bank/internal/types/querier.go b/x/bank/internal/types/querier.go index ef0a8576b87..7e0ef43fe7b 100644 --- a/x/bank/internal/types/querier.go +++ b/x/bank/internal/types/querier.go @@ -4,12 +4,29 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// Querier path constants +const ( + QueryBalance = "balance" + QueryAllBalances = "all_balances" +) + // QueryBalanceParams defines the params for querying an account balance. type QueryBalanceParams struct { Address sdk.AccAddress + Denom string } // NewQueryBalanceParams creates a new instance of QueryBalanceParams. -func NewQueryBalanceParams(addr sdk.AccAddress) QueryBalanceParams { - return QueryBalanceParams{Address: addr} +func NewQueryBalanceParams(addr sdk.AccAddress, denom string) QueryBalanceParams { + return QueryBalanceParams{Address: addr, Denom: denom} +} + +// QueryAllBalancesParams defines the params for querying all account balances +type QueryAllBalancesParams struct { + Address sdk.AccAddress +} + +// NewQueryAllBalancesParams creates a new instance of QueryAllBalancesParams. +func NewQueryAllBalancesParams(addr sdk.AccAddress) QueryAllBalancesParams { + return QueryAllBalancesParams{Address: addr} } diff --git a/x/bank/module.go b/x/bank/module.go index 11496238275..7c0281d5dc3 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -90,7 +90,7 @@ func (AppModule) Name() string { return ModuleName } // RegisterInvariants registers the bank module invariants. func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - keeper.RegisterInvariants(ir, am.accountKeeper) + keeper.RegisterInvariants(ir, am.keeper) } // Route returns the message routing key for the bank module. diff --git a/x/bank/simulation/genesis.go b/x/bank/simulation/genesis.go index 2dae431c986..38172b20876 100644 --- a/x/bank/simulation/genesis.go +++ b/x/bank/simulation/genesis.go @@ -7,6 +7,7 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) @@ -21,6 +22,21 @@ func GenSendEnabled(r *rand.Rand) bool { return r.Int63n(101) <= 95 // 95% chance of transfers being enabled } +// RandomGenesisAccounts returns a slice of account balances. Each account has +// a balance of simState.InitialStake for sdk.DefaultBondDenom. +func RandomGenesisBalances(simState *module.SimulationState) []types.Balance { + genesisBalances := []types.Balance{} + + for _, acc := range simState.Accounts { + genesisBalances = append(genesisBalances, types.Balance{ + Address: acc.Address, + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(simState.InitialStake))), + }) + } + + return genesisBalances +} + // RandomizedGenState generates a random GenesisState for bank func RandomizedGenState(simState *module.SimulationState) { var sendEnabled bool @@ -29,7 +45,7 @@ func RandomizedGenState(simState *module.SimulationState) { func(r *rand.Rand) { sendEnabled = GenSendEnabled(r) }, ) - bankGenesis := types.NewGenesisState(sendEnabled) + bankGenesis := types.NewGenesisState(sendEnabled, RandomGenesisBalances(simState)) fmt.Printf("Selected randomly generated bank parameters:\n%s\n", codec.MustMarshalJSONIndent(simState.Cdc, bankGenesis)) simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(bankGenesis) diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 123e0b8eb45..90c97522e68 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -63,7 +63,7 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat return simulation.NoOpMsg(types.ModuleName), nil, nil } - simAccount, toSimAcc, coins, skip, err := randomSendFields(r, ctx, accs, ak) + simAccount, toSimAcc, coins, skip, err := randomSendFields(r, ctx, accs, bk, ak) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -74,7 +74,7 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat msg := types.NewMsgSend(simAccount.Address, toSimAcc.Address, coins) - err = sendMsgSend(r, app, ak, msg, ctx, chainID, []crypto.PrivKey{simAccount.PrivKey}) + err = sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []crypto.PrivKey{simAccount.PrivKey}) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -85,19 +85,19 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat // sendMsgSend sends a transaction with a MsgSend from a provided random account. func sendMsgSend( - r *rand.Rand, app *baseapp.BaseApp, ak types.AccountKeeper, + r *rand.Rand, app *baseapp.BaseApp, bk keeper.Keeper, ak types.AccountKeeper, msg types.MsgSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, ) error { account := ak.GetAccount(ctx, msg.FromAddress) - coins := account.SpendableCoins(ctx.BlockTime()) var ( fees sdk.Coins err error ) - coins, hasNeg := coins.SafeSub(msg.Amount) - if !hasNeg { + cacheCtx, _ := ctx.CacheContext() + coins, err := bk.SubtractCoins(cacheCtx, msg.FromAddress, msg.Amount) + if err == nil { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { return err @@ -148,11 +148,11 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O var totalSentCoins sdk.Coins for i := range inputs { // generate random input fields, ignore to address - simAccount, _, coins, skip, err := randomSendFields(r, ctx, accs, ak) + simAccount, _, coins, skip, err := randomSendFields(r, ctx, accs, bk, ak) // make sure account is fresh and not used in previous input for usedAddrs[simAccount.Address.String()] { - simAccount, _, coins, skip, err = randomSendFields(r, ctx, accs, ak) + simAccount, _, coins, skip, err = randomSendFields(r, ctx, accs, bk, ak) } if err != nil { @@ -207,7 +207,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O Outputs: outputs, } - err := sendMsgMultiSend(r, app, ak, msg, ctx, chainID, privs) + err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -219,7 +219,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O // sendMsgMultiSend sends a transaction with a MsgMultiSend from a provided random // account. func sendMsgMultiSend( - r *rand.Rand, app *baseapp.BaseApp, ak types.AccountKeeper, + r *rand.Rand, app *baseapp.BaseApp, bk keeper.Keeper, ak types.AccountKeeper, msg types.MsgMultiSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, ) error { @@ -234,14 +234,14 @@ func sendMsgMultiSend( // feePayer is the first signer, i.e. first input address feePayer := ak.GetAccount(ctx, msg.Inputs[0].Address) - coins := feePayer.SpendableCoins(ctx.BlockTime()) var ( fees sdk.Coins err error ) - coins, hasNeg := coins.SafeSub(msg.Inputs[0].Coins) - if !hasNeg { + cacheCtx, _ := ctx.CacheContext() + coins, err := bk.SubtractCoins(cacheCtx, feePayer.GetAddress(), msg.Inputs[0].Coins) + if err == nil { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { return err @@ -269,7 +269,7 @@ func sendMsgMultiSend( // randomSendFields returns the sender and recipient simulation accounts as well // as the transferred amount. func randomSendFields( - r *rand.Rand, ctx sdk.Context, accs []simulation.Account, ak types.AccountKeeper, + r *rand.Rand, ctx sdk.Context, accs []simulation.Account, bk keeper.Keeper, ak types.AccountKeeper, ) (simulation.Account, simulation.Account, sdk.Coins, bool, error) { simAccount, _ := simulation.RandomAcc(r, accs) @@ -285,9 +285,11 @@ func randomSendFields( return simAccount, toSimAcc, nil, true, nil // skip error } - coins := acc.SpendableCoins(ctx.BlockHeader().Time) + balances := bk.GetAllBalances(ctx, acc.GetAddress()) + locked := bk.LockedCoins(ctx, acc.GetAddress()) + balances = balances.Sub(locked) - sendCoins := simulation.RandSubsetCoins(r, coins) + sendCoins := simulation.RandSubsetCoins(r, balances) if sendCoins.Empty() { return simAccount, toSimAcc, nil, true, nil // skip error } diff --git a/x/genutil/client/cli/collect.go b/x/genutil/client/cli/collect.go index bc38ab74d28..f80bdabc060 100644 --- a/x/genutil/client/cli/collect.go +++ b/x/genutil/client/cli/collect.go @@ -21,7 +21,7 @@ const flagGenTxDir = "gentx-dir" // CollectGenTxsCmd - return the cobra command to collect genesis transactions func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec, - genAccIterator types.GenesisAccountsIterator, defaultNodeHome string) *cobra.Command { + genBalIterator types.GenesisBalancesIterator, defaultNodeHome string) *cobra.Command { cmd := &cobra.Command{ Use: "collect-gentxs", @@ -48,7 +48,7 @@ func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec, toPrint := newPrintInfo(config.Moniker, genDoc.ChainID, nodeID, genTxsDir, json.RawMessage("")) initCfg := genutil.NewInitConfig(genDoc.ChainID, genTxsDir, name, nodeID, valPubKey) - appMessage, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genAccIterator) + appMessage, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genBalIterator) if err != nil { return errors.Wrap(err, "failed to get genesis app state from config") } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 18ef098ff67..b992f446fe7 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -42,7 +42,7 @@ type StakingMsgBuildingHelpers interface { // GenTxCmd builds the application's gentx command. // nolint: errcheck func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, smbh StakingMsgBuildingHelpers, - genAccIterator types.GenesisAccountsIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command { + genBalIterator types.GenesisBalancesIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command { ipDefault, _ := server.ExternalIP() fsCreateValidator, flagNodeID, flagPubKey, flagAmount, defaultsDesc := smbh.CreateValidatorMsgHelpers(ipDefault) @@ -116,7 +116,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, sm return errors.Wrap(err, "failed to parse coins") } - err = genutil.ValidateAccountInGenesis(genesisState, genAccIterator, key.GetAddress(), coins, cdc) + err = genutil.ValidateAccountInGenesis(genesisState, genBalIterator, key.GetAddress(), coins, cdc) if err != nil { return errors.Wrap(err, "failed to validate account in genesis") } diff --git a/x/genutil/collect.go b/x/genutil/collect.go index 7145efb048a..4e000b91b8f 100644 --- a/x/genutil/collect.go +++ b/x/genutil/collect.go @@ -17,21 +17,21 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/genutil/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // GenAppStateFromConfig gets the genesis app state from the config func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, - initCfg InitConfig, genDoc tmtypes.GenesisDoc, - genAccIterator types.GenesisAccountsIterator, + initCfg InitConfig, genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, ) (appState json.RawMessage, err error) { // process genesis transactions, else create default genesis.json appGenTxs, persistentPeers, err := CollectStdTxs( - cdc, config.Moniker, initCfg.GenTxsDir, genDoc, genAccIterator) + cdc, config.Moniker, initCfg.GenTxsDir, genDoc, genBalIterator, + ) if err != nil { return appState, err } @@ -54,6 +54,7 @@ func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, if err != nil { return appState, err } + appState, err = codec.MarshalJSONIndent(cdc, appGenesisState) if err != nil { return appState, err @@ -61,13 +62,14 @@ func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, genDoc.AppState = appState err = ExportGenesisFile(&genDoc, config.GenesisFile()) + return appState, err } // CollectStdTxs processes and validates application's genesis StdTxs and returns // the list of appGenTxs, and persistent peers required to generate genesis.json. func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, - genDoc tmtypes.GenesisDoc, genAccIterator types.GenesisAccountsIterator, + genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, ) (appGenTxs []authtypes.StdTx, persistentPeers string, err error) { var fos []os.FileInfo @@ -76,17 +78,18 @@ func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, return appGenTxs, persistentPeers, err } - // prepare a map of all accounts in genesis state to then validate + // prepare a map of all balances in genesis state to then validate // against the validators addresses var appState map[string]json.RawMessage if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil { return appGenTxs, persistentPeers, err } - addrMap := make(map[string]authexported.Account) - genAccIterator.IterateGenesisAccounts(cdc, appState, - func(acc authexported.Account) (stop bool) { - addrMap[acc.GetAddress().String()] = acc + balancesMap := make(map[string]bankexported.GenesisBalance) + genBalIterator.IterateGenesisBalances( + cdc, appState, + func(balance bankexported.GenesisBalance) (stop bool) { + balancesMap[balance.GetAddress().String()] = balance return false }, ) @@ -105,10 +108,12 @@ func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, if jsonRawTx, err = ioutil.ReadFile(filename); err != nil { return appGenTxs, persistentPeers, err } + var genStdTx authtypes.StdTx if err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx); err != nil { return appGenTxs, persistentPeers, err } + appGenTxs = append(appGenTxs, genStdTx) // the memo flag is used to store @@ -116,39 +121,36 @@ func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, // "528fd3df22b31f4969b05652bfe8f0fe921321d5@192.168.2.37:26656" nodeAddrIP := genStdTx.GetMemo() if len(nodeAddrIP) == 0 { - return appGenTxs, persistentPeers, fmt.Errorf( - "couldn't find node's address and IP in %s", fo.Name()) + return appGenTxs, persistentPeers, fmt.Errorf("failed to find node's address and IP in %s", fo.Name()) } // genesis transactions must be single-message msgs := genStdTx.GetMsgs() if len(msgs) != 1 { - return appGenTxs, persistentPeers, errors.New( - "each genesis transaction must provide a single genesis message") + return appGenTxs, persistentPeers, errors.New("each genesis transaction must provide a single genesis message") } // TODO abstract out staking message validation back to staking msg := msgs[0].(stakingtypes.MsgCreateValidator) + // validate delegator and validator addresses and funds against the accounts in the state delAddr := msg.DelegatorAddress.String() valAddr := sdk.AccAddress(msg.ValidatorAddress).String() - delAcc, delOk := addrMap[delAddr] + delBal, delOk := balancesMap[delAddr] if !delOk { - return appGenTxs, persistentPeers, fmt.Errorf( - "account %v not in genesis.json: %+v", delAddr, addrMap) + return appGenTxs, persistentPeers, fmt.Errorf("account %s balance not in genesis state: %+v", delAddr, balancesMap) } - _, valOk := addrMap[valAddr] + _, valOk := balancesMap[valAddr] if !valOk { - return appGenTxs, persistentPeers, fmt.Errorf( - "account %v not in genesis.json: %+v", valAddr, addrMap) + return appGenTxs, persistentPeers, fmt.Errorf("account %s balance not in genesis state: %+v", valAddr, balancesMap) } - if delAcc.GetCoins().AmountOf(msg.Value.Denom).LT(msg.Value.Amount) { + if delBal.GetCoins().AmountOf(msg.Value.Denom).LT(msg.Value.Amount) { return appGenTxs, persistentPeers, fmt.Errorf( "insufficient fund for delegation %v: %v < %v", - delAcc.GetAddress(), delAcc.GetCoins().AmountOf(msg.Value.Denom), msg.Value.Amount, + delBal.GetAddress().String(), delBal.GetCoins().AmountOf(msg.Value.Denom), msg.Value.Amount, ) } diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go index 1ac4e64ed4c..577fedcef6a 100644 --- a/x/genutil/gentx.go +++ b/x/genutil/gentx.go @@ -10,24 +10,26 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/genutil/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // SetGenTxsInAppGenesisState - sets the genesis transactions in the app genesis state -func SetGenTxsInAppGenesisState(cdc *codec.Codec, appGenesisState map[string]json.RawMessage, - genTxs []authtypes.StdTx) (map[string]json.RawMessage, error) { +func SetGenTxsInAppGenesisState( + cdc *codec.Codec, appGenesisState map[string]json.RawMessage, genTxs []authtypes.StdTx, +) (map[string]json.RawMessage, error) { genesisState := GetGenesisStateFromAppState(cdc, appGenesisState) - // convert all the GenTxs to JSON genTxsBz := make([]json.RawMessage, 0, len(genTxs)) + for _, genTx := range genTxs { txBz, err := cdc.MarshalJSON(genTx) if err != nil { return appGenesisState, err } + genTxsBz = append(genTxsBz, txBz) } @@ -35,53 +37,52 @@ func SetGenTxsInAppGenesisState(cdc *codec.Codec, appGenesisState map[string]jso return SetGenesisStateInAppState(cdc, appGenesisState, genesisState), nil } -// ValidateAccountInGenesis checks that the provided key has sufficient -// coins in the genesis accounts -func ValidateAccountInGenesis(appGenesisState map[string]json.RawMessage, - genAccIterator types.GenesisAccountsIterator, - key sdk.Address, coins sdk.Coins, cdc *codec.Codec) error { - - accountIsInGenesis := false +// ValidateAccountInGenesis checks that the provided account has a sufficient +// balance in the set of genesis accounts. +func ValidateAccountInGenesis( + appGenesisState map[string]json.RawMessage, genBalIterator types.GenesisBalancesIterator, + addr sdk.Address, coins sdk.Coins, cdc *codec.Codec, +) error { - // TODO: refactor out bond denom to common state area - stakingDataBz := appGenesisState[stakingtypes.ModuleName] var stakingData stakingtypes.GenesisState - cdc.MustUnmarshalJSON(stakingDataBz, &stakingData) + cdc.MustUnmarshalJSON(appGenesisState[stakingtypes.ModuleName], &stakingData) bondDenom := stakingData.Params.BondDenom - genUtilDataBz := appGenesisState[stakingtypes.ModuleName] - var genesisState GenesisState - cdc.MustUnmarshalJSON(genUtilDataBz, &genesisState) - var err error - genAccIterator.IterateGenesisAccounts(cdc, appGenesisState, - func(acc authexported.Account) (stop bool) { - accAddress := acc.GetAddress() - accCoins := acc.GetCoins() - // Ensure that account is in genesis - if accAddress.Equals(key) { + accountIsInGenesis := false + + genBalIterator.IterateGenesisBalances(cdc, appGenesisState, + func(bal bankexported.GenesisBalance) (stop bool) { + accAddress := bal.GetAddress() + accCoins := bal.GetCoins() - // Ensure account contains enough funds of default bond denom + // ensure that account is in genesis + if accAddress.Equals(addr) { + // ensure account contains enough funds of default bond denom if coins.AmountOf(bondDenom).GT(accCoins.AmountOf(bondDenom)) { err = fmt.Errorf( - "account %v is in genesis, but it only has %v%v available to stake, not %v%v", - key.String(), accCoins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom, + "account %s has a balance in genesis, but it only has %v%s available to stake, not %v%s", + addr, accCoins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom, ) + return true } + accountIsInGenesis = true return true } + return false }, ) + if err != nil { return err } if !accountIsInGenesis { - return fmt.Errorf("account %s in not in the app_state.accounts array of genesis.json", key) + return fmt.Errorf("account %s does not have a balance in the genesis state", addr) } return nil @@ -89,18 +90,25 @@ func ValidateAccountInGenesis(appGenesisState map[string]json.RawMessage, type deliverTxfn func(abci.RequestDeliverTx) abci.ResponseDeliverTx -// DeliverGenTxs - deliver a genesis transaction -func DeliverGenTxs(ctx sdk.Context, cdc *codec.Codec, genTxs []json.RawMessage, - stakingKeeper types.StakingKeeper, deliverTx deliverTxfn) []abci.ValidatorUpdate { +// DeliverGenTxs iterates over all genesis txs, decodes each into a StdTx and +// invokes the provided deliverTxfn with the decoded StdTx. It returns the result +// of the staking module's ApplyAndReturnValidatorSetUpdates. +func DeliverGenTxs( + ctx sdk.Context, cdc *codec.Codec, genTxs []json.RawMessage, + stakingKeeper types.StakingKeeper, deliverTx deliverTxfn, +) []abci.ValidatorUpdate { for _, genTx := range genTxs { var tx authtypes.StdTx cdc.MustUnmarshalJSON(genTx, &tx) + bz := cdc.MustMarshalBinaryLengthPrefixed(tx) + res := deliverTx(abci.RequestDeliverTx{Tx: bz}) if !res.IsOK() { panic(res.Log) } } + return stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) } diff --git a/x/genutil/types/expected_keepers.go b/x/genutil/types/expected_keepers.go index b44236d7d8d..bd0e750f2f8 100644 --- a/x/genutil/types/expected_keepers.go +++ b/x/genutil/types/expected_keepers.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" ) // StakingKeeper defines the expected staking keeper (noalias) @@ -27,6 +28,15 @@ type GenesisAccountsIterator interface { IterateGenesisAccounts( cdc *codec.Codec, appGenesis map[string]json.RawMessage, - iterateFn func(authexported.Account) (stop bool), + cb func(authexported.Account) (stop bool), + ) +} + +// GenesisAccountsIterator defines the expected iterating genesis accounts object (noalias) +type GenesisBalancesIterator interface { + IterateGenesisBalances( + cdc *codec.Codec, + appGenesis map[string]json.RawMessage, + cb func(bankexported.GenesisBalance) (stop bool), ) } diff --git a/x/supply/genesis.go b/x/supply/genesis.go index e1dfc41ff55..17546515cf4 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -2,20 +2,19 @@ package supply import ( sdk "github.com/cosmos/cosmos-sdk/types" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/supply/internal/types" ) // InitGenesis sets supply information for genesis. // // CONTRACT: all types of accounts must have been already initialized/created -func InitGenesis(ctx sdk.Context, keeper Keeper, ak types.AccountKeeper, data GenesisState) { +func InitGenesis(ctx sdk.Context, keeper Keeper, bk types.BankKeeper, data GenesisState) { // manually set the total supply based on accounts if not provided if data.Supply.Empty() { var totalSupply sdk.Coins - ak.IterateAccounts(ctx, - func(acc authexported.Account) (stop bool) { - totalSupply = totalSupply.Add(acc.GetCoins()...) + bk.IterateAllBalances(ctx, + func(_ sdk.AccAddress, balance sdk.Coin) (stop bool) { + totalSupply = totalSupply.Add(balance) return false }, ) diff --git a/x/supply/internal/keeper/invariants.go b/x/supply/internal/keeper/invariants.go index aeec368e4bf..0b5ca06694e 100644 --- a/x/supply/internal/keeper/invariants.go +++ b/x/supply/internal/keeper/invariants.go @@ -4,7 +4,6 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/supply/internal/types" ) @@ -26,8 +25,8 @@ func TotalSupply(k Keeper) sdk.Invariant { var expectedTotal sdk.Coins supply := k.GetSupply(ctx) - k.ak.IterateAccounts(ctx, func(acc exported.Account) bool { - expectedTotal = expectedTotal.Add(acc.GetCoins()...) + k.bk.IterateAllBalances(ctx, func(_ sdk.AccAddress, balance sdk.Coin) bool { + expectedTotal = expectedTotal.Add(balance) return false }) diff --git a/x/supply/internal/types/account.go b/x/supply/internal/types/account.go index ac2136ec691..533084d2b0b 100644 --- a/x/supply/internal/types/account.go +++ b/x/supply/internal/types/account.go @@ -116,7 +116,6 @@ func (ma ModuleAccount) Validate() error { type moduleAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -133,7 +132,6 @@ func (ma ModuleAccount) String() string { func (ma ModuleAccount) MarshalYAML() (interface{}, error) { bs, err := yaml.Marshal(moduleAccountPretty{ Address: ma.Address, - Coins: ma.Coins, PubKey: "", AccountNumber: ma.AccountNumber, Sequence: ma.Sequence, @@ -152,7 +150,6 @@ func (ma ModuleAccount) MarshalYAML() (interface{}, error) { func (ma ModuleAccount) MarshalJSON() ([]byte, error) { return json.Marshal(moduleAccountPretty{ Address: ma.Address, - Coins: ma.Coins, PubKey: "", AccountNumber: ma.AccountNumber, Sequence: ma.Sequence, @@ -168,7 +165,7 @@ func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error { return err } - ma.BaseAccount = authtypes.NewBaseAccount(alias.Address, alias.Coins, nil, alias.AccountNumber, alias.Sequence) + ma.BaseAccount = authtypes.NewBaseAccount(alias.Address, nil, alias.AccountNumber, alias.Sequence) ma.Name = alias.Name ma.Permissions = alias.Permissions diff --git a/x/supply/internal/types/expected_keepers.go b/x/supply/internal/types/expected_keepers.go index 3ad1d8b13ce..8ef551e7e63 100644 --- a/x/supply/internal/types/expected_keepers.go +++ b/x/supply/internal/types/expected_keepers.go @@ -21,4 +21,6 @@ type BankKeeper interface { SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) + + IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, balance sdk.Coin) (stop bool)) } diff --git a/x/supply/module.go b/x/supply/module.go index 05ae901ebf7..73d05a77224 100644 --- a/x/supply/module.go +++ b/x/supply/module.go @@ -76,14 +76,16 @@ type AppModule struct { AppModuleBasic keeper Keeper + bk types.BankKeeper ak types.AccountKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, ak types.AccountKeeper) AppModule { +func NewAppModule(keeper Keeper, bk types.BankKeeper, ak types.AccountKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, + bk: bk, ak: ak, } } @@ -121,7 +123,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, am.ak, genesisState) + InitGenesis(ctx, am.keeper, am.bk, genesisState) return []abci.ValidatorUpdate{} } From 5af9e4baf5e39ae2eb224656a0880120276ba33b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 11:23:16 -0500 Subject: [PATCH 02/24] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b48c8a79b..9abe7a1a3c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,9 +37,15 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Client Breaking + +* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) The `/bank/balances/{address}` endpoint now returns all account +balances or a single balance by denom when the `denom` query parameter is present. + ### API Breaking Changes * (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move x/auth/client/utils/ types and functions to x/auth/client/. +* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`. ### Bug Fixes @@ -47,7 +53,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking -* (modules) [\#5539](https://github.com/cosmos/cosmos-sdk/pull/5539) Separate balance from accounts per ADR 004. +* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Separate balance from accounts per ADR 004. * Account balances are now persisted and retrieved via the `x/bank` module. * Vesting account interface has been modified to account for changes. * Callers to `NewBaseVestingAccount` are responsible for verifying account balance in relation to From 9855200c70a16ba05196a6231ac82abc34ea7a66 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 12:08:56 -0500 Subject: [PATCH 03/24] Implement and call ValidateBalance in x/bank InitGenesis --- x/bank/genesis.go | 4 ++++ x/bank/internal/keeper/keeper.go | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/x/bank/genesis.go b/x/bank/genesis.go index f3141a64128..c93196e2553 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -10,6 +10,10 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, genState GenesisState) { genState.Balances = SanitizeGenesisBalances(genState.Balances) for _, balance := range genState.Balances { + if err := keeper.ValidateBalance(ctx, balance.Address); err != nil { + panic(err) + } + keeper.SetBalances(ctx, balance.Address, balance.Coins) } } diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index e32008951b2..9d29cdbd7d5 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -371,6 +371,8 @@ var _ ViewKeeper = (*BaseViewKeeper)(nil) // ViewKeeper defines a module interface that facilitates read only access to // account balances. type ViewKeeper interface { + ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin @@ -502,6 +504,31 @@ func (k BaseViewKeeper) LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Co return sdk.NewCoins() } +// ValidateBalance validates all balances for a given account address returning +// an error if any balance is invalid. It will check for vesting account types +// and validate the balances against the original vesting balances. +func (k BaseViewKeeper) ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error { + acc := k.ak.GetAccount(ctx, addr) + if acc == nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) + } + + balances := k.GetAllBalances(ctx, addr) + if !balances.IsValid() { + return fmt.Errorf("account balance of %s is invalid", balances) + } + + vacc, ok := acc.(vestexported.VestingAccount) + if ok { + ogv := vacc.GetOriginalVesting() + if ogv.IsAnyGT(balances) { + return fmt.Errorf("vesting amount %s cannot be greater than total amount %s", ogv, balances) + } + } + + return nil +} + func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, blockTime time.Time, balance, amt sdk.Coins) error { acc := k.ak.GetAccount(ctx, addr) if acc == nil { From 4d52eb31d94e322daddd1fa8d84573a656ce5bee Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 14:09:55 -0500 Subject: [PATCH 04/24] Staking updates --- x/bank/internal/keeper/keeper.go | 3 +- x/staking/genesis.go | 16 +++++--- x/staking/keeper/invariants.go | 6 +-- x/staking/keeper/keeper.go | 12 +++--- x/staking/keeper/pool.go | 7 ++-- x/staking/keeper/querier.go | 4 +- x/staking/module.go | 15 ++++--- x/staking/simulation/operations.go | 62 ++++++++++++++++++----------- x/staking/types/expected_keepers.go | 8 ++++ 9 files changed, 83 insertions(+), 50 deletions(-) diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 9d29cdbd7d5..c0c9d16f70b 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -372,6 +372,7 @@ var _ ViewKeeper = (*BaseViewKeeper)(nil) // account balances. type ViewKeeper interface { ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error + HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin @@ -416,7 +417,7 @@ func (k BaseViewKeeper) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk return false }) - return balances + return balances.Sort() } // GetBalance returns the balance of a specific denomination for a given account diff --git a/x/staking/genesis.go b/x/staking/genesis.go index 4c1bbee7072..5c558ca4259 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -16,8 +16,10 @@ import ( // setting the indexes. In addition, it also sets any delegations found in // data. Finally, it updates the bonded validators. // Returns final validator set after applying all declaration and delegations -func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper, - supplyKeeper types.SupplyKeeper, data types.GenesisState) (res []abci.ValidatorUpdate) { +func InitGenesis( + ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, supplyKeeper types.SupplyKeeper, data types.GenesisState, +) (res []abci.ValidatorUpdate) { bondedTokens := sdk.ZeroInt() notBondedTokens := sdk.ZeroInt() @@ -98,10 +100,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 // add coins if not provided on genesis - if bondedPool.GetCoins().IsZero() { - if err := bondedPool.SetCoins(bondedCoins); err != nil { + if bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()).IsZero() { + if err := bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins); err != nil { panic(err) } + supplyKeeper.SetModuleAccount(ctx, bondedPool) } @@ -110,10 +113,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName)) } - if notBondedPool.GetCoins().IsZero() { - if err := notBondedPool.SetCoins(notBondedCoins); err != nil { + if bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()).IsZero() { + if err := bankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedCoins); err != nil { panic(err) } + supplyKeeper.SetModuleAccount(ctx, notBondedPool) } diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go index e89cfab1d04..0dc0a83824b 100644 --- a/x/staking/keeper/invariants.go +++ b/x/staking/keeper/invariants.go @@ -74,9 +74,9 @@ func ModuleAccountInvariants(k Keeper) sdk.Invariant { return false }) - poolBonded := bondedPool.GetCoins().AmountOf(bondDenom) - poolNotBonded := notBondedPool.GetCoins().AmountOf(bondDenom) - broken := !poolBonded.Equal(bonded) || !poolNotBonded.Equal(notBonded) + poolBonded := k.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom) + poolNotBonded := k.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom) + broken := !poolBonded.Amount.Equal(bonded) || !poolNotBonded.Amount.Equal(notBonded) // Bonded tokens should equal sum of tokens with bonded validators // Not-bonded tokens should equal unbonding delegations plus tokens on unbonded validators diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index fd51603115b..412f6a3a846 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -24,6 +24,7 @@ var _ types.DelegationSet = Keeper{} type Keeper struct { storeKey sdk.StoreKey cdc *codec.Codec + bankKeeper types.BankKeeper supplyKeeper types.SupplyKeeper hooks types.StakingHooks paramstore params.Subspace @@ -33,23 +34,24 @@ type Keeper struct { // NewKeeper creates a new staking Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, supplyKeeper types.SupplyKeeper, paramstore params.Subspace, + cdc *codec.Codec, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps params.Subspace, ) Keeper { // ensure bonded and not bonded module accounts are set - if addr := supplyKeeper.GetModuleAddress(types.BondedPoolName); addr == nil { + if addr := sk.GetModuleAddress(types.BondedPoolName); addr == nil { panic(fmt.Sprintf("%s module account has not been set", types.BondedPoolName)) } - if addr := supplyKeeper.GetModuleAddress(types.NotBondedPoolName); addr == nil { + if addr := sk.GetModuleAddress(types.NotBondedPoolName); addr == nil { panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName)) } return Keeper{ storeKey: key, cdc: cdc, - supplyKeeper: supplyKeeper, - paramstore: paramstore.WithKeyTable(ParamKeyTable()), + bankKeeper: bk, + supplyKeeper: sk, + paramstore: ps.WithKeyTable(ParamKeyTable()), hooks: nil, validatorCache: make(map[string]cachedValidator, aminoCacheSize), validatorCacheList: list.New(), diff --git a/x/staking/keeper/pool.go b/x/staking/keeper/pool.go index 004013ed8fe..d593bbbe53b 100644 --- a/x/staking/keeper/pool.go +++ b/x/staking/keeper/pool.go @@ -57,7 +57,7 @@ func (k Keeper) burnNotBondedTokens(ctx sdk.Context, amt sdk.Int) error { // TotalBondedTokens total staking tokens supply which is bonded func (k Keeper) TotalBondedTokens(ctx sdk.Context) sdk.Int { bondedPool := k.GetBondedPool(ctx) - return bondedPool.GetCoins().AmountOf(k.BondDenom(ctx)) + return k.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), k.BondDenom(ctx)).Amount } // StakingTokenSupply staking tokens from the total supply @@ -67,11 +67,10 @@ func (k Keeper) StakingTokenSupply(ctx sdk.Context) sdk.Int { // BondedRatio the fraction of the staking tokens which are currently bonded func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec { - bondedPool := k.GetBondedPool(ctx) - stakeSupply := k.StakingTokenSupply(ctx) if stakeSupply.IsPositive() { - return bondedPool.GetCoins().AmountOf(k.BondDenom(ctx)).ToDec().QuoInt(stakeSupply) + return k.TotalBondedTokens(ctx).ToDec().QuoInt(stakeSupply) } + return sdk.ZeroDec() } diff --git a/x/staking/keeper/querier.go b/x/staking/keeper/querier.go index bc8a5b5b7fc..1c9f54e7d3f 100644 --- a/x/staking/keeper/querier.go +++ b/x/staking/keeper/querier.go @@ -375,8 +375,8 @@ func queryPool(ctx sdk.Context, k Keeper) ([]byte, error) { } pool := types.NewPool( - notBondedPool.GetCoins().AmountOf(bondDenom), - bondedPool.GetCoins().AmountOf(bondDenom), + k.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount, + k.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount, ) res, err := codec.MarshalJSONIndent(types.ModuleCdc, pool) diff --git a/x/staking/module.go b/x/staking/module.go index 0f39343af84..0c7023a0195 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -106,17 +106,19 @@ type AppModule struct { keeper Keeper accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { +func NewAppModule(keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, sk types.SupplyKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, - accountKeeper: accountKeeper, - supplyKeeper: supplyKeeper, + accountKeeper: ak, + bankKeeper: bk, + supplyKeeper: sk, } } @@ -155,7 +157,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) - return InitGenesis(ctx, am.keeper, am.accountKeeper, am.supplyKeeper, genesisState) + return InitGenesis(ctx, am.keeper, am.accountKeeper, am.bankKeeper, am.supplyKeeper, genesisState) } // ExportGenesis returns the exported genesis state as raw bytes for the staking @@ -202,6 +204,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { // WeightedOperations returns the all the staking module operations with their respective weights. func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { - return simulation.WeightedOperations(simState.AppParams, simState.Cdc, - am.accountKeeper, am.keeper) + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper, + ) } diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index b1a93227064..8744496e07b 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -26,7 +26,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - k keeper.Keeper, + bk types.BankKeeper, k keeper.Keeper, ) simulation.WeightedOperations { var ( @@ -70,30 +70,30 @@ func WeightedOperations( return simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgCreateValidator, - SimulateMsgCreateValidator(ak, k), + SimulateMsgCreateValidator(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgEditValidator, - SimulateMsgEditValidator(ak, k), + SimulateMsgEditValidator(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgDelegate, - SimulateMsgDelegate(ak, k), + SimulateMsgDelegate(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgUndelegate, - SimulateMsgUndelegate(ak, k), + SimulateMsgUndelegate(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgBeginRedelegate, - SimulateMsgBeginRedelegate(ak, k), + SimulateMsgBeginRedelegate(ak, bk, k), ), } } // SimulateMsgCreateValidator generates a MsgCreateValidator with random values // nolint: funlen -func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -108,12 +108,13 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat } denom := k.GetParams(ctx).BondDenom - amount := ak.GetAccount(ctx, simAccount.Address).GetCoins().AmountOf(denom) - if !amount.IsPositive() { + + balance := bk.GetBalance(ctx, simAccount.Address, denom).Amount + if !balance.IsPositive() { return simulation.NoOpMsg(types.ModuleName), nil, nil } - amount, err := simulation.RandPositiveInt(r, amount) + amount, err := simulation.RandPositiveInt(r, balance) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -121,10 +122,12 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat selfDelegation := sdk.NewCoin(denom, amount) account := ak.GetAccount(ctx, simAccount.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) var fees sdk.Coins - coins, hasNeg := coins.SafeSub(sdk.Coins{selfDelegation}) + coins, hasNeg := spendable.SafeSub(sdk.Coins{selfDelegation}) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -171,7 +174,7 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat // SimulateMsgEditValidator generates a MsgEditValidator with random values // nolint: funlen -func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -200,7 +203,11 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulatio } account := ak.GetAccount(ctx, simAccount.Address) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -236,7 +243,7 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulatio // SimulateMsgDelegate generates a MsgDelegate with random values // nolint: funlen -func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -256,7 +263,7 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope return simulation.NoOpMsg(types.ModuleName), nil, nil } - amount := ak.GetAccount(ctx, simAccount.Address).GetCoins().AmountOf(denom) + amount := bk.GetBalance(ctx, simAccount.Address, denom).Amount if !amount.IsPositive() { return simulation.NoOpMsg(types.ModuleName), nil, nil } @@ -269,10 +276,12 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope bondAmt := sdk.NewCoin(denom, amount) account := ak.GetAccount(ctx, simAccount.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) var fees sdk.Coins - coins, hasNeg := coins.SafeSub(sdk.Coins{bondAmt}) + coins, hasNeg := spendable.SafeSub(sdk.Coins{bondAmt}) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -303,7 +312,7 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope // SimulateMsgUndelegate generates a MsgUndelegate with random values // nolint: funlen -func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -357,7 +366,11 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.O } account := ak.GetAccount(ctx, delAddr) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -383,7 +396,7 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.O // SimulateMsgBeginRedelegate generates a MsgBeginRedelegate with random values // nolint: funlen -func SimulateMsgBeginRedelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -456,9 +469,12 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, k keeper.Keeper) simulat return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("delegation addr: %s does not exist in simulation accounts", delAddr) } - // get tx fees account := ak.GetAccount(ctx, delAddr) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index 5e98f0abbed..c0e407ac7c2 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -19,6 +19,14 @@ type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account // only used for simulation } +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} + // SupplyKeeper defines the expected supply Keeper (noalias) type SupplyKeeper interface { GetSupply(ctx sdk.Context) supplyexported.SupplyI From b568331f23a6f5a4eccaa5b6e054afb3750039e6 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 15:01:25 -0500 Subject: [PATCH 05/24] Update mock --- x/mock/app.go | 58 ++++++++++++++++++++++++++++++-------------- x/mock/app_test.go | 10 ++++---- x/mock/test_utils.go | 6 ++--- x/mock/types.go | 18 ++++++++------ 4 files changed, 58 insertions(+), 34 deletions(-) diff --git a/x/mock/app.go b/x/mock/app.go index 29448e8a906..3afccc555df 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -19,6 +19,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/bank" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/params" ) @@ -32,14 +34,17 @@ type App struct { Cdc *codec.Codec // Cdc is public since the codec is passed into the module anyways KeyMain *sdk.KVStoreKey KeyAccount *sdk.KVStoreKey + KeyBank *sdk.KVStoreKey KeyParams *sdk.KVStoreKey TKeyParams *sdk.TransientStoreKey // TODO: Abstract this out from not needing to be auth specifically AccountKeeper auth.AccountKeeper + BankKeeper bank.Keeper ParamsKeeper params.Keeper GenesisAccounts []authexported.Account + GenesisBalances []bankexported.GenesisBalance TotalCoinsSupply sdk.Coins } @@ -58,30 +63,34 @@ func NewApp() *App { Cdc: cdc, KeyMain: sdk.NewKVStoreKey(bam.MainStoreKey), KeyAccount: sdk.NewKVStoreKey(auth.StoreKey), + KeyBank: sdk.NewKVStoreKey(bank.StoreKey), KeyParams: sdk.NewKVStoreKey("params"), TKeyParams: sdk.NewTransientStoreKey("transient_params"), TotalCoinsSupply: sdk.NewCoins(), } - // define keepers app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams) - app.AccountKeeper = auth.NewAccountKeeper( app.Cdc, app.KeyAccount, app.ParamsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount, ) - - supplyKeeper := NewDummySupplyKeeper(app.AccountKeeper) + app.BankKeeper = bank.NewBaseKeeper( + app.Cdc, + app.KeyBank, + app.AccountKeeper, + app.ParamsKeeper.Subspace(bank.DefaultParamspace), + make(map[string]bool), + ) + supplyKeeper := NewDummySupplyKeeper(app.AccountKeeper, app.BankKeeper) // Initialize the app. The chainers and blockers can be overwritten before // calling complete setup. app.SetInitChainer(app.InitChainer) app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, supplyKeeper, auth.DefaultSigVerificationGasConsumer)) - // Not sealing for custom extension - + // not sealing for custom extension return app } @@ -90,15 +99,17 @@ func NewApp() *App { func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error { newKeys = append( newKeys, - app.KeyMain, app.KeyAccount, app.KeyParams, app.TKeyParams, + app.KeyMain, app.KeyAccount, app.KeyBank, app.KeyParams, app.TKeyParams, ) for _, key := range newKeys { switch key.(type) { case *sdk.KVStoreKey: app.MountStore(key, sdk.StoreTypeIAVL) + case *sdk.TransientStoreKey: app.MountStore(key, sdk.StoreTypeTransient) + default: return fmt.Errorf("unsupported StoreKey: %+v", key) } @@ -111,15 +122,17 @@ func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error { // InitChainer performs custom logic for initialization. func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain { - - // Load the genesis accounts for _, genacc := range app.GenesisAccounts { acc := app.AccountKeeper.NewAccountWithAddress(ctx, genacc.GetAddress()) - acc.SetCoins(genacc.GetCoins()) app.AccountKeeper.SetAccount(ctx, acc) } + for _, balance := range app.GenesisBalances { + app.BankKeeper.SetBalances(ctx, balance.GetAddress(), balance.GetCoins()) + } + auth.InitGenesis(ctx, app.AccountKeeper, auth.DefaultGenesisState()) + bank.InitGenesis(ctx, app.BankKeeper, bank.DefaultGenesisState()) return abci.ResponseInitChain{} } @@ -167,8 +180,10 @@ func (b AddrKeysSlice) Swap(i, j int) { // CreateGenAccounts generates genesis accounts loaded with coins, and returns // their addresses, pubkeys, and privkeys. -func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []authexported.Account, - addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) { +func CreateGenAccounts(numAccs int, genCoins sdk.Coins) ( + genAccs []authexported.Account, genBalances []bankexported.GenesisBalance, + addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey, +) { addrKeysSlice := AddrKeysSlice{} @@ -188,6 +203,9 @@ func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []authexported. privKeys = append(privKeys, addrKeysSlice[i].PrivKey) genAccs = append(genAccs, &auth.BaseAccount{ Address: addrKeysSlice[i].Address, + }) + genBalances = append(genBalances, bank.Balance{ + Address: addrKeysSlice[i].Address, Coins: genCoins, }) } @@ -196,10 +214,11 @@ func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []authexported. } // SetGenesis sets the mock app genesis accounts. -func SetGenesis(app *App, accs []authexported.Account) { +func SetGenesis(app *App, accs []authexported.Account, balances []bankexported.GenesisBalance) { // Pass the accounts in via the application (lazy) instead of through // RequestInitChain. app.GenesisAccounts = accs + app.GenesisBalances = balances app.InitChain(abci.RequestInitChain{}) app.Commit() @@ -282,14 +301,15 @@ func GeneratePrivKeyAddressPairsFromRand(rand *rand.Rand, n int) (keys []crypto. // RandomSetGenesis set genesis accounts with random coin values using the // provided addresses and coin denominations. func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) { - accts := make([]authexported.Account, len(addrs)) + accounts := make([]authexported.Account, len(addrs)) + balances := make([]bankexported.GenesisBalance, len(addrs)) randCoinIntervals := []BigInterval{ {sdk.NewIntWithDecimal(1, 0), sdk.NewIntWithDecimal(1, 1)}, {sdk.NewIntWithDecimal(1, 2), sdk.NewIntWithDecimal(1, 3)}, {sdk.NewIntWithDecimal(1, 40), sdk.NewIntWithDecimal(1, 50)}, } - for i := 0; i < len(accts); i++ { + for i := 0; i < len(accounts); i++ { coins := make([]sdk.Coin, len(denoms)) // generate a random coin for each denomination @@ -302,10 +322,12 @@ func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []s app.TotalCoinsSupply = app.TotalCoinsSupply.Add(coins...) baseAcc := auth.NewBaseAccountWithAddress(addrs[i]) - (&baseAcc).SetCoins(coins) - accts[i] = &baseAcc + accounts[i] = &baseAcc + balances[i] = bank.Balance{Address: addrs[i], Coins: coins} } - app.GenesisAccounts = accts + + app.GenesisAccounts = accounts + app.GenesisBalances = balances } func createCodec() *codec.Codec { diff --git a/x/mock/app_test.go b/x/mock/app_test.go index 95bed4fda08..44b97940553 100644 --- a/x/mock/app_test.go +++ b/x/mock/app_test.go @@ -15,9 +15,9 @@ import ( const msgRoute = "testMsg" var ( - numAccts = 2 - genCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 77)} - accs, addrs, _, privKeys = CreateGenAccounts(numAccts, genCoins) + numAccts = 2 + genCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 77)} + accs, balances, addrs, _, privKeys = CreateGenAccounts(numAccts, genCoins) ) // testMsg is a mock transaction that has a validation which can fail. @@ -57,7 +57,7 @@ func TestCheckAndDeliverGenTx(t *testing.T) { mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) mApp.Cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) - SetGenesis(mApp, accs) + SetGenesis(mApp, accs, balances) ctxCheck := mApp.BaseApp.NewContext(true, abci.Header{}) msg := testMsg{signers: []sdk.AccAddress{addrs[0]}, positiveNum: 1} @@ -99,7 +99,7 @@ func TestCheckGenTx(t *testing.T) { mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) mApp.Cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) - SetGenesis(mApp, accs) + SetGenesis(mApp, accs, balances) msg1 := testMsg{signers: []sdk.AccAddress{addrs[0]}, positiveNum: 1} CheckGenTx( diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go index 11073e64f41..cece7051ed2 100644 --- a/x/mock/test_utils.go +++ b/x/mock/test_utils.go @@ -42,11 +42,9 @@ func RandFromBigInterval(r *rand.Rand, intervals []BigInterval) sdk.Int { } // CheckBalance checks the balance of an account. -func CheckBalance(t *testing.T, app *App, addr sdk.AccAddress, exp sdk.Coins) { +func CheckBalance(t *testing.T, app *App, addr sdk.AccAddress, balance sdk.Coins) { ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) - res := app.AccountKeeper.GetAccount(ctxCheck, addr) - - require.Equal(t, exp, res.GetCoins()) + require.Equal(t, balance, app.BankKeeper.GetAllBalances(ctxCheck, addr)) } // CheckGenTx checks a generated signed transaction. The result of the check is diff --git a/x/mock/types.go b/x/mock/types.go index 43dfbaecbb9..aed4a6c97f3 100644 --- a/x/mock/types.go +++ b/x/mock/types.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/supply/exported" ) @@ -14,30 +15,33 @@ import ( // circle dependencies type DummySupplyKeeper struct { ak auth.AccountKeeper + bk bank.Keeper } // NewDummySupplyKeeper creates a DummySupplyKeeper instance -func NewDummySupplyKeeper(ak auth.AccountKeeper) DummySupplyKeeper { - return DummySupplyKeeper{ak} +func NewDummySupplyKeeper(ak auth.AccountKeeper, bk bank.Keeper) DummySupplyKeeper { + return DummySupplyKeeper{ak, bk} } // SendCoinsFromAccountToModule for the dummy supply keeper func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { fromAcc := sk.ak.GetAccount(ctx, fromAddr) moduleAcc := sk.GetModuleAccount(ctx, recipientModule) + fromBalances := sk.bk.GetAllBalances(ctx, fromAcc.GetAddress()) - newFromCoins, hasNeg := fromAcc.GetCoins().SafeSub(amt) + newFromCoins, hasNeg := fromBalances.SafeSub(amt) if hasNeg { - return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, fromAcc.GetCoins().String()) + return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, fromBalances.String()) } - newToCoins := moduleAcc.GetCoins().Add(amt...) + toBalances := sk.bk.GetAllBalances(ctx, moduleAcc.GetAddress()) + newToCoins := toBalances.Add(amt...) - if err := fromAcc.SetCoins(newFromCoins); err != nil { + if err := sk.bk.SetBalances(ctx, fromAcc.GetAddress(), newFromCoins); err != nil { return err } - if err := moduleAcc.SetCoins(newToCoins); err != nil { + if err := sk.bk.SetBalances(ctx, moduleAcc.GetAddress(), newToCoins); err != nil { return err } From 1a51942133471d578c9ffd0504b7b3ae256e9eef Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 15:44:08 -0500 Subject: [PATCH 06/24] Updates to gov and slashing --- x/gov/keeper/invariants.go | 15 ++++---- x/gov/simulation/operations.go | 57 ++++++++++++++++++----------- x/gov/types/expected_keepers.go | 7 ++++ x/slashing/module.go | 14 ++++--- x/slashing/simulation/operations.go | 12 ++++-- 5 files changed, 67 insertions(+), 38 deletions(-) diff --git a/x/gov/keeper/invariants.go b/x/gov/keeper/invariants.go index 1ebe62c15d0..d0ec4dbfacc 100644 --- a/x/gov/keeper/invariants.go +++ b/x/gov/keeper/invariants.go @@ -10,20 +10,20 @@ import ( ) // RegisterInvariants registers all governance invariants -func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) { - ir.RegisterRoute(types.ModuleName, "module-account", ModuleAccountInvariant(keeper)) +func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper, bk types.BankKeeper) { + ir.RegisterRoute(types.ModuleName, "module-account", ModuleAccountInvariant(keeper, bk)) } // AllInvariants runs all invariants of the governance module -func AllInvariants(keeper Keeper) sdk.Invariant { +func AllInvariants(keeper Keeper, bk types.BankKeeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { - return ModuleAccountInvariant(keeper)(ctx) + return ModuleAccountInvariant(keeper, bk)(ctx) } } // ModuleAccountInvariant checks that the module account coins reflects the sum of // deposit amounts held on store -func ModuleAccountInvariant(keeper Keeper) sdk.Invariant { +func ModuleAccountInvariant(keeper Keeper, bk types.BankKeeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { var expectedDeposits sdk.Coins @@ -33,10 +33,11 @@ func ModuleAccountInvariant(keeper Keeper) sdk.Invariant { }) macc := keeper.GetGovernanceAccount(ctx) - broken := !macc.GetCoins().IsEqual(expectedDeposits) + balances := bk.GetAllBalances(ctx, macc.GetAddress()) + broken := !balances.IsEqual(expectedDeposits) return sdk.FormatInvariant(types.ModuleName, "deposits", fmt.Sprintf("\tgov ModuleAccount coins: %s\n\tsum of deposit amounts: %s\n", - macc.GetCoins(), expectedDeposits)), broken + balances, expectedDeposits)), broken } } diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index b53a9735014..3ebc2617cfd 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -24,8 +24,10 @@ const ( ) // WeightedOperations returns all the operations from the module with their respective weights -func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - k keeper.Keeper, wContents []simulation.WeightedProposalContent) simulation.WeightedOperations { +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + bk types.BankKeeper, k keeper.Keeper, wContents []simulation.WeightedProposalContent, +) simulation.WeightedOperations { var ( weightMsgDeposit int @@ -57,7 +59,7 @@ func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak typ wProposalOps, simulation.NewWeightedOperation( weight, - SimulateSubmitProposal(ak, k, wContent.ContentSimulatorFn), + SimulateSubmitProposal(ak, bk, k, wContent.ContentSimulatorFn), ), ) } @@ -65,11 +67,11 @@ func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak typ wGovOps := simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgDeposit, - SimulateMsgDeposit(ak, k), + SimulateMsgDeposit(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgVote, - SimulateMsgVote(ak, k), + SimulateMsgVote(ak, bk, k), ), } @@ -81,7 +83,7 @@ func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak typ // future operations. // nolint: funlen func SimulateSubmitProposal( - ak types.AccountKeeper, k keeper.Keeper, contentSim simulation.ContentSimulatorFn, + ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, contentSim simulation.ContentSimulatorFn, ) simulation.Operation { // The states are: // column 1: All validators vote @@ -115,7 +117,7 @@ func SimulateSubmitProposal( } simAccount, _ := simulation.RandomAcc(r, accs) - deposit, skip, err := randomDeposit(r, ctx, ak, k, simAccount.Address) + deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address) switch { case skip: return simulation.NoOpMsg(types.ModuleName), nil, nil @@ -126,10 +128,12 @@ func SimulateSubmitProposal( msg := types.NewMsgSubmitProposal(content, deposit, simAccount.Address) account := ak.GetAccount(ctx, simAccount.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) var fees sdk.Coins - coins, hasNeg := coins.SafeSub(deposit) + coins, hasNeg := spendable.SafeSub(deposit) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -177,7 +181,7 @@ func SimulateSubmitProposal( whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second) fops[i] = simulation.FutureOperation{ BlockTime: whenVote, - Op: operationSimulateMsgVote(ak, k, accs[whoVotes[i]], int64(proposalID)), + Op: operationSimulateMsgVote(ak, bk, k, accs[whoVotes[i]], int64(proposalID)), } } @@ -187,7 +191,7 @@ func SimulateSubmitProposal( // SimulateMsgDeposit generates a MsgDeposit with random values. // nolint: funlen -func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -198,7 +202,7 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper return simulation.NoOpMsg(types.ModuleName), nil, nil } - deposit, skip, err := randomDeposit(r, ctx, ak, k, simAccount.Address) + deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address) switch { case skip: return simulation.NoOpMsg(types.ModuleName), nil, nil @@ -209,10 +213,12 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper msg := types.NewMsgDeposit(simAccount.Address, proposalID, deposit) account := ak.GetAccount(ctx, simAccount.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) var fees sdk.Coins - coins, hasNeg := coins.SafeSub(deposit) + coins, hasNeg := spendable.SafeSub(deposit) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { @@ -241,11 +247,11 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper // SimulateMsgVote generates a MsgVote with random values. // nolint: funlen -func SimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { - return operationSimulateMsgVote(ak, k, simulation.Account{}, -1) +func SimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { + return operationSimulateMsgVote(ak, bk, k, simulation.Account{}, -1) } -func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, +func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, simAccount simulation.Account, proposalIDInt int64) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, @@ -273,7 +279,11 @@ func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, msg := types.NewMsgVote(simAccount.Address, proposalID, option) account := ak.GetAccount(ctx, simAccount.Address) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -302,11 +312,14 @@ func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, // This is to simulate multiple users depositing to get the // proposal above the minimum deposit amount func randomDeposit(r *rand.Rand, ctx sdk.Context, - ak types.AccountKeeper, k keeper.Keeper, addr sdk.AccAddress, + ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, addr sdk.AccAddress, ) (deposit sdk.Coins, skip bool, err error) { account := ak.GetAccount(ctx, addr) - coins := account.SpendableCoins(ctx.BlockHeader().Time) - if coins.Empty() { + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) + + if spendable.Empty() { return nil, true, nil // skip } @@ -314,7 +327,7 @@ func randomDeposit(r *rand.Rand, ctx sdk.Context, denomIndex := r.Intn(len(minDeposit)) denom := minDeposit[denomIndex].Denom - depositCoins := coins.AmountOf(denom) + depositCoins := spendable.AmountOf(denom) if depositCoins.IsZero() { return nil, true, nil } diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index 31e5d1e05cf..29e29392a24 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -44,3 +44,10 @@ type StakingKeeper interface { type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account } + +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} diff --git a/x/slashing/module.go b/x/slashing/module.go index e99b421574f..4b739ef217e 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -82,16 +82,18 @@ type AppModule struct { keeper Keeper accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper stakingKeeper stakingkeeper.Keeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, stakingKeeper stakingkeeper.Keeper) AppModule { +func NewAppModule(keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, sk stakingkeeper.Keeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, - accountKeeper: accountKeeper, - stakingKeeper: stakingKeeper, + accountKeeper: ak, + bankKeeper: bk, + stakingKeeper: sk, } } @@ -176,6 +178,8 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { // WeightedOperations returns the all the slashing module operations with their respective weights. func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { - return simulation.WeightedOperations(simState.AppParams, simState.Cdc, - am.accountKeeper, am.keeper, am.stakingKeeper) + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, + am.accountKeeper, am.bankKeeper, am.keeper, am.stakingKeeper, + ) } diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index f5e263b778d..ccd06ef5625 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -23,7 +23,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - k keeper.Keeper, sk stakingkeeper.Keeper, + bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper, ) simulation.WeightedOperations { var weightMsgUnjail int @@ -36,14 +36,14 @@ func WeightedOperations( return simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgUnjail, - SimulateMsgUnjail(ak, k, sk), + SimulateMsgUnjail(ak, bk, k, sk), ), } } // SimulateMsgUnjail generates a MsgUnjail with random values // nolint: funlen -func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -76,7 +76,11 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper } account := ak.GetAccount(ctx, sdk.AccAddress(validator.GetOperator())) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } From 5bda0df45994149c2f0de4dc58e62aa95f7ea970 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 16:06:51 -0500 Subject: [PATCH 07/24] More updates --- x/distribution/genesis.go | 7 +-- x/distribution/keeper/allocation.go | 2 +- x/distribution/keeper/invariants.go | 10 +++-- x/distribution/keeper/keeper.go | 3 +- x/distribution/module.go | 15 ++++--- x/distribution/simulation/operations.go | 44 ++++++++++++------- x/distribution/types/expected_keepers.go | 8 ++++ x/gov/genesis.go | 7 ++- x/gov/module.go | 15 ++++--- x/gov/types/expected_keepers.go | 1 + x/slashing/internal/types/expected_keepers.go | 8 ++++ 11 files changed, 82 insertions(+), 38 deletions(-) diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index 6a7f9c1fdba..9e00aeba2b7 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -8,7 +8,7 @@ import ( ) // InitGenesis sets distribution information for genesis -func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data types.GenesisState) { +func InitGenesis(ctx sdk.Context, bk types.BankKeeper, supplyKeeper types.SupplyKeeper, keeper Keeper, data types.GenesisState) { var moduleHoldings sdk.DecCoins keeper.SetFeePool(ctx, data.FeePool) @@ -47,10 +47,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) } - if moduleAcc.GetCoins().IsZero() { - if err := moduleAcc.SetCoins(moduleHoldingsInt); err != nil { + if bk.GetAllBalances(ctx, moduleAcc.GetAddress()).IsZero() { + if err := bk.SetBalances(ctx, moduleAcc.GetAddress(), moduleHoldingsInt); err != nil { panic(err) } + supplyKeeper.SetModuleAccount(ctx, moduleAcc) } } diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index b6a34a3d643..533aaac4385 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -22,7 +22,7 @@ func (k Keeper) AllocateTokens( // called in BeginBlock, collected fees will be from the previous block // (and distributed to the previous proposer) feeCollector := k.supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) - feesCollectedInt := feeCollector.GetCoins() + feesCollectedInt := k.bankKeeper.GetAllBalances(ctx, feeCollector.GetAddress()) feesCollected := sdk.NewDecCoinsFromCoins(feesCollectedInt...) // transfer collected fees to the distribution module account diff --git a/x/distribution/keeper/invariants.go b/x/distribution/keeper/invariants.go index cff02da0769..cfafe1b11b2 100644 --- a/x/distribution/keeper/invariants.go +++ b/x/distribution/keeper/invariants.go @@ -148,11 +148,15 @@ func ModuleAccountInvariant(k Keeper) sdk.Invariant { expectedInt, _ := expectedCoins.Add(communityPool...).TruncateDecimal() macc := k.GetDistributionAccount(ctx) + balances := k.bankKeeper.GetAllBalances(ctx, macc.GetAddress()) - broken := !macc.GetCoins().IsEqual(expectedInt) - return sdk.FormatInvariant(types.ModuleName, "ModuleAccount coins", + broken := !balances.IsEqual(expectedInt) + return sdk.FormatInvariant( + types.ModuleName, "ModuleAccount coins", fmt.Sprintf("\texpected ModuleAccount coins: %s\n"+ "\tdistribution ModuleAccount coins: %s\n", - expectedInt, macc.GetCoins())), broken + expectedInt, balances, + ), + ), broken } } diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 18cbce2b684..8895f5a3cd5 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -17,6 +17,7 @@ type Keeper struct { storeKey sdk.StoreKey cdc *codec.Codec paramSpace params.Subspace + bankKeeper types.BankKeeper stakingKeeper types.StakingKeeper supplyKeeper types.SupplyKeeper @@ -27,7 +28,7 @@ type Keeper struct { // NewKeeper creates a new distribution Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, + cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, bk types.BankKeeper, sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, blacklistedAddrs map[string]bool, ) Keeper { diff --git a/x/distribution/module.go b/x/distribution/module.go index 0b143d6478b..631d9b956fe 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -80,17 +80,21 @@ type AppModule struct { keeper Keeper accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper stakingKeeper stakingkeeper.Keeper supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, - supplyKeeper types.SupplyKeeper, stakingKeeper stakingkeeper.Keeper) AppModule { +func NewAppModule( + keeper Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, + supplyKeeper types.SupplyKeeper, stakingKeeper stakingkeeper.Keeper, +) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, accountKeeper: accountKeeper, + bankKeeper: bankKeeper, supplyKeeper: supplyKeeper, stakingKeeper: stakingKeeper, } @@ -131,7 +135,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) + InitGenesis(ctx, am.bankKeeper, am.supplyKeeper, am.keeper, genesisState) return []abci.ValidatorUpdate{} } @@ -180,6 +184,7 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { // WeightedOperations returns the all the gov module operations with their respective weights. func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { - return simulation.WeightedOperations(simState.AppParams, simState.Cdc, - am.accountKeeper, am.keeper, am.stakingKeeper) + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, am.keeper, am.stakingKeeper, + ) } diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index d2857e6c5af..1c81a047a72 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -26,7 +26,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - k keeper.Keeper, sk stakingkeeper.Keeper, + bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper, ) simulation.WeightedOperations { var weightMsgSetWithdrawAddress int @@ -60,26 +60,26 @@ func WeightedOperations( return simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgSetWithdrawAddress, - SimulateMsgSetWithdrawAddress(ak, k), + SimulateMsgSetWithdrawAddress(ak, bk, k), ), simulation.NewWeightedOperation( weightMsgWithdrawDelegationReward, - SimulateMsgWithdrawDelegatorReward(ak, k, sk), + SimulateMsgWithdrawDelegatorReward(ak, bk, k, sk), ), simulation.NewWeightedOperation( weightMsgWithdrawValidatorCommission, - SimulateMsgWithdrawValidatorCommission(ak, k, sk), + SimulateMsgWithdrawValidatorCommission(ak, bk, k, sk), ), simulation.NewWeightedOperation( weightMsgFundCommunityPool, - SimulateMsgFundCommunityPool(ak, k, sk), + SimulateMsgFundCommunityPool(ak, bk, k, sk), ), } } // SimulateMsgSetWithdrawAddress generates a MsgSetWithdrawAddress with random values. // nolint: funlen -func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { +func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -89,9 +89,13 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu simAccount, _ := simulation.RandomAcc(r, accs) simToAccount, _ := simulation.RandomAcc(r, accs) + account := ak.GetAccount(ctx, simAccount.Address) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -119,7 +123,7 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu // SimulateMsgWithdrawDelegatorReward generates a MsgWithdrawDelegatorReward with random values. // nolint: funlen -func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -137,7 +141,11 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, } account := ak.GetAccount(ctx, simAccount.Address) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -165,7 +173,7 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, // SimulateMsgWithdrawValidatorCommission generates a MsgWithdrawValidatorCommission with random values. // nolint: funlen -func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -186,7 +194,11 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee } account := ak.GetAccount(ctx, simAccount.Address) - fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime())) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) + + fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, err } @@ -214,7 +226,7 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee // SimulateMsgFundCommunityPool simulates MsgFundCommunityPool execution where // a random account sends a random amount of its funds to the community pool. -func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { +func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { @@ -222,9 +234,11 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk st funder, _ := simulation.RandomAcc(r, accs) account := ak.GetAccount(ctx, funder.Address) - coins := account.SpendableCoins(ctx.BlockTime()) + balances := bk.GetAllBalances(ctx, account.GetAddress()) + locked := bk.LockedCoins(ctx, account.GetAddress()) + spendable := balances.Sub(locked) - fundAmount := simulation.RandSubsetCoins(r, coins) + fundAmount := simulation.RandSubsetCoins(r, spendable) if fundAmount.Empty() { return simulation.NoOpMsg(types.ModuleName), nil, nil } @@ -234,7 +248,7 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk st err error ) - coins, hasNeg := coins.SafeSub(fundAmount) + coins, hasNeg := spendable.SafeSub(fundAmount) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index faa2f37235d..5937e1b986f 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -13,6 +13,14 @@ type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account } +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} + // StakingKeeper expected staking keeper (noalias) type StakingKeeper interface { // iterate through validators by operator address, execute func for each validator diff --git a/x/gov/genesis.go b/x/gov/genesis.go index b487c23ef85..f0eec06e110 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -8,8 +8,7 @@ import ( ) // InitGenesis - store genesis parameters -func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper types.SupplyKeeper, data GenesisState) { - +func InitGenesis(ctx sdk.Context, bk types.BankKeeper, supplyKeeper types.SupplyKeeper, k Keeper, data GenesisState) { k.SetProposalID(ctx, data.StartingProposalID) k.SetDepositParams(ctx, data.DepositParams) k.SetVotingParams(ctx, data.VotingParams) @@ -42,8 +41,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper types.SupplyKeeper, dat } // add coins if not provided on genesis - if moduleAcc.GetCoins().IsZero() { - if err := moduleAcc.SetCoins(totalDeposits); err != nil { + if bk.GetAllBalances(ctx, moduleAcc.GetAddress()).IsZero() { + if err := bk.SetBalances(ctx, moduleAcc.GetAddress(), totalDeposits); err != nil { panic(err) } supplyKeeper.SetModuleAccount(ctx, moduleAcc) diff --git a/x/gov/module.go b/x/gov/module.go index 7ad5ecbc0ac..bd2cabb97e7 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -102,16 +102,18 @@ type AppModule struct { keeper Keeper accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { +func NewAppModule(keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, sk types.SupplyKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, - accountKeeper: accountKeeper, - supplyKeeper: supplyKeeper, + accountKeeper: ak, + bankKeeper: bk, + supplyKeeper: sk, } } @@ -122,7 +124,7 @@ func (AppModule) Name() string { // RegisterInvariants registers module invariants func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - RegisterInvariants(ir, am.keeper) + RegisterInvariants(ir, am.keeper, am.bankKeeper) } // Route returns the message routing key for the gov module. @@ -150,7 +152,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState ModuleCdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) + InitGenesis(ctx, am.bankKeeper, am.supplyKeeper, am.keeper, genesisState) return []abci.ValidatorUpdate{} } @@ -200,5 +202,6 @@ func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { return simulation.WeightedOperations( simState.AppParams, simState.Cdc, - am.accountKeeper, am.keeper, simState.Contents) + am.accountKeeper, am.bankKeeper, am.keeper, simState.Contents, + ) } diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index 29e29392a24..f2b699dadbd 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -49,5 +49,6 @@ type AccountKeeper interface { type BankKeeper interface { GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } diff --git a/x/slashing/internal/types/expected_keepers.go b/x/slashing/internal/types/expected_keepers.go index 58e1f30d67e..e59c7d2877c 100644 --- a/x/slashing/internal/types/expected_keepers.go +++ b/x/slashing/internal/types/expected_keepers.go @@ -15,6 +15,14 @@ type AccountKeeper interface { IterateAccounts(ctx sdk.Context, process func(authexported.Account) (stop bool)) } +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} + // ParamSubspace defines the expected Subspace interfacace type ParamSubspace interface { WithKeyTable(table params.KeyTable) params.Subspace From 2846b0459d93992225e3b18f5a698849d408bb31 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 16:18:41 -0500 Subject: [PATCH 08/24] Update simapp --- simapp/app.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/simapp/app.go b/simapp/app.go index ec1aebf2753..e3a589adb87 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -180,14 +180,14 @@ func NewSimApp( app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, ) stakingKeeper := staking.NewKeeper( - app.cdc, keys[staking.StoreKey], app.SupplyKeeper, app.subspaces[staking.ModuleName], + app.cdc, keys[staking.StoreKey], app.BankKeeper, app.SupplyKeeper, app.subspaces[staking.ModuleName], ) app.MintKeeper = mint.NewKeeper( app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, ) app.DistrKeeper = distr.NewKeeper( - app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], &stakingKeeper, + app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], app.BankKeeper, &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs(), ) app.SlashingKeeper = slashing.NewKeeper( @@ -231,12 +231,12 @@ func NewSimApp( auth.NewAppModule(app.AccountKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), crisis.NewAppModule(&app.CrisisKeeper), - supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper), - gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper), + supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), + gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), mint.NewAppModule(app.MintKeeper), - slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), - distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), - staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), + slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), + distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, app.StakingKeeper), + staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), upgrade.NewAppModule(app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), ) @@ -265,12 +265,12 @@ func NewSimApp( app.sm = module.NewSimulationManager( auth.NewAppModule(app.AccountKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), - supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper), - gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper), + supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), + gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), mint.NewAppModule(app.MintKeeper), - staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), - distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), - slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), + staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), + distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, app.StakingKeeper), + slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), params.NewAppModule(), // NOTE: only used for simulation to generate randomized param change proposals ) @@ -283,7 +283,7 @@ func NewSimApp( // initialize BaseApp app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) - app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, auth.DefaultSigVerificationGasConsumer)) + app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, auth.DefaultSigVerificationGasConsumer)) app.SetEndBlocker(app.EndBlocker) if loadLatest { From c42f422b0fe2a1c52b719b2b38985e2d66bbcc5e Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 18:46:02 -0500 Subject: [PATCH 09/24] Set bank keeper in distribution constructor --- x/distribution/keeper/keeper.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 8895f5a3cd5..5cce89d0c33 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -47,6 +47,7 @@ func NewKeeper( storeKey: key, cdc: cdc, paramSpace: paramSpace, + bankKeeper: bk, stakingKeeper: sk, supplyKeeper: supplyKeeper, feeCollectorName: feeCollectorName, From 2f86f6ee51c4d2a46b0f4fe02372ff7a566d9b0e Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 27 Jan 2020 23:13:35 -0500 Subject: [PATCH 10/24] Fix error return --- x/bank/internal/keeper/keeper.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index c0c9d16f70b..96e0189b25b 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -30,7 +30,6 @@ type Keeper interface { type BaseKeeper struct { BaseSendKeeper - storeKey sdk.StoreKey ak types.AccountKeeper paramSpace params.Subspace } @@ -103,7 +102,7 @@ func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAdd return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - // safe to call Substract coins as a moduleAcc shouldn't be vesting + // safe to call subtract coins as a moduleAcc shouldn't be vesting _, err := k.SubtractCoins(ctx, moduleAccAddr, amt) if err != nil { return err @@ -335,7 +334,7 @@ func (k BaseSendKeeper) SetBalances(ctx sdk.Context, addr sdk.AccAddress, balanc // SetBalance sets the coin balance for an account by address. func (k BaseSendKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error { if !balance.IsValid() { - sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) } store := ctx.KVStore(k.storeKey) From 4f1717570a6b54513c4332f9d13d171b39e08910 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 29 Jan 2020 14:58:02 -0500 Subject: [PATCH 11/24] Update godoc on LockedCoins --- x/auth/vesting/exported/exported.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/auth/vesting/exported/exported.go b/x/auth/vesting/exported/exported.go index c01d07234bb..c53977c2ec8 100644 --- a/x/auth/vesting/exported/exported.go +++ b/x/auth/vesting/exported/exported.go @@ -14,6 +14,10 @@ type VestingAccount interface { // LockedCoins returns the set of coins that are not spendable (i.e. locked) // given the current account balance, only including tokens of vesting // denominations, and the current block time. + // + // To get spendable coins of a vesting account, first the total balance must + // be retrieved and the locked tokens can be subtracted from the total balance. + // Note, the spendable balance can be negative. LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins // TrackDelegation performs internal vesting accounting necessary when From 84a788ee22bc1025f798bfce9bf748886ba0f8cc Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 29 Jan 2020 16:01:15 -0500 Subject: [PATCH 12/24] Update CLI querying --- x/auth/client/cli/query.go | 2 +- x/bank/client/cli/query.go | 99 ++++++++++++++++++++++++++++++++++++++ x/bank/module.go | 4 +- 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 x/bank/client/cli/query.go diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index d0ebc155ef9..b3856c56535 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -46,7 +46,7 @@ func GetQueryCmd(cdc *codec.Codec) *cobra.Command { func GetAccountCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "account [address]", - Short: "Query account balance", + Short: "Query for account by address", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) diff --git a/x/bank/client/cli/query.go b/x/bank/client/cli/query.go new file mode 100644 index 00000000000..046e8405144 --- /dev/null +++ b/x/bank/client/cli/query.go @@ -0,0 +1,99 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/internal/types" +) + +const ( + flagDenom = "denom" +) + +// GetQueryCmd returns the parent querying command for the bank module. +func GetQueryCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the bank module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(GetBalancesCmd(cdc)) + + return cmd +} + +// GetAccountCmd returns a CLI command handler that facilitates querying for a +// single or all account balances by address. +func GetBalancesCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "balances [address]", + Short: "Query for account balances by address", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + addr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + var ( + params interface{} + result interface{} + route string + ) + + denom := viper.GetString(flagDenom) + if denom == "" { + params = types.NewQueryAllBalancesParams(addr) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllBalances) + } else { + params = types.NewQueryBalanceParams(addr, denom) + route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBalance) + } + + bz, err := cdc.MarshalJSON(params) + if err != nil { + return fmt.Errorf("failed to marshal params: %w", err) + } + + res, _, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + + if denom == "" { + var balances sdk.Coins + if err := cdc.UnmarshalJSON(res, &balances); err != nil { + return err + } + + result = balances + } else { + var balance sdk.Coin + if err := cdc.UnmarshalJSON(res, &balance); err != nil { + return err + } + + result = balance + } + + return cliCtx.PrintOutput(result) + }, + } + + cmd.Flags().String(flagDenom, "", "The specific balance denomination to query for") + + return flags.GetCommands(cmd)[0] +} diff --git a/x/bank/module.go b/x/bank/module.go index 7c0281d5dc3..72afda68622 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -64,7 +64,9 @@ func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { } // GetQueryCmd returns no root query command for the bank module. -func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetQueryCmd(cdc) +} //____________________________________________________________________________ From 5be12a9caf127097b23d72e03f2718f99b44afa8 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 30 Jan 2020 08:52:20 -0500 Subject: [PATCH 13/24] Update x/auth/vesting/types/vesting_account.go Co-Authored-By: Aditya --- x/auth/vesting/types/vesting_account.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index 34af9a95cdc..41c8bcada16 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -63,7 +63,7 @@ func (bva BaseVestingAccount) LockedCoinsFromVesting(balance, vestingCoins sdk.C var lockedCoins sdk.Coins for _, vestingCoin := range vestingCoins { - vestingAmt := vestingCoins.AmountOf(vestingCoin.Denom) + vestingAmt := vestingCoin.Amount delVestingAmt := bva.DelegatedVesting.AmountOf(vestingCoin.Denom) baseAmt := balance.AmountOf(vestingCoin.Denom) From ac0aa8a7259c0e49639373fac87ef9c5b8373bf4 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 09:15:50 -0500 Subject: [PATCH 14/24] Remove uneccessary comment --- x/bank/internal/keeper/keeper.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 96e0189b25b..0bc79fd5f45 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -102,7 +102,6 @@ func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAdd return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - // safe to call subtract coins as a moduleAcc shouldn't be vesting _, err := k.SubtractCoins(ctx, moduleAccAddr, amt) if err != nil { return err From 0b78a9ac11e474d65b5ddf10aa3da0c48b8db2f9 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 09:19:17 -0500 Subject: [PATCH 15/24] Remove uneccessary negative check in AddCoins --- x/bank/internal/keeper/keeper.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 0bc79fd5f45..b7fa728d004 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -280,15 +280,7 @@ func (k BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.C for _, coin := range amt { balance := k.GetBalance(ctx, addr, coin.Denom) - - // newBalance should never be negative as the amount is already validated newBalance := balance.Add(coin) - if newBalance.IsNegative() { - return nil, sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, "resulting balance %s is negative", newBalance, - ) - } - resultCoins = resultCoins.Add(newBalance) k.SetBalance(ctx, addr, newBalance) From 01adcdadfcee56e794613d8c31b30322deb97eda Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 09:22:06 -0500 Subject: [PATCH 16/24] Update ValidateBalance godoc --- x/bank/internal/keeper/keeper.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index b7fa728d004..fa3472c2b0a 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -498,6 +498,10 @@ func (k BaseViewKeeper) LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Co // ValidateBalance validates all balances for a given account address returning // an error if any balance is invalid. It will check for vesting account types // and validate the balances against the original vesting balances. +// +// CONTRACT: ValidateBalance should only be called upon genesis state. In the +// case of vesting accounts, balances may change in a valid manner that would +// otherwise yield an error from this call. func (k BaseViewKeeper) ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error { acc := k.ak.GetAccount(ctx, addr) if acc == nil { From eba6f274dadad6d39301d2d980d47c3f2da2d96d Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 12:45:57 -0500 Subject: [PATCH 17/24] Update LockedCoins to not depend on balance input/simplify logic --- x/auth/vesting/exported/exported.go | 6 ++-- x/auth/vesting/types/vesting_account.go | 38 ++++++++++--------------- x/bank/internal/keeper/keeper.go | 10 +------ 3 files changed, 18 insertions(+), 36 deletions(-) diff --git a/x/auth/vesting/exported/exported.go b/x/auth/vesting/exported/exported.go index c53977c2ec8..09caaec4a44 100644 --- a/x/auth/vesting/exported/exported.go +++ b/x/auth/vesting/exported/exported.go @@ -11,14 +11,12 @@ import ( type VestingAccount interface { authexported.Account - // LockedCoins returns the set of coins that are not spendable (i.e. locked) - // given the current account balance, only including tokens of vesting - // denominations, and the current block time. + // LockedCoins returns the set of coins that are not spendable (i.e. locked). // // To get spendable coins of a vesting account, first the total balance must // be retrieved and the locked tokens can be subtracted from the total balance. // Note, the spendable balance can be negative. - LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins + LockedCoins(blockTime time.Time) sdk.Coins // TrackDelegation performs internal vesting accounting necessary when // delegating from a vesting account. It accepts the current block time, the diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index 41c8bcada16..70efad2b33e 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -55,21 +55,19 @@ func NewBaseVestingAccount(baseAccount *authtypes.BaseAccount, originalVesting s } // LockedCoinsFromVesting returns all the coins that are not spendable (i.e. locked) -// for a vesting account given the current vesting coins and account balance, -// where the balance only includes tokens of vesting denomination. +// for a vesting account given the current vesting coins. If no coins are locked, +// an empty slice of Coins is returned. // // CONTRACT: Delegated vesting coins and vestingCoins must be sorted. -func (bva BaseVestingAccount) LockedCoinsFromVesting(balance, vestingCoins sdk.Coins) sdk.Coins { - var lockedCoins sdk.Coins +func (bva BaseVestingAccount) LockedCoinsFromVesting(vestingCoins sdk.Coins) sdk.Coins { + lockedCoins := sdk.NewCoins() for _, vestingCoin := range vestingCoins { vestingAmt := vestingCoin.Amount delVestingAmt := bva.DelegatedVesting.AmountOf(vestingCoin.Denom) - baseAmt := balance.AmountOf(vestingCoin.Denom) - // compute min((BC + DV) - V, BC) per the specification - min := sdk.MinInt(baseAmt.Add(delVestingAmt).Sub(vestingAmt), baseAmt) - lockedCoin := sdk.NewCoin(vestingCoin.Denom, baseAmt.Sub(min)) + max := sdk.MaxInt(vestingAmt.Sub(delVestingAmt), sdk.ZeroInt()) + lockedCoin := sdk.NewCoin(vestingCoin.Denom, max) if !lockedCoin.IsZero() { lockedCoins = lockedCoins.Add(lockedCoin) @@ -352,11 +350,9 @@ func (cva ContinuousVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coi return cva.OriginalVesting.Sub(cva.GetVestedCoins(blockTime)) } -// LockedCoins returns the set of coins that are not spendable (i.e. locked) -// given the current account balance, only including tokens of vesting -// denominations, and the current block time. -func (cva ContinuousVestingAccount) LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins { - return cva.BaseVestingAccount.LockedCoinsFromVesting(balance, cva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked). +func (cva ContinuousVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { + return cva.BaseVestingAccount.LockedCoinsFromVesting(cva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate @@ -553,11 +549,9 @@ func (pva PeriodicVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins return pva.OriginalVesting.Sub(pva.GetVestedCoins(blockTime)) } -// LockedCoins returns the set of coins that are not spendable (i.e. locked) -// given the current account balance, only including tokens of vesting -// denominations, and the current block time. -func (pva PeriodicVestingAccount) LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins { - return pva.BaseVestingAccount.LockedCoinsFromVesting(balance, pva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked). +func (pva PeriodicVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { + return pva.BaseVestingAccount.LockedCoinsFromVesting(pva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate @@ -740,11 +734,9 @@ func (dva DelayedVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins return dva.OriginalVesting.Sub(dva.GetVestedCoins(blockTime)) } -// LockedCoins returns the set of coins that are not spendable (i.e. locked) -// given the current account balance, only including tokens of vesting -// denominations, and the current block time. -func (dva DelayedVestingAccount) LockedCoins(balance sdk.Coins, blockTime time.Time) sdk.Coins { - return dva.BaseVestingAccount.LockedCoinsFromVesting(balance, dva.GetVestingCoins(blockTime)) +// LockedCoins returns the set of coins that are not spendable (i.e. locked). +func (dva DelayedVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { + return dva.BaseVestingAccount.LockedCoinsFromVesting(dva.GetVestingCoins(blockTime)) } // TrackDelegation tracks a desired delegation amount by setting the appropriate diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index fa3472c2b0a..7565513f3bf 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -480,15 +480,7 @@ func (k BaseViewKeeper) LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Co if acc != nil { vacc, ok := acc.(vestexported.VestingAccount) if ok { - vestingCoins := vacc.GetVestingCoins(ctx.BlockTime()) - balance := sdk.NewCoins() - - for _, vestingCoin := range vestingCoins { - balance := k.GetBalance(ctx, acc.GetAddress(), vestingCoin.Denom) - balance.Add(balance) - } - - return vacc.LockedCoins(balance, ctx.BlockTime()) + return vacc.LockedCoins(ctx.BlockTime()) } } From 0aeebc7334ab6d84fae118eb6ee61412a0b4b6bf Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 13:35:44 -0500 Subject: [PATCH 18/24] Update vesting spec --- x/auth/spec/05_vesting.md | 118 ++++++++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 44 deletions(-) diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index 7cddc26e7c6..f0d967cd28e 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -6,10 +6,12 @@ order: 6 - [Vesting](#vesting) - [Intro and Requirements](#intro-and-requirements) + - [Note](#note) - [Vesting Account Types](#vesting-account-types) - [Vesting Account Specification](#vesting-account-specification) - [Determining Vesting & Vested Amounts](#determining-vesting--vested-amounts) - [Continuously Vesting Accounts](#continuously-vesting-accounts) + - [Periodic Vesting Accounts](#periodic-vesting-accounts) - [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts) - [Transferring/Sending](#transferringsending) - [Keepers/Handlers](#keepershandlers) @@ -22,6 +24,7 @@ order: 6 - [Examples](#examples) - [Simple](#simple) - [Slashing](#slashing) + - [Periodic Vesting](#periodic-vesting) - [Glossary](#glossary) ## Intro and Requirements @@ -67,45 +70,50 @@ having coins fail to vest). // VestingAccount defines an interface that any vesting account type must // implement. type VestingAccount interface { - Account + Account - GetVestedCoins(Time) Coins - GetVestingCoins(Time) Coins + GetVestedCoins(Time) Coins + GetVestingCoins(Time) Coins - // Delegation and undelegation accounting that returns the resulting base - // coins amount. - TrackDelegation(Time, Coins) - TrackUndelegation(Coins) + // TrackDelegation performs internal vesting accounting necessary when + // delegating from a vesting account. It accepts the current block time, the + // delegation amount and balance of all coins whose denomination exists in + // the account's original vesting balance. + TrackDelegation(Time, Coins, Coins) - GetStartTime() int64 - GetEndTime() int64 + // TrackUndelegation performs internal vesting accounting necessary when a + // vesting account performs an undelegation. + TrackUndelegation(Coins) + + GetStartTime() int64 + GetEndTime() int64 } // BaseVestingAccount implements the VestingAccount interface. It contains all // the necessary fields needed for any vesting account implementation. type BaseVestingAccount struct { - BaseAccount + BaseAccount - OriginalVesting Coins // coins in account upon initialization - DelegatedFree Coins // coins that are vested and delegated - DelegatedVesting Coins // coins that vesting and delegated + OriginalVesting Coins // coins in account upon initialization + DelegatedFree Coins // coins that are vested and delegated + DelegatedVesting Coins // coins that vesting and delegated - EndTime int64 // when the coins become unlocked + EndTime int64 // when the coins become unlocked } // ContinuousVestingAccount implements the VestingAccount interface. It // continuously vests by unlocking coins linearly with respect to time. type ContinuousVestingAccount struct { - BaseVestingAccount + BaseVestingAccount - StartTime int64 // when the coins start to vest + StartTime int64 // when the coins start to vest } // DelayedVestingAccount implements the VestingAccount interface. It vests all // coins after a specific time, but non prior. In other words, it keeps them // locked until a specified time. type DelayedVestingAccount struct { - BaseVestingAccount + BaseVestingAccount } // VestingPeriod defines a length of time and amount of coins that will vest @@ -127,16 +135,18 @@ type PeriodicVestingAccount struct { ``` In order to facilitate less ad-hoc type checking and assertions and to support -flexibility in account usage, the existing `Account` interface is updated to contain -the following: +flexibility in account balance usage, the existing `x/bank` `ViewKeeper` interface +is updated to contain the following: ```go -type Account interface { - // ... +type ViewKeeper interface { + // ... + + // Calculates the total locked account balance. + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - // Calculates the amount of coins that can be sent to other accounts given - // the current time. - SpendableCoins(Time) Coins + // Calculates the total spendable balance that can be sent to other accounts. + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } ``` @@ -268,10 +278,35 @@ In other words, a vesting account may transfer the minimum of the base account balance and the base account balance plus the number of currently delegated vesting coins less the number of coins vested so far. +However, given that account balances are tracked via the `x/bank` module and that +we want to avoid loading the entire account balance, we can instead determine +the locked balance and infer the spendable balance, which can be defined as follows: +`max(V - DV, 0)`. + +```go +func (va VestingAccount) LockedCoinsFromVesting(v Coins) Coins { + return max(v - va.DelegatedVesting, 0) +} + +func (va VestingAccount) LockedCoins(t Time) Coins { + return va.LockedCoinsFromVesting(va.GetVestingCoins(t)) +} +``` + +The `x/bank` `ViewKeeper` can then provide APIs to determine locked and spendable +coins for any account: + ```go -func (va VestingAccount) SpendableCoins(t Time) Coins { - bc := va.GetCoins() - return min((bc + va.DelegatedVesting) - va.GetVestingCoins(t), bc) +func (k Keeper) LockedCoins(ctx Context, addr AccAddress) Coins { + acc := k.GetAccount(ctx, addr) + if acc != nil { + if acc.IsVesting() { + return acc.LockedCoins(ctx.BlockTime()) + } + } + + // non-vesting accounts do not have any locked coins + return NewCoins() } ``` @@ -281,21 +316,18 @@ The corresponding `x/bank` keeper should appropriately handle sending coins based on if the account is a vesting account or not. ```go -func SendCoins(t Time, from Account, to Account, amount Coins) { - bc := from.GetCoins() +func (k Keeper) SendCoins(ctx Context, from Account, to Account, amount Coins) { + bc := k.GetCoins(ctx, from) + v := k.LockedCoins(ctx, from) - if isVesting(from) { - sc := from.SpendableCoins(t) - assert(amount <= sc) - } - - newCoins := bc - amount + spendable := bc - v + newCoins := spendable - amount assert(newCoins >= 0) - from.SetCoins(bc - amount) - to.SetCoins(amount) + from.SetBalance(newCoins) + to.AddBalance(amount) - // save accounts... + // save balances... } ``` @@ -310,7 +342,8 @@ For a vesting account attempting to delegate `D` coins, the following is perform 5. Set `DF += Y` ```go -func (va VestingAccount) TrackDelegation(t Time, amount Coins) { +func (va VestingAccount) TrackDelegation(t Time, balance Coins, amount Coins) { + assert(balance <= amount) x := min(max(va.GetVestingCoins(t) - va.DelegatedVesting, 0), amount) y := amount - x @@ -326,13 +359,10 @@ fields, so upstream callers MUST modify the `Coins` field by subtracting `amount ```go func DelegateCoins(t Time, from Account, amount Coins) { - bc := from.GetCoins() - assert(amount <= bc) - if isVesting(from) { from.TrackDelegation(t, amount) } else { - from.SetCoins(sc - amount) + from.SetBalance(sc - amount) } // save account... @@ -383,7 +413,7 @@ func UndelegateCoins(to Account, amount Coins) { // save account ... } } else { - AddCoins(to, amount) + AddBalance(to, amount) // save account... } } From 636f0e01e00d2b750a4303fb9531160ba0994db9 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 13:36:50 -0500 Subject: [PATCH 19/24] Adjust wording --- x/auth/spec/05_vesting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index f0d967cd28e..8d66202ad53 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -280,8 +280,8 @@ vesting coins less the number of coins vested so far. However, given that account balances are tracked via the `x/bank` module and that we want to avoid loading the entire account balance, we can instead determine -the locked balance and infer the spendable balance, which can be defined as follows: -`max(V - DV, 0)`. +the locked balance, which can be defined as `max(V - DV, 0)`, and infer the +spendable balance from that. ```go func (va VestingAccount) LockedCoinsFromVesting(v Coins) Coins { From 519e290b7a51491ef3f8acf643b28ad5554d22cb Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 13:38:00 -0500 Subject: [PATCH 20/24] Adjust spec --- x/auth/spec/05_vesting.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index 8d66202ad53..6db8d7ecc58 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -284,12 +284,8 @@ the locked balance, which can be defined as `max(V - DV, 0)`, and infer the spendable balance from that. ```go -func (va VestingAccount) LockedCoinsFromVesting(v Coins) Coins { - return max(v - va.DelegatedVesting, 0) -} - func (va VestingAccount) LockedCoins(t Time) Coins { - return va.LockedCoinsFromVesting(va.GetVestingCoins(t)) + return max(va.GetVestingCoins(t) - va.DelegatedVesting, 0) } ``` From 62540e60731152c9c24f02c09395ff30829d0d58 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 13:38:44 -0500 Subject: [PATCH 21/24] Adjust spec --- x/auth/spec/05_vesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index 6db8d7ecc58..50bf70d03fc 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -313,7 +313,7 @@ based on if the account is a vesting account or not. ```go func (k Keeper) SendCoins(ctx Context, from Account, to Account, amount Coins) { - bc := k.GetCoins(ctx, from) + bc := k.GetBalances(ctx, from) v := k.LockedCoins(ctx, from) spendable := bc - v From d8eb4b7b1b9d990deecbe3d41d913501dcc8c793 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 13:55:32 -0500 Subject: [PATCH 22/24] Update ADR 004 --- .../adr-004-split-denomination-keys.md | 77 +++++++++++++++---- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/docs/architecture/adr-004-split-denomination-keys.md b/docs/architecture/adr-004-split-denomination-keys.md index 5e91f7da356..8f97cb0d2a4 100644 --- a/docs/architecture/adr-004-split-denomination-keys.md +++ b/docs/architecture/adr-004-split-denomination-keys.md @@ -5,6 +5,7 @@ - 2020-01-08: Initial version - 2020-01-09: Alterations to handle vesting accounts - 2020-01-14: Updates from review feedback +- 2020-01-30: Updates from implementation ## Context @@ -18,35 +19,74 @@ Balances shall be stored per-account & per-denomination under a denomination- an ### Account interface (x/auth) -`GetCoins()` and `SetCoins()` will be removed from the account interface, since coin balances will now be stored in & managed by the bank module. +`GetCoins()` and `SetCoins()` will be removed from the account interface, since coin balances will +now be stored in & managed by the bank module. -`SpendableCoinsVestingAccount()` and `TrackDelegation()` will be altered to take a bank keeper and a denomination as two additional arguments, which will be used to lookup the balances from the base account as necessary. +The vesting account interface will replace `SpendableCoins` in favor of `LockedCoins` which does +not require the account balance anymore. In addition, `TrackDelegation()` will now accept the +account balance of all tokens denominated in the vesting balance instead of loading the entire +account balance. -Vesting accounts will continue to store original vesting, delegated free, and delegated vesting coins (which is safe since these cannot contain arbitrary denominations). +Vesting accounts will continue to store original vesting, delegated free, and delegated +vesting coins (which is safe since these cannot contain arbitrary denominations). ### Bank keeper (x/bank) -`GetBalance(addr AccAddress, denom string) sdk.Coin` and `SetBalance(addr AccAddress, coin sdk.Coin)` methods will be added to the bank keeper to retrieve & set balances, respectively. +The following APIs will be added to the `x/bank` keeper: -Balances will be stored first by the address, then by the denomination (the reverse is also possible, but retrieval of all balances for a single account is presumed to be more frequent): +- `GetAllBalances(ctx Context, addr AccAddress) Coins` +- `GetBalance(ctx Context, addr AccAddress, denom string) Coin` +- `SetBalance(ctx Context, addr AccAddress, coin Coin)` +- `LockedCoins(ctx Context, addr AccAddress) Coins` +- `SpendableCoins(ctx Context, addr AccAddress) Coins` + +Additional APIs may be added to facilitate iteration and auxiliary functionality not essential to +core functionality or persistence. + +Balances will be stored first by the address, then by the denomination (the reverse is also possible, +but retrieval of all balances for a single account is presumed to be more frequent): ```golang -func BalanceKey(addr sdk.AccAddress, denom string) []byte { - return append(append(BalanceKeyPrefix, addr.Bytes()...), []byte(denom)...) +var BalancesPrefix = []byte("balances") + +func (k Keeper) SetBalance(ctx Context, addr AccAddress, balance Coin) error { + if !balance.IsValid() { + return err + } + + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + bz := Marshal(balance) + accountStore.Set([]byte(balance.Denom), bz) + + return nil } ``` -`DelegateCoins()` and `UndelegateCoins()` will be altered to take a single `sdk.Coin` (one denomination & amount) instead of `sdk.Coins`, since they should only operate on one denomination. They will read balances directly instead of calling `GetCoins()` (which no longer exists). +This will result in the balances being indexed by the byte representation of +`balances/{address}/{denom}`. + +`DelegateCoins()` and `UndelegateCoins()` will be altered to only load each individual +account balance by denomination found in the (un)delegation amount. As a result, +any mutations to the account balance by will made by denomination. -`SubtractCoins()` and `AddCoins()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist). +`SubtractCoins()` and `AddCoins()` will be altered to read & write the balances +directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist). -`trackDelegation()` and `trackUndelegation()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist). +`trackDelegation()` and `trackUndelegation()` will be altered to no longer update +account balances. -External APIs will need to scan all balances under an account to retain backwards-compatibility - additional methods should be added to fetch a balance for a single denomination only. +External APIs will need to scan all balances under an account to retain backwards-compatibility. It +is advised that these APIs use `GetBalance` and `SetBalance` instead of `GetAllBalances` when +possible as to not load the entire account balance. ### Supply module -The supply module, in order to implement the total supply invariant, will now need to scan all accounts & call `GetBalance` using the `x/bank` Keeper for the denomination in question, then sum the balances and check that they match the expected total supply. +The supply module, in order to implement the total supply invariant, will now need +to scan all accounts & call `GetAllBalances` using the `x/bank` Keeper, then sum +the balances and check that they match the expected total supply. ## Status @@ -56,11 +96,14 @@ Proposed. ### Positive -- O(1) reads & writes of balances (with respect to the number of denominations for which an account has non-zero balances) +- O(1) reads & writes of balances (with respect to the number of denominations for +which an account has non-zero balances). Note, this does not relate to the actual +I/O cost, rather the total number of direct reads needed. ### Negative -- Slighly less efficient reads/writes when reading & writing all balances of a single account in a transaction. +- Slightly less efficient reads/writes when reading & writing all balances of a +single account in a transaction. ### Neutral @@ -68,6 +111,6 @@ None in particular. ## References -Ref https://github.com/cosmos/cosmos-sdk/issues/4982 -Ref https://github.com/cosmos/cosmos-sdk/issues/5467 -Ref https://github.com/cosmos/cosmos-sdk/issues/5492 +- Ref: https://github.com/cosmos/cosmos-sdk/issues/4982 +- Ref: https://github.com/cosmos/cosmos-sdk/issues/5467 +- Ref: https://github.com/cosmos/cosmos-sdk/issues/5492 From 4290946f56347de22e10c961c47b14d81cff1afc Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Thu, 30 Jan 2020 13:57:26 -0500 Subject: [PATCH 23/24] Merge PR #5580: ADR 004 Implementation II (Unit Tests & Misc.) --- simapp/genesis_account_test.go | 17 +- simapp/test_helpers.go | 3 +- store/prefix/store_test.go | 4 +- x/auth/ante/ante_test.go | 61 +- x/auth/ante/fee_test.go | 4 +- x/auth/exported/exported_test.go | 2 +- x/auth/keeper/keeper_bench_test.go | 52 -- x/auth/legacy/v0_38/migrate.go | 4 +- x/auth/legacy/v0_38/types.go | 12 +- x/auth/legacy/v0_39/migrate.go | 23 + x/auth/legacy/v0_39/migrate_test.go | 87 +++ x/auth/legacy/v0_39/types.go | 8 + x/auth/types/account_test.go | 21 +- x/auth/types/genesis_test.go | 15 - x/auth/vesting/types/genesis_test.go | 12 +- x/auth/vesting/types/vesting_account_test.go | 353 ++++------ x/bank/alias.go | 2 +- x/bank/app_test.go | 66 +- x/bank/bench_test.go | 37 +- x/bank/genesis.go | 11 +- x/bank/internal/keeper/integration_test.go | 19 - x/bank/internal/keeper/keeper.go | 18 +- x/bank/internal/keeper/keeper_test.go | 650 ++++++++++-------- x/bank/internal/keeper/querier_test.go | 96 ++- x/bank/internal/types/key.go | 16 +- x/bank/internal/types/key_test.go | 7 +- x/bank/legacy/v0_38/types.go | 14 + x/bank/legacy/v0_39/migrate.go | 22 + x/bank/legacy/v0_39/migrate_test.go | 67 ++ x/bank/legacy/v0_39/types.go | 43 ++ x/bank/simulation/genesis.go | 3 - x/bank/simulation/operations.go | 38 +- x/crisis/handler_test.go | 2 +- x/distribution/keeper/allocation_test.go | 10 +- x/distribution/keeper/delegation_test.go | 27 +- x/distribution/keeper/keeper_test.go | 16 +- x/distribution/keeper/querier_test.go | 2 +- x/distribution/keeper/test_common.go | 31 +- x/distribution/proposal_handler_test.go | 34 +- x/distribution/simulation/operations.go | 16 +- x/distribution/types/expected_keepers.go | 1 + x/evidence/internal/keeper/infraction_test.go | 14 +- x/evidence/internal/keeper/keeper_test.go | 6 + x/genutil/client/cli/migrate.go | 2 + x/genutil/legacy/v0_39/migrate.go | 55 ++ x/gov/abci_test.go | 7 +- x/gov/genesis_test.go | 6 +- x/gov/keeper/deposit_test.go | 16 +- x/gov/keeper/keeper_test.go | 4 +- x/gov/keeper/proposal_test.go | 8 +- x/gov/keeper/querier_test.go | 4 +- x/gov/keeper/tally_test.go | 30 +- x/gov/keeper/test_common.go | 23 +- x/gov/keeper/vote_test.go | 2 +- x/gov/simulation/operations.go | 17 +- x/gov/test_common.go | 38 +- x/gov/types/expected_keepers.go | 1 + x/simulation/account_test.go | 2 + x/simulation/rand_util_test.go | 2 + x/slashing/abci_test.go | 4 +- x/slashing/app_test.go | 32 +- x/slashing/handler_test.go | 19 +- x/slashing/internal/keeper/keeper_test.go | 6 +- x/slashing/internal/keeper/test_common.go | 16 +- x/slashing/internal/types/expected_keepers.go | 1 + x/slashing/simulation/operations.go | 6 +- x/staking/app_test.go | 48 +- x/staking/genesis_test.go | 8 +- x/staking/handler_test.go | 66 +- x/staking/keeper/delegation_test.go | 137 ++-- x/staking/keeper/historical_info_test.go | 4 +- x/staking/keeper/keeper_test.go | 2 +- x/staking/keeper/querier_test.go | 21 +- x/staking/keeper/slash_test.go | 162 +++-- x/staking/keeper/test_common.go | 21 +- x/staking/keeper/validator_test.go | 74 +- x/staking/simulation/operations.go | 33 +- x/staking/types/expected_keepers.go | 1 + x/supply/internal/keeper/bank_test.go | 62 +- x/supply/internal/types/account_test.go | 7 +- x/supply/internal/types/expected_keepers.go | 3 + 81 files changed, 1692 insertions(+), 1204 deletions(-) create mode 100644 x/auth/legacy/v0_39/migrate.go create mode 100644 x/auth/legacy/v0_39/migrate_test.go create mode 100644 x/auth/legacy/v0_39/types.go delete mode 100644 x/bank/internal/keeper/integration_test.go create mode 100644 x/bank/legacy/v0_38/types.go create mode 100644 x/bank/legacy/v0_39/migrate.go create mode 100644 x/bank/legacy/v0_39/migrate_test.go create mode 100644 x/bank/legacy/v0_39/types.go create mode 100644 x/genutil/legacy/v0_39/migrate.go diff --git a/simapp/genesis_account_test.go b/simapp/genesis_account_test.go index 6c0c6d6775c..385bb7b217b 100644 --- a/simapp/genesis_account_test.go +++ b/simapp/genesis_account_test.go @@ -20,8 +20,7 @@ func TestSimGenesisAccountValidate(t *testing.T) { vestingStart := time.Now().UTC() coins := sdk.NewCoins(sdk.NewInt64Coin("test", 1000)) - baseAcc := authtypes.NewBaseAccount(addr, nil, pubkey, 0, 0) - require.NoError(t, baseAcc.SetCoins(coins)) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 0, 0) testCases := []struct { name string @@ -38,14 +37,14 @@ func TestSimGenesisAccountValidate(t *testing.T) { { "invalid basic account with mismatching address/pubkey", simapp.SimGenesisAccount{ - BaseAccount: authtypes.NewBaseAccount(addr, nil, secp256k1.GenPrivKey().PubKey(), 0, 0), + BaseAccount: authtypes.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), }, true, }, { "valid basic account with module name", simapp.SimGenesisAccount{ - BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(crypto.AddressHash([]byte("testmod"))), nil, nil, 0, 0), + BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(crypto.AddressHash([]byte("testmod"))), nil, 0, 0), ModuleName: "testmod", }, false, @@ -78,16 +77,6 @@ func TestSimGenesisAccountValidate(t *testing.T) { }, true, }, - { - "valid basic account with invalid original vesting coins", - simapp.SimGenesisAccount{ - BaseAccount: baseAcc, - OriginalVesting: coins.Add(coins...), - StartTime: vestingStart.Unix(), - EndTime: vestingStart.Add(1 * time.Hour).Unix(), - }, - true, - }, } for _, tc := range testCases { diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index edadd7d749e..3f2967e58f1 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -1,7 +1,6 @@ package simapp import ( - "os" "testing" "github.com/stretchr/testify/require" @@ -48,7 +47,7 @@ func Setup(isCheckTx bool) *SimApp { // genesis accounts. func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) + app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) // initialize the chain with the passed in genesis accounts genesisState := NewDefaultGenesisState() diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index 8431459748d..b5e99329055 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -18,9 +18,7 @@ import ( // copied from iavl/store_test.go var ( - cacheSize = 100 - numRecent int64 = 5 - storeEvery int64 = 3 + cacheSize = 100 ) func bz(s string) []byte { return []byte(s) } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 1d55b4d320c..75289545697 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -47,17 +47,17 @@ func TestSimulateGasCost(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, acc1.GetAddress(), types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, acc2.GetAddress(), types.NewTestCoins()) acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) - acc3.SetCoins(types.NewTestCoins()) require.NoError(t, acc3.SetAccountNumber(2)) app.AccountKeeper.SetAccount(ctx, acc3) + app.BankKeeper.SetBalances(ctx, acc3.GetAddress(), types.NewTestCoins()) // set up msgs and fee var tx sdk.Tx @@ -128,8 +128,8 @@ func TestAnteHandlerSigErrors(t *testing.T) { // save the first account, but second is still unrecognized acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(fee.Amount) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, fee.Amount) checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnknownAddress) } @@ -146,13 +146,13 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) // msg and signatures var tx sdk.Tx @@ -203,12 +203,12 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { // set the accounts, we don't need the acc numbers as it is in the genesis block acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) // msg and signatures var tx sdk.Tx @@ -260,17 +260,17 @@ func TestAnteHandlerSequences(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) - acc3.SetCoins(types.NewTestCoins()) require.NoError(t, acc3.SetAccountNumber(2)) app.AccountKeeper.SetAccount(ctx, acc3) + app.BankKeeper.SetBalances(ctx, addr3, types.NewTestCoins()) // msg and signatures var tx sdk.Tx @@ -347,19 +347,21 @@ func TestAnteHandlerFees(t *testing.T) { tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInsufficientFunds) - acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 149))) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("atom", 149))) checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInsufficientFunds) - require.True(t, app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetCoins().Empty()) - require.True(sdk.IntEq(t, app.AccountKeeper.GetAccount(ctx, addr1).GetCoins().AmountOf("atom"), sdk.NewInt(149))) + modAcc := app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName) + + require.True(t, app.BankKeeper.GetAllBalances(ctx, modAcc.GetAddress()).Empty()) + require.True(sdk.IntEq(t, app.BankKeeper.GetAllBalances(ctx, addr1).AmountOf("atom"), sdk.NewInt(149))) - acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) checkValidTx(t, anteHandler, ctx, tx, false) - require.True(sdk.IntEq(t, app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetCoins().AmountOf("atom"), sdk.NewInt(150))) - require.True(sdk.IntEq(t, app.AccountKeeper.GetAccount(ctx, addr1).GetCoins().AmountOf("atom"), sdk.NewInt(0))) + require.True(sdk.IntEq(t, app.BankKeeper.GetAllBalances(ctx, modAcc.GetAddress()).AmountOf("atom"), sdk.NewInt(150))) + require.True(sdk.IntEq(t, app.BankKeeper.GetAllBalances(ctx, addr1).AmountOf("atom"), sdk.NewInt(0))) } // Test logic around memo gas consumption. @@ -416,17 +418,17 @@ func TestAnteHandlerMultiSigner(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) - acc3.SetCoins(types.NewTestCoins()) require.NoError(t, acc3.SetAccountNumber(2)) app.AccountKeeper.SetAccount(ctx, acc3) + app.BankKeeper.SetBalances(ctx, addr3, types.NewTestCoins()) // set up msgs and fee var tx sdk.Tx @@ -465,13 +467,13 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) var tx sdk.Tx msg := types.NewTestMsg(addr1) @@ -542,13 +544,13 @@ func TestAnteHandlerSetPubKey(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - acc2.SetCoins(types.NewTestCoins()) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) + app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins()) var tx sdk.Tx @@ -669,9 +671,9 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) { // set the accounts for i, addr := range addrs { acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetCoins(types.NewTestCoins()) acc.SetAccountNumber(uint64(i)) app.AccountKeeper.SetAccount(ctx, acc) + app.BankKeeper.SetBalances(ctx, addr, types.NewTestCoins()) } var tx sdk.Tx @@ -705,8 +707,8 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) { // verify that an secp256k1 account gets rejected priv1, _, addr1 := types.KeyTestPubAddr() acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - _ = acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) var tx sdk.Tx msg := types.NewTestMsg(addr1) @@ -721,7 +723,8 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) { pub2 := priv2.PubKey() addr2 := sdk.AccAddress(pub2.Address()) acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - require.NoError(t, acc2.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150)))) + + require.NoError(t, app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("atom", 150)))) require.NoError(t, acc2.SetAccountNumber(1)) app.AccountKeeper.SetAccount(ctx, acc2) msg = types.NewTestMsg(addr2) @@ -745,9 +748,9 @@ func TestAnteHandlerReCheck(t *testing.T) { // set the accounts acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc1.SetCoins(types.NewTestCoins()) require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, types.NewTestCoins()) antehandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) @@ -806,8 +809,8 @@ func TestAnteHandlerReCheck(t *testing.T) { ctx = ctx.WithMinGasPrices(sdk.DecCoins{}) // remove funds for account so antehandler fails on recheck - acc1.SetCoins(sdk.Coins{}) app.AccountKeeper.SetAccount(ctx, acc1) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins()) _, err = antehandler(ctx, tx, false) require.NotNil(t, err, "antehandler on recheck did not fail once feePayer no longer has sufficient funds") diff --git a/x/auth/ante/fee_test.go b/x/auth/ante/fee_test.go index b088c196195..e489b19ba8f 100644 --- a/x/auth/ante/fee_test.go +++ b/x/auth/ante/fee_test.go @@ -78,8 +78,8 @@ func TestDeductFees(t *testing.T) { // Set account with insufficient funds acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - acc.SetCoins([]sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(10))}) app.AccountKeeper.SetAccount(ctx, acc) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(10)))) dfd := ante.NewDeductFeeDecorator(app.AccountKeeper, app.SupplyKeeper) antehandler := sdk.ChainAnteDecorators(dfd) @@ -89,8 +89,8 @@ func TestDeductFees(t *testing.T) { require.NotNil(t, err, "Tx did not error when fee payer had insufficient funds") // Set account with sufficient funds - acc.SetCoins([]sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(200))}) app.AccountKeeper.SetAccount(ctx, acc) + app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(200)))) _, err = antehandler(ctx, tx, false) diff --git a/x/auth/exported/exported_test.go b/x/auth/exported/exported_test.go index 8eaab048a8a..23de4f777e7 100644 --- a/x/auth/exported/exported_test.go +++ b/x/auth/exported/exported_test.go @@ -14,7 +14,7 @@ import ( func TestGenesisAccountsContains(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - acc := authtypes.NewBaseAccount(addr, nil, secp256k1.GenPrivKey().PubKey(), 0, 0) + acc := authtypes.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0) genAccounts := exported.GenesisAccounts{} require.False(t, genAccounts.Contains(acc.GetAddress())) diff --git a/x/auth/keeper/keeper_bench_test.go b/x/auth/keeper/keeper_bench_test.go index 818c36a7a94..a217eddacae 100644 --- a/x/auth/keeper/keeper_bench_test.go +++ b/x/auth/keeper/keeper_bench_test.go @@ -24,34 +24,6 @@ func BenchmarkAccountMapperGetAccountFound(b *testing.B) { } } -func BenchmarkAccountMapperGetAccountFoundWithCoins(b *testing.B) { - app, ctx := createTestApp(false) - - coins := sdk.Coins{ - sdk.NewCoin("ltc", sdk.NewInt(1000)), - sdk.NewCoin("btc", sdk.NewInt(1000)), - sdk.NewCoin("eth", sdk.NewInt(1000)), - sdk.NewCoin("xrp", sdk.NewInt(1000)), - sdk.NewCoin("bch", sdk.NewInt(1000)), - sdk.NewCoin("eos", sdk.NewInt(1000)), - } - - // assumes b.N < 2**24 - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - addr := sdk.AccAddress(arr) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetCoins(coins) - app.AccountKeeper.SetAccount(ctx, acc) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - app.AccountKeeper.GetAccount(ctx, sdk.AccAddress(arr)) - } -} - func BenchmarkAccountMapperSetAccount(b *testing.B) { app, ctx := createTestApp(false) @@ -65,27 +37,3 @@ func BenchmarkAccountMapperSetAccount(b *testing.B) { app.AccountKeeper.SetAccount(ctx, acc) } } - -func BenchmarkAccountMapperSetAccountWithCoins(b *testing.B) { - app, ctx := createTestApp(false) - - coins := sdk.Coins{ - sdk.NewCoin("ltc", sdk.NewInt(1000)), - sdk.NewCoin("btc", sdk.NewInt(1000)), - sdk.NewCoin("eth", sdk.NewInt(1000)), - sdk.NewCoin("xrp", sdk.NewInt(1000)), - sdk.NewCoin("bch", sdk.NewInt(1000)), - sdk.NewCoin("eos", sdk.NewInt(1000)), - } - - b.ResetTimer() - - // assumes b.N < 2**24 - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - addr := sdk.AccAddress(arr) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetCoins(coins) - app.AccountKeeper.SetAccount(ctx, acc) - } -} diff --git a/x/auth/legacy/v0_38/migrate.go b/x/auth/legacy/v0_38/migrate.go index e7693777767..f4a32b4454c 100644 --- a/x/auth/legacy/v0_38/migrate.go +++ b/x/auth/legacy/v0_38/migrate.go @@ -42,9 +42,9 @@ func Migrate(authGenState v036auth.GenesisState, genAccountsGenState v036genacco accounts[i] = genAccount } - accounts = sanitizeGenesisAccounts(accounts) + accounts = SanitizeGenesisAccounts(accounts) - if err := validateGenAccounts(accounts); err != nil { + if err := ValidateGenAccounts(accounts); err != nil { panic(err) } diff --git a/x/auth/legacy/v0_38/types.go b/x/auth/legacy/v0_38/types.go index 15896a39121..1502fb27dbf 100644 --- a/x/auth/legacy/v0_38/types.go +++ b/x/auth/legacy/v0_38/types.go @@ -46,7 +46,7 @@ type ( BaseAccount struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` + Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"` PubKey crypto.PubKey `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -54,7 +54,7 @@ type ( baseAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` + Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -72,7 +72,7 @@ type ( vestingAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` + Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -104,7 +104,7 @@ type ( moduleAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` + Coins sdk.Coins `json:"coins,omitempty" yaml:"coins,omitempty"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` @@ -486,7 +486,7 @@ func validatePermissions(permissions ...string) error { return nil } -func sanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts { +func SanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts { sort.Slice(genAccounts, func(i, j int) bool { return genAccounts[i].GetAccountNumber() < genAccounts[j].GetAccountNumber() }) @@ -500,7 +500,7 @@ func sanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts { return genAccounts } -func validateGenAccounts(genAccounts GenesisAccounts) error { +func ValidateGenAccounts(genAccounts GenesisAccounts) error { addrMap := make(map[string]bool, len(genAccounts)) for _, acc := range genAccounts { diff --git a/x/auth/legacy/v0_39/migrate.go b/x/auth/legacy/v0_39/migrate.go new file mode 100644 index 00000000000..82b1390869f --- /dev/null +++ b/x/auth/legacy/v0_39/migrate.go @@ -0,0 +1,23 @@ +package v039 + +import ( + "fmt" + + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" +) + +// Migrate accepts exported x/auth genesis state from v0.38 and migrates it to +// v0.39 x/auth genesis state. The migration includes: +// +// - Removing coins from account encoding. +func Migrate(authGenState v038auth.GenesisState) v038auth.GenesisState { + for _, account := range authGenState.Accounts { + // set coins to nil and allow the JSON encoding to omit coins + if err := account.SetCoins(nil); err != nil { + panic(fmt.Sprintf("failed to set account coins to nil: %s", err)) + } + } + + authGenState.Accounts = v038auth.SanitizeGenesisAccounts(authGenState.Accounts) + return authGenState +} diff --git a/x/auth/legacy/v0_39/migrate_test.go b/x/auth/legacy/v0_39/migrate_test.go new file mode 100644 index 00000000000..5f9cee0d257 --- /dev/null +++ b/x/auth/legacy/v0_39/migrate_test.go @@ -0,0 +1,87 @@ +package v039_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_34" + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v039 "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_39" + + "github.com/stretchr/testify/require" +) + +func TestMigrate(t *testing.T) { + v039Codec := codec.New() + codec.RegisterCrypto(v039Codec) + v038auth.RegisterCodec(v039Codec) + + coins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) + addr1, _ := sdk.AccAddressFromBech32("cosmos1xxkueklal9vejv9unqu80w9vptyepfa95pd53u") + acc1 := v038auth.NewBaseAccount(addr1, coins, nil, 1, 0) + + addr2, _ := sdk.AccAddressFromBech32("cosmos15v50ymp6n5dn73erkqtmq0u8adpl8d3ujv2e74") + vaac := v038auth.NewContinuousVestingAccountRaw( + v038auth.NewBaseVestingAccount( + v038auth.NewBaseAccount(addr2, coins, nil, 1, 0), coins, nil, nil, 3160620846, + ), + 1580309972, + ) + + gs := v038auth.GenesisState{ + Params: v0_34.Params{ + MaxMemoCharacters: 10, + TxSigLimit: 10, + TxSizeCostPerByte: 10, + SigVerifyCostED25519: 10, + SigVerifyCostSecp256k1: 10, + }, + Accounts: v038auth.GenesisAccounts{acc1, vaac}, + } + + migrated := v039.Migrate(gs) + expected := `{ + "params": { + "max_memo_characters": "10", + "tx_sig_limit": "10", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "10", + "sig_verify_cost_secp256k1": "10" + }, + "accounts": [ + { + "type": "cosmos-sdk/Account", + "value": { + "address": "cosmos1xxkueklal9vejv9unqu80w9vptyepfa95pd53u", + "public_key": "", + "account_number": 1, + "sequence": 0 + } + }, + { + "type": "cosmos-sdk/ContinuousVestingAccount", + "value": { + "address": "cosmos15v50ymp6n5dn73erkqtmq0u8adpl8d3ujv2e74", + "public_key": "", + "account_number": 1, + "sequence": 0, + "original_vesting": [ + { + "denom": "stake", + "amount": "50" + } + ], + "delegated_free": [], + "delegated_vesting": [], + "end_time": 3160620846, + "start_time": 1580309972 + } + } + ] +}` + + bz, err := v039Codec.MarshalJSONIndent(migrated, "", " ") + require.NoError(t, err) + require.Equal(t, expected, string(bz)) +} diff --git a/x/auth/legacy/v0_39/types.go b/x/auth/legacy/v0_39/types.go new file mode 100644 index 00000000000..419ffe39020 --- /dev/null +++ b/x/auth/legacy/v0_39/types.go @@ -0,0 +1,8 @@ +package v039 + +// DONTCOVER +// nolint + +const ( + ModuleName = "auth" +) diff --git a/x/auth/types/account_test.go b/x/auth/types/account_test.go index 7be6a25e562..90a4dacb0c9 100644 --- a/x/auth/types/account_test.go +++ b/x/auth/types/account_test.go @@ -46,17 +46,6 @@ func TestBaseAddressPubKey(t *testing.T) { require.EqualValues(t, addr2, acc2.GetAddress()) } -func TestBaseAccountCoins(t *testing.T) { - _, _, addr := KeyTestPubAddr() - acc := NewBaseAccountWithAddress(addr) - - someCoins := sdk.Coins{sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 246)} - - err := acc.SetCoins(someCoins) - require.Nil(t, err) - require.Equal(t, someCoins, acc.GetCoins()) -} - func TestBaseAccountSequence(t *testing.T) { _, _, addr := KeyTestPubAddr() acc := NewBaseAccountWithAddress(addr) @@ -72,7 +61,6 @@ func TestBaseAccountMarshal(t *testing.T) { _, pub, addr := KeyTestPubAddr() acc := NewBaseAccountWithAddress(addr) - someCoins := sdk.Coins{sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 246)} seq := uint64(7) // set everything on the account @@ -80,8 +68,6 @@ func TestBaseAccountMarshal(t *testing.T) { require.Nil(t, err) err = acc.SetSequence(seq) require.Nil(t, err) - err = acc.SetCoins(someCoins) - require.Nil(t, err) // need a codec for marshaling cdc := codec.New() @@ -104,7 +90,7 @@ func TestBaseAccountMarshal(t *testing.T) { func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - baseAcc := NewBaseAccount(addr, nil, pubkey, 0, 0) + baseAcc := NewBaseAccount(addr, pubkey, 0, 0) tests := []struct { name string acc exported.GenesisAccount @@ -117,7 +103,7 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "invalid base valid account", - NewBaseAccount(addr, sdk.NewCoins(), secp256k1.GenPrivKey().PubKey(), 0, 0), + NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), errors.New("pubkey and address pair is invalid"), }, } @@ -133,8 +119,7 @@ func TestGenesisAccountValidate(t *testing.T) { func TestBaseAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := NewBaseAccount(addr, pubkey, 10, 50) bz, err := json.Marshal(baseAcc) require.NoError(t, err) diff --git a/x/auth/types/genesis_test.go b/x/auth/types/genesis_test.go index f28b67b21a2..3b892f48038 100644 --- a/x/auth/types/genesis_test.go +++ b/x/auth/types/genesis_test.go @@ -14,31 +14,19 @@ import ( func TestSanitize(t *testing.T) { addr1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) authAcc1 := NewBaseAccountWithAddress(addr1) - authAcc1.SetCoins(sdk.Coins{ - sdk.NewInt64Coin("bcoin", 150), - sdk.NewInt64Coin("acoin", 150), - }) authAcc1.SetAccountNumber(1) addr2 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) authAcc2 := NewBaseAccountWithAddress(addr2) - authAcc2.SetCoins(sdk.Coins{ - sdk.NewInt64Coin("acoin", 150), - sdk.NewInt64Coin("bcoin", 150), - }) genAccs := exported.GenesisAccounts{&authAcc1, &authAcc2} require.True(t, genAccs[0].GetAccountNumber() > genAccs[1].GetAccountNumber()) - require.Equal(t, genAccs[0].GetCoins()[0].Denom, "bcoin") - require.Equal(t, genAccs[0].GetCoins()[1].Denom, "acoin") require.Equal(t, genAccs[1].GetAddress(), addr2) genAccs = SanitizeGenesisAccounts(genAccs) require.False(t, genAccs[0].GetAccountNumber() > genAccs[1].GetAccountNumber()) require.Equal(t, genAccs[1].GetAddress(), addr1) - require.Equal(t, genAccs[1].GetCoins()[0].Denom, "acoin") - require.Equal(t, genAccs[1].GetCoins()[1].Denom, "bcoin") } var ( @@ -51,7 +39,6 @@ var ( // require duplicate accounts fails validation func TestValidateGenesisDuplicateAccounts(t *testing.T) { acc1 := NewBaseAccountWithAddress(sdk.AccAddress(addr1)) - acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) genAccs := make(exported.GenesisAccounts, 2) genAccs[0] = &acc1 @@ -62,10 +49,8 @@ func TestValidateGenesisDuplicateAccounts(t *testing.T) { func TestGenesisAccountIterator(t *testing.T) { acc1 := NewBaseAccountWithAddress(sdk.AccAddress(addr1)) - acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) acc2 := NewBaseAccountWithAddress(sdk.AccAddress(addr2)) - acc2.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) genAccounts := exported.GenesisAccounts{&acc1, &acc2} diff --git a/x/auth/vesting/types/genesis_test.go b/x/auth/vesting/types/genesis_test.go index aee8d1fa091..7a9781eb704 100644 --- a/x/auth/vesting/types/genesis_test.go +++ b/x/auth/vesting/types/genesis_test.go @@ -21,21 +21,21 @@ var ( // require invalid vesting account fails validation func TestValidateGenesisInvalidAccounts(t *testing.T) { acc1 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr1)) - acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) - baseVestingAcc, err := NewBaseVestingAccount(&acc1, acc1.Coins, 1548775410) - require.NoError(t, err) + acc1Balance := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) + baseVestingAcc := NewBaseVestingAccount(&acc1, acc1Balance, 1548775410) + // invalid delegated vesting - baseVestingAcc.DelegatedVesting = acc1.Coins.Add(acc1.Coins...) + baseVestingAcc.DelegatedVesting = acc1Balance.Add(acc1Balance...) acc2 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr2)) - acc2.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) + // acc2Balance := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) genAccs := make([]exported.GenesisAccount, 2) genAccs[0] = baseVestingAcc genAccs[1] = &acc2 require.Error(t, authtypes.ValidateGenAccounts(genAccs)) - baseVestingAcc.DelegatedVesting = acc1.Coins + baseVestingAcc.DelegatedVesting = acc1Balance genAccs[0] = baseVestingAcc require.NoError(t, authtypes.ValidateGenAccounts(genAccs)) // invalid start time diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index 651416338c0..6d3082bb8fa 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -27,8 +27,7 @@ func TestGetVestedCoinsContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) // require no coins vested in the very beginning of the vesting schedule vestedCoins := cva.GetVestedCoins(now) @@ -54,8 +53,7 @@ func TestGetVestingCoinsContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) // require all coins vesting in the beginning of the vesting schedule vestingCoins := cva.GetVestingCoins(now) @@ -77,37 +75,31 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - // require that there exist no spendable coins in the beginning of the - // vesting schedule - spendableCoins := cva.SpendableCoins(now) - require.Nil(t, spendableCoins) + currBalance := origCoins - // require that all original coins are spendable at the end of the vesting + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + + // require that all original coins are locked at the end of the vesting // schedule - spendableCoins = cva.SpendableCoins(endTime) - require.Equal(t, origCoins, spendableCoins) + lockedCoins := cva.LockedCoins(currBalance, now) + require.Equal(t, origCoins, lockedCoins) + + // require that there exist no locked coins in the beginning of the + lockedCoins = cva.LockedCoins(currBalance, endTime) + require.Nil(t, lockedCoins) // require that all vested coins (50%) are spendable - spendableCoins = cva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, spendableCoins) + lockedCoins = cva.LockedCoins(currBalance, now.Add(12*time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) // receive some coins recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - cva.SetCoins(cva.GetCoins().Add(recvAmt...)) + currBalance = currBalance.Add(recvAmt...) // require that all vested coins (50%) are spendable plus any received - spendableCoins = cva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 100)}, spendableCoins) - - // spend all spendable coins - cva.SetCoins(cva.GetCoins().Sub(spendableCoins)) - - // require that no more coins are spendable - spendableCoins = cva.SpendableCoins(now.Add(12 * time.Hour)) - require.Nil(t, spendableCoins) + lockedCoins = cva.LockedCoins(currBalance, now.Add(12*time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) } func TestTrackDelegationContVestingAcc(t *testing.T) { @@ -117,37 +109,33 @@ func TestTrackDelegationContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to delegate all vesting coins - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(now, origCoins) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) // require the ability to delegate all vested coins - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(endTime, origCoins) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, cva.DelegatedVesting) require.Equal(t, origCoins, cva.DelegatedFree) // require the ability to delegate all vesting coins (50%) and all vested coins (50%) - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) - cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedVesting) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) require.Panics(t, func() { - cva.TrackDelegation(endTime, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + cva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) require.Nil(t, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) @@ -160,27 +148,24 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to undelegate all vesting coins - cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(now, origCoins) + cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(now, origCoins, origCoins) cva.TrackUndelegation(origCoins) require.Nil(t, cva.DelegatedFree) require.Nil(t, cva.DelegatedVesting) // require the ability to undelegate all vested coins - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) - cva.TrackDelegation(endTime, origCoins) + cva.TrackDelegation(endTime, origCoins, origCoins) cva.TrackUndelegation(origCoins) require.Nil(t, cva.DelegatedFree) require.Nil(t, cva.DelegatedVesting) // require no modifications when the undelegation amount is zero - bacc.SetCoins(origCoins) - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) require.Panics(t, func() { cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -189,9 +174,9 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { require.Nil(t, cva.DelegatedVesting) // vest 50% and delegate to two validators - cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix()) - cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva = NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) // undelegate from one validator that got slashed 50% cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) @@ -211,10 +196,9 @@ func TestGetVestedCoinsDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require no coins are vested until schedule maturation - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) vestedCoins := dva.GetVestedCoins(now) require.Nil(t, vestedCoins) @@ -230,10 +214,9 @@ func TestGetVestingCoinsDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require all coins vesting at the beginning of the schedule - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) vestingCoins := dva.GetVestingCoins(now) require.Equal(t, origCoins, vestingCoins) @@ -249,38 +232,34 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - // require that no coins are spendable in the beginning of the vesting + // require that all coins are locked in the beginning of the vesting // schedule - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) - spendableCoins := dva.SpendableCoins(now) - require.Nil(t, spendableCoins) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + lockedCoins := dva.LockedCoins(origCoins, now) + require.True(t, lockedCoins.IsEqual(origCoins)) // require that all coins are spendable after the maturation of the vesting // schedule - spendableCoins = dva.SpendableCoins(endTime) - require.Equal(t, origCoins, spendableCoins) + lockedCoins = dva.LockedCoins(origCoins, endTime) + require.Nil(t, lockedCoins) // require that all coins are still vesting after some time - spendableCoins = dva.SpendableCoins(now.Add(12 * time.Hour)) - require.Nil(t, spendableCoins) + lockedCoins = dva.LockedCoins(origCoins, now.Add(12*time.Hour)) + require.True(t, lockedCoins.IsEqual(origCoins)) // receive some coins - recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - dva.SetCoins(dva.GetCoins().Add(recvAmt...)) - // require that only received coins are spendable since the account is still // vesting - spendableCoins = dva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, recvAmt, spendableCoins) - - // spend all spendable coins - dva.SetCoins(dva.GetCoins().Sub(spendableCoins)) - - // require that no more coins are spendable - spendableCoins = dva.SpendableCoins(now.Add(12 * time.Hour)) - require.Nil(t, spendableCoins) + lockedCoins = dva.LockedCoins(origCoins.Add(sdk.NewInt64Coin(stakeDenom, 50)), now.Add(12*time.Hour)) + require.True(t, lockedCoins.IsEqual(origCoins)) + + // delegate some locked coins + // require that locked is reduced + delegatedAmount := sdk.NewCoins(sdk.NewInt64Coin(stakeDenom, 50)) + dva.TrackDelegation(now.Add(12*time.Hour), origCoins, delegatedAmount) + lockedCoins = dva.LockedCoins(origCoins.Sub(delegatedAmount), now.Add(12*time.Hour)) + require.True(t, lockedCoins.IsEqual(origCoins.Sub(delegatedAmount))) } func TestTrackDelegationDelVestingAcc(t *testing.T) { @@ -290,36 +269,31 @@ func TestTrackDelegationDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to delegate all vesting coins - bacc.SetCoins(origCoins) - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(now, origCoins) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) // require the ability to delegate all vested coins - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(endTime, origCoins) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, dva.DelegatedVesting) require.Equal(t, origCoins, dva.DelegatedFree) // require the ability to delegate all coins half way through the vesting // schedule - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(now.Add(12*time.Hour), origCoins) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(now.Add(12*time.Hour), origCoins, origCoins) require.Equal(t, origCoins, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) require.Panics(t, func() { - dva.TrackDelegation(endTime, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + dva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) require.Nil(t, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) @@ -332,27 +306,23 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to undelegate all vesting coins - bacc.SetCoins(origCoins) - dva := NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(now, origCoins) + dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(now, origCoins, origCoins) dva.TrackUndelegation(origCoins) require.Nil(t, dva.DelegatedFree) require.Nil(t, dva.DelegatedVesting) // require the ability to undelegate all vested coins - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(endTime, origCoins) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(endTime, origCoins, origCoins) dva.TrackUndelegation(origCoins) require.Nil(t, dva.DelegatedFree) require.Nil(t, dva.DelegatedVesting) // require no modifications when the undelegation amount is zero - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) require.Panics(t, func() { dva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -361,10 +331,9 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { require.Nil(t, dva.DelegatedVesting) // vest 50% and delegate to two validators - bacc.SetCoins(origCoins) - dva = NewDelayedVestingAccount(&bacc, endTime.Unix()) - dva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - dva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + dva = NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) + dva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + dva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) // undelegate from one validator that got slashed 50% dva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) @@ -390,8 +359,7 @@ func TestGetVestedCoinsPeriodicVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) // require no coins vested at the beginning of the vesting schedule vestedCoins := pva.GetVestedCoins(now) @@ -437,8 +405,7 @@ func TestGetVestingCoinsPeriodicVestingAcc(t *testing.T) { origCoins := sdk.Coins{ sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) // require all coins vesting at the beginning of the vesting schedule vestingCoins := pva.GetVestingCoins(now) @@ -478,37 +445,27 @@ func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { origCoins := sdk.Coins{ sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) // require that there exist no spendable coins at the beginning of the // vesting schedule - spendableCoins := pva.SpendableCoins(now) - require.Nil(t, spendableCoins) + lockedCoins := pva.LockedCoins(origCoins, now) + require.Equal(t, origCoins, lockedCoins) // require that all original coins are spendable at the end of the vesting // schedule - spendableCoins = pva.SpendableCoins(endTime) - require.Equal(t, origCoins, spendableCoins) + lockedCoins = pva.LockedCoins(origCoins, endTime) + require.Nil(t, lockedCoins) - // require that all vested coins (50%) are spendable - spendableCoins = pva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, spendableCoins) + // require that all still vesting coins (50%) are locked + lockedCoins = pva.LockedCoins(origCoins, now.Add(12*time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) // receive some coins + // require that all still vesting coins (50% of original) are locked plus any received recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - pva.SetCoins(pva.GetCoins().Add(recvAmt...)) - - // require that all vested coins (50%) are spendable plus any received - spendableCoins = pva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 100)}, spendableCoins) - - // spend all spendable coins - pva.SetCoins(pva.GetCoins().Sub(spendableCoins)) - - // require that no more coins are spendable - spendableCoins = pva.SpendableCoins(now.Add(12 * time.Hour)) - require.Nil(t, spendableCoins) + lockedCoins = pva.LockedCoins(origCoins.Add(recvAmt...), now.Add(12*time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) } func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { @@ -523,53 +480,47 @@ func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to delegate all vesting coins - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now, origCoins) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) // require the ability to delegate all vested coins - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(endTime, origCoins) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, pva.DelegatedVesting) require.Equal(t, origCoins, pva.DelegatedFree) // delegate half of vesting coins - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now, periods[0].Amount) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now, origCoins, periods[0].Amount) // require that all delegated coins are delegated vesting require.Equal(t, pva.DelegatedVesting, periods[0].Amount) require.Nil(t, pva.DelegatedFree) // delegate 75% of coins, split between vested and vesting - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now.Add(12*time.Hour), periods[0].Amount.Add(periods[1].Amount...)) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, periods[0].Amount.Add(periods[1].Amount...)) // require that the maximum possible amount of vesting coins are chosen for delegation. require.Equal(t, pva.DelegatedFree, periods[1].Amount) require.Equal(t, pva.DelegatedVesting, periods[0].Amount) // require the ability to delegate all vesting coins (50%) and all vested coins (50%) - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) - pva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedVesting) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) require.Panics(t, func() { - pva.TrackDelegation(endTime, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + pva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) require.Nil(t, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) @@ -587,35 +538,31 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { _, _, addr := KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - bacc.SetCoins(origCoins) // require the ability to undelegate all vesting coins at the beginning of vesting - pva := NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now, origCoins) + pva := NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now, origCoins, origCoins) pva.TrackUndelegation(origCoins) require.Nil(t, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require the ability to undelegate all vested coins at the end of vesting - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) - pva.TrackDelegation(endTime, origCoins) + pva.TrackDelegation(endTime, origCoins, origCoins) pva.TrackUndelegation(origCoins) require.Nil(t, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require the ability to undelegate half of coins - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(endTime, periods[0].Amount) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(endTime, origCoins, periods[0].Amount) pva.TrackUndelegation(periods[0].Amount) require.Nil(t, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require no modifications when the undelegation amount is zero - bacc.SetCoins(origCoins) - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) require.Panics(t, func() { pva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) @@ -624,9 +571,9 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Nil(t, pva.DelegatedVesting) // vest 50% and delegate to two validators - pva = NewPeriodicVestingAccount(&bacc, now.Unix(), periods) - pva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - pva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + pva = NewPeriodicVestingAccount(&bacc, origCoins, now.Unix(), periods) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) // undelegate from one validator that got slashed 50% pva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) @@ -639,42 +586,42 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, pva.DelegatedVesting) } -func TestNewBaseVestingAccount(t *testing.T) { - pubkey := secp256k1.GenPrivKey().PubKey() - addr := sdk.AccAddress(pubkey.Address()) - _, err := NewBaseVestingAccount( - authtypes.NewBaseAccount(addr, sdk.NewCoins(), pubkey, 0, 0), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, - ) - require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - - _, err = NewBaseVestingAccount( - authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)), pubkey, 0, 0), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, - ) - require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - - _, err = NewBaseVestingAccount( - authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)), pubkey, 0, 0), - sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)), 100, - ) - require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) - - _, err = NewBaseVestingAccount( - authtypes.NewBaseAccount(addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, pubkey, 0, 0), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, - ) - require.NoError(t, err) - -} +// TODO: Move test to bank +// func TestNewBaseVestingAccount(t *testing.T) { +// pubkey := secp256k1.GenPrivKey().PubKey() +// addr := sdk.AccAddress(pubkey.Address()) +// _, err := NewBaseVestingAccount( +// authtypes.NewBaseAccount(addr, sdk.NewCoins(), pubkey, 0, 0), +// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, +// ) +// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) + +// _, err = NewBaseVestingAccount( +// authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)), pubkey, 0, 0), +// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, +// ) +// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) + +// _, err = NewBaseVestingAccount( +// authtypes.NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)), pubkey, 0, 0), +// sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)), 100, +// ) +// require.Equal(t, errors.New("vesting amount cannot be greater than total amount"), err) + +// _, err = NewBaseVestingAccount( +// authtypes.NewBaseAccount(addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, pubkey, 0, 0), +// sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, 100, +// ) +// require.NoError(t, err) + +// } func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - baseAcc := authtypes.NewBaseAccount(addr, nil, pubkey, 0, 0) - baseAccWithCoins := authtypes.NewBaseAccount(addr, nil, pubkey, 0, 0) - baseAccWithCoins.SetCoins(sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}) - baseVestingWithCoins, _ := NewBaseVestingAccount(baseAccWithCoins, baseAccWithCoins.Coins, 100) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 0, 0) + initialVesting := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)) + baseVestingWithCoins := NewBaseVestingAccount(baseAcc, initialVesting, 100) tests := []struct { name string acc authexported.GenesisAccount @@ -687,7 +634,7 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "invalid base valid account", - authtypes.NewBaseAccount(addr, sdk.NewCoins(), secp256k1.GenPrivKey().PubKey(), 0, 0), + authtypes.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0), errors.New("pubkey and address pair is invalid"), }, { @@ -697,17 +644,17 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "valid continuous vesting account", - NewContinuousVestingAccount(baseAcc, 100, 200), + NewContinuousVestingAccount(baseAcc, initialVesting, 100, 200), nil, }, { "invalid vesting times", - NewContinuousVestingAccount(baseAcc, 1654668078, 1554668078), + NewContinuousVestingAccount(baseAcc, initialVesting, 1654668078, 1554668078), errors.New("vesting start-time cannot be before end-time"), }, { "valid periodic vesting account", - NewPeriodicVestingAccount(baseAccWithCoins, 0, Periods{Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), + NewPeriodicVestingAccount(baseAcc, initialVesting, 0, Periods{Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}), nil, }, { @@ -738,10 +685,9 @@ func TestBaseVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc, err := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) - require.NoError(t, err) + acc := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -759,11 +705,10 @@ func TestContinuousVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - baseVesting, err := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) + baseVesting := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) acc := NewContinuousVestingAccountRaw(baseVesting, baseVesting.EndTime) - require.NoError(t, err) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -781,9 +726,9 @@ func TestPeriodicVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc := NewPeriodicVestingAccount(baseAcc, time.Now().Unix(), Periods{Period{3600, coins}}) + acc := NewPeriodicVestingAccount(baseAcc, coins, time.Now().Unix(), Periods{Period{3600, coins}}) bz, err := json.Marshal(acc) require.NoError(t, err) @@ -801,9 +746,9 @@ func TestDelayedVestingAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - acc := NewDelayedVestingAccount(baseAcc, time.Now().Unix()) + acc := NewDelayedVestingAccount(baseAcc, coins, time.Now().Unix()) bz, err := json.Marshal(acc) require.NoError(t, err) diff --git a/x/bank/alias.go b/x/bank/alias.go index 302a5ffdb76..2fdfa6602b8 100644 --- a/x/bank/alias.go +++ b/x/bank/alias.go @@ -50,7 +50,7 @@ var ( ModuleCdc = types.ModuleCdc ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled BalancesPrefix = types.BalancesPrefix - AddressFromBalancesKey = types.AddressFromBalancesKey + AddressFromBalancesStore = types.AddressFromBalancesStore ) type ( diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 7a9894aa8c3..e124baaeef7 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -49,7 +49,6 @@ var ( halfCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 5)} sendMsg1 = types.NewMsgSend(addr1, addr2, coins) - sendMsg2 = types.NewMsgSend(addr1, moduleAccAddr, coins) multiSendMsg1 = types.MsgMultiSend{ Inputs: []types.Input{types.NewInput(addr1, coins)}, @@ -93,15 +92,18 @@ var ( func TestSendNotEnoughBalance(t *testing.T) { acc := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, } genAccs := []authexported.GenesisAccount{acc} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) + require.NoError(t, err) + + app.Commit() - res1 := app.AccountKeeper.GetAccount(ctxCheck, addr1) + res1 := app.AccountKeeper.GetAccount(ctx, addr1) require.NotNil(t, res1) require.Equal(t, acc, res1.(*auth.BaseAccount)) @@ -157,15 +159,18 @@ func TestSendToModuleAcc(t *testing.T) { t.Run(test.name, func(t *testing.T) { acc := &auth.BaseAccount{ Address: test.msg.FromAddress, - Coins: test.fromBalance, } genAccs := []authexported.GenesisAccount{acc} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + err := app.BankKeeper.SetBalances(ctx, test.msg.FromAddress, test.fromBalance) + require.NoError(t, err) - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + app.Commit() - res1 := app.AccountKeeper.GetAccount(ctxCheck, test.msg.FromAddress) + res1 := app.AccountKeeper.GetAccount(ctx, test.msg.FromAddress) require.NotNil(t, res1) require.Equal(t, acc, res1.(*auth.BaseAccount)) @@ -190,15 +195,18 @@ func TestSendToModuleAcc(t *testing.T) { func TestMsgMultiSendWithAccounts(t *testing.T) { acc := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, } genAccs := []authexported.GenesisAccount{acc} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) + require.NoError(t, err) + + app.Commit() - res1 := app.AccountKeeper.GetAccount(ctxCheck, addr1) + res1 := app.AccountKeeper.GetAccount(ctx, addr1) require.NotNil(t, res1) require.Equal(t, acc, res1.(*auth.BaseAccount)) @@ -244,18 +252,24 @@ func TestMsgMultiSendWithAccounts(t *testing.T) { } func TestMsgMultiSendMultipleOut(t *testing.T) { - acc1 := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } acc2 := &auth.BaseAccount{ Address: addr2, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } genAccs := []authexported.GenesisAccount{acc1, acc2} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + err = app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + app.Commit() testCases := []appTestCase{ { @@ -284,22 +298,30 @@ func TestMsgMultiSendMultipleOut(t *testing.T) { } func TestMsgMultiSendMultipleInOut(t *testing.T) { - acc1 := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } acc2 := &auth.BaseAccount{ Address: addr2, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } acc4 := &auth.BaseAccount{ Address: addr4, - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}, } genAccs := []authexported.GenesisAccount{acc1, acc2, acc4} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + err = app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + err = app.BankKeeper.SetBalances(ctx, addr4, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + app.Commit() testCases := []appTestCase{ { @@ -331,13 +353,17 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) { func TestMsgMultiSendDependent(t *testing.T) { acc1 := auth.NewBaseAccountWithAddress(addr1) acc2 := auth.NewBaseAccountWithAddress(addr2) - err := acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) - require.NoError(t, err) - err = acc2.SetAccountNumber(1) + err := acc2.SetAccountNumber(1) require.NoError(t, err) genAccs := []authexported.GenesisAccount{&acc1, &acc2} app := simapp.SetupWithGenesisAccounts(genAccs) + ctx := app.BaseApp.NewContext(false, abci.Header{}) + + err = app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) + require.NoError(t, err) + + app.Commit() testCases := []appTestCase{ { diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index 9161a88c31b..d9ccdc5702a 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -3,6 +3,7 @@ package bank_test import ( "testing" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" @@ -19,29 +20,38 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) { // Add an account at genesis acc := auth.BaseAccount{ Address: addr1, - // Some value conceivably higher than the benchmarks would ever go - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 100000000000)}, } - // Construct genesis state + // construct genesis state genAccs := []authexported.GenesisAccount{&acc} benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs) + ctx := benchmarkApp.BaseApp.NewContext(false, abci.Header{}) + + // some value conceivably higher than the benchmarks would ever go + err := benchmarkApp.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 100000000000))) + require.NoError(b, err) + + benchmarkApp.Commit() // Precompute all txs txs := simapp.GenSequenceOfTxs([]sdk.Msg{sendMsg1}, []uint64{0}, []uint64{uint64(0)}, b.N, priv1) b.ResetTimer() + + height := int64(3) + // Run this with a profiler, so its easy to distinguish what time comes from // Committing, and what time comes from Check/Deliver Tx. for i := 0; i < b.N; i++ { - benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) + benchmarkApp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: height}}) _, _, err := benchmarkApp.Check(txs[i]) if err != nil { panic("something is broken in checking transaction") } benchmarkApp.Deliver(txs[i]) - benchmarkApp.EndBlock(abci.RequestEndBlock{}) + benchmarkApp.EndBlock(abci.RequestEndBlock{Height: height}) benchmarkApp.Commit() + height++ } } @@ -49,28 +59,37 @@ func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) { // Add an account at genesis acc := auth.BaseAccount{ Address: addr1, - // Some value conceivably higher than the benchmarks would ever go - Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 100000000000)}, } // Construct genesis state genAccs := []authexported.GenesisAccount{&acc} benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs) + ctx := benchmarkApp.BaseApp.NewContext(false, abci.Header{}) + + // some value conceivably higher than the benchmarks would ever go + err := benchmarkApp.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 100000000000))) + require.NoError(b, err) + + benchmarkApp.Commit() // Precompute all txs txs := simapp.GenSequenceOfTxs([]sdk.Msg{multiSendMsg1}, []uint64{0}, []uint64{uint64(0)}, b.N, priv1) b.ResetTimer() + + height := int64(3) + // Run this with a profiler, so its easy to distinguish what time comes from // Committing, and what time comes from Check/Deliver Tx. for i := 0; i < b.N; i++ { - benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) + benchmarkApp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: height}}) _, _, err := benchmarkApp.Check(txs[i]) if err != nil { panic("something is broken in checking transaction") } benchmarkApp.Deliver(txs[i]) - benchmarkApp.EndBlock(abci.RequestEndBlock{}) + benchmarkApp.EndBlock(abci.RequestEndBlock{Height: height}) benchmarkApp.Commit() + height++ } } diff --git a/x/bank/genesis.go b/x/bank/genesis.go index c93196e2553..7f68e94cff8 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -1,6 +1,8 @@ package bank import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -29,9 +31,14 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { balances := []Balance{} - for addr, coins := range balancesSet { + for addrStr, coins := range balancesSet { + addr, err := sdk.AccAddressFromBech32(addrStr) + if err != nil { + panic(fmt.Errorf("failed to convert address from string: %w", err)) + } + balances = append(balances, Balance{ - Address: sdk.AccAddress([]byte(addr)), + Address: addr, Coins: coins, }) } diff --git a/x/bank/internal/keeper/integration_test.go b/x/bank/internal/keeper/integration_test.go deleted file mode 100644 index f008a555883..00000000000 --- a/x/bank/internal/keeper/integration_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package keeper_test - -import ( - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/simapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" -) - -func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { - app := simapp.Setup(isCheckTx) - ctx := app.BaseApp.NewContext(isCheckTx, abci.Header{}) - - app.AccountKeeper.SetParams(ctx, auth.DefaultParams()) - app.BankKeeper.SetSendEnabled(ctx, true) - - return app, ctx -} diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index 7565513f3bf..38050717863 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -368,6 +368,7 @@ type ViewKeeper interface { GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(coin sdk.Coin) (stop bool)) IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, coin sdk.Coin) (stop bool)) @@ -460,7 +461,7 @@ func (k BaseViewKeeper) IterateAllBalances(ctx sdk.Context, cb func(sdk.AccAddre defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - address := types.AddressFromBalancesKey(iterator.Key()) + address := types.AddressFromBalancesStore(iterator.Key()) var balance sdk.Coin k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &balance) @@ -487,6 +488,21 @@ func (k BaseViewKeeper) LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Co return sdk.NewCoins() } +// SpendableCoins returns the total balances of spendable coins for an account +// by address. If the account has no spendable coins, an empty Coins slice is +// returned. +func (k BaseViewKeeper) SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + balances := k.GetAllBalances(ctx, addr) + locked := k.LockedCoins(ctx, addr) + + spendable, hasNeg := balances.SafeSub(locked) + if hasNeg { + return sdk.NewCoins() + } + + return spendable +} + // ValidateBalance validates all balances for a given account address returning // an error if any balance is invalid. It will check for vesting account types // and validate the balances against the original vesting balances. diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index 6b6f3cd4048..9af2e1cbbd7 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" tmkv "github.com/tendermint/tendermint/libs/kv" tmtime "github.com/tendermint/tendermint/types/time" @@ -13,189 +13,248 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/vesting" - keep "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" - "github.com/cosmos/cosmos-sdk/x/supply" ) -func TestKeeper(t *testing.T) { - app, ctx := createTestApp(false) - - addr := sdk.AccAddress([]byte("addr1")) - addr2 := sdk.AccAddress([]byte("addr2")) - addr3 := sdk.AccAddress([]byte("addr3")) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - - // Test GetCoins/SetCoins - app.AccountKeeper.SetAccount(ctx, acc) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) +const ( + fooDenom = "foo" + barDenom = "bar" +) - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) +func newFooCoin(amt int64) sdk.Coin { + return sdk.NewInt64Coin(fooDenom, amt) +} - // Test HasCoins - require.True(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - require.False(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) +func newBarCoin(amt int64) sdk.Coin { + return sdk.NewInt64Coin(barDenom, amt) +} - // Test AddCoins - app.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 25)))) +type IntegrationTestSuite struct { + suite.Suite - app.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 15))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 15), sdk.NewInt64Coin("foocoin", 25)))) + app *simapp.SimApp + ctx sdk.Context +} - // Test SubtractCoins - app.BankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - app.BankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 15)))) +func (suite *IntegrationTestSuite) SetupTest() { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{}) - app.BankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 11))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 15)))) + app.AccountKeeper.SetParams(ctx, auth.DefaultParams()) + app.BankKeeper.SetSendEnabled(ctx, true) - app.BankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, app.BankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 1)))) + suite.app = app + suite.ctx = ctx +} - // Test SendCoins - app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) +func (suite *IntegrationTestSuite) TestInputOutputCoins() { + app, ctx := suite.app, suite.ctx + balances := sdk.NewCoins(newFooCoin(90), newBarCoin(30)) - app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) - app.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 30))) - app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 5))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 5)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 10)))) + addr2 := sdk.AccAddress([]byte("addr2")) + acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + app.AccountKeeper.SetAccount(ctx, acc2) - // Test InputOutputCoins - input1 := types.NewInput(addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 2))) - output1 := types.NewOutput(addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 2))) - app.BankKeeper.InputOutputCoins(ctx, []types.Input{input1}, []types.Output{output1}) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 7)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 8)))) + addr3 := sdk.AccAddress([]byte("addr3")) + acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3) + app.AccountKeeper.SetAccount(ctx, acc3) inputs := []types.Input{ - types.NewInput(addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 3))), - types.NewInput(addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 3), sdk.NewInt64Coin("foocoin", 2))), + {Address: addr1, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}, + {Address: addr1, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}, } - outputs := []types.Output{ - types.NewOutput(addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 1))), - types.NewOutput(addr3, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 2), sdk.NewInt64Coin("foocoin", 5))), + {Address: addr2, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}, + {Address: addr3, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}, } - app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 21), sdk.NewInt64Coin("foocoin", 4)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 7), sdk.NewInt64Coin("foocoin", 6)))) - require.True(t, app.BankKeeper.GetCoins(ctx, addr3).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 2), sdk.NewInt64Coin("foocoin", 5)))) - - // Test retrieving black listed accounts - for acc := range simapp.GetMaccPerms() { - addr := supply.NewModuleAddress(acc) - require.Equal(t, app.BlacklistedAccAddrs()[addr.String()], app.BankKeeper.BlacklistedAddr(addr)) + + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, []types.Output{})) + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) + + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + + insufficientInputs := []types.Input{ + {Address: addr1, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, + {Address: addr1, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, } + insufficientOutputs := []types.Output{ + {Address: addr2, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, + {Address: addr3, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, + } + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, insufficientInputs, insufficientOutputs)) + suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) + + acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1) + expected := sdk.NewCoins(newFooCoin(30), newBarCoin(10)) + suite.Require().Equal(expected, acc1Balances) + + acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2) + suite.Require().Equal(expected, acc2Balances) + + acc3Balances := app.BankKeeper.GetAllBalances(ctx, addr3) + suite.Require().Equal(expected, acc3Balances) } -func TestSendKeeper(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestSendCoins() { + app, ctx := suite.app, suite.ctx + balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50)) - blacklistedAddrs := make(map[string]bool) + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) - paramSpace := app.ParamsKeeper.Subspace("newspace") - sendKeeper := keep.NewBaseSendKeeper(app.AccountKeeper, paramSpace, blacklistedAddrs) - app.BankKeeper.SetSendEnabled(ctx, true) + addr2 := sdk.AccAddress([]byte("addr2")) + acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + app.AccountKeeper.SetAccount(ctx, acc2) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, balances)) - addr := sdk.AccAddress([]byte("addr1")) + sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(25)) + suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt)) + + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt)) + + acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1) + expected := sdk.NewCoins(newFooCoin(50), newBarCoin(25)) + suite.Require().Equal(expected, acc1Balances) + + acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2) + expected = sdk.NewCoins(newFooCoin(150), newBarCoin(75)) + suite.Require().Equal(expected, acc2Balances) +} + +func (suite *IntegrationTestSuite) TestValidateBalance() { + app, ctx := suite.app, suite.ctx + now := tmtime.Now() + ctx = ctx.WithBlockHeader(abci.Header{Time: now}) + endTime := now.Add(24 * time.Hour) + + addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - // Test GetCoins/SetCoins + suite.Require().Error(app.BankKeeper.ValidateBalance(ctx, addr1)) + + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) - - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - - // Test HasCoins - require.True(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - require.False(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) - - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15))) - - // Test SendCoins - sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5))) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - - sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - - app.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 30))) - sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 5))) - require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 5)))) - require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 10)))) - - // validate coins with invalid denoms or negative values cannot be sent - // NOTE: We must use the Coin literal as the constructor does not allow - // negative values. - err := sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{Denom: "FOOCOIN", Amount: sdk.NewInt(-5)}}) - require.Error(t, err) + + balances := sdk.NewCoins(newFooCoin(100)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(app.BankKeeper.ValidateBalance(ctx, addr1)) + + bacc := auth.NewBaseAccountWithAddress(addr2) + vacc := vesting.NewContinuousVestingAccount(&bacc, balances.Add(balances...), now.Unix(), endTime.Unix()) + + app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, balances)) + suite.Require().Error(app.BankKeeper.ValidateBalance(ctx, addr2)) } -func TestMsgSendEvents(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestBalance() { + app, ctx := suite.app, suite.ctx + addr := sdk.AccAddress([]byte("addr1")) - app.BankKeeper.SetSendEnabled(ctx, true) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + app.AccountKeeper.SetAccount(ctx, acc) + + suite.Require().Equal(sdk.NewCoin(fooDenom, sdk.ZeroInt()), app.BankKeeper.GetBalance(ctx, addr, fooDenom)) + balances := sdk.NewCoins(newFooCoin(100)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr, balances)) + + suite.Require().Equal(balances.AmountOf(fooDenom), app.BankKeeper.GetBalance(ctx, addr, fooDenom).Amount) + suite.Require().Equal(balances, app.BankKeeper.GetAllBalances(ctx, addr)) + + newFooBalance := newFooCoin(99) + suite.Require().NoError(app.BankKeeper.SetBalance(ctx, addr, newFooBalance)) + suite.Require().Equal(newFooBalance, app.BankKeeper.GetBalance(ctx, addr, fooDenom)) + + balances = sdk.NewCoins(newBarCoin(500)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr, balances)) + suite.Require().Equal(sdk.NewCoin(fooDenom, sdk.ZeroInt()), app.BankKeeper.GetBalance(ctx, addr, fooDenom)) + suite.Require().Equal(balances.AmountOf(barDenom), app.BankKeeper.GetBalance(ctx, addr, barDenom).Amount) + suite.Require().Equal(balances, app.BankKeeper.GetAllBalances(ctx, addr)) + invalidBalance := sdk.Coin{Denom: "fooDenom", Amount: sdk.NewInt(-50)} + suite.Require().Error(app.BankKeeper.SetBalance(ctx, addr, invalidBalance)) +} + +func (suite *IntegrationTestSuite) TestSendEnabled() { + app, ctx := suite.app, suite.ctx + enabled := false + app.BankKeeper.SetSendEnabled(ctx, enabled) + suite.Require().Equal(enabled, app.BankKeeper.GetSendEnabled(ctx)) +} + +func (suite *IntegrationTestSuite) TestHasBalance() { + app, ctx := suite.app, suite.ctx + addr := sdk.AccAddress([]byte("addr1")) + + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + app.AccountKeeper.SetAccount(ctx, acc) + + balances := sdk.NewCoins(newFooCoin(100)) + suite.Require().False(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(99))) + + app.BankKeeper.SetBalances(ctx, addr, balances) + suite.Require().False(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(101))) + suite.Require().True(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(100))) + suite.Require().True(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(1))) +} + +func (suite *IntegrationTestSuite) TestMsgSendEvents() { + app, ctx := suite.app, suite.ctx addr := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) app.AccountKeeper.SetAccount(ctx, acc) - newCoins := sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) - err := app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins) - require.Error(t, err) + newCoins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + + suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) + events := ctx.EventManager().Events() - require.Equal(t, 2, len(events)) + suite.Require().Equal(2, len(events)) + event1 := sdk.Event{ Type: types.EventTypeTransfer, Attributes: []tmkv.Pair{}, } event1.Attributes = append( event1.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr2.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr2.String())}, + ) event1.Attributes = append( event1.Attributes, - tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) + tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}, + ) event2 := sdk.Event{ Type: sdk.EventTypeMessage, Attributes: []tmkv.Pair{}, } event2.Attributes = append( event2.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}) - require.Equal(t, event1, events[0]) - require.Equal(t, event2, events[1]) - - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - newCoins = sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) - err = app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins) - require.NoError(t, err) + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, + ) + + suite.Require().Equal(event1, events[0]) + suite.Require().Equal(event2, events[1]) + + app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) + newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) + events = ctx.EventManager().Events() - require.Equal(t, 4, len(events)) - require.Equal(t, event1, events[2]) - require.Equal(t, event2, events[3]) + suite.Require().Equal(4, len(events)) + suite.Require().Equal(event1, events[2]) + suite.Require().Equal(event2, events[3]) } -func TestMsgMultiSendEvents(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { + app, ctx := suite.app, suite.ctx app.BankKeeper.SetSendEnabled(ctx, true) @@ -208,8 +267,9 @@ func TestMsgMultiSendEvents(t *testing.T) { app.AccountKeeper.SetAccount(ctx, acc) app.AccountKeeper.SetAccount(ctx, acc2) - newCoins := sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) - newCoins2 := sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100)) + + newCoins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + newCoins2 := sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100)) inputs := []types.Input{ {Address: addr, Coins: newCoins}, {Address: addr2, Coins: newCoins2}, @@ -218,51 +278,58 @@ func TestMsgMultiSendEvents(t *testing.T) { {Address: addr3, Coins: newCoins}, {Address: addr4, Coins: newCoins2}, } - err := app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.Error(t, err) + + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) + events := ctx.EventManager().Events() - require.Equal(t, 0, len(events)) + suite.Require().Equal(0, len(events)) // Set addr's coins but not addr2's coins - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) + app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) + + suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) - err = app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.Error(t, err) events = ctx.EventManager().Events() - require.Equal(t, 1, len(events)) + suite.Require().Equal(1, len(events)) + event1 := sdk.Event{ Type: sdk.EventTypeMessage, Attributes: []tmkv.Pair{}, } event1.Attributes = append( event1.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}) - require.Equal(t, event1, events[0]) + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, + ) + suite.Require().Equal(event1, events[0]) // Set addr's coins and addr2's coins - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - newCoins = sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50)) - app.BankKeeper.SetCoins(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100))) - newCoins2 = sdk.NewCoins(sdk.NewInt64Coin("barcoin", 100)) + app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) + newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + + app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))) + newCoins2 = sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100)) + + suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) - err = app.BankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.NoError(t, err) events = ctx.EventManager().Events() - require.Equal(t, 5, len(events)) + suite.Require().Equal(5, len(events)) + event2 := sdk.Event{ Type: sdk.EventTypeMessage, Attributes: []tmkv.Pair{}, } event2.Attributes = append( event2.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr2.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeySender), Value: []byte(addr2.String())}, + ) event3 := sdk.Event{ Type: types.EventTypeTransfer, Attributes: []tmkv.Pair{}, } event3.Attributes = append( event3.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr3.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr3.String())}, + ) event3.Attributes = append( event3.Attributes, tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) @@ -272,41 +339,52 @@ func TestMsgMultiSendEvents(t *testing.T) { } event4.Attributes = append( event4.Attributes, - tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr4.String())}) + tmkv.Pair{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr4.String())}, + ) event4.Attributes = append( event4.Attributes, - tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}) - require.Equal(t, event1, events[1]) - require.Equal(t, event2, events[2]) - require.Equal(t, event3, events[3]) - require.Equal(t, event4, events[4]) + tmkv.Pair{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}, + ) + + suite.Require().Equal(event1, events[1]) + suite.Require().Equal(event2, events[2]) + suite.Require().Equal(event3, events[3]) + suite.Require().Equal(event4, events[4]) } -func TestViewKeeper(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestSpendableCoins() { + app, ctx := suite.app, suite.ctx + now := tmtime.Now() + ctx = ctx.WithBlockHeader(abci.Header{Time: now}) + endTime := now.Add(24 * time.Hour) - //paramSpace := app.ParamsKeeper.Subspace(types.DefaultParamspace) - viewKeeper := keep.NewBaseViewKeeper(app.AccountKeeper) + origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) + delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - addr := sdk.AccAddress([]byte("addr1")) - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + addr1 := sdk.AccAddress([]byte("addr1")) + addr2 := sdk.AccAddress([]byte("addr2")) + addrModule := sdk.AccAddress([]byte("moduleAcc")) + + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) + bacc := auth.NewBaseAccountWithAddress(addr1) + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) - // Test GetCoins/SetCoins + app.AccountKeeper.SetAccount(ctx, macc) + app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) - app.BankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) + suite.Require().Equal(origCoins, app.BankKeeper.SpendableCoins(ctx, addr2)) - // Test HasCoins - require.True(t, viewKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, viewKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - require.False(t, viewKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, viewKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) + ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) + suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr2, addrModule, delCoins)) + suite.Require().Equal(origCoins.Sub(delCoins), app.BankKeeper.SpendableCoins(ctx, addr1)) } -func TestVestingAccountSend(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestVestingAccountSend() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) endTime := now.Add(24 * time.Hour) @@ -316,29 +394,27 @@ func TestVestingAccountSend(t *testing.T) { addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) + bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) - vacc := vesting.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) + app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) // require that no coins be sendable at the beginning of the vesting schedule - err := app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) - require.Error(t, err) + suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) // receive some coins - vacc.SetCoins(origCoins.Add(sendCoins...)) - app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins.Add(sendCoins...))) // require that all vested coins are spendable plus any received ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) - err = app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) - vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - require.NoError(t, err) - require.Equal(t, origCoins, vacc.GetCoins()) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) + suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) } -func TestPeriodicVestingAccountSend(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestPeriodicVestingAccountSend() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) @@ -346,34 +422,32 @@ func TestPeriodicVestingAccountSend(t *testing.T) { addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) - bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) periods := vesting.Periods{ vesting.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 50)}}, vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, } - vacc := vesting.NewPeriodicVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), periods) + + bacc := auth.NewBaseAccountWithAddress(addr1) + vacc := vesting.NewPeriodicVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) + app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) // require that no coins be sendable at the beginning of the vesting schedule - err := app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) - require.Error(t, err) + suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) // receive some coins - vacc.SetCoins(origCoins.Add(sendCoins...)) - app.AccountKeeper.SetAccount(ctx, vacc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins.Add(sendCoins...))) // require that all vested coins are spendable plus any received ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) - err = app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) - vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.PeriodicVestingAccount) - require.NoError(t, err) - require.Equal(t, origCoins, vacc.GetCoins()) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) + suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) } -func TestVestingAccountReceive(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestVestingAccountReceive() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) endTime := now.Add(24 * time.Hour) @@ -385,27 +459,29 @@ func TestVestingAccountReceive(t *testing.T) { addr2 := sdk.AccAddress([]byte("addr2")) bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) - vacc := vesting.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - app.BankKeeper.SetCoins(ctx, addr2, origCoins) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) // send some coins to the vesting account - app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins)) // require the coins are spendable vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - require.Equal(t, origCoins.Add(sendCoins...), vacc.GetCoins()) - require.Equal(t, vacc.SpendableCoins(now), sendCoins) + balances := app.BankKeeper.GetAllBalances(ctx, addr1) + suite.Require().Equal(origCoins.Add(sendCoins...), balances) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(balances, now)), sendCoins) // require coins are spendable plus any that have vested - require.Equal(t, vacc.SpendableCoins(now.Add(12*time.Hour)), origCoins) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(balances, now.Add(12*time.Hour))), origCoins) } -func TestPeriodicVestingAccountReceive(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestPeriodicVestingAccountReceive() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) @@ -416,36 +492,38 @@ func TestPeriodicVestingAccountReceive(t *testing.T) { addr2 := sdk.AccAddress([]byte("addr2")) bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) periods := vesting.Periods{ vesting.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 50)}}, vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}}, } - vacc := vesting.NewPeriodicVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), periods) + + vacc := vesting.NewPeriodicVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - app.BankKeeper.SetCoins(ctx, addr2, origCoins) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) // send some coins to the vesting account - app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins) + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins)) // require the coins are spendable vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.PeriodicVestingAccount) - require.Equal(t, origCoins.Add(sendCoins...), vacc.GetCoins()) - require.Equal(t, vacc.SpendableCoins(now), sendCoins) + balances := app.BankKeeper.GetAllBalances(ctx, addr1) + suite.Require().Equal(origCoins.Add(sendCoins...), balances) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(balances, now)), sendCoins) // require coins are spendable plus any that have vested - require.Equal(t, vacc.SpendableCoins(now.Add(12*time.Hour)), origCoins) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(balances, now.Add(12*time.Hour))), origCoins) } -func TestDelegateCoins(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestDelegateCoins() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) endTime := now.Add(24 * time.Hour) - ak := app.AccountKeeper origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) @@ -454,39 +532,58 @@ func TestDelegateCoins(t *testing.T) { addr2 := sdk.AccAddress([]byte("addr2")) addrModule := sdk.AccAddress([]byte("moduleAcc")) + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) - macc := ak.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing - vacc := vesting.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix()) - acc := ak.NewAccountWithAddress(ctx, addr2) - ak.SetAccount(ctx, vacc) - ak.SetAccount(ctx, acc) - ak.SetAccount(ctx, macc) - app.BankKeeper.SetCoins(ctx, addr2, origCoins) + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + + app.AccountKeeper.SetAccount(ctx, vacc) + app.AccountKeeper.SetAccount(ctx, acc) + app.AccountKeeper.SetAccount(ctx, macc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) // require the ability for a non-vesting account to delegate - err := app.BankKeeper.DelegateCoins(ctx, addr2, addrModule, delCoins) - acc = ak.GetAccount(ctx, addr2) - macc = ak.GetAccount(ctx, addrModule) - require.NoError(t, err) - require.Equal(t, origCoins.Sub(delCoins), acc.GetCoins()) - require.Equal(t, delCoins, macc.GetCoins()) + suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr2, addrModule, delCoins)) + suite.Require().Equal(origCoins.Sub(delCoins), app.BankKeeper.GetAllBalances(ctx, addr2)) + suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addrModule)) // require the ability for a vesting account to delegate - err = app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins) - vacc = ak.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - require.NoError(t, err) - require.Equal(t, delCoins, vacc.GetCoins()) + suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) + suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) +} + +func (suite *IntegrationTestSuite) TestDelegateCoins_Invalid() { + app, ctx := suite.app, suite.ctx + + origCoins := sdk.NewCoins(newFooCoin(100)) + delCoins := sdk.NewCoins(newFooCoin(50)) + + addr1 := sdk.AccAddress([]byte("addr1")) + addrModule := sdk.AccAddress([]byte("moduleAcc")) + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + + suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) + invalidCoins := sdk.Coins{sdk.Coin{Denom: "fooDenom", Amount: sdk.NewInt(-50)}} + suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, invalidCoins)) + + app.AccountKeeper.SetAccount(ctx, macc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + + suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) + app.AccountKeeper.SetAccount(ctx, acc) + + suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, origCoins.Add(origCoins...))) } -func TestUndelegateCoins(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestUndelegateCoins() { + app, ctx := suite.app, suite.ctx now := tmtime.Now() ctx = ctx.WithBlockHeader(abci.Header{Time: now}) endTime := now.Add(24 * time.Hour) - ak := app.AccountKeeper origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) @@ -496,50 +593,67 @@ func TestUndelegateCoins(t *testing.T) { addrModule := sdk.AccAddress([]byte("moduleAcc")) bacc := auth.NewBaseAccountWithAddress(addr1) - bacc.SetCoins(origCoins) - macc := ak.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing - vacc := vesting.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix()) - acc := ak.NewAccountWithAddress(ctx, addr2) - ak.SetAccount(ctx, vacc) - ak.SetAccount(ctx, acc) - ak.SetAccount(ctx, macc) - app.BankKeeper.SetCoins(ctx, addr2, origCoins) + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing + + vacc := vesting.NewContinuousVestingAccount(&bacc, origCoins, ctx.BlockHeader().Time.Unix(), endTime.Unix()) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) + + app.AccountKeeper.SetAccount(ctx, vacc) + app.AccountKeeper.SetAccount(ctx, acc) + app.AccountKeeper.SetAccount(ctx, macc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) // require the ability for a non-vesting account to delegate err := app.BankKeeper.DelegateCoins(ctx, addr2, addrModule, delCoins) - require.NoError(t, err) + suite.Require().NoError(err) - acc = ak.GetAccount(ctx, addr2) - macc = ak.GetAccount(ctx, addrModule) - require.Equal(t, origCoins.Sub(delCoins), acc.GetCoins()) - require.Equal(t, delCoins, macc.GetCoins()) + suite.Require().Equal(origCoins.Sub(delCoins), app.BankKeeper.GetAllBalances(ctx, addr2)) + suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addrModule)) // require the ability for a non-vesting account to undelegate - err = app.BankKeeper.UndelegateCoins(ctx, addrModule, addr2, delCoins) - require.NoError(t, err) + suite.Require().NoError(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr2, delCoins)) - acc = ak.GetAccount(ctx, addr2) - macc = ak.GetAccount(ctx, addrModule) - require.Equal(t, origCoins, acc.GetCoins()) - require.True(t, macc.GetCoins().Empty()) + suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr2)) + suite.Require().True(app.BankKeeper.GetAllBalances(ctx, addrModule).Empty()) // require the ability for a vesting account to delegate - err = app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins) - require.NoError(t, err) + suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) - vacc = ak.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - macc = ak.GetAccount(ctx, addrModule) - require.Equal(t, origCoins.Sub(delCoins), vacc.GetCoins()) - require.Equal(t, delCoins, macc.GetCoins()) + suite.Require().Equal(origCoins.Sub(delCoins), app.BankKeeper.GetAllBalances(ctx, addr1)) + suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addrModule)) // require the ability for a vesting account to undelegate - err = app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins) - require.NoError(t, err) + suite.Require().NoError(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) + + suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) + suite.Require().True(app.BankKeeper.GetAllBalances(ctx, addrModule).Empty()) +} + +func (suite *IntegrationTestSuite) TestUndelegateCoins_Invalid() { + app, ctx := suite.app, suite.ctx + + origCoins := sdk.NewCoins(newFooCoin(100)) + delCoins := sdk.NewCoins(newFooCoin(50)) + + addr1 := sdk.AccAddress([]byte("addr1")) + addrModule := sdk.AccAddress([]byte("moduleAcc")) + macc := app.AccountKeeper.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + + suite.Require().Error(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) + + app.AccountKeeper.SetAccount(ctx, macc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + + suite.Require().Error(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) + app.AccountKeeper.SetAccount(ctx, acc) + + suite.Require().Error(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) +} - vacc = ak.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) - macc = ak.GetAccount(ctx, addrModule) - require.Equal(t, origCoins, vacc.GetCoins()) - require.True(t, macc.GetCoins().Empty()) +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) } diff --git a/x/bank/internal/keeper/querier_test.go b/x/bank/internal/keeper/querier_test.go index 11f7504043a..643f7b1798c 100644 --- a/x/bank/internal/keeper/querier_test.go +++ b/x/bank/internal/keeper/querier_test.go @@ -2,59 +2,95 @@ package keeper_test import ( "fmt" - "testing" - - "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - keep "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) -func TestBalances(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestQuerier_QueryBalance() { + app, ctx := suite.app, suite.ctx + _, _, addr := authtypes.KeyTestPubAddr() req := abci.RequestQuery{ - Path: fmt.Sprintf("custom/bank/%s", keep.QueryBalance), + Path: fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryBalance), Data: []byte{}, } - querier := keep.NewQuerier(app.BankKeeper) + querier := keeper.NewQuerier(app.BankKeeper) + + res, err := querier(ctx, []string{types.QueryBalance}, req) + suite.Require().NotNil(err) + suite.Require().Nil(res) + + req.Data = app.Codec().MustMarshalJSON(types.NewQueryBalanceParams(addr, fooDenom)) + res, err = querier(ctx, []string{types.QueryBalance}, req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + + var balance sdk.Coin + suite.Require().NoError(app.Codec().UnmarshalJSON(res, &balance)) + suite.True(balance.IsZero()) + + origCoins := sdk.NewCoins(newFooCoin(50), newBarCoin(30)) + acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + + app.AccountKeeper.SetAccount(ctx, acc) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins)) - res, err := querier(ctx, []string{"balances"}, req) - require.NotNil(t, err) - require.Nil(t, res) + res, err = querier(ctx, []string{types.QueryBalance}, req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().NoError(app.Codec().UnmarshalJSON(res, &balance)) + suite.True(balance.IsEqual(newFooCoin(50))) +} +func (suite *IntegrationTestSuite) TestQuerier_QueryAllBalances() { + app, ctx := suite.app, suite.ctx _, _, addr := authtypes.KeyTestPubAddr() - req.Data = app.Codec().MustMarshalJSON(types.NewQueryBalanceParams(addr)) - res, err = querier(ctx, []string{"balances"}, req) - require.Nil(t, err) // the account does not exist, no error returned anyway - require.NotNil(t, res) + req := abci.RequestQuery{ + Path: fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryAllBalances), + Data: []byte{}, + } + + querier := keeper.NewQuerier(app.BankKeeper) - var coins sdk.Coins - require.NoError(t, app.Codec().UnmarshalJSON(res, &coins)) - require.True(t, coins.IsZero()) + res, err := querier(ctx, []string{types.QueryAllBalances}, req) + suite.Require().NotNil(err) + suite.Require().Nil(res) + req.Data = app.Codec().MustMarshalJSON(types.NewQueryAllBalancesParams(addr)) + res, err = querier(ctx, []string{types.QueryAllBalances}, req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + + var balances sdk.Coins + suite.Require().NoError(app.Codec().UnmarshalJSON(res, &balances)) + suite.True(balances.IsZero()) + + origCoins := sdk.NewCoins(newFooCoin(50), newBarCoin(30)) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - acc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("foo", 10))) + app.AccountKeeper.SetAccount(ctx, acc) - res, err = querier(ctx, []string{"balances"}, req) - require.Nil(t, err) - require.NotNil(t, res) - require.NoError(t, app.Codec().UnmarshalJSON(res, &coins)) - require.True(t, coins.AmountOf("foo").Equal(sdk.NewInt(10))) + suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins)) + + res, err = querier(ctx, []string{types.QueryAllBalances}, req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().NoError(app.Codec().UnmarshalJSON(res, &balances)) + suite.True(balances.IsEqual(origCoins)) } -func TestQuerierRouteNotFound(t *testing.T) { - app, ctx := createTestApp(false) +func (suite *IntegrationTestSuite) TestQuerierRouteNotFound() { + app, ctx := suite.app, suite.ctx req := abci.RequestQuery{ - Path: "custom/bank/notfound", + Path: fmt.Sprintf("custom/%s/invalid", types.ModuleName), Data: []byte{}, } - querier := keep.NewQuerier(app.BankKeeper) - _, err := querier(ctx, []string{"notfound"}, req) - require.Error(t, err) + querier := keeper.NewQuerier(app.BankKeeper) + _, err := querier(ctx, []string{"invalid"}, req) + suite.Error(err) } diff --git a/x/bank/internal/types/key.go b/x/bank/internal/types/key.go index 0a9e716f73a..dcb10655347 100644 --- a/x/bank/internal/types/key.go +++ b/x/bank/internal/types/key.go @@ -1,6 +1,8 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -23,8 +25,14 @@ var ( BalancesPrefix = []byte("balances") ) -// AddressFromBalancesKey returns an account address from a balances key which -// is used as an index to store balances per account. -func AddressFromBalancesKey(key []byte) sdk.AccAddress { - return sdk.AccAddress(key[len(BalancesPrefix) : len(BalancesPrefix)+sdk.AddrLen]) +// AddressFromBalancesStore returns an account address from a balances prefix +// store. The key must not contain the perfix BalancesPrefix as the prefix store +// iterator discards the actual prefix. +func AddressFromBalancesStore(key []byte) sdk.AccAddress { + addr := key[:sdk.AddrLen] + if len(addr) != sdk.AddrLen { + panic(fmt.Sprintf("unexpected account address key length; got: %d, expected: %d", len(addr), sdk.AddrLen)) + } + + return sdk.AccAddress(addr) } diff --git a/x/bank/internal/types/key_test.go b/x/bank/internal/types/key_test.go index 5065794588e..a16a22381d6 100644 --- a/x/bank/internal/types/key_test.go +++ b/x/bank/internal/types/key_test.go @@ -15,12 +15,11 @@ func cloneAppend(bz []byte, tail []byte) (res []byte) { return } -func TestAddressFromBalancesKey(t *testing.T) { +func TestAddressFromBalancesStore(t *testing.T) { addr, err := sdk.AccAddressFromBech32("cosmos1n88uc38xhjgxzw9nwre4ep2c8ga4fjxcar6mn7") require.NoError(t, err) - key := cloneAppend(types.BalancesPrefix, addr.Bytes()) - - res := types.AddressFromBalancesKey(key) + key := cloneAppend(addr.Bytes(), []byte("stake")) + res := types.AddressFromBalancesStore(key) require.Equal(t, res, addr) } diff --git a/x/bank/legacy/v0_38/types.go b/x/bank/legacy/v0_38/types.go new file mode 100644 index 00000000000..e67640bf2b1 --- /dev/null +++ b/x/bank/legacy/v0_38/types.go @@ -0,0 +1,14 @@ +package v038 + +// DONTCOVER +// nolint + +const ( + ModuleName = "bank" +) + +type ( + GenesisState struct { + SendEnabled bool `json:"send_enabled" yaml:"send_enabled"` + } +) diff --git a/x/bank/legacy/v0_39/migrate.go b/x/bank/legacy/v0_39/migrate.go new file mode 100644 index 00000000000..222992357d9 --- /dev/null +++ b/x/bank/legacy/v0_39/migrate.go @@ -0,0 +1,22 @@ +package v039 + +import ( + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v038bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_38" +) + +// Migrate accepts exported x/auth and x/bank genesis state from v0.38 and migrates +// it to v0.39 x/bank genesis state. The migration includes: +// +// - Moving balances from x/auth to x/bank genesis state. +func Migrate(bankGenState v038bank.GenesisState, authGenState v038auth.GenesisState) GenesisState { + balances := make([]Balance, len(authGenState.Accounts)) + for i, acc := range authGenState.Accounts { + balances[i] = Balance{ + Address: acc.GetAddress(), + Coins: acc.GetCoins(), + } + } + + return NewGenesisState(bankGenState.SendEnabled, balances) +} diff --git a/x/bank/legacy/v0_39/migrate_test.go b/x/bank/legacy/v0_39/migrate_test.go new file mode 100644 index 00000000000..ae51134d47c --- /dev/null +++ b/x/bank/legacy/v0_39/migrate_test.go @@ -0,0 +1,67 @@ +package v039_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v038bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_38" + v039bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_39" + + "github.com/stretchr/testify/require" +) + +func TestMigrate(t *testing.T) { + v039Codec := codec.New() + codec.RegisterCrypto(v039Codec) + v038auth.RegisterCodec(v039Codec) + + coins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) + addr1, _ := sdk.AccAddressFromBech32("cosmos1xxkueklal9vejv9unqu80w9vptyepfa95pd53u") + acc1 := v038auth.NewBaseAccount(addr1, coins, nil, 1, 0) + + addr2, _ := sdk.AccAddressFromBech32("cosmos15v50ymp6n5dn73erkqtmq0u8adpl8d3ujv2e74") + vaac := v038auth.NewContinuousVestingAccountRaw( + v038auth.NewBaseVestingAccount( + v038auth.NewBaseAccount(addr2, coins, nil, 1, 0), coins, nil, nil, 3160620846, + ), + 1580309972, + ) + + bankGenState := v038bank.GenesisState{ + SendEnabled: true, + } + authGenState := v038auth.GenesisState{ + Accounts: v038auth.GenesisAccounts{acc1, vaac}, + } + + migrated := v039bank.Migrate(bankGenState, authGenState) + expected := `{ + "send_enabled": true, + "balances": [ + { + "address": "cosmos1xxkueklal9vejv9unqu80w9vptyepfa95pd53u", + "coins": [ + { + "denom": "stake", + "amount": "50" + } + ] + }, + { + "address": "cosmos15v50ymp6n5dn73erkqtmq0u8adpl8d3ujv2e74", + "coins": [ + { + "denom": "stake", + "amount": "50" + } + ] + } + ] +}` + + bz, err := v039Codec.MarshalJSONIndent(migrated, "", " ") + require.NoError(t, err) + require.Equal(t, expected, string(bz)) +} diff --git a/x/bank/legacy/v0_39/types.go b/x/bank/legacy/v0_39/types.go new file mode 100644 index 00000000000..d569ac4f757 --- /dev/null +++ b/x/bank/legacy/v0_39/types.go @@ -0,0 +1,43 @@ +package v039 + +// DONTCOVER +// nolint + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + ModuleName = "bank" +) + +var _ GenesisBalance = (*Balance)(nil) + +type ( + GenesisBalance interface { + GetAddress() sdk.AccAddress + GetCoins() sdk.Coins + } + + GenesisState struct { + SendEnabled bool `json:"send_enabled" yaml:"send_enabled"` + Balances []Balance `json:"balances" yaml:"balances"` + } + + Balance struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` + } +) + +func NewGenesisState(sendEnabled bool, balances []Balance) GenesisState { + return GenesisState{SendEnabled: sendEnabled, Balances: balances} +} + +func (b Balance) GetAddress() sdk.AccAddress { + return b.Address +} + +func (b Balance) GetCoins() sdk.Coins { + return b.Coins +} diff --git a/x/bank/simulation/genesis.go b/x/bank/simulation/genesis.go index 38172b20876..b593fa05b07 100644 --- a/x/bank/simulation/genesis.go +++ b/x/bank/simulation/genesis.go @@ -3,10 +3,8 @@ package simulation // DONTCOVER import ( - "fmt" "math/rand" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" @@ -47,6 +45,5 @@ func RandomizedGenState(simState *module.SimulationState) { bankGenesis := types.NewGenesisState(sendEnabled, RandomGenesisBalances(simState)) - fmt.Printf("Selected randomly generated bank parameters:\n%s\n", codec.MustMarshalJSONIndent(simState.Cdc, bankGenesis)) simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(bankGenesis) } diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 90c97522e68..0c6d8d242b8 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -22,8 +22,9 @@ const ( ) // WeightedOperations returns all the operations from the module with their respective weights -func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, - bk keeper.Keeper) simulation.WeightedOperations { +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, bk keeper.Keeper, +) simulation.WeightedOperations { var weightMsgSend, weightMsgMultiSend int appParams.GetOrGenerate(cdc, OpWeightMsgSend, &weightMsgSend, nil, @@ -84,20 +85,22 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat } // sendMsgSend sends a transaction with a MsgSend from a provided random account. +// nolint: interfacer func sendMsgSend( r *rand.Rand, app *baseapp.BaseApp, bk keeper.Keeper, ak types.AccountKeeper, msg types.MsgSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, ) error { - account := ak.GetAccount(ctx, msg.FromAddress) - var ( fees sdk.Coins err error ) - cacheCtx, _ := ctx.CacheContext() - coins, err := bk.SubtractCoins(cacheCtx, msg.FromAddress, msg.Amount) - if err == nil { + + account := ak.GetAccount(ctx, msg.FromAddress) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + coins, hasNeg := spendable.SafeSub(msg.Amount) + if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { return err @@ -218,6 +221,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O // sendMsgMultiSend sends a transaction with a MsgMultiSend from a provided random // account. +// nolint: interfacer func sendMsgMultiSend( r *rand.Rand, app *baseapp.BaseApp, bk keeper.Keeper, ak types.AccountKeeper, msg types.MsgMultiSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, @@ -232,16 +236,17 @@ func sendMsgMultiSend( sequenceNumbers[i] = acc.GetSequence() } - // feePayer is the first signer, i.e. first input address - feePayer := ak.GetAccount(ctx, msg.Inputs[0].Address) - var ( fees sdk.Coins err error ) - cacheCtx, _ := ctx.CacheContext() - coins, err := bk.SubtractCoins(cacheCtx, feePayer.GetAddress(), msg.Inputs[0].Coins) - if err == nil { + + // feePayer is the first signer, i.e. first input address + feePayer := ak.GetAccount(ctx, msg.Inputs[0].Address) + spendable := bk.SpendableCoins(ctx, feePayer.GetAddress()) + + coins, hasNeg := spendable.SafeSub(msg.Inputs[0].Coins) + if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) if err != nil { return err @@ -268,6 +273,7 @@ func sendMsgMultiSend( // randomSendFields returns the sender and recipient simulation accounts as well // as the transferred amount. +// nolint: interfacer func randomSendFields( r *rand.Rand, ctx sdk.Context, accs []simulation.Account, bk keeper.Keeper, ak types.AccountKeeper, ) (simulation.Account, simulation.Account, sdk.Coins, bool, error) { @@ -285,11 +291,9 @@ func randomSendFields( return simAccount, toSimAcc, nil, true, nil // skip error } - balances := bk.GetAllBalances(ctx, acc.GetAddress()) - locked := bk.LockedCoins(ctx, acc.GetAddress()) - balances = balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, acc.GetAddress()) - sendCoins := simulation.RandSubsetCoins(r, balances) + sendCoins := simulation.RandSubsetCoins(r, spendable) if sendCoins.Empty() { return simAccount, toSimAcc, nil, true, nil // skip error } diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index 912bd863f7c..2db4012d2f7 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -90,7 +90,7 @@ func TestHandleMsgVerifyInvariant(t *testing.T) { func TestHandleMsgVerifyInvariantWithNotEnoughSenderCoins(t *testing.T) { app, ctx, addrs := createTestApp() sender := addrs[0] - coin := app.AccountKeeper.GetAccount(ctx, sender).GetCoins()[0] + coin := app.BankKeeper.GetAllBalances(ctx, sender)[0] excessCoins := sdk.NewCoin(coin.Denom, coin.Amount.AddRaw(1)) app.CrisisKeeper.SetConstantFee(ctx, excessCoins) diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 83821ea3820..61513a02dca 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -11,7 +11,7 @@ import ( ) func TestAllocateTokensToValidatorWithCommission(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -44,7 +44,7 @@ func TestAllocateTokensToValidatorWithCommission(t *testing.T) { } func TestAllocateTokensToManyValidators(t *testing.T) { - ctx, ak, k, sk, supplyKeeper := CreateTestInputDefault(t, false, 1000) + ctx, ak, bk, k, sk, supplyKeeper := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -88,7 +88,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) { feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) require.NotNil(t, feeCollector) - err = feeCollector.SetCoins(fees) + err = bk.SetBalances(ctx, feeCollector.GetAddress(), fees) require.NoError(t, err) ak.SetAccount(ctx, feeCollector) @@ -121,7 +121,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) { func TestAllocateTokensTruncation(t *testing.T) { communityTax := sdk.NewDec(0) - ctx, ak, _, k, sk, _, supplyKeeper := CreateTestInputAdvanced(t, false, 1000000, communityTax) + ctx, ak, bk, k, sk, _, supplyKeeper := CreateTestInputAdvanced(t, false, 1000000, communityTax) sh := staking.NewHandler(sk) // create validator with 10% commission @@ -177,7 +177,7 @@ func TestAllocateTokensTruncation(t *testing.T) { feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) require.NotNil(t, feeCollector) - err = feeCollector.SetCoins(fees) + err = bk.SetBalances(ctx, feeCollector.GetAddress(), fees) require.NoError(t, err) ak.SetAccount(ctx, feeCollector) diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index 6d23ad95899..7f593fd5ecd 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -10,7 +10,7 @@ import ( ) func TestCalculateRewardsBasic(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -67,7 +67,7 @@ func TestCalculateRewardsBasic(t *testing.T) { } func TestCalculateRewardsAfterSlash(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -132,7 +132,7 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { } func TestCalculateRewardsAfterManySlashes(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -209,7 +209,7 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { } func TestCalculateRewardsMultiDelegator(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -279,12 +279,12 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { func TestWithdrawDelegationRewardsBasic(t *testing.T) { balancePower := int64(1000) balanceTokens := sdk.TokensFromConsensusPower(balancePower) - ctx, ak, k, sk, _ := CreateTestInputDefault(t, false, balancePower) + ctx, _, bk, k, sk, _ := CreateTestInputDefault(t, false, balancePower) sh := staking.NewHandler(sk) // set module account coins distrAcc := k.GetDistributionAccount(ctx) - distrAcc.SetCoins(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens))) + require.NoError(t, bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens)))) k.supplyKeeper.SetModuleAccount(ctx, distrAcc) // create validator with 50% commission @@ -305,7 +305,7 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { expTokens := balanceTokens.Sub(valTokens) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, expTokens)}, - ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins(), + bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), ) // end block to bond validator @@ -337,7 +337,7 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { exp := balanceTokens.Sub(valTokens).Add(initial.QuoRaw(2)) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)}, - ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins(), + bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), ) // withdraw commission @@ -348,12 +348,12 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { exp = balanceTokens.Sub(valTokens).Add(initial) require.Equal(t, sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)}, - ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins(), + bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr1)), ) } func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -423,7 +423,7 @@ func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { } func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) // create validator with 50% commission @@ -505,13 +505,14 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { } func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { - ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, bk, k, sk, _ := CreateTestInputDefault(t, false, 1000) sh := staking.NewHandler(sk) initial := int64(20) // set module account coins distrAcc := k.GetDistributionAccount(ctx) - distrAcc.SetCoins(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)))) + err := bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)))) + require.NoError(t, err) k.supplyKeeper.SetModuleAccount(ctx, distrAcc) tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDec(initial))} diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 5b2d989f7f8..ce0721ce665 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -11,7 +11,7 @@ import ( ) func TestSetWithdrawAddr(t *testing.T) { - ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogseld params := keeper.GetParams(ctx) params.WithdrawAddrEnabled = false @@ -31,7 +31,7 @@ func TestSetWithdrawAddr(t *testing.T) { } func TestWithdrawValidatorCommission(t *testing.T) { - ctx, ak, keeper, _, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, bk, keeper, _, _ := CreateTestInputDefault(t, false, 1000) valCommission := sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))), @@ -40,14 +40,14 @@ func TestWithdrawValidatorCommission(t *testing.T) { // set module account coins distrAcc := keeper.GetDistributionAccount(ctx) - distrAcc.SetCoins(sdk.NewCoins( + bk.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins( sdk.NewCoin("mytoken", sdk.NewInt(2)), sdk.NewCoin("stake", sdk.NewInt(2)), )) keeper.supplyKeeper.SetModuleAccount(ctx, distrAcc) // check initial balance - balance := ak.GetAccount(ctx, sdk.AccAddress(valOpAddr3)).GetCoins() + balance := bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr3)) expTokens := sdk.TokensFromConsensusPower(1000) expCoins := sdk.NewCoins(sdk.NewCoin("stake", expTokens)) require.Equal(t, expCoins, balance) @@ -62,7 +62,7 @@ func TestWithdrawValidatorCommission(t *testing.T) { keeper.WithdrawValidatorCommission(ctx, valOpAddr3) // check balance increase - balance = ak.GetAccount(ctx, sdk.AccAddress(valOpAddr3)).GetCoins() + balance = bk.GetAllBalances(ctx, sdk.AccAddress(valOpAddr3)) require.Equal(t, sdk.NewCoins( sdk.NewCoin("mytoken", sdk.NewInt(1)), sdk.NewCoin("stake", expTokens.AddRaw(1)), @@ -79,7 +79,7 @@ func TestWithdrawValidatorCommission(t *testing.T) { } func TestGetTotalRewards(t *testing.T) { - ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) + ctx, _, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) // nolint: dogseld valCommission := sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))), @@ -100,7 +100,7 @@ func TestFundCommunityPool(t *testing.T) { ctx, _, bk, keeper, _, _, _ := CreateTestInputAdvanced(t, false, 1000, sdk.NewDecWithPrec(2, 2)) amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) - _ = bk.SetCoins(ctx, delAddr1, amount) + require.NoError(t, bk.SetBalances(ctx, delAddr1, amount)) initPool := keeper.GetFeePool(ctx) assert.Empty(t, initPool.CommunityPool) @@ -109,5 +109,5 @@ func TestFundCommunityPool(t *testing.T) { assert.Nil(t, err) assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...), keeper.GetFeePool(ctx).CommunityPool) - assert.Empty(t, bk.GetCoins(ctx, delAddr1)) + assert.Empty(t, bk.GetAllBalances(ctx, delAddr1)) } diff --git a/x/distribution/keeper/querier_test.go b/x/distribution/keeper/querier_test.go index b5efd15a3a6..ed87f42edd7 100644 --- a/x/distribution/keeper/querier_test.go +++ b/x/distribution/keeper/querier_test.go @@ -109,7 +109,7 @@ func TestQueries(t *testing.T) { cdc := codec.New() types.RegisterCodec(cdc) supply.RegisterCodec(cdc) - ctx, _, keeper, sk, _ := CreateTestInputDefault(t, false, 100) + ctx, _, _, keeper, sk, _ := CreateTestInputDefault(t, false, 100) querier := NewQuerier(keeper) // test param queries diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 78425e47c11..e049c3bbc57 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -6,6 +6,7 @@ import ( "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" dbm "github.com/tendermint/tm-db" @@ -53,6 +54,9 @@ var ( delAddr1, delAddr2, delAddr3, valAccAddr1, valAccAddr2, valAccAddr3, } + pubkeys = []crypto.PubKey{ + delPk1, delPk2, delPk3, valOpPk1, valOpPk2, valOpPk3, + } distrAcc = supply.NewEmptyModuleAccount(types.ModuleName) ) @@ -73,21 +77,23 @@ func MakeTestCodec() *codec.Codec { // test input with default values func CreateTestInputDefault(t *testing.T, isCheckTx bool, initPower int64) ( - sdk.Context, auth.AccountKeeper, Keeper, staking.Keeper, types.SupplyKeeper) { + sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, types.SupplyKeeper) { communityTax := sdk.NewDecWithPrec(2, 2) - ctx, ak, _, dk, sk, _, supplyKeeper := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax) - return ctx, ak, dk, sk, supplyKeeper + ctx, ak, bk, dk, sk, _, supplyKeeper := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax) + return ctx, ak, bk, dk, sk, supplyKeeper } // hogpodge of all sorts of input required for testing -func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, - communityTax sdk.Dec) (sdk.Context, auth.AccountKeeper, bank.Keeper, - Keeper, staking.Keeper, params.Keeper, types.SupplyKeeper) { +func CreateTestInputAdvanced( + t *testing.T, isCheckTx bool, initPower int64, communityTax sdk.Dec, +) (sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, params.Keeper, types.SupplyKeeper, +) { initTokens := sdk.TokensFromConsensusPower(initPower) + keyBank := sdk.NewKVStoreKey(bank.StoreKey) keyDistr := sdk.NewKVStoreKey(types.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) @@ -98,6 +104,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyDistr, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) @@ -123,7 +130,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.ModuleName: nil, @@ -132,19 +139,19 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, } supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(cdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) - keeper := NewKeeper(cdc, keyDistr, pk.Subspace(types.DefaultParamspace), sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) + keeper := NewKeeper(cdc, keyDistr, pk.Subspace(types.DefaultParamspace), bankKeeper, sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens)) totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) // fill all the addresses with some coins, set the loose pool tokens simultaneously - for _, addr := range TestAddrs { - _, err := bankKeeper.AddCoins(ctx, addr, initCoins) - require.Nil(t, err) + for i, addr := range TestAddrs { + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, pubkeys[i], uint64(i), 0)) + require.NoError(t, bankKeeper.SetBalances(ctx, addr, initCoins)) } // set module accounts diff --git a/x/distribution/proposal_handler_test.go b/x/distribution/proposal_handler_test.go index 1aeee1f2880..1f13f15d524 100644 --- a/x/distribution/proposal_handler_test.go +++ b/x/distribution/proposal_handler_test.go @@ -19,28 +19,24 @@ var ( ) func testProposal(recipient sdk.AccAddress, amount sdk.Coins) types.CommunityPoolSpendProposal { - return types.NewCommunityPoolSpendProposal( - "Test", - "description", - recipient, - amount, - ) + return types.NewCommunityPoolSpendProposal("Test", "description", recipient, amount) } func TestProposalHandlerPassed(t *testing.T) { - ctx, accountKeeper, keeper, _, supplyKeeper := CreateTestInputDefault(t, false, 10) + ctx, ak, bk, keeper, _, supplyKeeper := CreateTestInputDefault(t, false, 10) recipient := delAddr1 // add coins to the module account macc := keeper.GetDistributionAccount(ctx) - err := macc.SetCoins(macc.GetCoins().Add(amount...)) + balances := bk.GetAllBalances(ctx, macc.GetAddress()) + err := bk.SetBalances(ctx, macc.GetAddress(), balances.Add(amount...)) require.NoError(t, err) supplyKeeper.SetModuleAccount(ctx, macc) - account := accountKeeper.NewAccountWithAddress(ctx, recipient) - require.True(t, account.GetCoins().IsZero()) - accountKeeper.SetAccount(ctx, account) + account := ak.NewAccountWithAddress(ctx, recipient) + ak.SetAccount(ctx, account) + require.True(t, bk.GetAllBalances(ctx, account.GetAddress()).IsZero()) feePool := keeper.GetFeePool(ctx) feePool.CommunityPool = sdk.NewDecCoinsFromCoins(amount...) @@ -49,19 +45,23 @@ func TestProposalHandlerPassed(t *testing.T) { tp := testProposal(recipient, amount) hdlr := NewCommunityPoolSpendProposalHandler(keeper) require.NoError(t, hdlr(ctx, tp)) - require.Equal(t, accountKeeper.GetAccount(ctx, recipient).GetCoins(), amount) + + balances = bk.GetAllBalances(ctx, recipient) + require.Equal(t, balances, amount) } func TestProposalHandlerFailed(t *testing.T) { - ctx, accountKeeper, keeper, _, _ := CreateTestInputDefault(t, false, 10) + ctx, ak, bk, keeper, _, _ := CreateTestInputDefault(t, false, 10) recipient := delAddr1 - account := accountKeeper.NewAccountWithAddress(ctx, recipient) - require.True(t, account.GetCoins().IsZero()) - accountKeeper.SetAccount(ctx, account) + account := ak.NewAccountWithAddress(ctx, recipient) + ak.SetAccount(ctx, account) + require.True(t, bk.GetAllBalances(ctx, account.GetAddress()).IsZero()) tp := testProposal(recipient, amount) hdlr := NewCommunityPoolSpendProposalHandler(keeper) require.Error(t, hdlr(ctx, tp)) - require.True(t, accountKeeper.GetAccount(ctx, recipient).GetCoins().IsZero()) + + balances := bk.GetAllBalances(ctx, recipient) + require.True(t, balances.IsZero()) } diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index 1c81a047a72..30bc1a61ec2 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -91,9 +91,7 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, simToAccount, _ := simulation.RandomAcc(r, accs) account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { @@ -141,9 +139,7 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKee } account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { @@ -194,9 +190,7 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.Ban } account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { @@ -234,9 +228,7 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k funder, _ := simulation.RandomAcc(r, accs) account := ak.GetAccount(ctx, funder.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fundAmount := simulation.RandSubsetCoins(r, spendable) if fundAmount.Empty() { diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index 5937e1b986f..1f9d0a51a34 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -19,6 +19,7 @@ type BankKeeper interface { GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } // StakingKeeper expected staking keeper (noalias) diff --git a/x/evidence/internal/keeper/infraction_test.go b/x/evidence/internal/keeper/infraction_test.go index cbef53de192..d0ae5d74239 100644 --- a/x/evidence/internal/keeper/infraction_test.go +++ b/x/evidence/internal/keeper/infraction_test.go @@ -24,24 +24,24 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { power := int64(100) stakingParams := suite.app.StakingKeeper.GetParams(ctx) - amt := sdk.TokensFromConsensusPower(power) + selfDelegation := sdk.TokensFromConsensusPower(power) operatorAddr, val := valAddresses[0], pubkeys[0] // create validator - res, err := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) + res, err := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, selfDelegation)) suite.NoError(err) suite.NotNil(res) // execute end-blocker and verify validator attributes staking.EndBlocker(ctx, suite.app.StakingKeeper) suite.Equal( - suite.app.BankKeeper.GetCoins(ctx, sdk.AccAddress(operatorAddr)), - sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(amt))), + suite.app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(operatorAddr)).String(), + sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(selfDelegation))).String(), ) - suite.Equal(amt, suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) + suite.Equal(selfDelegation, suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) // handle a signature to set signing info - suite.app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), amt.Int64(), true) + suite.app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), selfDelegation.Int64(), true) // double sign less than max age oldTokens := suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetTokens() @@ -101,7 +101,7 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { // execute end-blocker and verify validator attributes staking.EndBlocker(ctx, suite.app.StakingKeeper) suite.Equal( - suite.app.BankKeeper.GetCoins(ctx, sdk.AccAddress(operatorAddr)), + suite.app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(operatorAddr)), sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(amt))), ) suite.Equal(amt, suite.app.StakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) diff --git a/x/evidence/internal/keeper/keeper_test.go b/x/evidence/internal/keeper/keeper_test.go index 45347ab96be..d6e35a4956a 100644 --- a/x/evidence/internal/keeper/keeper_test.go +++ b/x/evidence/internal/keeper/keeper_test.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/evidence" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/internal/keeper" @@ -76,6 +77,11 @@ func (suite *KeeperTestSuite) SetupTest() { suite.querier = keeper.NewQuerier(*evidenceKeeper) suite.keeper = *evidenceKeeper suite.app = app + + for i, addr := range valAddresses { + addr := sdk.AccAddress(addr) + app.AccountKeeper.SetAccount(suite.ctx, auth.NewBaseAccount(addr, pubkeys[i], uint64(i), 0)) + } } func (suite *KeeperTestSuite) populateEvidence(ctx sdk.Context, numEvidence int) []exported.Evidence { diff --git a/x/genutil/client/cli/migrate.go b/x/genutil/client/cli/migrate.go index 3ae77c506d6..eeba89356a9 100644 --- a/x/genutil/client/cli/migrate.go +++ b/x/genutil/client/cli/migrate.go @@ -16,6 +16,7 @@ import ( extypes "github.com/cosmos/cosmos-sdk/x/genutil" v036 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_36" v038 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_38" + v039 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_39" ) const ( @@ -29,6 +30,7 @@ const ( var migrationMap = extypes.MigrationMap{ "v0.36": v036.Migrate, "v0.38": v038.Migrate, // NOTE: v0.37 and v0.38 are genesis compatible + "v0.39": v039.Migrate, } // GetMigrationCallback returns a MigrationCallback for a given version. diff --git a/x/genutil/legacy/v0_39/migrate.go b/x/genutil/legacy/v0_39/migrate.go new file mode 100644 index 00000000000..aea5ccd3f91 --- /dev/null +++ b/x/genutil/legacy/v0_39/migrate.go @@ -0,0 +1,55 @@ +package v039 + +import ( + "github.com/cosmos/cosmos-sdk/codec" + v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38" + v039auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_39" + v038bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_38" + v039bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v0_39" + "github.com/cosmos/cosmos-sdk/x/genutil" +) + +func Migrate(appState genutil.AppMap) genutil.AppMap { + v038Codec := codec.New() + codec.RegisterCrypto(v038Codec) + v038auth.RegisterCodec(v038Codec) + + v039Codec := codec.New() + codec.RegisterCrypto(v039Codec) + v038auth.RegisterCodec(v039Codec) + + // remove balances from existing accounts + if appState[v038auth.ModuleName] != nil { + // unmarshal relative source genesis application state + var authGenState v038auth.GenesisState + v038Codec.MustUnmarshalJSON(appState[v038auth.ModuleName], &authGenState) + + // delete deprecated x/auth genesis state + delete(appState, v038auth.ModuleName) + + // Migrate relative source genesis application state and marshal it into + // the respective key. + appState[v039auth.ModuleName] = v039Codec.MustMarshalJSON(v039auth.Migrate(authGenState)) + } + + if appState[v038bank.ModuleName] != nil { + // unmarshal relative source genesis application state + var bankGenState v038bank.GenesisState + v038Codec.MustUnmarshalJSON(appState[v038bank.ModuleName], &bankGenState) + + // unmarshal x/auth genesis state to retrieve all account balances + var authGenState v038auth.GenesisState + v038Codec.MustUnmarshalJSON(appState[v038auth.ModuleName], &authGenState) + + // delete deprecated x/bank genesis state + delete(appState, v038bank.ModuleName) + + // Migrate relative source genesis application state and marshal it into + // the respective key. + appState[v039bank.ModuleName] = v039Codec.MustMarshalJSON( + v039bank.Migrate(bankGenState, authGenState), + ) + } + + return appState +} diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index db5509f45e1..355abed3e84 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -5,7 +5,6 @@ import ( "time" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -263,7 +262,7 @@ func TestProposalPassedEndblocker(t *testing.T) { macc := input.keeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - initialModuleAccCoins := macc.GetCoins() + initialModuleAccCoins := input.bk.GetAllBalances(ctx, macc.GetAddress()) proposal, err := input.keeper.SubmitProposal(ctx, keep.TestProposal) require.NoError(t, err) @@ -277,7 +276,7 @@ func TestProposalPassedEndblocker(t *testing.T) { macc = input.keeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - moduleAccCoins := macc.GetCoins() + moduleAccCoins := input.bk.GetAllBalances(ctx, macc.GetAddress()) deposits := initialModuleAccCoins.Add(proposal.TotalDeposit...).Add(proposalCoins...) require.True(t, moduleAccCoins.IsEqual(deposits)) @@ -293,7 +292,7 @@ func TestProposalPassedEndblocker(t *testing.T) { macc = input.keeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) - require.True(t, macc.GetCoins().IsEqual(initialModuleAccCoins)) + require.True(t, input.bk.GetAllBalances(ctx, macc.GetAddress()).IsEqual(initialModuleAccCoins)) } func TestEndBlockerProposalHandlerFailed(t *testing.T) { diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 02b6eed9b42..0add3343c40 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -3,9 +3,8 @@ package gov import ( "testing" - "github.com/stretchr/testify/require" - keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" ) @@ -63,7 +62,8 @@ func TestImportExportQueues(t *testing.T) { require.True(t, proposal1.Status == StatusDepositPeriod) require.True(t, proposal2.Status == StatusVotingPeriod) - require.Equal(t, input2.keeper.GetDepositParams(ctx2).MinDeposit, input2.keeper.GetGovernanceAccount(ctx2).GetCoins()) + macc := input2.keeper.GetGovernanceAccount(ctx2) + require.Equal(t, input2.keeper.GetDepositParams(ctx2).MinDeposit, input2.bk.GetAllBalances(ctx2, macc.GetAddress())) // Run the endblocker. Check to make sure that proposal1 is removed from state, and proposal2 is finished VotingPeriod. EndBlocker(ctx2, input2.keeper) diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index edf45246409..ed17d448155 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -10,7 +10,7 @@ import ( ) func TestDeposits(t *testing.T) { - ctx, ak, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, bk, keeper, _, _ := createTestInput(t, false, 100) tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) @@ -20,8 +20,8 @@ func TestDeposits(t *testing.T) { fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4))) fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))) - addr0Initial := ak.GetAccount(ctx, TestAddrs[0]).GetCoins() - addr1Initial := ak.GetAccount(ctx, TestAddrs[1]).GetCoins() + addr0Initial := bk.GetAllBalances(ctx, TestAddrs[0]) + addr1Initial := bk.GetAllBalances(ctx, TestAddrs[1]) require.True(t, proposal.TotalDeposit.IsEqual(sdk.NewCoins())) @@ -43,7 +43,7 @@ func TestDeposits(t *testing.T) { proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake, proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) + require.Equal(t, addr0Initial.Sub(fourStake), bk.GetAllBalances(ctx, TestAddrs[0])) // Check a second deposit from same address votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) @@ -56,7 +56,7 @@ func TestDeposits(t *testing.T) { proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake.Add(fiveStake...), proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) + require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), bk.GetAllBalances(ctx, TestAddrs[0])) // Check third deposit from a new address votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) @@ -69,7 +69,7 @@ func TestDeposits(t *testing.T) { proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) require.Equal(t, fourStake.Add(fiveStake...).Add(fourStake...), proposal.TotalDeposit) - require.Equal(t, addr1Initial.Sub(fourStake), ak.GetAccount(ctx, TestAddrs[1]).GetCoins()) + require.Equal(t, addr1Initial.Sub(fourStake), bk.GetAllBalances(ctx, TestAddrs[1])) // Check that proposal moved to voting period proposal, ok = keeper.GetProposal(ctx, proposalID) @@ -93,6 +93,6 @@ func TestDeposits(t *testing.T) { keeper.RefundDeposits(ctx, proposalID) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1]) require.False(t, found) - require.Equal(t, addr0Initial, ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) - require.Equal(t, addr1Initial, ak.GetAccount(ctx, TestAddrs[1]).GetCoins()) + require.Equal(t, addr0Initial, bk.GetAllBalances(ctx, TestAddrs[0])) + require.Equal(t, addr1Initial, bk.GetAllBalances(ctx, TestAddrs[1])) } diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 5549049e3a3..9cd2a0559e6 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -9,7 +9,7 @@ import ( ) func TestIncrementProposalNumber(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled tp := TestProposal keeper.SubmitProposal(ctx, tp) @@ -24,7 +24,7 @@ func TestIncrementProposalNumber(t *testing.T) { } func TestProposalQueues(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled // create test proposals tp := TestProposal diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index b8f37cbd364..5848e0d753e 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -14,7 +14,7 @@ import ( ) func TestGetSetProposal(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) @@ -28,7 +28,7 @@ func TestGetSetProposal(t *testing.T) { } func TestActivateVotingPeriod(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) @@ -97,7 +97,7 @@ func registerTestCodec(cdc *codec.Codec) { } func TestSubmitProposal(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled registerTestCodec(keeper.cdc) @@ -125,7 +125,7 @@ func TestSubmitProposal(t *testing.T) { func TestGetProposalsFiltered(t *testing.T) { proposalID := uint64(1) - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled status := []types.ProposalStatus{types.StatusDepositPeriod, types.StatusVotingPeriod} addr1 := sdk.AccAddress("foo") diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index f79057f03e9..54aeae6fe7a 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -142,7 +142,7 @@ func getQueriedVotes(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sd } func TestQueries(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 1000) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 1000) // nolint: dogsled querier := NewQuerier(keeper) oneCoins := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)) @@ -285,7 +285,7 @@ func TestQueries(t *testing.T) { } func TestPaginatedVotesQuery(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 1000) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 1000) // nolint: dogsled proposal := types.Proposal{ ProposalID: 100, diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index ceaed4eb443..52812793c95 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -11,7 +11,7 @@ import ( ) func TestTallyNoOneVotes(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 5, 5}) tp := TestProposal @@ -31,7 +31,7 @@ func TestTallyNoOneVotes(t *testing.T) { } func TestTallyNoQuorum(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{2, 5, 0}) tp := TestProposal @@ -52,7 +52,7 @@ func TestTallyNoQuorum(t *testing.T) { } func TestTallyOnlyValidatorsAllYes(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 5, 5}) tp := TestProposal @@ -76,7 +76,7 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { } func TestTallyOnlyValidators51No(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 0}) tp := TestProposal @@ -98,7 +98,7 @@ func TestTallyOnlyValidators51No(t *testing.T) { } func TestTallyOnlyValidators51Yes(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 0}) tp := TestProposal @@ -121,7 +121,7 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { } func TestTallyOnlyValidatorsVetoed(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) tp := TestProposal @@ -146,7 +146,7 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { } func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) tp := TestProposal @@ -170,7 +170,7 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { } func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{6, 6, 7}) tp := TestProposal @@ -194,7 +194,7 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { } func TestTallyOnlyValidatorsNonVoter(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) tp := TestProposal @@ -217,7 +217,7 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { } func TestTallyDelgatorOverride(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) delTokens := sdk.TokensFromConsensusPower(30) @@ -251,7 +251,7 @@ func TestTallyDelgatorOverride(t *testing.T) { } func TestTallyDelgatorInherit(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) delTokens := sdk.TokensFromConsensusPower(30) @@ -284,7 +284,7 @@ func TestTallyDelgatorInherit(t *testing.T) { } func TestTallyDelgatorMultipleOverride(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{5, 6, 7}) delTokens := sdk.TokensFromConsensusPower(10) @@ -322,7 +322,7 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { } func TestTallyDelgatorMultipleInherit(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{25, 6, 7}) delTokens := sdk.TokensFromConsensusPower(10) @@ -359,7 +359,7 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { } func TestTallyJailedValidator(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{25, 6, 7}) delTokens := sdk.TokensFromConsensusPower(10) @@ -398,7 +398,7 @@ func TestTallyJailedValidator(t *testing.T) { } func TestTallyValidatorMultipleDelegations(t *testing.T) { - ctx, _, keeper, sk, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, sk, _ := createTestInput(t, false, 100) createValidators(ctx, sk, []int64{10, 10, 10}) delTokens := sdk.TokensFromConsensusPower(10) diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 777d71a8c88..897ad8b05da 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -52,6 +52,9 @@ var ( delAddr1, delAddr2, delAddr3, valAccAddr1, valAccAddr2, valAccAddr3, } + pubkeys = []crypto.PubKey{ + delPk1, delPk2, delPk3, valOpPk1, valOpPk2, valOpPk3, + } emptyDelAddr sdk.AccAddress emptyValAddr sdk.ValAddress @@ -88,11 +91,14 @@ func makeTestCodec() *codec.Codec { return cdc } -func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, Keeper, staking.Keeper, types.SupplyKeeper) { +func createTestInput( + t *testing.T, isCheckTx bool, initPower int64, +) (sdk.Context, auth.AccountKeeper, bank.Keeper, Keeper, staking.Keeper, types.SupplyKeeper, +) { initTokens := sdk.TokensFromConsensusPower(initPower) - keyAcc := sdk.NewKVStoreKey(auth.StoreKey) + keyBank := sdk.NewKVStoreKey(bank.StoreKey) keyGov := sdk.NewKVStoreKey(types.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) @@ -104,6 +110,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyGov, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) @@ -141,10 +148,10 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context pk := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(cdc, keyStaking, bankKeeper, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) rtr := types.NewRouter(). @@ -163,9 +170,9 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - for _, addr := range TestAddrs { - _, err := bankKeeper.AddCoins(ctx, addr, initCoins) - require.Nil(t, err) + for i, addr := range TestAddrs { + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, pubkeys[i], uint64(i), 0)) + require.NoError(t, bankKeeper.SetBalances(ctx, addr, initCoins)) } keeper.supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) @@ -173,7 +180,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context keeper.supplyKeeper.SetModuleAccount(ctx, bondPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - return ctx, accountKeeper, keeper, sk, supplyKeeper + return ctx, accountKeeper, bankKeeper, keeper, sk, supplyKeeper } // ProposalEqual checks if two proposals are equal (note: slow, for tests only) diff --git a/x/gov/keeper/vote_test.go b/x/gov/keeper/vote_test.go index 36c02d09137..ae25c7fcc23 100644 --- a/x/gov/keeper/vote_test.go +++ b/x/gov/keeper/vote_test.go @@ -9,7 +9,7 @@ import ( ) func TestVotes(t *testing.T) { - ctx, _, keeper, _, _ := createTestInput(t, false, 100) + ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled tp := TestProposal proposal, err := keeper.SubmitProposal(ctx, tp) diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 3ebc2617cfd..91659bd423a 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -128,9 +128,7 @@ func SimulateSubmitProposal( msg := types.NewMsgSubmitProposal(content, deposit, simAccount.Address) account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) var fees sdk.Coins coins, hasNeg := spendable.SafeSub(deposit) @@ -213,9 +211,7 @@ func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke msg := types.NewMsgDeposit(simAccount.Address, proposalID, deposit) account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) var fees sdk.Coins coins, hasNeg := spendable.SafeSub(deposit) @@ -275,13 +271,10 @@ func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k kee } option := randomVotingOption(r) - msg := types.NewMsgVote(simAccount.Address, proposalID, option) account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { @@ -315,9 +308,7 @@ func randomDeposit(r *rand.Rand, ctx sdk.Context, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, addr sdk.AccAddress, ) (deposit sdk.Coins, skip bool, err error) { account := ak.GetAccount(ctx, addr) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) if spendable.Empty() { return nil, true, nil // skip diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 7ecd4bd50f6..c6fe5d7fcbb 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -19,6 +19,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/mock" @@ -38,6 +39,7 @@ type testInput struct { mApp *mock.App keeper keep.Keeper router types.Router + bk bank.Keeper sk staking.Keeper addrs []sdk.AccAddress pubKeys []crypto.PubKey @@ -68,21 +70,18 @@ func getMockApp( blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := mApp.ParamsKeeper - - rtr := types.NewRouter(). - AddRoute(types.RouterKey, handler) - - bk := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) - + rtr := types.NewRouter().AddRoute(types.RouterKey, handler) maccPerms := map[string][]string{ types.ModuleName: {supply.Burner}, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking}, } + + pk := mApp.ParamsKeeper + bk := mApp.BankKeeper supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, maccPerms) sk := staking.NewKeeper( - mApp.Cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), + mApp.Cdc, keyStaking, bk, supplyKeeper, pk.Subspace(staking.DefaultParamspace), ) keeper := keep.NewKeeper( @@ -93,24 +92,25 @@ func getMockApp( mApp.QueryRouter().AddRoute(types.QuerierRoute, keep.NewQuerier(keeper)) mApp.SetEndBlocker(getEndBlocker(keeper)) - mApp.SetInitChainer(getInitChainer(mApp, keeper, sk, supplyKeeper, genAccs, genState, + mApp.SetInitChainer(getInitChainer(mApp, bk, keeper, sk, supplyKeeper, genAccs, genState, []supplyexported.ModuleAccountI{govAcc, notBondedPool, bondPool})) require.NoError(t, mApp.CompleteSetup(keyStaking, keyGov, keySupply)) var ( - addrs []sdk.AccAddress - pubKeys []crypto.PubKey - privKeys []crypto.PrivKey + genBalances []bankexported.GenesisBalance + addrs []sdk.AccAddress + pubKeys []crypto.PubKey + privKeys []crypto.PrivKey ) if genAccs == nil || len(genAccs) == 0 { - genAccs, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs, valCoins) + genAccs, genBalances, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs, valCoins) } - mock.SetGenesis(mApp, genAccs) + mock.SetGenesis(mApp, genAccs, genBalances) - return testInput{mApp, keeper, rtr, sk, addrs, pubKeys, privKeys} + return testInput{mApp, keeper, rtr, bk, sk, addrs, pubKeys, privKeys} } // gov and staking endblocker @@ -122,7 +122,7 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker { } // gov and staking initchainer -func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, supplyKeeper supply.Keeper, accs []authexported.Account, genState GenesisState, +func getInitChainer(mapp *mock.App, bk types.BankKeeper, keeper Keeper, stakingKeeper staking.Keeper, supplyKeeper supply.Keeper, accs []authexported.Account, genState GenesisState, blacklistedAddrs []supplyexported.ModuleAccountI) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) @@ -137,11 +137,11 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, supplyKeeper.SetModuleAccount(ctx, macc) } - validators := staking.InitGenesis(ctx, stakingKeeper, mapp.AccountKeeper, supplyKeeper, stakingGenesis) + validators := staking.InitGenesis(ctx, stakingKeeper, mapp.AccountKeeper, bk, supplyKeeper, stakingGenesis) if genState.IsEmpty() { - InitGenesis(ctx, keeper, supplyKeeper, types.DefaultGenesisState()) + InitGenesis(ctx, bk, supplyKeeper, keeper, types.DefaultGenesisState()) } else { - InitGenesis(ctx, keeper, supplyKeeper, genState) + InitGenesis(ctx, bk, supplyKeeper, keeper, genState) } return abci.ResponseInitChain{ Validators: validators, diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index f2b699dadbd..e2b7572016e 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -51,4 +51,5 @@ type BankKeeper interface { GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } diff --git a/x/simulation/account_test.go b/x/simulation/account_test.go index adb28dcf984..b0f6494fac3 100644 --- a/x/simulation/account_test.go +++ b/x/simulation/account_test.go @@ -65,6 +65,8 @@ func TestRandomFees(t *testing.T) { {"0 coins", sdk.NewCoins(sdk.NewInt64Coin("aaa", 10), sdk.NewInt64Coin("bbb", 5)), false, false}, } for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { got, err := simulation.RandomFees(r, sdk.Context{}, tt.spendableCoins) if (err != nil) != tt.wantErr { diff --git a/x/simulation/rand_util_test.go b/x/simulation/rand_util_test.go index 2128de4050a..9d46164e59f 100644 --- a/x/simulation/rand_util_test.go +++ b/x/simulation/rand_util_test.go @@ -46,6 +46,8 @@ func TestRandStringOfLength(t *testing.T) { {"10-size", 1_000_000_000, 1_000_000_000}, } for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { got := simulation.RandStringOfLength(r, tt.n) require.Equal(t, tt.want, len(got)) diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index bcd1ee7ce8a..a2138479f2c 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -14,7 +14,7 @@ import ( ) func TestBeginBlocker(t *testing.T) { - ctx, ck, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) power := int64(100) amt := sdk.TokensFromConsensusPower(power) addr, pk := slashingkeeper.Addrs[2], slashingkeeper.Pks[2] @@ -26,7 +26,7 @@ func TestBeginBlocker(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), ) require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 23dd43e590b..88ae3bb0b75 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -48,21 +49,24 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) { blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking}, } - supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, bankKeeper, maccPerms) - stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) + supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, mapp.BankKeeper, maccPerms) + stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, mapp.BankKeeper, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace)) mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper)) mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) mapp.SetEndBlocker(getEndBlocker(stakingKeeper)) - mapp.SetInitChainer(getInitChainer(mapp, stakingKeeper, mapp.AccountKeeper, supplyKeeper, - []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool})) + mapp.SetInitChainer( + getInitChainer( + mapp, stakingKeeper, mapp.AccountKeeper, mapp.BankKeeper, supplyKeeper, + []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool}, + ), + ) require.NoError(t, mapp.CompleteSetup(keyStaking, keySupply, keySlashing)) @@ -80,8 +84,11 @@ func getEndBlocker(keeper staking.Keeper) sdk.EndBlocker { } // overwrite the mock init chainer -func getInitChainer(mapp *mock.App, keeper staking.Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper, - blacklistedAddrs []supplyexported.ModuleAccountI) sdk.InitChainer { +func getInitChainer( + mapp *mock.App, keeper staking.Keeper, accountKeeper types.AccountKeeper, bk types.BankKeeper, + supplyKeeper types.SupplyKeeper, blacklistedAddrs []supplyexported.ModuleAccountI, +) sdk.InitChainer { + return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { // set module accounts for _, macc := range blacklistedAddrs { @@ -90,7 +97,7 @@ func getInitChainer(mapp *mock.App, keeper staking.Keeper, accountKeeper types.A mapp.InitChainer(ctx, req) stakingGenesis := staking.DefaultGenesisState() - validators := staking.InitGenesis(ctx, keeper, accountKeeper, supplyKeeper, stakingGenesis) + validators := staking.InitGenesis(ctx, keeper, accountKeeper, bk, supplyKeeper, stakingGenesis) return abci.ResponseInitChain{ Validators: validators, } @@ -123,10 +130,15 @@ func TestSlashingMsgs(t *testing.T) { acc1 := &auth.BaseAccount{ Address: addr1, - Coins: sdk.Coins{genCoin}, } accs := []authexported.Account{acc1} - mock.SetGenesis(mapp, accs) + balances := []bankexported.GenesisBalance{ + bank.Balance{ + Address: addr1, + Coins: sdk.Coins{genCoin}, + }, + } + mock.SetGenesis(mapp, accs, balances) description := staking.NewDescription("foo_moniker", "", "", "", "") commission := staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index a137ff8d0d0..b3d181c806e 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -17,7 +17,7 @@ import ( func TestCannotUnjailUnlessJailed(t *testing.T) { // initial setup - ctx, ck, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) slh := NewHandler(keeper) amt := sdk.TokensFromConsensusPower(100) addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] @@ -30,7 +30,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, ) require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) @@ -44,7 +44,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { // initial setup - ctx, ck, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, DefaultParams()) slh := NewHandler(keeper) amtInt := int64(100) addr, val, amt := slashingkeeper.Addrs[0], slashingkeeper.Pks[0], sdk.TokensFromConsensusPower(amtInt) @@ -58,7 +58,7 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))}, ) @@ -153,9 +153,8 @@ func TestInvalidMsg(t *testing.T) { // Test a validator through uptime, downtime, revocation, // unrevocation, starting height reset, and revocation again func TestHandleAbsentValidator(t *testing.T) { - // initial setup - ctx, ck, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashingkeeper.TestParams()) + ctx, bk, sk, _, keeper := slashingkeeper.CreateTestInput(t, slashingkeeper.TestParams()) power := int64(100) amt := sdk.TokensFromConsensusPower(power) addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] @@ -169,7 +168,7 @@ func TestHandleAbsentValidator(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, slashingkeeper.InitTokens.Sub(amt))), ) require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) @@ -206,8 +205,9 @@ func TestHandleAbsentValidator(t *testing.T) { // validator should be bonded still validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Bonded, validator.GetStatus()) + bondPool := sk.GetBondedPool(ctx) - require.True(sdk.IntEq(t, amt, bondPool.GetCoins().AmountOf(sk.BondDenom(ctx)))) + require.True(sdk.IntEq(t, amt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount)) // 501st block missed ctx = ctx.WithBlockHeight(height) @@ -265,8 +265,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, sdk.Bonded, validator.GetStatus()) // validator should have been slashed - bondPool = sk.GetBondedPool(ctx) - require.Equal(t, amt.Int64()-slashAmt, bondPool.GetCoins().AmountOf(sk.BondDenom(ctx)).Int64()) + require.Equal(t, amt.Int64()-slashAmt, bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) // Validator start height should not have been changed info, found = keeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) diff --git a/x/slashing/internal/keeper/keeper_test.go b/x/slashing/internal/keeper/keeper_test.go index 52eb6b59b77..fdf50a261e2 100644 --- a/x/slashing/internal/keeper/keeper_test.go +++ b/x/slashing/internal/keeper/keeper_test.go @@ -16,7 +16,7 @@ import ( // and that they are not immediately jailed func TestHandleNewValidator(t *testing.T) { // initial setup - ctx, ck, sk, _, keeper := CreateTestInput(t, TestParams()) + ctx, bk, sk, _, keeper := CreateTestInput(t, TestParams()) addr, val := Addrs[0], Pks[0] amt := sdk.TokensFromConsensusPower(100) sh := staking.NewHandler(sk) @@ -32,7 +32,7 @@ func TestHandleNewValidator(t *testing.T) { staking.EndBlocker(ctx, sk) require.Equal( - t, ck.GetCoins(ctx, sdk.AccAddress(addr)), + t, bk.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), ) require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) @@ -54,7 +54,7 @@ func TestHandleNewValidator(t *testing.T) { require.Equal(t, sdk.Bonded, validator.GetStatus()) bondPool := sk.GetBondedPool(ctx) expTokens := sdk.TokensFromConsensusPower(100) - require.Equal(t, expTokens.Int64(), bondPool.GetCoins().AmountOf(sk.BondDenom(ctx)).Int64()) + require.Equal(t, expTokens.Int64(), bk.GetBalance(ctx, bondPool.GetAddress(), sk.BondDenom(ctx)).Amount.Int64()) } // Test a jailed validator being "down" twice diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/internal/keeper/test_common.go index eb8870c1d19..79a436b2e1d 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/internal/keeper/test_common.go @@ -57,6 +57,7 @@ func createTestCodec() *codec.Codec { func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Keeper, staking.Keeper, params.Subspace, Keeper) { keyAcc := sdk.NewKVStoreKey(auth.StoreKey) + keyBank := sdk.NewKVStoreKey(bank.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) keySlashing := sdk.NewKVStoreKey(types.StoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) @@ -67,6 +68,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) @@ -91,7 +93,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bk := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) + bk := bank.NewBaseKeeper(cdc, keyBank, accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, @@ -102,7 +104,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) + sk := staking.NewKeeper(cdc, keyStaking, bk, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) genesis := staking.DefaultGenesisState() // set module accounts @@ -110,12 +112,14 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee supplyKeeper.SetModuleAccount(ctx, bondPool) supplyKeeper.SetModuleAccount(ctx, notBondedPool) - _ = staking.InitGenesis(ctx, sk, accountKeeper, supplyKeeper, genesis) + _ = staking.InitGenesis(ctx, sk, accountKeeper, bk, supplyKeeper, genesis) - for _, addr := range Addrs { - _, err = bk.AddCoins(ctx, sdk.AccAddress(addr), initCoins) + for i, addr := range Addrs { + addr := sdk.AccAddress(addr) + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, Pks[i], uint64(i), 0)) + require.NoError(t, bk.SetBalances(ctx, addr, initCoins)) } - require.Nil(t, err) + paramstore := paramsKeeper.Subspace(types.DefaultParamspace) keeper := NewKeeper(cdc, keySlashing, &sk, paramstore) diff --git a/x/slashing/internal/types/expected_keepers.go b/x/slashing/internal/types/expected_keepers.go index e59c7d2877c..bf09731a03e 100644 --- a/x/slashing/internal/types/expected_keepers.go +++ b/x/slashing/internal/types/expected_keepers.go @@ -21,6 +21,7 @@ type BankKeeper interface { GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } // ParamSubspace defines the expected Subspace interfacace diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index ccd06ef5625..c7e1b0bfb6c 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -42,7 +42,7 @@ func WeightedOperations( } // SimulateMsgUnjail generates a MsgUnjail with random values -// nolint: funlen +// nolint: funlen interfacer func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, @@ -76,9 +76,7 @@ func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Kee } account := ak.GetAccount(ctx, sdk.AccAddress(validator.GetOperator())) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { diff --git a/x/staking/app_test.go b/x/staking/app_test.go index a5692311338..586b5d95d75 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" + bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/cosmos-sdk/x/supply" @@ -35,19 +36,22 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) { blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - bankKeeper := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.NotBondedPoolName: {supply.Burner, supply.Staking}, types.BondedPoolName: {supply.Burner, supply.Staking}, } - supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bankKeeper, maccPerms) - keeper := NewKeeper(mApp.Cdc, keyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) + supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, mApp.BankKeeper, maccPerms) + keeper := NewKeeper(mApp.Cdc, keyStaking, mApp.BankKeeper, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) mApp.Router().AddRoute(RouterKey, NewHandler(keeper)) mApp.SetEndBlocker(getEndBlocker(keeper)) - mApp.SetInitChainer(getInitChainer(mApp, keeper, mApp.AccountKeeper, supplyKeeper, - []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool})) + mApp.SetInitChainer( + getInitChainer( + mApp, keeper, mApp.AccountKeeper, mApp.BankKeeper, supplyKeeper, + []supplyexported.ModuleAccountI{feeCollector, notBondedPool, bondPool}, + ), + ) require.NoError(t, mApp.CompleteSetup(keyStaking, keySupply)) return mApp, keeper @@ -66,18 +70,22 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker { // getInitChainer initializes the chainer of the mock app and sets the genesis // state. It returns an empty ResponseInitChain. -func getInitChainer(mapp *mock.App, keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper, - blacklistedAddrs []supplyexported.ModuleAccountI) sdk.InitChainer { +func getInitChainer( + mapp *mock.App, keeper Keeper, ak types.AccountKeeper, bk types.BankKeeper, + sk types.SupplyKeeper, blacklistedAddrs []supplyexported.ModuleAccountI, +) sdk.InitChainer { + return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) // set module accounts for _, macc := range blacklistedAddrs { - supplyKeeper.SetModuleAccount(ctx, macc) + sk.SetModuleAccount(ctx, macc) } stakingGenesis := DefaultGenesisState() - validators := InitGenesis(ctx, keeper, accountKeeper, supplyKeeper, stakingGenesis) + validators := InitGenesis(ctx, keeper, ak, bk, sk, stakingGenesis) + return abci.ResponseInitChain{ Validators: validators, } @@ -121,17 +129,21 @@ func TestStakingMsgs(t *testing.T) { genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens) bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, bondTokens) - acc1 := &auth.BaseAccount{ - Address: addr1, - Coins: sdk.Coins{genCoin}, - } - acc2 := &auth.BaseAccount{ - Address: addr2, - Coins: sdk.Coins{genCoin}, - } + acc1 := &auth.BaseAccount{Address: addr1} + acc2 := &auth.BaseAccount{Address: addr2} accs := []authexported.Account{acc1, acc2} + balances := []bankexported.GenesisBalance{ + bank.Balance{ + Address: addr1, + Coins: sdk.Coins{genCoin}, + }, + bank.Balance{ + Address: addr2, + Coins: sdk.Coins{genCoin}, + }, + } - mock.SetGenesis(mApp, accs) + mock.SetGenesis(mApp, accs, balances) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin}) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index 4a56b3ac9c9..4f3a7f1d05b 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -17,7 +17,7 @@ import ( ) func TestInitGenesis(t *testing.T) { - ctx, accKeeper, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) + ctx, accKeeper, bk, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) valTokens := sdk.TokensFromConsensusPower(1) @@ -40,7 +40,7 @@ func TestInitGenesis(t *testing.T) { validators[1].DelegatorShares = valTokens.ToDec() genesisState := types.NewGenesisState(params, validators, delegations) - vals := InitGenesis(ctx, keeper, accKeeper, supplyKeeper, genesisState) + vals := InitGenesis(ctx, keeper, accKeeper, bk, supplyKeeper, genesisState) actualGenesis := ExportGenesis(ctx, keeper) require.Equal(t, genesisState.Params, actualGenesis.Params) @@ -68,7 +68,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { size := 200 require.True(t, size > 100) - ctx, accKeeper, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) + ctx, accKeeper, bk, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) delegations := []Delegation{} @@ -89,7 +89,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { } genesisState := types.NewGenesisState(params, validators, delegations) - vals := InitGenesis(ctx, keeper, accKeeper, supplyKeeper, genesisState) + vals := InitGenesis(ctx, keeper, accKeeper, bk, supplyKeeper, genesisState) abcivals := make([]abci.ValidatorUpdate, 100) for i, val := range validators[:100] { diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 92147eabb09..75e9242e07c 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -22,7 +22,7 @@ func TestValidatorByPowerIndex(t *testing.T) { initPower := int64(1000000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -104,7 +104,7 @@ func TestValidatorByPowerIndex(t *testing.T) { } func TestDuplicatesMsgCreateValidator(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) addr1, addr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) pk1, pk2 := keep.PKs[0], keep.PKs[1] @@ -160,7 +160,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { } func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) addr := sdk.ValAddress(keep.Addrs[0]) invalidPk := secp256k1.GenPrivKey().PubKey() @@ -181,7 +181,7 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { } func TestLegacyValidatorDelegations(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, int64(1000)) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, int64(1000)) bondAmount := sdk.TokensFromConsensusPower(10) valAddr := sdk.ValAddress(keep.Addrs[0]) @@ -279,7 +279,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { func TestIncrementsMsgDelegate(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) params := keeper.GetParams(ctx) bondAmount := sdk.TokensFromConsensusPower(10) @@ -332,7 +332,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { gotBond := bond.Shares.RoundInt() gotDelegatorShares := validator.DelegatorShares.RoundInt() - gotDelegatorAcc := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(params.BondDenom) + gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount require.Equal(t, expBond, gotBond, "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", @@ -351,7 +351,7 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) - ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -384,7 +384,7 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { initPower := int64(100) initBond := sdk.TokensFromConsensusPower(100) - ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, initPower) // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) @@ -415,7 +415,7 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { func TestIncrementsMsgUnbond(t *testing.T) { initPower := int64(1000) initBond := sdk.TokensFromConsensusPower(initPower) - ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) params := keeper.GetParams(ctx) denom := params.BondDenom @@ -429,7 +429,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.NotNil(t, res) // initial balance - amt1 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) + amt1 := bk.GetBalance(ctx, delegatorAddr, denom).Amount msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) res, err = handleMsgDelegate(ctx, msgDelegate, keeper) @@ -437,7 +437,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.NotNil(t, res) // balance should have been subtracted after delegation - amt2 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) + amt2 := bk.GetBalance(ctx, delegatorAddr, denom).Amount require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2)) // apply TM updates @@ -477,7 +477,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { gotBond := bond.Shares.RoundInt() gotDelegatorShares := validator.DelegatorShares.RoundInt() - gotDelegatorAcc := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(params.BondDenom) + gotDelegatorAcc := bk.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount require.Equal(t, expBond.Int64(), gotBond.Int64(), "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", @@ -520,7 +520,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { func TestMultipleMsgCreateValidator(t *testing.T) { initPower := int64(1000) initTokens := sdk.TokensFromConsensusPower(initPower) - ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower) + ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, initPower) params := keeper.GetParams(ctx) blockTime := time.Now().UTC() @@ -552,7 +552,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { val := validators[i] balanceExpd := initTokens.Sub(valTokens) - balanceGot := accMapper.GetAccount(ctx, delegatorAddrs[i]).GetCoins().AmountOf(params.BondDenom) + balanceGot := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) require.Equal(t, valTokens, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", 10, val.DelegatorShares) @@ -589,13 +589,13 @@ func TestMultipleMsgCreateValidator(t *testing.T) { _, found = keeper.GetValidator(ctx, validatorAddr) require.False(t, found) - gotBalance := accMapper.GetAccount(ctx, delegatorAddrs[i]).GetCoins().AmountOf(params.BondDenom) + gotBalance := bk.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance) } } func TestMultipleMsgDelegate(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:] // first make a validator @@ -639,7 +639,7 @@ func TestMultipleMsgDelegate(t *testing.T) { } func TestJailValidator(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // create the validator @@ -689,7 +689,7 @@ func TestJailValidator(t *testing.T) { } func TestValidatorQueue(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // set the unbonding time @@ -750,7 +750,7 @@ func TestValidatorQueue(t *testing.T) { } func TestUnbondingPeriod(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -798,7 +798,7 @@ func TestUnbondingPeriod(t *testing.T) { } func TestUnbondingFromUnbondingValidator(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // create the validator @@ -843,7 +843,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { } func TestRedelegationPeriod(t *testing.T) { - ctx, AccMapper, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, bk, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) denom := keeper.GetParams(ctx).BondDenom @@ -856,14 +856,14 @@ func TestRedelegationPeriod(t *testing.T) { msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) // initial balance - amt1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) + amt1 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.NoError(t, err) require.NotNil(t, res) // balance should have been subtracted after creation - amt2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) + amt2 := bk.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) @@ -871,7 +871,7 @@ func TestRedelegationPeriod(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - bal1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() + bal1 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) @@ -881,7 +881,7 @@ func TestRedelegationPeriod(t *testing.T) { require.NotNil(t, res) // origin account should not lose tokens as with a regular delegation - bal2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() + bal2 := bk.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) require.Equal(t, bal1, bal2) origHeader := ctx.BlockHeader() @@ -905,7 +905,7 @@ func TestRedelegationPeriod(t *testing.T) { } func TestTransitiveRedelegation(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr := sdk.ValAddress(keep.Addrs[0]) validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) @@ -955,7 +955,7 @@ func TestTransitiveRedelegation(t *testing.T) { } func TestMultipleRedelegationAtSameTime(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valAddr := sdk.ValAddress(keep.Addrs[0]) valAddr2 := sdk.ValAddress(keep.Addrs[1]) @@ -1011,7 +1011,7 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { } func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valAddr := sdk.ValAddress(keep.Addrs[0]) valAddr2 := sdk.ValAddress(keep.Addrs[1]) @@ -1069,7 +1069,7 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { } func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -1119,7 +1119,7 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { } func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time @@ -1176,7 +1176,7 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { } func TestUnbondingWhenExcessValidators(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) validatorAddr1 := sdk.ValAddress(keep.Addrs[0]) validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) @@ -1238,7 +1238,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { } func TestBondUnbondRedelegateSlashTwice(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) @@ -1353,7 +1353,7 @@ func TestInvalidMsg(t *testing.T) { } func TestInvalidCoinDenom(t *testing.T) { - ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := keep.CreateTestInput(t, false, 1000) valA, valB, delAddr := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] valTokens := sdk.TokensFromConsensusPower(100) diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index e3e61969767..f2832dd498d 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -13,7 +13,7 @@ import ( // tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations func TestDelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 10) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) //construct the validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} @@ -128,7 +128,7 @@ func TestDelegation(t *testing.T) { // tests Get/Set/Remove UnbondingDelegation func TestUnbondingDelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, time.Unix(0, 0), sdk.NewInt(5)) @@ -167,13 +167,12 @@ func TestUnbondingDelegation(t *testing.T) { } func TestUnbondDelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(10) - notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens))) - require.NoError(t, err) + + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) // create a validator and a delegator to that validator @@ -204,12 +203,13 @@ func TestUnbondDelegation(t *testing.T) { } func TestUnbondingDelegationsMaxEntries(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) startTokens := sdk.TokensFromConsensusPower(10) - bondDenom := keeper.BondDenom(ctx) + bondDenom := keeper.BondDenom(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) + + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -228,8 +228,8 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { maxEntries := keeper.MaxEntries(ctx) - oldBonded := keeper.GetBondedPool(ctx).GetCoins().AmountOf(bondDenom) - oldNotBonded := keeper.GetNotBondedPool(ctx).GetCoins().AmountOf(bondDenom) + oldBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + oldNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // should all pass var completionTime time.Time @@ -239,51 +239,50 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { require.NoError(t, err) } - bondedPool := keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded.SubRaw(int64(maxEntries)))) - require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.AddRaw(int64(maxEntries)))) + newBonded := bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded := bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(int64(maxEntries)))) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(int64(maxEntries)))) - oldBonded = bondedPool.GetCoins().AmountOf(bondDenom) - oldNotBonded = notBondedPool.GetCoins().AmountOf(bondDenom) + oldBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // an additional unbond should fail due to max entries _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) require.Error(t, err) - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded)) - require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded)) + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + + require.True(sdk.IntEq(t, newBonded, oldBonded)) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded)) // mature unbonding delegations ctx = ctx.WithBlockTime(completionTime) err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0]) require.NoError(t, err) - bondedPool = keeper.GetBondedPool(ctx) - notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded)) - require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.SubRaw(int64(maxEntries)))) + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded)) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.SubRaw(int64(maxEntries)))) - oldNotBonded = notBondedPool.GetCoins().AmountOf(bondDenom) + oldNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // unbonding should work again _, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) require.NoError(t, err) - bondedPool = keeper.GetBondedPool(ctx) - - notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded.SubRaw(1))) - require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.AddRaw(1))) + newBonded = bk.GetBalance(ctx, keeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount + newNotBonded = bk.GetBalance(ctx, keeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, newBonded, oldBonded.SubRaw(1))) + require.True(sdk.IntEq(t, newNotBonded, oldNotBonded.AddRaw(1))) } // test undelegating self delegation from a validator pushing it below MinSelfDelegation // shift it from the bonded to unbonding state and jailed func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { - - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) @@ -296,7 +295,8 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -308,7 +308,8 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -319,8 +320,8 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { require.Equal(t, delTokens, issuedShares.RoundInt()) // add bonded tokens to pool for delegations - bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -344,7 +345,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { } func TestUndelegateFromUnbondingValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) @@ -356,7 +357,8 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -367,7 +369,8 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -377,8 +380,8 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { validator, issuedShares = validator.AddTokensFromDel(delTokens) require.Equal(t, delTokens, issuedShares.RoundInt()) - bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -386,8 +389,8 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) keeper.SetDelegation(ctx, delegation) - bondedPool = keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -432,13 +435,14 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { } func TestUndelegateFromUnbondedValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1) delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -456,7 +460,8 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -511,13 +516,14 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { } func TestUnbondingAllDelegationFromValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) delTokens := sdk.TokensFromConsensusPower(10) delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -541,7 +547,8 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { require.Equal(t, delTokens, issuedShares.RoundInt()) bondedPool := keeper.GetBondedPool(ctx) - err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins...)) + oldBonded := bk.GetAllBalances(ctx, bondedPool.GetAddress()) + err = bk.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -582,7 +589,7 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { // Make sure that that the retrieving the delegations doesn't affect the state func TestGetRedelegationsFromSrcValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, time.Unix(0, 0), sdk.NewInt(5), @@ -606,7 +613,7 @@ func TestGetRedelegationsFromSrcValidator(t *testing.T) { // tests Get/Set/Remove/Has UnbondingDelegation func TestRedelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, time.Unix(0, 0), sdk.NewInt(5), @@ -666,13 +673,14 @@ func TestRedelegation(t *testing.T) { } func TestRedelegateToSameValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) valTokens := sdk.TokensFromConsensusPower(10) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -689,17 +697,17 @@ func TestRedelegateToSameValidator(t *testing.T) { _, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) require.Error(t, err) - } func TestRedelegationMaxEntries(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(20) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -746,13 +754,14 @@ func TestRedelegationMaxEntries(t *testing.T) { } func TestRedelegateSelfDelegation(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -798,13 +807,14 @@ func TestRedelegateSelfDelegation(t *testing.T) { } func TestRedelegateFromUnbondingValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -877,13 +887,14 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { } func TestRedelegateFromUnbondedValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) startTokens := sdk.TokensFromConsensusPower(30) startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := keeper.GetNotBondedPool(ctx) - err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins...)) + oldNotBonded := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + err := bk.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 204dd3ac512..574d0c9dd9a 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -13,7 +13,7 @@ import ( ) func TestHistoricalInfo(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 10) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) validators := make([]types.Validator, len(addrVals)) for i, valAddr := range addrVals { @@ -37,7 +37,7 @@ func TestHistoricalInfo(t *testing.T) { } func TestTrackHistoricalInfo(t *testing.T) { - ctx, _, k, _ := CreateTestInput(t, false, 10) + ctx, _, _, k, _ := CreateTestInput(t, false, 10) // set historical entries in params to 5 params := types.DefaultParams() diff --git a/x/staking/keeper/keeper_test.go b/x/staking/keeper/keeper_test.go index eb9d16459e4..dbde12e7b1a 100644 --- a/x/staking/keeper/keeper_test.go +++ b/x/staking/keeper/keeper_test.go @@ -9,7 +9,7 @@ import ( ) func TestParams(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 0) expParams := types.DefaultParams() //check that the empty keeper loads the default diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 320266ca1a2..2bbd468ae07 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -20,7 +20,7 @@ var ( func TestNewQuerier(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8)} var validators [2]types.Validator @@ -107,7 +107,7 @@ func TestNewQuerier(t *testing.T) { func TestQueryParametersPool(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) bondDenom := sdk.DefaultBondDenom res, err := queryParameters(ctx, keeper) @@ -124,15 +124,14 @@ func TestQueryParametersPool(t *testing.T) { var pool types.Pool bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - errRes = cdc.UnmarshalJSON(res, &pool) - require.NoError(t, errRes) - require.Equal(t, bondedPool.GetCoins().AmountOf(bondDenom), pool.BondedTokens) - require.Equal(t, notBondedPool.GetCoins().AmountOf(bondDenom), pool.NotBondedTokens) + require.NoError(t, cdc.UnmarshalJSON(res, &pool)) + require.Equal(t, keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount, pool.NotBondedTokens) + require.Equal(t, keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount, pool.BondedTokens) } func TestQueryValidators(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) params := keeper.GetParams(ctx) // Create Validators @@ -195,7 +194,7 @@ func TestQueryValidators(t *testing.T) { func TestQueryDelegation(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) params := keeper.GetParams(ctx) // Create Validators and Delegation @@ -415,7 +414,7 @@ func TestQueryDelegation(t *testing.T) { func TestQueryRedelegations(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) // Create Validators and Delegation val1 := types.NewValidator(addrVal1, pk1, types.Description{}) @@ -480,7 +479,7 @@ func TestQueryRedelegations(t *testing.T) { func TestQueryUnbondingDelegation(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) // Create Validators and Delegation val1 := types.NewValidator(addrVal1, pk1, types.Description{}) @@ -571,7 +570,7 @@ func TestQueryUnbondingDelegation(t *testing.T) { func TestQueryHistoricalInfo(t *testing.T) { cdc := codec.New() - ctx, _, keeper, _ := CreateTestInput(t, false, 10000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10000) // Create Validators and Delegation val1 := types.NewValidator(addrVal1, pk1, types.Description{}) diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index cc4d4651731..2127cf51e19 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -15,17 +15,15 @@ import ( // TODO integrate with test_common.go helper (CreateTestInput) // setup helper function - creates two validators func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) { - // setup - ctx, _, keeper, _ := CreateTestInput(t, false, power) + ctx, _, _, keeper, _ := CreateTestInput(t, false, power) params := keeper.GetParams(ctx) numVals := int64(3) amt := sdk.TokensFromConsensusPower(power) bondedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), amt.MulRaw(numVals))) bondedPool := keeper.GetBondedPool(ctx) - err := bondedPool.SetCoins(bondedCoins) - require.NoError(t, err) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins)) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) // add numVals validators @@ -43,7 +41,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) // tests Jail, Unjail func TestRevocation(t *testing.T) { - // setup ctx, keeper, _ := setupHelper(t, 10) addr := addrVals[0] @@ -90,7 +87,8 @@ func TestSlashUnbondingDelegation(t *testing.T) { require.Equal(t, int64(0), slashAmount.Int64()) // test valid slash, before expiration timestamp and to which stake contributed - oldUnbondedPool := keeper.GetNotBondedPool(ctx) + notBondedPool := keeper.GetNotBondedPool(ctx) + oldUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) keeper.SetUnbondingDelegation(ctx, ubd) slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) @@ -104,9 +102,9 @@ func TestSlashUnbondingDelegation(t *testing.T) { // balance decreased require.Equal(t, sdk.NewInt(5), ubd.Entries[0].Balance) - newUnbondedPool := keeper.GetNotBondedPool(ctx) - diffTokens := oldUnbondedPool.GetCoins().Sub(newUnbondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, int64(5), diffTokens.Int64()) + newUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) + require.Equal(t, int64(5), diffTokens.AmountOf(keeper.BondDenom(ctx)).Int64()) } // tests slashRedelegation @@ -117,8 +115,9 @@ func TestSlashRedelegation(t *testing.T) { // add bonded tokens to pool for (re)delegations startCoins := sdk.NewCoins(sdk.NewInt64Coin(keeper.BondDenom(ctx), 15)) bondedPool := keeper.GetBondedPool(ctx) - err := bondedPool.SetCoins(bondedPool.GetCoins().Add(startCoins...)) - require.NoError(t, err) + balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(startCoins...))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) // set a redelegation with an expiration timestamp beyond which the @@ -146,6 +145,8 @@ func TestSlashRedelegation(t *testing.T) { slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) require.Equal(t, int64(0), slashAmount.Int64()) + balances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + // test valid slash, before expiration timestamp and to which stake contributed ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) keeper.SetRedelegation(ctx, rd) @@ -171,8 +172,7 @@ func TestSlashRedelegation(t *testing.T) { // pool bonded tokens should decrease burnedCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), slashAmount)) - newBondedPool := keeper.GetBondedPool(ctx) - require.Equal(t, bondedPool.GetCoins().Sub(burnedCoins), newBondedPool.GetCoins()) + require.Equal(t, balances.Sub(burnedCoins), keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress())) } // tests Slash at a future height (must panic) @@ -190,7 +190,9 @@ func TestSlashAtNegativeHeight(t *testing.T) { consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) - oldBondedPool := keeper.GetBondedPool(ctx) + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) keeper.Slash(ctx, consAddr, -2, 10, fraction) @@ -198,7 +200,6 @@ func TestSlashAtNegativeHeight(t *testing.T) { // read updated state validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - newBondedPool := keeper.GetBondedPool(ctx) // end block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -207,9 +208,11 @@ func TestSlashAtNegativeHeight(t *testing.T) { validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) // power decreased require.Equal(t, int64(5), validator.GetConsensusPower()) + // pool bonded shares decreased - diffTokens := oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5), diffTokens) + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) } // tests Slash at the current height @@ -218,7 +221,9 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) - oldBondedPool := keeper.GetBondedPool(ctx) + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) keeper.Slash(ctx, consAddr, ctx.BlockHeight(), 10, fraction) @@ -226,7 +231,6 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { // read updated state validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - newBondedPool := keeper.GetBondedPool(ctx) // end block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -235,9 +239,11 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { validator = keeper.mustGetValidator(ctx, validator.OperatorAddress) // power decreased require.Equal(t, int64(5), validator.GetConsensusPower()) + // pool bonded shares decreased - diffTokens := oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5), diffTokens) + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) + require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) } // tests Slash at a previous height with an unbonding delegation @@ -255,7 +261,9 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // slash validator for the first time ctx = ctx.WithBlockHeight(12) - oldBondedPool := keeper.GetBondedPool(ctx) + bondedPool := keeper.GetBondedPool(ctx) + oldBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) keeper.Slash(ctx, consAddr, 10, 10, fraction) @@ -268,16 +276,19 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.Len(t, ubd.Entries, 1) + // balance decreased require.Equal(t, sdk.TokensFromConsensusPower(2), ubd.Entries[0].Balance) - // read updated pool - newBondedPool := keeper.GetBondedPool(ctx) + // bonded tokens burned - diffTokens := oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) + newBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(3), diffTokens) + // read updated validator validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) + // power decreased by 3 - 6 stake originally bonded at the time of infraction // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction @@ -287,19 +298,23 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // slash validator again ctx = ctx.WithBlockHeight(13) keeper.Slash(ctx, consAddr, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.Len(t, ubd.Entries, 1) + // balance decreased again require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - // read updated pool - newBondedPool = keeper.GetBondedPool(ctx) + // bonded tokens burned again - diffTokens = oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(6), diffTokens) + // read updated validator validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) + // power decreased by 3 again require.Equal(t, int64(4), validator.GetConsensusPower()) @@ -309,19 +324,23 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 ctx = ctx.WithBlockHeight(13) keeper.Slash(ctx, consAddr, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.Len(t, ubd.Entries, 1) + // balance unchanged require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - // read updated pool - newBondedPool = keeper.GetBondedPool(ctx) + // bonded tokens burned again - diffTokens = oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(9), diffTokens) + // read updated validator validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) + // power decreased by 3 again require.Equal(t, int64(1), validator.GetConsensusPower()) @@ -331,18 +350,22 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 ctx = ctx.WithBlockHeight(13) keeper.Slash(ctx, consAddr, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.Len(t, ubd.Entries, 1) + // balance unchanged require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance) - // read updated pool - newBondedPool = keeper.GetBondedPool(ctx) + // just 1 bonded token burned again since that's all the validator now has - diffTokens = oldBondedPool.GetCoins().Sub(newBondedPool.GetCoins()).AmountOf(keeper.BondDenom(ctx)) + newBondedPoolBalances = keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(keeper.BondDenom(ctx)) require.Equal(t, sdk.TokensFromConsensusPower(10), diffTokens) + // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) + // read updated validator // power decreased by 1 again, validator is out of stake // validator should be in unbonding period @@ -371,12 +394,15 @@ func TestSlashWithRedelegation(t *testing.T) { bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) rdCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdTokens.MulRaw(2))) - err := bondedPool.SetCoins(bondedPool.GetCoins().Add(rdCoins...)) + + balances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + err := keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(rdCoins...)) require.NoError(t, err) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) - oldBonded := bondedPool.GetCoins().AmountOf(bondDenom) - oldNotBonded := notBondedPool.GetCoins().AmountOf(bondDenom) + oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount // slash validator ctx = ctx.WithBlockHeight(12) @@ -388,10 +414,14 @@ func TestSlashWithRedelegation(t *testing.T) { bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) + // burn bonded tokens from only from delegations - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPool.GetCoins().AmountOf(bondDenom))) - oldBonded = bondedPool.GetCoins().AmountOf(bondDenom) + bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + + notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -416,10 +446,18 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) + // seven bonded tokens burned - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPool.GetCoins().AmountOf(bondDenom))) - oldBonded = bondedPool.GetCoins().AmountOf(bondDenom) + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -444,9 +482,12 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPool.GetCoins().AmountOf(bondDenom))) - oldBonded = bondedPool.GetCoins().AmountOf(bondDenom) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnAmount), bondedPoolBalance)) + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) + oldBonded = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -471,8 +512,11 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, oldBonded, bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded, notBondedPool.GetCoins().AmountOf(bondDenom))) + + bondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded, bondedPoolBalance)) + notBondedPoolBalance = keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded, notBondedPoolBalance)) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -515,14 +559,18 @@ func TestSlashBoth(t *testing.T) { // update bonded tokens bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - require.NoError(t, bondedPool.SetCoins(bondedPool.GetCoins().Add(bondedCoins...))) - require.NoError(t, bondedPool.SetCoins(notBondedPool.GetCoins().Add(notBondedCoins...))) + + bondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedPoolBalances.Add(bondedCoins...))) + + notBondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, keeper.bankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedPoolBalances.Add(notBondedCoins...))) + keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) - oldBonded := bondedPool.GetCoins().AmountOf(bondDenom) - oldNotBonded := notBondedPool.GetCoins().AmountOf(bondDenom) - + oldBonded := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + oldNotBonded := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount // slash validator ctx = ctx.WithBlockHeight(12) validator, found := keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) @@ -537,8 +585,12 @@ func TestSlashBoth(t *testing.T) { // read updated pool bondedPool = keeper.GetBondedPool(ctx) notBondedPool = keeper.GetNotBondedPool(ctx) - require.True(sdk.IntEq(t, oldBonded.Sub(burnedBondAmount), bondedPool.GetCoins().AmountOf(bondDenom))) - require.True(sdk.IntEq(t, oldNotBonded.Sub(burnedNotBondedAmount), notBondedPool.GetCoins().AmountOf(bondDenom))) + + bondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldBonded.Sub(burnedBondAmount), bondedPoolBalance)) + + notBondedPoolBalance := keeper.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount + require.True(sdk.IntEq(t, oldNotBonded.Sub(burnedNotBondedAmount), notBondedPoolBalance)) // read updating redelegation rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 0d730b48b3c..65efabe4e25 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -79,9 +79,10 @@ func MakeTestCodec() *codec.Codec { // Hogpodge of all sorts of input required for testing. // `initPower` is converted to an amount of tokens. // If `initPower` is 0, no addrs get created. -func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, Keeper, types.SupplyKeeper) { +func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, types.BankKeeper, Keeper, types.SupplyKeeper) { keyStaking := sdk.NewKVStoreKey(types.StoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) + bankKey := sdk.NewKVStoreKey(bank.StoreKey) keyParams := sdk.NewKVStoreKey(params.StoreKey) tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) @@ -90,6 +91,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(bankKey, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) @@ -125,6 +127,8 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ) bk := bank.NewBaseKeeper( + cdc, + bankKey, accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs, @@ -143,26 +147,23 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - keeper := NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(DefaultParamspace)) + keeper := NewKeeper(cdc, keyStaking, bk, supplyKeeper, pk.Subspace(DefaultParamspace)) keeper.SetParams(ctx, types.DefaultParams()) // set module accounts - err = notBondedPool.SetCoins(totalSupply) - require.NoError(t, err) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply)) supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc) supplyKeeper.SetModuleAccount(ctx, bondPool) supplyKeeper.SetModuleAccount(ctx, notBondedPool) // fill all the addresses with some coins, set the loose pool tokens simultaneously - for _, addr := range Addrs { - _, err := bk.AddCoins(ctx, addr, initCoins) - if err != nil { - panic(err) - } + for i, addr := range Addrs { + accountKeeper.SetAccount(ctx, auth.NewBaseAccount(addr, PKs[i], uint64(i), 0)) + require.NoError(t, bk.SetBalances(ctx, addr, initCoins)) } - return ctx, accountKeeper, keeper, supplyKeeper + return ctx, accountKeeper, bk, keeper, supplyKeeper } func NewPubKey(pk string) (res crypto.PubKey) { diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index c01fabbca2d..ae2552fe837 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -17,7 +17,7 @@ import ( //_______________________________________________________ func TestSetValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 10) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 10) valPubKey := PKs[0] valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) @@ -70,12 +70,12 @@ func TestSetValidator(t *testing.T) { } func TestUpdateValidatorByPowerIndex(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - bondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -111,7 +111,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { maxVals := 5 // create context, keeper, and pool for tests - ctx, _, keeper, _ := CreateTestInput(t, false, 0) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 0) bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) @@ -121,8 +121,8 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { keeper.SetParams(ctx, params) // create a random pool - bondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) @@ -165,14 +165,14 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { func TestSlashToZeroPowerRemoved(t *testing.T) { // initialize setup - ctx, _, keeper, _ := CreateTestInput(t, false, 100) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 100) // add a validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) valTokens := sdk.TokensFromConsensusPower(100) bondedPool := keeper.GetBondedPool(ctx) - err := bondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens))) + err := bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens))) require.NoError(t, err) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -195,7 +195,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { // This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator func TestValidatorBasics(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) //construct the validators var validators [3]types.Validator @@ -294,7 +294,7 @@ func TestValidatorBasics(t *testing.T) { // test how the validators are sorted, tests GetBondedValidatorsByPower func TestGetValidatorSortingUnmixed(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // initialize some validators into the state amts := []int64{ @@ -374,11 +374,12 @@ func TestGetValidatorSortingUnmixed(t *testing.T) { } func TestGetValidatorSortingMixed(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) bondedPool := keeper.GetBondedPool(ctx) notBondedPool := keeper.GetNotBondedPool(ctx) - bondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) - notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) + + bk.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) + bk.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) @@ -432,7 +433,7 @@ func TestGetValidatorSortingMixed(t *testing.T) { // TODO separate out into multiple tests func TestGetValidatorsEdgeCases(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, bk, keeper, _ := CreateTestInput(t, false, 1000) // set max validators to 2 params := keeper.GetParams(ctx) @@ -446,10 +447,14 @@ func TestGetValidatorsEdgeCases(t *testing.T) { for i, power := range powers { moniker := fmt.Sprintf("val#%d", int64(i)) validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) + tokens := sdk.TokensFromConsensusPower(power) validators[i], _ = validators[i].AddTokensFromDel(tokens) + notBondedPool := keeper.GetNotBondedPool(ctx) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, tokens)))) + balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, tokens)))) + keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[i] = TestingUpdateValidator(keeper, ctx, validators[i], true) } @@ -465,8 +470,10 @@ func TestGetValidatorsEdgeCases(t *testing.T) { delTokens := sdk.TokensFromConsensusPower(500) validators[0], _ = validators[0].AddTokensFromDel(delTokens) notBondedPool := keeper.GetNotBondedPool(ctx) + newTokens := sdk.NewCoins() - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(newTokens...))) + balances := bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) // test that the two largest validators are @@ -496,7 +503,8 @@ func TestGetValidatorsEdgeCases(t *testing.T) { notBondedPool = keeper.GetNotBondedPool(ctx) newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.TokensFromConsensusPower(1))) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(newTokens...))) + balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) @@ -511,7 +519,8 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], _ = validators[3].RemoveDelShares(sdk.NewDec(201)) bondedPool := keeper.GetBondedPool(ctx) - require.NoError(t, bondedPool.SetCoins(bondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, rmTokens)))) + balances = bk.GetAllBalances(ctx, bondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, rmTokens)))) keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) @@ -525,7 +534,8 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], _ = validators[3].AddTokensFromDel(sdk.NewInt(200)) notBondedPool = keeper.GetNotBondedPool(ctx) - require.NoError(t, notBondedPool.SetCoins(notBondedPool.GetCoins().Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) + balances = bk.GetAllBalances(ctx, notBondedPool.GetAddress()) + require.NoError(t, bk.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool) validators[3] = TestingUpdateValidator(keeper, ctx, validators[3], true) @@ -538,7 +548,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { } func TestValidatorBondHeight(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) // now 2 max resValidators params := keeper.GetParams(ctx) @@ -585,7 +595,7 @@ func TestValidatorBondHeight(t *testing.T) { } func TestFullValidatorSetPowerChange(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) max := 2 params.MaxValidators = uint16(2) @@ -627,7 +637,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20} var validators [2]types.Validator @@ -657,7 +667,7 @@ func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20} var validators [2]types.Validator @@ -680,7 +690,7 @@ func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20} var validators [2]types.Validator @@ -709,7 +719,7 @@ func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20} var validators [2]types.Validator @@ -741,7 +751,7 @@ func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{10, 20, 5, 15, 25} var validators [5]types.Validator @@ -787,7 +797,7 @@ func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := types.DefaultParams() params.MaxValidators = 2 keeper.SetParams(ctx, params) @@ -828,7 +838,7 @@ func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) powers := []int64{100, 100} var validators [2]types.Validator @@ -869,7 +879,7 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) params.MaxValidators = uint16(3) @@ -950,7 +960,7 @@ func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { } func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) params.MaxValidators = uint16(2) @@ -1027,7 +1037,7 @@ func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { } func TestUpdateValidatorCommission(t *testing.T) { - ctx, _, keeper, _ := CreateTestInput(t, false, 1000) + ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) ctx = ctx.WithBlockHeader(abci.Header{Time: time.Now().UTC()}) commission1 := types.NewCommissionWithTime( diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 8744496e07b..58451676a73 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -92,7 +92,7 @@ func WeightedOperations( } // SimulateMsgCreateValidator generates a MsgCreateValidator with random values -// nolint: funlen +// nolint: funlen interfacer func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -122,9 +122,7 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k k selfDelegation := sdk.NewCoin(denom, amount) account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) var fees sdk.Coins coins, hasNeg := spendable.SafeSub(sdk.Coins{selfDelegation}) @@ -173,7 +171,7 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k k } // SimulateMsgEditValidator generates a MsgEditValidator with random values -// nolint: funlen +// nolint: funlen interfacer func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -203,9 +201,7 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k kee } account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { @@ -242,7 +238,7 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k kee } // SimulateMsgDelegate generates a MsgDelegate with random values -// nolint: funlen +// nolint: funlen interfacer func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -276,9 +272,7 @@ func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.K bondAmt := sdk.NewCoin(denom, amount) account := ak.GetAccount(ctx, simAccount.Address) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) var fees sdk.Coins coins, hasNeg := spendable.SafeSub(sdk.Coins{bondAmt}) @@ -311,7 +305,7 @@ func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.K } // SimulateMsgUndelegate generates a MsgUndelegate with random values -// nolint: funlen +// nolint: funlen,interfacer func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -366,9 +360,7 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper } account := ak.GetAccount(ctx, delAddr) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { @@ -395,7 +387,7 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper } // SimulateMsgBeginRedelegate generates a MsgBeginRedelegate with random values -// nolint: funlen +// nolint: funlen,interfacer func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, @@ -406,8 +398,8 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k k if !ok { return simulation.NoOpMsg(types.ModuleName), nil, nil } - srcAddr := srcVal.GetOperator() + srcAddr := srcVal.GetOperator() delegations := k.GetValidatorDelegations(ctx, srcAddr) // get random delegator from src validator @@ -464,15 +456,14 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k k break } } + // if simaccount.PrivKey == nil, delegation address does not exist in accs. Return error if simAccount.PrivKey == nil { return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("delegation addr: %s does not exist in simulation accounts", delAddr) } account := ak.GetAccount(ctx, delAddr) - balances := bk.GetAllBalances(ctx, account.GetAddress()) - locked := bk.LockedCoins(ctx, account.GetAddress()) - spendable := balances.Sub(locked) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) fees, err := simulation.RandomFees(r, ctx, spendable) if err != nil { diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index c0e407ac7c2..c9e69b9018b 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -25,6 +25,7 @@ type BankKeeper interface { GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } // SupplyKeeper defines the expected supply Keeper (noalias) diff --git a/x/supply/internal/keeper/bank_test.go b/x/supply/internal/keeper/bank_test.go index 6a817a164f8..5388dc804d4 100644 --- a/x/supply/internal/keeper/bank_test.go +++ b/x/supply/internal/keeper/bank_test.go @@ -24,24 +24,26 @@ var ( initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) ) -func getCoinsByName(ctx sdk.Context, sk keep.Keeper, ak types.AccountKeeper, moduleName string) sdk.Coins { +// nolint +func getCoinsByName(ctx sdk.Context, sk keep.Keeper, ak types.AccountKeeper, bk types.BankKeeper, moduleName string) sdk.Coins { moduleAddress := sk.GetModuleAddress(moduleName) macc := ak.GetAccount(ctx, moduleAddress) if macc == nil { return sdk.Coins(nil) } - return macc.GetCoins() + + return bk.GetAllBalances(ctx, macc.GetAddress()) } func TestSendCoins(t *testing.T) { app, ctx := createTestApp(false) keeper := app.SupplyKeeper ak := app.AccountKeeper + bk := app.BankKeeper baseAcc := ak.NewAccountWithAddress(ctx, types.NewModuleAddress("baseAcc")) - err := holderAcc.SetCoins(initCoins) - require.NoError(t, err) + require.NoError(t, bk.SetBalances(ctx, holderAcc.GetAddress(), initCoins)) keeper.SetSupply(ctx, types.NewSupply(initCoins)) keeper.SetModuleAccount(ctx, holderAcc) @@ -60,30 +62,33 @@ func TestSendCoins(t *testing.T) { keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) }) - err = keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins...)) - require.Error(t, err) - - err = keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), types.Burner, initCoins) - require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, holderAcc.GetName())) - require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Burner)) - - err = keeper.SendCoinsFromModuleToAccount(ctx, types.Burner, baseAcc.GetAddress(), initCoins) - require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, types.Burner)) - - require.Equal(t, initCoins, ak.GetAccount(ctx, baseAcc.GetAddress()).GetCoins()) - - err = keeper.SendCoinsFromAccountToModule(ctx, baseAcc.GetAddress(), types.Burner, initCoins) - require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), ak.GetAccount(ctx, baseAcc.GetAddress()).GetCoins()) - require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Burner)) + require.Error( + t, + keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins...)), + ) + + require.NoError( + t, keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), types.Burner, initCoins), + ) + require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, bk, holderAcc.GetName())) + require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, types.Burner)) + + require.NoError( + t, keeper.SendCoinsFromModuleToAccount(ctx, types.Burner, baseAcc.GetAddress(), initCoins), + ) + require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, bk, types.Burner)) + require.Equal(t, initCoins, bk.GetAllBalances(ctx, baseAcc.GetAddress())) + + require.NoError(t, keeper.SendCoinsFromAccountToModule(ctx, baseAcc.GetAddress(), types.Burner, initCoins)) + require.Equal(t, sdk.Coins(nil), bk.GetAllBalances(ctx, baseAcc.GetAddress())) + require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, types.Burner)) } func TestMintCoins(t *testing.T) { app, ctx := createTestApp(false) keeper := app.SupplyKeeper ak := app.AccountKeeper + bk := app.BankKeeper keeper.SetModuleAccount(ctx, burnerAcc) keeper.SetModuleAccount(ctx, minterAcc) @@ -101,7 +106,7 @@ func TestMintCoins(t *testing.T) { err = keeper.MintCoins(ctx, types.Minter, initCoins) require.NoError(t, err) - require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Minter)) + require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, types.Minter)) require.Equal(t, initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) // test same functionality on module account with multiple permissions @@ -109,7 +114,7 @@ func TestMintCoins(t *testing.T) { err = keeper.MintCoins(ctx, multiPermAcc.GetName(), initCoins) require.NoError(t, err) - require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, multiPermAcc.GetName())) + require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, bk, multiPermAcc.GetName())) require.Equal(t, initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }) @@ -119,8 +124,9 @@ func TestBurnCoins(t *testing.T) { app, ctx := createTestApp(false) keeper := app.SupplyKeeper ak := app.AccountKeeper + bk := app.BankKeeper - require.NoError(t, burnerAcc.SetCoins(initCoins)) + require.NoError(t, bk.SetBalances(ctx, burnerAcc.GetAddress(), initCoins)) keeper.SetSupply(ctx, types.NewSupply(initCoins)) keeper.SetModuleAccount(ctx, burnerAcc) @@ -136,7 +142,7 @@ func TestBurnCoins(t *testing.T) { err = keeper.BurnCoins(ctx, types.Burner, initCoins) require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, types.Burner)) + require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, bk, types.Burner)) require.Equal(t, initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal()) // test same functionality on module account with multiple permissions @@ -144,11 +150,11 @@ func TestBurnCoins(t *testing.T) { initialSupply = initialSupply.Inflate(initCoins) keeper.SetSupply(ctx, initialSupply) - require.NoError(t, multiPermAcc.SetCoins(initCoins)) + require.NoError(t, bk.SetBalances(ctx, multiPermAcc.GetAddress(), initCoins)) keeper.SetModuleAccount(ctx, multiPermAcc) err = keeper.BurnCoins(ctx, multiPermAcc.GetName(), initCoins) require.NoError(t, err) - require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, multiPermAcc.GetName())) + require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, bk, multiPermAcc.GetName())) require.Equal(t, initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal()) } diff --git a/x/supply/internal/types/account_test.go b/x/supply/internal/types/account_test.go index 396f1a90be1..a3ee01bf1af 100644 --- a/x/supply/internal/types/account_test.go +++ b/x/supply/internal/types/account_test.go @@ -23,7 +23,7 @@ func TestModuleAccountMarshalYAML(t *testing.T) { bs, err := yaml.Marshal(moduleAcc) require.NoError(t, err) - want := "|\n address: cosmos1n7rdpqvgf37ktx30a2sv2kkszk3m7ncmg5drhe\n coins: []\n public_key: \"\"\n account_number: 0\n sequence: 0\n name: test\n permissions:\n - minter\n - burner\n - staking\n" + want := "|\n address: cosmos1n7rdpqvgf37ktx30a2sv2kkszk3m7ncmg5drhe\n public_key: \"\"\n account_number: 0\n sequence: 0\n name: test\n permissions:\n - minter\n - burner\n - staking\n" require.Equal(t, want, string(bs)) } @@ -52,7 +52,7 @@ func TestHasPermissions(t *testing.T) { func TestValidate(t *testing.T) { addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - baseAcc := authtypes.NewBaseAccount(addr, sdk.Coins{}, nil, 0, 0) + baseAcc := authtypes.NewBaseAccount(addr, nil, 0, 0) tests := []struct { name string acc authexported.GenesisAccount @@ -86,8 +86,7 @@ func TestValidate(t *testing.T) { func TestModuleAccountJSON(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) - coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, coins, nil, 10, 50) + baseAcc := authtypes.NewBaseAccount(addr, nil, 10, 50) acc := NewModuleAccount(baseAcc, "test", "burner") bz, err := json.Marshal(acc) diff --git a/x/supply/internal/types/expected_keepers.go b/x/supply/internal/types/expected_keepers.go index 8ef551e7e63..de933b75145 100644 --- a/x/supply/internal/types/expected_keepers.go +++ b/x/supply/internal/types/expected_keepers.go @@ -19,6 +19,9 @@ type BankKeeper interface { DelegateCoins(ctx sdk.Context, fromAdd, toAddr sdk.AccAddress, amt sdk.Coins) error UndelegateCoins(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) From 148c9fd4c3dd5592d1634a4089a0579e343670dd Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 30 Jan 2020 15:11:09 -0500 Subject: [PATCH 24/24] Fix tests --- x/auth/vesting/types/vesting_account_test.go | 39 ++++++++------------ x/bank/internal/keeper/keeper_test.go | 8 ++-- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index 6d3082bb8fa..4555d329e62 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -76,29 +76,23 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) { origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} bacc := authtypes.NewBaseAccountWithAddress(addr) - currBalance := origCoins - cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix()) // require that all original coins are locked at the end of the vesting // schedule - lockedCoins := cva.LockedCoins(currBalance, now) + lockedCoins := cva.LockedCoins(now) require.Equal(t, origCoins, lockedCoins) // require that there exist no locked coins in the beginning of the - lockedCoins = cva.LockedCoins(currBalance, endTime) - require.Nil(t, lockedCoins) + lockedCoins = cva.LockedCoins(endTime) + require.Equal(t, sdk.NewCoins(), lockedCoins) // require that all vested coins (50%) are spendable - lockedCoins = cva.LockedCoins(currBalance, now.Add(12*time.Hour)) + lockedCoins = cva.LockedCoins(now.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) - // receive some coins - recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - currBalance = currBalance.Add(recvAmt...) - // require that all vested coins (50%) are spendable plus any received - lockedCoins = cva.LockedCoins(currBalance, now.Add(12*time.Hour)) + lockedCoins = cva.LockedCoins(now.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) } @@ -236,29 +230,29 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) { // require that all coins are locked in the beginning of the vesting // schedule dva := NewDelayedVestingAccount(&bacc, origCoins, endTime.Unix()) - lockedCoins := dva.LockedCoins(origCoins, now) + lockedCoins := dva.LockedCoins(now) require.True(t, lockedCoins.IsEqual(origCoins)) // require that all coins are spendable after the maturation of the vesting // schedule - lockedCoins = dva.LockedCoins(origCoins, endTime) - require.Nil(t, lockedCoins) + lockedCoins = dva.LockedCoins(endTime) + require.Equal(t, sdk.NewCoins(), lockedCoins) // require that all coins are still vesting after some time - lockedCoins = dva.LockedCoins(origCoins, now.Add(12*time.Hour)) + lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour)) require.True(t, lockedCoins.IsEqual(origCoins)) // receive some coins // require that only received coins are spendable since the account is still // vesting - lockedCoins = dva.LockedCoins(origCoins.Add(sdk.NewInt64Coin(stakeDenom, 50)), now.Add(12*time.Hour)) + lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour)) require.True(t, lockedCoins.IsEqual(origCoins)) // delegate some locked coins // require that locked is reduced delegatedAmount := sdk.NewCoins(sdk.NewInt64Coin(stakeDenom, 50)) dva.TrackDelegation(now.Add(12*time.Hour), origCoins, delegatedAmount) - lockedCoins = dva.LockedCoins(origCoins.Sub(delegatedAmount), now.Add(12*time.Hour)) + lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour)) require.True(t, lockedCoins.IsEqual(origCoins.Sub(delegatedAmount))) } @@ -449,22 +443,21 @@ func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { // require that there exist no spendable coins at the beginning of the // vesting schedule - lockedCoins := pva.LockedCoins(origCoins, now) + lockedCoins := pva.LockedCoins(now) require.Equal(t, origCoins, lockedCoins) // require that all original coins are spendable at the end of the vesting // schedule - lockedCoins = pva.LockedCoins(origCoins, endTime) - require.Nil(t, lockedCoins) + lockedCoins = pva.LockedCoins(endTime) + require.Equal(t, sdk.NewCoins(), lockedCoins) // require that all still vesting coins (50%) are locked - lockedCoins = pva.LockedCoins(origCoins, now.Add(12*time.Hour)) + lockedCoins = pva.LockedCoins(now.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) // receive some coins // require that all still vesting coins (50% of original) are locked plus any received - recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} - lockedCoins = pva.LockedCoins(origCoins.Add(recvAmt...), now.Add(12*time.Hour)) + lockedCoins = pva.LockedCoins(now.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) } diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index 9af2e1cbbd7..8f2eab8138d 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -474,10 +474,10 @@ func (suite *IntegrationTestSuite) TestVestingAccountReceive() { vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.ContinuousVestingAccount) balances := app.BankKeeper.GetAllBalances(ctx, addr1) suite.Require().Equal(origCoins.Add(sendCoins...), balances) - suite.Require().Equal(balances.Sub(vacc.LockedCoins(balances, now)), sendCoins) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(now)), sendCoins) // require coins are spendable plus any that have vested - suite.Require().Equal(balances.Sub(vacc.LockedCoins(balances, now.Add(12*time.Hour))), origCoins) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(now.Add(12*time.Hour))), origCoins) } func (suite *IntegrationTestSuite) TestPeriodicVestingAccountReceive() { @@ -513,10 +513,10 @@ func (suite *IntegrationTestSuite) TestPeriodicVestingAccountReceive() { vacc = app.AccountKeeper.GetAccount(ctx, addr1).(*vesting.PeriodicVestingAccount) balances := app.BankKeeper.GetAllBalances(ctx, addr1) suite.Require().Equal(origCoins.Add(sendCoins...), balances) - suite.Require().Equal(balances.Sub(vacc.LockedCoins(balances, now)), sendCoins) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(now)), sendCoins) // require coins are spendable plus any that have vested - suite.Require().Equal(balances.Sub(vacc.LockedCoins(balances, now.Add(12*time.Hour))), origCoins) + suite.Require().Equal(balances.Sub(vacc.LockedCoins(now.Add(12*time.Hour))), origCoins) } func (suite *IntegrationTestSuite) TestDelegateCoins() {