From 2bf78d92c784d67afc7c409ffd6243451efa066c Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 11 Jul 2018 14:46:54 -0400 Subject: [PATCH 01/25] wip removing pool shares --- x/stake/types/pool.go | 108 +++---------------------- x/stake/types/pool_test.go | 120 +++------------------------- x/stake/types/shares.go | 149 ----------------------------------- x/stake/types/shares_test.go | 35 -------- x/stake/types/tokens.go | 66 ++++++++++++++++ x/stake/types/tokens_test.go | 19 +++++ x/stake/types/validator.go | 71 ++++++----------- 7 files changed, 135 insertions(+), 433 deletions(-) delete mode 100644 x/stake/types/shares.go delete mode 100644 x/stake/types/shares_test.go create mode 100644 x/stake/types/tokens.go create mode 100644 x/stake/types/tokens_test.go diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 8ef187f0784b..6dbc036aa4cb 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -9,13 +9,8 @@ import ( // Pool - dynamic parameters of the current state type Pool struct { - LooseTokens int64 `json:"loose_tokens"` // tokens not associated with any validator - UnbondedTokens int64 `json:"unbonded_tokens"` // reserve of unbonded tokens held with validators - UnbondingTokens int64 `json:"unbonding_tokens"` // tokens moving from bonded to unbonded pool - BondedTokens int64 `json:"bonded_tokens"` // reserve of bonded tokens - UnbondedShares sdk.Rat `json:"unbonded_shares"` // sum of all shares distributed for the Unbonded Pool - UnbondingShares sdk.Rat `json:"unbonding_shares"` // shares moving from Bonded to Unbonded Pool - BondedShares sdk.Rat `json:"bonded_shares"` // sum of all shares distributed for the Bonded Pool + LooseTokens sdk.Rat `json:"loose_tokens"` // tokens which are not bonded in a validator + BondedTokens sdk.Rat `json:"bonded_tokens"` // reserve of bonded tokens InflationLastTime int64 `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time Inflation sdk.Rat `json:"inflation"` // current annual inflation rate @@ -35,13 +30,8 @@ func (p Pool) Equal(p2 Pool) bool { // initial pool for testing func InitialPool() Pool { return Pool{ - LooseTokens: 0, - BondedTokens: 0, - UnbondingTokens: 0, - UnbondedTokens: 0, - BondedShares: sdk.ZeroRat(), - UnbondingShares: sdk.ZeroRat(), - UnbondedShares: sdk.ZeroRat(), + LooseTokens: sdk.ZeroRat(), + BondedTokens: sdk.ZeroRat(), InflationLastTime: 0, Inflation: sdk.NewRat(7, 100), DateLastCommissionReset: 0, @@ -53,7 +43,7 @@ func InitialPool() Pool { // Sum total of all staking tokens in the pool func (p Pool) TokenSupply() int64 { - return p.LooseTokens + p.UnbondedTokens + p.UnbondingTokens + p.BondedTokens + return p.LooseTokens.Add(p.BondedTokens) } //____________________________________________________________________ @@ -66,94 +56,22 @@ func (p Pool) BondedRatio() sdk.Rat { return sdk.ZeroRat() } -// get the exchange rate of bonded token per issued share -func (p Pool) BondedShareExRate() sdk.Rat { - if p.BondedShares.IsZero() { - return sdk.OneRat() - } - return sdk.NewRat(p.BondedTokens).Quo(p.BondedShares) -} - -// get the exchange rate of unbonding tokens held in validators per issued share -func (p Pool) UnbondingShareExRate() sdk.Rat { - if p.UnbondingShares.IsZero() { - return sdk.OneRat() - } - return sdk.NewRat(p.UnbondingTokens).Quo(p.UnbondingShares) -} - -// get the exchange rate of unbonded tokens held in validators per issued share -func (p Pool) UnbondedShareExRate() sdk.Rat { - if p.UnbondedShares.IsZero() { - return sdk.OneRat() - } - return sdk.NewRat(p.UnbondedTokens).Quo(p.UnbondedShares) -} - //_______________________________________________________________________ -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 - p.LooseTokens -= amount - if p.LooseTokens < 0 { - panic(fmt.Sprintf("sanity check: loose tokens negative, pool: %v", p)) - } - return p, NewUnbondedShares(issuedSharesAmount) -} - -func (p Pool) removeSharesUnbonded(shares sdk.Rat) (p2 Pool, removedTokens int64) { - removedTokens = p.UnbondedShareExRate().Mul(shares).RoundInt64() // (tokens/shares) * shares - p.UnbondedShares = p.UnbondedShares.Sub(shares) - p.UnbondedTokens -= removedTokens - p.LooseTokens += removedTokens - if p.UnbondedTokens < 0 { - panic(fmt.Sprintf("sanity check: unbonded tokens negative, pool: %v", p)) - } - return p, removedTokens -} - -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 - p.LooseTokens -= amount - if p.LooseTokens < 0 { - panic(fmt.Sprintf("sanity check: loose tokens negative, pool: %v", p)) - } - return p, NewUnbondingShares(issuedSharesAmount) -} - -func (p Pool) removeSharesUnbonding(shares sdk.Rat) (p2 Pool, removedTokens int64) { - removedTokens = p.UnbondingShareExRate().Mul(shares).RoundInt64() // (tokens/shares) * shares - p.UnbondingShares = p.UnbondingShares.Sub(shares) - p.UnbondingTokens -= removedTokens - p.LooseTokens += removedTokens - if p.UnbondedTokens < 0 { - panic(fmt.Sprintf("sanity check: unbonding tokens negative, pool: %v", p)) - } - return p, removedTokens -} - -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 - p.LooseTokens -= amount +func (p Pool) addBondedTokens(bondedTokens sdk.Rat) Pool { + p.BondedTokens = p.BondedTokens.Add(bondedTokens) + p.LooseTokens = p.LooseTokens.Sub(bondedTokens) if p.LooseTokens < 0 { panic(fmt.Sprintf("sanity check: loose tokens negative, pool: %v", p)) } - return p, NewBondedShares(issuedSharesAmount) + return p } -func (p Pool) removeSharesBonded(shares sdk.Rat) (p2 Pool, removedTokens int64) { - removedTokens = p.BondedShareExRate().Mul(shares).RoundInt64() // (tokens/shares) * shares - p.BondedShares = p.BondedShares.Sub(shares) - p.BondedTokens -= removedTokens - p.LooseTokens += removedTokens +func (p Pool) removeBondedTokens(bondedTokens sdk.Rat) Pool { + p.BondedTokens = p.BondedTokens.Sub(bondedTokens) + p.LooseTokens = p.LooseTokens.Add(bondedTokens) if p.UnbondedTokens < 0 { panic(fmt.Sprintf("sanity check: bonded tokens negative, pool: %v", p)) } - return p, removedTokens + return p } diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 3a52646f6703..2e1fc1a17aa5 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -21,120 +21,24 @@ func TestPoolEqual(t *testing.T) { require.False(t, ok) } -func TestBondedRatio(t *testing.T) { +func TestAddBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = 1 - pool.BondedTokens = 2 + pool.LooseTokens = sdk.NewRat(10) + pool.BondedTokens = sdk.NewRat(10) - // bonded pool / total supply - require.Equal(t, pool.BondedRatio(), sdk.NewRat(2).Quo(sdk.NewRat(3))) + pool = pool.addTokensBonded(sdk.NewRat(10)) - // avoids divide-by-zero - pool.LooseTokens = 0 - pool.BondedTokens = 0 - require.Equal(t, pool.BondedRatio(), sdk.ZeroRat()) + require.Equal(t, sdk.NewRat(20), pool.BondedTokens) + require.Equal(t, sdk.NewRat(0), pool.LooseTokens) } -func TestBondedShareExRate(t *testing.T) { +func TestRemoveBondedTokens(t *testing.T) { pool := InitialPool() - pool.BondedTokens = 3 - pool.BondedShares = sdk.NewRat(10) + pool.LooseTokens = sdk.NewRat(10) + pool.BondedTokens = sdk.NewRat(10) - // bonded pool / bonded shares - require.Equal(t, pool.BondedShareExRate(), sdk.NewRat(3).Quo(sdk.NewRat(10))) - pool.BondedShares = sdk.ZeroRat() + pool = pool.removeTokensBonded(sdk.NewRat(5)) - // avoids divide-by-zero - require.Equal(t, pool.BondedShareExRate(), sdk.OneRat()) -} - -func TestUnbondingShareExRate(t *testing.T) { - pool := InitialPool() - pool.UnbondingTokens = 3 - pool.UnbondingShares = sdk.NewRat(10) - - // unbonding pool / unbonding shares - require.Equal(t, pool.UnbondingShareExRate(), sdk.NewRat(3).Quo(sdk.NewRat(10))) - pool.UnbondingShares = sdk.ZeroRat() - - // avoids divide-by-zero - require.Equal(t, pool.UnbondingShareExRate(), sdk.OneRat()) -} - -func TestUnbondedShareExRate(t *testing.T) { - pool := InitialPool() - pool.UnbondedTokens = 3 - pool.UnbondedShares = sdk.NewRat(10) - - // unbonded pool / unbonded shares - require.Equal(t, pool.UnbondedShareExRate(), sdk.NewRat(3).Quo(sdk.NewRat(10))) - pool.UnbondedShares = sdk.ZeroRat() - - // avoids divide-by-zero - require.Equal(t, pool.UnbondedShareExRate(), sdk.OneRat()) -} - -func TestAddTokensBonded(t *testing.T) { - poolA := InitialPool() - poolA.LooseTokens = 10 - require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) - - poolB, sharesB := poolA.addTokensBonded(10) - require.Equal(t, poolB.BondedShareExRate(), sdk.OneRat()) - - // correct changes to bonded shares and bonded pool - require.Equal(t, poolB.BondedShares, poolA.BondedShares.Add(sharesB.Amount)) - require.Equal(t, poolB.BondedTokens, poolA.BondedTokens+10) - - // same number of bonded shares / tokens when exchange rate is one - require.True(t, poolB.BondedShares.Equal(sdk.NewRat(poolB.BondedTokens))) -} - -func TestRemoveSharesBonded(t *testing.T) { - poolA := InitialPool() - poolA.LooseTokens = 10 - require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) - - poolB, tokensB := poolA.removeSharesBonded(sdk.NewRat(10)) - require.Equal(t, poolB.BondedShareExRate(), sdk.OneRat()) - - // correct changes to bonded shares and bonded pool - require.Equal(t, poolB.BondedShares, poolA.BondedShares.Sub(sdk.NewRat(10))) - require.Equal(t, poolB.BondedTokens, poolA.BondedTokens-tokensB) - - // same number of bonded shares / tokens when exchange rate is one - require.True(t, poolB.BondedShares.Equal(sdk.NewRat(poolB.BondedTokens))) -} - -func TestAddTokensUnbonded(t *testing.T) { - poolA := InitialPool() - poolA.LooseTokens = 10 - require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) - - poolB, sharesB := poolA.addTokensUnbonded(10) - require.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat()) - - // correct changes to unbonded shares and unbonded pool - require.Equal(t, poolB.UnbondedShares, poolA.UnbondedShares.Add(sharesB.Amount)) - require.Equal(t, poolB.UnbondedTokens, poolA.UnbondedTokens+10) - - // same number of unbonded shares / tokens when exchange rate is one - require.True(t, poolB.UnbondedShares.Equal(sdk.NewRat(poolB.UnbondedTokens))) -} - -func TestRemoveSharesUnbonded(t *testing.T) { - poolA := InitialPool() - poolA.UnbondedTokens = 10 - poolA.UnbondedShares = sdk.NewRat(10) - require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) - - poolB, tokensB := poolA.removeSharesUnbonded(sdk.NewRat(10)) - require.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat()) - - // correct changes to unbonded shares and bonded pool - require.Equal(t, poolB.UnbondedShares, poolA.UnbondedShares.Sub(sdk.NewRat(10))) - require.Equal(t, poolB.UnbondedTokens, poolA.UnbondedTokens-tokensB) - - // same number of unbonded shares / tokens when exchange rate is one - require.True(t, poolB.UnbondedShares.Equal(sdk.NewRat(poolB.UnbondedTokens))) + require.Equal(t, sdk.NewRat(5), pool.BondedTokens) + require.Equal(t, sdk.NewRat(15), pool.LooseTokens) } diff --git a/x/stake/types/shares.go b/x/stake/types/shares.go deleted file mode 100644 index 5a2cb2be6c52..000000000000 --- a/x/stake/types/shares.go +++ /dev/null @@ -1,149 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// PoolShares reflects the shares of a validator in a pool. -type PoolShares struct { - Status sdk.BondStatus `json:"status"` - Amount sdk.Rat `json:"amount"` -} - -// Equal returns a boolean determining of two PoolShares are identical. -func (s PoolShares) Equal(s2 PoolShares) bool { - return s.Status == s2.Status && - s.Amount.Equal(s2.Amount) -} - -// NewUnbondedShares returns a new PoolShares with a specified unbonded amount. -func NewUnbondedShares(amount sdk.Rat) PoolShares { - return PoolShares{ - Status: sdk.Unbonded, - Amount: amount, - } -} - -// NewUnbondingShares returns a new PoolShares with a specified unbonding -// amount. -func NewUnbondingShares(amount sdk.Rat) PoolShares { - return PoolShares{ - Status: sdk.Unbonding, - Amount: amount, - } -} - -// NewBondedShares returns a new PoolSahres with a specified bonding amount. -func NewBondedShares(amount sdk.Rat) PoolShares { - return PoolShares{ - Status: sdk.Bonded, - Amount: amount, - } -} - -// Unbonded returns the amount of unbonded shares. -func (s PoolShares) Unbonded() sdk.Rat { - if s.Status == sdk.Unbonded { - return s.Amount - } - return sdk.ZeroRat() -} - -// Unbonding returns the amount of unbonding shares. -func (s PoolShares) Unbonding() sdk.Rat { - if s.Status == sdk.Unbonding { - return s.Amount - } - return sdk.ZeroRat() -} - -// Bonded returns amount of bonded shares. -func (s PoolShares) Bonded() sdk.Rat { - if s.Status == sdk.Bonded { - return s.Amount - } - return sdk.ZeroRat() -} - -// ToUnbonded returns the equivalent amount of pool shares if the shares were -// unbonded. -func (s PoolShares) ToUnbonded(p Pool) PoolShares { - var amount sdk.Rat - - switch s.Status { - case sdk.Bonded: - // (tok/bondedshr)/(tok/unbondedshr) = unbondedshr/bondedshr - exRate := p.BondedShareExRate().Quo(p.UnbondedShareExRate()) - // bondedshr*unbondedshr/bondedshr = unbondedshr - amount = s.Amount.Mul(exRate) - case sdk.Unbonding: - // (tok/unbondingshr)/(tok/unbondedshr) = unbondedshr/unbondingshr - exRate := p.UnbondingShareExRate().Quo(p.UnbondedShareExRate()) - // unbondingshr*unbondedshr/unbondingshr = unbondedshr - amount = s.Amount.Mul(exRate) - case sdk.Unbonded: - amount = s.Amount - } - - return NewUnbondedShares(amount) -} - -// ToUnbonding returns the equivalent amount of pool shares if the shares were -// unbonding. -func (s PoolShares) ToUnbonding(p Pool) PoolShares { - var amount sdk.Rat - - switch s.Status { - case sdk.Bonded: - // (tok/bondedshr)/(tok/unbondingshr) = unbondingshr/bondedshr - exRate := p.BondedShareExRate().Quo(p.UnbondingShareExRate()) - // bondedshr*unbondingshr/bondedshr = unbondingshr - amount = s.Amount.Mul(exRate) - case sdk.Unbonding: - amount = s.Amount - case sdk.Unbonded: - // (tok/unbondedshr)/(tok/unbondingshr) = unbondingshr/unbondedshr - exRate := p.UnbondedShareExRate().Quo(p.UnbondingShareExRate()) - // unbondedshr*unbondingshr/unbondedshr = unbondingshr - amount = s.Amount.Mul(exRate) - } - - return NewUnbondingShares(amount) -} - -// ToBonded the equivalent amount of pool shares if the shares were bonded. -func (s PoolShares) ToBonded(p Pool) PoolShares { - var amount sdk.Rat - - switch s.Status { - case sdk.Bonded: - amount = s.Amount - case sdk.Unbonding: - // (tok/ubshr)/(tok/bshr) = bshr/ubshr - exRate := p.UnbondingShareExRate().Quo(p.BondedShareExRate()) - // ubshr*bshr/ubshr = bshr - amount = s.Amount.Mul(exRate) - case sdk.Unbonded: - // (tok/ubshr)/(tok/bshr) = bshr/ubshr - exRate := p.UnbondedShareExRate().Quo(p.BondedShareExRate()) - // ubshr*bshr/ubshr = bshr - amount = s.Amount.Mul(exRate) - } - - return NewUnbondedShares(amount) -} - -// Tokens returns the equivalent amount of tokens contained by the pool shares -// for a given pool. -func (s PoolShares) Tokens(p Pool) sdk.Rat { - switch s.Status { - case sdk.Bonded: - return p.BondedShareExRate().Mul(s.Amount) - case sdk.Unbonding: - return p.UnbondingShareExRate().Mul(s.Amount) - case sdk.Unbonded: - return p.UnbondedShareExRate().Mul(s.Amount) - default: - panic("unknown share kind") - } -} diff --git a/x/stake/types/shares_test.go b/x/stake/types/shares_test.go deleted file mode 100644 index 8a374606c516..000000000000 --- a/x/stake/types/shares_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package types - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" -) - -func TestPoolSharesTokens(t *testing.T) { - pool := InitialPool() - pool.LooseTokens = 10 - - val := Validator{ - Owner: addr1, - PubKey: pk1, - PoolShares: NewBondedShares(sdk.NewRat(100)), - DelegatorShares: sdk.NewRat(100), - } - - pool.BondedTokens = val.PoolShares.Bonded().RoundInt64() - pool.BondedShares = val.PoolShares.Bonded() - - poolShares := NewBondedShares(sdk.NewRat(50)) - tokens := poolShares.Tokens(pool) - require.Equal(t, int64(50), tokens.RoundInt64()) - - poolShares = NewUnbondingShares(sdk.NewRat(50)) - tokens = poolShares.Tokens(pool) - require.Equal(t, int64(50), tokens.RoundInt64()) - - poolShares = NewUnbondedShares(sdk.NewRat(50)) - tokens = poolShares.Tokens(pool) - require.Equal(t, int64(50), tokens.RoundInt64()) -} diff --git a/x/stake/types/tokens.go b/x/stake/types/tokens.go new file mode 100644 index 000000000000..faacaf8d9489 --- /dev/null +++ b/x/stake/types/tokens.go @@ -0,0 +1,66 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Tokens of a validator +type Tokens struct { + Status sdk.BondStatus `json:"status"` + Amount sdk.Rat `json:"amount"` +} + +// Equal returns a boolean determining of two Tokens are identical. +func (s Tokens) Equal(s2 Tokens) bool { + return s.Status == s2.Status && + s.Amount.Equal(s2.Amount) +} + +// NewUnbondedTokens returns a new Tokens with a specified unbonded amount. +func NewUnbondedTokens(amount sdk.Rat) Tokens { + return Tokens{ + Status: sdk.Unbonded, + Amount: amount, + } +} + +// NewUnbondingTokens returns a new Tokens with a specified unbonding +// amount. +func NewUnbondingTokens(amount sdk.Rat) Tokens { + return Tokens{ + Status: sdk.Unbonding, + Amount: amount, + } +} + +// NewBondedTokens returns a new PoolSahres with a specified bonding amount. +func NewBondedTokens(amount sdk.Rat) Tokens { + return Tokens{ + Status: sdk.Bonded, + Amount: amount, + } +} + +// Unbonded returns the amount of unbonded shares. +func (s Tokens) Unbonded() sdk.Rat { + if s.Status == sdk.Unbonded { + return s.Amount + } + return sdk.ZeroRat() +} + +// Unbonding returns the amount of unbonding shares. +func (s Tokens) Unbonding() sdk.Rat { + if s.Status == sdk.Unbonding { + return s.Amount + } + return sdk.ZeroRat() +} + +// Bonded returns amount of bonded shares. +func (s Tokens) Bonded() sdk.Rat { + if s.Status == sdk.Bonded { + return s.Amount + } + return sdk.ZeroRat() +} diff --git a/x/stake/types/tokens_test.go b/x/stake/types/tokens_test.go new file mode 100644 index 000000000000..481abfc82997 --- /dev/null +++ b/x/stake/types/tokens_test.go @@ -0,0 +1,19 @@ +package types + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestTokens(t *testing.T) { + tokens := NewBondedTokens(sdk.NewRat(50)) + require.Equal(t, int64(50), tokens.Bonded().RoundInt64()) + + tokens = NewUnbondingTokens(sdk.NewRat(50)) + require.Equal(t, int64(50), tokens.Unbonding().RoundInt64()) + + tokens = NewUnbondedTokens(sdk.NewRat(50)) + require.Equal(t, int64(50), tokens.Unbonded().RoundInt64()) +} diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 7b143364add5..947a9ba3a551 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -239,73 +239,54 @@ func (v Validator) Status() sdk.BondStatus { return v.PoolShares.Status } -// UpdateStatus updates the location of the shares within a validator if it's -// bond status has changed. +// UpdateStatus updates the location of the shares within a validator +// to reflect the new status func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, Pool) { var tokens int64 switch v.Status() { case sdk.Unbonded: - if NewStatus == sdk.Unbonded { + + switch NewStatus { + case sdk.Unbonded: return v, pool + case sdk.Bonded: + pool = pool.AddTokensBonded(v.PoolShares.Amount) } - pool, tokens = pool.removeSharesUnbonded(v.PoolShares.Amount) - case sdk.Unbonding: - if NewStatus == sdk.Unbonding { + + switch NewStatus { + case sdk.Unbonding: return v, pool + case sdk.Bonded: + pool = pool.AddTokensBonded(v.PoolShares.Amount) } - pool, tokens = pool.removeSharesUnbonding(v.PoolShares.Amount) - case sdk.Bonded: - if NewStatus == sdk.Bonded { - // Return if nothing needs switching + + switch NewStatus { + case sdk.Bonded: return v, pool + default: + pool = pool.RemoveTokensBonded(v.PoolShares.Amount) } - pool, tokens = pool.removeSharesBonded(v.PoolShares.Amount) - } - - switch NewStatus { - case sdk.Unbonded: - pool, v.PoolShares = pool.addTokensUnbonded(tokens) - case sdk.Unbonding: - pool, v.PoolShares = pool.addTokensUnbonding(tokens) - case sdk.Bonded: - pool, v.PoolShares = pool.addTokensBonded(tokens) } + v.Tokens.Status = NewStatus return v, pool } -// RemovePoolShares removes pool shares from a validator. It returns -// corresponding tokens, which could be burned (e.g. when slashing a validator) -// or redistributed elsewhere. -func (v Validator) RemovePoolShares(pool Pool, poolShares sdk.Rat) (Validator, Pool, int64) { +// removes tokens from a validator +func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { var tokens int64 - switch v.Status() { - case sdk.Unbonded: - pool, tokens = pool.removeSharesUnbonded(poolShares) - case sdk.Unbonding: - pool, tokens = pool.removeSharesUnbonding(poolShares) - case sdk.Bonded: - pool, tokens = pool.removeSharesBonded(poolShares) + if v.Status() == sdk.Bonded { + pool = pool.removeBondedTokens(tokens) } v.PoolShares.Amount = v.PoolShares.Amount.Sub(poolShares) return v, pool, tokens } -// EquivalentBondedShares ... -// -// TODO: Remove should only be tokens get the power or potential power for a -// validator if bonded, the power is the BondedShares if not bonded, the power -// is the amount of bonded shares which the the validator would have it was -// bonded. -func (v Validator) EquivalentBondedShares(pool Pool) (eqBondedShares sdk.Rat) { - return v.PoolShares.ToBonded(pool).Amount -} - //_________________________________________________________________________________________________________ // AddTokensFromDel adds tokens to a validator @@ -365,14 +346,12 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Poo } // DelegatorShareExRate gets the exchange rate of tokens over delegator shares. -// UNITS: eq-val-bonded-shares/delegator-shares +// UNITS: tokens/delegator-shares func (v Validator) DelegatorShareExRate(pool Pool) sdk.Rat { if v.DelegatorShares.IsZero() { return sdk.OneRat() } - - eqBondedShares := v.PoolShares.ToBonded(pool).Amount - return eqBondedShares.Quo(v.DelegatorShares) + return v.Tokens.Amount.Quo(v.DelegatorShares) } //______________________________________________________________________ @@ -402,7 +381,7 @@ func (v Validator) HumanReadableString() (string, error) { resp := "Validator \n" resp += fmt.Sprintf("Owner: %s\n", v.Owner) resp += fmt.Sprintf("Validator: %s\n", bechVal) - resp += fmt.Sprintf("Shares: Status %s, Amount: %s\n", sdk.BondStatusToString(v.PoolShares.Status), v.PoolShares.Amount.FloatString()) + resp += fmt.Sprintf("Tokens: Status %s, Amount: %s\n", sdk.BondStatusToString(v.Tokens.Status), v.Tokens.Amount.FloatString()) resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.FloatString()) resp += fmt.Sprintf("Description: %s\n", v.Description) resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight) From 53afa925330183a9aa4516279102a49deee84d3d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 11 Jul 2018 18:16:06 -0400 Subject: [PATCH 02/25] remove PoolShares/Tokens entirely --- x/stake/types/tokens.go | 66 ------------------------------------ x/stake/types/tokens_test.go | 19 ----------- x/stake/types/validator.go | 65 +++++++++++------------------------ 3 files changed, 20 insertions(+), 130 deletions(-) delete mode 100644 x/stake/types/tokens.go delete mode 100644 x/stake/types/tokens_test.go diff --git a/x/stake/types/tokens.go b/x/stake/types/tokens.go deleted file mode 100644 index faacaf8d9489..000000000000 --- a/x/stake/types/tokens.go +++ /dev/null @@ -1,66 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Tokens of a validator -type Tokens struct { - Status sdk.BondStatus `json:"status"` - Amount sdk.Rat `json:"amount"` -} - -// Equal returns a boolean determining of two Tokens are identical. -func (s Tokens) Equal(s2 Tokens) bool { - return s.Status == s2.Status && - s.Amount.Equal(s2.Amount) -} - -// NewUnbondedTokens returns a new Tokens with a specified unbonded amount. -func NewUnbondedTokens(amount sdk.Rat) Tokens { - return Tokens{ - Status: sdk.Unbonded, - Amount: amount, - } -} - -// NewUnbondingTokens returns a new Tokens with a specified unbonding -// amount. -func NewUnbondingTokens(amount sdk.Rat) Tokens { - return Tokens{ - Status: sdk.Unbonding, - Amount: amount, - } -} - -// NewBondedTokens returns a new PoolSahres with a specified bonding amount. -func NewBondedTokens(amount sdk.Rat) Tokens { - return Tokens{ - Status: sdk.Bonded, - Amount: amount, - } -} - -// Unbonded returns the amount of unbonded shares. -func (s Tokens) Unbonded() sdk.Rat { - if s.Status == sdk.Unbonded { - return s.Amount - } - return sdk.ZeroRat() -} - -// Unbonding returns the amount of unbonding shares. -func (s Tokens) Unbonding() sdk.Rat { - if s.Status == sdk.Unbonding { - return s.Amount - } - return sdk.ZeroRat() -} - -// Bonded returns amount of bonded shares. -func (s Tokens) Bonded() sdk.Rat { - if s.Status == sdk.Bonded { - return s.Amount - } - return sdk.ZeroRat() -} diff --git a/x/stake/types/tokens_test.go b/x/stake/types/tokens_test.go deleted file mode 100644 index 481abfc82997..000000000000 --- a/x/stake/types/tokens_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package types - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" -) - -func TestTokens(t *testing.T) { - tokens := NewBondedTokens(sdk.NewRat(50)) - require.Equal(t, int64(50), tokens.Bonded().RoundInt64()) - - tokens = NewUnbondingTokens(sdk.NewRat(50)) - require.Equal(t, int64(50), tokens.Unbonding().RoundInt64()) - - tokens = NewUnbondedTokens(sdk.NewRat(50)) - require.Equal(t, int64(50), tokens.Unbonded().RoundInt64()) -} diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 947a9ba3a551..2ef3f81e6f7c 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -27,8 +27,9 @@ type Validator struct { PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? - PoolShares 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 + Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) + Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) + 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:"bond_height"` // earliest height as a bonded validator @@ -234,17 +235,12 @@ func (v Validator) ABCIValidatorZero() abci.Validator { } } -// Status returns the validator's bond status inferred from the pool shares. -func (v Validator) Status() sdk.BondStatus { - return v.PoolShares.Status -} - // UpdateStatus updates the location of the shares within a validator // to reflect the new status func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, Pool) { var tokens int64 - switch v.Status() { + switch v.Status { case sdk.Unbonded: switch NewStatus { @@ -279,7 +275,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { var tokens int64 - if v.Status() == sdk.Bonded { + if v.Status == sdk.Bonded { pool = pool.removeBondedTokens(tokens) } @@ -290,29 +286,20 @@ func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { //_________________________________________________________________________________________________________ // AddTokensFromDel adds tokens to a validator -func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Rat) { - var ( - poolShares PoolShares - equivalentBondedShares sdk.Rat - ) +func (v Validator) AddTokensFromDel(pool Pool, amount int64) (validator Validator, pool Pool, issuedShares sdk.Rat) { + var poolShares PoolShares + var equivalentBondedShares sdk.Rat // bondedShare/delegatedShare exRate := v.DelegatorShareExRate(pool) - switch v.Status() { - case sdk.Unbonded: - pool, poolShares = pool.addTokensUnbonded(amount) - case sdk.Unbonding: - pool, poolShares = pool.addTokensUnbonding(amount) - case sdk.Bonded: - pool, poolShares = pool.addTokensBonded(amount) + if v.Status == sdk.Bonded { + pool = pool.AddBondedTokens(sdk.NewRat(amount)) } - v.PoolShares.Amount = v.PoolShares.Amount.Add(poolShares.Amount) - equivalentBondedShares = poolShares.ToBonded(pool).Amount - // bondedShare/(bondedShare/delegatedShare) = delegatedShare - issuedDelegatorShares := equivalentBondedShares.Quo(exRate) - v.DelegatorShares = v.DelegatorShares.Add(issuedDelegatorShares) + v.Tokens.Amount = v.Tokens.Amount.Add(poolShares.Amount) + issuedShares := Tokens.Amount.Quo(exRate) + v.DelegatorShares = v.DelegatorShares.Add(issuedShares) return v, pool, issuedDelegatorShares } @@ -321,28 +308,15 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s // // NOTE: This function assumes the shares have already been updated for the // validator status. -func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, int64) { +func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (validator Validator, pool Pool, issuedTokens sdk.Rat) { amount := v.DelegatorShareExRate(pool).Mul(delShares) - eqBondedSharesToRemove := NewBondedShares(amount) v.DelegatorShares = v.DelegatorShares.Sub(delShares) - var createdCoins int64 - - switch v.Status() { - case sdk.Unbonded: - unbondedShares := eqBondedSharesToRemove.ToUnbonded(pool).Amount - pool, createdCoins = pool.removeSharesUnbonded(unbondedShares) - v.PoolShares.Amount = v.PoolShares.Amount.Sub(unbondedShares) - case sdk.Unbonding: - unbondingShares := eqBondedSharesToRemove.ToUnbonding(pool).Amount - pool, createdCoins = pool.removeSharesUnbonding(unbondingShares) - v.PoolShares.Amount = v.PoolShares.Amount.Sub(unbondingShares) - case sdk.Bonded: - pool, createdCoins = pool.removeSharesBonded(eqBondedSharesToRemove.Amount) - v.PoolShares.Amount = v.PoolShares.Amount.Sub(eqBondedSharesToRemove.Amount) + if v.Status == sdk.Bonded { + pool = pool.RemoveBondedTokens(sdk.NewRat(amount)) } - return v, pool, createdCoins + return v, pool, amount } // DelegatorShareExRate gets the exchange rate of tokens over delegator shares. @@ -362,7 +336,7 @@ var _ sdk.Validator = Validator{} // nolint - for sdk.Validator func (v Validator) GetRevoked() bool { return v.Revoked } func (v Validator) GetMoniker() string { return v.Description.Moniker } -func (v Validator) GetStatus() sdk.BondStatus { return v.Status() } +func (v Validator) GetStatus() sdk.BondStatus { return v.Status } func (v Validator) GetOwner() sdk.AccAddress { return v.Owner } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } func (v Validator) GetPower() sdk.Rat { return v.PoolShares.Bonded() } @@ -381,7 +355,8 @@ func (v Validator) HumanReadableString() (string, error) { resp := "Validator \n" resp += fmt.Sprintf("Owner: %s\n", v.Owner) resp += fmt.Sprintf("Validator: %s\n", bechVal) - resp += fmt.Sprintf("Tokens: Status %s, Amount: %s\n", sdk.BondStatusToString(v.Tokens.Status), v.Tokens.Amount.FloatString()) + resp += fmt.Sprintf("Status: %s\n", sdk.BondStatusToString(v.Status)) + resp += fmt.Sprintf("Tokens: %s\n", v.Tokens.FloatString()) resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.FloatString()) resp += fmt.Sprintf("Description: %s\n", v.Description) resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight) From d1270ce744c7f176968ca2ce96d080c243b1a12e Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 11 Jul 2018 20:05:54 -0400 Subject: [PATCH 03/25] worked through stake/type compile error --- types/stake.go | 7 +- x/stake/keeper/slash.go | 22 ++++-- x/stake/keeper/validator.go | 38 +++++------ x/stake/types/pool.go | 10 +-- x/stake/types/test_utils.go | 130 +++++++++++++++--------------------- x/stake/types/validator.go | 64 ++++++++++-------- 6 files changed, 136 insertions(+), 135 deletions(-) diff --git a/types/stake.go b/types/stake.go index 35eeaba1f0c1..eb3f660820f3 100644 --- a/types/stake.go +++ b/types/stake.go @@ -26,10 +26,15 @@ func BondStatusToString(b BondStatus) string { case 0x02: return "Bonded" default: - return "" + panic("improper use of BondStatusToString") } } +// nolint +func (b BondStatus) Equal(b2 BondStatus) bool { + return byte(b) == byte(b2) +} + // validator for a delegated proof of stake system type Validator interface { GetRevoked() bool // whether the validator is revoked diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 44bc2aade609..bbd99b28f000 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -38,7 +38,9 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // NOTE: Correctness dependent on invariant that unbonding delegations / redelegations must also have been completely // slashed in this case - which we don't explicitly check, but should be true. // Log the slash attempt for future reference (maybe we should tag it too) - logger.Error(fmt.Sprintf("WARNING: Ignored attempt to slash a nonexistent validator with address %s, we recommend you investigate immediately", pubkey.Address())) + logger.Error(fmt.Sprintf( + "WARNING: Ignored attempt to slash a nonexistent validator with address %s, we recommend you investigate immediately", + pubkey.Address())) return } ownerAddress := validator.GetOwner() @@ -51,11 +53,15 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in switch { case infractionHeight > ctx.BlockHeight(): // Can't slash infractions in the future - panic(fmt.Sprintf("impossible attempt to slash future infraction at height %d but we are at height %d", infractionHeight, ctx.BlockHeight())) + panic(fmt.Sprintf( + "impossible attempt to slash future infraction at height %d but we are at height %d", + infractionHeight, ctx.BlockHeight())) case infractionHeight == ctx.BlockHeight(): // Special-case slash at current height for efficiency - we don't need to look through unbonding delegations or redelegations - logger.Info(fmt.Sprintf("Slashing at current height %d, not scanning unbonding delegations & redelegations", infractionHeight)) + logger.Info(fmt.Sprintf( + "Slashing at current height %d, not scanning unbonding delegations & redelegations", + infractionHeight)) case infractionHeight < ctx.BlockHeight(): // Iterate through unbonding delegations from slashed validator @@ -81,12 +87,12 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // Cannot decrease balance below zero - sharesToRemove := sdk.MinInt(remainingSlashAmount, validator.PoolShares.Amount.RoundInt()) + sharesToRemove := sdk.MinInt(remainingSlashAmount, validator.Tokens.RoundInt()) // Get the current pool pool := k.GetPool(ctx) // remove shares from the validator - validator, pool, burned := validator.RemovePoolShares(pool, sdk.NewRatFromInt(sharesToRemove)) + validator, pool, burned := validator.RemoveBondedTokens(pool, sdk.NewRatFromInt(sharesToRemove)) // burn tokens pool.LooseTokens -= burned // update the pool @@ -94,12 +100,14 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // update the validator, possibly kicking it out validator = k.UpdateValidator(ctx, validator) // remove validator if it has been reduced to zero shares - if validator.PoolShares.Amount.IsZero() { + if validator.Tokens.IsZero() { k.RemoveValidator(ctx, validator.Owner) } // Log that a slash occurred! - logger.Info(fmt.Sprintf("Validator %s slashed by slashFactor %v, removed %v shares and burned %d tokens", pubkey.Address(), slashFactor, sharesToRemove, burned)) + logger.Info(fmt.Sprintf( + "Validator %s slashed by slashFactor %v, removed %v shares and burned %d tokens", + pubkey.Address(), slashFactor, sharesToRemove, burned)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index e96a1330b5cc..c7ae43cbebc1 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -149,7 +149,7 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { if !found { panic(fmt.Sprintf("validator record not found for address: %v\n", address)) } - if validator.Status() == sdk.Bonded { + if validator.Status == sdk.Bonded { validators[i] = validator i++ } @@ -212,7 +212,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type switch { // if already bonded and power increasing only need to update tendermint case powerIncreasing && !validator.Revoked && - (oldFound && oldValidator.Status() == sdk.Bonded): + (oldFound && oldValidator.Status == sdk.Bonded): bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) store.Set(GetTendermintUpdatesKey(validator.Owner), bz) @@ -224,7 +224,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type // if was unbonded and the new power is less than the cliff validator case cliffPower != nil && - (oldFound && oldValidator.Status() == sdk.Unbonded) && + (oldFound && oldValidator.Status == sdk.Unbonded) && bytes.Compare(valPower, cliffPower) == -1: //(valPower < cliffPower // skip to completion @@ -234,19 +234,19 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type default: // update the validator set for this validator + // if updated, the validator has changed bonding status updatedVal, updated := k.UpdateBondedValidators(ctx, validator) if updated { // updates to validator occurred to be updated validator = updatedVal - } else { + break + } - // if decreased in power but still bonded, update Tendermint validator - // (if updatedVal is set, the validator has changed bonding status) - stillBonded := oldFound && oldValidator.Status() == sdk.Bonded - if stillBonded && oldValidator.PoolShares.Bonded().GT(validator.PoolShares.Bonded()) { - bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) - store.Set(GetTendermintUpdatesKey(validator.Owner), bz) - } + // if decreased in power but still bonded, update Tendermint validator + if oldFound && oldValidator.BondedTokens().GT(validator.BondedTokens()) { + bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) + store.Set(GetTendermintUpdatesKey(validator.Owner), bz) } + } k.SetValidator(ctx, validator) @@ -254,7 +254,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type } func (k Keeper) updateForRevoking(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator { - if newValidator.Revoked && oldFound && oldValidator.Status() == sdk.Bonded { + if newValidator.Revoked && oldFound && oldValidator.Status == sdk.Bonded { newValidator = k.unbondValidator(ctx, newValidator) // need to also clear the cliff validator spot because the revoke has @@ -266,7 +266,7 @@ func (k Keeper) updateForRevoking(ctx sdk.Context, oldFound bool, oldValidator, } func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool { - if oldFound && oldValidator.PoolShares.Bonded().LT(newValidator.PoolShares.Bonded()) { + if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) { return true } return false @@ -277,7 +277,7 @@ func (k Keeper) bondIncrement(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) (height int64, intraTxCounter int16) { // if already a validator, copy the old block height and counter, else set them - if oldFound && oldValidator.Status() == sdk.Bonded { + if oldFound && oldValidator.Status == sdk.Bonded { height = oldValidator.BondHeight intraTxCounter = oldValidator.BondIntraTxCounter return @@ -350,14 +350,14 @@ func (k Keeper) UpdateBondedValidators(ctx sdk.Context, // increment bondedValidatorsCount / get the validator to bond if !validator.Revoked { - if validator.Status() != sdk.Bonded { + if validator.Status != sdk.Bonded { validatorToBond = validator newValidatorBonded = true } bondedValidatorsCount++ // sanity check - } else if validator.Status() == sdk.Bonded { + } else if validator.Status == sdk.Bonded { panic(fmt.Sprintf("revoked validator cannot be bonded, address: %v\n", ownerAddr)) } @@ -444,7 +444,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) { if !validator.Revoked { bondedValidatorsCount++ } else { - if validator.Status() == sdk.Bonded { + if validator.Status == sdk.Bonded { panic(fmt.Sprintf("revoked validator cannot be bonded, address: %v\n", ownerAddr)) } } @@ -483,7 +483,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) type pool := k.GetPool(ctx) // sanity check - if validator.Status() == sdk.Unbonded { + if validator.Status == sdk.Unbonded { panic(fmt.Sprintf("should not already be unbonded, validator: %v\n", validator)) } @@ -510,7 +510,7 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. pool := k.GetPool(ctx) // sanity check - if validator.Status() == sdk.Bonded { + if validator.Status == sdk.Bonded { panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator)) } diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 6dbc036aa4cb..d11f36cf9faa 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -42,7 +42,7 @@ func InitialPool() Pool { //____________________________________________________________________ // Sum total of all staking tokens in the pool -func (p Pool) TokenSupply() int64 { +func (p Pool) TokenSupply() sdk.Rat { return p.LooseTokens.Add(p.BondedTokens) } @@ -50,8 +50,8 @@ func (p Pool) TokenSupply() int64 { // get the bond ratio of the global state func (p Pool) BondedRatio() sdk.Rat { - if p.TokenSupply() > 0 { - return sdk.NewRat(p.BondedTokens, p.TokenSupply()) + if p.TokenSupply().GT(sdk.ZeroRat()) { + return p.BondedTokens.Quo(p.TokenSupply()) } return sdk.ZeroRat() } @@ -61,7 +61,7 @@ func (p Pool) BondedRatio() sdk.Rat { func (p Pool) addBondedTokens(bondedTokens sdk.Rat) Pool { p.BondedTokens = p.BondedTokens.Add(bondedTokens) p.LooseTokens = p.LooseTokens.Sub(bondedTokens) - if p.LooseTokens < 0 { + if p.LooseTokens.LT(sdk.ZeroRat()) { panic(fmt.Sprintf("sanity check: loose tokens negative, pool: %v", p)) } return p @@ -70,7 +70,7 @@ func (p Pool) addBondedTokens(bondedTokens sdk.Rat) Pool { func (p Pool) removeBondedTokens(bondedTokens sdk.Rat) Pool { p.BondedTokens = p.BondedTokens.Sub(bondedTokens) p.LooseTokens = p.LooseTokens.Add(bondedTokens) - if p.UnbondedTokens < 0 { + if p.BondedTokens.LT(sdk.ZeroRat()) { panic(fmt.Sprintf("sanity check: bonded tokens negative, pool: %v", p)) } return p diff --git a/x/stake/types/test_utils.go b/x/stake/types/test_utils.go index d0622d46a897..92f0482d58fa 100644 --- a/x/stake/types/test_utils.go +++ b/x/stake/types/test_utils.go @@ -25,62 +25,59 @@ var ( // Operation reflects any operation that transforms staking state. It takes in // a RNG instance, pool, validator and returns an updated pool, updated // validator, delta tokens, and descriptive message. -type Operation func(r *rand.Rand, pool Pool, c Validator) (Pool, Validator, int64, string) +type Operation func(r *rand.Rand, pool Pool, c Validator) (Pool, Validator, sdk.Rat, string) // OpBondOrUnbond implements an operation that bonds or unbonds a validator // depending on current status. // nolint: unparam -func OpBondOrUnbond(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) { +// TODO split up into multiple operations +func OpBondOrUnbond(r *rand.Rand, pool Pool, validator Validator) (Pool, Validator, sdk.Rat, string) { var ( msg string newStatus sdk.BondStatus ) - if val.Status() == sdk.Bonded { - msg = fmt.Sprintf("sdk.Unbonded previously bonded validator %s (poolShares: %v, delShares: %v, DelegatorShareExRate: %v)", - val.Owner, val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool)) + if validator.Status == sdk.Bonded { + msg = fmt.Sprintf("sdk.Unbonded previously bonded validator %#v", validator) newStatus = sdk.Unbonded - } else if val.Status() == sdk.Unbonded { - msg = fmt.Sprintf("sdk.Bonded previously unbonded validator %s (poolShares: %v, delShares: %v, DelegatorShareExRate: %v)", - val.Owner, val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool)) + } else if validator.Status == sdk.Unbonded { + msg = fmt.Sprintf("sdk.Bonded previously bonded validator %#v", validator) newStatus = sdk.Bonded } - val, pool = val.UpdateStatus(pool, newStatus) - return pool, val, 0, msg + validator, pool = validator.UpdateStatus(pool, newStatus) + return pool, validator, sdk.ZeroRat(), msg } // OpAddTokens implements an operation that adds a random number of tokens to a // validator. -func OpAddTokens(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) { - msg := fmt.Sprintf("validator %s (status: %d, poolShares: %v, delShares: %v, DelegatorShareExRate: %v)", - val.Owner, val.Status(), val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool)) +func OpAddTokens(r *rand.Rand, pool Pool, validator Validator) (Pool, Validator, sdk.Rat, string) { + msg := fmt.Sprintf("validator %#v", validator) tokens := int64(r.Int31n(1000)) - val, pool, _ = val.AddTokensFromDel(pool, tokens) + validator, pool, _ = validator.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) // Tokens are removed so for accounting must be negative - return pool, val, -1 * tokens, msg + return pool, validator, sdk.NewRat(-1 * tokens), msg } // OpRemoveShares implements an operation that removes a random number of -// shares from a validator. -func OpRemoveShares(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) { +// delegatorshares from a validator. +func OpRemoveShares(r *rand.Rand, pool Pool, validator Validator) (Pool, Validator, sdk.Rat, string) { var shares sdk.Rat for { shares = sdk.NewRat(int64(r.Int31n(1000))) - if shares.LT(val.DelegatorShares) { + if shares.LT(validator.DelegatorShares) { break } } - msg := fmt.Sprintf("Removed %v shares from validator %s (status: %d, poolShares: %v, delShares: %v, DelegatorShareExRate: %v)", - shares, val.Owner, val.Status(), val.PoolShares, val.DelegatorShares, val.DelegatorShareExRate(pool)) + msg := fmt.Sprintf("Removed %v shares from validator %#v", shares, validator) - val, pool, tokens := val.RemoveDelShares(pool, shares) - return pool, val, tokens, msg + validator, pool, tokens := validator.RemoveDelShares(pool, shares) + return pool, validator, tokens, msg } // RandomOperation returns a random staking operation. @@ -100,39 +97,28 @@ func RandomOperation(r *rand.Rand) Operation { // AssertInvariants ensures invariants that should always be true are true. // nolint: unparam func AssertInvariants(t *testing.T, msg string, - pOrig Pool, cOrig []Validator, pMod Pool, vMods []Validator, tokens int64) { + pOrig Pool, cOrig []Validator, pMod Pool, vMods []Validator, tokens sdk.Rat) { // total tokens conserved require.Equal(t, - pOrig.UnbondedTokens+pOrig.BondedTokens, - pMod.UnbondedTokens+pMod.BondedTokens+tokens, - "Tokens not conserved - msg: %v\n, pOrig.PoolShares.Bonded(): %v, pOrig.PoolShares.Unbonded(): %v, pMod.PoolShares.Bonded(): %v, pMod.PoolShares.Unbonded(): %v, pOrig.UnbondedTokens: %v, pOrig.BondedTokens: %v, pMod.UnbondedTokens: %v, pMod.BondedTokens: %v, tokens: %v\n", + pOrig.LooseTokens.Add(pOrig.BondedTokens), + pMod.LooseTokens.Add(pMod.BondedTokens).Add(tokens), + "Tokens not conserved - msg: %v\n, pOrig.BondedTokens: %v, pOrig.LooseTokens: %v, pMod.BondedTokens: %v, pMod.LooseTokens: %v, tokens: %v\n", msg, - pOrig.BondedShares, pOrig.UnbondedShares, - pMod.BondedShares, pMod.UnbondedShares, - pOrig.UnbondedTokens, pOrig.BondedTokens, - pMod.UnbondedTokens, pMod.BondedTokens, tokens) + pOrig.BondedTokens, pOrig.LooseTokens, + pMod.BondedTokens, pMod.LooseTokens, + tokens) - // Nonnegative bonded shares - require.False(t, pMod.BondedShares.LT(sdk.ZeroRat()), + // Nonnegative bonded tokens + require.False(t, pMod.BondedTokens.LT(sdk.ZeroRat()), "Negative bonded shares - msg: %v\npOrig: %v\npMod: %v\ntokens: %v\n", msg, pOrig, pMod, tokens) - // Nonnegative unbonded shares - require.False(t, pMod.UnbondedShares.LT(sdk.ZeroRat()), + // Nonnegative loose tokens + require.False(t, pMod.LooseTokens.LT(sdk.ZeroRat()), "Negative unbonded shares - msg: %v\npOrig: %v\npMod: %v\ntokens: %v\n", msg, pOrig, pMod, tokens) - // Nonnegative bonded ex rate - require.False(t, pMod.BondedShareExRate().LT(sdk.ZeroRat()), - "Applying operation \"%s\" resulted in negative BondedShareExRate: %d", - msg, pMod.BondedShareExRate().RoundInt64()) - - // Nonnegative unbonded ex rate - require.False(t, pMod.UnbondedShareExRate().LT(sdk.ZeroRat()), - "Applying operation \"%s\" resulted in negative UnbondedShareExRate: %d", - msg, pMod.UnbondedShareExRate().RoundInt64()) - for _, vMod := range vMods { // Nonnegative ex rate require.False(t, vMod.DelegatorShareExRate(pMod).LT(sdk.ZeroRat()), @@ -143,23 +129,17 @@ func AssertInvariants(t *testing.T, msg string, ) // Nonnegative poolShares - require.False(t, vMod.PoolShares.Bonded().LT(sdk.ZeroRat()), - "Applying operation \"%s\" resulted in negative validator.PoolShares.Bonded(): %v (validator.DelegatorShares: %v, validator.DelegatorShareExRate: %v, validator.Owner: %s)", + require.False(t, vMod.BondedTokens().LT(sdk.ZeroRat()), + "Applying operation \"%s\" resulted in negative validator.BondedTokens(): %#v", msg, - vMod.PoolShares.Bonded(), - vMod.DelegatorShares, - vMod.DelegatorShareExRate(pMod), - vMod.Owner, + vMod, ) // Nonnegative delShares require.False(t, vMod.DelegatorShares.LT(sdk.ZeroRat()), - "Applying operation \"%s\" resulted in negative validator.DelegatorShares: %v (validator.PoolShares.Bonded(): %v, validator.DelegatorShareExRate: %v, validator.Owner: %s)", + "Applying operation \"%s\" resulted in negative validator.DelegatorShares: %#v", msg, - vMod.DelegatorShares, - vMod.PoolShares.Bonded(), - vMod.DelegatorShareExRate(pMod), - vMod.Owner, + vMod, ) } } @@ -169,40 +149,40 @@ func AssertInvariants(t *testing.T, msg string, // randomValidator generates a random validator. // nolint: unparam func randomValidator(r *rand.Rand, i int) Validator { - poolSharesAmt := sdk.NewRat(int64(r.Int31n(10000))) - delShares := sdk.NewRat(int64(r.Int31n(10000))) - var pShares PoolShares + tokens := sdk.NewRat(int64(r.Int31n(10000))) + delShares := sdk.NewRat(int64(r.Int31n(10000))) - if r.Float64() < float64(0.5) { - pShares = NewBondedShares(poolSharesAmt) - } else { - pShares = NewUnbondedShares(poolSharesAmt) + // TODO add more options here + status := sdk.Bonded + if r.Float64() > float64(0.5) { + status = sdk.Unbonded } - return Validator{ - Owner: addr1, - PubKey: pk1, - PoolShares: pShares, - DelegatorShares: delShares, - } + validator := NewValidator(addr1, pk1, Description{}) + validator.Status = status + validator.Tokens = tokens + validator.DelegatorShares = delShares + + return validator } // RandomSetup generates a random staking state. func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) { pool := InitialPool() - pool.LooseTokens = 100000 + pool.LooseTokens = sdk.NewRat(100000) validators := make([]Validator, numValidators) for i := 0; i < numValidators; i++ { validator := randomValidator(r, i) - if validator.Status() == sdk.Bonded { - pool.BondedShares = pool.BondedShares.Add(validator.PoolShares.Bonded()) - pool.BondedTokens += validator.PoolShares.Bonded().RoundInt64() - } else if validator.Status() == sdk.Unbonded { - pool.UnbondedShares = pool.UnbondedShares.Add(validator.PoolShares.Unbonded()) - pool.UnbondedTokens += validator.PoolShares.Unbonded().RoundInt64() + switch validator.Status { + case sdk.Bonded: + pool.BondedTokens = pool.BondedTokens.Add(validator.Tokens) + case sdk.Unbonded, sdk.Unbonding: + pool.LooseTokens = pool.BondedTokens.Add(validator.Tokens) + default: + panic("improper use of RandomSetup") } validators[i] = validator diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 2ef3f81e6f7c..24e6ea931ed3 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -51,7 +51,8 @@ func NewValidator(owner sdk.AccAddress, pubKey crypto.PubKey, description Descri Owner: owner, PubKey: pubKey, Revoked: false, - PoolShares: NewUnbondedShares(sdk.ZeroRat()), + Status: sdk.Unbonded, + Tokens: sdk.ZeroRat(), DelegatorShares: sdk.ZeroRat(), Description: description, BondHeight: int64(0), @@ -69,7 +70,8 @@ func NewValidator(owner sdk.AccAddress, pubKey crypto.PubKey, description Descri type validatorValue struct { PubKey crypto.PubKey Revoked bool - PoolShares PoolShares + Tokens sdk.Rat + Status sdk.BondStatus DelegatorShares sdk.Rat Description Description BondHeight int64 @@ -87,7 +89,8 @@ func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte { val := validatorValue{ PubKey: validator.PubKey, Revoked: validator.Revoked, - PoolShares: validator.PoolShares, + Tokens: validator.Tokens, + Status: validator.Status, DelegatorShares: validator.DelegatorShares, Description: validator.Description, BondHeight: validator.BondHeight, @@ -129,7 +132,8 @@ func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Val Owner: ownerAddr, PubKey: storeValue.PubKey, Revoked: storeValue.Revoked, - PoolShares: storeValue.PoolShares, + Tokens: storeValue.Tokens, + Status: storeValue.Status, DelegatorShares: storeValue.DelegatorShares, Description: storeValue.Description, BondHeight: storeValue.BondHeight, @@ -147,7 +151,8 @@ func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Val func (v Validator) Equal(c2 Validator) bool { return v.PubKey.Equals(c2.PubKey) && bytes.Equal(v.Owner, c2.Owner) && - v.PoolShares.Equal(c2.PoolShares) && + v.Tokens.Equal(c2.Tokens) && + v.Status.Equal(c2.Status) && v.DelegatorShares.Equal(c2.DelegatorShares) && v.Description == c2.Description && v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) && @@ -222,7 +227,7 @@ func (d Description) EnsureLength() (Description, sdk.Error) { func (v Validator) ABCIValidator() abci.Validator { return abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(v.PubKey), - Power: v.PoolShares.Bonded().RoundInt64(), + Power: v.BondedTokens().RoundInt64(), } } @@ -238,7 +243,6 @@ func (v Validator) ABCIValidatorZero() abci.Validator { // UpdateStatus updates the location of the shares within a validator // to reflect the new status func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, Pool) { - var tokens int64 switch v.Status { case sdk.Unbonded: @@ -247,7 +251,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Unbonded: return v, pool case sdk.Bonded: - pool = pool.AddTokensBonded(v.PoolShares.Amount) + pool = pool.addBondedTokens(v.Tokens) } case sdk.Unbonding: @@ -255,7 +259,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Unbonding: return v, pool case sdk.Bonded: - pool = pool.AddTokensBonded(v.PoolShares.Amount) + pool = pool.addBondedTokens(v.Tokens) } case sdk.Bonded: @@ -263,60 +267,56 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Bonded: return v, pool default: - pool = pool.RemoveTokensBonded(v.PoolShares.Amount) + pool = pool.removeBondedTokens(v.Tokens) } } - v.Tokens.Status = NewStatus + v.Status = NewStatus return v, pool } // removes tokens from a validator func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { - var tokens int64 - if v.Status == sdk.Bonded { pool = pool.removeBondedTokens(tokens) } - v.PoolShares.Amount = v.PoolShares.Amount.Sub(poolShares) - return v, pool, tokens + v.Tokens = v.Tokens.Sub(tokens) + return v, pool } //_________________________________________________________________________________________________________ // AddTokensFromDel adds tokens to a validator -func (v Validator) AddTokensFromDel(pool Pool, amount int64) (validator Validator, pool Pool, issuedShares sdk.Rat) { - var poolShares PoolShares - var equivalentBondedShares sdk.Rat +func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Rat) { // bondedShare/delegatedShare exRate := v.DelegatorShareExRate(pool) if v.Status == sdk.Bonded { - pool = pool.AddBondedTokens(sdk.NewRat(amount)) + pool = pool.addBondedTokens(sdk.NewRat(amount)) } - v.Tokens.Amount = v.Tokens.Amount.Add(poolShares.Amount) - issuedShares := Tokens.Amount.Quo(exRate) + v.Tokens = v.Tokens.Add(sdk.NewRat(amount)) + issuedShares := v.Tokens.Quo(exRate) v.DelegatorShares = v.DelegatorShares.Add(issuedShares) - return v, pool, issuedDelegatorShares + return v, pool, issuedShares } // RemoveDelShares removes delegator shares from a validator. // // NOTE: This function assumes the shares have already been updated for the // validator status. -func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (validator Validator, pool Pool, issuedTokens sdk.Rat) { - amount := v.DelegatorShareExRate(pool).Mul(delShares) +func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, sdk.Rat) { + issuedTokens := v.DelegatorShareExRate(pool).Mul(delShares) v.DelegatorShares = v.DelegatorShares.Sub(delShares) if v.Status == sdk.Bonded { - pool = pool.RemoveBondedTokens(sdk.NewRat(amount)) + pool = pool.removeBondedTokens(issuedTokens) } - return v, pool, amount + return v, pool, issuedTokens } // DelegatorShareExRate gets the exchange rate of tokens over delegator shares. @@ -325,7 +325,15 @@ func (v Validator) DelegatorShareExRate(pool Pool) sdk.Rat { if v.DelegatorShares.IsZero() { return sdk.OneRat() } - return v.Tokens.Amount.Quo(v.DelegatorShares) + return v.Tokens.Quo(v.DelegatorShares) +} + +// Get the bonded tokens which the validator holds +func (v Validator) BondedTokens() sdk.Rat { + if v.Status == sdk.Bonded { + return v.Tokens + } + return sdk.ZeroRat() } //______________________________________________________________________ @@ -339,7 +347,7 @@ func (v Validator) GetMoniker() string { return v.Description.Moniker } func (v Validator) GetStatus() sdk.BondStatus { return v.Status } func (v Validator) GetOwner() sdk.AccAddress { return v.Owner } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } -func (v Validator) GetPower() sdk.Rat { return v.PoolShares.Bonded() } +func (v Validator) GetPower() sdk.Rat { return v.BondedTokens() } func (v Validator) GetDelegatorShares() sdk.Rat { return v.DelegatorShares } func (v Validator) GetBondHeight() int64 { return v.BondHeight } From 8252e47754f30be1142a6e5bd8e8407536de8101 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 11 Jul 2018 20:39:46 -0400 Subject: [PATCH 04/25] work through a bunch of keeper errors --- types/rational.go | 8 +++++++ x/stake/keeper/delegation.go | 6 ++--- x/stake/keeper/inflation.go | 4 ++-- x/stake/keeper/key.go | 4 ++-- x/stake/keeper/sdk_types.go | 2 +- x/stake/keeper/slash.go | 44 ++++++++++++++++++++--------------- x/stake/keeper/test_common.go | 2 +- 7 files changed, 42 insertions(+), 28 deletions(-) diff --git a/types/rational.go b/types/rational.go index f81ee083649e..d30903ac28de 100644 --- a/types/rational.go +++ b/types/rational.go @@ -252,3 +252,11 @@ func RatsEqual(r1s, r2s []Rat) bool { func RatEq(t *testing.T, exp, got Rat) (*testing.T, bool, string, Rat, Rat) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got } + +// test if two rat arrays are the equal +func MinRat(r1, r2 Rat) Rat { + if r1.LT(r2) { + return r1 + } + return r2 +} diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index e2f96f3d9f57..d1b92cd107dd 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -235,7 +235,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt // unbond the the delegation return func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, - shares sdk.Rat) (amount int64, err sdk.Error) { + shares sdk.Rat) (amount sdk.Rat, err sdk.Error) { // check if delegation has any shares in it unbond delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -303,7 +303,7 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk // create the unbonding delegation params := k.GetParams(ctx) minTime := ctx.BlockHeader().Time + params.UnbondingTime - balance := sdk.Coin{params.BondDenom, sdk.NewInt(returnAmount)} + balance := sdk.Coin{params.BondDenom, returnAmount.RoundInt()} ubd := types.UnbondingDelegation{ DelegatorAddr: delegatorAddr, @@ -353,7 +353,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd } params := k.GetParams(ctx) - returnCoin := sdk.Coin{params.BondDenom, sdk.NewInt(returnAmount)} + returnCoin := sdk.Coin{params.BondDenom, returnAmount.RoundInt()} dstValidator, found := k.GetValidator(ctx, validatorDstAddr) if !found { return types.ErrBadRedelegationDst(k.Codespace()) diff --git a/x/stake/keeper/inflation.go b/x/stake/keeper/inflation.go index 26b5158791ba..3cf8ec4667b3 100644 --- a/x/stake/keeper/inflation.go +++ b/x/stake/keeper/inflation.go @@ -18,10 +18,10 @@ func (k Keeper) ProcessProvisions(ctx sdk.Context) types.Pool { pool := k.GetPool(ctx) pool.Inflation = k.NextInflation(ctx) - provisions := pool.Inflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat).RoundInt64() + provisions := pool.Inflation.Mul(pool.TokenSupply()).Quo(hrsPerYrRat) // TODO add to the fees provisions - pool.LooseTokens += provisions + pool.LooseTokens = pool.LooseTokens.Add(provisions) return pool } diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index ac7fe6e5f25d..e373ede18a45 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -69,8 +69,8 @@ func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) [] // NOTE the larger values are of higher value func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { - power := validator.EquivalentBondedShares(pool) - powerBytes := []byte(power.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) + potentialPower := validator.Tokens + powerBytes := []byte(potentialPower.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) revokedBytes := make([]byte, 1) if validator.Revoked { diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 989e951663e7..280320649601 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -60,7 +60,7 @@ func (k Keeper) Validator(ctx sdk.Context, address sdk.AccAddress) sdk.Validator // total power from the bond func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat { pool := k.GetPool(ctx) - return pool.BondedShares + return pool.BondedTokens } //__________________________________________________________________________ diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index bbd99b28f000..7d434019aa0a 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -28,7 +28,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // Amount of slashing = slash slashFactor * power at time of infraction - slashAmount := sdk.NewRat(power).Mul(slashFactor).RoundInt() + slashAmount := sdk.NewRat(power).Mul(slashFactor) // ref https://github.com/cosmos/cosmos-sdk/issues/1348 // ref https://github.com/cosmos/cosmos-sdk/issues/1471 @@ -52,18 +52,21 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in switch { case infractionHeight > ctx.BlockHeight(): + // Can't slash infractions in the future panic(fmt.Sprintf( "impossible attempt to slash future infraction at height %d but we are at height %d", infractionHeight, ctx.BlockHeight())) case infractionHeight == ctx.BlockHeight(): + // Special-case slash at current height for efficiency - we don't need to look through unbonding delegations or redelegations logger.Info(fmt.Sprintf( "Slashing at current height %d, not scanning unbonding delegations & redelegations", infractionHeight)) case infractionHeight < ctx.BlockHeight(): + // Iterate through unbonding delegations from slashed validator unbondingDelegations := k.GetUnbondingDelegationsFromValidator(ctx, ownerAddress) for _, unbondingDelegation := range unbondingDelegations { @@ -83,18 +86,17 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } remainingSlashAmount = remainingSlashAmount.Sub(amountSlashed) } - } // Cannot decrease balance below zero - sharesToRemove := sdk.MinInt(remainingSlashAmount, validator.Tokens.RoundInt()) + burned := sdk.MinRat(remainingSlashAmount, validator.Tokens) // Get the current pool pool := k.GetPool(ctx) // remove shares from the validator - validator, pool, burned := validator.RemoveBondedTokens(pool, sdk.NewRatFromInt(sharesToRemove)) + validator, pool = validator.RemoveTokens(pool, burned) // burn tokens - pool.LooseTokens -= burned + pool.LooseTokens = pool.LooseTokens.Sub(burned) // update the pool k.SetPool(ctx, pool) // update the validator, possibly kicking it out @@ -106,8 +108,8 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // Log that a slash occurred! logger.Info(fmt.Sprintf( - "Validator %s slashed by slashFactor %v, removed %v shares and burned %d tokens", - pubkey.Address(), slashFactor, sharesToRemove, burned)) + "Validator %s slashed by slashFactor %v, burned %d tokens", + pubkey.Address(), slashFactor, burned)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return @@ -147,28 +149,30 @@ func (k Keeper) setRevoked(ctx sdk.Context, pubkey crypto.PubKey, revoked bool) // the unbonding delegation had enough stake to slash // (the amount actually slashed may be less if there's // insufficient stake remaining) -func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Int) { +func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, + infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Rat) { + now := ctx.BlockHeader().Time // If unbonding started before this height, stake didn't contribute to infraction if unbondingDelegation.CreationHeight < infractionHeight { - return sdk.ZeroInt() + return sdk.ZeroRat() } if unbondingDelegation.MinTime < now { // Unbonding delegation no longer eligible for slashing, skip it // TODO Settle and delete it automatically? - return sdk.ZeroInt() + return sdk.ZeroRat() } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewRatFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor).RoundInt() + slashAmount = sdk.NewRatFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) // Don't slash more tokens than held // Possible since the unbonding delegation may already // have been slashed, and slash amounts are calculated // according to stake held at time of infraction - unbondingSlashAmount := sdk.MinInt(slashAmount, unbondingDelegation.Balance.Amount) + unbondingSlashAmount := sdk.MinInt(slashAmount.RoundInt(), unbondingDelegation.Balance.Amount) // Update unbonding delegation if necessary if !unbondingSlashAmount.IsZero() { @@ -177,7 +181,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty pool := k.GetPool(ctx) // Burn loose tokens // Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760 - pool.LooseTokens -= slashAmount.Int64() + pool.LooseTokens = pool.LooseTokens.Sub(slashAmount) k.SetPool(ctx, pool) } @@ -189,28 +193,30 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty // the unbonding delegation had enough stake to slash // (the amount actually slashed may be less if there's // insufficient stake remaining) -func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation, infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Int) { +func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation, + infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Rat) { + now := ctx.BlockHeader().Time // If redelegation started before this height, stake didn't contribute to infraction if redelegation.CreationHeight < infractionHeight { - return sdk.ZeroInt() + return sdk.ZeroRat() } if redelegation.MinTime < now { // Redelegation no longer eligible for slashing, skip it // TODO Delete it automatically? - return sdk.ZeroInt() + return sdk.ZeroRat() } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewRatFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor).RoundInt() + slashAmount = sdk.NewRatFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) // Don't slash more tokens than held // Possible since the redelegation may already // have been slashed, and slash amounts are calculated // according to stake held at time of infraction - redelegationSlashAmount := sdk.MinInt(slashAmount, redelegation.Balance.Amount) + redelegationSlashAmount := sdk.MinInt(slashAmount.RoundInt(), redelegation.Balance.Amount) // Update redelegation if necessary if !redelegationSlashAmount.IsZero() { @@ -235,7 +241,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re } // Burn loose tokens pool := k.GetPool(ctx) - pool.LooseTokens -= tokensToBurn + pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) k.SetPool(ctx, pool) } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 983933123fa6..7b62af8523ff 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -118,7 +118,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context {keeper.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)}, }) require.Nil(t, err) - pool.LooseTokens += initCoins + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewRat(initCoins)) keeper.SetPool(ctx, pool) } From 4563fb7eb4409a28dd96534380002b5050511306 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 11 Jul 2018 20:56:21 -0400 Subject: [PATCH 05/25] worked through compile errors --- client/lcd/test_helpers.go | 2 +- cmd/gaia/app/genesis.go | 4 +-- x/gov/test_common.go | 2 +- x/slashing/test_common.go | 4 ++- x/stake/client/rest/query.go | 55 ++-------------------------------- x/stake/genesis.go | 4 +-- x/stake/stake.go | 4 --- x/stake/types/validator.go | 58 ++++++++++++++++++++++++++++++++++++ 8 files changed, 69 insertions(+), 64 deletions(-) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 5967b2319fb2..28afef68d6a0 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -146,7 +146,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress accAuth.Coins = sdk.Coins{sdk.NewCoin("steak", 100)} acc := gapp.NewGenesisAccount(&accAuth) genesisState.Accounts = append(genesisState.Accounts, acc) - genesisState.StakeData.Pool.LooseTokens += 100 + genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewRat(100)) } appState, err := wire.MarshalJSONIndent(cdc, genesisState) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 0472c46ada2d..af547e844620 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -160,7 +160,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState } acc := NewGenesisAccount(&accAuth) genaccs[i] = acc - stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens + freeFermionsAcc // increase the supply + stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewRat(freeFermionsAcc)) // increase the supply // add the validator if len(genTx.Name) > 0 { @@ -168,7 +168,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState validator := stake.NewValidator(genTx.Address, sdk.MustGetAccPubKeyBech32(genTx.PubKey), desc) - stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens + freeFermionVal // increase the supply + stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewRat(freeFermionVal)) // increase the supply // add some new shares to the validator var issuedDelShares sdk.Rat diff --git a/x/gov/test_common.go b/x/gov/test_common.go index ecdaa34faddb..5567e4697a7f 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -59,7 +59,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = 100000 + stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) err := stake.InitGenesis(ctx, stakeKeeper, stakeGenesis) if err != nil { diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index b9a91f4d5bc7..1b1b81cee0f7 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -63,7 +63,9 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep ck := bank.NewKeeper(accountMapper) sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) genesis := stake.DefaultGenesisState() - genesis.Pool.LooseTokens = initCoins.MulRaw(int64(len(addrs))).Int64() + + genesis.Pool.LooseTokens = sdk.NewRat(initCoins.MulRaw(int64(len(addrs))).Int64()) + err = stake.InitGenesis(ctx, sk, genesis) require.Nil(t, err) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index f5a17c7850e9..9a4c3755ddcc 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -215,57 +215,6 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { } } -// TODO move exist next to validator struct for maintainability -type StakeValidatorOutput struct { - Owner sdk.AccAddress `json:"owner"` // in bech32 - PubKey string `json:"pub_key"` // in bech32 - Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? - - PoolShares stake.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 stake.Description `json:"description"` // description terms for the validator - BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator - BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change - ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer - - Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators - CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission - CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) - - // fee related - PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools -} - -func bech32StakeValidatorOutput(validator stake.Validator) (StakeValidatorOutput, error) { - bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey) - if err != nil { - return StakeValidatorOutput{}, err - } - - return StakeValidatorOutput{ - Owner: validator.Owner, - PubKey: bechValPubkey, - Revoked: validator.Revoked, - - PoolShares: validator.PoolShares, - DelegatorShares: validator.DelegatorShares, - - Description: validator.Description, - BondHeight: validator.BondHeight, - BondIntraTxCounter: validator.BondIntraTxCounter, - ProposerRewardPool: validator.ProposerRewardPool, - - Commission: validator.Commission, - CommissionMax: validator.CommissionMax, - CommissionChangeRate: validator.CommissionChangeRate, - CommissionChangeToday: validator.CommissionChangeToday, - - PrevBondedShares: validator.PrevBondedShares, - }, nil -} - // TODO bech32 // http request handler to query list of validators func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { @@ -284,7 +233,7 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF } // parse out the validators - validators := make([]StakeValidatorOutput, len(kvs)) + validators := make([]types.BechValidator, len(kvs)) for i, kv := range kvs { addr := kv.Key[1:] @@ -295,7 +244,7 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF return } - bech32Validator, err := bech32StakeValidatorOutput(validator) + bech32Validator, err := validator.Bech32Validator() if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 177f89b76776..e54517fa5fd4 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -20,7 +20,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error for _, validator := range data.Validators { keeper.SetValidator(ctx, validator) - if validator.PoolShares.Amount.IsZero() { + if validator.Tokens.IsZero() { return errors.Errorf("genesis validator cannot have zero pool shares, validator: %v", validator) } if validator.DelegatorShares.IsZero() { @@ -31,7 +31,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error keeper.SetValidatorByPubKeyIndex(ctx, validator) keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool) - if validator.Status() == sdk.Bonded { + if validator.Status == sdk.Bonded { keeper.SetValidatorBondedIndex(ctx, validator) } } diff --git a/x/stake/stake.go b/x/stake/stake.go index c582fb6357a6..f1ac25fabab4 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -16,7 +16,6 @@ type ( Redelegation = types.Redelegation Params = types.Params Pool = types.Pool - PoolShares = types.PoolShares MsgCreateValidator = types.MsgCreateValidator MsgEditValidator = types.MsgEditValidator MsgDelegate = types.MsgDelegate @@ -62,9 +61,6 @@ var ( DefaultParams = types.DefaultParams InitialPool = types.InitialPool - NewUnbondedShares = types.NewUnbondedShares - NewUnbondingShares = types.NewUnbondingShares - NewBondedShares = types.NewBondedShares NewValidator = types.NewValidator NewDescription = types.NewDescription NewGenesisState = types.NewGenesisState diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 24e6ea931ed3..dafd6a5c9cf7 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -147,6 +147,64 @@ func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Val }, nil } +//___________________________________________________________________ + +// validator struct for bech output +type BechValidator struct { + Owner sdk.AccAddress `json:"owner"` // in bech32 + PubKey string `json:"pub_key"` // in bech32 + Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? + + Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) + Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) + 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:"bond_height"` // earliest height as a bonded validator + BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change + ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer + + Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators + CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge + CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) + + // fee related + PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools +} + +// get the bech validator from the the regular validator +func (v Validator) Bech32Validator() (BechValidator, error) { + bechValPubkey, err := sdk.Bech32ifyValPub(v.PubKey) + if err != nil { + return BechValidator{}, err + } + + return BechValidator{ + Owner: v.Owner, + PubKey: bechValPubkey, + Revoked: v.Revoked, + + Tokens: v.Tokens, + Status: v.Status, + DelegatorShares: v.DelegatorShares, + + Description: v.Description, + BondHeight: v.BondHeight, + BondIntraTxCounter: v.BondIntraTxCounter, + ProposerRewardPool: v.ProposerRewardPool, + + Commission: v.Commission, + CommissionMax: v.CommissionMax, + CommissionChangeRate: v.CommissionChangeRate, + CommissionChangeToday: v.CommissionChangeToday, + + PrevBondedShares: v.PrevBondedShares, + }, nil +} + +//___________________________________________________________________ + // only the vitals - does not check bond height of IntraTxCounter func (v Validator) Equal(c2 Validator) bool { return v.PubKey.Equals(c2.PubKey) && From 1daa854c85be0fde153d55e3816b3be2aab51ab5 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 11 Jul 2018 22:25:51 -0400 Subject: [PATCH 06/25] debugging tests --- client/lcd/lcd_test.go | 5 +- x/slashing/app_test.go | 6 +-- x/stake/app_test.go | 6 +-- x/stake/genesis_test.go | 5 +- x/stake/handler_test.go | 23 ++++----- x/stake/keeper/delegation_test.go | 10 ++-- x/stake/keeper/inflation_test.go | 43 ++++++++-------- x/stake/keeper/keeper_test.go | 3 +- x/stake/keeper/slash_test.go | 2 +- x/stake/stake.go | 1 + x/stake/types/pool_test.go | 16 ++---- x/stake/types/validator_test.go | 83 ++++++++++++++----------------- 12 files changed, 92 insertions(+), 111 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index b5800ca2920f..336ac307521e 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -26,7 +26,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" - stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest" ) func init() { @@ -828,11 +827,11 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, return results[0] } -func getValidators(t *testing.T, port string) []stakerest.StakeValidatorOutput { +func getValidators(t *testing.T, port string) []stake.BechValidator { // get the account to get the sequence res, body := Request(t, port, "GET", "/stake/validators", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var validators []stakerest.StakeValidatorOutput + var validators []stake.BechValidator err := cdc.UnmarshalJSON([]byte(body), &validators) require.Nil(t, err) return validators diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 333b4dc836ee..c249134ac12d 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -54,7 +54,7 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = 100000 + stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) err := stake.InitGenesis(ctx, keeper, stakeGenesis) if err != nil { panic(err) @@ -101,8 +101,8 @@ func TestSlashingMsgs(t *testing.T) { validator := checkValidator(t, mapp, stakeKeeper, addr1, true) require.Equal(t, addr1, validator.Owner) - require.Equal(t, sdk.Bonded, validator.Status()) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) + require.Equal(t, sdk.Bonded, validator.Status) + require.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) unrevokeMsg := MsgUnrevoke{ValidatorAddr: sdk.AccAddress(validator.PubKey.Address())} // no signing info yet diff --git a/x/stake/app_test.go b/x/stake/app_test.go index d1224230da40..c33677d9a964 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -63,7 +63,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { mapp.InitChainer(ctx, req) stakeGenesis := DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = 100000 + stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) err := InitGenesis(ctx, keeper, stakeGenesis) if err != nil { @@ -135,8 +135,8 @@ func TestStakeMsgs(t *testing.T) { validator := checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, addr1, validator.Owner) - require.Equal(t, sdk.Bonded, validator.Status()) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) + require.Equal(t, sdk.Bonded, validator.Status) + require.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) // check the bond that should have been created as well checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10)) diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 4ad5b3978d0d..2faff5bc02d6 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -14,8 +14,7 @@ func TestInitGenesis(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) pool := keeper.GetPool(ctx) - pool.UnbondedTokens = 1 - pool.UnbondedShares = sdk.OneRat() + pool.LooseTokens = sdk.OneRat() params := keeper.GetParams(ctx) var delegations []Delegation @@ -28,7 +27,7 @@ func TestInitGenesis(t *testing.T) { err := InitGenesis(ctx, keeper, genesisState) require.Error(t, err) - validators[0].PoolShares.Amount = sdk.OneRat() + validators[0].Tokens = sdk.OneRat() validators[0].DelegatorShares = sdk.OneRat() genesisState = types.NewGenesisState(pool, params, validators, delegations) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index ec0ef35f555a..98f4f25832f4 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -79,8 +79,8 @@ func TestValidatorByPowerIndex(t *testing.T) { keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - require.Equal(t, sdk.Unbonded, validator.PoolShares.Status) // ensure is unbonded - require.Equal(t, int64(500000), validator.PoolShares.Amount.RoundInt64()) // ensure is unbonded + require.Equal(t, sdk.Unbonded, validator.Status) // ensure is unbonded + require.Equal(t, int64(500000), validator.Tokens.RoundInt64()) // ensure is unbonded // the old power record should have been deleted as the power changed require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) @@ -128,10 +128,10 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { validator, found := keeper.GetValidator(ctx, addr1) require.True(t, found) - assert.Equal(t, sdk.Bonded, validator.Status()) + assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr1, validator.Owner) assert.Equal(t, pk1, validator.PubKey) - assert.Equal(t, sdk.NewRat(10), validator.PoolShares.Bonded()) + assert.Equal(t, sdk.NewRat(10), validator.BondedTokens()) assert.Equal(t, sdk.NewRat(10), validator.DelegatorShares) assert.Equal(t, Description{}, validator.Description) @@ -152,10 +152,10 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { validator, found = keeper.GetValidator(ctx, addr2) require.True(t, found) - assert.Equal(t, sdk.Bonded, validator.Status()) + assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr2, validator.Owner) assert.Equal(t, pk2, validator.PubKey) - assert.Equal(t, sdk.NewRat(10), validator.PoolShares.Bonded()) + assert.Equal(t, sdk.NewRat(10), validator.BondedTokens()) assert.Equal(t, sdk.NewRat(10), validator.DelegatorShares) assert.Equal(t, Description{}, validator.Description) } @@ -175,9 +175,9 @@ func TestIncrementsMsgDelegate(t *testing.T) { validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - require.Equal(t, sdk.Bonded, validator.Status()) + require.Equal(t, sdk.Bonded, validator.Status) require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64()) - require.Equal(t, bondAmount, validator.PoolShares.Bonded().RoundInt64(), "validator: %v", validator) + require.Equal(t, bondAmount, validator.BondedTokens().RoundInt64(), "validator: %v", validator) _, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.False(t, found) @@ -189,8 +189,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { pool := keeper.GetPool(ctx) exRate := validator.DelegatorShareExRate(pool) require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) - require.Equal(t, bondAmount, pool.BondedShares.RoundInt64()) - require.Equal(t, bondAmount, pool.BondedTokens) + require.Equal(t, bondAmount, pool.BondedTokens()) // just send the same msgbond multiple times msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) @@ -252,7 +251,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.Equal(t, initBond*2, validator.DelegatorShares.RoundInt64()) - require.Equal(t, initBond*2, validator.PoolShares.Bonded().RoundInt64()) + require.Equal(t, initBond*2, validator.BondedTokens().RoundInt64()) // just send the same msgUnbond multiple times // TODO use decimals here @@ -619,7 +618,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 2, len(vals), "vals %v", vals) val1, found := keeper.GetValidator(ctx, validatorAddr1) require.True(t, found) - require.Equal(t, sdk.Bonded, val1.Status(), "%v", val1) + require.Equal(t, sdk.Bonded, val1.Status, "%v", val1) } func TestJoiningAsCliffValidator(t *testing.T) { diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index c0a3ee8c5786..24df7f08a740 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -141,7 +141,7 @@ func TestUnbondingDelegation(t *testing.T) { func TestUnbondDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = 10 + pool.LooseTokens = sdk.NewRat(10) //create a validator and a delegator to that validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -152,7 +152,7 @@ func TestUnbondDelegation(t *testing.T) { pool = keeper.GetPool(ctx) require.Equal(t, int64(10), pool.BondedTokens) - require.Equal(t, int64(10), validator.PoolShares.Bonded().RoundInt64()) + require.Equal(t, int64(10), validator.BondedTokens().RoundInt64()) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -162,10 +162,10 @@ func TestUnbondDelegation(t *testing.T) { keeper.SetDelegation(ctx, delegation) var err error - var amount int64 + var amount sdk.Rat amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewRat(6)) require.NoError(t, err) - require.Equal(t, int64(6), amount) // shares to be added to an unbonding delegation / redelegation + require.Equal(t, int64(6), amount.RoundInt64()) // shares to be added to an unbonding delegation / redelegation delegation, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) @@ -174,7 +174,7 @@ func TestUnbondDelegation(t *testing.T) { pool = keeper.GetPool(ctx) require.Equal(t, int64(4), delegation.Shares.RoundInt64()) - require.Equal(t, int64(4), validator.PoolShares.Bonded().RoundInt64()) + require.Equal(t, int64(4), validator.BondedTokens().RoundInt64()) require.Equal(t, int64(6), pool.LooseTokens, "%v", pool) require.Equal(t, int64(4), pool.BondedTokens) } diff --git a/x/stake/keeper/inflation_test.go b/x/stake/keeper/inflation_test.go index 28efc0c59b8e..1f1a4ff1ad8f 100644 --- a/x/stake/keeper/inflation_test.go +++ b/x/stake/keeper/inflation_test.go @@ -25,32 +25,32 @@ func TestGetInflation(t *testing.T) { // inflationRateChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationRateChange tests := []struct { - name string - setBondedTokens, setLooseTokens int64 - setInflation, expectedChange sdk.Rat + name string + setBondedTokens, setLooseTokens, + setInflation, expectedChange sdk.Rat }{ // with 0% bonded atom supply the inflation should increase by InflationRateChange - {"test 1", 0, 0, sdk.NewRat(7, 100), params.InflationRateChange.Quo(hrsPerYrRat).Round(precision)}, + {"test 1", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), params.InflationRateChange.Quo(hrsPerYrRat).Round(precision)}, // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) - {"test 2", 1, 0, sdk.NewRat(20, 100), + {"test 2", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), sdk.OneRat().Sub(sdk.OneRat().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, // 50% bonded, starting at 10% inflation and being increased - {"test 3", 1, 1, sdk.NewRat(10, 100), + {"test 3", sdk.OneRat(), sdk.OneRat(), sdk.NewRat(10, 100), sdk.OneRat().Sub(sdk.NewRat(1, 2).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, // test 7% minimum stop (testing with 100% bonded) - {"test 4", 1, 0, sdk.NewRat(7, 100), sdk.ZeroRat()}, - {"test 5", 1, 0, sdk.NewRat(70001, 1000000), sdk.NewRat(-1, 1000000).Round(precision)}, + {"test 4", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), sdk.ZeroRat()}, + {"test 5", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(70001, 1000000), sdk.NewRat(-1, 1000000).Round(precision)}, // test 20% maximum stop (testing with 0% bonded) - {"test 6", 0, 0, sdk.NewRat(20, 100), sdk.ZeroRat()}, - {"test 7", 0, 0, sdk.NewRat(199999, 1000000), sdk.NewRat(1, 1000000).Round(precision)}, + {"test 6", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), sdk.ZeroRat()}, + {"test 7", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(199999, 1000000), sdk.NewRat(1, 1000000).Round(precision)}, // perfect balance shouldn't change inflation - {"test 8", 67, 33, sdk.NewRat(15, 100), sdk.ZeroRat()}, + {"test 8", sdk.NewRat(67), sdk.NewRat(33), sdk.NewRat(15, 100), sdk.ZeroRat()}, } for _, tc := range tests { pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens @@ -78,7 +78,7 @@ func TestProcessProvisions(t *testing.T) { validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} bondedValidators uint16 = 2 ) - pool.LooseTokens = initialTotalTokens + pool.LooseTokens = sdk.NewRat(initialTotalTokens) // create some validators some bonded, some unbonded _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) @@ -110,7 +110,7 @@ func TestHourlyInflationRateOfChange(t *testing.T) { validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} bondedValidators uint16 = 1 ) - pool.LooseTokens = initialTotalTokens + pool.LooseTokens = sdk.NewRat(initialTotalTokens) // create some validators some bonded, some unbonded _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) @@ -147,7 +147,7 @@ func TestLargeUnbond(t *testing.T) { validatorTokens = []int64{300000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000} bondedValidators uint16 = 7 ) - pool.LooseTokens = initialTotalTokens + pool.LooseTokens = sdk.NewRat(initialTotalTokens) _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) @@ -167,11 +167,11 @@ func TestLargeUnbond(t *testing.T) { _, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0) bondedShares = bondedShares.Sub(bondSharesVal0) - val0UnbondedTokens = pool.UnbondedShareExRate().Mul(validator.PoolShares.Unbonded()).RoundInt64() - unbondedShares = unbondedShares.Add(sdk.NewRat(val0UnbondedTokens, 1).Mul(pool.UnbondedShareExRate())) // unbonded shares should increase - require.True(t, unbondedShares.GT(sdk.NewRat(300000000, 1))) + require.Equal(t, sdk.Unbonded, validator.Status) + require.True(t, validator.Tokens.GT(sdk.NewRat(300000000, 1))) + // Ensure that new bonded ratio is less than old bonded ratio , because before they were increasing (i.e. 50% < 75) require.True(t, (pool.BondedRatio().LT(initialBondedRatio))) @@ -194,7 +194,7 @@ func TestLargeBond(t *testing.T) { validatorTokens = []int64{400000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 400000000} bondedValidators uint16 = 1 ) - pool.LooseTokens = initialTotalTokens + pool.LooseTokens = sdk.NewRat(initialTotalTokens) _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) @@ -295,13 +295,13 @@ func checkFinalPoolValues(t *testing.T, pool types.Pool, initialTotalTokens, cum // Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests func updateProvisions(t *testing.T, keeper Keeper, pool types.Pool, ctx sdk.Context, hr int) (sdk.Rat, int64, types.Pool) { expInflation := keeper.NextInflation(ctx) - expProvisions := (expInflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat)).RoundInt64() + expProvisions := (expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrRat)).RoundInt64() startTotalSupply := pool.TokenSupply() pool = keeper.ProcessProvisions(ctx) keeper.SetPool(ctx, pool) //check provisions were added to pool - require.Equal(t, startTotalSupply+expProvisions, pool.TokenSupply()) + require.Equal(t, startTotalSupply+expProvisions, pool.TokenSupply().RoundInt64()) return expInflation, expProvisions, pool } @@ -333,12 +333,9 @@ func setupTestValidators(pool types.Pool, keeper Keeper, ctx sdk.Context, valida func checkValidatorSetup(t *testing.T, pool types.Pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens int64) { require.Equal(t, initialTotalTokens, pool.TokenSupply(), "%v", pool) require.Equal(t, initialBondedTokens, pool.BondedTokens, "%v", pool) - require.Equal(t, initialUnbondedTokens, pool.UnbondedTokens, "%v", pool) // test initial bonded ratio require.True(t, pool.BondedRatio().Equal(sdk.NewRat(initialBondedTokens, initialTotalTokens)), "%v", pool.BondedRatio()) - // test the value of validator shares - require.True(t, pool.BondedShareExRate().Equal(sdk.OneRat()), "%v", pool.BondedShareExRate()) } // Checks that The inflation will correctly increase or decrease after an update to the pool diff --git a/x/stake/keeper/keeper_test.go b/x/stake/keeper/keeper_test.go index 15fecf3f2541..3f763ea25efa 100644 --- a/x/stake/keeper/keeper_test.go +++ b/x/stake/keeper/keeper_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -32,7 +33,7 @@ func TestPool(t *testing.T) { require.True(t, expPool.Equal(resPool)) //modify a params, save, and retrieve - expPool.BondedTokens = 777 + expPool.BondedTokens = sdk.NewRat(777) keeper.SetPool(ctx, expPool) resPool = keeper.GetPool(ctx) require.True(t, expPool.Equal(resPool)) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index f9cd8229a064..2693e1e5a9f2 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -18,7 +18,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { params := keeper.GetParams(ctx) pool := keeper.GetPool(ctx) numVals := 3 - pool.LooseTokens = amt * int64(numVals) + pool.LooseTokens = sdk.NewRat(amt * int64(numVals)) // add numVals validators for i := 0; i < numVals; i++ { diff --git a/x/stake/stake.go b/x/stake/stake.go index f1ac25fabab4..189473d74557 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -10,6 +10,7 @@ import ( type ( Keeper = keeper.Keeper Validator = types.Validator + BechValidator = types.BechValidator Description = types.Description Delegation = types.Delegation UnbondingDelegation = types.UnbondingDelegation diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 2e1fc1a17aa5..3712f6ae723b 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -10,15 +10,9 @@ import ( func TestPoolEqual(t *testing.T) { p1 := InitialPool() p2 := InitialPool() - - ok := p1.Equal(p2) - require.True(t, ok) - - p2.BondedTokens = 3 - p2.BondedShares = sdk.NewRat(10) - - ok = p1.Equal(p2) - require.False(t, ok) + require.True(t, p1.Equal(p2)) + p2.BondedTokens = sdk.NewRat(3) + require.False(t, p1.Equal(p2)) } func TestAddBondedTokens(t *testing.T) { @@ -26,7 +20,7 @@ func TestAddBondedTokens(t *testing.T) { pool.LooseTokens = sdk.NewRat(10) pool.BondedTokens = sdk.NewRat(10) - pool = pool.addTokensBonded(sdk.NewRat(10)) + pool = pool.addBondedTokens(sdk.NewRat(10)) require.Equal(t, sdk.NewRat(20), pool.BondedTokens) require.Equal(t, sdk.NewRat(0), pool.LooseTokens) @@ -37,7 +31,7 @@ func TestRemoveBondedTokens(t *testing.T) { pool.LooseTokens = sdk.NewRat(10) pool.BondedTokens = sdk.NewRat(10) - pool = pool.removeTokensBonded(sdk.NewRat(5)) + pool = pool.removeBondedTokens(sdk.NewRat(5)) require.Equal(t, sdk.NewRat(5), pool.BondedTokens) require.Equal(t, sdk.NewRat(15), pool.LooseTokens) diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index f978a6d6ebb1..cad00163f387 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -46,7 +46,7 @@ func TestABCIValidator(t *testing.T) { abciVal := val.ABCIValidator() require.Equal(t, tmtypes.TM2PB.PubKey(val.PubKey), abciVal.PubKey) - require.Equal(t, val.PoolShares.Bonded().RoundInt64(), abciVal.Power) + require.Equal(t, val.BondedTokens().RoundInt64(), abciVal.Power) } func TestABCIValidatorZero(t *testing.T) { @@ -57,33 +57,31 @@ func TestABCIValidatorZero(t *testing.T) { require.Equal(t, int64(0), abciVal.Power) } -func TestRemovePoolShares(t *testing.T) { +func TestRemoveTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = 10 + pool.LooseTokens = sdk.NewRat(10) val := Validator{ Owner: addr1, PubKey: pk1, - PoolShares: NewBondedShares(sdk.NewRat(100)), + Status: sdk.Bonded, + Tokens: sdk.NewRat(100), DelegatorShares: sdk.NewRat(100), } - pool.BondedTokens = val.PoolShares.Bonded().RoundInt64() - pool.BondedShares = val.PoolShares.Bonded() + pool.BondedTokens = val.BondedTokens().RoundInt64() val, pool = val.UpdateStatus(pool, sdk.Bonded) - val, pool, tk := val.RemovePoolShares(pool, sdk.NewRat(10)) - require.Equal(t, int64(90), val.PoolShares.Amount.RoundInt64()) + val, pool, tk := val.RemoveTokens(pool, sdk.NewRat(10)) + require.Equal(t, int64(90), val.Tokens.RoundInt64()) require.Equal(t, int64(90), pool.BondedTokens) - require.Equal(t, int64(90), pool.BondedShares.RoundInt64()) require.Equal(t, int64(20), pool.LooseTokens) require.Equal(t, int64(10), tk) val, pool = val.UpdateStatus(pool, sdk.Unbonded) - val, pool, tk = val.RemovePoolShares(pool, sdk.NewRat(10)) - require.Equal(t, int64(80), val.PoolShares.Amount.RoundInt64()) + val, pool, tk = val.RemoveTokens(pool, sdk.NewRat(10)) + require.Equal(t, int64(80), val.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens) - require.Equal(t, int64(0), pool.BondedShares.RoundInt64()) require.Equal(t, int64(30), pool.LooseTokens) require.Equal(t, int64(10), tk) } @@ -101,7 +99,7 @@ func TestAddTokensValidatorBonded(t *testing.T) { require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), val.PoolShares.Bonded())) + assert.True(sdk.RatEq(t, sdk.NewRat(10), val.BondedTokens())) } func TestAddTokensValidatorUnbonding(t *testing.T) { @@ -117,7 +115,8 @@ func TestAddTokensValidatorUnbonding(t *testing.T) { require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), val.PoolShares.Unbonding())) + assert.Equal(t, sdk.Unbonding, val.Status) + assert.True(sdk.RatEq(t, sdk.NewRat(10), val.Tokens)) } func TestAddTokensValidatorUnbonded(t *testing.T) { @@ -133,7 +132,8 @@ func TestAddTokensValidatorUnbonded(t *testing.T) { require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), val.PoolShares.Unbonded())) + assert.Equal(t, sdk.Unbonded, val.Status) + assert.True(sdk.RatEq(t, sdk.NewRat(10), val.Tokens)) } // TODO refactor to make simpler like the AddToken tests above @@ -143,11 +143,11 @@ func TestRemoveDelShares(t *testing.T) { valA := Validator{ Owner: addr1, PubKey: pk1, - PoolShares: NewBondedShares(sdk.NewRat(100)), + Status: sdk.Bonded, + Tokens: sdk.NewRat(100), DelegatorShares: sdk.NewRat(100), } - poolA.BondedTokens = valA.PoolShares.Bonded().RoundInt64() - poolA.BondedShares = valA.PoolShares.Bonded() + poolA.BondedTokens = valA.BondedTokens().RoundInt64() require.Equal(t, valA.DelegatorShareExRate(poolA), sdk.OneRat()) require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) @@ -156,17 +156,18 @@ func TestRemoveDelShares(t *testing.T) { // coins were created require.Equal(t, coinsB, int64(10)) // pool shares were removed - require.Equal(t, valB.PoolShares.Bonded(), valA.PoolShares.Bonded().Sub(sdk.NewRat(10).Mul(valA.DelegatorShareExRate(poolA)))) + require.Equal(t, valB.BondedTokens(), valA.BondedTokens().Sub(sdk.NewRat(10).Mul(valA.DelegatorShareExRate(poolA)))) // conservation of tokens require.Equal(t, poolB.UnbondedTokens+poolB.BondedTokens+coinsB, poolA.UnbondedTokens+poolA.BondedTokens) // specific case from random tests - poolShares := sdk.NewRat(5102) + poolTokens := sdk.NewRat(5102) delShares := sdk.NewRat(115) val := Validator{ Owner: addr1, PubKey: pk1, - PoolShares: NewBondedShares(poolShares), + Status: sdk.Bonded, + Tokens: sdk.NewRat(poolTokens), DelegatorShares: delShares, } pool := Pool{ @@ -178,8 +179,7 @@ func TestRemoveDelShares(t *testing.T) { Inflation: sdk.NewRat(7, 100), } shares := sdk.NewRat(29) - msg := fmt.Sprintf("validator %s (status: %d, poolShares: %v, delShares: %v, DelegatorShareExRate: %v)", - val.Owner, val.Status(), val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool)) + msg := fmt.Sprintf("validator %#v", val) msg = fmt.Sprintf("Removed %v shares from %s", shares, msg) _, newPool, tokens := val.RemoveDelShares(pool, shares) require.Equal(t, @@ -194,51 +194,42 @@ func TestUpdateStatus(t *testing.T) { val := NewValidator(addr1, pk1, Description{}) val, pool, _ = val.AddTokensFromDel(pool, 100) - require.Equal(t, int64(0), val.PoolShares.Bonded().RoundInt64()) - require.Equal(t, int64(0), val.PoolShares.Unbonding().RoundInt64()) - require.Equal(t, int64(100), val.PoolShares.Unbonded().RoundInt64()) + require.Equal(t, sdk.Unbonded, val.Status) + require.Equal(t, int64(100), val.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens) - require.Equal(t, int64(0), pool.UnbondingTokens) - require.Equal(t, int64(100), pool.UnbondedTokens) + require.Equal(t, int64(100), pool.LooseTokens) val, pool = val.UpdateStatus(pool, sdk.Unbonding) - require.Equal(t, int64(0), val.PoolShares.Bonded().RoundInt64()) - require.Equal(t, int64(100), val.PoolShares.Unbonding().RoundInt64()) - require.Equal(t, int64(0), val.PoolShares.Unbonded().RoundInt64()) + require.Equal(t, sdk.Unbonding, val.Status) + require.Equal(t, int64(100), val.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens) - require.Equal(t, int64(100), pool.UnbondingTokens) - require.Equal(t, int64(0), pool.UnbondedTokens) + require.Equal(t, int64(100), pool.LooseTokens) val, pool = val.UpdateStatus(pool, sdk.Bonded) - require.Equal(t, int64(100), val.PoolShares.Bonded().RoundInt64()) - require.Equal(t, int64(0), val.PoolShares.Unbonding().RoundInt64()) - require.Equal(t, int64(0), val.PoolShares.Unbonded().RoundInt64()) + require.Equal(t, sdk.Bonded, val.Status) + require.Equal(t, int64(100), val.Tokens.RoundInt64()) require.Equal(t, int64(100), pool.BondedTokens) - require.Equal(t, int64(0), pool.UnbondingTokens) - require.Equal(t, int64(0), pool.UnbondedTokens) + require.Equal(t, int64(0), pool.LooseTokens) } func TestPossibleOverflow(t *testing.T) { - poolShares := sdk.NewRat(2159) + poolTokens := sdk.NewRat(2159) delShares := sdk.NewRat(391432570689183511).Quo(sdk.NewRat(40113011844664)) val := Validator{ Owner: addr1, PubKey: pk1, - PoolShares: NewBondedShares(poolShares), + Status: sdk.Bonded, + Tokens: poolTokens, DelegatorShares: delShares, } pool := Pool{ LooseTokens: 100, - BondedShares: poolShares, - UnbondedShares: sdk.ZeroRat(), - BondedTokens: poolShares.RoundInt64(), - UnbondedTokens: 0, + BondedTokens: poolTokens.RoundInt64(), InflationLastTime: 0, Inflation: sdk.NewRat(7, 100), } tokens := int64(71) - msg := fmt.Sprintf("validator %s (status: %d, poolShares: %v, delShares: %v, DelegatorShareExRate: %v)", - val.Owner, val.Status(), val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool)) + msg := fmt.Sprintf("validator %#v", val) newValidator, _, _ := val.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) From cc754a8bd780a292993d2fbd45c49ad0760d9f1d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 12 Jul 2018 01:34:16 -0400 Subject: [PATCH 07/25] resolve compilation error --- x/stake/handler_test.go | 2 +- x/stake/keeper/inflation_test.go | 85 ++++++++++-------------- x/stake/keeper/slash_test.go | 38 +++++------ x/stake/keeper/validator_test.go | 109 ++++++++++++++++--------------- x/stake/types/validator_test.go | 80 ++++++++++------------- 5 files changed, 147 insertions(+), 167 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 98f4f25832f4..8c61823ee792 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -189,7 +189,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { pool := keeper.GetPool(ctx) exRate := validator.DelegatorShareExRate(pool) require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) - require.Equal(t, bondAmount, pool.BondedTokens()) + require.Equal(t, bondAmount, pool.BondedTokens) // just send the same msgbond multiple times msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) diff --git a/x/stake/keeper/inflation_test.go b/x/stake/keeper/inflation_test.go index 1f1a4ff1ad8f..e1dfb60ed611 100644 --- a/x/stake/keeper/inflation_test.go +++ b/x/stake/keeper/inflation_test.go @@ -71,29 +71,28 @@ func TestProcessProvisions(t *testing.T) { pool := keeper.GetPool(ctx) var ( - initialTotalTokens int64 = 550000000 - initialBondedTokens int64 = 250000000 - initialUnbondedTokens int64 = 300000000 - cumulativeExpProvs int64 - validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} - bondedValidators uint16 = 2 + initialTotalTokens int64 = 550000000 + initialBondedTokens int64 = 250000000 + cumulativeExpProvs = sdk.ZeroRat() + validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} + bondedValidators uint16 = 2 ) pool.LooseTokens = sdk.NewRat(initialTotalTokens) // create some validators some bonded, some unbonded _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) - checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) + checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens) // process the provisions for a year for hr := 0; hr < 8766; hr++ { pool := keeper.GetPool(ctx) _, expProvisions, _ := updateProvisions(t, keeper, pool, ctx, hr) - cumulativeExpProvs = cumulativeExpProvs + expProvisions + cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions) } //get the pool and do the final value checks from checkFinalPoolValues pool = keeper.GetPool(ctx) - checkFinalPoolValues(t, pool, initialTotalTokens, cumulativeExpProvs) + checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), cumulativeExpProvs) } // Tests that the hourly rate of change of inflation will be positive, negative, or zero, depending on bonded ratio and inflation rate @@ -103,32 +102,31 @@ func TestHourlyInflationRateOfChange(t *testing.T) { pool := keeper.GetPool(ctx) var ( - initialTotalTokens int64 = 550000000 - initialBondedTokens int64 = 150000000 - initialUnbondedTokens int64 = 400000000 - cumulativeExpProvs int64 - validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} - bondedValidators uint16 = 1 + initialTotalTokens int64 = 550000000 + initialBondedTokens int64 = 150000000 + cumulativeExpProvs = sdk.ZeroRat() + validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} + bondedValidators uint16 = 1 ) pool.LooseTokens = sdk.NewRat(initialTotalTokens) // create some validators some bonded, some unbonded _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) - checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) + checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens) // ~11.4 years to go from 7%, up to 20%, back down to 7% for hr := 0; hr < 100000; hr++ { pool := keeper.GetPool(ctx) previousInflation := pool.Inflation updatedInflation, expProvisions, pool := updateProvisions(t, keeper, pool, ctx, hr) - cumulativeExpProvs = cumulativeExpProvs + expProvisions + cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions) msg := strconv.Itoa(hr) checkInflation(t, pool, previousInflation, updatedInflation, msg) } // Final check that the pool equals initial values + cumulative provisions and adjustments we recorded pool = keeper.GetPool(ctx) - checkFinalPoolValues(t, pool, initialTotalTokens, cumulativeExpProvs) + checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), cumulativeExpProvs) } //Test that a large unbonding will significantly lower the bonded ratio @@ -137,20 +135,15 @@ func TestLargeUnbond(t *testing.T) { pool := keeper.GetPool(ctx) var ( - initialTotalTokens int64 = 1200000000 - initialBondedTokens int64 = 900000000 - initialUnbondedTokens int64 = 300000000 - val0UnbondedTokens int64 - bondedShares = sdk.NewRat(900000000, 1) - unbondedShares = sdk.NewRat(300000000, 1) - bondSharesVal0 = sdk.NewRat(300000000, 1) - validatorTokens = []int64{300000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000} - bondedValidators uint16 = 7 + initialTotalTokens int64 = 1200000000 + initialBondedTokens int64 = 900000000 + validatorTokens = []int64{300000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000} + bondedValidators uint16 = 7 ) pool.LooseTokens = sdk.NewRat(initialTotalTokens) _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) - checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) + checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens) pool = keeper.GetPool(ctx) validator, found := keeper.GetValidator(ctx, Addrs[0]) @@ -166,8 +159,6 @@ func TestLargeUnbond(t *testing.T) { // process provisions after the bonding, to compare the difference in expProvisions and expInflation _, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0) - bondedShares = bondedShares.Sub(bondSharesVal0) - // unbonded shares should increase require.Equal(t, sdk.Unbonded, validator.Status) require.True(t, validator.Tokens.GT(sdk.NewRat(300000000, 1))) @@ -177,7 +168,7 @@ func TestLargeUnbond(t *testing.T) { // Final check that the pool equals initial values + provisions and adjustments we recorded pool = keeper.GetPool(ctx) - checkFinalPoolValues(t, pool, initialTotalTokens, expProvisionsAfter) + checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), expProvisionsAfter) } //Test that a large bonding will significantly increase the bonded ratio @@ -186,18 +177,15 @@ func TestLargeBond(t *testing.T) { pool := keeper.GetPool(ctx) var ( - initialTotalTokens int64 = 1600000000 - initialBondedTokens int64 = 400000000 - initialUnbondedTokens int64 = 1200000000 - unbondedShares = sdk.NewRat(1200000000, 1) - unbondedSharesVal9 = sdk.NewRat(400000000, 1) - validatorTokens = []int64{400000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 400000000} - bondedValidators uint16 = 1 + initialTotalTokens int64 = 1600000000 + initialBondedTokens int64 = 400000000 + validatorTokens = []int64{400000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 400000000} + bondedValidators uint16 = 1 ) pool.LooseTokens = sdk.NewRat(initialTotalTokens) _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) - checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) + checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens) pool = keeper.GetPool(ctx) validator, found := keeper.GetValidator(ctx, Addrs[9]) @@ -216,16 +204,13 @@ func TestLargeBond(t *testing.T) { // process provisions after the bonding, to compare the difference in expProvisions and expInflation _, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0) - unbondedShares = unbondedShares.Sub(unbondedSharesVal9) - // unbonded shares should decrease - require.True(t, unbondedShares.LT(sdk.NewRat(1200000000, 1))) // Ensure that new bonded ratio is greater than old bonded ratio (i.e. 50% > 25%) require.True(t, (pool.BondedRatio().GT(initialBondedRatio))) // Final check that the pool equals initial values + provisions and adjustments we recorded pool = keeper.GetPool(ctx) - checkFinalPoolValues(t, pool, initialTotalTokens, expProvisionsAfter) + checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), expProvisionsAfter) } // Tests that inflation increases or decreases as expected when we do a random operation on 20 different validators @@ -286,22 +271,22 @@ func TestInflationWithRandomOperations(t *testing.T) { ////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// // Final check on the global pool values for what the total tokens accumulated from each hour of provisions -func checkFinalPoolValues(t *testing.T, pool types.Pool, initialTotalTokens, cumulativeExpProvs int64) { - calculatedTotalTokens := initialTotalTokens + cumulativeExpProvs - require.Equal(t, calculatedTotalTokens, pool.TokenSupply()) +func checkFinalPoolValues(t *testing.T, pool types.Pool, initialTotalTokens, cumulativeExpProvs sdk.Rat) { + calculatedTotalTokens := initialTotalTokens.Add(cumulativeExpProvs) + require.Equal(sdk.RatEq(t, calculatedTotalTokens, pool.TokenSupply())) } // Processes provisions are added to the pool correctly every hour // Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests -func updateProvisions(t *testing.T, keeper Keeper, pool types.Pool, ctx sdk.Context, hr int) (sdk.Rat, int64, types.Pool) { +func updateProvisions(t *testing.T, keeper Keeper, pool types.Pool, ctx sdk.Context, hr int) (sdk.Rat, sdk.Rat, types.Pool) { expInflation := keeper.NextInflation(ctx) - expProvisions := (expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrRat)).RoundInt64() + expProvisions := expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrRat) startTotalSupply := pool.TokenSupply() pool = keeper.ProcessProvisions(ctx) keeper.SetPool(ctx, pool) //check provisions were added to pool - require.Equal(t, startTotalSupply+expProvisions, pool.TokenSupply().RoundInt64()) + require.Equal(t, startTotalSupply.Add(expProvisions), pool.TokenSupply().RoundInt64()) return expInflation, expProvisions, pool } @@ -330,7 +315,7 @@ func setupTestValidators(pool types.Pool, keeper Keeper, ctx sdk.Context, valida } // Checks that the deterministic validator setup you wanted matches the values in the pool -func checkValidatorSetup(t *testing.T, pool types.Pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens int64) { +func checkValidatorSetup(t *testing.T, pool types.Pool, initialTotalTokens, initialBondedTokens int64) { require.Equal(t, initialTotalTokens, pool.TokenSupply(), "%v", pool) require.Equal(t, initialBondedTokens, pool.BondedTokens, "%v", pool) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 2693e1e5a9f2..d5a0e7f549a3 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -77,20 +77,20 @@ func TestSlashUnbondingDelegation(t *testing.T) { // unbonding started prior to the infraction height, stake didn't contribute slashAmount := keeper.slashUnbondingDelegation(ctx, ubd, 1, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) + require.Equal(t, int64(0), slashAmount.RoundInt64()) // after the expiration time, no longer eligible for slashing ctx = ctx.WithBlockHeader(abci.Header{Time: int64(10)}) keeper.SetUnbondingDelegation(ctx, ubd) slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) + require.Equal(t, int64(0), slashAmount.RoundInt64()) // test valid slash, before expiration timestamp and to which stake contributed oldPool := keeper.GetPool(ctx) ctx = ctx.WithBlockHeader(abci.Header{Time: int64(0)}) keeper.SetUnbondingDelegation(ctx, ubd) slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) - require.Equal(t, int64(5), slashAmount.Int64()) + require.Equal(t, int64(5), slashAmount.RoundInt64()) ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) // initialbalance unchanged @@ -98,7 +98,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // balance decreased require.Equal(t, sdk.NewCoin(params.BondDenom, 5), ubd.Balance) newPool := keeper.GetPool(ctx) - require.Equal(t, int64(5), oldPool.LooseTokens-newPool.LooseTokens) + require.Equal(t, int64(5), oldPool.LooseTokens.Sub(newPool.LooseTokens).RoundInt64()) } // tests slashRedelegation @@ -133,7 +133,7 @@ func TestSlashRedelegation(t *testing.T) { validator, found := keeper.GetValidator(ctx, addrVals[1]) require.True(t, found) slashAmount := keeper.slashRedelegation(ctx, validator, rd, 1, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) + require.Equal(t, int64(0), slashAmount.RoundInt64()) // after the expiration time, no longer eligible for slashing ctx = ctx.WithBlockHeader(abci.Header{Time: int64(10)}) @@ -141,7 +141,7 @@ func TestSlashRedelegation(t *testing.T) { validator, found = keeper.GetValidator(ctx, addrVals[1]) require.True(t, found) slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) + require.Equal(t, int64(0), slashAmount.RoundInt64()) // test valid slash, before expiration timestamp and to which stake contributed oldPool := keeper.GetPool(ctx) @@ -150,7 +150,7 @@ func TestSlashRedelegation(t *testing.T) { validator, found = keeper.GetValidator(ctx, addrVals[1]) require.True(t, found) slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) - require.Equal(t, int64(5), slashAmount.Int64()) + require.Equal(t, int64(5), slashAmount.RoundInt64()) rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) // initialbalance unchanged @@ -163,7 +163,7 @@ func TestSlashRedelegation(t *testing.T) { require.Equal(t, int64(5), del.Shares.RoundInt64()) // pool bonded tokens decreased newPool := keeper.GetPool(ctx) - require.Equal(t, int64(5), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(5), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) } // tests Slash at a future height (must panic) @@ -193,7 +193,7 @@ func TestSlashAtCurrentHeight(t *testing.T) { // power decreased require.Equal(t, sdk.NewRat(5), validator.GetPower()) // pool bonded shares decreased - require.Equal(t, sdk.NewRat(5).RoundInt64(), oldPool.BondedShares.Sub(newPool.BondedShares).RoundInt64()) + require.Equal(t, sdk.NewRat(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) } // tests Slash at a previous height with an unbonding delegation @@ -229,7 +229,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // read updated pool newPool := keeper.GetPool(ctx) // bonded tokens burned - require.Equal(t, int64(3), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(3), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) @@ -249,7 +249,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // read updated pool newPool = keeper.GetPool(ctx) // bonded tokens burned again - require.Equal(t, int64(6), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(6), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) @@ -269,7 +269,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // read updated pool newPool = keeper.GetPool(ctx) // bonded tokens burned again - require.Equal(t, int64(9), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(9), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) @@ -289,7 +289,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // read updated pool newPool = keeper.GetPool(ctx) // just 1 bonded token burned again since that's all the validator now has - require.Equal(t, int64(10), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(10), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator // power decreased by 1 again, validator is out of stake // ergo validator should have been removed from the store @@ -340,7 +340,7 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool newPool := keeper.GetPool(ctx) // bonded tokens burned - require.Equal(t, int64(5), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(5), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) @@ -364,7 +364,7 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool newPool = keeper.GetPool(ctx) // 7 bonded tokens burned - require.Equal(t, int64(12), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(12), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) @@ -385,7 +385,7 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool newPool = keeper.GetPool(ctx) // four more bonded tokens burned - require.Equal(t, int64(16), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator // validator decreased to zero power, should have been removed from the store _, found = keeper.GetValidatorByPubKey(ctx, pk) @@ -407,7 +407,7 @@ func TestSlashWithRedelegation(t *testing.T) { // read updated pool newPool = keeper.GetPool(ctx) // no more bonded tokens burned - require.Equal(t, int64(16), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator // power still zero, still not in the store _, found = keeper.GetValidatorByPubKey(ctx, pk) @@ -469,9 +469,9 @@ func TestSlashBoth(t *testing.T) { // read updated pool newPool := keeper.GetPool(ctx) // loose tokens burned - require.Equal(t, int64(2), oldPool.LooseTokens-newPool.LooseTokens) + require.Equal(t, int64(2), oldPool.LooseTokens.Sub(newPool.LooseTokens).RoundInt64()) // bonded tokens burned - require.Equal(t, int64(3), oldPool.BondedTokens-newPool.BondedTokens) + require.Equal(t, int64(3), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0]) require.True(t, found) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 4e962420a5c2..a42e4ef23475 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -18,8 +18,8 @@ func TestSetValidator(t *testing.T) { // test how the validator is set from a purely unbonbed pool validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.Unbonded, validator.Status()) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Unbonded())) + require.Equal(t, sdk.Unbonded, validator.Status) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) @@ -27,8 +27,8 @@ func TestSetValidator(t *testing.T) { // 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.PoolShares.Bonded())) + require.Equal(t, sdk.Bonded, validator.Status) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) // Check each store for being saved @@ -55,25 +55,20 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool := keeper.GetPool(ctx) // create a random pool - pool.LooseTokens = 10000 - pool.BondedTokens = 1234 - pool.BondedShares = sdk.NewRat(124) - pool.UnbondingTokens = 13934 - pool.UnbondingShares = sdk.NewRat(145) - pool.UnbondedTokens = 154 - pool.UnbondedShares = sdk.NewRat(1333) + pool.LooseTokens = sdk.NewRat(10000) + pool.BondedTokens = sdk.NewRat(1234) keeper.SetPool(ctx, pool) // add a validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, delSharesCreated := validator.AddTokensFromDel(pool, 100) - require.Equal(t, sdk.Unbonded, validator.Status()) - require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).RoundInt64()) + require.Equal(t, sdk.Unbonded, validator.Status) + require.Equal(t, int64(100), validator.Tokens.RoundInt64()) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).RoundInt64(), "\nvalidator %v\npool %v", validator, pool) + require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) pool = keeper.GetPool(ctx) power := GetValidatorsByPowerIndexKey(validator, pool) @@ -101,12 +96,12 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { // add a validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 100) - require.Equal(t, sdk.Unbonded, validator.Status()) - require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).RoundInt64()) + require.Equal(t, sdk.Unbonded, validator.Status) + require.Equal(t, int64(100), validator.Tokens.RoundInt64()) keeper.SetPool(ctx, pool) keeper.SetValidatorByPubKeyIndex(ctx, validator) validator = keeper.UpdateValidator(ctx, validator) - require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).RoundInt64(), "\nvalidator %v\npool %v", validator, pool) + require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) // slash the validator by 100% keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneRat()) @@ -125,7 +120,8 @@ func TestValidatorBasics(t *testing.T) { amts := []int64{9, 8, 7} for i, amt := range amts { validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) - validators[i].PoolShares = types.NewUnbondedShares(sdk.ZeroRat()) + validators[i].Status = sdk.Unbonded + validators[i].Tokens = sdk.ZeroRat() validators[i].AddTokensFromDel(pool, amt) } @@ -146,7 +142,8 @@ func TestValidatorBasics(t *testing.T) { assert.True(ValEq(t, validators[0], resVals[0])) // modify a records, save, and retrieve - validators[0].PoolShares = types.NewBondedShares(sdk.NewRat(10)) + validators[0].Status = sdk.Bonded + validators[0].Tokens = sdk.NewRat(10) validators[0].DelegatorShares = sdk.NewRat(10) validators[0] = keeper.UpdateValidator(ctx, validators[0]) resVal, found = keeper.GetValidator(ctx, addrVals[0]) @@ -189,7 +186,8 @@ func GetValidatorSortingUnmixed(t *testing.T) { var validators [5]types.Validator for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) - validators[i].PoolShares = types.NewBondedShares(sdk.NewRat(amt)) + validators[i].Status = sdk.Bonded + validators[i].Tokens = sdk.NewRat(amt) validators[i].DelegatorShares = sdk.NewRat(amt) keeper.UpdateValidator(ctx, validators[i]) } @@ -197,11 +195,11 @@ func GetValidatorSortingUnmixed(t *testing.T) { // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewRat(400), resValidators[0].PoolShares.Bonded(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(200), resValidators[1].PoolShares.Bonded(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(100), resValidators[2].PoolShares.Bonded(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(1), resValidators[3].PoolShares.Bonded(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(0), resValidators[4].PoolShares.Bonded(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -209,14 +207,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.Equal(t, validators[0].Owner, resValidators[4].Owner, "%v", resValidators) // test a basic increase in voting power - validators[3].PoolShares = types.NewBondedShares(sdk.NewRat(500)) + validators[3].Tokens = sdk.NewRat(500) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power - validators[3].PoolShares = types.NewBondedShares(sdk.NewRat(300)) + validators[3].Tokens = sdk.NewRat(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -224,7 +222,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // test equal voting power, different age - validators[3].PoolShares = types.NewBondedShares(sdk.NewRat(200)) + validators[3].Tokens = sdk.NewRat(200) ctx = ctx.WithBlockHeight(10) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -243,8 +241,8 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // change in voting power of both validators, both still in v-set, no age change - validators[3].PoolShares = types.NewBondedShares(sdk.NewRat(300)) - validators[4].PoolShares = types.NewBondedShares(sdk.NewRat(300)) + validators[3].Tokens = sdk.NewRat(300) + validators[4].Tokens = sdk.NewRat(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -273,11 +271,19 @@ func GetValidatorSortingMixed(t *testing.T) { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) validators[i].DelegatorShares = sdk.NewRat(amt) } - validators[0].PoolShares = types.NewUnbondedShares(sdk.NewRat(amts[0])) - validators[1].PoolShares = types.NewUnbondedShares(sdk.NewRat(amts[1])) - validators[2].PoolShares = types.NewUnbondedShares(sdk.NewRat(amts[2])) - validators[3].PoolShares = types.NewBondedShares(sdk.NewRat(amts[3])) - validators[4].PoolShares = types.NewBondedShares(sdk.NewRat(amts[4])) + + validators[0].Status = sdk.Bonded + validators[1].Status = sdk.Bonded + validators[2].Status = sdk.Bonded + validators[0].Tokens = sdk.NewRat(amts[0]) + validators[1].Tokens = sdk.NewRat(amts[1]) + validators[2].Tokens = sdk.NewRat(amts[2]) + + validators[3].Status = sdk.Bonded + validators[4].Status = sdk.Bonded + validators[3].Tokens = sdk.NewRat(amts[3]) + validators[4].Tokens = sdk.NewRat(amts[4]) + for i := range amts { keeper.UpdateValidator(ctx, validators[i]) } @@ -291,20 +297,20 @@ func GetValidatorSortingMixed(t *testing.T) { require.True(t, found) val4, found := keeper.GetValidator(ctx, Addrs[4]) require.True(t, found) - require.Equal(t, sdk.Unbonded, val0.Status()) - require.Equal(t, sdk.Unbonded, val1.Status()) - require.Equal(t, sdk.Unbonded, val2.Status()) - require.Equal(t, sdk.Bonded, val3.Status()) - require.Equal(t, sdk.Bonded, val4.Status()) + require.Equal(t, sdk.Unbonded, val0.Status) + require.Equal(t, sdk.Unbonded, val1.Status) + require.Equal(t, sdk.Unbonded, val2.Status) + require.Equal(t, sdk.Bonded, val3.Status) + require.Equal(t, sdk.Bonded, val4.Status) // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewRat(400), resValidators[0].PoolShares.Bonded(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(200), resValidators[1].PoolShares.Bonded(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(100), resValidators[2].PoolShares.Bonded(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(1), resValidators[3].PoolShares.Bonded(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(0), resValidators[4].PoolShares.Bonded(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -454,11 +460,11 @@ func TestFullValidatorSetPowerChange(t *testing.T) { validators[i], found = keeper.GetValidator(ctx, validators[i].Owner) require.True(t, found) } - assert.Equal(t, sdk.Unbonded, validators[0].Status()) - assert.Equal(t, sdk.Unbonded, validators[1].Status()) - assert.Equal(t, sdk.Bonded, validators[2].Status()) - assert.Equal(t, sdk.Bonded, validators[3].Status()) - assert.Equal(t, sdk.Unbonded, validators[4].Status()) + assert.Equal(t, sdk.Unbonded, validators[0].Status) + assert.Equal(t, sdk.Unbonded, validators[1].Status) + assert.Equal(t, sdk.Bonded, validators[2].Status) + assert.Equal(t, sdk.Bonded, validators[3].Status) + assert.Equal(t, sdk.Unbonded, validators[4].Status) resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, max, len(resValidators)) assert.True(ValEq(t, validators[2], resValidators[0])) // in the order of txs @@ -576,7 +582,8 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { // test single value change // tendermintUpdate set: {} -> {c1'} - validators[0].PoolShares = types.NewBondedShares(sdk.NewRat(600)) + validators[0].Status = sdk.Bonded + validators[0].Tokens = sdk.NewRat(600) validators[0] = keeper.UpdateValidator(ctx, validators[0]) updates := keeper.GetTendermintUpdates(ctx) diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index cad00163f387..62a93fd35b84 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -69,34 +69,29 @@ func TestRemoveTokens(t *testing.T) { DelegatorShares: sdk.NewRat(100), } - pool.BondedTokens = val.BondedTokens().RoundInt64() + pool.BondedTokens = val.BondedTokens() val, pool = val.UpdateStatus(pool, sdk.Bonded) - val, pool, tk := val.RemoveTokens(pool, sdk.NewRat(10)) + val, pool = val.RemoveTokens(pool, sdk.NewRat(10)) require.Equal(t, int64(90), val.Tokens.RoundInt64()) - require.Equal(t, int64(90), pool.BondedTokens) - require.Equal(t, int64(20), pool.LooseTokens) - require.Equal(t, int64(10), tk) + require.Equal(t, int64(90), pool.BondedTokens.RoundInt64()) + require.Equal(t, int64(20), pool.LooseTokens.RoundInt64()) val, pool = val.UpdateStatus(pool, sdk.Unbonded) - val, pool, tk = val.RemoveTokens(pool, sdk.NewRat(10)) + val, pool = val.RemoveTokens(pool, sdk.NewRat(10)) require.Equal(t, int64(80), val.Tokens.RoundInt64()) - require.Equal(t, int64(0), pool.BondedTokens) - require.Equal(t, int64(30), pool.LooseTokens) - require.Equal(t, int64(10), tk) + require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) + require.Equal(t, int64(30), pool.LooseTokens.RoundInt64()) } func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = 10 + pool.LooseTokens = sdk.NewRat(10) val := NewValidator(addr1, pk1, Description{}) val, pool = val.UpdateStatus(pool, sdk.Bonded) val, pool, delShares := val.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) - require.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) - require.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) - require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.True(sdk.RatEq(t, sdk.NewRat(10), val.BondedTokens())) @@ -104,15 +99,12 @@ func TestAddTokensValidatorBonded(t *testing.T) { func TestAddTokensValidatorUnbonding(t *testing.T) { pool := InitialPool() - pool.LooseTokens = 10 + pool.LooseTokens = sdk.NewRat(10) val := NewValidator(addr1, pk1, Description{}) val, pool = val.UpdateStatus(pool, sdk.Unbonding) val, pool, delShares := val.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) - require.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) - require.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) - require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.Equal(t, sdk.Unbonding, val.Status) @@ -121,15 +113,12 @@ func TestAddTokensValidatorUnbonding(t *testing.T) { func TestAddTokensValidatorUnbonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = 10 + pool.LooseTokens = sdk.NewRat(10) val := NewValidator(addr1, pk1, Description{}) val, pool = val.UpdateStatus(pool, sdk.Unbonded) val, pool, delShares := val.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) - require.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) - require.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) - require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.Equal(t, sdk.Unbonded, val.Status) @@ -139,7 +128,7 @@ func TestAddTokensValidatorUnbonded(t *testing.T) { // TODO refactor to make simpler like the AddToken tests above func TestRemoveDelShares(t *testing.T) { poolA := InitialPool() - poolA.LooseTokens = 10 + poolA.LooseTokens = sdk.NewRat(10) valA := Validator{ Owner: addr1, PubKey: pk1, @@ -147,18 +136,20 @@ func TestRemoveDelShares(t *testing.T) { Tokens: sdk.NewRat(100), DelegatorShares: sdk.NewRat(100), } - poolA.BondedTokens = valA.BondedTokens().RoundInt64() + poolA.BondedTokens = valA.BondedTokens() require.Equal(t, valA.DelegatorShareExRate(poolA), sdk.OneRat()) - require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) - require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewRat(10)) // coins were created require.Equal(t, coinsB, int64(10)) + // pool shares were removed require.Equal(t, valB.BondedTokens(), valA.BondedTokens().Sub(sdk.NewRat(10).Mul(valA.DelegatorShareExRate(poolA)))) + // conservation of tokens - require.Equal(t, poolB.UnbondedTokens+poolB.BondedTokens+coinsB, poolA.UnbondedTokens+poolA.BondedTokens) + require.True(sdk.RatEq(t, + poolB.LooseTokens.Add(poolB.BondedTokens).Add(coinsB), + poolA.LooseTokens.Add(poolA.BondedTokens))) // specific case from random tests poolTokens := sdk.NewRat(5102) @@ -167,14 +158,12 @@ func TestRemoveDelShares(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewRat(poolTokens), + Tokens: poolTokens, DelegatorShares: delShares, } pool := Pool{ - BondedShares: sdk.NewRat(248305), - UnbondedShares: sdk.NewRat(232147), - BondedTokens: 248305, - UnbondedTokens: 232147, + BondedTokens: sdk.NewRat(248305), + LooseTokens: sdk.NewRat(232147), InflationLastTime: 0, Inflation: sdk.NewRat(7, 100), } @@ -182,34 +171,33 @@ func TestRemoveDelShares(t *testing.T) { msg := fmt.Sprintf("validator %#v", val) msg = fmt.Sprintf("Removed %v shares from %s", shares, msg) _, newPool, tokens := val.RemoveDelShares(pool, shares) - require.Equal(t, - tokens+newPool.UnbondedTokens+newPool.BondedTokens, - pool.BondedTokens+pool.UnbondedTokens, - "Tokens were not conserved: %s", msg) + require.True(sdk.RatEq(t, + tokens.Add(newPool.LooseTokens).Add(newPool.BondedTokens), + pool.LooseTokens.Add(pool.BondedTokens))) } func TestUpdateStatus(t *testing.T) { pool := InitialPool() - pool.LooseTokens = 100 + pool.LooseTokens = sdk.NewRat(100) val := NewValidator(addr1, pk1, Description{}) val, pool, _ = val.AddTokensFromDel(pool, 100) require.Equal(t, sdk.Unbonded, val.Status) require.Equal(t, int64(100), val.Tokens.RoundInt64()) - require.Equal(t, int64(0), pool.BondedTokens) - require.Equal(t, int64(100), pool.LooseTokens) + require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) + require.Equal(t, int64(100), pool.LooseTokens.RoundInt64()) val, pool = val.UpdateStatus(pool, sdk.Unbonding) require.Equal(t, sdk.Unbonding, val.Status) require.Equal(t, int64(100), val.Tokens.RoundInt64()) - require.Equal(t, int64(0), pool.BondedTokens) - require.Equal(t, int64(100), pool.LooseTokens) + require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) + require.Equal(t, int64(100), pool.LooseTokens.RoundInt64()) val, pool = val.UpdateStatus(pool, sdk.Bonded) require.Equal(t, sdk.Bonded, val.Status) require.Equal(t, int64(100), val.Tokens.RoundInt64()) - require.Equal(t, int64(100), pool.BondedTokens) - require.Equal(t, int64(0), pool.LooseTokens) + require.Equal(t, int64(100), pool.BondedTokens.RoundInt64()) + require.Equal(t, int64(0), pool.LooseTokens.RoundInt64()) } func TestPossibleOverflow(t *testing.T) { @@ -223,8 +211,8 @@ func TestPossibleOverflow(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - LooseTokens: 100, - BondedTokens: poolTokens.RoundInt64(), + LooseTokens: sdk.NewRat(100), + BondedTokens: poolTokens, InflationLastTime: 0, Inflation: sdk.NewRat(7, 100), } @@ -249,7 +237,7 @@ func TestSingleValidatorIntegrationInvariants(t *testing.T) { // sanity check AssertInvariants(t, "no operation", poolOrig, validatorsOrig, - poolOrig, validatorsOrig, 0) + poolOrig, validatorsOrig, sdk.ZeroRat()) for j := 0; j < 5; j++ { poolMod, validatorMod, tokens, msg := RandomOperation(r)(r, poolOrig, validatorsOrig[0]) @@ -279,7 +267,7 @@ func TestMultiValidatorIntegrationInvariants(t *testing.T) { AssertInvariants(t, "no operation", poolOrig, validatorsOrig, - poolOrig, validatorsOrig, 0) + poolOrig, validatorsOrig, sdk.ZeroRat()) for j := 0; j < 5; j++ { index := int(r.Int31n(int32(len(validatorsOrig)))) From 68946e6bc45146184613871a1c60981737446437 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 12 Jul 2018 13:14:49 -0400 Subject: [PATCH 08/25] resolved types errors --- x/stake/keeper/slash.go | 2 +- x/stake/types/pool_test.go | 8 +- x/stake/types/test_utils.go | 23 +++-- x/stake/types/validator.go | 1 + x/stake/types/validator_test.go | 148 +++++++++++++++++--------------- 5 files changed, 96 insertions(+), 86 deletions(-) diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 7d434019aa0a..27110ba10c01 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -108,7 +108,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // Log that a slash occurred! logger.Info(fmt.Sprintf( - "Validator %s slashed by slashFactor %v, burned %d tokens", + "Validator %s slashed by slashFactor %v, burned %v tokens", pubkey.Address(), slashFactor, burned)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 3712f6ae723b..0dc00be2e607 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -22,8 +22,8 @@ func TestAddBondedTokens(t *testing.T) { pool = pool.addBondedTokens(sdk.NewRat(10)) - require.Equal(t, sdk.NewRat(20), pool.BondedTokens) - require.Equal(t, sdk.NewRat(0), pool.LooseTokens) + require.True(sdk.RatEq(t, sdk.NewRat(20), pool.BondedTokens)) + require.True(sdk.RatEq(t, sdk.NewRat(0), pool.LooseTokens)) } func TestRemoveBondedTokens(t *testing.T) { @@ -33,6 +33,6 @@ func TestRemoveBondedTokens(t *testing.T) { pool = pool.removeBondedTokens(sdk.NewRat(5)) - require.Equal(t, sdk.NewRat(5), pool.BondedTokens) - require.Equal(t, sdk.NewRat(15), pool.LooseTokens) + require.True(sdk.RatEq(t, sdk.NewRat(5), pool.BondedTokens)) + require.True(sdk.RatEq(t, sdk.NewRat(15), pool.LooseTokens)) } diff --git a/x/stake/types/test_utils.go b/x/stake/types/test_utils.go index 92f0482d58fa..635fd7be2951 100644 --- a/x/stake/types/test_utils.go +++ b/x/stake/types/test_utils.go @@ -97,27 +97,26 @@ func RandomOperation(r *rand.Rand) Operation { // AssertInvariants ensures invariants that should always be true are true. // nolint: unparam func AssertInvariants(t *testing.T, msg string, - pOrig Pool, cOrig []Validator, pMod Pool, vMods []Validator, tokens sdk.Rat) { + pOrig Pool, cOrig []Validator, pMod Pool, vMods []Validator) { // total tokens conserved - require.Equal(t, - pOrig.LooseTokens.Add(pOrig.BondedTokens), - pMod.LooseTokens.Add(pMod.BondedTokens).Add(tokens), - "Tokens not conserved - msg: %v\n, pOrig.BondedTokens: %v, pOrig.LooseTokens: %v, pMod.BondedTokens: %v, pMod.LooseTokens: %v, tokens: %v\n", + require.True(t, + pOrig.LooseTokens.Add(pOrig.BondedTokens).Equal( + pMod.LooseTokens.Add(pMod.BondedTokens)), + "Tokens not conserved - msg: %v\n, pOrig.BondedTokens: %v, pOrig.LooseTokens: %v, pMod.BondedTokens: %v, pMod.LooseTokens: %v", msg, pOrig.BondedTokens, pOrig.LooseTokens, - pMod.BondedTokens, pMod.LooseTokens, - tokens) + pMod.BondedTokens, pMod.LooseTokens) // Nonnegative bonded tokens require.False(t, pMod.BondedTokens.LT(sdk.ZeroRat()), - "Negative bonded shares - msg: %v\npOrig: %v\npMod: %v\ntokens: %v\n", - msg, pOrig, pMod, tokens) + "Negative bonded shares - msg: %v\npOrig: %v\npMod: %v\n", + msg, pOrig, pMod) // Nonnegative loose tokens require.False(t, pMod.LooseTokens.LT(sdk.ZeroRat()), - "Negative unbonded shares - msg: %v\npOrig: %v\npMod: %v\ntokens: %v\n", - msg, pOrig, pMod, tokens) + "Negative unbonded shares - msg: %v\npOrig: %v\npMod: %v\n", + msg, pOrig, pMod) for _, vMod := range vMods { // Nonnegative ex rate @@ -180,7 +179,7 @@ func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) { case sdk.Bonded: pool.BondedTokens = pool.BondedTokens.Add(validator.Tokens) case sdk.Unbonded, sdk.Unbonding: - pool.LooseTokens = pool.BondedTokens.Add(validator.Tokens) + pool.LooseTokens = pool.LooseTokens.Add(validator.Tokens) default: panic("improper use of RandomSetup") } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index dafd6a5c9cf7..1c5728e7af70 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -368,6 +368,7 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s // validator status. func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, sdk.Rat) { issuedTokens := v.DelegatorShareExRate(pool).Mul(delShares) + v.Tokens = v.Tokens.Sub(issuedTokens) v.DelegatorShares = v.DelegatorShares.Sub(delShares) if v.Status == sdk.Bonded { diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 62a93fd35b84..fd7926124226 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -42,26 +42,24 @@ func TestUpdateDescription(t *testing.T) { } func TestABCIValidator(t *testing.T) { - val := NewValidator(addr1, pk1, Description{}) + validator := NewValidator(addr1, pk1, Description{}) - abciVal := val.ABCIValidator() - require.Equal(t, tmtypes.TM2PB.PubKey(val.PubKey), abciVal.PubKey) - require.Equal(t, val.BondedTokens().RoundInt64(), abciVal.Power) + abciVal := validator.ABCIValidator() + require.Equal(t, tmtypes.TM2PB.PubKey(validator.PubKey), abciVal.PubKey) + require.Equal(t, validator.BondedTokens().RoundInt64(), abciVal.Power) } func TestABCIValidatorZero(t *testing.T) { - val := NewValidator(addr1, pk1, Description{}) + validator := NewValidator(addr1, pk1, Description{}) - abciVal := val.ABCIValidatorZero() - require.Equal(t, tmtypes.TM2PB.PubKey(val.PubKey), abciVal.PubKey) + abciVal := validator.ABCIValidatorZero() + require.Equal(t, tmtypes.TM2PB.PubKey(validator.PubKey), abciVal.PubKey) require.Equal(t, int64(0), abciVal.Power) } func TestRemoveTokens(t *testing.T) { - pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) - val := Validator{ + validator := Validator{ Owner: addr1, PubKey: pk1, Status: sdk.Bonded, @@ -69,66 +67,74 @@ func TestRemoveTokens(t *testing.T) { DelegatorShares: sdk.NewRat(100), } - pool.BondedTokens = val.BondedTokens() + pool := InitialPool() + pool.LooseTokens = sdk.NewRat(10) + pool.BondedTokens = validator.BondedTokens() - val, pool = val.UpdateStatus(pool, sdk.Bonded) - val, pool = val.RemoveTokens(pool, sdk.NewRat(10)) - require.Equal(t, int64(90), val.Tokens.RoundInt64()) + validator, pool = validator.UpdateStatus(pool, sdk.Bonded) + require.Equal(t, sdk.Bonded, validator.Status) + + // remove tokens and test check everything + validator, pool = validator.RemoveTokens(pool, sdk.NewRat(10)) + require.Equal(t, int64(90), validator.Tokens.RoundInt64()) require.Equal(t, int64(90), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(20), pool.LooseTokens.RoundInt64()) - val, pool = val.UpdateStatus(pool, sdk.Unbonded) - val, pool = val.RemoveTokens(pool, sdk.NewRat(10)) - require.Equal(t, int64(80), val.Tokens.RoundInt64()) + // update validator to unbonded and remove some more tokens + validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) + require.Equal(t, sdk.Unbonded, validator.Status) + require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) + require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) + + validator, pool = validator.RemoveTokens(pool, sdk.NewRat(10)) + require.Equal(t, int64(80), validator.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) - require.Equal(t, int64(30), pool.LooseTokens.RoundInt64()) + require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) } func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() pool.LooseTokens = sdk.NewRat(10) - val := NewValidator(addr1, pk1, Description{}) - val, pool = val.UpdateStatus(pool, sdk.Bonded) - val, pool, delShares := val.AddTokensFromDel(pool, 10) + validator := NewValidator(addr1, pk1, Description{}) + validator, pool = validator.UpdateStatus(pool, sdk.Bonded) + validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate(pool)) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), val.BondedTokens())) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) } func TestAddTokensValidatorUnbonding(t *testing.T) { pool := InitialPool() pool.LooseTokens = sdk.NewRat(10) - val := NewValidator(addr1, pk1, Description{}) - val, pool = val.UpdateStatus(pool, sdk.Unbonding) - val, pool, delShares := val.AddTokensFromDel(pool, 10) + validator := NewValidator(addr1, pk1, Description{}) + validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) + validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate(pool)) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) - assert.Equal(t, sdk.Unbonding, val.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), val.Tokens)) + assert.Equal(t, sdk.Unbonding, validator.Status) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) } func TestAddTokensValidatorUnbonded(t *testing.T) { pool := InitialPool() pool.LooseTokens = sdk.NewRat(10) - val := NewValidator(addr1, pk1, Description{}) - val, pool = val.UpdateStatus(pool, sdk.Unbonded) - val, pool, delShares := val.AddTokensFromDel(pool, 10) + validator := NewValidator(addr1, pk1, Description{}) + validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) + validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate(pool)) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) - assert.Equal(t, sdk.Unbonded, val.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), val.Tokens)) + assert.Equal(t, sdk.Unbonded, validator.Status) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) } // TODO refactor to make simpler like the AddToken tests above func TestRemoveDelShares(t *testing.T) { - poolA := InitialPool() - poolA.LooseTokens = sdk.NewRat(10) valA := Validator{ Owner: addr1, PubKey: pk1, @@ -136,25 +142,28 @@ func TestRemoveDelShares(t *testing.T) { Tokens: sdk.NewRat(100), DelegatorShares: sdk.NewRat(100), } + poolA := InitialPool() + poolA.LooseTokens = sdk.NewRat(10) poolA.BondedTokens = valA.BondedTokens() require.Equal(t, valA.DelegatorShareExRate(poolA), sdk.OneRat()) - valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewRat(10)) - - // coins were created - require.Equal(t, coinsB, int64(10)) - // pool shares were removed - require.Equal(t, valB.BondedTokens(), valA.BondedTokens().Sub(sdk.NewRat(10).Mul(valA.DelegatorShareExRate(poolA)))) + // Remove delegator shares + valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewRat(10)) + assert.Equal(t, int64(10), coinsB.RoundInt64()) + assert.Equal(t, int64(90), valB.DelegatorShares.RoundInt64()) + assert.Equal(t, int64(90), valB.BondedTokens().RoundInt64()) + assert.Equal(t, int64(90), poolB.BondedTokens.RoundInt64()) + assert.Equal(t, int64(20), poolB.LooseTokens.RoundInt64()) // conservation of tokens require.True(sdk.RatEq(t, - poolB.LooseTokens.Add(poolB.BondedTokens).Add(coinsB), + poolB.LooseTokens.Add(poolB.BondedTokens), poolA.LooseTokens.Add(poolA.BondedTokens))) // specific case from random tests poolTokens := sdk.NewRat(5102) delShares := sdk.NewRat(115) - val := Validator{ + validator := Validator{ Owner: addr1, PubKey: pk1, Status: sdk.Bonded, @@ -168,11 +177,12 @@ func TestRemoveDelShares(t *testing.T) { Inflation: sdk.NewRat(7, 100), } shares := sdk.NewRat(29) - msg := fmt.Sprintf("validator %#v", val) + msg := fmt.Sprintf("validator %#v", validator) msg = fmt.Sprintf("Removed %v shares from %s", shares, msg) - _, newPool, tokens := val.RemoveDelShares(pool, shares) + _, newPool, tokens := validator.RemoveDelShares(pool, shares) + require.True(sdk.RatEq(t, sdk.NewRat(147958, 115), tokens)) require.True(sdk.RatEq(t, - tokens.Add(newPool.LooseTokens).Add(newPool.BondedTokens), + newPool.LooseTokens.Add(newPool.BondedTokens), pool.LooseTokens.Add(pool.BondedTokens))) } @@ -180,22 +190,22 @@ func TestUpdateStatus(t *testing.T) { pool := InitialPool() pool.LooseTokens = sdk.NewRat(100) - val := NewValidator(addr1, pk1, Description{}) - val, pool, _ = val.AddTokensFromDel(pool, 100) - require.Equal(t, sdk.Unbonded, val.Status) - require.Equal(t, int64(100), val.Tokens.RoundInt64()) + validator := NewValidator(addr1, pk1, Description{}) + validator, pool, _ = validator.AddTokensFromDel(pool, 100) + require.Equal(t, sdk.Unbonded, validator.Status) + require.Equal(t, int64(100), validator.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(100), pool.LooseTokens.RoundInt64()) - val, pool = val.UpdateStatus(pool, sdk.Unbonding) - require.Equal(t, sdk.Unbonding, val.Status) - require.Equal(t, int64(100), val.Tokens.RoundInt64()) + validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) + require.Equal(t, sdk.Unbonding, validator.Status) + require.Equal(t, int64(100), validator.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(100), pool.LooseTokens.RoundInt64()) - val, pool = val.UpdateStatus(pool, sdk.Bonded) - require.Equal(t, sdk.Bonded, val.Status) - require.Equal(t, int64(100), val.Tokens.RoundInt64()) + validator, pool = validator.UpdateStatus(pool, sdk.Bonded) + require.Equal(t, sdk.Bonded, validator.Status) + require.Equal(t, int64(100), validator.Tokens.RoundInt64()) require.Equal(t, int64(100), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(0), pool.LooseTokens.RoundInt64()) } @@ -203,7 +213,7 @@ func TestUpdateStatus(t *testing.T) { func TestPossibleOverflow(t *testing.T) { poolTokens := sdk.NewRat(2159) delShares := sdk.NewRat(391432570689183511).Quo(sdk.NewRat(40113011844664)) - val := Validator{ + validator := Validator{ Owner: addr1, PubKey: pk1, Status: sdk.Bonded, @@ -217,8 +227,8 @@ func TestPossibleOverflow(t *testing.T) { Inflation: sdk.NewRat(7, 100), } tokens := int64(71) - msg := fmt.Sprintf("validator %#v", val) - newValidator, _, _ := val.AddTokensFromDel(pool, tokens) + msg := fmt.Sprintf("validator %#v", validator) + newValidator, _, _ := validator.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) require.False(t, newValidator.DelegatorShareExRate(pool).LT(sdk.ZeroRat()), @@ -237,10 +247,10 @@ func TestSingleValidatorIntegrationInvariants(t *testing.T) { // sanity check AssertInvariants(t, "no operation", poolOrig, validatorsOrig, - poolOrig, validatorsOrig, sdk.ZeroRat()) + poolOrig, validatorsOrig) for j := 0; j < 5; j++ { - poolMod, validatorMod, tokens, msg := RandomOperation(r)(r, poolOrig, validatorsOrig[0]) + poolMod, validatorMod, _, msg := RandomOperation(r)(r, poolOrig, validatorsOrig[0]) validatorsMod := make([]Validator, len(validatorsOrig)) copy(validatorsMod[:], validatorsOrig[:]) @@ -250,7 +260,7 @@ func TestSingleValidatorIntegrationInvariants(t *testing.T) { AssertInvariants(t, msg, poolOrig, validatorsOrig, - poolMod, validatorsMod, tokens) + poolMod, validatorsMod) poolOrig = poolMod validatorsOrig = validatorsMod @@ -267,18 +277,18 @@ func TestMultiValidatorIntegrationInvariants(t *testing.T) { AssertInvariants(t, "no operation", poolOrig, validatorsOrig, - poolOrig, validatorsOrig, sdk.ZeroRat()) + poolOrig, validatorsOrig) for j := 0; j < 5; j++ { index := int(r.Int31n(int32(len(validatorsOrig)))) - poolMod, validatorMod, tokens, msg := RandomOperation(r)(r, poolOrig, validatorsOrig[index]) + poolMod, validatorMod, _, msg := RandomOperation(r)(r, poolOrig, validatorsOrig[index]) validatorsMod := make([]Validator, len(validatorsOrig)) copy(validatorsMod[:], validatorsOrig[:]) validatorsMod[index] = validatorMod AssertInvariants(t, msg, poolOrig, validatorsOrig, - poolMod, validatorsMod, tokens) + poolMod, validatorsMod) poolOrig = poolMod validatorsOrig = validatorsMod @@ -288,11 +298,11 @@ func TestMultiValidatorIntegrationInvariants(t *testing.T) { } func TestHumanReadableString(t *testing.T) { - val := NewValidator(addr1, pk1, Description{}) + validator := NewValidator(addr1, pk1, Description{}) // NOTE: Being that the validator's keypair is random, we cannot test the // actual contents of the string. - valStr, err := val.HumanReadableString() + valStr, err := validator.HumanReadableString() require.Nil(t, err) require.NotEmpty(t, valStr) } From f2eb3056e62e34c5cbfebf1b156ec18acd425e5a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 12 Jul 2018 15:09:51 -0400 Subject: [PATCH 09/25] ... --- x/stake/keeper/delegation_test.go | 6 +++--- x/stake/keeper/inflation_test.go | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 24df7f08a740..01c764d8278e 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -151,7 +151,7 @@ func TestUnbondDelegation(t *testing.T) { validator = keeper.UpdateValidator(ctx, validator) pool = keeper.GetPool(ctx) - require.Equal(t, int64(10), pool.BondedTokens) + require.Equal(t, int64(10), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(10), validator.BondedTokens().RoundInt64()) delegation := types.Delegation{ @@ -175,8 +175,8 @@ func TestUnbondDelegation(t *testing.T) { require.Equal(t, int64(4), delegation.Shares.RoundInt64()) require.Equal(t, int64(4), validator.BondedTokens().RoundInt64()) - require.Equal(t, int64(6), pool.LooseTokens, "%v", pool) - require.Equal(t, int64(4), pool.BondedTokens) + require.Equal(t, int64(6), pool.LooseTokens.RoundInt64(), "%v", pool) + require.Equal(t, int64(4), pool.BondedTokens.RoundInt64()) } // Make sure that that the retrieving the delegations doesn't affect the state diff --git a/x/stake/keeper/inflation_test.go b/x/stake/keeper/inflation_test.go index e1dfb60ed611..f32b07eb431f 100644 --- a/x/stake/keeper/inflation_test.go +++ b/x/stake/keeper/inflation_test.go @@ -240,7 +240,7 @@ func TestInflationWithRandomOperations(t *testing.T) { previousInflation := pool.Inflation // Perform the random operation, and record how validators are modified - poolMod, validatorMod, tokens, msg := types.RandomOperation(r)(r, pool, validators[validatorCounter]) + poolMod, validatorMod, _, msg := types.RandomOperation(r)(r, pool, validators[validatorCounter]) validatorsMod := make([]types.Validator, len(validators)) copy(validatorsMod[:], validators[:]) require.Equal(t, numValidators, len(validators), "i %v", validatorCounter) @@ -249,7 +249,7 @@ func TestInflationWithRandomOperations(t *testing.T) { types.AssertInvariants(t, msg, pool, validators, - poolMod, validatorsMod, tokens) + poolMod, validatorsMod) // set pool and validators after the random operation pool = poolMod @@ -286,7 +286,7 @@ func updateProvisions(t *testing.T, keeper Keeper, pool types.Pool, ctx sdk.Cont keeper.SetPool(ctx, pool) //check provisions were added to pool - require.Equal(t, startTotalSupply.Add(expProvisions), pool.TokenSupply().RoundInt64()) + require.Equal(sdk.RatEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) return expInflation, expProvisions, pool } @@ -316,8 +316,8 @@ func setupTestValidators(pool types.Pool, keeper Keeper, ctx sdk.Context, valida // Checks that the deterministic validator setup you wanted matches the values in the pool func checkValidatorSetup(t *testing.T, pool types.Pool, initialTotalTokens, initialBondedTokens int64) { - require.Equal(t, initialTotalTokens, pool.TokenSupply(), "%v", pool) - require.Equal(t, initialBondedTokens, pool.BondedTokens, "%v", pool) + require.Equal(t, initialTotalTokens, pool.TokenSupply().RoundInt64(), "%v", pool) + require.Equal(t, initialBondedTokens, pool.BondedTokens.RoundInt64(), "%v", pool) // test initial bonded ratio require.True(t, pool.BondedRatio().Equal(sdk.NewRat(initialBondedTokens, initialTotalTokens)), "%v", pool.BondedRatio()) From a0ab1d61964519a9a94c2c62ac80a0e04606cdeb Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 12 Jul 2018 17:22:21 -0400 Subject: [PATCH 10/25] move inflation to pool type --- x/stake/handler.go | 3 +- x/stake/keeper/inflation.go | 53 ----- x/stake/keeper/inflation_test.go | 360 ------------------------------- x/stake/types/pool.go | 41 ++++ 4 files changed, 43 insertions(+), 414 deletions(-) delete mode 100644 x/stake/keeper/inflation.go delete mode 100644 x/stake/keeper/inflation_test.go diff --git a/x/stake/handler.go b/x/stake/handler.go index 265bb4e91352..c675dd5bda33 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -35,12 +35,13 @@ func NewHandler(k keeper.Keeper) sdk.Handler { // Called every block, process inflation, update validator set func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Validator) { pool := k.GetPool(ctx) + params := k.GetParams(ctx) // Process types.Validator Provisions blockTime := ctx.BlockHeader().Time if pool.InflationLastTime+blockTime >= 3600 { pool.InflationLastTime = blockTime - pool = k.ProcessProvisions(ctx) + pool.ProcessProvisions(params) } // save the params diff --git a/x/stake/keeper/inflation.go b/x/stake/keeper/inflation.go deleted file mode 100644 index 3cf8ec4667b3..000000000000 --- a/x/stake/keeper/inflation.go +++ /dev/null @@ -1,53 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/stake/types" -) - -const ( - hrsPerYr = 8766 // as defined by a julian year of 365.25 days - precision = 100000000000 // increased to this precision for accuracy -) - -var hrsPerYrRat = sdk.NewRat(hrsPerYr) - -// process provisions for an hour period -func (k Keeper) ProcessProvisions(ctx sdk.Context) types.Pool { - - pool := k.GetPool(ctx) - pool.Inflation = k.NextInflation(ctx) - - provisions := pool.Inflation.Mul(pool.TokenSupply()).Quo(hrsPerYrRat) - - // TODO add to the fees provisions - pool.LooseTokens = pool.LooseTokens.Add(provisions) - return pool -} - -// get the next inflation rate for the hour -func (k Keeper) NextInflation(ctx sdk.Context) (inflation sdk.Rat) { - - params := k.GetParams(ctx) - pool := k.GetPool(ctx) - // The target annual inflation rate is recalculated for each previsions cycle. The - // inflation is also subject to a rate change (positive or negative) depending on - // the distance from the desired ratio (67%). The maximum rate change possible is - // defined to be 13% per year, however the annual inflation is capped as between - // 7% and 20%. - - // (1 - bondedRatio/GoalBonded) * InflationRateChange - inflationRateChangePerYear := sdk.OneRat().Sub(pool.BondedRatio().Quo(params.GoalBonded)).Mul(params.InflationRateChange) - inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrRat) - - // increase the new annual inflation for this next cycle - inflation = pool.Inflation.Add(inflationRateChange) - if inflation.GT(params.InflationMax) { - inflation = params.InflationMax - } - if inflation.LT(params.InflationMin) { - inflation = params.InflationMin - } - - return inflation.Round(precision) -} diff --git a/x/stake/keeper/inflation_test.go b/x/stake/keeper/inflation_test.go deleted file mode 100644 index f32b07eb431f..000000000000 --- a/x/stake/keeper/inflation_test.go +++ /dev/null @@ -1,360 +0,0 @@ -package keeper - -import ( - "math/rand" - "strconv" - "testing" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/stake/types" -) - -//changing the int in NewSource will allow you to test different, deterministic, sets of operations -var r = rand.New(rand.NewSource(6595)) - -func TestGetInflation(t *testing.T) { - ctx, _, keeper := CreateTestInput(t, false, 0) - pool := keeper.GetPool(ctx) - params := keeper.GetParams(ctx) - hrsPerYrRat := sdk.NewRat(hrsPerYr) - - // Governing Mechanism: - // BondedRatio = BondedTokens / TotalSupply - // inflationRateChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationRateChange - - tests := []struct { - name string - setBondedTokens, setLooseTokens, - setInflation, expectedChange sdk.Rat - }{ - // with 0% bonded atom supply the inflation should increase by InflationRateChange - {"test 1", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), params.InflationRateChange.Quo(hrsPerYrRat).Round(precision)}, - - // 100% bonded, starting at 20% inflation and being reduced - // (1 - (1/0.67))*(0.13/8667) - {"test 2", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), - sdk.OneRat().Sub(sdk.OneRat().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, - - // 50% bonded, starting at 10% inflation and being increased - {"test 3", sdk.OneRat(), sdk.OneRat(), sdk.NewRat(10, 100), - sdk.OneRat().Sub(sdk.NewRat(1, 2).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, - - // test 7% minimum stop (testing with 100% bonded) - {"test 4", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), sdk.ZeroRat()}, - {"test 5", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(70001, 1000000), sdk.NewRat(-1, 1000000).Round(precision)}, - - // test 20% maximum stop (testing with 0% bonded) - {"test 6", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), sdk.ZeroRat()}, - {"test 7", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(199999, 1000000), sdk.NewRat(1, 1000000).Round(precision)}, - - // perfect balance shouldn't change inflation - {"test 8", sdk.NewRat(67), sdk.NewRat(33), sdk.NewRat(15, 100), sdk.ZeroRat()}, - } - for _, tc := range tests { - pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens - pool.Inflation = tc.setInflation - keeper.SetPool(ctx, pool) - - inflation := keeper.NextInflation(ctx) - diffInflation := inflation.Sub(tc.setInflation) - - require.True(t, diffInflation.Equal(tc.expectedChange), - "Name: %v\nDiff: %v\nExpected: %v\n", tc.name, diffInflation, tc.expectedChange) - } -} - -// Test that provisions are correctly added to the pool and validators each hour for 1 year -func TestProcessProvisions(t *testing.T) { - ctx, _, keeper := CreateTestInput(t, false, 0) - pool := keeper.GetPool(ctx) - - var ( - initialTotalTokens int64 = 550000000 - initialBondedTokens int64 = 250000000 - cumulativeExpProvs = sdk.ZeroRat() - validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} - bondedValidators uint16 = 2 - ) - pool.LooseTokens = sdk.NewRat(initialTotalTokens) - - // create some validators some bonded, some unbonded - _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) - checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens) - - // process the provisions for a year - for hr := 0; hr < 8766; hr++ { - pool := keeper.GetPool(ctx) - _, expProvisions, _ := updateProvisions(t, keeper, pool, ctx, hr) - cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions) - } - - //get the pool and do the final value checks from checkFinalPoolValues - pool = keeper.GetPool(ctx) - checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), cumulativeExpProvs) -} - -// Tests that the hourly rate of change of inflation will be positive, negative, or zero, depending on bonded ratio and inflation rate -// Cycles through the whole gambit of inflation possibilities, starting at 7% inflation, up to 20%, back down to 7% (it takes ~11.4 years) -func TestHourlyInflationRateOfChange(t *testing.T) { - ctx, _, keeper := CreateTestInput(t, false, 0) - pool := keeper.GetPool(ctx) - - var ( - initialTotalTokens int64 = 550000000 - initialBondedTokens int64 = 150000000 - cumulativeExpProvs = sdk.ZeroRat() - validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} - bondedValidators uint16 = 1 - ) - pool.LooseTokens = sdk.NewRat(initialTotalTokens) - - // create some validators some bonded, some unbonded - _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) - checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens) - - // ~11.4 years to go from 7%, up to 20%, back down to 7% - for hr := 0; hr < 100000; hr++ { - pool := keeper.GetPool(ctx) - previousInflation := pool.Inflation - updatedInflation, expProvisions, pool := updateProvisions(t, keeper, pool, ctx, hr) - cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions) - msg := strconv.Itoa(hr) - checkInflation(t, pool, previousInflation, updatedInflation, msg) - } - - // Final check that the pool equals initial values + cumulative provisions and adjustments we recorded - pool = keeper.GetPool(ctx) - checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), cumulativeExpProvs) -} - -//Test that a large unbonding will significantly lower the bonded ratio -func TestLargeUnbond(t *testing.T) { - ctx, _, keeper := CreateTestInput(t, false, 0) - pool := keeper.GetPool(ctx) - - var ( - initialTotalTokens int64 = 1200000000 - initialBondedTokens int64 = 900000000 - validatorTokens = []int64{300000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000} - bondedValidators uint16 = 7 - ) - pool.LooseTokens = sdk.NewRat(initialTotalTokens) - - _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) - checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens) - - pool = keeper.GetPool(ctx) - validator, found := keeper.GetValidator(ctx, Addrs[0]) - require.True(t, found) - - // initialBondedRatio that we can use to compare to the new values after the unbond - initialBondedRatio := pool.BondedRatio() - - // validator[0] will be unbonded, bringing us from 75% bonded ratio to ~50% (unbonding 300,000,000) - pool, validator, _, _ = types.OpBondOrUnbond(r, pool, validator) - keeper.SetPool(ctx, pool) - - // process provisions after the bonding, to compare the difference in expProvisions and expInflation - _, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0) - - // unbonded shares should increase - require.Equal(t, sdk.Unbonded, validator.Status) - require.True(t, validator.Tokens.GT(sdk.NewRat(300000000, 1))) - - // Ensure that new bonded ratio is less than old bonded ratio , because before they were increasing (i.e. 50% < 75) - require.True(t, (pool.BondedRatio().LT(initialBondedRatio))) - - // Final check that the pool equals initial values + provisions and adjustments we recorded - pool = keeper.GetPool(ctx) - checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), expProvisionsAfter) -} - -//Test that a large bonding will significantly increase the bonded ratio -func TestLargeBond(t *testing.T) { - ctx, _, keeper := CreateTestInput(t, false, 0) - pool := keeper.GetPool(ctx) - - var ( - initialTotalTokens int64 = 1600000000 - initialBondedTokens int64 = 400000000 - validatorTokens = []int64{400000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 400000000} - bondedValidators uint16 = 1 - ) - pool.LooseTokens = sdk.NewRat(initialTotalTokens) - - _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) - checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens) - - pool = keeper.GetPool(ctx) - validator, found := keeper.GetValidator(ctx, Addrs[9]) - require.True(t, found) - - // initialBondedRatio that we can use to compare to the new values after the unbond - initialBondedRatio := pool.BondedRatio() - - params := types.DefaultParams() - params.MaxValidators = bondedValidators + 1 //must do this to allow for an extra validator to bond - keeper.SetParams(ctx, params) - - // validator[9] will be bonded, bringing us from 25% to ~50% (bonding 400,000,000 tokens) - pool, _, _, _ = types.OpBondOrUnbond(r, pool, validator) - keeper.SetPool(ctx, pool) - - // process provisions after the bonding, to compare the difference in expProvisions and expInflation - _, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0) - - // Ensure that new bonded ratio is greater than old bonded ratio (i.e. 50% > 25%) - require.True(t, (pool.BondedRatio().GT(initialBondedRatio))) - // Final check that the pool equals initial values + provisions and adjustments we recorded - pool = keeper.GetPool(ctx) - - checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), expProvisionsAfter) -} - -// Tests that inflation increases or decreases as expected when we do a random operation on 20 different validators -func TestInflationWithRandomOperations(t *testing.T) { - ctx, _, keeper := CreateTestInput(t, false, 0) - params := types.DefaultParams() - keeper.SetParams(ctx, params) - numValidators := 20 - - // start off by randomly setting up 20 validators - pool, validators := types.RandomSetup(r, numValidators) - require.Equal(t, numValidators, len(validators)) - - for i := 0; i < len(validators); i++ { - keeper.SetValidator(ctx, validators[i]) - } - keeper.SetPool(ctx, pool) - - // Used to rotate validators so each random operation is applied to a different validator - validatorCounter := 0 - - // Loop through 20 random operations, and check the inflation after each operation - for i := 0; i < numValidators; i++ { - pool := keeper.GetPool(ctx) - - // Get inflation before RandomOperation, for comparison later - previousInflation := pool.Inflation - - // Perform the random operation, and record how validators are modified - poolMod, validatorMod, _, msg := types.RandomOperation(r)(r, pool, validators[validatorCounter]) - validatorsMod := make([]types.Validator, len(validators)) - copy(validatorsMod[:], validators[:]) - require.Equal(t, numValidators, len(validators), "i %v", validatorCounter) - require.Equal(t, numValidators, len(validatorsMod), "i %v", validatorCounter) - validatorsMod[validatorCounter] = validatorMod - - types.AssertInvariants(t, msg, - pool, validators, - poolMod, validatorsMod) - - // set pool and validators after the random operation - pool = poolMod - keeper.SetPool(ctx, pool) - validators = validatorsMod - - // Must set inflation here manually, as opposed to most other tests in this suite, where we call keeper.processProvisions(), which updates pool.Inflation - updatedInflation := keeper.NextInflation(ctx) - pool.Inflation = updatedInflation - keeper.SetPool(ctx, pool) - - // Ensure inflation changes as expected when random operations are applied. - checkInflation(t, pool, previousInflation, updatedInflation, msg) - validatorCounter++ - } -} - -//_________________________________________________________________________________________ -////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// - -// Final check on the global pool values for what the total tokens accumulated from each hour of provisions -func checkFinalPoolValues(t *testing.T, pool types.Pool, initialTotalTokens, cumulativeExpProvs sdk.Rat) { - calculatedTotalTokens := initialTotalTokens.Add(cumulativeExpProvs) - require.Equal(sdk.RatEq(t, calculatedTotalTokens, pool.TokenSupply())) -} - -// Processes provisions are added to the pool correctly every hour -// Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests -func updateProvisions(t *testing.T, keeper Keeper, pool types.Pool, ctx sdk.Context, hr int) (sdk.Rat, sdk.Rat, types.Pool) { - expInflation := keeper.NextInflation(ctx) - expProvisions := expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrRat) - startTotalSupply := pool.TokenSupply() - pool = keeper.ProcessProvisions(ctx) - keeper.SetPool(ctx, pool) - - //check provisions were added to pool - require.Equal(sdk.RatEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) - - return expInflation, expProvisions, pool -} - -// Deterministic setup of validators and pool -// Allows you to decide how many validators to setup -// Allows you to pick which validators are bonded by adjusting the MaxValidators of params -func setupTestValidators(pool types.Pool, keeper Keeper, ctx sdk.Context, validatorTokens []int64, - maxValidators uint16) ([]types.Validator, Keeper, types.Pool) { - - params := types.DefaultParams() - params.MaxValidators = maxValidators - keeper.SetParams(ctx, params) - numValidators := len(validatorTokens) - validators := make([]types.Validator, numValidators) - - for i := 0; i < numValidators; i++ { - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) - validators[i], pool, _ = validators[i].AddTokensFromDel(pool, validatorTokens[i]) - keeper.SetPool(ctx, pool) - validators[i] = keeper.UpdateValidator(ctx, validators[i]) //will kick out lower power validators. Keep this in mind when setting up the test validators order - pool = keeper.GetPool(ctx) - } - - return validators, keeper, pool -} - -// Checks that the deterministic validator setup you wanted matches the values in the pool -func checkValidatorSetup(t *testing.T, pool types.Pool, initialTotalTokens, initialBondedTokens int64) { - require.Equal(t, initialTotalTokens, pool.TokenSupply().RoundInt64(), "%v", pool) - require.Equal(t, initialBondedTokens, pool.BondedTokens.RoundInt64(), "%v", pool) - - // test initial bonded ratio - require.True(t, pool.BondedRatio().Equal(sdk.NewRat(initialBondedTokens, initialTotalTokens)), "%v", pool.BondedRatio()) -} - -// Checks that The inflation will correctly increase or decrease after an update to the pool -// nolint: gocyclo -func checkInflation(t *testing.T, pool types.Pool, previousInflation, updatedInflation sdk.Rat, msg string) { - inflationChange := updatedInflation.Sub(previousInflation) - - switch { - //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation - case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)): - require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) - - //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio - case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(20, 100)): - if previousInflation.Equal(sdk.NewRat(20, 100)) { - require.Equal(t, true, inflationChange.IsZero(), msg) - - //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) - } else { - require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) - } - - //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% - case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)) && updatedInflation.GT(sdk.NewRat(7, 100)): - require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) - - //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. - case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(7, 100)): - if previousInflation.Equal(sdk.NewRat(7, 100)) { - require.Equal(t, true, inflationChange.IsZero(), msg) - - //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) - } else { - require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) - } - } -} diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index d11f36cf9faa..e3e721774ce5 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -75,3 +75,44 @@ func (p Pool) removeBondedTokens(bondedTokens sdk.Rat) Pool { } return p } + +//_______________________________________________________________________ +// Inflation + +const precision = 100000000000 // increased to this precision for accuracy +var hrsPerYrRat = sdk.NewRat(8766) // as defined by a julian year of 365.25 days + +// process provisions for an hour period +func (p Pool) ProcessProvisions(params Params) Pool { + p.Inflation = p.NextInflation(params) + provisions := p.Inflation.Mul(p.TokenSupply()).Quo(hrsPerYrRat) + + // TODO add to the fees provisions + p.LooseTokens = p.LooseTokens.Add(provisions) + return p +} + +// get the next inflation rate for the hour +func (p Pool) NextInflation(params Params) (inflation sdk.Rat) { + + // The target annual inflation rate is recalculated for each previsions cycle. The + // inflation is also subject to a rate change (positive or negative) depending on + // the distance from the desired ratio (67%). The maximum rate change possible is + // defined to be 13% per year, however the annual inflation is capped as between + // 7% and 20%. + + // (1 - bondedRatio/GoalBonded) * InflationRateChange + inflationRateChangePerYear := sdk.OneRat().Sub(p.BondedRatio().Quo(params.GoalBonded)).Mul(params.InflationRateChange) + inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrRat) + + // increase the new annual inflation for this next cycle + inflation = p.Inflation.Add(inflationRateChange) + if inflation.GT(params.InflationMax) { + inflation = params.InflationMax + } + if inflation.LT(params.InflationMin) { + inflation = params.InflationMin + } + + return inflation.Round(precision) +} From b5ba3344ea74379bbdf29b5ff146667890c8d5d8 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 12 Jul 2018 17:22:42 -0400 Subject: [PATCH 11/25] ... --- x/stake/types/inflation_test.go | 142 ++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 x/stake/types/inflation_test.go diff --git a/x/stake/types/inflation_test.go b/x/stake/types/inflation_test.go new file mode 100644 index 000000000000..555408853cb2 --- /dev/null +++ b/x/stake/types/inflation_test.go @@ -0,0 +1,142 @@ +package types + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +//changing the int in NewSource will allow you to test different, deterministic, sets of operations +var r = rand.New(rand.NewSource(6595)) + +func TestGetInflation(t *testing.T) { + pool := InitialPool() + params := DefaultParams() + + // Governing Mechanism: + // BondedRatio = BondedTokens / TotalSupply + // inflationRateChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationRateChange + + tests := []struct { + name string + setBondedTokens, setLooseTokens, + setInflation, expectedChange sdk.Rat + }{ + // with 0% bonded atom supply the inflation should increase by InflationRateChange + {"test 1", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), params.InflationRateChange.Quo(hrsPerYrRat).Round(precision)}, + + // 100% bonded, starting at 20% inflation and being reduced + // (1 - (1/0.67))*(0.13/8667) + {"test 2", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), + sdk.OneRat().Sub(sdk.OneRat().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, + + // 50% bonded, starting at 10% inflation and being increased + {"test 3", sdk.OneRat(), sdk.OneRat(), sdk.NewRat(10, 100), + sdk.OneRat().Sub(sdk.NewRat(1, 2).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, + + // test 7% minimum stop (testing with 100% bonded) + {"test 4", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), sdk.ZeroRat()}, + {"test 5", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(70001, 1000000), sdk.NewRat(-1, 1000000).Round(precision)}, + + // test 20% maximum stop (testing with 0% bonded) + {"test 6", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), sdk.ZeroRat()}, + {"test 7", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(199999, 1000000), sdk.NewRat(1, 1000000).Round(precision)}, + + // perfect balance shouldn't change inflation + {"test 8", sdk.NewRat(67), sdk.NewRat(33), sdk.NewRat(15, 100), sdk.ZeroRat()}, + } + for _, tc := range tests { + pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens + pool.Inflation = tc.setInflation + + inflation := pool.NextInflation(params) + diffInflation := inflation.Sub(tc.setInflation) + + require.True(t, diffInflation.Equal(tc.expectedChange), + "Name: %v\nDiff: %v\nExpected: %v\n", tc.name, diffInflation, tc.expectedChange) + } +} + +// Test that provisions are correctly added to the pool and validators each hour for 1 year +func TestProcessProvisions(t *testing.T) { + pool := InitialPool() + params := DefaultParams() + + var ( + initialTotalTokens int64 = 550000000 + cumulativeExpProvs = sdk.ZeroRat() + ) + pool.LooseTokens = sdk.NewRat(initialTotalTokens) + + // process the provisions for a year + for hr := 0; hr < 100; hr++ { + var expProvisions sdk.Rat + _, expProvisions, pool = updateProvisions(t, pool, params, hr) + cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions) + } + + //get the pool and do the final value checks from checkFinalPoolValues + checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), cumulativeExpProvs) +} + +//_________________________________________________________________________________________ +////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// + +// Final check on the global pool values for what the total tokens accumulated from each hour of provisions +func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs sdk.Rat) { + calculatedTotalTokens := initialTotalTokens.Add(cumulativeExpProvs) + require.True(sdk.RatEq(t, calculatedTotalTokens, pool.TokenSupply())) +} + +// Processes provisions are added to the pool correctly every hour +// Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests +func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Rat, sdk.Rat, Pool) { + expInflation := pool.NextInflation(params) + expProvisions := expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrRat) + startTotalSupply := pool.TokenSupply() + pool = pool.ProcessProvisions(params) + + //check provisions were added to pool + require.True(sdk.RatEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) + + return expInflation, expProvisions, pool +} + +// Checks that The inflation will correctly increase or decrease after an update to the pool +// nolint: gocyclo +func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Rat, msg string) { + inflationChange := updatedInflation.Sub(previousInflation) + + switch { + //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation + case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)): + require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + + //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio + case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(20, 100)): + if previousInflation.Equal(sdk.NewRat(20, 100)) { + require.Equal(t, true, inflationChange.IsZero(), msg) + + //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) + } else { + require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + } + + //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% + case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)) && updatedInflation.GT(sdk.NewRat(7, 100)): + require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + + //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. + case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(7, 100)): + if previousInflation.Equal(sdk.NewRat(7, 100)) { + require.Equal(t, true, inflationChange.IsZero(), msg) + + //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) + } else { + require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + } + } +} From 885615ffea8607d35c8088e89283c72203b8b4d3 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 12 Jul 2018 18:34:55 -0400 Subject: [PATCH 12/25] stumped problem --- x/stake/keeper/slash.go | 2 +- x/stake/keeper/slash_test.go | 8 ++++++-- x/stake/keeper/validator_test.go | 26 ++++++++++++++++++++++---- x/stake/types/validator_test.go | 12 ++++++------ 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 27110ba10c01..8cc44464b2af 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -93,7 +93,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // Get the current pool pool := k.GetPool(ctx) - // remove shares from the validator + // remove tokens from the validator validator, pool = validator.RemoveTokens(pool, burned) // burn tokens pool.LooseTokens = pool.LooseTokens.Sub(burned) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index d5a0e7f549a3..c9c3ed20a03b 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -25,9 +26,12 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) - keeper.UpdateValidator(ctx, validator) + validator = keeper.UpdateValidator(ctx, validator) + fmt.Printf("debug validator: %v\n", validator) keeper.SetValidatorByPubKeyIndex(ctx, validator) } + pool = keeper.GetPool(ctx) + fmt.Printf("debug pool: %v\n", pool) return ctx, keeper, params } @@ -354,7 +358,7 @@ func TestSlashWithRedelegation(t *testing.T) { ctx = ctx.WithBlockHeight(12) validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.NewRat(3, 4)) + require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.NewRat(3, 4)) }) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index a42e4ef23475..0b0f10777393 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -76,7 +76,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { // burn half the delegator shares validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewRat(2))) - require.Equal(t, int64(50), burned) + require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out require.False(t, keeper.validatorByPowerIndexExists(ctx, power)) @@ -122,8 +122,12 @@ func TestValidatorBasics(t *testing.T) { validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) validators[i].Status = sdk.Unbonded validators[i].Tokens = sdk.ZeroRat() - validators[i].AddTokensFromDel(pool, amt) + validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt) + keeper.SetPool(ctx, pool) } + assert.True(sdk.RatEq(t, sdk.NewRat(9), validators[0].Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(8), validators[1].Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(7), validators[2].Tokens)) // check the empty keeper first _, found := keeper.GetValidator(ctx, addrVals[0]) @@ -131,6 +135,9 @@ func TestValidatorBasics(t *testing.T) { resVals := keeper.GetValidatorsBonded(ctx) assert.Zero(t, len(resVals)) + pool = keeper.GetPool(ctx) + assert.True(sdk.RatEq(t, sdk.ZeroRat(), pool.BondedTokens)) + // set and retrieve a record validators[0] = keeper.UpdateValidator(ctx, validators[0]) resVal, found := keeper.GetValidator(ctx, addrVals[0]) @@ -140,6 +147,11 @@ func TestValidatorBasics(t *testing.T) { resVals = keeper.GetValidatorsBonded(ctx) require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validators[0], resVals[0])) + assert.Equal(t, sdk.Bonded, validators[0].Status) + assert.True(sdk.RatEq(t, sdk.NewRat(9), validators[0].BondedTokens())) + + pool = keeper.GetPool(ctx) + assert.True(sdk.RatEq(t, pool.BondedTokens, validators[0].BondedTokens())) // modify a records, save, and retrieve validators[0].Status = sdk.Bonded @@ -398,6 +410,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { func TestValidatorBondHeight(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) + pool := keeper.GetPool(ctx) // now 2 max resValidators params := keeper.GetParams(ctx) @@ -405,7 +418,6 @@ func TestValidatorBondHeight(t *testing.T) { keeper.SetParams(ctx, params) // initialize some validators into the state - pool := keeper.GetPool(ctx) var validators [3]types.Validator validators[0] = types.NewValidator(Addrs[0], PKs[0], types.Description{}) validators[1] = types.NewValidator(Addrs[1], PKs[1], types.Description{}) @@ -414,14 +426,18 @@ func TestValidatorBondHeight(t *testing.T) { validators[0], pool, _ = validators[0].AddTokensFromDel(pool, 200) validators[1], pool, _ = validators[1].AddTokensFromDel(pool, 100) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, 100) - keeper.SetPool(ctx, pool) + validators[0] = keeper.UpdateValidator(ctx, validators[0]) + //////////////////////////////////////// // If two validators both increase to the same voting power in the same block, // the one with the first transaction should become bonded validators[1] = keeper.UpdateValidator(ctx, validators[1]) validators[2] = keeper.UpdateValidator(ctx, validators[2]) + + pool = keeper.GetPool(ctx) + resValidators := keeper.GetValidatorsByPower(ctx) require.Equal(t, uint16(len(resValidators)), params.MaxValidators) @@ -430,7 +446,9 @@ func TestValidatorBondHeight(t *testing.T) { validators[1], pool, _ = validators[1].AddTokensFromDel(pool, 50) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, 50) keeper.SetPool(ctx, pool) + //require.NotPanics(t, func() { validators[2] = keeper.UpdateValidator(ctx, validators[2]) + //}) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, params.MaxValidators, uint16(len(resValidators))) validators[1] = keeper.UpdateValidator(ctx, validators[1]) diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index fd7926124226..3ff234957e99 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -197,17 +197,17 @@ func TestUpdateStatus(t *testing.T) { require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(100), pool.LooseTokens.RoundInt64()) - validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) - require.Equal(t, sdk.Unbonding, validator.Status) - require.Equal(t, int64(100), validator.Tokens.RoundInt64()) - require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) - require.Equal(t, int64(100), pool.LooseTokens.RoundInt64()) - validator, pool = validator.UpdateStatus(pool, sdk.Bonded) require.Equal(t, sdk.Bonded, validator.Status) require.Equal(t, int64(100), validator.Tokens.RoundInt64()) require.Equal(t, int64(100), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(0), pool.LooseTokens.RoundInt64()) + + validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) + require.Equal(t, sdk.Unbonding, validator.Status) + require.Equal(t, int64(100), validator.Tokens.RoundInt64()) + require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) + require.Equal(t, int64(100), pool.LooseTokens.RoundInt64()) } func TestPossibleOverflow(t *testing.T) { From 244d1ba7140898abab0f8cd613dd0edf8e524973 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 13 Jul 2018 02:47:44 +0200 Subject: [PATCH 13/25] Calculate newly issued shares, remove unnecessary pool arg from exchange rate calculation --- x/stake/types/test_utils.go | 4 ++-- x/stake/types/validator.go | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/x/stake/types/test_utils.go b/x/stake/types/test_utils.go index 635fd7be2951..104eae3d315f 100644 --- a/x/stake/types/test_utils.go +++ b/x/stake/types/test_utils.go @@ -120,10 +120,10 @@ func AssertInvariants(t *testing.T, msg string, for _, vMod := range vMods { // Nonnegative ex rate - require.False(t, vMod.DelegatorShareExRate(pMod).LT(sdk.ZeroRat()), + require.False(t, vMod.DelegatorShareExRate().LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative validator.DelegatorShareExRate(): %v (validator.Owner: %s)", msg, - vMod.DelegatorShareExRate(pMod), + vMod.DelegatorShareExRate(), vMod.Owner, ) diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 1c5728e7af70..8b6b588abd9d 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -349,14 +349,15 @@ func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Rat) { // bondedShare/delegatedShare - exRate := v.DelegatorShareExRate(pool) + exRate := v.DelegatorShareExRate() if v.Status == sdk.Bonded { pool = pool.addBondedTokens(sdk.NewRat(amount)) } - v.Tokens = v.Tokens.Add(sdk.NewRat(amount)) - issuedShares := v.Tokens.Quo(exRate) + amountRat := sdk.NewRat(amount) + v.Tokens = v.Tokens.Add(amountRat) + issuedShares := amountRat.Quo(exRate) v.DelegatorShares = v.DelegatorShares.Add(issuedShares) return v, pool, issuedShares @@ -367,7 +368,7 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s // NOTE: This function assumes the shares have already been updated for the // validator status. func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, sdk.Rat) { - issuedTokens := v.DelegatorShareExRate(pool).Mul(delShares) + issuedTokens := v.DelegatorShareExRate().Mul(delShares) v.Tokens = v.Tokens.Sub(issuedTokens) v.DelegatorShares = v.DelegatorShares.Sub(delShares) @@ -380,7 +381,7 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Poo // DelegatorShareExRate gets the exchange rate of tokens over delegator shares. // UNITS: tokens/delegator-shares -func (v Validator) DelegatorShareExRate(pool Pool) sdk.Rat { +func (v Validator) DelegatorShareExRate() sdk.Rat { if v.DelegatorShares.IsZero() { return sdk.OneRat() } From 3a5a396ef5e3f177d6cf7e981411a51685950db6 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 13 Jul 2018 03:08:24 +0200 Subject: [PATCH 14/25] Rounding changed --- x/stake/keeper/slash_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index c9c3ed20a03b..072de9fad127 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -329,6 +329,11 @@ func TestSlashWithRedelegation(t *testing.T) { } keeper.SetDelegation(ctx, del) + // update bonded tokens + pool := keeper.GetPool(ctx) + pool.BondedTokens = pool.BondedTokens.Add(sdk.NewRat(6)) + keeper.SetPool(ctx, pool) + // slash validator ctx = ctx.WithBlockHeight(12) oldPool := keeper.GetPool(ctx) @@ -358,7 +363,7 @@ func TestSlashWithRedelegation(t *testing.T) { ctx = ctx.WithBlockHeight(12) validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) - require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.NewRat(3, 4)) }) + require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) }) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -367,7 +372,7 @@ func TestSlashWithRedelegation(t *testing.T) { require.Equal(t, sdk.NewInt(0), rd.Balance.Amount) // read updated pool newPool = keeper.GetPool(ctx) - // 7 bonded tokens burned + // seven bonded tokens burned require.Equal(t, int64(12), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator validator, found = keeper.GetValidatorByPubKey(ctx, pk) From 40c8bcba520afc8d9e3a52f34ba8e8e6815bea9d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 13 Jul 2018 03:11:48 +0200 Subject: [PATCH 15/25] Update x/slashing tests for sdk.Rat BondedTokens --- x/slashing/keeper_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 6d0bf868c7c5..794bc2c92c70 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -100,7 +100,7 @@ func TestHandleAbsentValidator(t *testing.T) { validator, _ := sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) - require.Equal(t, int64(amtInt), pool.BondedTokens) + require.Equal(t, int64(amtInt), pool.BondedTokens.RoundInt64()) // 501st block missed ctx = ctx.WithBlockHeight(height) @@ -129,7 +129,7 @@ func TestHandleAbsentValidator(t *testing.T) { // validator should have been slashed pool = sk.GetPool(ctx) - require.Equal(t, int64(amtInt-1), pool.BondedTokens) + require.Equal(t, int64(amtInt-1), pool.BondedTokens.RoundInt64()) // validator start height should have been changed info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) @@ -194,5 +194,5 @@ func TestHandleNewValidator(t *testing.T) { validator, _ := sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) - require.Equal(t, int64(100), pool.BondedTokens) + require.Equal(t, int64(100), pool.BondedTokens.RoundInt64()) } From f448183c488f1f5b5b81f19191416da5dfd9a902 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 13 Jul 2018 02:22:20 -0400 Subject: [PATCH 16/25] testing fixes --- x/stake/app_test.go | 4 ++-- x/stake/handler_test.go | 24 ++++++++++++------------ x/stake/keeper/slash_test.go | 3 --- x/stake/types/validator_test.go | 12 ++++++------ 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 40e987b8c81d..606369cd65bb 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -147,8 +147,8 @@ func TestStakeMsgs(t *testing.T) { validator = checkValidator(t, mApp, keeper, addr2, true) require.Equal(t, addr2, validator.Owner) - require.Equal(t, sdk.Bonded, validator.Status()) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) + require.Equal(t, sdk.Bonded, validator.Status) + require.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) // check the bond that should have been created as well checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10)) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index c4d3e845af34..f23291af6179 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -98,8 +98,9 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2)) // inflate a bunch + params := keeper.GetParams(ctx) for i := 0; i < 20000; i++ { - pool = keeper.ProcessProvisions(ctx) + pool = pool.ProcessProvisions(params) keeper.SetPool(ctx, pool) } @@ -160,8 +161,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr2, validator.Owner) assert.Equal(t, pk2, validator.PubKey) - assert.Equal(t, sdk.NewRat(10), validator.BondedTokens()) - assert.Equal(t, sdk.NewRat(10), validator.DelegatorShares) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) } @@ -177,12 +178,12 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - require.Equal(t, sdk.Bonded, validator.Status()) - require.Equal(t, validatorAddr, validator.Owner) - require.Equal(t, pk, validator.PubKey) - require.Equal(t, sdk.NewRat(10), validator.PoolShares.Bonded()) - require.Equal(t, sdk.NewRat(10), validator.DelegatorShares) - require.Equal(t, Description{}, validator.Description) + assert.Equal(t, sdk.Bonded, validator.Status) + assert.Equal(t, validatorAddr, validator.Owner) + assert.Equal(t, pk, validator.PubKey) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.Equal(t, Description{}, validator.Description) // one validator cannot be created twice even from different delegator msgCreateValidatorOnBehalfOf.DelegatorAddr = keep.Addrs[2] @@ -218,7 +219,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { require.Equal(t, bondAmount, bond.Shares.RoundInt64()) pool := keeper.GetPool(ctx) - exRate := validator.DelegatorShareExRate(pool) + exRate := validator.DelegatorShareExRate() require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) require.Equal(t, bondAmount, pool.BondedTokens) @@ -237,8 +238,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.True(t, found) - pool := keeper.GetPool(ctx) - exRate := validator.DelegatorShareExRate(pool) + exRate := validator.DelegatorShareExRate() 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/slash_test.go b/x/stake/keeper/slash_test.go index 072de9fad127..a9f5e888c9f1 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -1,7 +1,6 @@ package keeper import ( - "fmt" "testing" "github.com/stretchr/testify/require" @@ -27,11 +26,9 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { validator, pool, _ = validator.AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) validator = keeper.UpdateValidator(ctx, validator) - fmt.Printf("debug validator: %v\n", validator) keeper.SetValidatorByPubKeyIndex(ctx, validator) } pool = keeper.GetPool(ctx) - fmt.Printf("debug pool: %v\n", pool) return ctx, keeper, params } diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 3ff234957e99..abaad2c0f62e 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -99,7 +99,7 @@ func TestAddTokensValidatorBonded(t *testing.T) { validator, pool = validator.UpdateStatus(pool, sdk.Bonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) @@ -112,7 +112,7 @@ func TestAddTokensValidatorUnbonding(t *testing.T) { validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.Equal(t, sdk.Unbonding, validator.Status) @@ -126,7 +126,7 @@ func TestAddTokensValidatorUnbonded(t *testing.T) { validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.Equal(t, sdk.Unbonded, validator.Status) @@ -145,7 +145,7 @@ func TestRemoveDelShares(t *testing.T) { poolA := InitialPool() poolA.LooseTokens = sdk.NewRat(10) poolA.BondedTokens = valA.BondedTokens() - require.Equal(t, valA.DelegatorShareExRate(poolA), sdk.OneRat()) + require.Equal(t, valA.DelegatorShareExRate(), sdk.OneRat()) // Remove delegator shares valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewRat(10)) @@ -231,9 +231,9 @@ func TestPossibleOverflow(t *testing.T) { newValidator, _, _ := validator.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) - require.False(t, newValidator.DelegatorShareExRate(pool).LT(sdk.ZeroRat()), + require.False(t, newValidator.DelegatorShareExRate().LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative DelegatorShareExRate(): %v", - msg, newValidator.DelegatorShareExRate(pool)) + msg, newValidator.DelegatorShareExRate()) } // run random operations in a random order on a random single-validator state, assert invariants hold From ef112055d29d9ca597338ff99178c70e529416f8 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 13 Jul 2018 02:27:36 -0400 Subject: [PATCH 17/25] resolved test fixes --- x/stake/handler_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index f23291af6179..f183b279a640 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -99,7 +99,7 @@ func TestValidatorByPowerIndex(t *testing.T) { // inflate a bunch params := keeper.GetParams(ctx) - for i := 0; i < 20000; i++ { + for i := 0; i < 200; i++ { pool = pool.ProcessProvisions(params) keeper.SetPool(ctx, pool) } @@ -221,7 +221,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { pool := keeper.GetPool(ctx) exRate := validator.DelegatorShareExRate() require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) - require.Equal(t, bondAmount, pool.BondedTokens) + require.Equal(t, bondAmount, pool.BondedTokens.RoundInt64()) // just send the same msgbond multiple times msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) From 00bbef0a69ebcc5192602a9bd3461dca2b7d012a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 13 Jul 2018 03:05:42 -0400 Subject: [PATCH 18/25] cwgoes comments, changelog, lint --- CHANGELOG.md | 2 ++ types/rational.go | 2 +- x/stake/keeper/validator_test.go | 2 -- x/stake/types/pool.go | 4 ++-- x/stake/types/pool_test.go | 4 ++-- x/stake/types/validator.go | 13 +++++++------ x/stake/types/validator_test.go | 2 -- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ac7bd4372ee..893bf78d83a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ BREAKING CHANGES * [x/stake] Specify DelegatorAddress in MsgCreateValidator +* [x/stake] Remove the use of global shares in the pool + * Remove the use of `PoolShares` type in `x/stake/validator` type - replace with `Status` `Tokens` fields * [x/auth] NewAccountMapper takes a constructor instead of a prototype * [keys] Keybase.Update function now takes in a function to get the newpass, rather than the password itself diff --git a/types/rational.go b/types/rational.go index d30903ac28de..cb07bf5437b2 100644 --- a/types/rational.go +++ b/types/rational.go @@ -253,7 +253,7 @@ func RatEq(t *testing.T, exp, got Rat) (*testing.T, bool, string, Rat, Rat) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got } -// test if two rat arrays are the equal +// minimum rational between two func MinRat(r1, r2 Rat) Rat { if r1.LT(r2) { return r1 diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 0b0f10777393..06273d6af77c 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -446,9 +446,7 @@ func TestValidatorBondHeight(t *testing.T) { validators[1], pool, _ = validators[1].AddTokensFromDel(pool, 50) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, 50) keeper.SetPool(ctx, pool) - //require.NotPanics(t, func() { validators[2] = keeper.UpdateValidator(ctx, validators[2]) - //}) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, params.MaxValidators, uint16(len(resValidators))) validators[1] = keeper.UpdateValidator(ctx, validators[1]) diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index e3e721774ce5..59b519d2a466 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -58,7 +58,7 @@ func (p Pool) BondedRatio() sdk.Rat { //_______________________________________________________________________ -func (p Pool) addBondedTokens(bondedTokens sdk.Rat) Pool { +func (p Pool) looseTokensToBonded(bondedTokens sdk.Rat) Pool { p.BondedTokens = p.BondedTokens.Add(bondedTokens) p.LooseTokens = p.LooseTokens.Sub(bondedTokens) if p.LooseTokens.LT(sdk.ZeroRat()) { @@ -67,7 +67,7 @@ func (p Pool) addBondedTokens(bondedTokens sdk.Rat) Pool { return p } -func (p Pool) removeBondedTokens(bondedTokens sdk.Rat) Pool { +func (p Pool) bondedTokensToLoose(bondedTokens sdk.Rat) Pool { p.BondedTokens = p.BondedTokens.Sub(bondedTokens) p.LooseTokens = p.LooseTokens.Add(bondedTokens) if p.BondedTokens.LT(sdk.ZeroRat()) { diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 0dc00be2e607..43a2eac065a4 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -20,7 +20,7 @@ func TestAddBondedTokens(t *testing.T) { pool.LooseTokens = sdk.NewRat(10) pool.BondedTokens = sdk.NewRat(10) - pool = pool.addBondedTokens(sdk.NewRat(10)) + pool = pool.looseTokensToBonded(sdk.NewRat(10)) require.True(sdk.RatEq(t, sdk.NewRat(20), pool.BondedTokens)) require.True(sdk.RatEq(t, sdk.NewRat(0), pool.LooseTokens)) @@ -31,7 +31,7 @@ func TestRemoveBondedTokens(t *testing.T) { pool.LooseTokens = sdk.NewRat(10) pool.BondedTokens = sdk.NewRat(10) - pool = pool.removeBondedTokens(sdk.NewRat(5)) + pool = pool.bondedTokensToLoose(sdk.NewRat(5)) require.True(sdk.RatEq(t, sdk.NewRat(5), pool.BondedTokens)) require.True(sdk.RatEq(t, sdk.NewRat(15), pool.LooseTokens)) diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 8b6b588abd9d..12551db67043 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -206,6 +206,7 @@ func (v Validator) Bech32Validator() (BechValidator, error) { //___________________________________________________________________ // only the vitals - does not check bond height of IntraTxCounter +// nolint gocyclo - why dis fail? func (v Validator) Equal(c2 Validator) bool { return v.PubKey.Equals(c2.PubKey) && bytes.Equal(v.Owner, c2.Owner) && @@ -309,7 +310,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Unbonded: return v, pool case sdk.Bonded: - pool = pool.addBondedTokens(v.Tokens) + pool = pool.looseTokensToBonded(v.Tokens) } case sdk.Unbonding: @@ -317,7 +318,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Unbonding: return v, pool case sdk.Bonded: - pool = pool.addBondedTokens(v.Tokens) + pool = pool.looseTokensToBonded(v.Tokens) } case sdk.Bonded: @@ -325,7 +326,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Bonded: return v, pool default: - pool = pool.removeBondedTokens(v.Tokens) + pool = pool.bondedTokensToLoose(v.Tokens) } } @@ -336,7 +337,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, // removes tokens from a validator func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { if v.Status == sdk.Bonded { - pool = pool.removeBondedTokens(tokens) + pool = pool.bondedTokensToLoose(tokens) } v.Tokens = v.Tokens.Sub(tokens) @@ -352,7 +353,7 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s exRate := v.DelegatorShareExRate() if v.Status == sdk.Bonded { - pool = pool.addBondedTokens(sdk.NewRat(amount)) + pool = pool.looseTokensToBonded(sdk.NewRat(amount)) } amountRat := sdk.NewRat(amount) @@ -373,7 +374,7 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Poo v.DelegatorShares = v.DelegatorShares.Sub(delShares) if v.Status == sdk.Bonded { - pool = pool.removeBondedTokens(issuedTokens) + pool = pool.bondedTokensToLoose(issuedTokens) } return v, pool, issuedTokens diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index abaad2c0f62e..8d97cbce749e 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -177,8 +177,6 @@ func TestRemoveDelShares(t *testing.T) { Inflation: sdk.NewRat(7, 100), } shares := sdk.NewRat(29) - msg := fmt.Sprintf("validator %#v", validator) - msg = fmt.Sprintf("Removed %v shares from %s", shares, msg) _, newPool, tokens := validator.RemoveDelShares(pool, shares) require.True(sdk.RatEq(t, sdk.NewRat(147958, 115), tokens)) require.True(sdk.RatEq(t, From 754baa7239e3db9c8ef0a2ac0c2c471a2244e3f7 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 13 Jul 2018 03:39:46 -0400 Subject: [PATCH 19/25] cli bugfixes --- cmd/gaia/cli_test/cli_test.go | 5 +++-- x/stake/types/validator.go | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index e37e4d52199a..df238f5dc202 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -131,7 +131,8 @@ func TestGaiaCLICreateValidator(t *testing.T) { validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) require.Equal(t, validator.Owner, barAddr) - require.Equal(t, "2/1", validator.PoolShares.Amount.String()) + require.Fail(t, "", "validator %v", validator) + require.Equal(t, "2/1", validator.Tokens.String()) // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) @@ -149,7 +150,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc) */ validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) - require.Equal(t, "1/1", validator.PoolShares.Amount.String()) + require.Equal(t, "1/1", validator.Tokens.String()) } func TestGaiaCLISubmitProposal(t *testing.T) { diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 12551db67043..fbe6820b283e 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -27,8 +27,8 @@ type Validator struct { PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? - Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) + Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator @@ -70,8 +70,8 @@ func NewValidator(owner sdk.AccAddress, pubKey crypto.PubKey, description Descri type validatorValue struct { PubKey crypto.PubKey Revoked bool - Tokens sdk.Rat Status sdk.BondStatus + Tokens sdk.Rat DelegatorShares sdk.Rat Description Description BondHeight int64 @@ -89,8 +89,8 @@ func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte { val := validatorValue{ PubKey: validator.PubKey, Revoked: validator.Revoked, - Tokens: validator.Tokens, Status: validator.Status, + Tokens: validator.Tokens, DelegatorShares: validator.DelegatorShares, Description: validator.Description, BondHeight: validator.BondHeight, @@ -155,8 +155,8 @@ type BechValidator struct { PubKey string `json:"pub_key"` // in bech32 Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? - Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) + Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator @@ -185,8 +185,8 @@ func (v Validator) Bech32Validator() (BechValidator, error) { PubKey: bechValPubkey, Revoked: v.Revoked, - Tokens: v.Tokens, Status: v.Status, + Tokens: v.Tokens, DelegatorShares: v.DelegatorShares, Description: v.Description, @@ -210,8 +210,8 @@ func (v Validator) Bech32Validator() (BechValidator, error) { func (v Validator) Equal(c2 Validator) bool { return v.PubKey.Equals(c2.PubKey) && bytes.Equal(v.Owner, c2.Owner) && - v.Tokens.Equal(c2.Tokens) && v.Status.Equal(c2.Status) && + v.Tokens.Equal(c2.Tokens) && v.DelegatorShares.Equal(c2.DelegatorShares) && v.Description == c2.Description && v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) && From a97101dfcd38a8ed15fa0bdd55c59f68af872652 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 13 Jul 2018 03:40:29 -0400 Subject: [PATCH 20/25] .. --- cmd/gaia/cli_test/cli_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index df238f5dc202..14b249482c5d 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -131,7 +131,6 @@ func TestGaiaCLICreateValidator(t *testing.T) { validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) require.Equal(t, validator.Owner, barAddr) - require.Fail(t, "", "validator %v", validator) require.Equal(t, "2/1", validator.Tokens.String()) // unbond a single share From b3111bc52ba324e7689182a74fd5b318355e1e8d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 13 Jul 2018 03:46:58 -0400 Subject: [PATCH 21/25] cli fixed --- cmd/gaia/cli_test/cli_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 14b249482c5d..650021d315ab 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -131,7 +131,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) require.Equal(t, validator.Owner, barAddr) - require.Equal(t, "2/1", validator.Tokens.String()) + require.True(sdk.RatEq(t, sdk.NewRat(2), validator.Tokens)) // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) From 15656458e95c8390bac58b69f693fa53d52663c0 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 13 Jul 2018 03:54:31 -0400 Subject: [PATCH 22/25] spec update --- docs/spec/staking/state.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index f337f4f71c49..58cf1f9fd4b5 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -6,29 +6,18 @@ - value: `amino(pool)` The pool is a space for all dynamic global state of the Cosmos Hub. It tracks -information about the total amounts of Atoms in all states, representative -validator shares for stake in the global pools, moving Atom inflation -information, etc. +information about the total amounts of Atoms in all states, moving Atom +inflation information, etc. ```golang type Pool struct { LooseTokens int64 // tokens not associated with any validator - UnbondedTokens int64 // reserve of unbonded tokens held with validators - UnbondingTokens int64 // tokens moving from bonded to unbonded pool BondedTokens int64 // reserve of bonded tokens - UnbondedShares sdk.Rat // sum of all shares distributed for the Unbonded Pool - UnbondingShares sdk.Rat // shares moving from Bonded to Unbonded Pool - BondedShares sdk.Rat // sum of all shares distributed for the Bonded Pool InflationLastTime int64 // block which the last inflation was processed // TODO make time Inflation sdk.Rat // current annual inflation rate DateLastCommissionReset int64 // unix timestamp for last commission accounting reset (daily) } - -type PoolShares struct { - Status sdk.BondStatus // either: unbonded, unbonding, or bonded - Amount sdk.Rat // total shares of type ShareKind -} ``` ### Params @@ -85,7 +74,9 @@ type Validator struct { ConsensusPubKey crypto.PubKey // Tendermint consensus pubkey of validator Revoked bool // has the validator been revoked? - PoolShares PoolShares // total shares for tokens held in the pool + PoolShares sdk.BondStatus // total shares for tokens held in the pool + Status sdk.BondStatus // validator status (bonded/unbonding/unbonded) + Tokens sdk.Rat // delegated tokens (incl. self-delegation) DelegatorShares sdk.Rat // total shares issued to a validator's delegators SlashRatio sdk.Rat // increases each time the validator is slashed From 54c0bdb3829439e64ac669539eb9875f941d076b Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 13 Jul 2018 19:57:09 +0200 Subject: [PATCH 23/25] 'make format' --- store/tracekvstore_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/store/tracekvstore_test.go b/store/tracekvstore_test.go index e6f1bf363385..2182c5288634 100644 --- a/store/tracekvstore_test.go +++ b/store/tracekvstore_test.go @@ -11,9 +11,9 @@ import ( ) var kvPairs = []KVPair{ - KVPair{Key: keyFmt(1), Value: valFmt(1)}, - KVPair{Key: keyFmt(2), Value: valFmt(2)}, - KVPair{Key: keyFmt(3), Value: valFmt(3)}, + {Key: keyFmt(1), Value: valFmt(1)}, + {Key: keyFmt(2), Value: valFmt(2)}, + {Key: keyFmt(3), Value: valFmt(3)}, } func newTraceKVStore(w io.Writer) *TraceKVStore { From 813087ae9a64c7736957691bb12fa5dc3c36f4c7 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 13 Jul 2018 15:09:40 -0400 Subject: [PATCH 24/25] cwgoes comments --- docs/spec/staking/state.md | 5 ++--- x/stake/handler.go | 2 +- x/stake/keeper/slash.go | 8 ++++---- x/stake/types/pool.go | 5 +++-- x/stake/types/validator.go | 25 +++++++++++-------------- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index 58cf1f9fd4b5..76101e609750 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -11,7 +11,7 @@ inflation information, etc. ```golang type Pool struct { - LooseTokens int64 // tokens not associated with any validator + LooseTokens int64 // tokens not associated with any bonded validator BondedTokens int64 // reserve of bonded tokens InflationLastTime int64 // block which the last inflation was processed // TODO make time Inflation sdk.Rat // current annual inflation rate @@ -74,7 +74,6 @@ type Validator struct { ConsensusPubKey crypto.PubKey // Tendermint consensus pubkey of validator Revoked bool // has the validator been revoked? - PoolShares sdk.BondStatus // total shares for tokens held in the pool Status sdk.BondStatus // validator status (bonded/unbonding/unbonded) Tokens sdk.Rat // delegated tokens (incl. self-delegation) DelegatorShares sdk.Rat // total shares issued to a validator's delegators @@ -91,7 +90,7 @@ type Validator struct { ProposerRewardPool sdk.Coins // reward pool collected from being the proposer // TODO: maybe this belongs in distribution module ? - PrevPoolShares PoolShares // total shares of a global hold pools + LastBondedTokens sdk.Rat // last bonded token amount } type CommissionInfo struct { diff --git a/x/stake/handler.go b/x/stake/handler.go index b690d790dff3..b39298edebc1 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -41,7 +41,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid blockTime := ctx.BlockHeader().Time if pool.InflationLastTime+blockTime >= 3600 { pool.InflationLastTime = blockTime - pool.ProcessProvisions(params) + pool = pool.ProcessProvisions(params) } // save the params diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 8cc44464b2af..fb9297e9cae5 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -89,14 +89,14 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // Cannot decrease balance below zero - burned := sdk.MinRat(remainingSlashAmount, validator.Tokens) + tokensToBurn := sdk.MinRat(remainingSlashAmount, validator.Tokens) // Get the current pool pool := k.GetPool(ctx) // remove tokens from the validator - validator, pool = validator.RemoveTokens(pool, burned) + validator, pool = validator.RemoveTokens(pool, tokensToBurn) // burn tokens - pool.LooseTokens = pool.LooseTokens.Sub(burned) + pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) // update the pool k.SetPool(ctx, pool) // update the validator, possibly kicking it out @@ -109,7 +109,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // Log that a slash occurred! logger.Info(fmt.Sprintf( "Validator %s slashed by slashFactor %v, burned %v tokens", - pubkey.Address(), slashFactor, burned)) + pubkey.Address(), slashFactor, tokensToBurn)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 59b519d2a466..01dfacadafd7 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -50,8 +50,9 @@ func (p Pool) TokenSupply() sdk.Rat { // get the bond ratio of the global state func (p Pool) BondedRatio() sdk.Rat { - if p.TokenSupply().GT(sdk.ZeroRat()) { - return p.BondedTokens.Quo(p.TokenSupply()) + supply := p.TokenSupply() + if supply.GT(sdk.ZeroRat()) { + return p.BondedTokens.Quo(supply) } return sdk.ZeroRat() } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index fbe6820b283e..ed109830f035 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -42,7 +42,7 @@ type Validator struct { CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related - PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools + LastBondedTokens sdk.Rat `json:"prev_bonded_tokens"` // Previous bonded tokens held } // NewValidator - initialize a new validator @@ -62,7 +62,7 @@ func NewValidator(owner sdk.AccAddress, pubKey crypto.PubKey, description Descri CommissionMax: sdk.ZeroRat(), CommissionChangeRate: sdk.ZeroRat(), CommissionChangeToday: sdk.ZeroRat(), - PrevBondedShares: sdk.ZeroRat(), + LastBondedTokens: sdk.ZeroRat(), } } @@ -81,7 +81,7 @@ type validatorValue struct { CommissionMax sdk.Rat CommissionChangeRate sdk.Rat CommissionChangeToday sdk.Rat - PrevBondedShares sdk.Rat + LastBondedTokens sdk.Rat } // return the redelegation without fields contained within the key for the store @@ -100,7 +100,7 @@ func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte { CommissionMax: validator.CommissionMax, CommissionChangeRate: validator.CommissionChangeRate, CommissionChangeToday: validator.CommissionChangeToday, - PrevBondedShares: validator.PrevBondedShares, + LastBondedTokens: validator.LastBondedTokens, } return cdc.MustMarshalBinary(val) } @@ -143,7 +143,7 @@ func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Val CommissionMax: storeValue.CommissionMax, CommissionChangeRate: storeValue.CommissionChangeRate, CommissionChangeToday: storeValue.CommissionChangeToday, - PrevBondedShares: storeValue.PrevBondedShares, + LastBondedTokens: storeValue.LastBondedTokens, }, nil } @@ -170,7 +170,7 @@ type BechValidator struct { CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related - PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools + LastBondedTokens sdk.Rat `json:"prev_bonded_shares"` // last bonded token amount } // get the bech validator from the the regular validator @@ -199,7 +199,7 @@ func (v Validator) Bech32Validator() (BechValidator, error) { CommissionChangeRate: v.CommissionChangeRate, CommissionChangeToday: v.CommissionChangeToday, - PrevBondedShares: v.PrevBondedShares, + LastBondedTokens: v.LastBondedTokens, }, nil } @@ -219,7 +219,7 @@ func (v Validator) Equal(c2 Validator) bool { v.CommissionMax.Equal(c2.CommissionMax) && v.CommissionChangeRate.Equal(c2.CommissionChangeRate) && v.CommissionChangeToday.Equal(c2.CommissionChangeToday) && - v.PrevBondedShares.Equal(c2.PrevBondedShares) + v.LastBondedTokens.Equal(c2.LastBondedTokens) } // Description - description fields for a validator @@ -351,12 +351,12 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s // bondedShare/delegatedShare exRate := v.DelegatorShareExRate() + amountRat := sdk.NewRat(amount) if v.Status == sdk.Bonded { - pool = pool.looseTokensToBonded(sdk.NewRat(amount)) + pool = pool.looseTokensToBonded(amountRat) } - amountRat := sdk.NewRat(amount) v.Tokens = v.Tokens.Add(amountRat) issuedShares := amountRat.Quo(exRate) v.DelegatorShares = v.DelegatorShares.Add(issuedShares) @@ -365,9 +365,6 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s } // RemoveDelShares removes delegator shares from a validator. -// -// NOTE: This function assumes the shares have already been updated for the -// validator status. func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, sdk.Rat) { issuedTokens := v.DelegatorShareExRate().Mul(delShares) v.Tokens = v.Tokens.Sub(issuedTokens) @@ -434,7 +431,7 @@ func (v Validator) HumanReadableString() (string, error) { resp += fmt.Sprintf("Max Commission Rate: %s\n", v.CommissionMax.String()) resp += fmt.Sprintf("Commission Change Rate: %s\n", v.CommissionChangeRate.String()) resp += fmt.Sprintf("Commission Change Today: %s\n", v.CommissionChangeToday.String()) - resp += fmt.Sprintf("Previously Bonded Stares: %s\n", v.PrevBondedShares.String()) + resp += fmt.Sprintf("Previous Bonded Tokens: %s\n", v.LastBondedTokens.String()) return resp, nil } From f8d72bee5b88f1eda3f0bc076ed05341556b254d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 13 Jul 2018 21:54:56 +0200 Subject: [PATCH 25/25] Increase test_cover parallelism --- .circleci/config.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 155945ae6917..a8d42872e406 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -87,7 +87,7 @@ jobs: test_cover: <<: *defaults - parallelism: 2 + parallelism: 4 steps: - attach_workspace: at: /tmp/workspace @@ -103,7 +103,6 @@ jobs: make install for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v /vendor/ | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | circleci tests split --split-by=timings); do id=$(basename "$pkg") - GOCACHE=off go test -v -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" | tee "/tmp/logs/$id-$RANDOM.log" done - persist_to_workspace: