Merge pull request #745 from cosmos/joon/732-stake-keeper
Joon/732 stake keeper
This commit is contained in:
commit
d88026244d
|
@ -1,6 +1,8 @@
|
|||
package stake
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
|
@ -87,6 +89,11 @@ func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
// if the voting power is the same no need to update any of the other indexes
|
||||
if oldFound && oldCandidate.Assets.Equal(candidate.Assets) {
|
||||
return
|
||||
}
|
||||
|
||||
// update the list ordered by voting power
|
||||
if oldFound {
|
||||
store.Delete(GetValidatorKey(address, oldCandidate.Assets, k.cdc))
|
||||
|
@ -94,11 +101,19 @@ func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) {
|
|||
store.Set(GetValidatorKey(address, validator.VotingPower, k.cdc), bz)
|
||||
|
||||
// add to the validators to update list if is already a validator
|
||||
if store.Get(GetRecentValidatorKey(address)) == nil {
|
||||
return
|
||||
}
|
||||
store.Set(GetAccUpdateValidatorKey(validator.Address), bz)
|
||||
// or is a new validator
|
||||
setAcc := false
|
||||
if store.Get(GetRecentValidatorKey(address)) != nil {
|
||||
setAcc = true
|
||||
|
||||
// want to check in the else statement because inefficient
|
||||
} else if k.isNewValidator(ctx, store, address) {
|
||||
setAcc = true
|
||||
}
|
||||
if setAcc {
|
||||
store.Set(GetAccUpdateValidatorKey(validator.Address), bz)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
|
||||
|
@ -112,6 +127,7 @@ func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
|
|||
// delete the old candidate record
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Delete(GetCandidateKey(address))
|
||||
store.Delete(GetValidatorKey(address, oldCandidate.Assets, k.cdc))
|
||||
|
||||
// delete from recent and power weighted validator groups if the validator
|
||||
// exists and add validator with zero power to the validator updates
|
||||
|
@ -124,7 +140,6 @@ func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
|
|||
}
|
||||
store.Set(GetAccUpdateValidatorKey(address), bz)
|
||||
store.Delete(GetRecentValidatorKey(address))
|
||||
store.Delete(GetValidatorKey(address, oldCandidate.Assets, k.cdc))
|
||||
}
|
||||
|
||||
//___________________________________________________________________________
|
||||
|
@ -136,12 +151,18 @@ func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
|
|||
func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
// clear the recent validators store
|
||||
k.deleteSubSpace(store, RecentValidatorsKey)
|
||||
// clear the recent validators store, add to the ToKickOut Temp store
|
||||
iterator := store.Iterator(subspace(RecentValidatorsKey))
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
addr := AddrFromKey(iterator.Key())
|
||||
store.Set(GetToKickOutValidatorKey(addr), []byte{})
|
||||
store.Delete(iterator.Key())
|
||||
}
|
||||
iterator.Close()
|
||||
|
||||
// add the actual validator power sorted store
|
||||
maxVal := k.GetParams(ctx).MaxValidators
|
||||
iterator := store.ReverseIterator(subspace(ValidatorsKey)) //smallest to largest
|
||||
iterator = store.ReverseIterator(subspace(ValidatorsKey)) // largest to smallest
|
||||
validators = make([]Validator, maxVal)
|
||||
i := 0
|
||||
for ; ; i++ {
|
||||
|
@ -157,15 +178,58 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
|
|||
}
|
||||
validators[i] = val
|
||||
|
||||
// remove from ToKickOut group
|
||||
store.Delete(GetToKickOutValidatorKey(val.Address))
|
||||
|
||||
// also add to the recent validators group
|
||||
store.Set(GetRecentValidatorKey(val.Address), bz)
|
||||
store.Set(GetRecentValidatorKey(val.Address), bz) // XXX should store nothing
|
||||
|
||||
iterator.Next()
|
||||
}
|
||||
|
||||
// add any kicked out validators to the acc change
|
||||
iterator = store.Iterator(subspace(ToKickOutValidatorsKey))
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
addr := AddrFromKey(iterator.Key())
|
||||
bz, err := k.cdc.MarshalBinary(Validator{addr, sdk.ZeroRat})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
store.Set(GetAccUpdateValidatorKey(addr), bz)
|
||||
store.Delete(iterator.Key())
|
||||
}
|
||||
iterator.Close()
|
||||
|
||||
return validators[:i] // trim
|
||||
}
|
||||
|
||||
// TODO this is madly inefficient because need to call every time we set a candidate
|
||||
// Should use something better than an iterator maybe?
|
||||
// Used to determine if something has just been added to the actual validator set
|
||||
func (k Keeper) isNewValidator(ctx sdk.Context, store sdk.KVStore, address sdk.Address) bool {
|
||||
// add the actual validator power sorted store
|
||||
maxVal := k.GetParams(ctx).MaxValidators
|
||||
iterator := store.ReverseIterator(subspace(ValidatorsKey)) // largest to smallest
|
||||
for i := 0; ; i++ {
|
||||
if !iterator.Valid() || i > int(maxVal-1) {
|
||||
iterator.Close()
|
||||
break
|
||||
}
|
||||
bz := iterator.Value()
|
||||
var val Validator
|
||||
err := k.cdc.UnmarshalBinary(bz, &val)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if bytes.Equal(val.Address, address) {
|
||||
return true
|
||||
}
|
||||
iterator.Next()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Is the address provided a part of the most recently saved validator group?
|
||||
func (k Keeper) IsRecentValidator(ctx sdk.Context, address sdk.Address) bool {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
|
|
@ -17,7 +17,9 @@ var (
|
|||
AccUpdateValidatorsKey = []byte{0x04} // prefix for each key to a validator which is being updated
|
||||
RecentValidatorsKey = []byte{0x05} // prefix for each key to the last updated validator group
|
||||
|
||||
DelegatorBondKeyPrefix = []byte{0x06} // prefix for each key to a delegator's bond
|
||||
ToKickOutValidatorsKey = []byte{0x06} // prefix for each key to the last updated validator group
|
||||
|
||||
DelegatorBondKeyPrefix = []byte{0x07} // prefix for each key to a delegator's bond
|
||||
)
|
||||
|
||||
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
||||
|
@ -43,6 +45,16 @@ func GetRecentValidatorKey(addr sdk.Address) []byte {
|
|||
return append(RecentValidatorsKey, addr.Bytes()...)
|
||||
}
|
||||
|
||||
// reverse operation of GetRecentValidatorKey
|
||||
func AddrFromKey(key []byte) sdk.Address {
|
||||
return key[1:]
|
||||
}
|
||||
|
||||
// get the key for the accumulated update validators
|
||||
func GetToKickOutValidatorKey(addr sdk.Address) []byte {
|
||||
return append(ToKickOutValidatorsKey, addr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the key for delegator bond with candidate
|
||||
func GetDelegatorBondKey(delegatorAddr, candidateAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
return append(GetDelegatorBondsKey(delegatorAddr, cdc), candidateAddr.Bytes()...)
|
||||
|
|
|
@ -5,39 +5,22 @@ import (
|
|||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
addrDel1 = addrs[0]
|
||||
addrDel2 = addrs[1]
|
||||
addrVal1 = addrs[2]
|
||||
addrVal2 = addrs[3]
|
||||
addrVal3 = addrs[4]
|
||||
pk1 = crypto.GenPrivKeyEd25519().PubKey()
|
||||
pk2 = crypto.GenPrivKeyEd25519().PubKey()
|
||||
pk3 = crypto.GenPrivKeyEd25519().PubKey()
|
||||
|
||||
candidate1 = Candidate{
|
||||
Address: addrVal1,
|
||||
PubKey: pk1,
|
||||
Assets: sdk.NewRat(9),
|
||||
Liabilities: sdk.NewRat(9),
|
||||
addrDels = []sdk.Address{
|
||||
addrs[0],
|
||||
addrs[1],
|
||||
}
|
||||
candidate2 = Candidate{
|
||||
Address: addrVal2,
|
||||
PubKey: pk2,
|
||||
Assets: sdk.NewRat(9),
|
||||
Liabilities: sdk.NewRat(9),
|
||||
}
|
||||
candidate3 = Candidate{
|
||||
Address: addrVal3,
|
||||
PubKey: pk3,
|
||||
Assets: sdk.NewRat(9),
|
||||
Liabilities: sdk.NewRat(9),
|
||||
addrVals = []sdk.Address{
|
||||
addrs[2],
|
||||
addrs[3],
|
||||
addrs[4],
|
||||
addrs[5],
|
||||
addrs[6],
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -45,6 +28,18 @@ var (
|
|||
func TestCandidate(t *testing.T) {
|
||||
ctx, _, keeper := createTestInput(t, nil, false, 0)
|
||||
|
||||
//construct the candidates
|
||||
var candidates [3]Candidate
|
||||
amts := []int64{9, 8, 7}
|
||||
for i, amt := range amts {
|
||||
candidates[i] = Candidate{
|
||||
Address: addrVals[i],
|
||||
PubKey: pks[i],
|
||||
Assets: sdk.NewRat(amt),
|
||||
Liabilities: sdk.NewRat(amt),
|
||||
}
|
||||
}
|
||||
|
||||
candidatesEqual := func(c1, c2 Candidate) bool {
|
||||
return c1.Status == c2.Status &&
|
||||
c1.PubKey.Equals(c2.PubKey) &&
|
||||
|
@ -55,47 +50,47 @@ func TestCandidate(t *testing.T) {
|
|||
}
|
||||
|
||||
// check the empty keeper first
|
||||
_, found := keeper.GetCandidate(ctx, addrVal1)
|
||||
_, found := keeper.GetCandidate(ctx, addrVals[0])
|
||||
assert.False(t, found)
|
||||
resCands := keeper.GetCandidates(ctx, 100)
|
||||
assert.Zero(t, len(resCands))
|
||||
|
||||
// set and retrieve a record
|
||||
keeper.setCandidate(ctx, candidate1)
|
||||
resCand, found := keeper.GetCandidate(ctx, addrVal1)
|
||||
keeper.setCandidate(ctx, candidates[0])
|
||||
resCand, found := keeper.GetCandidate(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
assert.True(t, candidatesEqual(candidate1, resCand), "%v \n %v", resCand, candidate1)
|
||||
assert.True(t, candidatesEqual(candidates[0], resCand), "%v \n %v", resCand, candidates[0])
|
||||
|
||||
// modify a records, save, and retrieve
|
||||
candidate1.Liabilities = sdk.NewRat(99)
|
||||
keeper.setCandidate(ctx, candidate1)
|
||||
resCand, found = keeper.GetCandidate(ctx, addrVal1)
|
||||
candidates[0].Liabilities = sdk.NewRat(99)
|
||||
keeper.setCandidate(ctx, candidates[0])
|
||||
resCand, found = keeper.GetCandidate(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
assert.True(t, candidatesEqual(candidate1, resCand))
|
||||
assert.True(t, candidatesEqual(candidates[0], resCand))
|
||||
|
||||
// also test that the address has been added to address list
|
||||
resCands = keeper.GetCandidates(ctx, 100)
|
||||
require.Equal(t, 1, len(resCands))
|
||||
assert.Equal(t, addrVal1, resCands[0].Address)
|
||||
assert.Equal(t, addrVals[0], resCands[0].Address)
|
||||
|
||||
// add other candidates
|
||||
keeper.setCandidate(ctx, candidate2)
|
||||
keeper.setCandidate(ctx, candidate3)
|
||||
resCand, found = keeper.GetCandidate(ctx, addrVal2)
|
||||
keeper.setCandidate(ctx, candidates[1])
|
||||
keeper.setCandidate(ctx, candidates[2])
|
||||
resCand, found = keeper.GetCandidate(ctx, addrVals[1])
|
||||
require.True(t, found)
|
||||
assert.True(t, candidatesEqual(candidate2, resCand), "%v \n %v", resCand, candidate2)
|
||||
resCand, found = keeper.GetCandidate(ctx, addrVal3)
|
||||
assert.True(t, candidatesEqual(candidates[1], resCand), "%v \n %v", resCand, candidates[1])
|
||||
resCand, found = keeper.GetCandidate(ctx, addrVals[2])
|
||||
require.True(t, found)
|
||||
assert.True(t, candidatesEqual(candidate3, resCand), "%v \n %v", resCand, candidate3)
|
||||
assert.True(t, candidatesEqual(candidates[2], resCand), "%v \n %v", resCand, candidates[2])
|
||||
resCands = keeper.GetCandidates(ctx, 100)
|
||||
require.Equal(t, 3, len(resCands))
|
||||
assert.True(t, candidatesEqual(candidate1, resCands[0]), "%v \n %v", resCands[0], candidate1)
|
||||
assert.True(t, candidatesEqual(candidate2, resCands[1]), "%v \n %v", resCands[1], candidate2)
|
||||
assert.True(t, candidatesEqual(candidate3, resCands[2]), "%v \n %v", resCands[2], candidate3)
|
||||
assert.True(t, candidatesEqual(candidates[0], resCands[0]), "%v \n %v", resCands[0], candidates[0])
|
||||
assert.True(t, candidatesEqual(candidates[1], resCands[1]), "%v \n %v", resCands[1], candidates[1])
|
||||
assert.True(t, candidatesEqual(candidates[2], resCands[2]), "%v \n %v", resCands[2], candidates[2])
|
||||
|
||||
// remove a record
|
||||
keeper.removeCandidate(ctx, candidate2.Address)
|
||||
_, found = keeper.GetCandidate(ctx, addrVal2)
|
||||
keeper.removeCandidate(ctx, candidates[1].Address)
|
||||
_, found = keeper.GetCandidate(ctx, addrVals[1])
|
||||
assert.False(t, found)
|
||||
}
|
||||
|
||||
|
@ -103,12 +98,24 @@ func TestCandidate(t *testing.T) {
|
|||
func TestBond(t *testing.T) {
|
||||
ctx, _, keeper := createTestInput(t, nil, false, 0)
|
||||
|
||||
// first add a candidate1 to delegate too
|
||||
keeper.setCandidate(ctx, candidate1)
|
||||
//construct the candidates
|
||||
amts := []int64{9, 8, 7}
|
||||
var candidates [3]Candidate
|
||||
for i, amt := range amts {
|
||||
candidates[i] = Candidate{
|
||||
Address: addrVals[i],
|
||||
PubKey: pks[i],
|
||||
Assets: sdk.NewRat(amt),
|
||||
Liabilities: sdk.NewRat(amt),
|
||||
}
|
||||
}
|
||||
|
||||
// first add a candidates[0] to delegate too
|
||||
keeper.setCandidate(ctx, candidates[0])
|
||||
|
||||
bond1to1 := DelegatorBond{
|
||||
DelegatorAddr: addrDel1,
|
||||
CandidateAddr: addrVal1,
|
||||
DelegatorAddr: addrDels[0],
|
||||
CandidateAddr: addrVals[0],
|
||||
Shares: sdk.NewRat(9),
|
||||
}
|
||||
|
||||
|
@ -119,30 +126,30 @@ func TestBond(t *testing.T) {
|
|||
}
|
||||
|
||||
// check the empty keeper first
|
||||
_, found := keeper.getDelegatorBond(ctx, addrDel1, addrVal1)
|
||||
_, found := keeper.getDelegatorBond(ctx, addrDels[0], addrVals[0])
|
||||
assert.False(t, found)
|
||||
|
||||
// set and retrieve a record
|
||||
keeper.setDelegatorBond(ctx, bond1to1)
|
||||
resBond, found := keeper.getDelegatorBond(ctx, addrDel1, addrVal1)
|
||||
resBond, found := keeper.getDelegatorBond(ctx, addrDels[0], addrVals[0])
|
||||
assert.True(t, found)
|
||||
assert.True(t, bondsEqual(bond1to1, resBond))
|
||||
|
||||
// modify a records, save, and retrieve
|
||||
bond1to1.Shares = sdk.NewRat(99)
|
||||
keeper.setDelegatorBond(ctx, bond1to1)
|
||||
resBond, found = keeper.getDelegatorBond(ctx, addrDel1, addrVal1)
|
||||
resBond, found = keeper.getDelegatorBond(ctx, addrDels[0], addrVals[0])
|
||||
assert.True(t, found)
|
||||
assert.True(t, bondsEqual(bond1to1, resBond))
|
||||
|
||||
// add some more records
|
||||
keeper.setCandidate(ctx, candidate2)
|
||||
keeper.setCandidate(ctx, candidate3)
|
||||
bond1to2 := DelegatorBond{addrDel1, addrVal2, sdk.NewRat(9)}
|
||||
bond1to3 := DelegatorBond{addrDel1, addrVal3, sdk.NewRat(9)}
|
||||
bond2to1 := DelegatorBond{addrDel2, addrVal1, sdk.NewRat(9)}
|
||||
bond2to2 := DelegatorBond{addrDel2, addrVal2, sdk.NewRat(9)}
|
||||
bond2to3 := DelegatorBond{addrDel2, addrVal3, sdk.NewRat(9)}
|
||||
keeper.setCandidate(ctx, candidates[1])
|
||||
keeper.setCandidate(ctx, candidates[2])
|
||||
bond1to2 := DelegatorBond{addrDels[0], addrVals[1], sdk.NewRat(9)}
|
||||
bond1to3 := DelegatorBond{addrDels[0], addrVals[2], sdk.NewRat(9)}
|
||||
bond2to1 := DelegatorBond{addrDels[1], addrVals[0], sdk.NewRat(9)}
|
||||
bond2to2 := DelegatorBond{addrDels[1], addrVals[1], sdk.NewRat(9)}
|
||||
bond2to3 := DelegatorBond{addrDels[1], addrVals[2], sdk.NewRat(9)}
|
||||
keeper.setDelegatorBond(ctx, bond1to2)
|
||||
keeper.setDelegatorBond(ctx, bond1to3)
|
||||
keeper.setDelegatorBond(ctx, bond2to1)
|
||||
|
@ -150,16 +157,16 @@ func TestBond(t *testing.T) {
|
|||
keeper.setDelegatorBond(ctx, bond2to3)
|
||||
|
||||
// test all bond retrieve capabilities
|
||||
resBonds := keeper.getDelegatorBonds(ctx, addrDel1, 5)
|
||||
resBonds := keeper.getDelegatorBonds(ctx, addrDels[0], 5)
|
||||
require.Equal(t, 3, len(resBonds))
|
||||
assert.True(t, bondsEqual(bond1to1, resBonds[0]))
|
||||
assert.True(t, bondsEqual(bond1to2, resBonds[1]))
|
||||
assert.True(t, bondsEqual(bond1to3, resBonds[2]))
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDel1, 3)
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDels[0], 3)
|
||||
require.Equal(t, 3, len(resBonds))
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDel1, 2)
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDels[0], 2)
|
||||
require.Equal(t, 2, len(resBonds))
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDel2, 5)
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDels[1], 5)
|
||||
require.Equal(t, 3, len(resBonds))
|
||||
assert.True(t, bondsEqual(bond2to1, resBonds[0]))
|
||||
assert.True(t, bondsEqual(bond2to2, resBonds[1]))
|
||||
|
@ -167,9 +174,9 @@ func TestBond(t *testing.T) {
|
|||
|
||||
// delete a record
|
||||
keeper.removeDelegatorBond(ctx, bond2to3)
|
||||
_, found = keeper.getDelegatorBond(ctx, addrDel2, addrVal3)
|
||||
_, found = keeper.getDelegatorBond(ctx, addrDels[1], addrVals[2])
|
||||
assert.False(t, found)
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDel2, 5)
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDels[1], 5)
|
||||
require.Equal(t, 2, len(resBonds))
|
||||
assert.True(t, bondsEqual(bond2to1, resBonds[0]))
|
||||
assert.True(t, bondsEqual(bond2to2, resBonds[1]))
|
||||
|
@ -177,11 +184,11 @@ func TestBond(t *testing.T) {
|
|||
// delete all the records from delegator 2
|
||||
keeper.removeDelegatorBond(ctx, bond2to1)
|
||||
keeper.removeDelegatorBond(ctx, bond2to2)
|
||||
_, found = keeper.getDelegatorBond(ctx, addrDel2, addrVal1)
|
||||
_, found = keeper.getDelegatorBond(ctx, addrDels[1], addrVals[0])
|
||||
assert.False(t, found)
|
||||
_, found = keeper.getDelegatorBond(ctx, addrDel2, addrVal2)
|
||||
_, found = keeper.getDelegatorBond(ctx, addrDels[1], addrVals[1])
|
||||
assert.False(t, found)
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDel2, 5)
|
||||
resBonds = keeper.getDelegatorBonds(ctx, addrDels[1], 5)
|
||||
require.Equal(t, 0, len(resBonds))
|
||||
}
|
||||
|
||||
|
@ -193,14 +200,14 @@ func TestGetValidators(t *testing.T) {
|
|||
// initialize some candidates into the state
|
||||
amts := []int64{0, 100, 1, 400, 200}
|
||||
n := len(amts)
|
||||
candidates := make([]Candidate, n)
|
||||
for i := 0; i < n; i++ {
|
||||
var candidates [5]Candidate
|
||||
for i, amt := range amts {
|
||||
c := Candidate{
|
||||
Status: Unbonded,
|
||||
PubKey: pks[i],
|
||||
Address: addrs[i],
|
||||
Assets: sdk.NewRat(amts[i]),
|
||||
Liabilities: sdk.NewRat(amts[i]),
|
||||
Assets: sdk.NewRat(amt),
|
||||
Liabilities: sdk.NewRat(amt),
|
||||
}
|
||||
keeper.setCandidate(ctx, c)
|
||||
candidates[i] = c
|
||||
|
@ -259,36 +266,282 @@ func TestGetValidators(t *testing.T) {
|
|||
assert.Equal(t, candidates[3].Address, validators[1].Address, "%v", validators)
|
||||
}
|
||||
|
||||
// TODO
|
||||
// test the mechanism which keeps track of a validator set change
|
||||
func TestGetAccUpdateValidators(t *testing.T) {
|
||||
//TODO
|
||||
// test from nothing to something
|
||||
// test from something to nothing
|
||||
// test identical
|
||||
// test single value change
|
||||
// test multiple value change
|
||||
// test validator added at the beginning
|
||||
// test validator added in the middle
|
||||
// test validator added at the end
|
||||
// test multiple validators removed
|
||||
}
|
||||
|
||||
// clear the tracked changes to the validator set
|
||||
func TestClearAccUpdateValidators(t *testing.T) {
|
||||
//TODO
|
||||
ctx, _, keeper := createTestInput(t, nil, false, 0)
|
||||
|
||||
amts := []int64{100, 400, 200}
|
||||
candidates := make([]Candidate, len(amts))
|
||||
for i, amt := range amts {
|
||||
c := Candidate{
|
||||
Status: Unbonded,
|
||||
PubKey: pks[i],
|
||||
Address: addrs[i],
|
||||
Assets: sdk.NewRat(amt),
|
||||
Liabilities: sdk.NewRat(amt),
|
||||
}
|
||||
candidates[i] = c
|
||||
keeper.setCandidate(ctx, c)
|
||||
}
|
||||
|
||||
acc := keeper.getAccUpdateValidators(ctx)
|
||||
assert.Equal(t, len(amts), len(acc))
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
acc = keeper.getAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 0, len(acc))
|
||||
}
|
||||
|
||||
// test the mechanism which keeps track of a validator set change
|
||||
func TestGetAccUpdateValidators(t *testing.T) {
|
||||
ctx, _, keeper := createTestInput(t, nil, false, 0)
|
||||
params := defaultParams()
|
||||
params.MaxValidators = 4
|
||||
keeper.setParams(ctx, params)
|
||||
|
||||
// TODO eliminate use of candidatesIn here
|
||||
// tests could be clearer if they just
|
||||
// created the candidate at time of use
|
||||
// and were labelled by power in the comments
|
||||
// outlining in each test
|
||||
amts := []int64{10, 11, 12, 13, 1}
|
||||
var candidatesIn [5]Candidate
|
||||
for i, amt := range amts {
|
||||
candidatesIn[i] = Candidate{
|
||||
Address: addrs[i],
|
||||
PubKey: pks[i],
|
||||
Assets: sdk.NewRat(amt),
|
||||
Liabilities: sdk.NewRat(amt),
|
||||
}
|
||||
}
|
||||
|
||||
// test from nothing to something
|
||||
// candidate set: {} -> {c1, c3}
|
||||
// validator set: {} -> {c1, c3}
|
||||
// accUpdate set: {} -> {c1, c3}
|
||||
assert.Equal(t, 0, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 0, len(keeper.GetValidators(ctx)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
keeper.setCandidate(ctx, candidatesIn[1])
|
||||
keeper.setCandidate(ctx, candidatesIn[3])
|
||||
|
||||
vals := keeper.GetValidators(ctx) // to init recent validator set
|
||||
require.Equal(t, 2, len(vals))
|
||||
acc := keeper.getAccUpdateValidators(ctx)
|
||||
require.Equal(t, 2, len(acc))
|
||||
candidates := keeper.GetCandidates(ctx, 5)
|
||||
require.Equal(t, 2, len(candidates))
|
||||
assert.Equal(t, candidates[0].validator(), acc[0])
|
||||
assert.Equal(t, candidates[1].validator(), acc[1])
|
||||
assert.Equal(t, candidates[0].validator(), vals[1])
|
||||
assert.Equal(t, candidates[1].validator(), vals[0])
|
||||
|
||||
// test identical,
|
||||
// candidate set: {c1, c3} -> {c1, c3}
|
||||
// accUpdate set: {} -> {}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 2, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
keeper.setCandidate(ctx, candidates[0])
|
||||
keeper.setCandidate(ctx, candidates[1])
|
||||
|
||||
require.Equal(t, 2, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
// test single value change
|
||||
// candidate set: {c1, c3} -> {c1', c3}
|
||||
// accUpdate set: {} -> {c1'}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 2, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
candidates[0].Assets = sdk.NewRat(600)
|
||||
keeper.setCandidate(ctx, candidates[0])
|
||||
|
||||
candidates = keeper.GetCandidates(ctx, 5)
|
||||
require.Equal(t, 2, len(candidates))
|
||||
assert.True(t, candidates[0].Assets.Equal(sdk.NewRat(600)))
|
||||
acc = keeper.getAccUpdateValidators(ctx)
|
||||
require.Equal(t, 1, len(acc))
|
||||
assert.Equal(t, candidates[0].validator(), acc[0])
|
||||
|
||||
// test multiple value change
|
||||
// candidate set: {c1, c3} -> {c1', c3'}
|
||||
// accUpdate set: {c1, c3} -> {c1', c3'}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 2, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
candidates[0].Assets = sdk.NewRat(200)
|
||||
candidates[1].Assets = sdk.NewRat(100)
|
||||
keeper.setCandidate(ctx, candidates[0])
|
||||
keeper.setCandidate(ctx, candidates[1])
|
||||
|
||||
acc = keeper.getAccUpdateValidators(ctx)
|
||||
require.Equal(t, 2, len(acc))
|
||||
candidates = keeper.GetCandidates(ctx, 5)
|
||||
require.Equal(t, 2, len(candidates))
|
||||
require.Equal(t, candidates[0].validator(), acc[0])
|
||||
require.Equal(t, candidates[1].validator(), acc[1])
|
||||
|
||||
// test validtor added at the beginning
|
||||
// candidate set: {c1, c3} -> {c0, c1, c3}
|
||||
// accUpdate set: {} -> {c0}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 2, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
keeper.setCandidate(ctx, candidatesIn[0])
|
||||
acc = keeper.getAccUpdateValidators(ctx)
|
||||
require.Equal(t, 1, len(acc))
|
||||
candidates = keeper.GetCandidates(ctx, 5)
|
||||
require.Equal(t, 3, len(candidates))
|
||||
assert.Equal(t, candidates[0].validator(), acc[0])
|
||||
|
||||
// test validator added at the middle
|
||||
// candidate set: {c0, c1, c3} -> {c0, c1, c2, c3]
|
||||
// accUpdate set: {} -> {c2}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 3, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
keeper.setCandidate(ctx, candidatesIn[2])
|
||||
acc = keeper.getAccUpdateValidators(ctx)
|
||||
require.Equal(t, 1, len(acc))
|
||||
candidates = keeper.GetCandidates(ctx, 5)
|
||||
require.Equal(t, 4, len(candidates))
|
||||
assert.Equal(t, candidates[2].validator(), acc[0])
|
||||
|
||||
// test candidate added at the end but not inserted in the valset
|
||||
// candidate set: {c0, c1, c2, c3} -> {c0, c1, c2, c3, c4}
|
||||
// validator set: {c0, c1, c2, c3} -> {c0, c1, c2, c3}
|
||||
// accUpdate set: {} -> {}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 4, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 4, len(keeper.GetValidators(ctx)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
keeper.setCandidate(ctx, candidatesIn[4])
|
||||
|
||||
assert.Equal(t, 5, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 4, len(keeper.GetValidators(ctx)))
|
||||
require.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx))) // max validator number is 4
|
||||
|
||||
// test candidate change its power but still not in the valset
|
||||
// candidate set: {c0, c1, c2, c3, c4} -> {c0, c1, c2, c3, c4}
|
||||
// validator set: {c0, c1, c2, c3} -> {c0, c1, c2, c3}
|
||||
// accUpdate set: {} -> {}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 5, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 4, len(keeper.GetValidators(ctx)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
candidatesIn[4].Assets = sdk.NewRat(1)
|
||||
keeper.setCandidate(ctx, candidatesIn[4])
|
||||
|
||||
assert.Equal(t, 5, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 4, len(keeper.GetValidators(ctx)))
|
||||
require.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx))) // max validator number is 4
|
||||
|
||||
// test candidate change its power and become a validator (pushing out an existing)
|
||||
// candidate set: {c0, c1, c2, c3, c4} -> {c0, c1, c2, c3, c4}
|
||||
// validator set: {c0, c1, c2, c3} -> {c1, c2, c3, c4}
|
||||
// accUpdate set: {} -> {c0, c4}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 5, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 4, len(keeper.GetValidators(ctx)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
candidatesIn[4].Assets = sdk.NewRat(1000)
|
||||
keeper.setCandidate(ctx, candidatesIn[4])
|
||||
|
||||
candidates = keeper.GetCandidates(ctx, 5)
|
||||
require.Equal(t, 5, len(candidates))
|
||||
vals = keeper.GetValidators(ctx)
|
||||
require.Equal(t, 4, len(vals))
|
||||
assert.Equal(t, candidatesIn[1].Address, vals[1].Address)
|
||||
assert.Equal(t, candidatesIn[2].Address, vals[3].Address)
|
||||
assert.Equal(t, candidatesIn[3].Address, vals[2].Address)
|
||||
assert.Equal(t, candidatesIn[4].Address, vals[0].Address)
|
||||
|
||||
acc = keeper.getAccUpdateValidators(ctx)
|
||||
require.Equal(t, 2, len(acc), "%v", acc)
|
||||
|
||||
assert.Equal(t, candidatesIn[0].Address, acc[0].Address)
|
||||
assert.Equal(t, int64(0), acc[0].VotingPower.Evaluate())
|
||||
assert.Equal(t, vals[0], acc[1])
|
||||
|
||||
// test from something to nothing
|
||||
// candidate set: {c0, c1, c2, c3, c4} -> {}
|
||||
// validator set: {c1, c2, c3, c4} -> {}
|
||||
// accUpdate set: {} -> {c1, c2, c3, c4}
|
||||
keeper.clearAccUpdateValidators(ctx)
|
||||
assert.Equal(t, 5, len(keeper.GetCandidates(ctx, 5)))
|
||||
assert.Equal(t, 4, len(keeper.GetValidators(ctx)))
|
||||
assert.Equal(t, 0, len(keeper.getAccUpdateValidators(ctx)))
|
||||
|
||||
keeper.removeCandidate(ctx, candidatesIn[0].Address)
|
||||
keeper.removeCandidate(ctx, candidatesIn[1].Address)
|
||||
keeper.removeCandidate(ctx, candidatesIn[2].Address)
|
||||
keeper.removeCandidate(ctx, candidatesIn[3].Address)
|
||||
keeper.removeCandidate(ctx, candidatesIn[4].Address)
|
||||
|
||||
vals = keeper.GetValidators(ctx)
|
||||
assert.Equal(t, 0, len(vals), "%v", vals)
|
||||
candidates = keeper.GetCandidates(ctx, 5)
|
||||
require.Equal(t, 0, len(candidates))
|
||||
acc = keeper.getAccUpdateValidators(ctx)
|
||||
require.Equal(t, 4, len(acc))
|
||||
assert.Equal(t, candidatesIn[1].Address, acc[0].Address)
|
||||
assert.Equal(t, candidatesIn[2].Address, acc[1].Address)
|
||||
assert.Equal(t, candidatesIn[3].Address, acc[2].Address)
|
||||
assert.Equal(t, candidatesIn[4].Address, acc[3].Address)
|
||||
assert.Equal(t, int64(0), acc[0].VotingPower.Evaluate())
|
||||
assert.Equal(t, int64(0), acc[1].VotingPower.Evaluate())
|
||||
assert.Equal(t, int64(0), acc[2].VotingPower.Evaluate())
|
||||
assert.Equal(t, int64(0), acc[3].VotingPower.Evaluate())
|
||||
}
|
||||
|
||||
// test if is a validator from the last update
|
||||
func TestIsRecentValidator(t *testing.T) {
|
||||
//TODO
|
||||
ctx, _, keeper := createTestInput(t, nil, false, 0)
|
||||
|
||||
amts := []int64{9, 8, 7, 10, 6}
|
||||
var candidatesIn [5]Candidate
|
||||
for i, amt := range amts {
|
||||
candidatesIn[i] = Candidate{
|
||||
Address: addrVals[i],
|
||||
PubKey: pks[i],
|
||||
Assets: sdk.NewRat(amt),
|
||||
Liabilities: sdk.NewRat(amt),
|
||||
}
|
||||
}
|
||||
|
||||
// test that an empty validator set doesn't have any validators
|
||||
validators := keeper.GetValidators(ctx)
|
||||
assert.Equal(t, 0, len(validators))
|
||||
|
||||
// get the validators for the first time
|
||||
keeper.setCandidate(ctx, candidatesIn[0])
|
||||
keeper.setCandidate(ctx, candidatesIn[1])
|
||||
validators = keeper.GetValidators(ctx)
|
||||
require.Equal(t, 2, len(validators))
|
||||
assert.Equal(t, candidatesIn[0].validator(), validators[0])
|
||||
assert.Equal(t, candidatesIn[1].validator(), validators[1])
|
||||
|
||||
// test a basic retrieve of something that should be a recent validator
|
||||
assert.True(t, keeper.IsRecentValidator(ctx, candidatesIn[0].Address))
|
||||
assert.True(t, keeper.IsRecentValidator(ctx, candidatesIn[1].Address))
|
||||
|
||||
// test a basic retrieve of something that should not be a recent validator
|
||||
assert.False(t, keeper.IsRecentValidator(ctx, candidatesIn[2].Address))
|
||||
|
||||
// remove that validator, but don't retrieve the recent validator group
|
||||
keeper.removeCandidate(ctx, candidatesIn[0].Address)
|
||||
|
||||
// test that removed validator is not considered a recent validator
|
||||
assert.False(t, keeper.IsRecentValidator(ctx, candidatesIn[0].Address))
|
||||
}
|
||||
|
||||
func TestParams(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue