2019-09-23 18:23:00 +00:00
package keeper
import (
2019-09-27 18:48:57 +00:00
"bytes"
2019-09-23 18:23:00 +00:00
"testing"
"time"
"github.com/stretchr/testify/require"
tmtime "github.com/tendermint/tendermint/types/time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported"
2019-10-04 17:55:49 +00:00
"github.com/kava-labs/kava/x/validator-vesting/internal/types"
2019-09-23 18:23:00 +00:00
)
func TestGetSetValidatorVestingAccounts ( t * testing . T ) {
ctx , ak , _ , _ , _ , keeper := CreateTestInput ( t , false , 1000 )
vva := ValidatorVestingTestAccount ( )
// Add the validator vesting account to the auth store
ak . SetAccount ( ctx , vva )
// require that the keeper can set the account key without panic
require . NotPanics ( t , func ( ) { keeper . SetValidatorVestingAccountKey ( ctx , vva . Address ) } )
// require that we can get the account from auth keeper as a validator vesting account.
require . NotPanics ( t , func ( ) { keeper . GetAccountFromAuthKeeper ( ctx , vva . Address ) } )
// fetching a regular account from the auth keeper does not panic
require . NotPanics ( t , func ( ) { ak . GetAccount ( ctx , TestAddrs [ 0 ] ) } )
// fetching a regular account from the validator vesting keeper panics.
require . Panics ( t , func ( ) { keeper . GetAccountFromAuthKeeper ( ctx , TestAddrs [ 0 ] ) } )
// require that GetAllAccountKeys returns one account
keys := keeper . GetAllAccountKeys ( ctx )
require . Equal ( t , 1 , len ( keys ) )
2019-09-27 18:48:57 +00:00
for _ , k := range keys {
2019-10-04 17:55:49 +00:00
require . NotPanics ( t , func ( ) { keeper . GetAccountFromAuthKeeper ( ctx , k ) } )
2019-09-27 18:48:57 +00:00
}
vvAccounts := ValidatorVestingTestAccounts ( 10 )
for _ , a := range vvAccounts {
ak . SetAccount ( ctx , a )
keeper . SetValidatorVestingAccountKey ( ctx , a . Address )
}
keys = keeper . GetAllAccountKeys ( ctx )
require . Equal ( t , 10 , len ( keys ) )
var ikeys [ ] [ ] byte
keeper . IterateAccountKeys ( ctx , func ( accountKey [ ] byte ) bool {
2019-10-04 17:55:49 +00:00
if bytes . Equal ( accountKey [ 1 : ] , keys [ 0 ] ) {
2019-09-27 18:48:57 +00:00
ikeys = append ( ikeys , accountKey )
return true
}
return false
} )
require . Equal ( t , 1 , len ( ikeys ) )
2019-09-23 18:23:00 +00:00
}
func TestGetSetPreviousBlock ( t * testing . T ) {
ctx , _ , _ , _ , _ , keeper := CreateTestInput ( t , false , 1000 )
now := tmtime . Now ( )
// require panic if the previous blocktime was never set
require . Panics ( t , func ( ) { keeper . GetPreviousBlockTime ( ctx ) } )
// require that passing a valid time to SetPreviousBlockTime does not panic
require . NotPanics ( t , func ( ) { keeper . SetPreviousBlockTime ( ctx , now ) } )
// require that the value from GetPreviousBlockTime equals what was set
bpt := keeper . GetPreviousBlockTime ( ctx )
require . Equal ( t , now , bpt )
2019-10-02 13:10:28 +00:00
// require that the zero value is safe
require . NotPanics ( t , func ( ) { keeper . SetPreviousBlockTime ( ctx , tmtime . Canonical ( time . Unix ( 0 , 0 ) ) ) } )
bpt = keeper . GetPreviousBlockTime ( ctx )
require . Equal ( t , tmtime . Canonical ( time . Unix ( 0 , 0 ) ) , bpt )
2019-09-23 18:23:00 +00:00
}
2019-09-27 18:48:57 +00:00
func TestGetEndTImes ( 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 )
expectedEndTimes := [ ] int64 {
now . Add ( 12 * time . Hour ) . Unix ( ) ,
now . Add ( 18 * time . Hour ) . Unix ( ) ,
now . Add ( 24 * time . Hour ) . Unix ( ) ,
}
endTimes := keeper . GetPeriodEndTimes ( ctx , vva . Address )
require . Equal ( t , expectedEndTimes , endTimes )
}
2019-10-09 22:42:23 +00:00
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 ) )
}
2019-09-23 18:23:00 +00:00
func TestSetMissingSignCount ( t * testing . T ) {
ctx , ak , _ , _ , _ , keeper := CreateTestInput ( t , false , 1000 )
vva := ValidatorVestingTestAccount ( )
// Add the validator vesting account to the auth store
ak . SetAccount ( ctx , vva )
// require empty array after ValidatorVestingAccount is initialized
2019-10-04 17:55:49 +00:00
require . Equal ( t , types . CurrentPeriodProgress { 0 , 0 } , vva . CurrentPeriodProgress )
2019-09-23 18:23:00 +00:00
// validator signs a block
keeper . UpdateMissingSignCount ( ctx , vva . Address , false )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
2019-10-04 17:55:49 +00:00
require . Equal ( t , types . CurrentPeriodProgress { 0 , 1 } , vva . CurrentPeriodProgress )
2019-09-23 18:23:00 +00:00
// validator misses a block
keeper . UpdateMissingSignCount ( ctx , vva . Address , true )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
2019-10-04 17:55:49 +00:00
require . Equal ( t , types . CurrentPeriodProgress { 1 , 2 } , vva . CurrentPeriodProgress )
2019-09-23 18:23:00 +00:00
}
func TestUpdateVestedCoinsProgress ( t * testing . T ) {
ctx , ak , _ , _ , _ , keeper := CreateTestInput ( t , false , 1000 )
vva := ValidatorVestingTestAccount ( )
// Add the validator vesting account to the auth store
ak . SetAccount ( ctx , vva )
// require all vesting period tracking variables to be zero after validator vesting account is initialized
2019-10-04 17:55:49 +00:00
require . Equal ( t , [ ] types . VestingProgress { types . VestingProgress { false , false } , types . VestingProgress { false , false } , types . VestingProgress { false , false } } , vva . VestingPeriodProgress )
2019-09-23 18:23:00 +00:00
// period 0 passes with all blocks signed
2019-10-04 17:55:49 +00:00
vva . CurrentPeriodProgress . MissedBlocks = 0
vva . CurrentPeriodProgress . TotalBlocks = 100
2019-09-23 18:23:00 +00:00
ak . SetAccount ( ctx , vva )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
keeper . UpdateVestedCoinsProgress ( ctx , vva . Address , 0 )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
2019-10-09 22:42:23 +00:00
// require that debt is zerox
2019-09-23 18:23:00 +00:00
require . Equal ( t , sdk . Coins ( nil ) , vva . DebtAfterFailedVesting )
2019-10-04 17:55:49 +00:00
// 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 )
2019-09-27 18:48:57 +00:00
// require that the missing block counter has reset
2019-10-04 17:55:49 +00:00
require . Equal ( t , types . CurrentPeriodProgress { 0 , 0 } , vva . CurrentPeriodProgress )
2019-09-27 18:48:57 +00:00
vva = ValidatorVestingTestAccount ( )
ak . SetAccount ( ctx , vva )
// period 0 passes with no blocks signed
// this is an edge case that shouldn't happen,
// the vest is considered successful in this case.
2019-10-04 17:55:49 +00:00
vva . CurrentPeriodProgress . MissedBlocks = 0
vva . CurrentPeriodProgress . TotalBlocks = 0
2019-09-27 18:48:57 +00:00
ak . SetAccount ( ctx , vva )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
keeper . UpdateVestedCoinsProgress ( ctx , vva . Address , 0 )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
// require that debt is zero
require . Equal ( t , sdk . Coins ( nil ) , vva . DebtAfterFailedVesting )
2019-10-04 17:55:49 +00:00
// 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 )
2019-09-23 18:23:00 +00:00
// require that the missing block counter has reset
2019-10-04 17:55:49 +00:00
require . Equal ( t , types . CurrentPeriodProgress { 0 , 0 } , vva . CurrentPeriodProgress )
2019-09-23 18:23:00 +00:00
vva = ValidatorVestingTestAccount ( )
ak . SetAccount ( ctx , vva )
// period 0 passes with 50% of blocks signed (below threshold)
2019-10-04 17:55:49 +00:00
vva . CurrentPeriodProgress . MissedBlocks = 50
vva . CurrentPeriodProgress . TotalBlocks = 100
2019-09-23 18:23:00 +00:00
ak . SetAccount ( ctx , vva )
keeper . UpdateVestedCoinsProgress ( ctx , vva . Address , 0 )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
// require that period 1 coins have become debt
require . Equal ( t , sdk . NewCoins ( sdk . NewInt64Coin ( feeDenom , 500 ) , sdk . NewInt64Coin ( stakeDenom , 50 ) ) , vva . DebtAfterFailedVesting )
2019-10-04 17:55:49 +00:00
// require that the first vesting progress variable is {true, false}
require . Equal ( t , [ ] types . VestingProgress { types . VestingProgress { true , false } , types . VestingProgress { false , false } , types . VestingProgress { false , false } } , vva . VestingPeriodProgress )
2019-09-23 18:23:00 +00:00
// require that the missing block counter has reset
2019-10-04 17:55:49 +00:00
require . Equal ( t , types . CurrentPeriodProgress { 0 , 0 } , vva . CurrentPeriodProgress )
2019-09-23 18:23:00 +00:00
}
2019-09-27 18:48:57 +00:00
func TestHandleVestingDebtNoDebt ( t * testing . T ) {
// ctx, ak, bk, stakingKeeper, supplyKeeper, keeper := CreateTestInput(t, false, 1000)
ctx , ak , _ , _ , _ , keeper := CreateTestInput ( t , false , 1000 )
2019-09-23 18:23:00 +00:00
vva := ValidatorVestingTestAccount ( )
// Delegate all coins
origCoins := sdk . Coins { sdk . NewInt64Coin ( feeDenom , 1000 ) , sdk . NewInt64Coin ( stakeDenom , 100 ) }
now := tmtime . Now ( )
vva . TrackDelegation ( now , origCoins )
// Add the validator vesting account to the auth store
ak . SetAccount ( ctx , vva )
// Require that calling HandleVestingDebt when debt is zero doesn't alter the delegation
keeper . HandleVestingDebt ( ctx , vva . Address , now )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
require . Equal ( t , origCoins , vva . DelegatedVesting )
require . Nil ( t , vva . DelegatedFree )
2019-09-27 18:48:57 +00:00
}
func TestHandleVestingDebtForcedUnbond ( t * testing . T ) {
// ctx, ak, bk, stakingKeeper, supplyKeeper, keeper := CreateTestInput(t, false, 1000)
ctx , ak , _ , stakingKeeper , _ , keeper := CreateTestInput ( t , false , 1000 )
now := tmtime . Now ( )
2019-09-23 18:23:00 +00:00
// Create validators and a delegation from the validator vesting account
CreateValidators ( ctx , stakingKeeper , [ ] int64 { 5 , 5 , 5 } )
2019-09-27 18:48:57 +00:00
vva := ValidatorVestingDelegatorTestAccount ( now )
2019-09-23 18:23:00 +00:00
ak . SetAccount ( ctx , vva )
2019-09-27 18:48:57 +00:00
delTokens := sdk . TokensFromConsensusPower ( 60 )
val1 , found := stakingKeeper . GetValidator ( ctx , ValOpAddr1 )
2019-09-23 18:23:00 +00:00
require . True ( t , found )
_ , err := stakingKeeper . Delegate ( ctx , vva . Address , delTokens , sdk . Unbonded , val1 , true )
require . NoError ( t , err )
_ = staking . EndBlocker ( ctx , stakingKeeper )
2019-09-27 18:48:57 +00:00
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
// t.Log(vva.GetDelegatedFree())
t . Log ( vva . GetDelegatedVesting ( ) )
2019-09-23 18:23:00 +00:00
// 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 )
// period 0 passes and the threshold is not met
2019-10-04 17:55:49 +00:00
vva . CurrentPeriodProgress . MissedBlocks = 50
vva . CurrentPeriodProgress . TotalBlocks = 100
2019-09-23 18:23:00 +00:00
ak . SetAccount ( ctx , vva )
keeper . UpdateVestedCoinsProgress ( ctx , vva . Address , 0 )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
2019-09-27 18:48:57 +00:00
2019-09-23 18:23:00 +00:00
// require that period 0 coins have become debt
require . Equal ( t , sdk . NewCoins ( sdk . NewInt64Coin ( stakeDenom , 30000000 ) ) , vva . DebtAfterFailedVesting )
// when there are no additional liquid coins in the account, require that there are no delegations after HandleVestingDebt (ie the account has been force unbonded)
keeper . HandleVestingDebt ( ctx , vva . Address , now . Add ( 12 * time . Hour ) )
2019-09-27 18:48:57 +00:00
2019-09-23 18:23:00 +00:00
delegations = 0
stakingKeeper . IterateDelegations ( ctx , vva . Address , func ( index int64 , d stakingexported . DelegationI ) ( stop bool ) {
delegations ++
return false
} )
require . Equal ( t , 0 , delegations )
}
func TestHandleVestingDebtBurn ( t * testing . T ) {
ctx , ak , _ , stakingKeeper , supplyKeeper , keeper := CreateTestInput ( t , false , 1000 )
CreateValidators ( ctx , stakingKeeper , [ ] int64 { 5 , 5 , 5 } )
now := tmtime . Now ( )
vva := ValidatorVestingDelegatorTestAccount ( now )
ak . SetAccount ( ctx , vva )
delTokens := sdk . TokensFromConsensusPower ( 30 )
2019-09-27 18:48:57 +00:00
val1 , found := stakingKeeper . GetValidator ( ctx , ValOpAddr1 )
2019-09-23 18:23:00 +00:00
require . True ( t , found )
2019-09-27 18:48:57 +00:00
// delegate half the tokens, which will make the period 1 coins that fail to vest immediately cover the debt.
2019-09-23 18:23:00 +00:00
_ , err := stakingKeeper . Delegate ( ctx , vva . Address , delTokens , sdk . Unbonded , val1 , true )
require . NoError ( t , err )
_ = staking . EndBlocker ( ctx , stakingKeeper )
// period 0 passes and the threshold is not met
2019-10-04 17:55:49 +00:00
vva . CurrentPeriodProgress . MissedBlocks = 50
vva . CurrentPeriodProgress . TotalBlocks = 100
2019-09-23 18:23:00 +00:00
ak . SetAccount ( ctx , vva )
keeper . UpdateVestedCoinsProgress ( ctx , vva . Address , 0 )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
// require that period 0 coins have become debt
require . Equal ( t , sdk . NewCoins ( sdk . NewInt64Coin ( stakeDenom , 30000000 ) ) , vva . DebtAfterFailedVesting )
initialSupply := supplyKeeper . GetSupply ( ctx ) . GetTotal ( )
expectedSupply := initialSupply . Sub ( vva . DebtAfterFailedVesting )
// Context needs the block time because bank keeper calls 'SpendableCoins' by getting the header from the context.
ctx = ctx . WithBlockTime ( now . Add ( 12 * time . Hour ) )
keeper . HandleVestingDebt ( ctx , vva . Address , now . Add ( 12 * time . Hour ) )
// in the case when the return address is not set require that the total supply has decreased by the debt amount
require . Equal ( t , expectedSupply , supplyKeeper . GetSupply ( ctx ) . GetTotal ( ) )
// require that there is still one delegation
delegations := 0
stakingKeeper . IterateDelegations ( ctx , vva . Address , func ( index int64 , d stakingexported . DelegationI ) ( stop bool ) {
delegations ++
return false
} )
require . Equal ( t , 1 , delegations )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
//require that debt is now zero
require . Equal ( t , sdk . Coins ( nil ) , vva . DebtAfterFailedVesting )
}
func TestHandleVestingDebtReturn ( t * testing . T ) {
ctx , ak , _ , stakingKeeper , _ , keeper := CreateTestInput ( t , false , 1000 )
CreateValidators ( ctx , stakingKeeper , [ ] int64 { 5 , 5 , 5 } )
now := tmtime . Now ( )
vva := ValidatorVestingDelegatorTestAccount ( now )
vva . ReturnAddress = TestAddrs [ 2 ]
ak . SetAccount ( ctx , vva )
delTokens := sdk . TokensFromConsensusPower ( 30 )
2019-09-27 18:48:57 +00:00
val1 , found := stakingKeeper . GetValidator ( ctx , ValOpAddr1 )
2019-09-23 18:23:00 +00:00
require . True ( t , found )
_ , err := stakingKeeper . Delegate ( ctx , vva . Address , delTokens , sdk . Unbonded , val1 , true )
require . NoError ( t , err )
_ = staking . EndBlocker ( ctx , stakingKeeper )
// period 0 passes and the threshold is not met
2019-10-04 17:55:49 +00:00
vva . CurrentPeriodProgress . MissedBlocks = 50
vva . CurrentPeriodProgress . TotalBlocks = 100
2019-09-23 18:23:00 +00:00
ak . SetAccount ( ctx , vva )
keeper . UpdateVestedCoinsProgress ( ctx , vva . Address , 0 )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
// require that period 0 coins have become debt
require . Equal ( t , sdk . NewCoins ( sdk . NewInt64Coin ( stakeDenom , 30000000 ) ) , vva . DebtAfterFailedVesting )
initialBalance := ak . GetAccount ( ctx , TestAddrs [ 2 ] ) . GetCoins ( )
expectedBalance := initialBalance . Add ( vva . DebtAfterFailedVesting )
// Context needs the block time because bank keeper calls 'SpendableCoins' by getting the header from the context.
ctx = ctx . WithBlockTime ( now . Add ( 12 * time . Hour ) )
keeper . HandleVestingDebt ( ctx , vva . Address , now . Add ( 12 * time . Hour ) )
// in the case when the return address is, set require that return address balance has increased by the debt amount
require . Equal ( t , expectedBalance , ak . GetAccount ( ctx , TestAddrs [ 2 ] ) . GetCoins ( ) )
// require that there is still one delegation
delegations := 0
stakingKeeper . IterateDelegations ( ctx , vva . Address , func ( index int64 , d stakingexported . DelegationI ) ( stop bool ) {
delegations ++
return false
} )
require . Equal ( t , 1 , delegations )
vva = keeper . GetAccountFromAuthKeeper ( ctx , vva . Address )
//require that debt is now zero
require . Equal ( t , sdk . Coins ( nil ) , vva . DebtAfterFailedVesting )
}