staking fee distribution working commit

This commit is contained in:
rigelrozanski 2018-05-01 02:07:06 -04:00
parent 8336eb9bc5
commit d871605241
11 changed files with 202 additions and 139 deletions

View File

@ -81,7 +81,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
app.SetInitChainer(app.initChainer)
app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper))
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, stake.FeeHandler))
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.stakeKeeper.FeeHandler))
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())

View File

@ -105,7 +105,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.GetDefaultGenesisState(),
StakeData: stake.DefaultGenesisState(),
}
stateBytes, err := wire.MarshalJSONIndent(gapp.cdc, genesisState)
@ -147,7 +147,7 @@ func setGenesisAccounts(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.GetDefaultGenesisState(),
StakeData: stake.DefaultGenesisState(),
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")

View File

@ -135,7 +135,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso
}
// start with the default staking genesis state
stakeData := stake.GetDefaultGenesisState()
stakeData := stake.DefaultGenesisState()
// get genesis flag account information
genaccs := make([]GenesisAccount, len(appGenTxs))

View File

@ -4,7 +4,7 @@ package types
type Handler func(ctx Context, msg Msg) Result
// core function variable which application runs to handle fees
type FeeHandler func(ctx Context, tx Tx, fee Coins)
type FeeHandler func(ctx Context, fee Coins)
// If newCtx.IsZero(), ctx is used instead.
type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool)

View File

