Merge PR #5572: ADR 004 Implementation
This commit is contained in:
parent
b669ac5eaa
commit
6890feb3d2
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -37,14 +37,29 @@ 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
|
||||
|
||||
* (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) [\#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
|
||||
the original vesting amount.
|
||||
* The `SendKeeper` and `ViewKeeper` interfaces in `x/bank` have been modified to account for changes.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (types) [\#5581](https://github.com/cosmos/cosmos-sdk/pull/5581) Add convenience functions {,Must}Bech32ifyAddressBytes.
|
||||
|
|
|
@ -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}`.
|
||||
|
||||
`SubtractCoins()` and `AddCoins()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist).
|
||||
`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.
|
||||
|
||||
`trackDelegation()` and `trackUndelegation()` 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).
|
||||
|
||||
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.
|
||||
`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. 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
|
||||
|
|
|
@ -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,20 +174,20 @@ 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,
|
||||
)
|
||||
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
|
||||
)
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
@ -101,11 +100,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
|
||||
|
|
|
@ -19,8 +19,6 @@ import (
|
|||
// copied from iavl/store_test.go
|
||||
var (
|
||||
cacheSize = 100
|
||||
numRecent int64 = 5
|
||||
storeEvery int64 = 3
|
||||
)
|
||||
|
||||
func bz(s string) []byte { return []byte(s) }
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package v039
|
||||
|
||||
// DONTCOVER
|
||||
// nolint
|
||||
|
||||
const (
|
||||
ModuleName = "auth"
|
||||
)
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -72,9 +75,14 @@ type VestingAccount interface {
|
|||
GetVestedCoins(Time) Coins
|
||||
GetVestingCoins(Time) Coins
|
||||
|
||||
// Delegation and undelegation accounting that returns the resulting base
|
||||
// coins amount.
|
||||
TrackDelegation(Time, 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)
|
||||
|
||||
// TrackUndelegation performs internal vesting accounting necessary when a
|
||||
// vesting account performs an undelegation.
|
||||
TrackUndelegation(Coins)
|
||||
|
||||
GetStartTime() int64
|
||||
|
@ -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 amount of coins that can be sent to other accounts given
|
||||
// the current time.
|
||||
SpendableCoins(Time) Coins
|
||||
// Calculates the total locked account balance.
|
||||
LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.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,31 @@ 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, which can be defined as `max(V - DV, 0)`, and infer the
|
||||
spendable balance from that.
|
||||
|
||||
```go
|
||||
func (va VestingAccount) SpendableCoins(t Time) Coins {
|
||||
bc := va.GetCoins()
|
||||
return min((bc + va.DelegatedVesting) - va.GetVestingCoins(t), bc)
|
||||
func (va VestingAccount) LockedCoins(t Time) Coins {
|
||||
return max(va.GetVestingCoins(t) - va.DelegatedVesting, 0)
|
||||
}
|
||||
```
|
||||
|
||||
The `x/bank` `ViewKeeper` can then provide APIs to determine locked and spendable
|
||||
coins for any account:
|
||||
|
||||
```go
|
||||
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 +312,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.GetBalances(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 +338,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 +355,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 +409,7 @@ func UndelegateCoins(to Account, amount Coins) {
|
|||
// save account ...
|
||||
}
|
||||
} else {
|
||||
AddCoins(to, amount)
|
||||
AddBalance(to, amount)
|
||||
// save account...
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -11,9 +11,21 @@ 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).
|
||||
//
|
||||
// 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(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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -41,56 +41,51 @@ 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. If no coins are locked,
|
||||
// an empty slice of Coins is returned.
|
||||
//
|
||||
// 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()
|
||||
// CONTRACT: Delegated vesting coins and vestingCoins must be sorted.
|
||||
func (bva BaseVestingAccount) LockedCoinsFromVesting(vestingCoins sdk.Coins) sdk.Coins {
|
||||
lockedCoins := sdk.NewCoins()
|
||||
|
||||
for _, coin := range bc {
|
||||
baseAmt := coin.Amount
|
||||
vestingAmt := vestingCoins.AmountOf(coin.Denom)
|
||||
delVestingAmt := bva.DelegatedVesting.AmountOf(coin.Denom)
|
||||
for _, vestingCoin := range vestingCoins {
|
||||
vestingAmt := vestingCoin.Amount
|
||||
delVestingAmt := bva.DelegatedVesting.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)
|
||||
max := sdk.MaxInt(vestingAmt.Sub(delVestingAmt), sdk.ZeroInt())
|
||||
lockedCoin := sdk.NewCoin(vestingCoin.Denom, max)
|
||||
|
||||
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 +182,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 +204,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 +233,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 +272,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 +304,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 +350,16 @@ 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).
|
||||
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
|
||||
// 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 +386,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 +416,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 +457,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 +492,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 +526,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 +549,16 @@ 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).
|
||||
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
|
||||
// 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 +602,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 +633,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 +675,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 +708,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 +734,16 @@ 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).
|
||||
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
|
||||
// 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 +760,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 +800,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,
|
||||
|
|
|
@ -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,25 @@ 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)
|
||||
cva := NewContinuousVestingAccount(&bacc, origCoins, now.Unix(), endTime.Unix())
|
||||
|
||||
// require that all original coins are spendable at the end of the vesting
|
||||
// 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(now)
|
||||
require.Equal(t, origCoins, lockedCoins)
|
||||
|
||||
// require that there exist no locked coins in the beginning of the
|
||||
lockedCoins = cva.LockedCoins(endTime)
|
||||
require.Equal(t, sdk.NewCoins(), 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)
|
||||
|
||||
// receive some coins
|
||||
recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}
|
||||
cva.SetCoins(cva.GetCoins().Add(recvAmt...))
|
||||
lockedCoins = cva.LockedCoins(now.Add(12 * time.Hour))
|
||||
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins)
|
||||
|
||||
// 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(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 +103,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 +142,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 +168,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 +190,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 +208,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 +226,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(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(endTime)
|
||||
require.Equal(t, sdk.NewCoins(), 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(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)
|
||||
lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour))
|
||||
require.True(t, lockedCoins.IsEqual(origCoins))
|
||||
|
||||
// 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)
|
||||
// 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(now.Add(12 * time.Hour))
|
||||
require.True(t, lockedCoins.IsEqual(origCoins.Sub(delegatedAmount)))
|
||||
}
|
||||
|
||||
func TestTrackDelegationDelVestingAcc(t *testing.T) {
|
||||
|
@ -290,36 +263,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 +300,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 +325,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 +353,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 +399,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 +439,26 @@ 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(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(endTime)
|
||||
require.Equal(t, sdk.NewCoins(), 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(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)}
|
||||
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)
|
||||
// require that all still vesting coins (50% of original) are locked plus any received
|
||||
lockedCoins = pva.LockedCoins(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 +473,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 +531,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 +564,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 +579,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)
|
||||
// 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(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.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)
|
||||
// _, 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 +627,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 +637,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 +678,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 +698,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 +719,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 +739,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)
|
||||
|
|
|
@ -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,8 +46,11 @@ var (
|
|||
ValidateInputsOutputs = types.ValidateInputsOutputs
|
||||
ParamKeyTable = types.ParamKeyTable
|
||||
NewQueryBalanceParams = types.NewQueryBalanceParams
|
||||
NewQueryAllBalancesParams = types.NewQueryAllBalancesParams
|
||||
ModuleCdc = types.ModuleCdc
|
||||
ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled
|
||||
BalancesPrefix = types.BalancesPrefix
|
||||
AddressFromBalancesStore = types.AddressFromBalancesStore
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -55,9 +61,11 @@ type (
|
|||
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
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
||||
res1 := app.AccountKeeper.GetAccount(ctxCheck, addr1)
|
||||
app.Commit()
|
||||
|
||||
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{})
|
||||
|
||||
ctxCheck := app.BaseApp.NewContext(true, abci.Header{})
|
||||
err := app.BankKeeper.SetBalances(ctx, test.msg.FromAddress, test.fromBalance)
|
||||
require.NoError(t, err)
|
||||
|
||||
res1 := app.AccountKeeper.GetAccount(ctxCheck, test.msg.FromAddress)
|
||||
app.Commit()
|
||||
|
||||
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)
|
||||
|
||||
res1 := app.AccountKeeper.GetAccount(ctxCheck, addr1)
|
||||
app.Commit()
|
||||
|
||||
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{
|
||||
{
|
||||
|
|
|
@ -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++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
|
@ -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"`
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -1,15 +1,47 @@
|
|||
package bank
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
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 {
|
||||
if err := keeper.ValidateBalance(ctx, balance.Address); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
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 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: addr,
|
||||
Coins: coins,
|
||||
})
|
||||
}
|
||||
|
||||
return NewGenesisState(keeper.GetSendEnabled(ctx), balances)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
@ -33,14 +34,13 @@ type BaseKeeper struct {
|
|||
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 +48,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 +61,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 {
|
||||
for _, coin := range amt {
|
||||
balance := k.GetBalance(ctx, delegatorAddr, coin.Denom)
|
||||
if balance.IsLT(coin) {
|
||||
return sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt,
|
||||
sdkerrors.ErrInsufficientFunds, "failed to delegate; %s < %s", balance, amt,
|
||||
)
|
||||
}
|
||||
|
||||
if err := trackDelegation(delegatorAcc, ctx.BlockHeader().Time, amt); err != nil {
|
||||
balances = balances.Add(balance)
|
||||
k.SetBalance(ctx, delegatorAddr, balance.Sub(coin))
|
||||
}
|
||||
|
||||
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 +89,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 +102,20 @@ 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)
|
||||
_, 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 +129,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 +146,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 +180,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 +194,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 +211,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 +226,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 +239,121 @@ 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)
|
||||
_, hasNeg := sdk.Coins{spendable}.SafeSub(sdk.Coins{coin})
|
||||
if hasNeg {
|
||||
return amt, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", spendableCoins, amt,
|
||||
)
|
||||
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 := balance.Add(coin)
|
||||
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
|
||||
})
|
||||
|
||||
acc := keeper.ak.GetAccount(ctx, addr)
|
||||
if acc == nil {
|
||||
acc = keeper.ak.NewAccountWithAddress(ctx, addr)
|
||||
}
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
balancesStore := prefix.NewStore(store, types.BalancesPrefix)
|
||||
accountStore := prefix.NewStore(balancesStore, addr.Bytes())
|
||||
|
||||
err := acc.SetCoins(amt)
|
||||
for _, key := range keys {
|
||||
accountStore.Delete(key)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
keeper.ak.SetAccount(ctx, acc)
|
||||
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() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String())
|
||||
}
|
||||
|
||||
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 +361,203 @@ 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
|
||||
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
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
// BaseViewKeeper implements a read only keeper implementation of ViewKeeper.
|
||||
type BaseViewKeeper struct {
|
||||
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 {
|
||||
// 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.Sort()
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
|
||||
var balance sdk.Coin
|
||||
k.cdc.MustUnmarshalBinaryBare(bz, &balance)
|
||||
|
||||
return balance
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.AddressFromBalancesStore(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 {
|
||||
return vacc.LockedCoins(ctx.BlockTime())
|
||||
}
|
||||
}
|
||||
|
||||
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 acc.GetCoins()
|
||||
|
||||
return spendable
|
||||
}
|
||||
|
||||
// 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)
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
|
||||
// CONTRACT: assumes that amt is valid.
|
||||
func trackDelegation(acc authexported.Account, blockTime time.Time, amt sdk.Coins) error {
|
||||
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
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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, coins)
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, balance)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
req := abci.RequestQuery{
|
||||
Path: fmt.Sprintf("custom/bank/%s", keep.QueryBalance),
|
||||
Data: []byte{},
|
||||
}
|
||||
|
||||
querier := keep.NewQuerier(app.BankKeeper)
|
||||
|
||||
res, err := querier(ctx, []string{"balances"}, req)
|
||||
require.NotNil(t, err)
|
||||
require.Nil(t, res)
|
||||
|
||||
func (suite *IntegrationTestSuite) TestQuerier_QueryBalance() {
|
||||
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)
|
||||
|
||||
var coins sdk.Coins
|
||||
require.NoError(t, app.Codec().UnmarshalJSON(res, &coins))
|
||||
require.True(t, coins.IsZero())
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
func TestQuerierRouteNotFound(t *testing.T) {
|
||||
app, ctx := createTestApp(false)
|
||||
req := abci.RequestQuery{
|
||||
Path: "custom/bank/notfound",
|
||||
Path: fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryBalance),
|
||||
Data: []byte{},
|
||||
}
|
||||
|
||||
querier := keep.NewQuerier(app.BankKeeper)
|
||||
_, err := querier(ctx, []string{"notfound"}, req)
|
||||
require.Error(t, err)
|
||||
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{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 := abci.RequestQuery{
|
||||
Path: fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryAllBalances),
|
||||
Data: []byte{},
|
||||
}
|
||||
|
||||
querier := keeper.NewQuerier(app.BankKeeper)
|
||||
|
||||
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)
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, acc)
|
||||
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 (suite *IntegrationTestSuite) TestQuerierRouteNotFound() {
|
||||
app, ctx := suite.app, suite.ctx
|
||||
req := abci.RequestQuery{
|
||||
Path: fmt.Sprintf("custom/%s/invalid", types.ModuleName),
|
||||
Data: []byte{},
|
||||
}
|
||||
|
||||
querier := keeper.NewQuerier(app.BankKeeper)
|
||||
_, err := querier(ctx, []string{"invalid"}, req)
|
||||
suite.Error(err)
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,38 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// module name
|
||||
// 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")
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
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 TestAddressFromBalancesStore(t *testing.T) {
|
||||
addr, err := sdk.AccAddressFromBech32("cosmos1n88uc38xhjgxzw9nwre4ep2c8ga4fjxcar6mn7")
|
||||
require.NoError(t, err)
|
||||
|
||||
key := cloneAppend(addr.Bytes(), []byte("stake"))
|
||||
res := types.AddressFromBalancesStore(key)
|
||||
require.Equal(t, res, addr)
|
||||
}
|
|
@ -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"`
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package v038
|
||||
|
||||
// DONTCOVER
|
||||
// nolint
|
||||
|
||||
const (
|
||||
ModuleName = "bank"
|
||||
)
|
||||
|
||||
type (
|
||||
GenesisState struct {
|
||||
SendEnabled bool `json:"send_enabled" yaml:"send_enabled"`
|
||||
}
|
||||
)
|
|
@ -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)
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
//____________________________________________________________________________
|
||||
|
||||
|
@ -90,7 +92,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.
|
||||
|
|
|
@ -3,10 +3,9 @@ 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"
|
||||
)
|
||||
|
@ -21,6 +20,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,8 +43,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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -63,7 +64,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 +75,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
|
||||
}
|
||||
|
@ -84,19 +85,21 @@ 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, 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)
|
||||
|
||||
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 {
|
||||
|
@ -148,11 +151,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 +210,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
|
||||
}
|
||||
|
@ -218,8 +221,9 @@ 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, 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 {
|
||||
|
||||
|
@ -232,15 +236,16 @@ func sendMsgMultiSend(
|
|||
sequenceNumbers[i] = acc.GetSequence()
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
// 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 {
|
||||
|
@ -268,8 +273,9 @@ 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, 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 +291,9 @@ func randomSendFields(
|
|||
return simAccount, toSimAcc, nil, true, nil // skip error
|
||||
}
|
||||
|
||||
coins := acc.SpendableCoins(ctx.BlockHeader().Time)
|
||||
spendable := bk.SpendableCoins(ctx, acc.GetAddress())
|
||||
|
||||
sendCoins := simulation.RandSubsetCoins(r, coins)
|
||||
sendCoins := simulation.RandSubsetCoins(r, spendable)
|
||||
if sendCoins.Empty() {
|
||||
return simAccount, toSimAcc, nil, true, nil // skip error
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -46,6 +47,7 @@ func NewKeeper(
|
|||
storeKey: key,
|
||||
cdc: cdc,
|
||||
paramSpace: paramSpace,
|
||||
bankKeeper: bk,
|
||||
stakingKeeper: sk,
|
||||
supplyKeeper: supplyKeeper,
|
||||
feeCollectorName: feeCollectorName,
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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,11 @@ 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)
|
||||
|
||||
fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime()))
|
||||
account := ak.GetAccount(ctx, simAccount.Address)
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
fees, err := simulation.RandomFees(r, ctx, spendable)
|
||||
if err != nil {
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, err
|
||||
}
|
||||
|
@ -119,7 +121,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 +139,9 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper,
|
|||
}
|
||||
|
||||
account := ak.GetAccount(ctx, simAccount.Address)
|
||||
fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime()))
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
fees, err := simulation.RandomFees(r, ctx, spendable)
|
||||
if err != nil {
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, err
|
||||
}
|
||||
|
@ -165,7 +169,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 +190,9 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee
|
|||
}
|
||||
|
||||
account := ak.GetAccount(ctx, simAccount.Address)
|
||||
fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime()))
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
fees, err := simulation.RandomFees(r, ctx, spendable)
|
||||
if err != nil {
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, err
|
||||
}
|
||||
|
@ -214,7 +220,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 +228,9 @@ 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())
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
fundAmount := simulation.RandSubsetCoins(r, coins)
|
||||
fundAmount := simulation.RandSubsetCoins(r, spendable)
|
||||
if fundAmount.Empty() {
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, nil
|
||||
}
|
||||
|
@ -234,7 +240,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 {
|
||||
|
|
|
@ -13,6 +13,15 @@ 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
|
||||
SpendableCoins(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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
// 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 {
|
||||
|
||||
var stakingData stakingtypes.GenesisState
|
||||
cdc.MustUnmarshalJSON(appGenesisState[stakingtypes.ModuleName], &stakingData)
|
||||
bondDenom := stakingData.Params.BondDenom
|
||||
|
||||
var err error
|
||||
|
||||
accountIsInGenesis := false
|
||||
|
||||
// TODO: refactor out bond denom to common state area
|
||||
stakingDataBz := appGenesisState[stakingtypes.ModuleName]
|
||||
var stakingData stakingtypes.GenesisState
|
||||
cdc.MustUnmarshalJSON(stakingDataBz, &stakingData)
|
||||
bondDenom := stakingData.Params.BondDenom
|
||||
genBalIterator.IterateGenesisBalances(cdc, appGenesisState,
|
||||
func(bal bankexported.GenesisBalance) (stop bool) {
|
||||
accAddress := bal.GetAddress()
|
||||
accCoins := bal.GetCoins()
|
||||
|
||||
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) {
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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,10 @@ func SimulateSubmitProposal(
|
|||
msg := types.NewMsgSubmitProposal(content, deposit, simAccount.Address)
|
||||
|
||||
account := ak.GetAccount(ctx, simAccount.Address)
|
||||
coins := account.SpendableCoins(ctx.BlockTime())
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
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 +179,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 +189,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 +200,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 +211,10 @@ 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())
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
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 +243,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,
|
||||
|
@ -269,11 +271,12 @@ func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper,
|
|||
}
|
||||
|
||||
option := randomVotingOption(r)
|
||||
|
||||
msg := types.NewMsgVote(simAccount.Address, proposalID, option)
|
||||
|
||||
account := ak.GetAccount(ctx, simAccount.Address)
|
||||
fees, err := simulation.RandomFees(r, ctx, account.SpendableCoins(ctx.BlockTime()))
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
fees, err := simulation.RandomFees(r, ctx, spendable)
|
||||
if err != nil {
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, err
|
||||
}
|
||||
|
@ -302,11 +305,12 @@ 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() {
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
if spendable.Empty() {
|
||||
return nil, true, nil // skip
|
||||
}
|
||||
|
||||
|
@ -314,7 +318,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
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
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,
|
||||
|
|
|
@ -44,3 +44,12 @@ 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
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -17,7 +17,7 @@ const msgRoute = "testMsg"
|
|||
var (
|
||||
numAccts = 2
|
||||
genCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 77)}
|
||||
accs, addrs, _, privKeys = CreateGenAccounts(numAccts, genCoins)
|
||||
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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue