diff --git a/types/rational_test.go b/types/rational_test.go index c83af3917b..5af63e8ec9 100644 --- a/types/rational_test.go +++ b/types/rational_test.go @@ -192,15 +192,18 @@ func TestRound(t *testing.T) { } } -func TestToLeftPaddedString(t *testing.T) { +func TestToLeftPadded(t *testing.T) { tests := []struct { rat Rat digits int8 res string }{ {NewRat(100, 3), 8, "00000033"}, + {NewRat(1, 3), 8, "00000000"}, + {NewRat(100, 2), 8, "00000050"}, + {NewRat(1000, 3), 8, "00000333"}, + {NewRat(1000, 3), 12, "000000000333"}, } - for _, tc := range tests { assert.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits)) } diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 1caaeb63bc..af2015fe81 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -141,7 +141,7 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) { // add the actual validator power sorted store maxVal := k.GetParams(ctx).MaxValidators - iterator := store.Iterator(subspace(ValidatorsKey)) //smallest to largest + iterator := store.ReverseIterator(subspace(ValidatorsKey)) //smallest to largest validators = make([]Validator, maxVal) i := 0 for ; ; i++ { diff --git a/x/stake/keeper_keys.go b/x/stake/keeper_keys.go index ae0928bcc6..051994456e 100644 --- a/x/stake/keeper_keys.go +++ b/x/stake/keeper_keys.go @@ -20,6 +20,8 @@ var ( DelegatorBondKeyPrefix = []byte{0x05} // prefix for each key to a delegator's bond ) +const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch + // get the key for the candidate with address func GetCandidateKey(addr sdk.Address) []byte { return append(CandidatesKey, addr.Bytes()...) @@ -27,11 +29,8 @@ func GetCandidateKey(addr sdk.Address) []byte { // get the key for the validator used in the power-store func GetValidatorKey(addr sdk.Address, power sdk.Rat, cdc *wire.Codec) []byte { - b, err := cdc.MarshalBinary(power) - if err != nil { - panic(err) - } - return append(ValidatorsKey, append(b, addr.Bytes()...)...) + powerBytes := []byte(power.ToLeftPadded(maxDigitsForAccount)) + return append(ValidatorsKey, append(powerBytes, addr.Bytes()...)...) } // get the key for the accumulated update validators diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index 1f44a3ea9e..6e7478957f 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -41,178 +41,7 @@ var ( } ) -/* -func TestUpdateVotingPower(t *testing.T) { - ctx, _, keeper := createTestInput(t, nil, false, 0) - - // initialize some candidates into the state - amts := []int64{400, 200, 100, 10, 1} - candidates := make([]Candidate, 5) - for i := 0; i < 5; i++ { - c := Candidate{ - Status: Unbonded, - PubKey: pks[i], - Address: addrs[i], - Assets: sdk.NewRat(amts[i]), - Liabilities: sdk.NewRat(amts[i]), - } - keeper.setCandidate(ctx, c) - candidate[i] = c - } - - // test a basic change in voting power - candidates[0].Assets = sdk.NewRat(500) - keeper.setCandidate(ctx, candidate[0]) - validators - - assert.Equal(int64(500), candidates[0].VotingPower.Evaluate(), "%v", candidates[0]) - - // test a swap in voting power - candidates[1].Assets = sdk.NewRat(600) - candidates.updateVotingPower(store, p, params) - assert.Equal(int64(600), candidates[0].VotingPower.Evaluate(), "%v", candidates[0]) - assert.Equal(int64(500), candidates[1].VotingPower.Evaluate(), "%v", candidates[1]) - - // test the max validators term - params.MaxValidators = 4 - setParams(store, params) - candidates.updateVotingPower(store, p, params) - assert.Equal(int64(0), candidates[4].VotingPower.Evaluate(), "%v", candidates[4]) -} - -func TestValidatorsChanged(t *testing.T) { - require := require.New(t) - - v1 := (&Candidate{PubKey: pks[0], VotingPower: sdk.NewRat(10)}).validator() - v2 := (&Candidate{PubKey: pks[1], VotingPower: sdk.NewRat(10)}).validator() - v3 := (&Candidate{PubKey: pks[2], VotingPower: sdk.NewRat(10)}).validator() - v4 := (&Candidate{PubKey: pks[3], VotingPower: sdk.NewRat(10)}).validator() - v5 := (&Candidate{PubKey: pks[4], VotingPower: sdk.NewRat(10)}).validator() - - // test from nothing to something - vs1 := []Validator{} - vs2 := []Validator{v1, v2} - changed := vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testChange(t, vs2[0], changed[0]) - testChange(t, vs2[1], changed[1]) - - // test from something to nothing - vs1 = []Validator{v1, v2} - vs2 = []Validator{} - changed = vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testRemove(t, vs1[0], changed[0]) - testRemove(t, vs1[1], changed[1]) - - // test identical - vs1 = []Validator{v1, v2, v4} - vs2 = []Validator{v1, v2, v4} - changed = vs1.validatorsUpdated(vs2) - require.ZeroRat(len(changed)) - - // test single value change - vs2[2].VotingPower = sdk.OneRat - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testChange(t, vs2[2], changed[0]) - - // test multiple value change - vs2[0].VotingPower = sdk.NewRat(11) - vs2[2].VotingPower = sdk.NewRat(5) - changed = vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testChange(t, vs2[0], changed[0]) - testChange(t, vs2[2], changed[1]) - - // test validator added at the beginning - vs1 = []Validator{v2, v4} - vs2 = []Validator{v2, v4, v1} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testChange(t, vs2[0], changed[0]) - - // test validator added in the middle - vs1 = []Validator{v1, v2, v4} - vs2 = []Validator{v3, v1, v4, v2} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testChange(t, vs2[2], changed[0]) - - // test validator added at the end - vs2 = []Validator{v1, v2, v4, v5} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) //testChange(t, vs2[3], changed[0]) //// test multiple validators added //vs2 = []Validator{v1, v2, v3, v4, v5} //changed = vs1.validatorsUpdated(vs2) //require.Equal(2, len(changed)) //testChange(t, vs2[2], changed[0]) //testChange(t, vs2[4], changed[1]) //// test validator removed at the beginning //vs2 = []Validator{v2, v4} //changed = vs1.validatorsUpdated(vs2) //require.Equal(1, len(changed)) //testRemove(t, vs1[0], changed[0]) //// test validator removed in the middle //vs2 = []Validator{v1, v4} //changed = vs1.validatorsUpdated(vs2) //require.Equal(1, len(changed)) //testRemove(t, vs1[1], changed[0]) //// test validator removed at the end - vs2 = []Validator{v1, v2} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testRemove(t, vs1[2], changed[0]) - - // test multiple validators removed - vs2 = []Validator{v1} - changed = vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testRemove(t, vs1[1], changed[0]) - testRemove(t, vs1[2], changed[1]) - - // test many sdk of changes //vs2 = []Validator{v1, v3, v4, v5} //vs2[2].VotingPower = sdk.NewRat(11) //changed = vs1.validatorsUpdated(vs2) //require.Equal(4, len(changed), "%v", changed) // change 1, remove 1, add 2 //testRemove(t, vs1[1], changed[0]) //testChange(t, vs2[1], changed[1]) //testChange(t, vs2[2], changed[2]) //testChange(t, vs2[3], changed[3]) //} //func TestUpdateValidatorSet(t *testing.T) { //assert, require := assert.New(t), require.New(t) //store := initTestStore(t) //params := GetParams(store) //gs := GetPool(store) //N := 5 - actors := newAddrs(N) - candidates := candidatesFromActors(actors, []int64{400, 200, 100, 10, 1}) - for _, c := range candidates { - setCandidate(store, c) - } - - // they should all already be validators - change, err := UpdateValidatorSet(store, p, params) - require.Nil(err) - require.Equal(0, len(change), "%v", change) // change 1, remove 1, add 2 - - // test the max value and test again - params.MaxValidators = 4 - setParams(store, params) - change, err = UpdateValidatorSet(store, p, params) - require.Nil(err) - require.Equal(1, len(change), "%v", change) - testRemove(t, candidates[4].validator(), change[0]) - candidates = GetCandidates(store) - assert.Equal(int64(0), candidates[4].VotingPower.Evaluate()) - - // mess with the power's of the candidates and test - candidates[0].Assets = sdk.NewRat(10) - candidates[1].Assets = sdk.NewRat(600) - candidates[2].Assets = sdk.NewRat(1000) - candidates[3].Assets = sdk.OneRat - candidates[4].Assets = sdk.NewRat(10) - for _, c := range candidates { - setCandidate(store, c) - } - change, err = UpdateValidatorSet(store, p, params) - require.Nil(err) - require.Equal(5, len(change), "%v", change) // 3 changed, 1 added, 1 removed - candidates = GetCandidates(store) - testChange(t, candidates[0].validator(), change[0]) - testChange(t, candidates[1].validator(), change[1]) - testChange(t, candidates[2].validator(), change[2]) - testRemove(t, candidates[3].validator(), change[3]) - testChange(t, candidates[4].validator(), change[4]) -} -*/ - -// XXX BROKEN TEST -func TestGetValidators(t *testing.T) { - ctx, _, keeper := createTestInput(t, nil, false, 0) - params := keeper.GetParams(ctx) - params.MaxValidators = 2 - keeper.setParams(ctx, params) - candidatesFromAddrs(ctx, keeper, addrs, []int64{0, 0, 0, 400, 200, 0}) // XXX rearrange these something messed is happenning! - - validators := keeper.GetValidators(ctx) - require.Equal(t, 2, len(validators)) - assert.Equal(t, addrs[0], validators[0].Address, "%v", validators) - assert.Equal(t, addrs[1], validators[1].Address, "%v", validators) -} - -// XXX expand to include both liabilities and assets use/test all candidate1 fields +// This function tests GetCandidate, GetCandidates, setCandidate, removeCandidate func TestCandidate(t *testing.T) { ctx, _, keeper := createTestInput(t, nil, false, 0) @@ -228,29 +57,49 @@ func TestCandidate(t *testing.T) { // check the empty keeper first _, found := keeper.GetCandidate(ctx, addrVal1) assert.False(t, found) - resAddrs := keeper.GetCandidates(ctx, 100) - assert.Zero(t, len(resAddrs)) + 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) - assert.True(t, found) + require.True(t, found) assert.True(t, candidatesEqual(candidate1, resCand), "%v \n %v", resCand, candidate1) // modify a records, save, and retrieve candidate1.Liabilities = sdk.NewRat(99) keeper.setCandidate(ctx, candidate1) resCand, found = keeper.GetCandidate(ctx, addrVal1) - assert.True(t, found) + require.True(t, found) assert.True(t, candidatesEqual(candidate1, resCand)) // also test that the address has been added to address list - resAddrs = keeper.GetCandidates(ctx, 100) - require.Equal(t, 1, len(resAddrs)) - assert.Equal(t, addrVal1, resAddrs[0].Address) + resCands = keeper.GetCandidates(ctx, 100) + require.Equal(t, 1, len(resCands)) + assert.Equal(t, addrVal1, resCands[0].Address) + // add other candidates + keeper.setCandidate(ctx, candidate2) + keeper.setCandidate(ctx, candidate3) + resCand, found = keeper.GetCandidate(ctx, addrVal2) + require.True(t, found) + assert.True(t, candidatesEqual(candidate2, resCand), "%v \n %v", resCand, candidate2) + resCand, found = keeper.GetCandidate(ctx, addrVal3) + require.True(t, found) + assert.True(t, candidatesEqual(candidate3, resCand), "%v \n %v", resCand, candidate3) + 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) + + // remove a record + keeper.removeCandidate(ctx, candidate2.Address) + _, found = keeper.GetCandidate(ctx, addrVal2) + assert.False(t, found) } +// tests GetDelegatorBond, GetDelegatorBonds, SetDelegatorBond, removeDelegatorBond func TestBond(t *testing.T) { ctx, _, keeper := createTestInput(t, nil, false, 0) @@ -315,6 +164,131 @@ func TestBond(t *testing.T) { assert.True(t, bondsEqual(bond2to1, resBonds[0])) assert.True(t, bondsEqual(bond2to2, resBonds[1])) assert.True(t, bondsEqual(bond2to3, resBonds[2])) + + // delete a record + keeper.removeDelegatorBond(ctx, bond2to3) + _, found = keeper.getDelegatorBond(ctx, addrDel2, addrVal3) + assert.False(t, found) + resBonds = keeper.getDelegatorBonds(ctx, addrDel2, 5) + require.Equal(t, 2, len(resBonds)) + assert.True(t, bondsEqual(bond2to1, resBonds[0])) + assert.True(t, bondsEqual(bond2to2, resBonds[1])) + + // delete all the records from delegator 2 + keeper.removeDelegatorBond(ctx, bond2to1) + keeper.removeDelegatorBond(ctx, bond2to2) + _, found = keeper.getDelegatorBond(ctx, addrDel2, addrVal1) + assert.False(t, found) + _, found = keeper.getDelegatorBond(ctx, addrDel2, addrVal2) + assert.False(t, found) + resBonds = keeper.getDelegatorBonds(ctx, addrDel2, 5) + require.Equal(t, 0, len(resBonds)) +} + +// TODO integrate in testing for equal validators, whichever one was a validator +// first remains the validator https://github.com/cosmos/cosmos-sdk/issues/582 +func TestGetValidators(t *testing.T) { + ctx, _, keeper := createTestInput(t, nil, false, 0) + + // 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++ { + c := Candidate{ + Status: Unbonded, + PubKey: pks[i], + Address: addrs[i], + Assets: sdk.NewRat(amts[i]), + Liabilities: sdk.NewRat(amts[i]), + } + keeper.setCandidate(ctx, c) + candidates[i] = c + } + + // first make sure everything as normal is ordered + validators := keeper.GetValidators(ctx) + require.Equal(t, len(validators), n) + assert.Equal(t, sdk.NewRat(400), validators[0].VotingPower, "%v", validators) + assert.Equal(t, sdk.NewRat(200), validators[1].VotingPower, "%v", validators) + assert.Equal(t, sdk.NewRat(100), validators[2].VotingPower, "%v", validators) + assert.Equal(t, sdk.NewRat(1), validators[3].VotingPower, "%v", validators) + assert.Equal(t, sdk.NewRat(0), validators[4].VotingPower, "%v", validators) + assert.Equal(t, candidates[3].Address, validators[0].Address, "%v", validators) + assert.Equal(t, candidates[4].Address, validators[1].Address, "%v", validators) + assert.Equal(t, candidates[1].Address, validators[2].Address, "%v", validators) + assert.Equal(t, candidates[2].Address, validators[3].Address, "%v", validators) + assert.Equal(t, candidates[0].Address, validators[4].Address, "%v", validators) + + // test a basic increase in voting power + candidates[3].Assets = sdk.NewRat(500) + keeper.setCandidate(ctx, candidates[3]) + validators = keeper.GetValidators(ctx) + require.Equal(t, len(validators), n) + assert.Equal(t, sdk.NewRat(500), validators[0].VotingPower, "%v", validators) + assert.Equal(t, candidates[3].Address, validators[0].Address, "%v", validators) + + // test a decrease in voting power + candidates[3].Assets = sdk.NewRat(300) + keeper.setCandidate(ctx, candidates[3]) + validators = keeper.GetValidators(ctx) + require.Equal(t, len(validators), n) + assert.Equal(t, sdk.NewRat(300), validators[0].VotingPower, "%v", validators) + assert.Equal(t, candidates[3].Address, validators[0].Address, "%v", validators) + + // test a swap in voting power + candidates[0].Assets = sdk.NewRat(600) + keeper.setCandidate(ctx, candidates[0]) + validators = keeper.GetValidators(ctx) + require.Equal(t, len(validators), n) + assert.Equal(t, sdk.NewRat(600), validators[0].VotingPower, "%v", validators) + assert.Equal(t, candidates[0].Address, validators[0].Address, "%v", validators) + assert.Equal(t, sdk.NewRat(300), validators[1].VotingPower, "%v", validators) + assert.Equal(t, candidates[3].Address, validators[1].Address, "%v", validators) + + // test the max validators term + params := keeper.GetParams(ctx) + n = 2 + params.MaxValidators = uint16(n) + keeper.setParams(ctx, params) + validators = keeper.GetValidators(ctx) + require.Equal(t, len(validators), n) + assert.Equal(t, sdk.NewRat(600), validators[0].VotingPower, "%v", validators) + assert.Equal(t, candidates[0].Address, validators[0].Address, "%v", validators) + assert.Equal(t, sdk.NewRat(300), validators[1].VotingPower, "%v", validators) + 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 +} + +// test if is a validator from the last update +func TestIsRecentValidator(t *testing.T) { + //TODO + + // test that an empty validator set doesn't have any validators + // get the validators for the first time + // test a basic retrieve of something that should be a recent validator + // test a basic retrieve of something that should not be a recent validator + // remove that validator, but don't retrieve the recent validator group + // test that removed validator is not considered a recent validator } func TestParams(t *testing.T) { diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 07f53b8315..aef4255813 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -154,17 +154,3 @@ func testAddr(addr string) sdk.Address { } return res } - -// XXX TODO remove this dep -func candidatesFromAddrs(ctx sdk.Context, keeper Keeper, addrs []crypto.Address, amts []int64) { - for i := 0; i < len(amts); i++ { - c := Candidate{ - Status: Unbonded, - PubKey: pks[i], - Address: addrs[i], - Assets: sdk.NewRat(amts[i]), - Liabilities: sdk.NewRat(amts[i]), - } - keeper.setCandidate(ctx, c) - } -}