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:
Alexander Bezobchuk 2019-01-17 11:15:13 -05:00 committed by Christopher Goes
parent 20bcacfaf4
commit f2e87ad81f
13 changed files with 247 additions and 115 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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) {

View File

@ -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

View File

@ -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
}
```

View File

@ -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

View File

@ -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)})

View File

@ -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)
}

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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