diff --git a/x/stake/handler.go b/x/stake/handler.go index cf88fcc5ed..46a18d392f 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -2,7 +2,6 @@ package stake import ( "bytes" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/abci/types" @@ -164,7 +163,6 @@ func delegate(ctx sdk.Context, k Keeper, delegatorAddr sdk.Address, return nil, err } validator, pool, newShares := validator.addTokensFromDel(pool, bondAmt.Amount) - fmt.Printf("debug newShares: %v\n", newShares) bond.Shares = bond.Shares.Add(newShares) // Update bond height diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index a88cf220d0..6260c06fb8 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -1,7 +1,6 @@ package stake import ( - "fmt" "strconv" "testing" @@ -106,7 +105,6 @@ func TestIncrementsMsgDelegate(t *testing.T) { pool := keeper.GetPool(ctx) exRate := validator.DelegatorShareExRate(pool) - fmt.Printf("debug validator: %v\n", validator) require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v, i = %v", exRate, i) expBond := int64(i+1) * bondAmount diff --git a/x/stake/keeper.go b/x/stake/keeper.go index b061c846f9..da3c205fca 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -2,6 +2,7 @@ package stake import ( "bytes" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -68,42 +69,53 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators Va } func (k Keeper) setValidator(ctx sdk.Context, validator Validator) Validator { + fmt.Println("wackydebugoutput setValidator 0") store := ctx.KVStore(k.storeKey) pool := k.getPool(store) address := validator.Address // update the main list ordered by address before exiting defer func() { + fmt.Println("wackydebugoutput setValidator 1") bz := k.cdc.MustMarshalBinary(validator) store.Set(GetValidatorKey(address), bz) }() + fmt.Println("wackydebugoutput setValidator 2") // retreive the old validator record oldValidator, oldFound := k.GetValidator(ctx, address) powerIncreasing := false if oldFound { + fmt.Println("wackydebugoutput setValidator 3") // if the voting power is the same no need to update any of the other indexes if oldValidator.Status == sdk.Bonded && oldValidator.PShares.Equal(validator.PShares) { + fmt.Println("wackydebugoutput setValidator 4") return validator } else if oldValidator.PShares.Bonded().LT(validator.PShares.Bonded()) { + fmt.Println("wackydebugoutput setValidator 5") powerIncreasing = true } + fmt.Println("wackydebugoutput setValidator 6") // delete the old record in the power ordered list store.Delete(GetValidatorsBondedByPowerKey(oldValidator, pool)) } + fmt.Println("wackydebugoutput setValidator 7") // if already a validator, copy the old block height and counter, else set them if oldFound && oldValidator.Status == sdk.Bonded { + fmt.Println("wackydebugoutput setValidator 8") validator.BondHeight = oldValidator.BondHeight validator.BondIntraTxCounter = oldValidator.BondIntraTxCounter } else { + fmt.Println("wackydebugoutput setValidator 9") validator.BondHeight = ctx.BlockHeight() counter := k.getIntraTxCounter(ctx) validator.BondIntraTxCounter = counter k.setIntraTxCounter(ctx, counter+1) } + fmt.Println("wackydebugoutput setValidator 10") // update the list ordered by voting power bz := k.cdc.MustMarshalBinary(validator) @@ -111,6 +123,7 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) Validator { // add to the validators and return to update list if is already a validator and power is increasing if powerIncreasing && oldFound && oldValidator.Status == sdk.Bonded { + fmt.Println("wackydebugoutput setValidator 11") // update the recent validator store store.Set(GetValidatorsBondedKey(validator.PubKey), bz) @@ -120,17 +133,20 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) Validator { store.Set(GetTendermintUpdatesKey(address), bz) return validator } + fmt.Println("wackydebugoutput setValidator 12") // update the validator set for this validator valIsNowBonded := k.updateValidators(ctx, store, validator.Address) if (!oldFound && valIsNowBonded) || (oldFound && oldValidator.Status != sdk.Bonded && valIsNowBonded) { + fmt.Println("wackydebugoutput setValidator 13") validator.Status = sdk.Bonded validator, pool = validator.UpdateSharesLocation(pool) k.setPool(ctx, pool) } + fmt.Println("wackydebugoutput setValidator 14") return validator } @@ -216,12 +232,14 @@ func (k Keeper) GetValidatorsBondedByPower(ctx sdk.Context) []Validator { // validator without needing to iterate over the subspace as we do in // GetValidators. func (k Keeper) updateValidators(ctx sdk.Context, store sdk.KVStore, updatedValidatorAddr sdk.Address) (updatedIsBonded bool) { + fmt.Println("wackydebugoutput updateValidators 0") updatedIsBonded = false // clear the current validators store, add to the ToKickOut temp store toKickOut := make(map[string][]byte) // map[key]value iterator := store.SubspaceIterator(ValidatorsBondedKey) for ; iterator.Valid(); iterator.Next() { + fmt.Println("wackydebugoutput updateValidators 1") bz := iterator.Value() var validator Validator @@ -233,17 +251,23 @@ func (k Keeper) updateValidators(ctx sdk.Context, store sdk.KVStore, updatedVali toKickOut[string(addr)] = iterator.Value() store.Delete(iterator.Key()) } + fmt.Println("wackydebugoutput updateValidators 2") iterator.Close() // add the actual validator power sorted store maxValidators := k.GetParams(ctx).MaxValidators + fmt.Printf("debug maxValidators: %v\n", maxValidators) iterator = store.ReverseSubspaceIterator(ValidatorsByPowerKey) // largest to smallest i := 0 for ; ; i++ { + fmt.Println("wackydebugoutput updateValidators 3") + fmt.Printf("debug i: %v\n", i) if !iterator.Valid() || i > int(maxValidators-1) { + fmt.Println("wackydebugoutput updateValidators 4") iterator.Close() break } + fmt.Println("wackydebugoutput updateValidators 5") bz := iterator.Value() var validator Validator k.cdc.MustUnmarshalBinary(bz, &validator) @@ -256,19 +280,25 @@ func (k Keeper) updateValidators(ctx sdk.Context, store sdk.KVStore, updatedVali // MOST IMPORTANTLY, add to the accumulated changes if this is the modified validator if bytes.Equal(updatedValidatorAddr, validator.Address) { + fmt.Println("wackydebugoutput updateValidators 6") bz = k.cdc.MustMarshalBinary(validator.abciValidator(k.cdc)) store.Set(GetTendermintUpdatesKey(updatedValidatorAddr), bz) updatedIsBonded = true // the updatedValidatorAddr is for a bonded validator } + fmt.Println("wackydebugoutput updateValidators 7") iterator.Next() } + fmt.Println("wackydebugoutput updateValidators 8") // add any kicked out validators to the accumulated changes for tendermint for key, value := range toKickOut { + fmt.Println("wackydebugoutput updateValidators 9") if value == nil { + fmt.Println("wackydebugoutput updateValidators 10") continue } + fmt.Println("wackydebugoutput updateValidators 11") addr := AddrFromKey([]byte(key)) var validator Validator @@ -276,6 +306,7 @@ func (k Keeper) updateValidators(ctx sdk.Context, store sdk.KVStore, updatedVali bz := k.cdc.MustMarshalBinary(validator.abciValidatorZero(k.cdc)) store.Set(GetTendermintUpdatesKey(addr), bz) } + fmt.Println("wackydebugoutput updateValidators 12") return } diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index fa3321fc04..43b383456c 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -55,6 +55,7 @@ func TestValidatorBasics(t *testing.T) { for i, amt := range amts { validators[i] = NewValidator(addrVals[i], pks[i], Description{}) validators[i].Status = sdk.Bonded + validators[i].PShares = NewBondedShares(sdk.ZeroRat()) validators[i].addTokensFromDel(pool, amt) } @@ -307,7 +308,6 @@ func TestGetValidatorsEdgeCases(t *testing.T) { require.Equal(t, validator.BondHeight, int64(40)) } -// TODO seperate out into multiple tests func TestValidatorBondHeight(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) @@ -323,7 +323,7 @@ func TestValidatorBondHeight(t *testing.T) { validators[0].DelegatorShares = sdk.NewRat(200) keeper.setValidator(ctx, validators[0]) validators[1] = NewValidator(addrs[1], pks[1], Description{}) - validators[1].PShares = NewBondedShares(sdk.NewRat(100)) + validators[1].PShares = NewUnbondedShares(sdk.NewRat(100)) validators[1].DelegatorShares = sdk.NewRat(100) validators[2] = NewValidator(addrs[2], pks[2], Description{}) validators[2].PShares = NewUnbondedShares(sdk.NewRat(100)) @@ -338,8 +338,8 @@ func TestValidatorBondHeight(t *testing.T) { require.Equal(t, uint16(len(gotValidators)), params.MaxValidators) assert.True(ValEq(t, validators[0], gotValidators[0])) assert.True(ValEq(t, validators[1], gotValidators[1])) - validators[1].PShares = NewBondedShares(sdk.NewRat(1100)) - validators[2].PShares = NewBondedShares(sdk.NewRat(1100)) + validators[1].PShares = NewUnbondedShares(sdk.NewRat(150)) + validators[2].PShares = NewUnbondedShares(sdk.NewRat(150)) keeper.setValidator(ctx, validators[2]) keeper.setValidator(ctx, validators[1]) gotValidators = keeper.GetValidatorsBondedByPower(ctx) @@ -363,7 +363,7 @@ func TestGetValidatorsEdgeCases2(t *testing.T) { var validators [5]Validator for i, amt := range amts { validators[i] = NewValidator(addrs[i], pks[i], Description{}) - validators[i].PShares = NewBondedShares(sdk.NewRat(amt)) + validators[i].PShares = NewUnbondedShares(sdk.NewRat(amt)) validators[i].DelegatorShares = sdk.NewRat(amt) keeper.setValidator(ctx, validators[i]) } diff --git a/x/stake/pool.go b/x/stake/pool.go index c8c389c679..23e1764142 100644 --- a/x/stake/pool.go +++ b/x/stake/pool.go @@ -87,25 +87,25 @@ func (p Pool) unbondedShareExRate() sdk.Rat { //_______________________________________________________________________ -func (p Pool) addTokensBonded(amount int64) (p2 Pool, issuedShares sdk.Rat) { - issuedShares = sdk.NewRat(amount).Quo(p.bondedShareExRate()) // tokens * (shares/tokens) - p.BondedShares = p.BondedShares.Add(issuedShares) - p.BondedTokens += amount - return p, issuedShares +func (p Pool) addTokensUnbonded(amount int64) (p2 Pool, issuedShares PoolShares) { + issuedSharesAmount := sdk.NewRat(amount).Quo(p.unbondedShareExRate()) // tokens * (shares/tokens) + p.UnbondedShares = p.UnbondedShares.Add(issuedSharesAmount) + p.UnbondedTokens += amount + return p, NewUnbondedShares(issuedSharesAmount) } -func (p Pool) removeSharesBonded(shares sdk.Rat) (p2 Pool, removedTokens int64) { - removedTokens = p.bondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares - p.BondedShares = p.BondedShares.Sub(shares) - p.BondedTokens -= removedTokens +func (p Pool) removeSharesUnbonded(shares sdk.Rat) (p2 Pool, removedTokens int64) { + removedTokens = p.unbondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares + p.UnbondedShares = p.UnbondedShares.Sub(shares) + p.UnbondedTokens -= removedTokens return p, removedTokens } -func (p Pool) addTokensUnbonding(amount int64) (p2 Pool, issuedShares sdk.Rat) { - issuedShares = sdk.NewRat(amount).Quo(p.unbondingShareExRate()) // tokens * (shares/tokens) - p.UnbondingShares = p.UnbondingShares.Add(issuedShares) +func (p Pool) addTokensUnbonding(amount int64) (p2 Pool, issuedShares PoolShares) { + issuedSharesAmount := sdk.NewRat(amount).Quo(p.unbondingShareExRate()) // tokens * (shares/tokens) + p.UnbondingShares = p.UnbondingShares.Add(issuedSharesAmount) p.UnbondingTokens += amount - return p, issuedShares + return p, NewUnbondingShares(issuedSharesAmount) } func (p Pool) removeSharesUnbonding(shares sdk.Rat) (p2 Pool, removedTokens int64) { @@ -115,16 +115,16 @@ func (p Pool) removeSharesUnbonding(shares sdk.Rat) (p2 Pool, removedTokens int6 return p, removedTokens } -func (p Pool) addTokensUnbonded(amount int64) (p2 Pool, issuedShares sdk.Rat) { - issuedShares = sdk.NewRat(amount).Quo(p.unbondedShareExRate()) // tokens * (shares/tokens) - p.UnbondedShares = p.UnbondedShares.Add(issuedShares) - p.UnbondedTokens += amount - return p, issuedShares +func (p Pool) addTokensBonded(amount int64) (p2 Pool, issuedShares PoolShares) { + issuedSharesAmount := sdk.NewRat(amount).Quo(p.bondedShareExRate()) // tokens * (shares/tokens) + p.BondedShares = p.BondedShares.Add(issuedSharesAmount) + p.BondedTokens += amount + return p, NewBondedShares(issuedSharesAmount) } -func (p Pool) removeSharesUnbonded(shares sdk.Rat) (p2 Pool, removedTokens int64) { - removedTokens = p.unbondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares - p.UnbondedShares = p.UnbondedShares.Sub(shares) - p.UnbondedTokens -= removedTokens +func (p Pool) removeSharesBonded(shares sdk.Rat) (p2 Pool, removedTokens int64) { + removedTokens = p.bondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares + p.BondedShares = p.BondedShares.Sub(shares) + p.BondedTokens -= removedTokens return p, removedTokens } diff --git a/x/stake/pool_test.go b/x/stake/pool_test.go index a749f6337c..143c33bfb9 100644 --- a/x/stake/pool_test.go +++ b/x/stake/pool_test.go @@ -74,7 +74,7 @@ func TestAddTokensBonded(t *testing.T) { assert.Equal(t, poolB.bondedShareExRate(), sdk.OneRat()) // correct changes to bonded shares and bonded pool - assert.Equal(t, poolB.BondedShares, poolA.BondedShares.Add(sharesB)) + assert.Equal(t, poolB.BondedShares, poolA.BondedShares.Add(sharesB.Amount)) assert.Equal(t, poolB.BondedTokens, poolA.BondedTokens+10) // same number of bonded shares / tokens when exchange rate is one @@ -106,7 +106,7 @@ func TestAddTokensUnbonded(t *testing.T) { assert.Equal(t, poolB.unbondedShareExRate(), sdk.OneRat()) // correct changes to unbonded shares and unbonded pool - assert.Equal(t, poolB.UnbondedShares, poolA.UnbondedShares.Add(sharesB)) + assert.Equal(t, poolB.UnbondedShares, poolA.UnbondedShares.Add(sharesB.Amount)) assert.Equal(t, poolB.UnbondedTokens, poolA.UnbondedTokens+10) // same number of unbonded shares / tokens when exchange rate is one diff --git a/x/stake/validator.go b/x/stake/validator.go index d6473c64d5..99802df583 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -105,16 +105,6 @@ func NewDescription(moniker, identity, website, details string) Description { //XXX updateDescription function //XXX enforce limit to number of description characters -// get the exchange rate of tokens over delegator shares -// UNITS: eq-val-bonded-shares/delegator-shares -func (v Validator) DelegatorShareExRate(p Pool) sdk.Rat { - if v.DelegatorShares.IsZero() { - return sdk.OneRat() - } - eqBondedShares := v.PShares.ToBonded(p).Amount - return eqBondedShares.Quo(v.DelegatorShares) -} - // abci validator from stake validator type func (v Validator) abciValidator(cdc *wire.Codec) abci.Validator { return abci.Validator{ @@ -156,17 +146,13 @@ func (v Validator) UpdateSharesLocation(p Pool) (Validator, Pool) { p, tokens = p.removeSharesBonded(v.PShares.Amount) } - var shares sdk.Rat switch v.Status { case sdk.Unbonded, sdk.Revoked: - p, shares = p.addTokensUnbonded(tokens) - v.PShares = NewUnbondedShares(shares) + p, v.PShares = p.addTokensUnbonded(tokens) case sdk.Unbonding: - p, shares = p.addTokensUnbonding(tokens) - v.PShares = NewUnbondingShares(shares) + p, v.PShares = p.addTokensUnbonding(tokens) case sdk.Bonded: - p, shares = p.addTokensBonded(tokens) - v.PShares = NewBondedShares(shares) + p, v.PShares = p.addTokensBonded(tokens) } return v, p } @@ -187,7 +173,10 @@ func (v Validator) EquivalentBondedShares(p Pool) (eqBondedShares sdk.Rat) { func (v Validator) addTokensFromDel(p Pool, amount int64) (validator2 Validator, p2 Pool, issuedDelegatorShares sdk.Rat) { - var equivalentBondedShares, poolShares sdk.Rat + exRate := v.DelegatorShareExRate(p) // bshr/delshr + + var poolShares PoolShares + var equivalentBondedShares sdk.Rat switch v.Status { case sdk.Unbonded, sdk.Revoked: p, poolShares = p.addTokensUnbonded(amount) @@ -196,10 +185,9 @@ func (v Validator) addTokensFromDel(p Pool, case sdk.Bonded: p, poolShares = p.addTokensBonded(amount) } - v.PShares.Amount = v.PShares.Amount.Add(poolShares) - equivalentBondedShares = v.PShares.ToBonded(p).Amount + v.PShares.Amount = v.PShares.Amount.Add(poolShares.Amount) + equivalentBondedShares = poolShares.ToBonded(p).Amount - exRate := v.DelegatorShareExRate(p) // bshr/delshr issuedDelegatorShares = equivalentBondedShares.Quo(exRate) // bshr/(bshr/delshr) = delshr v.DelegatorShares = v.DelegatorShares.Add(issuedDelegatorShares) @@ -231,6 +219,16 @@ func (v Validator) removeDelShares(p Pool, return v, p, createdCoins } +// get the exchange rate of tokens over delegator shares +// UNITS: eq-val-bonded-shares/delegator-shares +func (v Validator) DelegatorShareExRate(p Pool) sdk.Rat { + if v.DelegatorShares.IsZero() { + return sdk.OneRat() + } + eqBondedShares := v.PShares.ToBonded(p).Amount + return eqBondedShares.Quo(v.DelegatorShares) +} + //______________________________________________________________________ // ensure fulfills the sdk validator types