2018-01-25 19:31:07 -08:00
|
|
|
package stake
|
|
|
|
|
|
|
|
import (
|
2018-04-30 23:07:06 -07:00
|
|
|
"bytes"
|
|
|
|
|
2018-02-20 07:55:53 -08:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2018-04-25 07:12:59 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/wire"
|
2018-05-06 07:18:45 -07:00
|
|
|
abci "github.com/tendermint/abci/types"
|
|
|
|
crypto "github.com/tendermint/go-crypto"
|
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 {
|
2018-05-09 18:39:14 -07:00
|
|
|
Pool Pool `json:"pool"`
|
|
|
|
Params Params `json:"params"`
|
2018-05-09 21:01:58 -07:00
|
|
|
Validators []Validator `json:"validators"`
|
2018-05-09 18:39:14 -07:00
|
|
|
Bonds []Delegation `json:"bonds"`
|
2018-04-06 22:50:46 -07:00
|
|
|
}
|
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
func NewGenesisState(pool Pool, params Params, validators []Validator, bonds []Delegation) GenesisState {
|
2018-05-04 12:38:25 -07:00
|
|
|
return GenesisState{
|
|
|
|
Pool: pool,
|
|
|
|
Params: params,
|
2018-05-09 21:01:58 -07:00
|
|
|
Validators: validators,
|
2018-05-04 12:38:25 -07:00
|
|
|
Bonds: bonds,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 23:07:06 -07:00
|
|
|
// get raw genesis raw message for testing
|
|
|
|
func DefaultGenesisState() GenesisState {
|
|
|
|
return GenesisState{
|
|
|
|
Pool: initialPool(),
|
|
|
|
Params: defaultParams(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-06 22:50:46 -07:00
|
|
|
//_________________________________________________________________________
|
|
|
|
|
2018-01-31 18:56:46 -08: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-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 &&
|
2018-05-09 18:39:14 -07:00
|
|
|
p.BondDenom == p2.BondDenom
|
2018-04-30 23:07:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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-04-30 14:21:14 -07:00
|
|
|
}
|
|
|
|
|
2018-01-31 18:56:46 -08: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-05-09 21:01:58 -07:00
|
|
|
UnbondedPool int64 `json:"unbonded_pool"` // reserve of unbonded tokens held with validators
|
2018-03-16 12:47:17 -07:00
|
|
|
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
|
2018-04-30 23:07:06 -07:00
|
|
|
|
|
|
|
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-09 18:39:14 -07:00
|
|
|
PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // last recorded bonded shares - for fee calcualtions
|
2018-01-25 19:31:07 -08:00
|
|
|
}
|
|
|
|
|
2018-04-30 14:21:14 -07:00
|
|
|
func (p Pool) equal(p2 Pool) bool {
|
2018-04-30 23:07:06 -07:00
|
|
|
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 &&
|
2018-04-30 23:07:06 -07:00
|
|
|
p.InflationLastTime == p2.InflationLastTime &&
|
|
|
|
p.Inflation.Equal(p2.Inflation) &&
|
|
|
|
p.DateLastCommissionReset == p2.DateLastCommissionReset &&
|
2018-05-04 12:38:25 -07:00
|
|
|
p.PrevBondedShares.Equal(p2.PrevBondedShares)
|
2018-04-30 23:07:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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(),
|
2018-04-30 23:07:06 -07:00
|
|
|
UnbondedShares: sdk.ZeroRat(),
|
|
|
|
BondedPool: 0,
|
2018-05-04 12:38:25 -07:00
|
|
|
UnbondingPool: 0,
|
2018-04-30 23:07:06 -07:00
|
|
|
UnbondedPool: 0,
|
|
|
|
InflationLastTime: 0,
|
|
|
|
Inflation: sdk.NewRat(7, 100),
|
|
|
|
DateLastCommissionReset: 0,
|
2018-05-04 12:38:25 -07:00
|
|
|
PrevBondedShares: sdk.ZeroRat(),
|
2018-04-30 23:07:06 -07:00
|
|
|
}
|
2018-04-30 14:21:14 -07:00
|
|
|
}
|
|
|
|
|
2018-04-06 22:50:46 -07:00
|
|
|
//_________________________________________________________________________
|
2018-01-31 18:56:46 -08:00
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
// Validator defines the total amount of bond shares and their exchange rate to
|
2018-01-25 19:31:07 -08:00
|
|
|
// 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
|
2018-05-09 21:01:58 -07:00
|
|
|
// validator, the validator is credited with a Delegation whose number of
|
2018-01-25 19:31:07 -08:00
|
|
|
// 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.
|
2018-05-09 21:01:58 -07:00
|
|
|
type Validator struct {
|
2018-05-11 14:58:28 -07:00
|
|
|
Status sdk.BondStatus `json:"status"` // bonded status
|
|
|
|
Address sdk.Address `json:"address"` // sender of BondTx - UnbondTx returns here
|
|
|
|
PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator
|
|
|
|
|
|
|
|
// note: There should only be one of the following 3 shares ever active in a delegator
|
|
|
|
// multiple terms are only added here for clarity.
|
|
|
|
BondedShares sdk.Rat `json:"bonded_shares"` // total shares of bonded global hold pool
|
|
|
|
UnbondingShares sdk.Rat `json:"unbonding_shares"` // total shares of unbonding global hold pool
|
|
|
|
UnbondedShares sdk.Rat `json:"unbonded_shares"` // total shares of unbonded global hold pool
|
|
|
|
|
|
|
|
DelegatorShares sdk.Rat `json:"liabilities"` // total shares issued to a validator's delegators
|
|
|
|
|
|
|
|
Description Description `json:"description"` // description terms for the validator
|
|
|
|
BondHeight int64 `json:"validator_bond_height"` // earliest height as a bonded validator
|
|
|
|
BondIntraTxCounter int16 `json:"validator_bond_counter"` // block-local tx index of validator change
|
2018-05-10 16:02:35 -07:00
|
|
|
ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer
|
2018-05-04 12:38:25 -07:00
|
|
|
|
|
|
|
Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators
|
2018-05-09 21:01:58 -07:00
|
|
|
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
|
2018-05-04 12:38:25 -07:00
|
|
|
CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time)
|
|
|
|
|
|
|
|
// fee related
|
2018-05-09 18:39:14 -07:00
|
|
|
PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools
|
2018-01-25 19:31:07 -08:00
|
|
|
}
|
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
// Validators - list of Validators
|
|
|
|
type Validators []Validator
|
2018-04-06 22:50:46 -07:00
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
// NewValidator - initialize a new validator
|
|
|
|
func NewValidator(address sdk.Address, pubKey crypto.PubKey, description Description) Validator {
|
|
|
|
return Validator{
|
2018-05-10 16:02:35 -07:00
|
|
|
Status: sdk.Unbonded,
|
|
|
|
Address: address,
|
|
|
|
PubKey: pubKey,
|
|
|
|
BondedShares: sdk.ZeroRat(),
|
|
|
|
DelegatorShares: sdk.ZeroRat(),
|
|
|
|
Description: description,
|
|
|
|
BondHeight: int64(0),
|
|
|
|
BondIntraTxCounter: int16(0),
|
|
|
|
ProposerRewardPool: sdk.Coins{},
|
|
|
|
Commission: sdk.ZeroRat(),
|
|
|
|
CommissionMax: sdk.ZeroRat(),
|
|
|
|
CommissionChangeRate: sdk.ZeroRat(),
|
|
|
|
CommissionChangeToday: sdk.ZeroRat(),
|
|
|
|
PrevBondedShares: sdk.ZeroRat(),
|
2018-01-25 19:31:07 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
func (v Validator) equal(c2 Validator) bool {
|
|
|
|
return v.Status == c2.Status &&
|
|
|
|
v.PubKey.Equals(c2.PubKey) &&
|
|
|
|
bytes.Equal(v.Address, c2.Address) &&
|
|
|
|
v.BondedShares.Equal(c2.BondedShares) &&
|
|
|
|
v.DelegatorShares.Equal(c2.DelegatorShares) &&
|
|
|
|
v.Description == c2.Description &&
|
2018-05-10 16:02:35 -07:00
|
|
|
v.BondHeight == c2.BondHeight &&
|
|
|
|
//v.BondIntraTxCounter == c2.BondIntraTxCounter && // counter is always changing
|
2018-05-09 21:01:58 -07:00
|
|
|
v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) &&
|
|
|
|
v.Commission.Equal(c2.Commission) &&
|
|
|
|
v.CommissionMax.Equal(c2.CommissionMax) &&
|
|
|
|
v.CommissionChangeRate.Equal(c2.CommissionChangeRate) &&
|
|
|
|
v.CommissionChangeToday.Equal(c2.CommissionChangeToday) &&
|
|
|
|
v.PrevBondedShares.Equal(c2.PrevBondedShares)
|
2018-04-30 23:07:06 -07:00
|
|
|
}
|
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
// Description - description fields for a validator
|
2018-03-26 07:48:15 -07:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-31 18:56:46 -08:00
|
|
|
// get the exchange rate of global pool shares over delegator shares
|
2018-05-12 11:33:55 -07:00
|
|
|
func (v Validator) DelegatorShareExRate() sdk.Rat {
|
2018-05-09 21:01:58 -07:00
|
|
|
if v.DelegatorShares.IsZero() {
|
2018-04-30 14:21:14 -07:00
|
|
|
return sdk.OneRat()
|
2018-01-31 18:56:46 -08:00
|
|
|
}
|
2018-05-10 16:02:35 -07:00
|
|
|
switch v.Status {
|
|
|
|
case sdk.Bonded:
|
|
|
|
return v.BondedShares.Quo(v.DelegatorShares)
|
|
|
|
case sdk.Unbonding:
|
|
|
|
return v.UnbondingShares.Quo(v.DelegatorShares)
|
|
|
|
default: //sdk.Unbonded, sdk.Revoked:
|
|
|
|
return v.UnbondedShares.Quo(v.DelegatorShares)
|
|
|
|
}
|
2018-01-31 18:56:46 -08:00
|
|
|
}
|
|
|
|
|
2018-04-05 09:31:36 -07:00
|
|
|
// abci validator from stake validator type
|
2018-05-06 07:18:45 -07:00
|
|
|
func (v Validator) abciValidator(cdc *wire.Codec) abci.Validator {
|
|
|
|
return abci.Validator{
|
2018-04-16 13:47:28 -07:00
|
|
|
PubKey: v.PubKey.Bytes(),
|
2018-05-10 16:02:35 -07:00
|
|
|
Power: v.BondedShares.Evaluate(),
|
2018-04-04 20:22:13 -07:00
|
|
|
}
|
2018-01-31 18:56:46 -08:00
|
|
|
}
|
|
|
|
|
2018-04-05 09:31:36 -07:00
|
|
|
// abci validator from stake validator type
|
|
|
|
// with zero power used for validator updates
|
2018-05-06 07:18:45 -07:00
|
|
|
func (v Validator) abciValidatorZero(cdc *wire.Codec) abci.Validator {
|
|
|
|
return abci.Validator{
|
2018-04-16 13:47:28 -07:00
|
|
|
PubKey: v.PubKey.Bytes(),
|
2018-04-05 09:31:36 -07:00
|
|
|
Power: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
//XXX updateDescription function
|
|
|
|
//XXX enforce limit to number of description characters
|
2018-05-06 07:18:45 -07:00
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
//______________________________________________________________________
|
2018-05-06 07:18:45 -07:00
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
// ensure fulfills the sdk validator types
|
|
|
|
var _ sdk.Validator = Validator{}
|
2018-05-06 07:18:45 -07:00
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
// nolint - for sdk.Validator
|
2018-05-11 14:58:28 -07:00
|
|
|
func (v Validator) GetStatus() sdk.BondStatus { return v.Status }
|
2018-05-10 16:02:35 -07:00
|
|
|
func (v Validator) GetAddress() sdk.Address { return v.Address }
|
|
|
|
func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey }
|
|
|
|
func (v Validator) GetPower() sdk.Rat { return v.BondedShares }
|
|
|
|
func (v Validator) GetBondHeight() int64 { return v.BondHeight }
|
2018-05-04 18:29:12 -07:00
|
|
|
|
2018-01-31 18:56:46 -08:00
|
|
|
//_________________________________________________________________________
|
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
// Delegation represents the bond with tokens held by an account. It is
|
2018-01-31 18:56:46 -08:00
|
|
|
// 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-05-09 18:39:14 -07:00
|
|
|
type Delegation struct {
|
2018-04-17 21:33:33 -07:00
|
|
|
DelegatorAddr sdk.Address `json:"delegator_addr"`
|
2018-05-09 21:01:58 -07:00
|
|
|
ValidatorAddr sdk.Address `json:"validator_addr"`
|
2018-03-20 06:56:07 -07:00
|
|
|
Shares sdk.Rat `json:"shares"`
|
2018-04-23 09:32:55 -07:00
|
|
|
Height int64 `json:"height"` // Last height bond updated
|
2018-03-14 11:42:50 -07:00
|
|
|
}
|
2018-04-30 23:07:06 -07:00
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
func (b Delegation) equal(b2 Delegation) bool {
|
2018-04-30 23:07:06 -07:00
|
|
|
return bytes.Equal(b.DelegatorAddr, b2.DelegatorAddr) &&
|
2018-05-09 21:01:58 -07:00
|
|
|
bytes.Equal(b.ValidatorAddr, b2.ValidatorAddr) &&
|
2018-04-30 23:07:06 -07:00
|
|
|
b.Height == b2.Height &&
|
|
|
|
b.Shares.Equal(b2.Shares)
|
|
|
|
}
|
2018-05-06 11:39:50 -07:00
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
// ensure fulfills the sdk validator types
|
|
|
|
var _ sdk.Delegation = Delegation{}
|
2018-05-06 11:39:50 -07:00
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
// nolint - for sdk.Delegation
|
|
|
|
func (b Delegation) GetDelegator() sdk.Address { return b.DelegatorAddr }
|
2018-05-09 21:01:58 -07:00
|
|
|
func (b Delegation) GetValidator() sdk.Address { return b.ValidatorAddr }
|
2018-05-10 16:02:35 -07:00
|
|
|
func (b Delegation) GetBondShares() sdk.Rat { return b.Shares }
|