cosmos-sdk/x/stake/types.go

337 lines
13 KiB
Go
Raw Normal View History

2018-01-25 19:31:07 -08:00
package stake
import (
"bytes"
2018-02-20 07:55:53 -08:00
sdk "github.com/cosmos/cosmos-sdk/types"
2018-01-25 19:31:07 -08:00
crypto "github.com/tendermint/go-crypto"
2018-04-25 07:12:59 -07:00
"github.com/cosmos/cosmos-sdk/wire"
2018-01-25 19:31:07 -08:00
)
2018-04-06 22:50:46 -07:00
// GenesisState - all staking state that must be provided at genesis
type GenesisState struct {
Pool Pool `json:"pool"`
Params Params `json:"params"`
Candidates []Candidate `json:"candidates"`
Bonds []DelegatorBond `json:"bonds"`
2018-04-06 22:50:46 -07:00
}
2018-05-04 12:38:25 -07:00
func NewGenesisState(pool Pool, params Params, candidates []Candidate, bonds []DelegatorBond) GenesisState {
return GenesisState{
Pool: pool,
Params: params,
Candidates: candidates,
Bonds: bonds,
}
}
// get raw genesis raw message for testing
func DefaultGenesisState() GenesisState {
return GenesisState{
Pool: initialPool(),
Params: defaultParams(),
}
}
2018-04-06 22:50:46 -07:00
//_________________________________________________________________________
// Params defines the high level settings for staking
2018-01-25 19:31:07 -08:00
type Params struct {
2018-03-16 12:47:17 -07:00
InflationRateChange sdk.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate
InflationMax sdk.Rat `json:"inflation_max"` // maximum inflation rate
InflationMin sdk.Rat `json:"inflation_min"` // minimum inflation rate
GoalBonded sdk.Rat `json:"goal_bonded"` // Goal of percent bonded atoms
2018-01-25 19:31:07 -08:00
2018-03-20 06:56:07 -07:00
MaxValidators uint16 `json:"max_validators"` // maximum number of validators
BondDenom string `json:"bond_denom"` // bondable coin denomination
2018-05-04 14:44:52 -07:00
FeeDenoms []string `json:"fee_denoms"` // accepted fee denoms
2018-05-04 12:38:25 -07:00
ReservePoolFee sdk.Rat `json:"reserve_pool_fee"` // percent of fees which go to reserve pool
2018-01-25 19:31:07 -08:00
}
2018-04-30 14:21:14 -07:00
func (p Params) equal(p2 Params) bool {
return p.InflationRateChange.Equal(p2.InflationRateChange) &&
p.InflationMax.Equal(p2.InflationMax) &&
p.InflationMin.Equal(p2.InflationMin) &&
p.GoalBonded.Equal(p2.GoalBonded) &&
p.MaxValidators == p2.MaxValidators &&
p.BondDenom == p2.BondDenom &&
p.ReservePoolFee.Equal(p2.ReservePoolFee)
}
func defaultParams() Params {
return Params{
InflationRateChange: sdk.NewRat(13, 100),
InflationMax: sdk.NewRat(20, 100),
InflationMin: sdk.NewRat(7, 100),
GoalBonded: sdk.NewRat(67, 100),
MaxValidators: 100,
BondDenom: "steak",
2018-05-04 12:38:25 -07:00
FeeDenoms: []string{"steak"},
ReservePoolFee: sdk.NewRat(5, 100),
}
2018-04-30 14:21:14 -07:00
}
//_________________________________________________________________________
2018-03-22 09:00:45 -07:00
// Pool - dynamic parameters of the current state
type Pool struct {
2018-03-16 12:47:17 -07:00
TotalSupply int64 `json:"total_supply"` // total supply of all tokens
BondedShares sdk.Rat `json:"bonded_shares"` // sum of all shares distributed for the Bonded Pool
2018-05-04 12:38:25 -07:00
UnbondingShares sdk.Rat `json:"unbonding_shares"` // shares moving from Bonded to Unbonded Pool
2018-03-16 12:47:17 -07:00
UnbondedShares sdk.Rat `json:"unbonded_shares"` // sum of all shares distributed for the Unbonded Pool
BondedPool int64 `json:"bonded_pool"` // reserve of bonded tokens
2018-05-04 14:44:52 -07:00
UnbondingPool int64 `json:"unbonding_pool"` // tokens moving from bonded to unbonded pool
2018-03-16 12:47:17 -07:00
UnbondedPool int64 `json:"unbonded_pool"` // reserve of unbonded tokens held with candidates
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
DateLastCommissionReset int64 `json:"date_last_commission_reset"` // unix timestamp for last commission accounting reset (daily)
2018-05-04 12:38:25 -07:00
// Fee Related
2018-05-04 14:44:52 -07:00
FeeReservePool sdk.Coins `json:"fee_reserve_pool"` // XXX reserve pool of collected fees for use by governance
FeePool sdk.Coins `json:"fee_pool"` // XXX fee pool for all the fee shares which have already been distributed
FeeSumReceived sdk.Coins `json:"fee_sum_received"` // XXX sum of all fees received, post reserve pool `json:"fee_sum_received"`
FeeRecent sdk.Coins `json:"fee_recent"` // XXX most recent fee collected
FeeAdjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms
PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // XXX last recorded bonded shares
2018-01-25 19:31:07 -08:00
}
2018-04-30 14:21:14 -07:00
func (p Pool) equal(p2 Pool) bool {
return p.TotalSupply == p2.TotalSupply &&
p.BondedShares.Equal(p2.BondedShares) &&
2018-04-30 14:21:14 -07:00
p.UnbondedShares.Equal(p2.UnbondedShares) &&
p.BondedPool == p2.BondedPool &&
p.UnbondedPool == p2.UnbondedPool &&
p.InflationLastTime == p2.InflationLastTime &&
p.Inflation.Equal(p2.Inflation) &&
p.DateLastCommissionReset == p2.DateLastCommissionReset &&
2018-05-04 12:38:25 -07:00
p.FeeReservePool.IsEqual(p2.FeeReservePool) &&
p.FeePool.IsEqual(p2.FeePool) &&
2018-05-04 12:38:25 -07:00
p.FeeSumReceived.IsEqual(p2.FeeSumReceived) &&
p.FeeRecent.IsEqual(p2.FeeRecent) &&
sdk.RatsEqual(p.FeeAdjustments, p2.FeeAdjustments) &&
p.PrevBondedShares.Equal(p2.PrevBondedShares)
}
// initial pool for testing
func initialPool() Pool {
return Pool{
TotalSupply: 0,
BondedShares: sdk.ZeroRat(),
2018-05-04 12:38:25 -07:00
UnbondingShares: sdk.ZeroRat(),
UnbondedShares: sdk.ZeroRat(),
BondedPool: 0,
2018-05-04 12:38:25 -07:00
UnbondingPool: 0,
UnbondedPool: 0,
InflationLastTime: 0,
Inflation: sdk.NewRat(7, 100),
DateLastCommissionReset: 0,
2018-05-04 12:38:25 -07:00
FeeReservePool: sdk.Coins(nil),
FeePool: sdk.Coins(nil),
2018-05-04 12:38:25 -07:00
FeeSumReceived: sdk.Coins(nil),
FeeRecent: sdk.Coins(nil),
2018-05-04 14:44:52 -07:00
FeeAdjustments: []sdk.Rat{sdk.ZeroRat()},
2018-05-04 12:38:25 -07:00
PrevBondedShares: sdk.ZeroRat(),
}
2018-04-30 14:21:14 -07:00
}
2018-04-06 22:50:46 -07:00
//_________________________________________________________________________
2018-05-03 23:00:30 -07:00
// Used in calculation of fee shares, added to a queue for each block where a power change occures
type PowerChange struct {
Height int64 `json:"height"` // block height at change
Power sdk.Rat `json:"power"` // total power at change
PrevPower sdk.Rat `json:"prev_power"` // total power at previous height-1
FeesIn sdk.Coins `json:"fees_in"` // fees in at block height
PrevFeePool sdk.Coins `json:"prev_fee_pool"` // total fees in at previous block height
}
//_________________________________________________________________________
2018-01-25 19:31:07 -08:00
// CandidateStatus - status of a validator-candidate
type CandidateStatus byte
const (
// nolint
Bonded CandidateStatus = 0x00
Unbonded CandidateStatus = 0x01
Revoked CandidateStatus = 0x02
)
// Candidate defines the total amount of bond shares and their exchange rate to
// coins. Accumulation of interest is modelled as an in increase in the
// exchange rate, and slashing as a decrease. When coins are delegated to this
// candidate, the candidate is credited with a DelegatorBond whose number of
// bond shares is based on the amount of coins delegated divided by the current
// exchange rate. Voting power can be calculated as total bonds multiplied by
// exchange rate.
type Candidate struct {
2018-05-04 14:44:52 -07:00
Status CandidateStatus `json:"status"` // Bonded status
Address sdk.Address `json:"owner"` // Sender of BondTx - UnbondTx returns here
PubKey crypto.PubKey `json:"pub_key"` // Pubkey of candidate
BondedShares sdk.Rat `json:"bonded_shares"` // total shares of a global hold pools
UnbondingShares sdk.Rat `json:"unbonding_shares"` // total shares of a global hold pools
UnbondedShares sdk.Rat `json:"unbonded_shares"` // total shares of a global hold pools
DelegatorShares sdk.Rat `json:"liabilities"` // total shares issued to a candidate's delegators
2018-05-04 12:38:25 -07:00
Description Description `json:"description"` // Description terms for the candidate
ValidatorBondHeight int64 `json:"validator_bond_height"` // Earliest height as a bonded validator
ValidatorBondCounter int16 `json:"validator_bond_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 candidate can ever charge
CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the candidate commission
CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time)
// fee related
2018-05-04 14:44:52 -07:00
FeeAdjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms
PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools
2018-01-25 19:31:07 -08:00
}
2018-04-06 22:50:46 -07:00
// Candidates - list of Candidates
type Candidates []Candidate
2018-01-25 19:31:07 -08:00
// NewCandidate - initialize a new candidate
2018-03-20 14:21:18 -07:00
func NewCandidate(address sdk.Address, pubKey crypto.PubKey, description Description) Candidate {
return Candidate{
Status: Unbonded,
Address: address,
PubKey: pubKey,
2018-05-04 12:38:25 -07:00
BondedShares: sdk.ZeroRat(),
DelegatorShares: sdk.ZeroRat(),
Description: description,
ValidatorBondHeight: int64(0),
ValidatorBondCounter: int16(0),
ProposerRewardPool: sdk.Coins{},
Commission: sdk.ZeroRat(),
CommissionMax: sdk.ZeroRat(),
CommissionChangeRate: sdk.ZeroRat(),
CommissionChangeToday: sdk.ZeroRat(),
2018-05-04 12:38:25 -07:00
FeeAdjustments: []sdk.Rat(nil),
PrevBondedShares: sdk.ZeroRat(),
2018-01-25 19:31:07 -08:00
}
}
func (c Candidate) equal(c2 Candidate) bool {
return c.Status == c2.Status &&
c.PubKey.Equals(c2.PubKey) &&
bytes.Equal(c.Address, c2.Address) &&
2018-05-04 12:38:25 -07:00
c.BondedShares.Equal(c2.BondedShares) &&
c.DelegatorShares.Equal(c2.DelegatorShares) &&
c.Description == c2.Description &&
c.ValidatorBondHeight == c2.ValidatorBondHeight &&
//c.ValidatorBondCounter == c2.ValidatorBondCounter && // counter is always changing
c.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) &&
c.Commission.Equal(c2.Commission) &&
c.CommissionMax.Equal(c2.CommissionMax) &&
c.CommissionChangeRate.Equal(c2.CommissionChangeRate) &&
2018-05-04 12:38:25 -07:00
c.CommissionChangeToday.Equal(c2.CommissionChangeToday) &&
sdk.RatsEqual(c.FeeAdjustments, c2.FeeAdjustments) &&
c.PrevBondedShares.Equal(c2.PrevBondedShares)
}
2018-03-26 07:48:15 -07:00
// Description - description fields for a candidate
type Description struct {
Moniker string `json:"moniker"`
Identity string `json:"identity"`
Website string `json:"website"`
Details string `json:"details"`
}
func NewDescription(moniker, identity, website, details string) Description {
return Description{
Moniker: moniker,
Identity: identity,
Website: website,
Details: details,
}
}
// get the exchange rate of global pool shares over delegator shares
2018-03-20 14:21:18 -07:00
func (c Candidate) delegatorShareExRate() sdk.Rat {
2018-05-04 12:38:25 -07:00
if c.DelegatorShares.IsZero() {
2018-04-30 14:21:14 -07:00
return sdk.OneRat()
}
2018-05-04 12:38:25 -07:00
return c.BondedShares.Quo(c.DelegatorShares)
}
// Validator returns a copy of the Candidate as a Validator.
// Should only be called when the Candidate qualifies as a validator.
func (c Candidate) validator() Validator {
return Validator{
Address: c.Address,
PubKey: c.PubKey,
2018-05-04 12:38:25 -07:00
Power: c.BondedShares,
Height: c.ValidatorBondHeight,
Counter: c.ValidatorBondCounter,
}
}
2018-03-20 06:56:07 -07:00
//XXX updateDescription function
//XXX enforce limit to number of description characters
//______________________________________________________________________
// Validator is one of the top Candidates
type Validator struct {
Address sdk.Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
2018-05-04 14:44:52 -07:00
Power sdk.Rat `json:"power"`
Height int64 `json:"height"` // Earliest height as a validator
Counter int16 `json:"counter"` // Block-local tx index for resolving equal voting power & height
}
2018-05-04 18:29:12 -07:00
// verify equal not including height or counter
func (v Validator) equal(v2 Validator) bool {
return bytes.Equal(v.Address, v2.Address) &&
v.PubKey.Equals(v2.PubKey) &&
2018-05-04 18:29:12 -07:00
v.Power.Equal(v2.Power)
}
// abci validator from stake validator type
2018-04-25 07:12:59 -07:00
func (v Validator) abciValidator(cdc *wire.Codec) sdk.Validator {
return sdk.Validator{
2018-04-16 13:47:28 -07:00
PubKey: v.PubKey.Bytes(),
Power: v.Power.Evaluate(),
}
}
// abci validator from stake validator type
// with zero power used for validator updates
2018-04-25 07:12:59 -07:00
func (v Validator) abciValidatorZero(cdc *wire.Codec) sdk.Validator {
return sdk.Validator{
2018-04-16 13:47:28 -07:00
PubKey: v.PubKey.Bytes(),
Power: 0,
}
}
2018-05-04 18:29:12 -07:00
// sortable validator list for testing
type validators []Validator
func (v validators) Len() int { return len(v) }
func (v validators) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v validators) Less(i, j int) bool { return v[i].Power.LT(v[j].Power) }
//_________________________________________________________________________
// DelegatorBond represents the bond with tokens held by an account. It is
// owned by one delegator, and is associated with the voting power of one
// pubKey.
2018-03-20 06:56:07 -07:00
// TODO better way of managing space
2018-01-25 19:31:07 -08:00
type DelegatorBond struct {
DelegatorAddr sdk.Address `json:"delegator_addr"`
2018-03-20 06:56:07 -07:00
CandidateAddr sdk.Address `json:"candidate_addr"`
Shares sdk.Rat `json:"shares"`
Height int64 `json:"height"` // Last height bond updated
}
func (b DelegatorBond) equal(b2 DelegatorBond) bool {
return bytes.Equal(b.DelegatorAddr, b2.DelegatorAddr) &&
bytes.Equal(b.CandidateAddr, b2.CandidateAddr) &&
b.Height == b2.Height &&
b.Shares.Equal(b2.Shares)
}