mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-27 16:55:21 +00:00
373 lines
11 KiB
Go
373 lines
11 KiB
Go
package validatorvesting
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
tmtime "github.com/tendermint/tendermint/types/time"
|
|
|
|
"github.com/cosmos/cosmos-sdk/x/staking"
|
|
stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported"
|
|
|
|
"github.com/kava-labs/kava/x/validator-vesting/keeper"
|
|
"github.com/kava-labs/kava/x/validator-vesting/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()
|
|
|
|
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 having signed
|
|
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, 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,
|
|
LastCommitInfo: abci.LastCommitInfo{
|
|
Votes: []abci.VoteInfo{{
|
|
Validator: val,
|
|
SignedLastBlock: false,
|
|
}},
|
|
},
|
|
}
|
|
|
|
BeginBlocker(ctx, req, vvk)
|
|
height++
|
|
blockTime = addHour(blockTime)
|
|
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
|
|
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,
|
|
LastCommitInfo: abci.LastCommitInfo{
|
|
Votes: []abci.VoteInfo{{
|
|
Validator: abci.Validator{},
|
|
SignedLastBlock: true,
|
|
}},
|
|
},
|
|
}
|
|
|
|
BeginBlocker(ctx, req, vvk)
|
|
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
|
|
require.Equal(t, types.CurrentPeriodProgress{2, 4}, vva.CurrentPeriodProgress)
|
|
}
|
|
|
|
func TestBeginBlockerSuccessfulPeriod(t *testing.T) {
|
|
height := int64(1)
|
|
now := tmtime.Now()
|
|
blockTime := now
|
|
numBlocks := int64(14)
|
|
addHour := func(t time.Time) time.Time { return t.Add(1 * time.Hour) }
|
|
ctx, ak, _, stakingKeeper, _, vvk := keeper.CreateTestInput(t, false, 1000)
|
|
|
|
vva := keeper.ValidatorVestingDelegatorTestAccount(now)
|
|
|
|
ak.SetAccount(ctx, vva)
|
|
vvk.SetValidatorVestingAccountKey(ctx, vva.Address)
|
|
|
|
keeper.CreateValidators(ctx, stakingKeeper, []int64{5, 5, 5})
|
|
|
|
val1, found := stakingKeeper.GetValidator(ctx, keeper.ValOpAddr1)
|
|
require.True(t, found)
|
|
|
|
_ = staking.EndBlocker(ctx, stakingKeeper)
|
|
|
|
val := abci.Validator{
|
|
Address: val1.ConsPubKey.Address(),
|
|
Power: val1.ConsensusPower(),
|
|
}
|
|
|
|
vva.ValidatorAddress = val1.ConsAddress()
|
|
ak.SetAccount(ctx, vva)
|
|
|
|
for ; height < numBlocks; height++ {
|
|
header := abci.Header{Height: height, Time: addHour(blockTime)}
|
|
// mark the validator as having signed
|
|
req := abci.RequestBeginBlock{
|
|
Header: header,
|
|
LastCommitInfo: abci.LastCommitInfo{
|
|
Votes: []abci.VoteInfo{{
|
|
Validator: val,
|
|
SignedLastBlock: true,
|
|
}},
|
|
},
|
|
}
|
|
ctx = ctx.WithBlockHeader(header)
|
|
BeginBlocker(ctx, req, vvk)
|
|
blockTime = addHour(blockTime)
|
|
|
|
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)
|
|
}
|
|
|
|
}
|
|
|
|
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
|
|
// t.Log(vva.MarshalYAML())
|
|
require.Equal(t, []types.VestingProgress{{true, true}, {false, false}, {false, false}}, vva.VestingPeriodProgress)
|
|
}
|
|
|
|
func TestBeginBlockerUnsuccessfulPeriod(t *testing.T) {
|
|
height := int64(1)
|
|
now := tmtime.Now()
|
|
blockTime := now
|
|
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)
|
|
|
|
initialSupply := supplyKeeper.GetSupply(ctx).GetTotal()
|
|
keeper.CreateValidators(ctx, stakingKeeper, []int64{5, 5, 5})
|
|
|
|
vva := keeper.ValidatorVestingDelegatorTestAccount(now)
|
|
|
|
ak.SetAccount(ctx, vva)
|
|
// delegate all coins
|
|
delTokens := sdk.TokensFromConsensusPower(60)
|
|
vvk.SetValidatorVestingAccountKey(ctx, vva.Address)
|
|
|
|
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)
|
|
|
|
// note that delegation modifies the account's state!
|
|
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
|
|
|
|
val := abci.Validator{
|
|
Address: val1.ConsPubKey.Address(),
|
|
Power: val1.ConsensusPower(),
|
|
}
|
|
|
|
vva.ValidatorAddress = val1.ConsAddress()
|
|
ak.SetAccount(ctx, vva)
|
|
|
|
// run one period's worth of blocks
|
|
for ; height < numBlocks; height++ {
|
|
header := abci.Header{Height: height, Time: addHour(blockTime)}
|
|
// mark the validator as having missed
|
|
req := abci.RequestBeginBlock{
|
|
Header: header,
|
|
LastCommitInfo: abci.LastCommitInfo{
|
|
Votes: []abci.VoteInfo{{
|
|
Validator: val,
|
|
SignedLastBlock: false,
|
|
}},
|
|
},
|
|
}
|
|
ctx = ctx.WithBlockHeader(header)
|
|
BeginBlocker(ctx, req, vvk)
|
|
blockTime = addHour(blockTime)
|
|
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
|
|
}
|
|
|
|
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
|
|
// check that the period was unsuccessful
|
|
require.Equal(t, []types.VestingProgress{{true, false}, {false, false}, {false, false}}, vva.VestingPeriodProgress)
|
|
// check that there is debt after the period.
|
|
require.Equal(t, sdk.Coins{sdk.NewInt64Coin("stake", 30000000)}, vva.DebtAfterFailedVesting)
|
|
|
|
var delegations int
|
|
stakingKeeper.IterateDelegations(ctx, vva.Address, func(index int64, d stakingexported.DelegationI) (stop bool) {
|
|
delegations++
|
|
return false
|
|
})
|
|
// require that all delegations were unbonded
|
|
require.Equal(t, 0, delegations)
|
|
|
|
// complete the unbonding period
|
|
header := abci.Header{Height: height, Time: blockTime.Add(time.Hour * 2)}
|
|
req := abci.RequestBeginBlock{
|
|
Header: header,
|
|
LastCommitInfo: abci.LastCommitInfo{
|
|
Votes: []abci.VoteInfo{{
|
|
Validator: val,
|
|
SignedLastBlock: false,
|
|
}},
|
|
},
|
|
}
|
|
ctx = ctx.WithBlockHeader(header)
|
|
BeginBlocker(ctx, req, vvk)
|
|
_ = staking.EndBlocker(ctx, stakingKeeper)
|
|
|
|
header = abci.Header{Height: height, Time: blockTime.Add(time.Hour * 2)}
|
|
req = abci.RequestBeginBlock{
|
|
Header: header,
|
|
LastCommitInfo: abci.LastCommitInfo{
|
|
Votes: []abci.VoteInfo{{
|
|
Validator: val,
|
|
SignedLastBlock: false,
|
|
}},
|
|
},
|
|
}
|
|
ctx = ctx.WithBlockHeader(header)
|
|
BeginBlocker(ctx, req, vvk)
|
|
vva = vvk.GetAccountFromAuthKeeper(ctx, vva.Address)
|
|
// require that debt has reset to zero and coins balance is reduced by period 1 amount.
|
|
require.Equal(t, vva.GetCoins(), sdk.Coins{sdk.NewInt64Coin("stake", 30000000)})
|
|
require.Equal(t, sdk.Coins(nil), vva.DebtAfterFailedVesting)
|
|
// require that the supply has decreased by period 1 amount
|
|
require.Equal(t, initialSupply.Sub(vva.VestingPeriods[0].Amount), supplyKeeper.GetSupply(ctx).GetTotal())
|
|
}
|