@ -77,7 +77,7 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan
// TODO: min fee
if !fee.Amount.IsZero() {
signerAcc, res = deductFees(signerAcc, fee)
feeHandler(ctx, tx, fee.Amount)
feeHandler(ctx, fee.Amount)
if !res.IsOK() {
return ctx, res, true
}
@ -166,5 +166,5 @@ func deductFees(acc sdk.Account, fee sdk.StdFee) (sdk.Account, sdk.Result) {
}
// BurnFeeHandler burns all fees (decreasing total supply)
func BurnFeeHandler(ctx sdk.Context, tx sdk.Tx, fee sdk.Coins) {
func BurnFeeHandler(ctx sdk.Context, fee sdk.Coins) {
}

View File

@ -5,6 +5,35 @@ import (
)
// Handle fee distribution to the validators and delegators
func FeeHandler(ctx sdk.Context, tx sdk.Tx, fee sdk.Coins) {
func (k Keeper) FeeHandler(ctx sdk.Context, collectedFees sdk.Coins) {
pool := k.GetPool(ctx)
params := k.GetParams(ctx)
// XXX calculate
sumOfVotingPowerOfPrecommitValidators := sdk.NewRat(67, 100)
candidate := NewCandidate(addrs[0], pks[0], Description{})
toProposer := coinsMulRat(collectedFees, (sdk.NewRat(1, 100).Add(sdk.NewRat(4, 100).Mul(sumOfVotingPowerOfPrecommitValidators).Quo(pool.BondedShares))))
candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer)
toReservePool := coinsMulRat(collectedFees, params.ReservePoolFee)
pool.ReservePool = pool.ReservePool.Plus(toReservePool)
distributedReward := (collectedFees.Minus(toProposer)).Minus(toReservePool)
pool.FeePool = pool.FeePool.Plus(distributedReward)
pool.SumFeesReceived = pool.SumFeesReceived.Plus(distributedReward)
pool.RecentFee = distributedReward
k.setPool(ctx, pool)
}
// XXX need to introduce rat amount based coins for the pool :(
func coinsMulRat(coins sdk.Coins, rat sdk.Rat) sdk.Coins {
var res sdk.Coins
for _, coin := range coins {
coinMulAmt := rat.Mul(sdk.NewRat(coin.Amount)).Evaluate()
coinMul := sdk.Coins{{coin.Denom, coinMulAmt}}
res = res.Plus(coinMul)
}
return res
}

View File

@ -77,7 +77,7 @@ func (k Keeper) GetCandidate(ctx sdk.Context, addr sdk.Address) (candidate Candi
// Get the set of all candidates, retrieve a maxRetrieve number of records
func (k Keeper) GetCandidates(ctx sdk.Context, maxRetrieve int16) (candidates Candidates) {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(subspace(CandidatesKey))
iterator := store.SubspaceIterator(CandidatesKey)
candidates = make([]Candidate, maxRetrieve)
i := 0
@ -220,7 +220,7 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
store := ctx.KVStore(k.storeKey)
// clear the recent validators store, add to the ToKickOut Temp store
iterator := store.Iterator(subspace(RecentValidatorsKey))
iterator := store.SubspaceIterator(RecentValidatorsKey)
for ; iterator.Valid(); iterator.Next() {
addr := AddrFromKey(iterator.Key())
@ -232,7 +232,7 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
// add the actual validator power sorted store
maxValidators := k.GetParams(ctx).MaxValidators
iterator = store.ReverseIterator(subspace(ValidatorsKey)) // largest to smallest
iterator = store.ReverseSubspaceIterator(ValidatorsKey) // largest to smallest
validators = make([]Validator, maxValidators)
i := 0
for ; ; i++ {
@ -258,7 +258,7 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
}
// add any kicked out validators to the acc change
iterator = store.Iterator(subspace(ToKickOutValidatorsKey))
iterator = store.SubspaceIterator(ToKickOutValidatorsKey)
for ; iterator.Valid(); iterator.Next() {
key := iterator.Key()
addr := AddrFromKey(key)
@ -289,7 +289,7 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
func (k Keeper) isNewValidator(ctx sdk.Context, store sdk.KVStore, address sdk.Address) bool {
// add the actual validator power sorted store
maxVal := k.GetParams(ctx).MaxValidators
iterator := store.ReverseIterator(subspace(ValidatorsKey)) // largest to smallest
iterator := store.ReverseSubspaceIterator(ValidatorsKey) // largest to smallest
for i := 0; ; i++ {
if !iterator.Valid() || i > int(maxVal-1) {
iterator.Close()
@ -326,7 +326,7 @@ func (k Keeper) IsRecentValidator(ctx sdk.Context, address sdk.Address) bool {
func (k Keeper) getAccUpdateValidators(ctx sdk.Context) (updates []abci.Validator) {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(subspace(AccUpdateValidatorsKey)) //smallest to largest
iterator := store.SubspaceIterator(AccUpdateValidatorsKey) //smallest to largest
for ; iterator.Valid(); iterator.Next() {
valBytes := iterator.Value()
var val abci.Validator
@ -345,7 +345,7 @@ func (k Keeper) clearAccUpdateValidators(ctx sdk.Context) {
store := ctx.KVStore(k.storeKey)
// delete subspace
iterator := store.Iterator(subspace(AccUpdateValidatorsKey))
iterator := store.SubspaceIterator(AccUpdateValidatorsKey)
for ; iterator.Valid(); iterator.Next() {
store.Delete(iterator.Key())
}
@ -374,7 +374,7 @@ func (k Keeper) GetDelegatorBond(ctx sdk.Context,
// load all bonds
func (k Keeper) getBonds(ctx sdk.Context, maxRetrieve int16) (bonds []DelegatorBond) {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(subspace(DelegatorBondKeyPrefix))
iterator := store.SubspaceIterator(DelegatorBondKeyPrefix)
bonds = make([]DelegatorBond, maxRetrieve)
i := 0
@ -399,7 +399,7 @@ func (k Keeper) getBonds(ctx sdk.Context, maxRetrieve int16) (bonds []DelegatorB
func (k Keeper) GetDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (bonds []DelegatorBond) {
store := ctx.KVStore(k.storeKey)
delegatorPrefixKey := GetDelegatorBondsKey(delegator, k.cdc)
iterator := store.Iterator(subspace(delegatorPrefixKey)) //smallest to largest
iterator := store.SubspaceIterator(delegatorPrefixKey) //smallest to largest
bonds = make([]DelegatorBond, maxRetrieve)
i := 0

View File

@ -49,14 +49,14 @@ func TestCandidate(t *testing.T) {
keeper.setCandidate(ctx, candidates[0])
resCand, found := keeper.GetCandidate(ctx, addrVals[0])
require.True(t, found)
assert.True(t, candidatesEqual(candidates[0], resCand), "%v \n %v", resCand, candidates[0])
assert.True(t, candidates[0].equal(resCand), "%v \n %v", resCand, candidates[0])
// modify a records, save, and retrieve
candidates[0].Liabilities = sdk.NewRat(99)
keeper.setCandidate(ctx, candidates[0])
resCand, found = keeper.GetCandidate(ctx, addrVals[0])
require.True(t, found)
assert.True(t, candidatesEqual(candidates[0], resCand))
assert.True(t, candidates[0].equal(resCand))
// also test that the address has been added to address list
resCands = keeper.GetCandidates(ctx, 100)
@ -68,15 +68,15 @@ func TestCandidate(t *testing.T) {
keeper.setCandidate(ctx, candidates[2])
resCand, found = keeper.GetCandidate(ctx, addrVals[1])
require.True(t, found)
assert.True(t, candidatesEqual(candidates[1], resCand), "%v \n %v", resCand, candidates[1])
assert.True(t, candidates[1].equal(resCand), "%v \n %v", resCand, candidates[1])
resCand, found = keeper.GetCandidate(ctx, addrVals[2])
require.True(t, found)
assert.True(t, candidatesEqual(candidates[2], resCand), "%v \n %v", resCand, candidates[2])
assert.True(t, candidates[2].equal(resCand), "%v \n %v", resCand, candidates[2])
resCands = keeper.GetCandidates(ctx, 100)
require.Equal(t, 3, len(resCands))
assert.True(t, candidatesEqual(candidates[0], resCands[0]), "%v \n %v", resCands[0], candidates[0])
assert.True(t, candidatesEqual(candidates[1], resCands[1]), "%v \n %v", resCands[1], candidates[1])
assert.True(t, candidatesEqual(candidates[2], resCands[2]), "%v \n %v", resCands[2], candidates[2])
assert.True(t, candidates[0].equal(resCands[0]), "%v \n %v", resCands[0], candidates[0])
assert.True(t, candidates[1].equal(resCands[1]), "%v \n %v", resCands[1], candidates[1])
assert.True(t, candidates[2].equal(resCands[2]), "%v \n %v", resCands[2], candidates[2])
// remove a record
keeper.removeCandidate(ctx, candidates[1].Address)
@ -117,14 +117,14 @@ func TestBond(t *testing.T) {
keeper.setDelegatorBond(ctx, bond1to1)
resBond, found := keeper.GetDelegatorBond(ctx, addrDels[0], addrVals[0])
assert.True(t, found)
assert.True(t, bondsEqual(bond1to1, resBond))
assert.True(t, bond1to1.equal(resBond))
// modify a records, save, and retrieve
bond1to1.Shares = sdk.NewRat(99)
keeper.setDelegatorBond(ctx, bond1to1)
resBond, found = keeper.GetDelegatorBond(ctx, addrDels[0], addrVals[0])
assert.True(t, found)
assert.True(t, bondsEqual(bond1to1, resBond))
assert.True(t, bond1to1.equal(resBond))
// add some more records
keeper.setCandidate(ctx, candidates[1])
@ -143,26 +143,26 @@ func TestBond(t *testing.T) {
// test all bond retrieve capabilities
resBonds := keeper.GetDelegatorBonds(ctx, addrDels[0], 5)
require.Equal(t, 3, len(resBonds))
assert.True(t, bondsEqual(bond1to1, resBonds[0]))
assert.True(t, bondsEqual(bond1to2, resBonds[1]))
assert.True(t, bondsEqual(bond1to3, resBonds[2]))
assert.True(t, bond1to1.equal(resBonds[0]))
assert.True(t, bond1to2.equal(resBonds[1]))
assert.True(t, bond1to3.equal(resBonds[2]))
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[0], 3)
require.Equal(t, 3, len(resBonds))
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[0], 2)
require.Equal(t, 2, len(resBonds))
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[1], 5)
require.Equal(t, 3, len(resBonds))
assert.True(t, bondsEqual(bond2to1, resBonds[0]))
assert.True(t, bondsEqual(bond2to2, resBonds[1]))
assert.True(t, bondsEqual(bond2to3, resBonds[2]))
assert.True(t, bond2to1.equal(resBonds[0]))
assert.True(t, bond2to2.equal(resBonds[1]))
assert.True(t, bond2to3.equal(resBonds[2]))
allBonds := keeper.getBonds(ctx, 1000)
require.Equal(t, 6, len(allBonds))
assert.True(t, bondsEqual(bond1to1, allBonds[0]))
assert.True(t, bondsEqual(bond1to2, allBonds[1]))
assert.True(t, bondsEqual(bond1to3, allBonds[2]))
assert.True(t, bondsEqual(bond2to1, allBonds[3]))
assert.True(t, bondsEqual(bond2to2, allBonds[4]))
assert.True(t, bondsEqual(bond2to3, allBonds[5]))
assert.True(t, bond1to1.equal(allBonds[0]))
assert.True(t, bond1to2.equal(allBonds[1]))
assert.True(t, bond1to3.equal(allBonds[2]))
assert.True(t, bond2to1.equal(allBonds[3]))
assert.True(t, bond2to2.equal(allBonds[4]))
assert.True(t, bond2to3.equal(allBonds[5]))
// delete a record
keeper.removeDelegatorBond(ctx, bond2to3)
@ -170,8 +170,8 @@ func TestBond(t *testing.T) {
assert.False(t, found)
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[1], 5)
require.Equal(t, 2, len(resBonds))
assert.True(t, bondsEqual(bond2to1, resBonds[0]))
assert.True(t, bondsEqual(bond2to2, resBonds[1]))
assert.True(t, bond2to1.equal(resBonds[0]))
assert.True(t, bond2to2.equal(resBonds[1]))
// delete all the records from delegator 2
keeper.removeDelegatorBond(ctx, bond2to1)
@ -443,8 +443,8 @@ func TestGetAccUpdateValidators(t *testing.T) {
require.Equal(t, 2, len(candidates))
assert.Equal(t, candidates[0].validator().abciValidator(keeper.cdc), acc[0])
assert.Equal(t, candidates[1].validator().abciValidator(keeper.cdc), acc[1])
assert.True(t, validatorsEqual(candidates[0].validator(), vals[1]))
assert.True(t, validatorsEqual(candidates[1].validator(), vals[0]))
assert.True(t, candidates[0].validator().equal(vals[1]))
assert.True(t, candidates[1].validator().equal(vals[0]))
// test identical,
// candidate set: {c1, c3} -> {c1, c3}
@ -637,10 +637,10 @@ func TestIsRecentValidator(t *testing.T) {
keeper.setCandidate(ctx, candidatesIn[1])
validators = keeper.GetValidators(ctx)
require.Equal(t, 2, len(validators))
assert.True(t, validatorsEqual(candidatesIn[0].validator(), validators[0]))
assert.True(t, candidatesIn[0].validator().equal(validators[0]))
c1ValWithCounter := candidatesIn[1].validator()
c1ValWithCounter.Counter = int16(1)
assert.True(t, validatorsEqual(c1ValWithCounter, validators[1]))
assert.True(t, c1ValWithCounter.equal(validators[1]))
// test a basic retrieve of something that should be a recent validator
assert.True(t, keeper.IsRecentValidator(ctx, candidatesIn[0].Address))

View File

@ -1,7 +1,6 @@
package stake
import (
"bytes"
"encoding/hex"
"testing"
@ -52,71 +51,6 @@ var (
emptyPubkey crypto.PubKey
)
func validatorsEqual(b1, b2 Validator) bool {
return bytes.Equal(b1.Address, b2.Address) &&
b1.PubKey.Equals(b2.PubKey) &&
b1.Power.Equal(b2.Power) &&
b1.Height == b2.Height &&
b1.Counter == b2.Counter
}
func candidatesEqual(c1, c2 Candidate) bool {
return c1.Status == c2.Status &&
c1.PubKey.Equals(c2.PubKey) &&
bytes.Equal(c1.Address, c2.Address) &&
c1.Assets.Equal(c2.Assets) &&
c1.Liabilities.Equal(c2.Liabilities) &&
c1.Description == c2.Description
}
func bondsEqual(b1, b2 DelegatorBond) bool {
return bytes.Equal(b1.DelegatorAddr, b2.DelegatorAddr) &&
bytes.Equal(b1.CandidateAddr, b2.CandidateAddr) &&
b1.Height == b2.Height &&
b1.Shares.Equal(b2.Shares)
}
// default params for testing
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",
}
}
// initial pool for testing
func initialPool() Pool {
return Pool{
TotalSupply: 0,
BondedShares: sdk.ZeroRat(),
UnbondedShares: sdk.ZeroRat(),
BondedPool: 0,
UnbondedPool: 0,
InflationLastTime: 0,
Inflation: sdk.NewRat(7, 100),
}
}
// get raw genesis raw message for testing
func GetDefaultGenesisState() GenesisState {
return GenesisState{
Pool: initialPool(),
Params: defaultParams(),
}
}
// XXX reference the common declaration of this function
func subspace(prefix []byte) (start, end []byte) {
end = make([]byte, len(prefix))
copy(end, prefix)
end[len(end)-1]++
return prefix, end
}
func makeTestCodec() *wire.Codec {
var cdc = wire.NewCodec()

View File

@ -1,6 +1,8 @@
package stake
import (
"bytes"
sdk "github.com/cosmos/cosmos-sdk/types"
crypto "github.com/tendermint/go-crypto"
@ -15,6 +17,14 @@ type GenesisState struct {
Bonds []DelegatorBond `json:"bonds"`
}
// get raw genesis raw message for testing
func DefaultGenesisState() GenesisState {
return GenesisState{
Pool: initialPool(),
Params: defaultParams(),
}
}
//_________________________________________________________________________
// Params defines the high level settings for staking
@ -26,6 +36,8 @@ type Params struct {
MaxValidators uint16 `json:"max_validators"` // maximum number of validators
BondDenom string `json:"bond_denom"` // bondable coin denomination
ReservePoolFee sdk.Rat `json:"reserve_pool_fee"` // percent of fees which go to reserve pool
}
func (p Params) equal(p2 Params) bool {
@ -34,7 +46,20 @@ func (p Params) equal(p2 Params) bool {
p.InflationMin.Equal(p2.InflationMin) &&
p.GoalBonded.Equal(p2.GoalBonded) &&
p.MaxValidators == p2.MaxValidators &&
p.BondDenom == p2.BondDenom
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",
ReservePoolFee: sdk.NewRat(5, 100),
}
}
//_________________________________________________________________________
@ -48,16 +73,50 @@ type Pool struct {
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)
// XXX need to use special sdk.Rat amounts in coins here because added at small increments
ReservePool sdk.Coins `json:"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
SumFeesReceived sdk.Coins `json:"sum_fees_received"` // XXX sum of all fees received
RecentFee sdk.Coins `json:"recent_fee"` // XXX most recent fee collected
Adjustment sdk.Rat `json:"adjustment"` // XXX Adjustment factor for calculating global fee accum
}
func (p Pool) equal(p2 Pool) bool {
return p.BondedShares.Equal(p2.BondedShares) &&
return p.TotalSupply == p2.TotalSupply &&
p.BondedShares.Equal(p2.BondedShares) &&
p.UnbondedShares.Equal(p2.UnbondedShares) &&
p.Inflation.Equal(p2.Inflation) &&
p.TotalSupply == p2.TotalSupply &&
p.BondedPool == p2.BondedPool &&
p.UnbondedPool == p2.UnbondedPool &&
p.InflationLastTime == p2.InflationLastTime
p.InflationLastTime == p2.InflationLastTime &&
p.Inflation.Equal(p2.Inflation) &&
p.DateLastCommissionReset == p2.DateLastCommissionReset &&
p.ReservePool.IsEqual(p2.ReservePool) &&
p.FeePool.IsEqual(p2.FeePool) &&
p.SumFeesReceived.IsEqual(p2.SumFeesReceived) &&
p.RecentFee.IsEqual(p2.RecentFee) &&
p.Adjustment.Equal(p2.Adjustment)
}
// initial pool for testing
func initialPool() Pool {
return Pool{
TotalSupply: 0,
BondedShares: sdk.ZeroRat(),
UnbondedShares: sdk.ZeroRat(),
BondedPool: 0,
UnbondedPool: 0,
InflationLastTime: 0,
Inflation: sdk.NewRat(7, 100),
DateLastCommissionReset: 0,
ReservePool: sdk.Coins{},
FeePool: sdk.Coins{},
SumFeesReceived: sdk.Coins{},
RecentFee: sdk.Coins{},
Adjustment: sdk.ZeroRat(),
}
}
//_________________________________________________________________________
@ -80,14 +139,19 @@ const (
// exchange rate. Voting power can be calculated as total bonds multiplied by
// exchange rate.
type Candidate struct {
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
Assets sdk.Rat `json:"assets"` // total shares of a global hold pools
Liabilities sdk.Rat `json:"liabilities"` // total shares issued to a candidate's delegators
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
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
Assets sdk.Rat `json:"assets"` // total shares of a global hold pools
Liabilities sdk.Rat `json:"liabilities"` // total shares issued to a candidate's delegators
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)
}
// Candidates - list of Candidates
@ -96,17 +160,38 @@ type Candidates []Candidate
// NewCandidate - initialize a new candidate
func NewCandidate(address sdk.Address, pubKey crypto.PubKey, description Description) Candidate {
return Candidate{
Status: Unbonded,
Address: address,
PubKey: pubKey,
Assets: sdk.ZeroRat(),
Liabilities: sdk.ZeroRat(),
Description: description,
ValidatorBondHeight: int64(0),
ValidatorBondCounter: int16(0),
Status: Unbonded,
Address: address,
PubKey: pubKey,
Assets: sdk.ZeroRat(),
Liabilities: 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(),
}
}
func (c Candidate) equal(c2 Candidate) bool {
return c.Status == c2.Status &&
c.PubKey.Equals(c2.PubKey) &&
bytes.Equal(c.Address, c2.Address) &&
c.Assets.Equal(c2.Assets) &&
c.Liabilities.Equal(c2.Liabilities) &&
c.Description == c2.Description &&
c.ValidatorBondHeight == c2.ValidatorBondHeight &&
c.ValidatorBondCounter == c2.ValidatorBondCounter &&
c.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) &&
c.Commission.Equal(c2.Commission) &&
c.CommissionMax.Equal(c2.CommissionMax) &&
c.CommissionChangeRate.Equal(c2.CommissionChangeRate) &&
c.CommissionChangeToday.Equal(c2.CommissionChangeToday)
}
// Description - description fields for a candidate
type Description struct {
Moniker string `json:"moniker"`
@ -158,6 +243,14 @@ type Validator struct {
Counter int16 `json:"counter"` // Block-local tx index for resolving equal voting power & height
}
func (v Validator) equal(v2 Validator) bool {
return bytes.Equal(v.Address, v2.Address) &&
v.PubKey.Equals(v2.PubKey) &&
v.Power.Equal(v2.Power) &&
v.Height == v2.Height &&
v.Counter == v2.Counter
}
// abci validator from stake validator type
func (v Validator) abciValidator(cdc *wire.Codec) sdk.Validator {
return sdk.Validator{
@ -187,3 +280,10 @@ type DelegatorBond struct {
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)
}

View File

@ -44,14 +44,14 @@ func TestViewSlashBond(t *testing.T) {
keeper.setDelegatorBond(ctx, bond1to1)
resBond, found := viewSlashKeeper.GetDelegatorBond(ctx, addrDels[0], addrVals[0])
assert.True(t, found)
assert.True(t, bondsEqual(bond1to1, resBond))
assert.True(t, bond1to1.equal(resBond))
// modify a records, save, and retrieve
bond1to1.Shares = sdk.NewRat(99)
keeper.setDelegatorBond(ctx, bond1to1)
resBond, found = viewSlashKeeper.GetDelegatorBond(ctx, addrDels[0], addrVals[0])
assert.True(t, found)
assert.True(t, bondsEqual(bond1to1, resBond))
assert.True(t, bond1to1.equal(resBond))
// add some more records
keeper.setCandidate(ctx, candidates[1])
@ -70,17 +70,17 @@ func TestViewSlashBond(t *testing.T) {
// test all bond retrieve capabilities
resBonds := viewSlashKeeper.GetDelegatorBonds(ctx, addrDels[0], 5)
require.Equal(t, 3, len(resBonds))
assert.True(t, bondsEqual(bond1to1, resBonds[0]))
assert.True(t, bondsEqual(bond1to2, resBonds[1]))
assert.True(t, bondsEqual(bond1to3, resBonds[2]))
assert.True(t, bond1to1.equal(resBonds[0]))
assert.True(t, bond1to2.equal(resBonds[1]))
assert.True(t, bond1to3.equal(resBonds[2]))
resBonds = viewSlashKeeper.GetDelegatorBonds(ctx, addrDels[0], 3)
require.Equal(t, 3, len(resBonds))
resBonds = viewSlashKeeper.GetDelegatorBonds(ctx, addrDels[0], 2)
require.Equal(t, 2, len(resBonds))
resBonds = viewSlashKeeper.GetDelegatorBonds(ctx, addrDels[1], 5)
require.Equal(t, 3, len(resBonds))
assert.True(t, bondsEqual(bond2to1, resBonds[0]))
assert.True(t, bondsEqual(bond2to2, resBonds[1]))
assert.True(t, bondsEqual(bond2to3, resBonds[2]))
assert.True(t, bond2to1.equal(resBonds[0]))
assert.True(t, bond2to2.equal(resBonds[1]))
assert.True(t, bond2to3.equal(resBonds[2]))
}