Merge PR #3308: Genesis Vesting Accounts & Simulation
* Update vesting spec and impl time fields and constructors * Update genesis to support vesting accounts * More spec and godoc updates * Update genesis section in vesting spec * Fix bank unit tests * Add test cases to ToAccount in genesis * Update RegisterCodec to include vesting interface and types * Fix GetVestedCoins bug where block time is past vesting end time * Add vesting accounts to simulation * Update vesting genesis logic to panic on invalid accounts * Change randomness of vesting accounts in simulation
This commit is contained in:
parent
20bcacfaf4
commit
f2e87ad81f
@ -55,6 +55,8 @@ FEATURES
|
||||
|
||||
* Gaia
|
||||
* [\#2182] [x/staking] Added querier for querying a single redelegation
|
||||
* [\#3305](https://github.com/cosmos/cosmos-sdk/issues/3305) Add support for
|
||||
vesting accounts at genesis.
|
||||
* [\#3198](https://github.com/cosmos/cosmos-sdk/issues/3198) [x/auth] Add multisig transactions support
|
||||
* [\#3198](https://github.com/cosmos/cosmos-sdk/issues/3198) `add-genesis-account` can take both account addresses and key names
|
||||
|
||||
|
||||
@ -231,10 +231,11 @@ func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisSt
|
||||
sort.Slice(genesisState.Accounts, func(i, j int) bool {
|
||||
return genesisState.Accounts[i].AccountNumber < genesisState.Accounts[j].AccountNumber
|
||||
})
|
||||
|
||||
// load the accounts
|
||||
for _, gacc := range genesisState.Accounts {
|
||||
acc := gacc.ToAccount()
|
||||
acc.AccountNumber = app.accountKeeper.GetNextAccountNumber(ctx)
|
||||
acc = app.accountKeeper.NewAccount(ctx, acc) // set account number
|
||||
app.accountKeeper.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
|
||||
@ -58,12 +58,15 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
|
||||
}
|
||||
}
|
||||
|
||||
// nolint
|
||||
// GenesisAccount defines an account initialized at genesis.
|
||||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
Sequence uint64 `json:"sequence_number"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
Vesting bool `json:"vesting"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
EndTime int64 `json:"end_time"`
|
||||
}
|
||||
|
||||
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||
@ -76,22 +79,43 @@ func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||
}
|
||||
|
||||
func NewGenesisAccountI(acc auth.Account) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
gacc := GenesisAccount{
|
||||
Address: acc.GetAddress(),
|
||||
Coins: acc.GetCoins(),
|
||||
AccountNumber: acc.GetAccountNumber(),
|
||||
Sequence: acc.GetSequence(),
|
||||
}
|
||||
|
||||
vacc, ok := acc.(auth.VestingAccount)
|
||||
if ok {
|
||||
gacc.Vesting = true
|
||||
gacc.StartTime = vacc.GetStartTime()
|
||||
gacc.EndTime = vacc.GetEndTime()
|
||||
}
|
||||
|
||||
return gacc
|
||||
}
|
||||
|
||||
// convert GenesisAccount to auth.BaseAccount
|
||||
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
|
||||
return &auth.BaseAccount{
|
||||
func (ga *GenesisAccount) ToAccount() auth.Account {
|
||||
bacc := &auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
AccountNumber: ga.AccountNumber,
|
||||
Sequence: ga.Sequence,
|
||||
}
|
||||
|
||||
if ga.Vesting {
|
||||
if ga.StartTime != 0 && ga.EndTime != 0 {
|
||||
return auth.NewContinuousVestingAccount(bacc, ga.StartTime, ga.EndTime)
|
||||
} else if ga.EndTime != 0 {
|
||||
return auth.NewDelayedVestingAccount(bacc, ga.EndTime)
|
||||
} else {
|
||||
panic(fmt.Sprintf("invalid genesis vesting account: %+v", ga))
|
||||
}
|
||||
}
|
||||
|
||||
return bacc
|
||||
}
|
||||
|
||||
// Create the core parameters for genesis initialization for gaia
|
||||
@ -114,11 +138,13 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js
|
||||
if err := cdc.UnmarshalJSON(genTx, &tx); err != nil {
|
||||
return genesisState, err
|
||||
}
|
||||
|
||||
msgs := tx.GetMsgs()
|
||||
if len(msgs) != 1 {
|
||||
return genesisState, errors.New(
|
||||
"must provide genesis StdTx with exactly 1 CreateValidator message")
|
||||
}
|
||||
|
||||
if _, ok := msgs[0].(staking.MsgCreateValidator); !ok {
|
||||
return genesisState, fmt.Errorf(
|
||||
"Genesis transaction %v does not contain a MsgCreateValidator", i)
|
||||
@ -126,7 +152,6 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js
|
||||
}
|
||||
|
||||
for _, acc := range genesisState.Accounts {
|
||||
// create the genesis account, give'm few steaks and a buncha token with there name
|
||||
for _, coin := range acc.Coins {
|
||||
if coin.Denom == bondDenom {
|
||||
stakingData.Pool.LooseTokens = stakingData.Pool.LooseTokens.
|
||||
@ -134,8 +159,10 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
genesisState.StakingData = stakingData
|
||||
genesisState.GenTxs = appGenTxs
|
||||
|
||||
return genesisState, nil
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package app
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
@ -56,7 +57,17 @@ func TestToAccount(t *testing.T) {
|
||||
addr := sdk.AccAddress(priv.PubKey().Address())
|
||||
authAcc := auth.NewBaseAccountWithAddress(addr)
|
||||
genAcc := NewGenesisAccount(&authAcc)
|
||||
require.Equal(t, authAcc, *genAcc.ToAccount())
|
||||
acc := genAcc.ToAccount()
|
||||
require.IsType(t, &auth.BaseAccount{}, acc)
|
||||
require.Equal(t, &authAcc, acc.(*auth.BaseAccount))
|
||||
|
||||
vacc := auth.NewContinuousVestingAccount(
|
||||
&authAcc, time.Now().Unix(), time.Now().Add(24*time.Hour).Unix(),
|
||||
)
|
||||
genAcc = NewGenesisAccountI(vacc)
|
||||
acc = genAcc.ToAccount()
|
||||
require.IsType(t, &auth.ContinuousVestingAccount{}, acc)
|
||||
require.Equal(t, vacc, acc.(*auth.ContinuousVestingAccount))
|
||||
}
|
||||
|
||||
func TestGaiaAppGenTx(t *testing.T) {
|
||||
|
||||
@ -54,7 +54,7 @@ func init() {
|
||||
flag.IntVar(&period, "SimulationPeriod", 1, "Run slow invariants only once every period assertions")
|
||||
}
|
||||
|
||||
func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||
func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) json.RawMessage {
|
||||
var genesisAccounts []GenesisAccount
|
||||
|
||||
amount := int64(r.Intn(1e6))
|
||||
@ -67,13 +67,44 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||
"\t{amount of steak per account: %v, initially bonded validators: %v}\n",
|
||||
amount, numInitiallyBonded)
|
||||
|
||||
// Randomly generate some genesis accounts
|
||||
for _, acc := range accs {
|
||||
// randomly generate some genesis accounts
|
||||
for i, acc := range accs {
|
||||
coins := sdk.Coins{sdk.NewCoin(stakingTypes.DefaultBondDenom, sdk.NewInt(amount))}
|
||||
genesisAccounts = append(genesisAccounts, GenesisAccount{
|
||||
Address: acc.Address,
|
||||
Coins: coins,
|
||||
})
|
||||
bacc := auth.NewBaseAccountWithAddress(acc.Address)
|
||||
bacc.SetCoins(coins)
|
||||
|
||||
var gacc GenesisAccount
|
||||
|
||||
// Only consider making a vesting account once the initial bonded validator
|
||||
// set is exhausted due to needing to track DelegatedVesting.
|
||||
if int64(i) > numInitiallyBonded && r.Intn(100) < 50 {
|
||||
var (
|
||||
vacc auth.VestingAccount
|
||||
endTime int
|
||||
)
|
||||
|
||||
startTime := genesisTimestamp.Unix()
|
||||
|
||||
// Allow for some vesting accounts to vest very quickly while others very
|
||||
// slowly.
|
||||
if r.Intn(100) < 50 {
|
||||
endTime = randIntBetween(r, int(startTime), int(startTime+(60*60*24*30)))
|
||||
} else {
|
||||
endTime = randIntBetween(r, int(startTime), int(startTime+(60*60*12)))
|
||||
}
|
||||
|
||||
if r.Intn(100) < 50 {
|
||||
vacc = auth.NewContinuousVestingAccount(&bacc, startTime, int64(endTime))
|
||||
} else {
|
||||
vacc = auth.NewDelayedVestingAccount(&bacc, int64(endTime))
|
||||
}
|
||||
|
||||
gacc = NewGenesisAccountI(vacc)
|
||||
} else {
|
||||
gacc = NewGenesisAccount(&bacc)
|
||||
}
|
||||
|
||||
genesisAccounts = append(genesisAccounts, gacc)
|
||||
}
|
||||
|
||||
authGenesis := auth.GenesisState{
|
||||
@ -156,6 +187,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||
validators = append(validators, validator)
|
||||
delegations = append(delegations, delegation)
|
||||
}
|
||||
|
||||
stakingGenesis.Pool.LooseTokens = sdk.NewInt((amount * numAccs) + (numInitiallyBonded * amount))
|
||||
stakingGenesis.Validators = validators
|
||||
stakingGenesis.Bonds = delegations
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
- [Undelegating](#undelegating)
|
||||
- [Keepers/Handlers](#keepershandlers-2)
|
||||
- [Keepers & Handlers](#keepers--handlers)
|
||||
- [Initializing at Genesis](#initializing-at-genesis)
|
||||
- [Genesis Initialization](#genesis-initialization)
|
||||
- [Examples](#examples)
|
||||
- [Simple](#simple)
|
||||
- [Slashing](#slashing)
|
||||
@ -45,13 +45,16 @@ order to make such a distinction.
|
||||
type VestingAccount interface {
|
||||
Account
|
||||
|
||||
GetVestedCoins(Time) Coins
|
||||
GetVestedCoins(Time) Coins
|
||||
GetVestingCoins(Time) Coins
|
||||
|
||||
// Delegation and undelegation accounting that returns the resulting base
|
||||
// coins amount.
|
||||
TrackDelegation(Time, Coins)
|
||||
TrackUndelegation(Coins)
|
||||
|
||||
GetStartTime() int64
|
||||
GetEndTime() int64
|
||||
}
|
||||
|
||||
// BaseVestingAccount implements the VestingAccount interface. It contains all
|
||||
@ -63,7 +66,7 @@ type BaseVestingAccount struct {
|
||||
DelegatedFree Coins // coins that are vested and delegated
|
||||
DelegatedVesting Coins // coins that vesting and delegated
|
||||
|
||||
EndTime Time // when the coins become unlocked
|
||||
EndTime int64 // when the coins become unlocked
|
||||
}
|
||||
|
||||
// ContinuousVestingAccount implements the VestingAccount interface. It
|
||||
@ -71,7 +74,7 @@ type BaseVestingAccount struct {
|
||||
type ContinuousVestingAccount struct {
|
||||
BaseVestingAccount
|
||||
|
||||
StartTime Time // when the coins start to vest
|
||||
StartTime int64 // when the coins start to vest
|
||||
}
|
||||
|
||||
// DelayedVestingAccount implements the VestingAccount interface. It vests all
|
||||
@ -127,11 +130,13 @@ is _vesting_.
|
||||
|
||||
```go
|
||||
func (cva ContinuousVestingAccount) GetVestedCoins(t Time) Coins {
|
||||
// We must handle the case where the start time for a vesting account has
|
||||
// been set into the future or when the start of the chain is not exactly
|
||||
// known.
|
||||
if t <= va.StartTime {
|
||||
if t <= cva.StartTime {
|
||||
// We must handle the case where the start time for a vesting account has
|
||||
// been set into the future or when the start of the chain is not exactly
|
||||
// known.
|
||||
return ZeroCoins
|
||||
} else if t >= cva.EndTime {
|
||||
return cva.OriginalVesting
|
||||
}
|
||||
|
||||
x := t - cva.StartTime
|
||||
@ -299,50 +304,38 @@ unlocked coin amount.
|
||||
|
||||
See the above specification for full implementation details.
|
||||
|
||||
## Initializing at Genesis
|
||||
## Genesis Initialization
|
||||
|
||||
To initialize both vesting and base accounts, the `GenesisAccount` struct will
|
||||
include an `EndTime`. Accounts meant to be of type `BaseAccount` will
|
||||
have `EndTime = 0`. The `initChainer` method will parse the GenesisAccount into
|
||||
BaseAccounts and VestingAccounts as appropriate.
|
||||
To initialize both vesting and non-vesting accounts, the `GenesisAccount` struct will
|
||||
include new fields: `Vesting`, `StartTime`, and `EndTime`. Accounts meant to be
|
||||
of type `BaseAccount` or any non-vesting type will have `Vesting = false`. The
|
||||
genesis initialization logic (e.g. `initFromGenesisState`) will have to parse
|
||||
and return the correct accounts accordingly based off of these new fields.
|
||||
|
||||
```go
|
||||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress
|
||||
GenesisCoins sdk.Coins
|
||||
EndTime int64
|
||||
StartTime int64
|
||||
// ...
|
||||
|
||||
Vesting bool
|
||||
EndTime int64
|
||||
StartTime int64
|
||||
}
|
||||
|
||||
func initChainer() {
|
||||
for genAcc in GenesisAccounts {
|
||||
baseAccount := BaseAccount{
|
||||
Address: genAcc.Address,
|
||||
Coins: genAcc.GenesisCoins,
|
||||
}
|
||||
func ToAccount(gacc GenesisAccount) Account {
|
||||
bacc := NewBaseAccount(gacc)
|
||||
|
||||
if genAcc.StartTime != 0 && genAcc.EndTime != 0 {
|
||||
vestingAccount := ContinuousVestingAccount{
|
||||
BaseAccount: baseAccount,
|
||||
OriginalVesting: genAcc.GenesisCoins,
|
||||
StartTime: RequestInitChain.Time,
|
||||
StartTime: genAcc.StartTime,
|
||||
EndTime: genAcc.EndTime,
|
||||
}
|
||||
|
||||
AddAccountToState(vestingAccount)
|
||||
} else if genAcc.EndTime != 0 {
|
||||
vestingAccount := DelayedVestingAccount{
|
||||
BaseAccount: baseAccount,
|
||||
OriginalVesting: genAcc.GenesisCoins,
|
||||
EndTime: genAcc.EndTime,
|
||||
}
|
||||
|
||||
AddAccountToState(vestingAccount)
|
||||
if gacc.Vesting {
|
||||
if ga.StartTime != 0 && ga.EndTime != 0 {
|
||||
return NewContinuousVestingAccount(bacc, gacc.StartTime, gacc.EndTime)
|
||||
} else if ga.EndTime != 0 {
|
||||
return NewDelayedVestingAccount(bacc, gacc.EndTime)
|
||||
} else {
|
||||
AddAccountToState(baseAccount)
|
||||
// invalid genesis vesting account provided
|
||||
panic()
|
||||
}
|
||||
}
|
||||
|
||||
return bacc
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -48,6 +48,9 @@ type VestingAccount interface {
|
||||
|
||||
GetVestedCoins(blockTime time.Time) sdk.Coins
|
||||
GetVestingCoins(blockTime time.Time) sdk.Coins
|
||||
|
||||
GetStartTime() int64
|
||||
GetEndTime() int64
|
||||
}
|
||||
|
||||
// AccountDecoder unmarshals account bytes
|
||||
@ -158,7 +161,7 @@ type BaseVestingAccount struct {
|
||||
DelegatedFree sdk.Coins // coins that are vested and delegated
|
||||
DelegatedVesting sdk.Coins // coins that vesting and delegated
|
||||
|
||||
EndTime time.Time // when the coins become unlocked
|
||||
EndTime int64 // when the coins become unlocked
|
||||
}
|
||||
|
||||
// spendableCoins returns all the spendable coins for a vesting account given a
|
||||
@ -320,21 +323,16 @@ var _ VestingAccount = (*ContinuousVestingAccount)(nil)
|
||||
type ContinuousVestingAccount struct {
|
||||
*BaseVestingAccount
|
||||
|
||||
StartTime time.Time // when the coins start to vest
|
||||
StartTime int64 // when the coins start to vest
|
||||
}
|
||||
|
||||
func NewContinuousVestingAccount(
|
||||
addr sdk.AccAddress, origCoins sdk.Coins, StartTime, EndTime time.Time,
|
||||
baseAcc *BaseAccount, StartTime, EndTime int64,
|
||||
) *ContinuousVestingAccount {
|
||||
|
||||
baseAcc := &BaseAccount{
|
||||
Address: addr,
|
||||
Coins: origCoins,
|
||||
}
|
||||
|
||||
baseVestingAcc := &BaseVestingAccount{
|
||||
BaseAccount: baseAcc,
|
||||
OriginalVesting: origCoins,
|
||||
OriginalVesting: baseAcc.Coins,
|
||||
EndTime: EndTime,
|
||||
}
|
||||
|
||||
@ -352,13 +350,15 @@ func (cva ContinuousVestingAccount) GetVestedCoins(blockTime time.Time) sdk.Coin
|
||||
// We must handle the case where the start time for a vesting account has
|
||||
// been set into the future or when the start of the chain is not exactly
|
||||
// known.
|
||||
if blockTime.Unix() <= cva.StartTime.Unix() {
|
||||
if blockTime.Unix() <= cva.StartTime {
|
||||
return vestedCoins
|
||||
} else if blockTime.Unix() >= cva.EndTime {
|
||||
return cva.OriginalVesting
|
||||
}
|
||||
|
||||
// calculate the vesting scalar
|
||||
x := int64(blockTime.Sub(cva.StartTime).Seconds())
|
||||
y := int64(cva.EndTime.Sub(cva.StartTime).Seconds())
|
||||
x := blockTime.Unix() - cva.StartTime
|
||||
y := cva.EndTime - cva.StartTime
|
||||
s := sdk.NewDec(x).Quo(sdk.NewDec(y))
|
||||
|
||||
for _, ovc := range cva.OriginalVesting {
|
||||
@ -388,6 +388,17 @@ func (cva *ContinuousVestingAccount) TrackDelegation(blockTime time.Time, amount
|
||||
cva.trackDelegation(cva.GetVestingCoins(blockTime), amount)
|
||||
}
|
||||
|
||||
// GetStartTime returns the time when vesting starts for a continuous vesting
|
||||
// account.
|
||||
func (cva *ContinuousVestingAccount) GetStartTime() int64 {
|
||||
return cva.StartTime
|
||||
}
|
||||
|
||||
// GetEndTime returns the time when vesting ends for a continuous vesting account.
|
||||
func (cva *ContinuousVestingAccount) GetEndTime() int64 {
|
||||
return cva.EndTime
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Delayed Vesting Account
|
||||
|
||||
@ -400,18 +411,10 @@ type DelayedVestingAccount struct {
|
||||
*BaseVestingAccount
|
||||
}
|
||||
|
||||
func NewDelayedVestingAccount(
|
||||
addr sdk.AccAddress, origCoins sdk.Coins, EndTime time.Time,
|
||||
) *DelayedVestingAccount {
|
||||
|
||||
baseAcc := &BaseAccount{
|
||||
Address: addr,
|
||||
Coins: origCoins,
|
||||
}
|
||||
|
||||
func NewDelayedVestingAccount(baseAcc *BaseAccount, EndTime int64) *DelayedVestingAccount {
|
||||
baseVestingAcc := &BaseVestingAccount{
|
||||
BaseAccount: baseAcc,
|
||||
OriginalVesting: origCoins,
|
||||
OriginalVesting: baseAcc.Coins,
|
||||
EndTime: EndTime,
|
||||
}
|
||||
|
||||
@ -421,7 +424,7 @@ func NewDelayedVestingAccount(
|
||||
// GetVestedCoins returns the total amount of vested coins for a delayed vesting
|
||||
// account. All coins are only vested once the schedule has elapsed.
|
||||
func (dva DelayedVestingAccount) GetVestedCoins(blockTime time.Time) sdk.Coins {
|
||||
if blockTime.Unix() >= dva.EndTime.Unix() {
|
||||
if blockTime.Unix() >= dva.EndTime {
|
||||
return dva.OriginalVesting
|
||||
}
|
||||
|
||||
@ -447,6 +450,16 @@ func (dva *DelayedVestingAccount) TrackDelegation(blockTime time.Time, amount sd
|
||||
dva.trackDelegation(dva.GetVestingCoins(blockTime), amount)
|
||||
}
|
||||
|
||||
// GetStartTime returns zero since a delayed vesting account has no start time.
|
||||
func (dva *DelayedVestingAccount) GetStartTime() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetEndTime returns the time when vesting ends for a delayed vesting account.
|
||||
func (dva *DelayedVestingAccount) GetEndTime() int64 {
|
||||
return dva.EndTime
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Codec
|
||||
|
||||
|
||||
@ -108,7 +108,9 @@ func TestGetVestedCoinsContVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
cva := NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
|
||||
// require no coins vested in the very beginning of the vesting schedule
|
||||
vestedCoins := cva.GetVestedCoins(now)
|
||||
@ -121,6 +123,10 @@ func TestGetVestedCoinsContVestingAcc(t *testing.T) {
|
||||
// require 50% of coins vested
|
||||
vestedCoins = cva.GetVestedCoins(now.Add(12 * time.Hour))
|
||||
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(testDenom, 50)}, vestedCoins)
|
||||
|
||||
// require 100% of coins vested
|
||||
vestedCoins = cva.GetVestedCoins(now.Add(48 * time.Hour))
|
||||
require.Equal(t, origCoins, vestedCoins)
|
||||
}
|
||||
|
||||
func TestGetVestingCoinsContVestingAcc(t *testing.T) {
|
||||
@ -129,7 +135,9 @@ func TestGetVestingCoinsContVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
cva := NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
|
||||
// require all coins vesting in the beginning of the vesting schedule
|
||||
vestingCoins := cva.GetVestingCoins(now)
|
||||
@ -150,7 +158,9 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
cva := NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
bacc := 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
|
||||
@ -188,23 +198,27 @@ func TestTrackDelegationContVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
|
||||
// require the ability to delegate all vesting coins
|
||||
cva := NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
cva.TrackDelegation(now, origCoins)
|
||||
require.Equal(t, origCoins, cva.DelegatedVesting)
|
||||
require.Nil(t, cva.DelegatedFree)
|
||||
require.Nil(t, cva.GetCoins())
|
||||
|
||||
// require the ability to delegate all vested coins
|
||||
cva = NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
cva.TrackDelegation(endTime, origCoins)
|
||||
require.Nil(t, cva.DelegatedVesting)
|
||||
require.Equal(t, origCoins, cva.DelegatedFree)
|
||||
require.Nil(t, cva.GetCoins())
|
||||
|
||||
// require the ability to delegate all vesting coins (50%) and all vested coins (50%)
|
||||
cva = NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(testDenom, 50)})
|
||||
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(testDenom, 50)}, cva.DelegatedVesting)
|
||||
require.Nil(t, cva.DelegatedFree)
|
||||
@ -215,7 +229,8 @@ func TestTrackDelegationContVestingAcc(t *testing.T) {
|
||||
require.Nil(t, cva.GetCoins())
|
||||
|
||||
// require no modifications when delegation amount is zero or not enough funds
|
||||
cva = NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
require.Panics(t, func() {
|
||||
cva.TrackDelegation(endTime, sdk.Coins{sdk.NewInt64Coin(testDenom, 1000000)})
|
||||
})
|
||||
@ -230,9 +245,11 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
|
||||
// require the ability to undelegate all vesting coins
|
||||
cva := NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
cva := NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
cva.TrackDelegation(now, origCoins)
|
||||
cva.TrackUndelegation(origCoins)
|
||||
require.Nil(t, cva.DelegatedFree)
|
||||
@ -240,7 +257,9 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) {
|
||||
require.Equal(t, origCoins, cva.GetCoins())
|
||||
|
||||
// require the ability to undelegate all vested coins
|
||||
cva = NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
|
||||
cva.TrackDelegation(endTime, origCoins)
|
||||
cva.TrackUndelegation(origCoins)
|
||||
require.Nil(t, cva.DelegatedFree)
|
||||
@ -248,7 +267,8 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) {
|
||||
require.Equal(t, origCoins, cva.GetCoins())
|
||||
|
||||
// require no modifications when the undelegation amount is zero
|
||||
cva = NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
|
||||
require.Panics(t, func() {
|
||||
cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(testDenom, 0)})
|
||||
@ -258,7 +278,7 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) {
|
||||
require.Equal(t, origCoins, cva.GetCoins())
|
||||
|
||||
// vest 50% and delegate to two validators
|
||||
cva = NewContinuousVestingAccount(addr, origCoins, now, endTime)
|
||||
cva = NewContinuousVestingAccount(&bacc, now.Unix(), endTime.Unix())
|
||||
cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(testDenom, 50)})
|
||||
cva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(testDenom, 50)})
|
||||
|
||||
@ -281,9 +301,11 @@ func TestGetVestedCoinsDelVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
|
||||
// require no coins are vested until schedule maturation
|
||||
dva := NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
dva := NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
vestedCoins := dva.GetVestedCoins(now)
|
||||
require.Nil(t, vestedCoins)
|
||||
|
||||
@ -298,9 +320,11 @@ func TestGetVestingCoinsDelVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
|
||||
// require all coins vesting at the beginning of the schedule
|
||||
dva := NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
dva := NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
vestingCoins := dva.GetVestingCoins(now)
|
||||
require.Equal(t, origCoins, vestingCoins)
|
||||
|
||||
@ -315,10 +339,12 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
|
||||
// require that no coins are spendable in the beginning of the vesting
|
||||
// schedule
|
||||
dva := NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
dva := NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
spendableCoins := dva.SpendableCoins(now)
|
||||
require.Nil(t, spendableCoins)
|
||||
|
||||
@ -354,16 +380,20 @@ func TestTrackDelegationDelVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
|
||||
// require the ability to delegate all vesting coins
|
||||
dva := NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
dva := NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
dva.TrackDelegation(now, origCoins)
|
||||
require.Equal(t, origCoins, dva.DelegatedVesting)
|
||||
require.Nil(t, dva.DelegatedFree)
|
||||
require.Nil(t, dva.GetCoins())
|
||||
|
||||
// require the ability to delegate all vested coins
|
||||
dva = NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
dva = NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
dva.TrackDelegation(endTime, origCoins)
|
||||
require.Nil(t, dva.DelegatedVesting)
|
||||
require.Equal(t, origCoins, dva.DelegatedFree)
|
||||
@ -371,14 +401,16 @@ func TestTrackDelegationDelVestingAcc(t *testing.T) {
|
||||
|
||||
// require the ability to delegate all coins half way through the vesting
|
||||
// schedule
|
||||
dva = NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
dva = NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
dva.TrackDelegation(now.Add(12*time.Hour), origCoins)
|
||||
require.Equal(t, origCoins, dva.DelegatedVesting)
|
||||
require.Nil(t, dva.DelegatedFree)
|
||||
require.Nil(t, dva.GetCoins())
|
||||
|
||||
// require no modifications when delegation amount is zero or not enough funds
|
||||
dva = NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
dva = NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
|
||||
require.Panics(t, func() {
|
||||
dva.TrackDelegation(endTime, sdk.Coins{sdk.NewInt64Coin(testDenom, 1000000)})
|
||||
@ -394,9 +426,12 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) {
|
||||
|
||||
_, _, addr := keyPubAddr()
|
||||
origCoins := sdk.Coins{sdk.NewInt64Coin(testDenom, 100)}
|
||||
bacc := NewBaseAccountWithAddress(addr)
|
||||
bacc.SetCoins(origCoins)
|
||||
|
||||
// require the ability to undelegate all vesting coins
|
||||
dva := NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
dva := NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
dva.TrackDelegation(now, origCoins)
|
||||
dva.TrackUndelegation(origCoins)
|
||||
require.Nil(t, dva.DelegatedFree)
|
||||
@ -404,7 +439,8 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) {
|
||||
require.Equal(t, origCoins, dva.GetCoins())
|
||||
|
||||
// require the ability to undelegate all vested coins
|
||||
dva = NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
dva = NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
dva.TrackDelegation(endTime, origCoins)
|
||||
dva.TrackUndelegation(origCoins)
|
||||
require.Nil(t, dva.DelegatedFree)
|
||||
@ -412,7 +448,8 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) {
|
||||
require.Equal(t, origCoins, dva.GetCoins())
|
||||
|
||||
// require no modifications when the undelegation amount is zero
|
||||
dva = NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
dva = NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
|
||||
require.Panics(t, func() {
|
||||
dva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(testDenom, 0)})
|
||||
@ -422,7 +459,8 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) {
|
||||
require.Equal(t, origCoins, dva.GetCoins())
|
||||
|
||||
// vest 50% and delegate to two validators
|
||||
dva = NewDelayedVestingAccount(addr, origCoins, endTime)
|
||||
bacc.SetCoins(origCoins)
|
||||
dva = NewDelayedVestingAccount(&bacc, endTime.Unix())
|
||||
dva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(testDenom, 50)})
|
||||
dva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(testDenom, 50)})
|
||||
|
||||
|
||||
@ -8,6 +8,10 @@ import (
|
||||
func RegisterCodec(cdc *codec.Codec) {
|
||||
cdc.RegisterInterface((*Account)(nil), nil)
|
||||
cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil)
|
||||
cdc.RegisterInterface((*VestingAccount)(nil), nil)
|
||||
cdc.RegisterConcrete(&BaseVestingAccount{}, "auth/BaseVestingAccount", nil)
|
||||
cdc.RegisterConcrete(&ContinuousVestingAccount{}, "auth/ContinuousVestingAccount", nil)
|
||||
cdc.RegisterConcrete(&DelayedVestingAccount{}, "auth/DelayedVestingAccount", nil)
|
||||
cdc.RegisterConcrete(StdTx{}, "auth/StdTx", nil)
|
||||
}
|
||||
|
||||
|
||||
@ -213,7 +213,9 @@ func TestVestingAccountSend(t *testing.T) {
|
||||
|
||||
addr1 := sdk.AccAddress([]byte("addr1"))
|
||||
addr2 := sdk.AccAddress([]byte("addr2"))
|
||||
vacc := auth.NewContinuousVestingAccount(addr1, origCoins, ctx.BlockHeader().Time, endTime)
|
||||
bacc := auth.NewBaseAccountWithAddress(addr1)
|
||||
bacc.SetCoins(origCoins)
|
||||
vacc := auth.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix())
|
||||
input.ak.SetAccount(ctx, vacc)
|
||||
|
||||
// require that no coins be sendable at the beginning of the vesting schedule
|
||||
@ -245,7 +247,9 @@ func TestVestingAccountReceive(t *testing.T) {
|
||||
addr1 := sdk.AccAddress([]byte("addr1"))
|
||||
addr2 := sdk.AccAddress([]byte("addr2"))
|
||||
|
||||
vacc := auth.NewContinuousVestingAccount(addr1, origCoins, ctx.BlockHeader().Time, endTime)
|
||||
bacc := auth.NewBaseAccountWithAddress(addr1)
|
||||
bacc.SetCoins(origCoins)
|
||||
vacc := auth.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix())
|
||||
acc := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
input.ak.SetAccount(ctx, vacc)
|
||||
input.ak.SetAccount(ctx, acc)
|
||||
@ -276,7 +280,9 @@ func TestDelegateCoins(t *testing.T) {
|
||||
addr1 := sdk.AccAddress([]byte("addr1"))
|
||||
addr2 := sdk.AccAddress([]byte("addr2"))
|
||||
|
||||
vacc := auth.NewContinuousVestingAccount(addr1, origCoins, ctx.BlockHeader().Time, endTime)
|
||||
bacc := auth.NewBaseAccountWithAddress(addr1)
|
||||
bacc.SetCoins(origCoins)
|
||||
vacc := auth.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix())
|
||||
acc := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
input.ak.SetAccount(ctx, vacc)
|
||||
input.ak.SetAccount(ctx, acc)
|
||||
@ -310,7 +316,9 @@ func TestUndelegateCoins(t *testing.T) {
|
||||
addr1 := sdk.AccAddress([]byte("addr1"))
|
||||
addr2 := sdk.AccAddress([]byte("addr2"))
|
||||
|
||||
vacc := auth.NewContinuousVestingAccount(addr1, origCoins, ctx.BlockHeader().Time, endTime)
|
||||
bacc := auth.NewBaseAccountWithAddress(addr1)
|
||||
bacc.SetCoins(origCoins)
|
||||
vacc := auth.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix())
|
||||
acc := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
input.ak.SetAccount(ctx, vacc)
|
||||
input.ak.SetAccount(ctx, acc)
|
||||
|
||||
@ -64,7 +64,7 @@ func createSingleInputSendMsg(r *rand.Rand, ctx sdk.Context, accs []simulation.A
|
||||
toAcc = simulation.RandomAcc(r, accs)
|
||||
}
|
||||
toAddr := toAcc.Address
|
||||
initFromCoins := mapper.GetAccount(ctx, fromAcc.Address).GetCoins()
|
||||
initFromCoins := mapper.GetAccount(ctx, fromAcc.Address).SpendableCoins(ctx.BlockHeader().Time)
|
||||
|
||||
if len(initFromCoins) == 0 {
|
||||
return fromAcc, "skipping, no coins at all", msg, true
|
||||
|
||||
@ -44,8 +44,10 @@ func RandomAccounts(r *rand.Rand, n int) []Account {
|
||||
} else {
|
||||
accs[i].PrivKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
|
||||
}
|
||||
|
||||
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
||||
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
||||
}
|
||||
|
||||
return accs
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
// AppStateFn returns the app state json bytes
|
||||
type AppStateFn func(r *rand.Rand, accs []Account) json.RawMessage
|
||||
type AppStateFn func(r *rand.Rand, accs []Account, genesisTimestamp time.Time) json.RawMessage
|
||||
|
||||
// Simulate tests application by sending random messages.
|
||||
func Simulate(t *testing.T, app *baseapp.BaseApp,
|
||||
@ -32,12 +32,13 @@ func Simulate(t *testing.T, app *baseapp.BaseApp,
|
||||
}
|
||||
|
||||
// initialize the chain for the simulation
|
||||
func initChain(r *rand.Rand, params Params, accounts []Account,
|
||||
app *baseapp.BaseApp,
|
||||
appStateFn AppStateFn) mockValidators {
|
||||
func initChain(
|
||||
r *rand.Rand, params Params, accounts []Account,
|
||||
app *baseapp.BaseApp, appStateFn AppStateFn, genesisTimestamp time.Time,
|
||||
) mockValidators {
|
||||
|
||||
req := abci.RequestInitChain{
|
||||
AppStateBytes: appStateFn(r, accounts),
|
||||
AppStateBytes: appStateFn(r, accounts, genesisTimestamp),
|
||||
}
|
||||
res := app.InitChain(req)
|
||||
validators := newMockValidators(r, res.Validators, params)
|
||||
@ -62,9 +63,9 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||
params := RandomParams(r) // := DefaultParams()
|
||||
fmt.Printf("Randomized simulation params: %+v\n", params)
|
||||
|
||||
timestamp := RandTimestamp(r)
|
||||
genesisTimestamp := RandTimestamp(r)
|
||||
fmt.Printf("Starting the simulation from time %v, unixtime %v\n",
|
||||
timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
|
||||
genesisTimestamp.UTC().Format(time.UnixDate), genesisTimestamp.Unix())
|
||||
|
||||
timeDiff := maxTimePerBlock - minTimePerBlock
|
||||
accs := RandomAccounts(r, params.NumKeys)
|
||||
@ -72,12 +73,12 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||
|
||||
// Second variable to keep pending validator set (delayed one block since
|
||||
// TM 0.24) Initially this is the same as the initial validator set
|
||||
validators := initChain(r, params, accs, app, appStateFn)
|
||||
validators := initChain(r, params, accs, app, appStateFn, genesisTimestamp)
|
||||
nextValidators := validators
|
||||
|
||||
header := abci.Header{
|
||||
Height: 1,
|
||||
Time: timestamp,
|
||||
Time: genesisTimestamp,
|
||||
ProposerAddress: validators.randomProposer(r),
|
||||
}
|
||||
opCount := 0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user