rebase, handle first block

This commit is contained in:
Kevin Davis 2019-10-09 18:42:23 -04:00
parent 49279a3ce5
commit 3908870761
10 changed files with 215 additions and 45 deletions

View File

@ -94,9 +94,12 @@ func AddGenesisAccountCmd(
baseAccount := auth.NewBaseAccount(addr, coins.Sort(), nil, 0, 0)
if !vestingAmt.IsZero() {
baseVestingAccount := vesting.NewBaseVestingAccount(
baseVestingAccount, err := vesting.NewBaseVestingAccount(
baseAccount, vestingAmt.Sort(), vestingEnd,
)
if err != nil {
return fmt.Errorf("Failed to create base vesting account: %w", err)
}
switch {
case vestingPeriodsFile != "":

View File

@ -24,24 +24,31 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper)
validatorVestingKeys := k.GetAllAccountKeys(ctx)
for _, key := range validatorVestingKeys {
acc := k.GetAccountFromAuthKeeper(ctx, key)
vote, found := voteInfos.FilterByValidatorAddress(acc.ValidatorAddress)
if !found || !vote.SignedLastBlock {
// if the validator was not found or explicitly didn't sign, increment the missing sign count
k.UpdateMissingSignCount(ctx, acc.GetAddress(), true)
} else {
k.UpdateMissingSignCount(ctx, acc.GetAddress(), false)
}
// check if a period ended in the last block
endTimes := k.GetPeriodEndTimes(ctx, key)
for i, t := range endTimes {
if currentBlockTime.Unix() >= t && previousBlockTime.Unix() < t {
k.UpdateVestedCoinsProgress(ctx, key, i)
if k.AccountIsVesting(ctx, acc.GetAddress()) {
vote, found := voteInfos.FilterByValidatorAddress(acc.ValidatorAddress)
if !found || !vote.SignedLastBlock {
if ctx.BlockHeight() <= 1 {
// don't count missed blocks on block 1 since there is no vote history
k.UpdateMissingSignCount(ctx, acc.GetAddress(), false)
} else {
// if the validator was not found or explicitly didn't sign, increment the missing sign count
k.UpdateMissingSignCount(ctx, acc.GetAddress(), true)
}
} else {
k.UpdateMissingSignCount(ctx, acc.GetAddress(), false)
}
// check if a period ended in the last block
endTimes := k.GetPeriodEndTimes(ctx, key)
for i, t := range endTimes {
if currentBlockTime.Unix() >= t && previousBlockTime.Unix() < t {
k.UpdateVestedCoinsProgress(ctx, key, i)
}
}
// handle any new/remaining debt on the account
k.HandleVestingDebt(ctx, key, currentBlockTime)
}
// handle any new/remaining debt on the account
k.HandleVestingDebt(ctx, key, currentBlockTime)
}
k.SetPreviousBlockTime(ctx, currentBlockTime)
}

View File

@ -15,6 +15,81 @@ import (
"github.com/kava-labs/kava/x/validator-vesting/internal/types"
)
func TestBeginBlockerZeroHeight(t *testing.T) {
ctx, ak, _, stakingKeeper, _, vvk := keeper.CreateTestInput(t, false, 1000)
now := tmtime.Now()
vva := keeper.ValidatorVestingDelegatorTestAccount(now)
ak.SetAccount(ctx, vva)
delTokens := sdk.TokensFromConsensusPower(30)
vvk.SetValidatorVestingAccountKey(ctx, vva.Address)
keeper.CreateValidators(ctx, stakingKeeper, []int64{5, 5, 5})
val1, found := stakingKeeper.GetValidator(ctx, keeper.ValOpAddr1)
require.True(t, found)
_, err := stakingKeeper.Delegate(ctx, vva.Address, delTokens, sdk.Unbonded, val1, true)
require.NoError(t, err)
_ = staking.EndBlocker(ctx, stakingKeeper)
// require that there exists one delegation
var delegations int
stakingKeeper.IterateDelegations(ctx, vva.Address, func(index int64, d stakingexported.DelegationI) (stop bool) {
delegations++
return false
})
require.Equal(t, 1, delegations)
val := abci.Validator{
Address: val1.ConsPubKey.Address(),
Power: val1.ConsensusPower(),
}
vva.ValidatorAddress = val1.ConsAddress()
ak.SetAccount(ctx, vva)
height := int64(1)
blockTime := now
addHour := func(t time.Time) time.Time { return t.Add(1 * time.Hour) }
header := abci.Header{Height: height, Time: addHour(blockTime)}
ctx = ctx.WithBlockHeader(header)
// mark the validator as absent
req := abci.RequestBeginBlock{
Header: header,
LastCommitInfo: abci.LastCommitInfo{
Votes: []abci.VoteInfo{{
Validator: abci.Validator{},
SignedLastBlock: false,
}},
},
}
BeginBlocker(ctx, req, vvk)
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
// require missed block counter doesn't increment because there's no voting history
require.Equal(t, types.CurrentPeriodProgress{0, 1}, vva.CurrentPeriodProgress)
// mark the validator as having missed
req = abci.RequestBeginBlock{
Header: header,
LastCommitInfo: abci.LastCommitInfo{
Votes: []abci.VoteInfo{{
Validator: val,
SignedLastBlock: false,
}},
},
}
BeginBlocker(ctx, req, vvk)
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
require.Equal(t, types.CurrentPeriodProgress{0, 2}, vva.CurrentPeriodProgress)
}
func TestBeginBlockerSignedBlock(t *testing.T) {
ctx, ak, _, stakingKeeper, _, vvk := keeper.CreateTestInput(t, false, 1000)
now := tmtime.Now()
@ -51,13 +126,13 @@ func TestBeginBlockerSignedBlock(t *testing.T) {
vva.ValidatorAddress = val1.ConsAddress()
ak.SetAccount(ctx, vva)
height := int64(0)
height := int64(1)
blockTime := now
addHour := func(t time.Time) time.Time { return t.Add(1 * time.Hour) }
header := abci.Header{Height: height, Time: addHour(blockTime)}
ctx = ctx.WithBlockHeader(header)
// mark the validator as having signed
req := abci.RequestBeginBlock{
Header: header,
@ -76,7 +151,26 @@ func TestBeginBlockerSignedBlock(t *testing.T) {
require.Equal(t, types.CurrentPeriodProgress{0, 1}, vva.CurrentPeriodProgress)
header = abci.Header{Height: height, Time: addHour(blockTime)}
// mark the validator as having signed
ctx = ctx.WithBlockHeader(header)
req = abci.RequestBeginBlock{
Header: header,
LastCommitInfo: abci.LastCommitInfo{
Votes: []abci.VoteInfo{{
Validator: val,
SignedLastBlock: true,
}},
},
}
BeginBlocker(ctx, req, vvk)
height++
blockTime = addHour(blockTime)
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
require.Equal(t, types.CurrentPeriodProgress{0, 2}, vva.CurrentPeriodProgress)
header = abci.Header{Height: height, Time: addHour(blockTime)}
ctx = ctx.WithBlockHeader(header)
// mark the validator as having missed
req = abci.RequestBeginBlock{
Header: header,
@ -92,8 +186,10 @@ func TestBeginBlockerSignedBlock(t *testing.T) {
height++
blockTime = addHour(blockTime)
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
require.Equal(t, types.CurrentPeriodProgress{1, 2}, vva.CurrentPeriodProgress)
require.Equal(t, types.CurrentPeriodProgress{1, 3}, vva.CurrentPeriodProgress)
header = abci.Header{Height: height, Time: addHour(blockTime)}
ctx = ctx.WithBlockHeader(header)
// mark the validator as being absent
req = abci.RequestBeginBlock{
Header: header,
@ -106,14 +202,12 @@ func TestBeginBlockerSignedBlock(t *testing.T) {
}
BeginBlocker(ctx, req, vvk)
height++
blockTime = addHour(blockTime)
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
require.Equal(t, types.CurrentPeriodProgress{2, 3}, vva.CurrentPeriodProgress)
require.Equal(t, types.CurrentPeriodProgress{2, 4}, vva.CurrentPeriodProgress)
}
func TestBeginBlockerSuccessfulPeriod(t *testing.T) {
height := int64(0)
height := int64(1)
now := tmtime.Now()
blockTime := now
numBlocks := int64(14)
@ -156,7 +250,7 @@ func TestBeginBlockerSuccessfulPeriod(t *testing.T) {
BeginBlocker(ctx, req, vvk)
blockTime = addHour(blockTime)
if height == 11 {
if height == 12 {
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
// require that missing sign count is set back to zero after the period increments.
require.Equal(t, types.CurrentPeriodProgress{0, 0}, vva.CurrentPeriodProgress)
@ -170,10 +264,10 @@ func TestBeginBlockerSuccessfulPeriod(t *testing.T) {
}
func TestBeginBlockerUnsuccessfulPeriod(t *testing.T) {
height := int64(0)
height := int64(1)
now := tmtime.Now()
blockTime := now
numBlocks := int64(12)
numBlocks := int64(13)
addHour := func(t time.Time) time.Time { return t.Add(1 * time.Hour) }
ctx, ak, _, stakingKeeper, supplyKeeper, vvk := keeper.CreateTestInput(t, false, 1000)

View File

@ -1,7 +1,10 @@
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/kava-labs/kava/x/validator-vesting/internal/types/
// ALIASGEN: github.com/kava-labs/kava/x/validator-vesting/internal/keeper/
package validatorvesting
// nolint
// DONTCOVER
import (
"github.com/kava-labs/kava/x/validator-vesting/internal/keeper"
"github.com/kava-labs/kava/x/validator-vesting/internal/types"
@ -13,19 +16,49 @@ const (
)
var (
NewValidatorVestingAccountRaw = types.NewValidatorVestingAccountRaw
NewValidatorVestingAccount = types.NewValidatorVestingAccount
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
RegisterCodec = types.RegisterCodec
ValidatorVestingAccountPrefix = types.ValidatorVestingAccountPrefix
// functions aliases
RegisterCodec = types.RegisterCodec
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
ValidateGenesis = types.ValidateGenesis
ValidatorVestingAccountKey = types.ValidatorVestingAccountKey
CreateTestAddrs = types.CreateTestAddrs
TestAddr = types.TestAddr
CreateTestPubKeys = types.CreateTestPubKeys
NewPubKey = types.NewPubKey
NewValidatorVestingAccountRaw = types.NewValidatorVestingAccountRaw
NewValidatorVestingAccount = types.NewValidatorVestingAccount
NewKeeper = keeper.NewKeeper
MakeTestCodec = keeper.MakeTestCodec
CreateTestInput = keeper.CreateTestInput
ValidatorVestingTestAccount = keeper.ValidatorVestingTestAccount
ValidatorVestingTestAccounts = keeper.ValidatorVestingTestAccounts
ValidatorVestingDelegatorTestAccount = keeper.ValidatorVestingDelegatorTestAccount
CreateValidators = keeper.CreateValidators
// variable aliases
ModuleCdc = types.ModuleCdc
BlocktimeKey = types.BlocktimeKey
ValidatorVestingAccountKey = types.ValidatorVestingAccountKey
NewKeeper = keeper.NewKeeper
ValidatorVestingAccountPrefix = types.ValidatorVestingAccountPrefix
ValOpPk1 = keeper.ValOpPk1
ValOpPk2 = keeper.ValOpPk2
ValOpPk3 = keeper.ValOpPk3
ValOpAddr1 = keeper.ValOpAddr1
ValOpAddr2 = keeper.ValOpAddr2
ValOpAddr3 = keeper.ValOpAddr3
ValConsPk11 = keeper.ValConsPk11
ValConsPk12 = keeper.ValConsPk12
ValConsPk13 = keeper.ValConsPk13
ValConsAddr1 = keeper.ValConsAddr1
ValConsAddr2 = keeper.ValConsAddr2
ValConsAddr3 = keeper.ValConsAddr3
TestAddrs = keeper.TestAddrs
)
type (
GenesisState = types.GenesisState
Keeper = keeper.Keeper
VestingProgress = types.VestingProgress
CurrentPeriodProgress = types.CurrentPeriodProgress
ValidatorVestingAccount = types.ValidatorVestingAccount
Keeper = keeper.Keeper
)

View File

@ -135,12 +135,14 @@ func (k Keeper) SetVestingProgress(ctx sdk.Context, addr sdk.AccAddress, period
k.ak.SetAccount(ctx, vv)
}
// AddDebt adds the input amount to DebtAfterFailedVesting field
func (k Keeper) AddDebt(ctx sdk.Context, addr sdk.AccAddress, amount sdk.Coins) {
vv := k.GetAccountFromAuthKeeper(ctx, addr)
vv.DebtAfterFailedVesting = vv.DebtAfterFailedVesting.Add(amount)
k.ak.SetAccount(ctx, vv)
}
// ResetCurrentPeriodProgress resets CurrentPeriodProgress to zero values
func (k Keeper) ResetCurrentPeriodProgress(ctx sdk.Context, addr sdk.AccAddress) {
vv := k.GetAccountFromAuthKeeper(ctx, addr)
vv.CurrentPeriodProgress = types.CurrentPeriodProgress{TotalBlocks: 0, MissedBlocks: 0}
@ -202,3 +204,17 @@ func (k Keeper) GetPeriodEndTimes(ctx sdk.Context, addr sdk.AccAddress) []int64
}
return endTimes
}
// AccountIsVesting returns true if all vesting periods is complete and there is no debt
func (k Keeper) AccountIsVesting(ctx sdk.Context, addr sdk.AccAddress) bool {
vv := k.GetAccountFromAuthKeeper(ctx, addr)
if !vv.DebtAfterFailedVesting.IsZero() {
return false
}
for _, p := range vv.VestingPeriodProgress {
if !p.PeriodComplete {
return false
}
}
return true
}

View File

@ -102,6 +102,25 @@ func TestGetEndTImes(t *testing.T) {
require.Equal(t, expectedEndTimes, endTimes)
}
func TestAccountIsVesting(t *testing.T) {
ctx, ak, _, _, _, keeper := CreateTestInput(t, false, 1000)
now := tmtime.Now()
vva := ValidatorVestingDelegatorTestAccount(now)
ak.SetAccount(ctx, vva)
keeper.SetValidatorVestingAccountKey(ctx, vva.Address)
require.Equal(t, false, keeper.AccountIsVesting(ctx, vva.Address))
for i := range vva.VestingPeriodProgress {
vva.VestingPeriodProgress[i] = types.VestingProgress{true, true}
ak.SetAccount(ctx, vva)
}
require.Equal(t, true, keeper.AccountIsVesting(ctx, vva.Address))
}
func TestSetMissingSignCount(t *testing.T) {
ctx, ak, _, _, _, keeper := CreateTestInput(t, false, 1000)
@ -142,7 +161,7 @@ func TestUpdateVestedCoinsProgress(t *testing.T) {
vva = keeper.GetAccountFromAuthKeeper(ctx, vva.Address)
keeper.UpdateVestedCoinsProgress(ctx, vva.Address, 0)
vva = keeper.GetAccountFromAuthKeeper(ctx, vva.Address)
// require that debt is zero
// require that debt is zerox
require.Equal(t, sdk.Coins(nil), vva.DebtAfterFailedVesting)
// require that the first vesting progress variable is successful
require.Equal(t, []types.VestingProgress{types.VestingProgress{true, true}, types.VestingProgress{false, false}, types.VestingProgress{false, false}}, vva.VestingPeriodProgress)

View File

@ -32,7 +32,7 @@ type VestingProgress struct {
// CurrentPeriodProgress tracks the progress of the current vesting period
type CurrentPeriodProgress struct {
MissedBlocks int64 `json:"missed_blocks" yaml:"missed_blocks"`
TotalBlocks int64 `json:"total_blocks" yaml:"total_blocks`
TotalBlocks int64 `json:"total_blocks" yaml:"total_blocks"`
}
// GetSignedPercentage returns the percentage of blocks signed for the current vesting period
@ -63,7 +63,7 @@ type ValidatorVestingAccount struct {
ValidatorAddress sdk.ConsAddress `json:"validator_address" yaml:"validator_address"`
ReturnAddress sdk.AccAddress `json:"return_address" yaml:"return_address"`
SigningThreshold int64 `json:"signing_threshold" yaml:"signing_threshold"`
CurrentPeriodProgress CurrentPeriodProgress `json:"missing_sign_count" yaml:"missing_sign_count"`
CurrentPeriodProgress CurrentPeriodProgress `json:"current_period_progress" yaml:"current_period_progress"`
VestingPeriodProgress []VestingProgress `json:"vesting_period_progress" yaml:"vesting_period_progress"`
DebtAfterFailedVesting sdk.Coins `json:"debt_after_failed_vesting" yaml:"debt_after_failed_vesting"`
}

View File

@ -35,7 +35,7 @@ func TestNewAccount(t *testing.T) {
origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)}
bacc := auth.NewBaseAccountWithAddress(testAddr)
bacc.SetCoins(origCoins)
bva := vesting.NewBaseVestingAccount(&bacc, origCoins, endTime)
bva, _ := vesting.NewBaseVestingAccount(&bacc, origCoins, endTime)
require.NotPanics(t, func() { NewValidatorVestingAccountRaw(bva, now.Unix(), periods, testConsAddr, nil, 90) })
vva := NewValidatorVestingAccountRaw(bva, now.Unix(), periods, testConsAddr, nil, 90)
vva.PubKey = testPk

View File

@ -3,7 +3,6 @@ package validatorvesting
import (
"encoding/json"
"math/rand"
"os"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -40,7 +39,6 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
// DefaultGenesis returns default genesis state as raw bytes for the validator-vesting
// module.
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
types.ModuleCdc.PrintTypes(os.Stdout)
return types.ModuleCdc.MustMarshalJSON(types.DefaultGenesisState())
}

View File

@ -35,7 +35,7 @@ func RandomizedGenState(simState *module.SimulationState) {
duration := va.GetEndTime() - va.GetStartTime()
vestingPeriods := getRandomVestingPeriods(duration, simState.Rand, va.GetCoins())
vestingCoins := getVestingCoins(vestingPeriods)
bva := vestingtypes.NewBaseVestingAccount(&bacc, vestingCoins, va.GetEndTime())
bva, _ := vestingtypes.NewBaseVestingAccount(&bacc, vestingCoins, va.GetEndTime())
var gacc authexported.GenesisAccount
if simState.Rand.Intn(100) < 50 {
// convert to periodic vesting account 50%