diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 7ca2412000..c9c17d7070 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -161,7 +161,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso if len(genTx.Name) > 0 { desc := stake.NewDescription(genTx.Name, "", "", "") validator := stake.NewValidator(genTx.Address, genTx.PubKey, desc) - validator.BondedShares = sdk.NewRat(freeFermionVal) + validator.PShares = stake.NewBondedShares(sdk.NewRat(freeFermionVal)) stakeData.Validators = append(stakeData.Validators, validator) // pool logic diff --git a/types/stake.go b/types/stake.go index 1d97fbbdbe..0e7310962a 100644 --- a/types/stake.go +++ b/types/stake.go @@ -10,9 +10,9 @@ type BondStatus byte // nolint const ( - Bonded BondStatus = 0x00 + Unbonded BondStatus = 0x00 Unbonding BondStatus = 0x01 - Unbonded BondStatus = 0x02 + Bonded BondStatus = 0x02 Revoked BondStatus = 0x03 ) diff --git a/x/stake/handler.go b/x/stake/handler.go index 9e5774768f..5d6c44b1f7 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -2,6 +2,7 @@ package stake import ( "bytes" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/abci/types" @@ -64,7 +65,7 @@ func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keepe } validator := NewValidator(msg.ValidatorAddr, msg.PubKey, msg.Description) - k.setValidator(ctx, validator) + validator = k.setValidator(ctx, validator) tags := sdk.NewTags( "action", []byte("declareCandidacy"), "validator", msg.ValidatorAddr.Bytes(), @@ -117,26 +118,38 @@ func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk } func handleMsgDelegate(ctx sdk.Context, msg MsgDelegate, k Keeper) sdk.Result { + fmt.Println("wackydebugoutput handleMsgDelegate 0") validator, found := k.GetValidator(ctx, msg.ValidatorAddr) if !found { + fmt.Println("wackydebugoutput handleMsgDelegate 1") return ErrBadValidatorAddr(k.codespace).Result() } + fmt.Println("wackydebugoutput handleMsgDelegate 2") if msg.Bond.Denom != k.GetParams(ctx).BondDenom { + fmt.Println("wackydebugoutput handleMsgDelegate 3") return ErrBadBondingDenom(k.codespace).Result() } + fmt.Println("wackydebugoutput handleMsgDelegate 4") if validator.Status == sdk.Revoked { + fmt.Println("wackydebugoutput handleMsgDelegate 5") return ErrValidatorRevoked(k.codespace).Result() } + fmt.Println("wackydebugoutput handleMsgDelegate 6") if ctx.IsCheckTx() { + fmt.Println("wackydebugoutput handleMsgDelegate 7") return sdk.Result{ GasUsed: GasDelegate, } + fmt.Println("wackydebugoutput handleMsgDelegate 9") } + fmt.Println("wackydebugoutput handleMsgDelegate 10") tags, err := delegate(ctx, k, msg.DelegatorAddr, msg.Bond, validator) if err != nil { + fmt.Println("wackydebugoutput handleMsgDelegate 11") return err.Result() } + fmt.Println("wackydebugoutput handleMsgDelegate 12") return sdk.Result{ Tags: tags, } @@ -145,24 +158,32 @@ func handleMsgDelegate(ctx sdk.Context, msg MsgDelegate, k Keeper) sdk.Result { // common functionality between handlers func delegate(ctx sdk.Context, k Keeper, delegatorAddr sdk.Address, bondAmt sdk.Coin, validator Validator) (sdk.Tags, sdk.Error) { + fmt.Println("wackydebugoutput delegate 0") // Get or create the delegator bond bond, found := k.GetDelegation(ctx, delegatorAddr, validator.Address) if !found { + fmt.Println("wackydebugoutput delegate 1") bond = Delegation{ DelegatorAddr: delegatorAddr, ValidatorAddr: validator.Address, Shares: sdk.ZeroRat(), } + fmt.Println("wackydebugoutput delegate 3") } + fmt.Println("wackydebugoutput delegate 4") // Account new shares, save pool := k.GetPool(ctx) _, _, err := k.coinKeeper.SubtractCoins(ctx, bond.DelegatorAddr, sdk.Coins{bondAmt}) + fmt.Println("wackydebugoutput delegate 5") if err != nil { + fmt.Println("wackydebugoutput delegate 6") return nil, err } + fmt.Println("wackydebugoutput delegate 7") 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 04a846200b..4e3db669de 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -1,6 +1,7 @@ package stake import ( + "fmt" "strconv" "testing" @@ -71,9 +72,23 @@ func TestIncrementsMsgDelegate(t *testing.T) { validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) + require.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, bondAmount, validator.DelegatorShares.Evaluate()) assert.Equal(t, bondAmount, validator.BondedShares.Evaluate(), "validator: %v", validator) + _, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) + require.False(t, found) + + bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr) + require.True(t, found) + assert.Equal(t, bondAmount, bond.Shares.Evaluate()) + + pool := keeper.GetPool(ctx) + exRate := validator.DelegatorShareExRate(pool) + require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) + assert.Equal(t, bondAmount, pool.BondedShares.Evaluate()) + assert.Equal(t, bondAmount, pool.BondedTokens) + // just send the same msgbond multiple times msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) @@ -89,6 +104,11 @@ func TestIncrementsMsgDelegate(t *testing.T) { bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.True(t, found) + 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 expDelegatorShares := int64(i+2) * bondAmount // (1 self delegation) expDelegatorAcc := initBond - expBond diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 7508b21c38..b061c846f9 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -2,7 +2,6 @@ package stake import ( "bytes" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -68,7 +67,7 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators Va return validators[:i] // trim } -func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { +func (k Keeper) setValidator(ctx sdk.Context, validator Validator) Validator { store := ctx.KVStore(k.storeKey) pool := k.getPool(store) address := validator.Address @@ -86,9 +85,9 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { if oldFound { // if the voting power is the same no need to update any of the other indexes if oldValidator.Status == sdk.Bonded && - oldValidator.BondedShares.Equal(validator.BondedShares) { - return - } else if oldValidator.BondedShares.LT(validator.BondedShares) { + oldValidator.PShares.Equal(validator.PShares) { + return validator + } else if oldValidator.PShares.Bonded().LT(validator.PShares.Bonded()) { powerIncreasing = true } // delete the old record in the power ordered list @@ -111,7 +110,7 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { store.Set(GetValidatorsBondedByPowerKey(validator, pool), 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 { + if powerIncreasing && oldFound && oldValidator.Status == sdk.Bonded { // update the recent validator store store.Set(GetValidatorsBondedKey(validator.PubKey), bz) @@ -119,22 +118,20 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { // and the Tendermint updates bz := k.cdc.MustMarshalBinary(validator.abciValidator(k.cdc)) store.Set(GetTendermintUpdatesKey(address), bz) - return + return validator } // update the validator set for this validator valIsNowBonded := k.updateValidators(ctx, store, validator.Address) - fmt.Printf("debug valIsNowBonded: %v\n", valIsNowBonded) - fmt.Printf("debug validator0: %v\n", validator) - if oldValidator.Status != sdk.Bonded && valIsNowBonded { + if (!oldFound && valIsNowBonded) || + (oldFound && oldValidator.Status != sdk.Bonded && valIsNowBonded) { + validator.Status = sdk.Bonded validator, pool = validator.UpdateSharesLocation(pool) k.setPool(ctx, pool) } - fmt.Printf("debug validator1: %v\n", validator) - - return + return validator } func (k Keeper) removeValidator(ctx sdk.Context, address sdk.Address) { diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index ff6432448f..dc21abc7ff 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -23,6 +23,27 @@ var ( } ) +func TestSetValidator(t *testing.T) { + ctx, _, keeper := createTestInput(t, false, 0) + pool := keeper.GetPool(ctx) + + // test how the validator is set from a purely unbonbed pool + validator := NewValidator(addrVals[0], pks[0], Description{}) + validator, pool, _ = validator.addTokensFromDel(pool, 10) + require.Equal(t, sdk.Unbonded, validator.Status) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.UnbondedShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + keeper.setPool(ctx, pool) + keeper.setValidator(ctx, validator) + // after the save the validator should be bonded + validator, found := keeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, sdk.Bonded, validator.Status) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + +} + // This function tests setValidator, GetValidator, GetValidatorsBonded, removeValidator func TestValidatorBasics(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) diff --git a/x/stake/pool.go b/x/stake/pool.go index 4d4aca3964..c8c389c679 100644 --- a/x/stake/pool.go +++ b/x/stake/pool.go @@ -89,8 +89,8 @@ 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.BondedTokens += amount p.BondedShares = p.BondedShares.Add(issuedShares) + p.BondedTokens += amount return p, issuedShares } diff --git a/x/stake/shares.go b/x/stake/shares.go new file mode 100644 index 0000000000..ac3fda3f07 --- /dev/null +++ b/x/stake/shares.go @@ -0,0 +1,139 @@ +package stake + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// kind of shares +type PoolShareKind byte + +// nolint +const ( + ShareUnbonded PoolShareKind = 0x00 + ShareUnbonding PoolShareKind = 0x01 + ShareBonded PoolShareKind = 0x02 +) + +// pool shares held by a validator +type PoolShares struct { + Kind PoolShareKind `json:"kind"` + Amount sdk.Rat `json:"shares"` // total shares of type ShareKind +} + +// only the vitals - does not check bond height of IntraTxCounter +func (s PoolShares) Equal(s2 PoolShares) bool { + return s.Kind == s2.Kind && + s.Amount.Equal(s2.Amount) +} + +func NewUnbondedShares(amount sdk.Rat) PoolShares { + return PoolShares{ + Kind: ShareUnbonded, + Amount: amount, + } +} + +func NewUnbondingShares(amount sdk.Rat) PoolShares { + return PoolShares{ + Kind: ShareUnbonding, + Amount: amount, + } +} + +func NewBondedShares(amount sdk.Rat) PoolShares { + return PoolShares{ + Kind: ShareBonded, + Amount: amount, + } +} + +//_________________________________________________________________________________________________________ + +// amount of unbonded shares +func (s PoolShares) Unbonded() sdk.Rat { + if s.Kind == ShareUnbonded { + return s.Amount + } + return sdk.ZeroRat() +} + +// amount of unbonding shares +func (s PoolShares) Unbonding() sdk.Rat { + if s.Kind == ShareUnbonding { + return s.Amount + } + return sdk.ZeroRat() +} + +// amount of bonded shares +func (s PoolShares) Bonded() sdk.Rat { + if s.Kind == ShareBonded { + return s.Amount + } + return sdk.ZeroRat() +} + +//_________________________________________________________________________________________________________ + +// equivalent amount of shares if the shares were unbonded +func (s PoolShares) ToUnbonded(p Pool) PoolShares { + var amount sdk.Rat + switch s.Kind { + case ShareBonded: + exRate := p.bondedShareExRate().Quo(p.unbondedShareExRate()) // (tok/bondedshr)/(tok/unbondedshr) = unbondedshr/bondedshr + amount = s.Amount.Mul(exRate) // bondedshr*unbondedshr/bondedshr = unbondedshr + case ShareUnbonding: + exRate := p.unbondingShareExRate().Quo(p.unbondedShareExRate()) // (tok/unbondingshr)/(tok/unbondedshr) = unbondedshr/unbondingshr + amount = s.Amount.Mul(exRate) // unbondingshr*unbondedshr/unbondingshr = unbondedshr + case ShareUnbonded: + amount = s.Amount + } + return NewUnbondedShares(amount) +} + +// equivalent amount of shares if the shares were unbonding +func (s PoolShares) ToUnbonding(p Pool) PoolShares { + var amount sdk.Rat + switch s.Kind { + case ShareBonded: + exRate := p.bondedShareExRate().Quo(p.unbondingShareExRate()) // (tok/bondedshr)/(tok/unbondingshr) = unbondingshr/bondedshr + amount = s.Amount.Mul(exRate) // bondedshr*unbondingshr/bondedshr = unbondingshr + case ShareUnbonding: + amount = s.Amount + case ShareUnbonded: + exRate := p.unbondedShareExRate().Quo(p.unbondingShareExRate()) // (tok/unbondedshr)/(tok/unbondingshr) = unbondingshr/unbondedshr + amount = s.Amount.Mul(exRate) // unbondedshr*unbondingshr/unbondedshr = unbondingshr + } + return NewUnbondingShares(amount) +} + +// equivalent amount of shares if the shares were bonded +func (s PoolShares) ToBonded(p Pool) PoolShares { + var amount sdk.Rat + switch s.Kind { + case ShareBonded: + amount = s.Amount + case ShareUnbonding: + exRate := p.unbondingShareExRate().Quo(p.bondedShareExRate()) // (tok/ubshr)/(tok/bshr) = bshr/ubshr + amount = s.Amount.Mul(exRate) // ubshr*bshr/ubshr = bshr + case ShareUnbonded: + exRate := p.unbondedShareExRate().Quo(p.bondedShareExRate()) // (tok/ubshr)/(tok/bshr) = bshr/ubshr + amount = s.Amount.Mul(exRate) // ubshr*bshr/ubshr = bshr + } + return NewUnbondedShares(amount) +} + +//_________________________________________________________________________________________________________ + +// get the equivalent amount of tokens contained by the shares +func (s PoolShares) Tokens(p Pool) sdk.Rat { + switch s.Kind { + case ShareBonded: + return p.unbondedShareExRate().Mul(s.Amount) // (tokens/shares) * shares + case ShareUnbonding: + return p.unbondedShareExRate().Mul(s.Amount) + case ShareUnbonded: + return p.unbondedShareExRate().Mul(s.Amount) + } + return sdk.ZeroRat() +} diff --git a/x/stake/validator.go b/x/stake/validator.go index 93b0234e9c..d6473c64d5 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -22,13 +22,8 @@ type Validator struct { 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. - BondedShares sdk.Rat `json:"bonded_shares"` // total shares of bonded global hold pool - UnbondingShares sdk.Rat `json:"unbonding_shares"` // total shares of unbonding global hold pool - UnbondedShares sdk.Rat `json:"unbonded_shares"` // total shares of unbonded global hold pool - - DelegatorShares sdk.Rat `json:"liabilities"` // total shares issued to a validator's delegators + PShares PoolShares `json:"pool_shares"` // total shares for tokens held in the pool + DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator BondHeight int64 `json:"validator_bond_height"` // earliest height as a bonded validator @@ -53,9 +48,7 @@ func NewValidator(address sdk.Address, pubKey crypto.PubKey, description Descrip Status: sdk.Unbonded, Address: address, PubKey: pubKey, - BondedShares: sdk.ZeroRat(), - UnbondingShares: sdk.ZeroRat(), - UnbondedShares: sdk.ZeroRat(), + PShares: NewUnbondedShares(sdk.ZeroRat()), DelegatorShares: sdk.ZeroRat(), Description: description, BondHeight: int64(0), @@ -74,7 +67,7 @@ func (v Validator) equal(c2 Validator) bool { return v.Status == c2.Status && v.PubKey.Equals(c2.PubKey) && bytes.Equal(v.Address, c2.Address) && - v.BondedShares.Equal(c2.BondedShares) && + v.PShares.Equal(c2.PShares) && v.DelegatorShares.Equal(c2.DelegatorShares) && v.Description == c2.Description && //v.BondHeight == c2.BondHeight && @@ -118,15 +111,15 @@ func (v Validator) DelegatorShareExRate(p Pool) sdk.Rat { if v.DelegatorShares.IsZero() { return sdk.OneRat() } - tokens := v.EquivalentBondedShares(p) - return tokens.Quo(v.DelegatorShares) + 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{ PubKey: v.PubKey.Bytes(), - Power: v.BondedShares.Evaluate(), + Power: v.PShares.Bonded().Evaluate(), } } @@ -144,35 +137,36 @@ func (v Validator) UpdateSharesLocation(p Pool) (Validator, Pool) { var tokens int64 switch { - case !v.BondedShares.IsZero(): - if v.Status == sdk.Bonded { // return if nothing needs switching - return v, p - } - p, tokens = p.removeSharesBonded(v.BondedShares) - v.BondedShares = sdk.ZeroRat() - - case !v.UnbondingShares.IsZero(): - if v.Status == sdk.Unbonding { - return v, p - } - p, tokens = p.removeSharesUnbonding(v.UnbondingShares) - v.UnbondingShares = sdk.ZeroRat() - - case !v.UnbondedShares.IsZero(): + case v.PShares.Kind == ShareUnbonded: if v.Status == sdk.Unbonded { return v, p } - p, tokens = p.removeSharesUnbonded(v.UnbondedShares) - v.UnbondedShares = sdk.ZeroRat() + p, tokens = p.removeSharesUnbonded(v.PShares.Amount) + + case v.PShares.Kind == ShareUnbonding: + if v.Status == sdk.Unbonding { + return v, p + } + p, tokens = p.removeSharesUnbonding(v.PShares.Amount) + + case v.PShares.Kind == ShareBonded: + if v.Status == sdk.Bonded { // return if nothing needs switching + return v, p + } + p, tokens = p.removeSharesBonded(v.PShares.Amount) } + var shares sdk.Rat switch v.Status { - case sdk.Bonded: - p, v.BondedShares = p.addTokensBonded(tokens) - case sdk.Unbonding: - p, v.UnbondingShares = p.addTokensUnbonding(tokens) case sdk.Unbonded, sdk.Revoked: - p, v.UnbondedShares = p.addTokensUnbonded(tokens) + p, shares = p.addTokensUnbonded(tokens) + v.PShares = NewUnbondedShares(shares) + case sdk.Unbonding: + p, shares = p.addTokensUnbonding(tokens) + v.PShares = NewUnbondingShares(shares) + case sdk.Bonded: + p, shares = p.addTokensBonded(tokens) + v.PShares = NewBondedShares(shares) } return v, p } @@ -183,92 +177,56 @@ func (v Validator) UpdateSharesLocation(p Pool) (Validator, Pool) { // if not bonded, the power is the amount of bonded shares which the // the validator would have it was bonded func (v Validator) EquivalentBondedShares(p Pool) (eqBondedShares sdk.Rat) { - switch v.Status { - case sdk.Bonded: - eqBondedShares = v.BondedShares - case sdk.Unbonding: - shares := v.UnbondingShares // ubShr - exRate := p.unbondingShareExRate().Quo(p.bondedShareExRate()) // (tok/ubshr)/(tok/bshr) = bshr/ubshr - eqBondedShares = shares.Mul(exRate) // ubshr*bshr/ubshr = bshr - case sdk.Unbonded, sdk.Revoked: - shares := v.UnbondedShares // ubShr - exRate := p.unbondedShareExRate().Quo(p.bondedShareExRate()) // (tok/ubshr)/(tok/bshr) = bshr/ubshr - eqBondedShares = shares.Mul(exRate) // ubshr*bshr/ubshr = bshr - } - return + return v.PShares.ToBonded(p).Amount } -// convert the equivalent bonded shares to a worth in unbonding shares -func EquivalentBondedSharesToUnbonding(p Pool, eqBondedShares sdk.Rat) (unbondingShares sdk.Rat) { - exRate := p.bondedShareExRate().Quo(p.unbondingShareExRate()) // (tok/bshr)/(tok/ubshr) = ubshr/bshr - return eqBondedShares.Mul(exRate) // bshr*ubshr/bshr = ubshr -} - -// convert the equivalent bonded shares to a worth in unbonded shares -func EquivalentBondedSharesToUnbonded(p Pool, eqBondedShares sdk.Rat) (unbondedShares sdk.Rat) { - exRate := p.bondedShareExRate().Quo(p.unbondedShareExRate()) // (tok/bshr)/(tok/ubshr) = ubshr/bshr - return eqBondedShares.Mul(exRate) // bshr*ubshr/bshr = ubshr -} - -// TODO Implement Use in query functionality -// get the equivalent amount of tokens contained by a validator -func (v Validator) Tokens(p Pool) sdk.Rat { - switch v.Status { - case sdk.Bonded: - return p.unbondedShareExRate().Mul(v.BondedShares) // (tokens/shares) * shares - case sdk.Unbonding: - return p.unbondedShareExRate().Mul(v.UnbondingShares) - case sdk.Unbonded, sdk.Revoked: - return p.unbondedShareExRate().Mul(v.UnbondedShares) - } - return sdk.ZeroRat() -} +//_________________________________________________________________________________________________________ // XXX Audit this function further to make sure it's correct // add tokens to a validator func (v Validator) addTokensFromDel(p Pool, amount int64) (validator2 Validator, p2 Pool, issuedDelegatorShares sdk.Rat) { - var poolShares sdk.Rat + var equivalentBondedShares, poolShares sdk.Rat switch v.Status { - case sdk.Bonded: - p, poolShares = p.addTokensBonded(amount) - v.BondedShares = v.BondedShares.Add(poolShares) - case sdk.Unbonding: - p, poolShares = p.addTokensUnbonding(amount) - v.UnbondingShares = v.UnbondingShares.Add(poolShares) case sdk.Unbonded, sdk.Revoked: p, poolShares = p.addTokensUnbonded(amount) - v.UnbondedShares = v.UnbondedShares.Add(poolShares) + case sdk.Unbonding: + p, poolShares = p.addTokensUnbonding(amount) + case sdk.Bonded: + p, poolShares = p.addTokensBonded(amount) } + v.PShares.Amount = v.PShares.Amount.Add(poolShares) + equivalentBondedShares = v.PShares.ToBonded(p).Amount - equivalentBondedShares := v.EquivalentBondedShares(p) - exRate := v.DelegatorShareExRate(p) // eq-val-bonded-shares/delegator-shares - issuedDelegatorShares = equivalentBondedShares.Quo(exRate) + exRate := v.DelegatorShareExRate(p) // bshr/delshr + issuedDelegatorShares = equivalentBondedShares.Quo(exRate) // bshr/(bshr/delshr) = delshr v.DelegatorShares = v.DelegatorShares.Add(issuedDelegatorShares) return v, p, issuedDelegatorShares } // remove delegator shares from a validator +// NOTE this function assumes the shares have already been updated for the validator status func (v Validator) removeDelShares(p Pool, delShares sdk.Rat) (validator2 Validator, p2 Pool, createdCoins int64) { - eqBondedSharesToRemove := v.DelegatorShareExRate(p).Mul(delShares) + amount := v.DelegatorShareExRate(p).Mul(delShares) + eqBondedSharesToRemove := NewBondedShares(amount) v.DelegatorShares = v.DelegatorShares.Sub(delShares) switch v.Status { - case sdk.Bonded: - p, createdCoins = p.removeSharesBonded(eqBondedSharesToRemove) - v.BondedShares = v.BondedShares.Sub(eqBondedSharesToRemove) - case sdk.Unbonding: - unbondingShares := EquivalentBondedSharesToUnbonding(p, eqBondedSharesToRemove) - p, createdCoins = p.removeSharesUnbonding(unbondingShares) - v.UnbondingShares = v.UnbondingShares.Sub(unbondingShares) case sdk.Unbonded, sdk.Revoked: - unbondedShares := EquivalentBondedSharesToUnbonded(p, eqBondedSharesToRemove) + unbondedShares := eqBondedSharesToRemove.ToUnbonded(p).Amount p, createdCoins = p.removeSharesUnbonded(unbondedShares) - v.UnbondedShares = v.UnbondedShares.Sub(unbondedShares) + v.PShares.Amount = v.PShares.Amount.Sub(unbondedShares) + case sdk.Unbonding: + unbondingShares := eqBondedSharesToRemove.ToUnbonding(p).Amount + p, createdCoins = p.removeSharesUnbonding(unbondingShares) + v.PShares.Amount = v.PShares.Amount.Sub(unbondingShares) + case sdk.Bonded: + p, createdCoins = p.removeSharesBonded(eqBondedSharesToRemove.Amount) + v.PShares.Amount = v.PShares.Amount.Sub(eqBondedSharesToRemove.Amount) } return v, p, createdCoins } @@ -282,5 +240,5 @@ var _ sdk.Validator = 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) GetPower() sdk.Rat { return v.PShares.Bonded() } func (v Validator) GetBondHeight() int64 { return v.BondHeight }