diff --git a/types/rational.go b/types/rational.go index 7cd082ac77..0709a350f4 100644 --- a/types/rational.go +++ b/types/rational.go @@ -189,5 +189,5 @@ func RatsEqual(r1s, r2s []Rat) bool { // intended to be used with require/assert: require.True(RatEq(...)) func RatEq(t *testing.T, exp, got Rat) (*testing.T, bool, string, Rat, Rat) { - return t, exp.Equal(got), "expected:\t%v\ngot:\t%v", exp, got + return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 00f9b2b35a..ff99827430 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -43,7 +43,7 @@ func TestDuplicatesMsgDeclareCandidacy(t *testing.T) { assert.True(t, got.IsOK(), "%v", got) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - assert.Equal(t, sdk.Unbonded, validator.Status) + assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, validatorAddr, validator.Address) assert.Equal(t, pk, validator.PubKey) assert.Equal(t, sdk.NewRat(10), validator.BondedShares) diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 4992b4c71f..b95247ade1 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -106,16 +106,18 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { } // update the list ordered by voting power - bzVal := k.cdc.MustMarshalBinary(validator) - store.Set(GetValidatorsBondedByPowerKey(validator), bzVal) + bz := k.cdc.MustMarshalBinary(validator) + store.Set(GetValidatorsBondedByPowerKey(validator), bz) // add to the validators and return to update list if is already a validator and power is increasing if powerIncreasing && oldValidator.Status == sdk.Bonded { - bzABCI := k.cdc.MustMarshalBinary(validator.abciValidator(k.cdc)) - store.Set(GetTendermintUpdatesKey(address), bzABCI) - // also update the recent validator store - store.Set(GetValidatorsBondedKey(validator.PubKey), bzVal) + // update the recent validator store + store.Set(GetValidatorsBondedKey(validator.PubKey), bz) + + // and the Tendermint updates + bz := k.cdc.MustMarshalBinary(validator.abciValidator(k.cdc)) + store.Set(GetTendermintUpdatesKey(address), bz) return } @@ -195,7 +197,7 @@ func (k Keeper) GetValidatorsBondedByPower(ctx sdk.Context) []Validator { validators[i] = validator iterator.Next() } - return validators + return validators[:i] // trim } // XXX TODO build in consideration for revoked diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index 172633d33b..59f2d06385 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -23,8 +23,8 @@ var ( } ) -// This function tests GetValidator, GetValidatorsBonded, setValidator, removeValidator -func TestValidator(t *testing.T) { +// This function tests setValidator, GetValidator, GetValidatorsBonded, removeValidator +func TestValidatorBasics(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) //construct the validators @@ -32,6 +32,7 @@ func TestValidator(t *testing.T) { amts := []int64{9, 8, 7} for i, amt := range amts { validators[i] = NewValidator(addrVals[i], pks[i], Description{}) + validators[i].Status = sdk.Bonded validators[i].BondedShares = sdk.NewRat(amt) validators[i].DelegatorShares = sdk.NewRat(amt) } @@ -39,41 +40,46 @@ func TestValidator(t *testing.T) { // check the empty keeper first _, found := keeper.GetValidator(ctx, addrVals[0]) assert.False(t, found) - resCands := keeper.GetValidatorsBonded(ctx) - assert.Zero(t, len(resCands)) + resVals := keeper.GetValidatorsBonded(ctx) + assert.Zero(t, len(resVals)) // set and retrieve a record keeper.setValidator(ctx, validators[0]) - resCand, found := keeper.GetValidator(ctx, addrVals[0]) + resVal, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - assert.True(t, validators[0].equal(resCand), "%v \n %v", resCand, validators[0]) + assert.True(ValEq(t, validators[0], resVal)) + + resVals = keeper.GetValidatorsBonded(ctx) + require.Equal(t, 1, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[0])) // modify a records, save, and retrieve - validators[0].DelegatorShares = sdk.NewRat(99) + validators[0].BondedShares = sdk.NewRat(10) + validators[0].DelegatorShares = sdk.NewRat(10) keeper.setValidator(ctx, validators[0]) - resCand, found = keeper.GetValidator(ctx, addrVals[0]) + resVal, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - assert.True(t, validators[0].equal(resCand)) + assert.True(ValEq(t, validators[0], resVal)) - // also test that the address has been added to address list - resCands = keeper.GetValidatorsBonded(ctx) - require.Equal(t, 1, len(resCands)) - assert.Equal(t, addrVals[0], resCands[0].Address) + resVals = keeper.GetValidatorsBonded(ctx) + require.Equal(t, 1, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[0])) // add other validators keeper.setValidator(ctx, validators[1]) keeper.setValidator(ctx, validators[2]) - resCand, found = keeper.GetValidator(ctx, addrVals[1]) + resVal, found = keeper.GetValidator(ctx, addrVals[1]) require.True(t, found) - assert.True(t, validators[1].equal(resCand), "%v \n %v", resCand, validators[1]) - resCand, found = keeper.GetValidator(ctx, addrVals[2]) + assert.True(ValEq(t, validators[1], resVal)) + resVal, found = keeper.GetValidator(ctx, addrVals[2]) require.True(t, found) - assert.True(t, validators[2].equal(resCand), "%v \n %v", resCand, validators[2]) - resCands = keeper.GetValidatorsBonded(ctx) - require.Equal(t, 3, len(resCands)) - assert.True(t, validators[0].equal(resCands[0]), "%v \n %v", resCands[0], validators[0]) - assert.True(t, validators[1].equal(resCands[1]), "%v \n %v", resCands[1], validators[1]) - assert.True(t, validators[2].equal(resCands[2]), "%v \n %v", resCands[2], validators[2]) + assert.True(ValEq(t, validators[2], resVal)) + + resVals = keeper.GetValidatorsBonded(ctx) + require.Equal(t, 3, len(resVals)) + assert.True(ValEq(t, validators[0], resVals[2])) // order doesn't matter here + assert.True(ValEq(t, validators[1], resVals[0])) + assert.True(ValEq(t, validators[2], resVals[1])) // remove a record keeper.removeValidator(ctx, validators[1].Address) @@ -81,105 +87,8 @@ func TestValidator(t *testing.T) { assert.False(t, found) } -// tests GetDelegation, GetDelegations, SetDelegation, removeDelegation, GetBonds -func TestBond(t *testing.T) { - ctx, _, keeper := createTestInput(t, false, 0) - - //construct the validators - amts := []int64{9, 8, 7} - var validators [3]Validator - for i, amt := range amts { - validators[i] = NewValidator(addrVals[i], pks[i], Description{}) - validators[i].BondedShares = sdk.NewRat(amt) - validators[i].DelegatorShares = sdk.NewRat(amt) - } - - // first add a validators[0] to delegate too - keeper.setValidator(ctx, validators[0]) - - bond1to1 := Delegation{ - DelegatorAddr: addrDels[0], - ValidatorAddr: addrVals[0], - Shares: sdk.NewRat(9), - } - - // check the empty keeper first - _, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - assert.False(t, found) - - // set and retrieve a record - keeper.setDelegation(ctx, bond1to1) - resBond, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - assert.True(t, found) - assert.True(t, bond1to1.equal(resBond)) - - // modify a records, save, and retrieve - bond1to1.Shares = sdk.NewRat(99) - keeper.setDelegation(ctx, bond1to1) - resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - assert.True(t, found) - assert.True(t, bond1to1.equal(resBond)) - - // add some more records - keeper.setValidator(ctx, validators[1]) - keeper.setValidator(ctx, validators[2]) - bond1to2 := Delegation{addrDels[0], addrVals[1], sdk.NewRat(9), 0} - bond1to3 := Delegation{addrDels[0], addrVals[2], sdk.NewRat(9), 1} - bond2to1 := Delegation{addrDels[1], addrVals[0], sdk.NewRat(9), 2} - bond2to2 := Delegation{addrDels[1], addrVals[1], sdk.NewRat(9), 3} - bond2to3 := Delegation{addrDels[1], addrVals[2], sdk.NewRat(9), 4} - keeper.setDelegation(ctx, bond1to2) - keeper.setDelegation(ctx, bond1to3) - keeper.setDelegation(ctx, bond2to1) - keeper.setDelegation(ctx, bond2to2) - keeper.setDelegation(ctx, bond2to3) - - // test all bond retrieve capabilities - resBonds := keeper.GetDelegations(ctx, addrDels[0], 5) - require.Equal(t, 3, len(resBonds)) - assert.True(t, bond1to1.equal(resBonds[0])) - assert.True(t, bond1to2.equal(resBonds[1])) - assert.True(t, bond1to3.equal(resBonds[2])) - resBonds = keeper.GetDelegations(ctx, addrDels[0], 3) - require.Equal(t, 3, len(resBonds)) - resBonds = keeper.GetDelegations(ctx, addrDels[0], 2) - require.Equal(t, 2, len(resBonds)) - resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) - require.Equal(t, 3, len(resBonds)) - assert.True(t, bond2to1.equal(resBonds[0])) - assert.True(t, bond2to2.equal(resBonds[1])) - assert.True(t, bond2to3.equal(resBonds[2])) - allBonds := keeper.getBonds(ctx, 1000) - require.Equal(t, 6, len(allBonds)) - assert.True(t, bond1to1.equal(allBonds[0])) - assert.True(t, bond1to2.equal(allBonds[1])) - assert.True(t, bond1to3.equal(allBonds[2])) - assert.True(t, bond2to1.equal(allBonds[3])) - assert.True(t, bond2to2.equal(allBonds[4])) - assert.True(t, bond2to3.equal(allBonds[5])) - - // delete a record - keeper.removeDelegation(ctx, bond2to3) - _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[2]) - assert.False(t, found) - resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) - require.Equal(t, 2, len(resBonds)) - assert.True(t, bond2to1.equal(resBonds[0])) - assert.True(t, bond2to2.equal(resBonds[1])) - - // delete all the records from delegator 2 - keeper.removeDelegation(ctx, bond2to1) - keeper.removeDelegation(ctx, bond2to2) - _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[0]) - assert.False(t, found) - _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[1]) - assert.False(t, found) - resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) - require.Equal(t, 0, len(resBonds)) -} - -// TODO seperate out into multiple tests -func TestGetValidators(t *testing.T) { +// test how the validators are sorted, tests GetValidatorsBondedByPower +func GetValidatorSorting(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) // initialize some validators into the state @@ -195,7 +104,7 @@ func TestGetValidators(t *testing.T) { // first make sure everything made it in to the gotValidator group gotValidators := keeper.GetValidatorsBondedByPower(ctx) - require.Equal(t, len(gotValidators), n) + require.Equal(t, n, len(gotValidators)) assert.Equal(t, sdk.NewRat(400), gotValidators[0].BondedShares, "%v", gotValidators) assert.Equal(t, sdk.NewRat(200), gotValidators[1].BondedShares, "%v", gotValidators) assert.Equal(t, sdk.NewRat(100), gotValidators[2].BondedShares, "%v", gotValidators) @@ -212,8 +121,7 @@ func TestGetValidators(t *testing.T) { keeper.setValidator(ctx, validators[3]) gotValidators = keeper.GetValidatorsBondedByPower(ctx) require.Equal(t, len(gotValidators), n) - assert.Equal(t, sdk.NewRat(500), gotValidators[0].BondedShares, "%v", gotValidators) - assert.Equal(t, validators[3].Address, gotValidators[0].Address, "%v", gotValidators) + assert.Equal(ValEq(t, validators[3], gotValidators[0])) // test a decrease in voting power validators[3].BondedShares = sdk.NewRat(300) @@ -605,6 +513,103 @@ func TestGetTendermintUpdates(t *testing.T) { assert.Equal(t, int64(0), updates[3].Power) } +// tests GetDelegation, GetDelegations, SetDelegation, removeDelegation, GetBonds +func TestBond(t *testing.T) { + ctx, _, keeper := createTestInput(t, false, 0) + + //construct the validators + amts := []int64{9, 8, 7} + var validators [3]Validator + for i, amt := range amts { + validators[i] = NewValidator(addrVals[i], pks[i], Description{}) + validators[i].BondedShares = sdk.NewRat(amt) + validators[i].DelegatorShares = sdk.NewRat(amt) + } + + // first add a validators[0] to delegate too + keeper.setValidator(ctx, validators[0]) + + bond1to1 := Delegation{ + DelegatorAddr: addrDels[0], + ValidatorAddr: addrVals[0], + Shares: sdk.NewRat(9), + } + + // check the empty keeper first + _, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) + assert.False(t, found) + + // set and retrieve a record + keeper.setDelegation(ctx, bond1to1) + resBond, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) + assert.True(t, found) + assert.True(t, bond1to1.equal(resBond)) + + // modify a records, save, and retrieve + bond1to1.Shares = sdk.NewRat(99) + keeper.setDelegation(ctx, bond1to1) + resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) + assert.True(t, found) + assert.True(t, bond1to1.equal(resBond)) + + // add some more records + keeper.setValidator(ctx, validators[1]) + keeper.setValidator(ctx, validators[2]) + bond1to2 := Delegation{addrDels[0], addrVals[1], sdk.NewRat(9), 0} + bond1to3 := Delegation{addrDels[0], addrVals[2], sdk.NewRat(9), 1} + bond2to1 := Delegation{addrDels[1], addrVals[0], sdk.NewRat(9), 2} + bond2to2 := Delegation{addrDels[1], addrVals[1], sdk.NewRat(9), 3} + bond2to3 := Delegation{addrDels[1], addrVals[2], sdk.NewRat(9), 4} + keeper.setDelegation(ctx, bond1to2) + keeper.setDelegation(ctx, bond1to3) + keeper.setDelegation(ctx, bond2to1) + keeper.setDelegation(ctx, bond2to2) + keeper.setDelegation(ctx, bond2to3) + + // test all bond retrieve capabilities + resBonds := keeper.GetDelegations(ctx, addrDels[0], 5) + require.Equal(t, 3, len(resBonds)) + assert.True(t, bond1to1.equal(resBonds[0])) + assert.True(t, bond1to2.equal(resBonds[1])) + assert.True(t, bond1to3.equal(resBonds[2])) + resBonds = keeper.GetDelegations(ctx, addrDels[0], 3) + require.Equal(t, 3, len(resBonds)) + resBonds = keeper.GetDelegations(ctx, addrDels[0], 2) + require.Equal(t, 2, len(resBonds)) + resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) + require.Equal(t, 3, len(resBonds)) + assert.True(t, bond2to1.equal(resBonds[0])) + assert.True(t, bond2to2.equal(resBonds[1])) + assert.True(t, bond2to3.equal(resBonds[2])) + allBonds := keeper.getBonds(ctx, 1000) + require.Equal(t, 6, len(allBonds)) + assert.True(t, bond1to1.equal(allBonds[0])) + assert.True(t, bond1to2.equal(allBonds[1])) + assert.True(t, bond1to3.equal(allBonds[2])) + assert.True(t, bond2to1.equal(allBonds[3])) + assert.True(t, bond2to2.equal(allBonds[4])) + assert.True(t, bond2to3.equal(allBonds[5])) + + // delete a record + keeper.removeDelegation(ctx, bond2to3) + _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[2]) + assert.False(t, found) + resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) + require.Equal(t, 2, len(resBonds)) + assert.True(t, bond2to1.equal(resBonds[0])) + assert.True(t, bond2to2.equal(resBonds[1])) + + // delete all the records from delegator 2 + keeper.removeDelegation(ctx, bond2to1) + keeper.removeDelegation(ctx, bond2to2) + _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[0]) + assert.False(t, found) + _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[1]) + assert.False(t, found) + resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) + require.Equal(t, 0, len(resBonds)) +} + func TestParams(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) expParams := defaultParams() diff --git a/x/stake/types.go b/x/stake/types.go index 1be5d9dc1a..55de038c45 100644 --- a/x/stake/types.go +++ b/x/stake/types.go @@ -2,6 +2,7 @@ package stake import ( "bytes" + "testing" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -127,8 +128,8 @@ func initialPool() Pool { // exchange rate. type Validator struct { Status sdk.BondStatus `json:"status"` // bonded status - Address sdk.Address `json:"address"` // sender of BondTx - UnbondTx returns here - PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator + Address sdk.Address `json:"address"` // sender of BondTx - UnbondTx returns here + PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator // note: There should only be one of the following 3 shares ever active in a delegator // multiple terms are only added here for clarity. @@ -192,6 +193,11 @@ func (v Validator) equal(c2 Validator) bool { v.PrevBondedShares.Equal(c2.PrevBondedShares) } +// intended to be used with require/assert: require.True(ValEq(...)) +func ValEq(t *testing.T, exp, got Validator) (*testing.T, bool, string, Validator, Validator) { + return t, exp.equal(got), "expected:\t%v\ngot:\t\t%v", exp, got +} + // Description - description fields for a validator type Description struct { Moniker string `json:"moniker"` @@ -251,10 +257,10 @@ var _ sdk.Validator = Validator{} // nolint - for sdk.Validator func (v Validator) GetStatus() sdk.BondStatus { return v.Status } -func (v Validator) GetAddress() sdk.Address { return v.Address } -func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } -func (v Validator) GetPower() sdk.Rat { return v.BondedShares } -func (v Validator) GetBondHeight() int64 { return v.BondHeight } +func (v Validator) GetAddress() sdk.Address { return v.Address } +func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } +func (v Validator) GetPower() sdk.Rat { return v.BondedShares } +func (v Validator) GetBondHeight() int64 { return v.BondHeight } //_________________________________________________________________________