Merge remote-tracking branch 'origin/develop' into bez/2339-fix-lcd-val-init
This commit is contained in:
commit
23dc24e9e4
|
@ -206,6 +206,12 @@ jobs:
|
|||
- run:
|
||||
name: run localnet and exit on failure
|
||||
command: |
|
||||
pushd /tmp
|
||||
wget https://dl.google.com/go/go1.11.linux-amd64.tar.gz
|
||||
sudo tar -xvf go1.11.linux-amd64.tar.gz
|
||||
sudo rm -rf /usr/local/go
|
||||
sudo mv go /usr/local
|
||||
popd
|
||||
set -x
|
||||
make get_tools
|
||||
make get_vendor_deps
|
||||
|
|
|
@ -111,6 +111,7 @@ FEATURES
|
|||
* [x/auth] \#2376 Remove FeePayer() from StdTx
|
||||
* [x/stake] [\#1672](https://github.com/cosmos/cosmos-sdk/issues/1672) Implement
|
||||
basis for the validator commission model.
|
||||
* [x/auth] Support account removal in the account mapper.
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
@ -135,6 +136,7 @@ IMPROVEMENTS
|
|||
* [genesis] \#2229 Ensure that there are no duplicate accounts or validators in the genesis state.
|
||||
* Add SDK validation to `config.toml` (namely disabling `create_empty_blocks`) \#1571
|
||||
* \#1941(https://github.com/cosmos/cosmos-sdk/issues/1941) Version is now inferred via `git describe --tags`.
|
||||
* [x/distribution] \#1671 add distribution types and tests
|
||||
|
||||
* SDK
|
||||
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
|
||||
|
|
|
@ -83,6 +83,13 @@ func (am AccountMapper) SetAccount(ctx sdk.Context, acc Account) {
|
|||
store.Set(AddressStoreKey(addr), bz)
|
||||
}
|
||||
|
||||
// RemoveAccount removes an account for the account mapper store.
|
||||
func (am AccountMapper) RemoveAccount(ctx sdk.Context, acc Account) {
|
||||
addr := acc.GetAddress()
|
||||
store := ctx.KVStore(am.key)
|
||||
store.Delete(AddressStoreKey(addr))
|
||||
}
|
||||
|
||||
// Implements sdk.AccountMapper.
|
||||
func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(Account) (stop bool)) {
|
||||
store := ctx.KVStore(am.key)
|
||||
|
|
|
@ -61,6 +61,44 @@ func TestAccountMapperGetSet(t *testing.T) {
|
|||
require.Equal(t, newSequence, acc.GetSequence())
|
||||
}
|
||||
|
||||
func TestAccountMapperRemoveAccount(t *testing.T) {
|
||||
ms, capKey, _ := setupMultiStore()
|
||||
cdc := codec.New()
|
||||
RegisterBaseAccount(cdc)
|
||||
|
||||
// make context and mapper
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger())
|
||||
mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount)
|
||||
|
||||
addr1 := sdk.AccAddress([]byte("addr1"))
|
||||
addr2 := sdk.AccAddress([]byte("addr2"))
|
||||
|
||||
// create accounts
|
||||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||
|
||||
accSeq1 := int64(20)
|
||||
accSeq2 := int64(40)
|
||||
|
||||
acc1.SetSequence(accSeq1)
|
||||
acc2.SetSequence(accSeq2)
|
||||
mapper.SetAccount(ctx, acc1)
|
||||
mapper.SetAccount(ctx, acc2)
|
||||
|
||||
acc1 = mapper.GetAccount(ctx, addr1)
|
||||
require.NotNil(t, acc1)
|
||||
require.Equal(t, accSeq1, acc1.GetSequence())
|
||||
|
||||
// remove one account
|
||||
mapper.RemoveAccount(ctx, acc1)
|
||||
acc1 = mapper.GetAccount(ctx, addr1)
|
||||
require.Nil(t, acc1)
|
||||
|
||||
acc2 = mapper.GetAccount(ctx, addr2)
|
||||
require.NotNil(t, acc2)
|
||||
require.Equal(t, accSeq2, acc2.GetSequence())
|
||||
}
|
||||
|
||||
func BenchmarkAccountMapperGetAccountFound(b *testing.B) {
|
||||
ms, capKey, _ := setupMultiStore()
|
||||
cdc := codec.New()
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
// Register concrete types on codec codec
|
||||
func RegisterCodec(cdc *codec.Codec) {
|
||||
cdc.RegisterConcrete(MsgWithdrawDelegatorRewardsAll{}, "cosmos-sdk/MsgWithdrawDelegationRewardsAll", nil)
|
||||
cdc.RegisterConcrete(MsgWithdrawDelegatorReward{}, "cosmos-sdk/MsgWithdrawDelegationReward", nil)
|
||||
cdc.RegisterConcrete(MsgWithdrawValidatorRewardsAll{}, "cosmos-sdk/MsgWithdrawValidatorRewardsAll", nil)
|
||||
cdc.RegisterConcrete(MsgSetWithdrawAddress{}, "cosmos-sdk/MsgModifyWithdrawAddress", nil)
|
||||
}
|
||||
|
||||
// generic sealed codec to be used throughout module
|
||||
var MsgCdc *codec.Codec
|
||||
|
||||
func init() {
|
||||
cdc := codec.New()
|
||||
RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
MsgCdc = cdc.Seal()
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Coins which can have additional decimal points
|
||||
type DecCoin struct {
|
||||
Denom string `json:"denom"`
|
||||
Amount sdk.Dec `json:"amount"`
|
||||
}
|
||||
|
||||
func NewDecCoin(denom string, amount int64) DecCoin {
|
||||
return DecCoin{
|
||||
Denom: denom,
|
||||
Amount: sdk.NewDec(amount),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDecCoinFromCoin(coin sdk.Coin) DecCoin {
|
||||
return DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: sdk.NewDecFromInt(coin.Amount),
|
||||
}
|
||||
}
|
||||
|
||||
// Adds amounts of two coins with same denom
|
||||
func (coin DecCoin) Plus(coinB DecCoin) DecCoin {
|
||||
if coin.Denom != coinB.Denom {
|
||||
panic(fmt.Sprintf("coin denom different: %v %v\n", coin.Denom, coinB.Denom))
|
||||
}
|
||||
return DecCoin{coin.Denom, coin.Amount.Add(coinB.Amount)}
|
||||
}
|
||||
|
||||
// Subtracts amounts of two coins with same denom
|
||||
func (coin DecCoin) Minus(coinB DecCoin) DecCoin {
|
||||
if coin.Denom != coinB.Denom {
|
||||
panic(fmt.Sprintf("coin denom different: %v %v\n", coin.Denom, coinB.Denom))
|
||||
}
|
||||
return DecCoin{coin.Denom, coin.Amount.Sub(coinB.Amount)}
|
||||
}
|
||||
|
||||
// return the decimal coins with trunctated decimals
|
||||
func (coin DecCoin) TruncateDecimal() sdk.Coin {
|
||||
return sdk.NewCoin(coin.Denom, coin.Amount.TruncateInt())
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
|
||||
// coins with decimal
|
||||
type DecCoins []DecCoin
|
||||
|
||||
func NewDecCoins(coins sdk.Coins) DecCoins {
|
||||
dcs := make(DecCoins, len(coins))
|
||||
for i, coin := range coins {
|
||||
dcs[i] = NewDecCoinFromCoin(coin)
|
||||
}
|
||||
return dcs
|
||||
}
|
||||
|
||||
// return the coins with trunctated decimals
|
||||
func (coins DecCoins) TruncateDecimal() sdk.Coins {
|
||||
out := make(sdk.Coins, len(coins))
|
||||
for i, coin := range coins {
|
||||
out[i] = coin.TruncateDecimal()
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Plus combines two sets of coins
|
||||
// CONTRACT: Plus will never return Coins where one Coin has a 0 amount.
|
||||
func (coins DecCoins) Plus(coinsB DecCoins) DecCoins {
|
||||
sum := ([]DecCoin)(nil)
|
||||
indexA, indexB := 0, 0
|
||||
lenA, lenB := len(coins), len(coinsB)
|
||||
for {
|
||||
if indexA == lenA {
|
||||
if indexB == lenB {
|
||||
return sum
|
||||
}
|
||||
return append(sum, coinsB[indexB:]...)
|
||||
} else if indexB == lenB {
|
||||
return append(sum, coins[indexA:]...)
|
||||
}
|
||||
coinA, coinB := coins[indexA], coinsB[indexB]
|
||||
switch strings.Compare(coinA.Denom, coinB.Denom) {
|
||||
case -1:
|
||||
sum = append(sum, coinA)
|
||||
indexA++
|
||||
case 0:
|
||||
if coinA.Amount.Add(coinB.Amount).IsZero() {
|
||||
// ignore 0 sum coin type
|
||||
} else {
|
||||
sum = append(sum, coinA.Plus(coinB))
|
||||
}
|
||||
indexA++
|
||||
indexB++
|
||||
case 1:
|
||||
sum = append(sum, coinB)
|
||||
indexB++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negative returns a set of coins with all amount negative
|
||||
func (coins DecCoins) Negative() DecCoins {
|
||||
res := make([]DecCoin, 0, len(coins))
|
||||
for _, coin := range coins {
|
||||
res = append(res, DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount.Neg(),
|
||||
})
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Minus subtracts a set of coins from another (adds the inverse)
|
||||
func (coins DecCoins) Minus(coinsB DecCoins) DecCoins {
|
||||
return coins.Plus(coinsB.Negative())
|
||||
}
|
||||
|
||||
// multiply all the coins by a decimal
|
||||
func (coins DecCoins) MulDec(d sdk.Dec) DecCoins {
|
||||
res := make([]DecCoin, len(coins))
|
||||
for i, coin := range coins {
|
||||
product := DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount.Mul(d),
|
||||
}
|
||||
res[i] = product
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// divide all the coins by a multiple
|
||||
func (coins DecCoins) QuoDec(d sdk.Dec) DecCoins {
|
||||
res := make([]DecCoin, len(coins))
|
||||
for i, coin := range coins {
|
||||
quotient := DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount.Quo(d),
|
||||
}
|
||||
res[i] = quotient
|
||||
}
|
||||
return res
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPlusDecCoin(t *testing.T) {
|
||||
decCoinA1 := DecCoin{"A", sdk.NewDecWithPrec(11, 1)}
|
||||
decCoinA2 := DecCoin{"A", sdk.NewDecWithPrec(22, 1)}
|
||||
decCoinB1 := DecCoin{"B", sdk.NewDecWithPrec(11, 1)}
|
||||
|
||||
// regular add
|
||||
res := decCoinA1.Plus(decCoinA1)
|
||||
require.Equal(t, decCoinA2, res, "sum of coins is incorrect")
|
||||
|
||||
// bad denom add
|
||||
assert.Panics(t, func() {
|
||||
decCoinA1.Plus(decCoinB1)
|
||||
}, "expected panic on sum of different denoms")
|
||||
|
||||
}
|
||||
|
||||
func TestPlusCoins(t *testing.T) {
|
||||
one := sdk.NewDec(1)
|
||||
zero := sdk.NewDec(0)
|
||||
negone := sdk.NewDec(-1)
|
||||
two := sdk.NewDec(2)
|
||||
|
||||
cases := []struct {
|
||||
inputOne DecCoins
|
||||
inputTwo DecCoins
|
||||
expected DecCoins
|
||||
}{
|
||||
{DecCoins{{"A", one}, {"B", one}}, DecCoins{{"A", one}, {"B", one}}, DecCoins{{"A", two}, {"B", two}}},
|
||||
{DecCoins{{"A", zero}, {"B", one}}, DecCoins{{"A", zero}, {"B", zero}}, DecCoins{{"B", one}}},
|
||||
{DecCoins{{"A", zero}, {"B", zero}}, DecCoins{{"A", zero}, {"B", zero}}, DecCoins(nil)},
|
||||
{DecCoins{{"A", one}, {"B", zero}}, DecCoins{{"A", negone}, {"B", zero}}, DecCoins(nil)},
|
||||
{DecCoins{{"A", negone}, {"B", zero}}, DecCoins{{"A", zero}, {"B", zero}}, DecCoins{{"A", negone}}},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range cases {
|
||||
res := tc.inputOne.Plus(tc.inputTwo)
|
||||
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// distribution info for a delegation - used to determine entitled rewards
|
||||
type DelegatorDistInfo struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
ValOperatorAddr sdk.ValAddress `json:"val_operator_addr"`
|
||||
WithdrawalHeight int64 `json:"withdrawal_height"` // last time this delegation withdrew rewards
|
||||
}
|
||||
|
||||
func NewDelegatorDistInfo(delegatorAddr sdk.AccAddress, valOperatorAddr sdk.ValAddress,
|
||||
currentHeight int64) DelegatorDistInfo {
|
||||
|
||||
return DelegatorDistInfo{
|
||||
DelegatorAddr: delegatorAddr,
|
||||
ValOperatorAddr: valOperatorAddr,
|
||||
WithdrawalHeight: currentHeight,
|
||||
}
|
||||
}
|
||||
|
||||
// withdraw rewards from delegator
|
||||
func (di DelegatorDistInfo) WithdrawRewards(fp FeePool, vi ValidatorDistInfo,
|
||||
height int64, totalBonded, vdTokens, totalDelShares, delegatorShares,
|
||||
commissionRate sdk.Dec) (DelegatorDistInfo, ValidatorDistInfo, FeePool, DecCoins) {
|
||||
|
||||
vi = vi.UpdateTotalDelAccum(height, totalDelShares)
|
||||
|
||||
if vi.DelAccum.Accum.IsZero() {
|
||||
return di, vi, fp, DecCoins{}
|
||||
}
|
||||
|
||||
vi, fp = vi.TakeFeePoolRewards(fp, height, totalBonded, vdTokens, commissionRate)
|
||||
|
||||
blocks := height - di.WithdrawalHeight
|
||||
di.WithdrawalHeight = height
|
||||
accum := delegatorShares.MulInt(sdk.NewInt(blocks))
|
||||
withdrawalTokens := vi.Pool.MulDec(accum).QuoDec(vi.DelAccum.Accum)
|
||||
remainingTokens := vi.Pool.Minus(withdrawalTokens)
|
||||
|
||||
vi.Pool = remainingTokens
|
||||
vi.DelAccum.Accum = vi.DelAccum.Accum.Sub(accum)
|
||||
|
||||
return di, vi, fp, withdrawalTokens
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWithdrawRewards(t *testing.T) {
|
||||
|
||||
// initialize
|
||||
height := int64(0)
|
||||
fp := InitialFeePool()
|
||||
vi := NewValidatorDistInfo(valAddr1, height)
|
||||
commissionRate := sdk.NewDecWithPrec(2, 2)
|
||||
validatorTokens := sdk.NewDec(10)
|
||||
validatorDelShares := sdk.NewDec(10)
|
||||
totalBondedTokens := validatorTokens.Add(sdk.NewDec(90)) // validator-1 is 10% of total power
|
||||
|
||||
di1 := NewDelegatorDistInfo(delAddr1, valAddr1, height)
|
||||
di1Shares := sdk.NewDec(5) // this delegator has half the shares in the validator
|
||||
|
||||
di2 := NewDelegatorDistInfo(delAddr2, valAddr1, height)
|
||||
di2Shares := sdk.NewDec(5)
|
||||
|
||||
// simulate adding some stake for inflation
|
||||
height = 10
|
||||
fp.Pool = DecCoins{NewDecCoin("stake", 1000)}
|
||||
|
||||
// withdraw rewards
|
||||
di1, vi, fp, rewardRecv1 := di1.WithdrawRewards(fp, vi, height, totalBondedTokens,
|
||||
validatorTokens, validatorDelShares, di1Shares, commissionRate)
|
||||
|
||||
assert.Equal(t, height, di1.WithdrawalHeight)
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.ValAccum.Accum))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(49), vi.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi.PoolCommission[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(49), rewardRecv1[0].Amount))
|
||||
|
||||
// add more blocks and inflation
|
||||
height = 20
|
||||
fp.Pool[0].Amount = fp.Pool[0].Amount.Add(sdk.NewDec(1000))
|
||||
|
||||
// withdraw rewards
|
||||
di2, vi, fp, rewardRecv2 := di2.WithdrawRewards(fp, vi, height, totalBondedTokens,
|
||||
validatorTokens, validatorDelShares, di2Shares, commissionRate)
|
||||
|
||||
assert.Equal(t, height, di2.WithdrawalHeight)
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.ValAccum.Accum))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(49), vi.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(4), vi.PoolCommission[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(98), rewardRecv2[0].Amount))
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// nolint
|
||||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
type CodeType = sdk.CodeType
|
||||
|
||||
const (
|
||||
DefaultCodespace sdk.CodespaceType = 6
|
||||
CodeInvalidInput CodeType = 103
|
||||
)
|
||||
|
||||
func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil")
|
||||
}
|
||||
func ErrNilWithdrawAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidInput, "withdraw address is nil")
|
||||
}
|
||||
func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil")
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// total accumulation tracker
|
||||
type TotalAccum struct {
|
||||
UpdateHeight int64 `json:"update_height"`
|
||||
Accum sdk.Dec `json:"accum"`
|
||||
}
|
||||
|
||||
func NewTotalAccum(height int64) TotalAccum {
|
||||
return TotalAccum{
|
||||
UpdateHeight: height,
|
||||
Accum: sdk.ZeroDec(),
|
||||
}
|
||||
}
|
||||
|
||||
// update total validator accumulation factor for the new height
|
||||
// CONTRACT: height should be greater than the old height
|
||||
func (ta TotalAccum) UpdateForNewHeight(height int64, accumCreatedPerBlock sdk.Dec) TotalAccum {
|
||||
blocks := height - ta.UpdateHeight
|
||||
if blocks < 0 {
|
||||
panic("reverse updated for new height")
|
||||
}
|
||||
ta.Accum = ta.Accum.Add(accumCreatedPerBlock.MulInt(sdk.NewInt(blocks)))
|
||||
ta.UpdateHeight = height
|
||||
return ta
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________________
|
||||
|
||||
// global fee pool for distribution
|
||||
type FeePool struct {
|
||||
ValAccum TotalAccum `json:"val_accum"` // total valdator accum held by validators
|
||||
Pool DecCoins `json:"pool"` // funds for all validators which have yet to be withdrawn
|
||||
CommunityPool DecCoins `json:"community_pool"` // pool for community funds yet to be spent
|
||||
}
|
||||
|
||||
// update total validator accumulation factor
|
||||
func (f FeePool) UpdateTotalValAccum(height int64, totalBondedTokens sdk.Dec) FeePool {
|
||||
f.ValAccum = f.ValAccum.UpdateForNewHeight(height, totalBondedTokens)
|
||||
return f
|
||||
}
|
||||
|
||||
// zero fee pool
|
||||
func InitialFeePool() FeePool {
|
||||
return FeePool{
|
||||
ValAccum: NewTotalAccum(0),
|
||||
Pool: DecCoins{},
|
||||
CommunityPool: DecCoins{},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTotalAccumUpdateForNewHeight(t *testing.T) {
|
||||
|
||||
ta := NewTotalAccum(0)
|
||||
|
||||
ta = ta.UpdateForNewHeight(5, sdk.NewDec(3))
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(15), ta.Accum))
|
||||
|
||||
ta = ta.UpdateForNewHeight(8, sdk.NewDec(2))
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(21), ta.Accum))
|
||||
}
|
||||
|
||||
func TestUpdateTotalValAccum(t *testing.T) {
|
||||
|
||||
fp := InitialFeePool()
|
||||
|
||||
fp = fp.UpdateTotalValAccum(5, sdk.NewDec(3))
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(15), fp.ValAccum.Accum))
|
||||
|
||||
fp = fp.UpdateTotalValAccum(8, sdk.NewDec(2))
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(21), fp.ValAccum.Accum))
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package types
|
||||
|
||||
import sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
// the address for where distributions rewards are withdrawn to by default
|
||||
// this struct is only used at genesis to feed in default withdraw addresses
|
||||
type DelegatorWithdrawInfo struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
WithdrawAddr sdk.AccAddress `json:"withdraw_addr"`
|
||||
}
|
||||
|
||||
// GenesisState - all distribution state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
FeePool FeePool `json:"fee_pool"`
|
||||
ValidatorDistInfos []ValidatorDistInfo `json:"validator_dist_infos"`
|
||||
DelegatorDistInfos []DelegatorDistInfo `json:"delegator_dist_infos"`
|
||||
DelegatorWithdrawInfos []DelegatorWithdrawInfo `json:"delegator_withdraw_infos"`
|
||||
}
|
||||
|
||||
func NewGenesisState(feePool FeePool, vdis []ValidatorDistInfo, ddis []DelegatorDistInfo) GenesisState {
|
||||
return GenesisState{
|
||||
FeePool: feePool,
|
||||
ValidatorDistInfos: vdis,
|
||||
DelegatorDistInfos: ddis,
|
||||
}
|
||||
}
|
||||
|
||||
// get raw genesis raw message for testing
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return GenesisState{
|
||||
FeePool: InitialFeePool(),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package types
|
||||
|
||||
import sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
// expected stake keeper
|
||||
type StakeKeeper interface {
|
||||
IterateDelegations(ctx sdk.Context, delegator sdk.AccAddress,
|
||||
fn func(index int64, delegation sdk.Delegation) (stop bool))
|
||||
Delegation(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) sdk.Delegation
|
||||
Validator(ctx sdk.Context, valAddr sdk.ValAddress) sdk.Validator
|
||||
ValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) sdk.Validator
|
||||
TotalPower(ctx sdk.Context) sdk.Dec
|
||||
}
|
||||
|
||||
// expected coin keeper
|
||||
type BankKeeper interface {
|
||||
AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error)
|
||||
}
|
||||
|
||||
// from ante handler
|
||||
type FeeCollectionKeeper interface {
|
||||
GetCollectedFees(ctx sdk.Context) sdk.Coins
|
||||
ClearCollectedFees(ctx sdk.Context)
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
//nolint
|
||||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// name to identify transaction types
|
||||
const MsgType = "distr"
|
||||
|
||||
// Verify interface at compile time
|
||||
var _, _ sdk.Msg = &MsgSetWithdrawAddress{}, &MsgWithdrawDelegatorRewardsAll{}
|
||||
var _, _ sdk.Msg = &MsgWithdrawDelegatorReward{}, &MsgWithdrawValidatorRewardsAll{}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// msg struct for changing the withdraw address for a delegator (or validator self-delegation)
|
||||
type MsgSetWithdrawAddress struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
WithdrawAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
}
|
||||
|
||||
func NewMsgSetWithdrawAddress(delAddr, withdrawAddr sdk.AccAddress) MsgSetWithdrawAddress {
|
||||
return MsgSetWithdrawAddress{
|
||||
DelegatorAddr: delAddr,
|
||||
WithdrawAddr: withdrawAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg MsgSetWithdrawAddress) Type() string { return MsgType }
|
||||
func (msg MsgSetWithdrawAddress) Name() string { return "set_withdraw_address" }
|
||||
|
||||
// Return address that must sign over msg.GetSignBytes()
|
||||
func (msg MsgSetWithdrawAddress) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{sdk.AccAddress(msg.DelegatorAddr)}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgSetWithdrawAddress) GetSignBytes() []byte {
|
||||
b, err := MsgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgSetWithdrawAddress) ValidateBasic() sdk.Error {
|
||||
if msg.DelegatorAddr == nil {
|
||||
return ErrNilDelegatorAddr(DefaultCodespace)
|
||||
}
|
||||
if msg.WithdrawAddr == nil {
|
||||
return ErrNilWithdrawAddr(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// msg struct for delegation withdraw for all of the delegator's delegations
|
||||
type MsgWithdrawDelegatorRewardsAll struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
}
|
||||
|
||||
func NewMsgWithdrawDelegatorRewardsAll(delAddr sdk.AccAddress) MsgWithdrawDelegatorRewardsAll {
|
||||
return MsgWithdrawDelegatorRewardsAll{
|
||||
DelegatorAddr: delAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg MsgWithdrawDelegatorRewardsAll) Type() string { return MsgType }
|
||||
func (msg MsgWithdrawDelegatorRewardsAll) Name() string { return "withdraw_delegation_rewards_all" }
|
||||
|
||||
// Return address that must sign over msg.GetSignBytes()
|
||||
func (msg MsgWithdrawDelegatorRewardsAll) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{sdk.AccAddress(msg.DelegatorAddr)}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgWithdrawDelegatorRewardsAll) GetSignBytes() []byte {
|
||||
b, err := MsgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgWithdrawDelegatorRewardsAll) ValidateBasic() sdk.Error {
|
||||
if msg.DelegatorAddr == nil {
|
||||
return ErrNilDelegatorAddr(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// msg struct for delegation withdraw from a single validator
|
||||
type MsgWithdrawDelegatorReward struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
ValidatorAddr sdk.ValAddress `json:"validator_addr"`
|
||||
}
|
||||
|
||||
func NewMsgWithdrawDelegatorReward(delAddr sdk.AccAddress, valAddr sdk.ValAddress) MsgWithdrawDelegatorReward {
|
||||
return MsgWithdrawDelegatorReward{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg MsgWithdrawDelegatorReward) Type() string { return MsgType }
|
||||
func (msg MsgWithdrawDelegatorReward) Name() string { return "withdraw_delegation_reward" }
|
||||
|
||||
// Return address that must sign over msg.GetSignBytes()
|
||||
func (msg MsgWithdrawDelegatorReward) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{sdk.AccAddress(msg.DelegatorAddr)}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgWithdrawDelegatorReward) GetSignBytes() []byte {
|
||||
b, err := MsgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgWithdrawDelegatorReward) ValidateBasic() sdk.Error {
|
||||
if msg.DelegatorAddr == nil {
|
||||
return ErrNilDelegatorAddr(DefaultCodespace)
|
||||
}
|
||||
if msg.ValidatorAddr == nil {
|
||||
return ErrNilValidatorAddr(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// msg struct for validator withdraw
|
||||
type MsgWithdrawValidatorRewardsAll struct {
|
||||
ValidatorAddr sdk.ValAddress `json:"validator_addr"`
|
||||
}
|
||||
|
||||
func NewMsgWithdrawValidatorRewardsAll(valAddr sdk.ValAddress) MsgWithdrawValidatorRewardsAll {
|
||||
return MsgWithdrawValidatorRewardsAll{
|
||||
ValidatorAddr: valAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg MsgWithdrawValidatorRewardsAll) Type() string { return MsgType }
|
||||
func (msg MsgWithdrawValidatorRewardsAll) Name() string { return "withdraw_validator_rewards_all" }
|
||||
|
||||
// Return address that must sign over msg.GetSignBytes()
|
||||
func (msg MsgWithdrawValidatorRewardsAll) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{sdk.AccAddress(msg.ValidatorAddr.Bytes())}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgWithdrawValidatorRewardsAll) GetSignBytes() []byte {
|
||||
b, err := MsgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgWithdrawValidatorRewardsAll) ValidateBasic() sdk.Error {
|
||||
if msg.ValidatorAddr == nil {
|
||||
return ErrNilValidatorAddr(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// test ValidateBasic for MsgCreateValidator
|
||||
func TestMsgSetWithdrawAddress(t *testing.T) {
|
||||
tests := []struct {
|
||||
delegatorAddr sdk.AccAddress
|
||||
withdrawAddr sdk.AccAddress
|
||||
expectPass bool
|
||||
}{
|
||||
{delAddr1, delAddr2, true},
|
||||
{delAddr1, delAddr1, true},
|
||||
{emptyDelAddr, delAddr1, false},
|
||||
{delAddr1, emptyDelAddr, false},
|
||||
{emptyDelAddr, emptyDelAddr, false},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
msg := NewMsgSetWithdrawAddress(tc.delegatorAddr, tc.withdrawAddr)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test index: %v", i)
|
||||
} else {
|
||||
require.NotNil(t, msg.ValidateBasic(), "test index: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test ValidateBasic for MsgEditValidator
|
||||
func TestMsgWithdrawDelegatorReward(t *testing.T) {
|
||||
tests := []struct {
|
||||
delegatorAddr sdk.AccAddress
|
||||
validatorAddr sdk.ValAddress
|
||||
expectPass bool
|
||||
}{
|
||||
{delAddr1, valAddr1, true},
|
||||
{emptyDelAddr, valAddr1, false},
|
||||
{delAddr1, emptyValAddr, false},
|
||||
{emptyDelAddr, emptyValAddr, false},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
msg := NewMsgWithdrawDelegatorReward(tc.delegatorAddr, tc.validatorAddr)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test index: %v", i)
|
||||
} else {
|
||||
require.NotNil(t, msg.ValidateBasic(), "test index: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test ValidateBasic and GetSigners for MsgCreateValidatorOnBehalfOf
|
||||
func TestMsgWithdrawDelegatorRewardsAll(t *testing.T) {
|
||||
tests := []struct {
|
||||
delegatorAddr sdk.AccAddress
|
||||
expectPass bool
|
||||
}{
|
||||
{delAddr1, true},
|
||||
{emptyDelAddr, false},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
msg := NewMsgWithdrawDelegatorRewardsAll(tc.delegatorAddr)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test index: %v", i)
|
||||
} else {
|
||||
require.NotNil(t, msg.ValidateBasic(), "test index: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test ValidateBasic for MsgDelegate
|
||||
func TestMsgWithdrawValidatorRewardsAll(t *testing.T) {
|
||||
tests := []struct {
|
||||
validatorAddr sdk.ValAddress
|
||||
expectPass bool
|
||||
}{
|
||||
{valAddr1, true},
|
||||
{emptyValAddr, false},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
msg := NewMsgWithdrawValidatorRewardsAll(tc.validatorAddr)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test index: %v", i)
|
||||
} else {
|
||||
require.NotNil(t, msg.ValidateBasic(), "test index: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
)
|
||||
|
||||
var (
|
||||
delPk1 = ed25519.GenPrivKey().PubKey()
|
||||
delPk2 = ed25519.GenPrivKey().PubKey()
|
||||
delPk3 = ed25519.GenPrivKey().PubKey()
|
||||
delAddr1 = sdk.AccAddress(delPk1.Address())
|
||||
delAddr2 = sdk.AccAddress(delPk2.Address())
|
||||
delAddr3 = sdk.AccAddress(delPk3.Address())
|
||||
emptyDelAddr sdk.AccAddress
|
||||
|
||||
valPk1 = ed25519.GenPrivKey().PubKey()
|
||||
valPk2 = ed25519.GenPrivKey().PubKey()
|
||||
valPk3 = ed25519.GenPrivKey().PubKey()
|
||||
valAddr1 = sdk.ValAddress(delPk1.Address())
|
||||
valAddr2 = sdk.ValAddress(delPk2.Address())
|
||||
valAddr3 = sdk.ValAddress(delPk3.Address())
|
||||
emptyValAddr sdk.ValAddress
|
||||
|
||||
emptyPubkey crypto.PubKey
|
||||
)
|
|
@ -0,0 +1,72 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// distribution info for a particular validator
|
||||
type ValidatorDistInfo struct {
|
||||
OperatorAddr sdk.ValAddress `json:"operator_addr"`
|
||||
|
||||
FeePoolWithdrawalHeight int64 `json:"global_withdrawal_height"` // last height this validator withdrew from the global pool
|
||||
Pool DecCoins `json:"pool"` // rewards owed to delegators, commission has already been charged (includes proposer reward)
|
||||
PoolCommission DecCoins `json:"pool_commission"` // commission collected by this validator (pending withdrawal)
|
||||
|
||||
DelAccum TotalAccum `json:"del_accum"` // total proposer pool accumulation factor held by delegators
|
||||
}
|
||||
|
||||
func NewValidatorDistInfo(operatorAddr sdk.ValAddress, currentHeight int64) ValidatorDistInfo {
|
||||
return ValidatorDistInfo{
|
||||
OperatorAddr: operatorAddr,
|
||||
FeePoolWithdrawalHeight: currentHeight,
|
||||
Pool: DecCoins{},
|
||||
PoolCommission: DecCoins{},
|
||||
DelAccum: NewTotalAccum(currentHeight),
|
||||
}
|
||||
}
|
||||
|
||||
// update total delegator accumululation
|
||||
func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares sdk.Dec) ValidatorDistInfo {
|
||||
vi.DelAccum = vi.DelAccum.UpdateForNewHeight(height, totalDelShares)
|
||||
return vi
|
||||
}
|
||||
|
||||
// move any available accumulated fees in the FeePool to the validator's pool
|
||||
func (vi ValidatorDistInfo) TakeFeePoolRewards(fp FeePool, height int64, totalBonded, vdTokens,
|
||||
commissionRate sdk.Dec) (ValidatorDistInfo, FeePool) {
|
||||
|
||||
fp = fp.UpdateTotalValAccum(height, totalBonded)
|
||||
|
||||
if fp.ValAccum.Accum.IsZero() {
|
||||
return vi, fp
|
||||
}
|
||||
|
||||
// update the validators pool
|
||||
blocks := height - vi.FeePoolWithdrawalHeight
|
||||
vi.FeePoolWithdrawalHeight = height
|
||||
accum := vdTokens.MulInt(sdk.NewInt(blocks))
|
||||
withdrawalTokens := fp.Pool.MulDec(accum).QuoDec(fp.ValAccum.Accum)
|
||||
remainingTokens := fp.Pool.Minus(withdrawalTokens)
|
||||
|
||||
commission := withdrawalTokens.MulDec(commissionRate)
|
||||
afterCommission := withdrawalTokens.Minus(commission)
|
||||
|
||||
fp.ValAccum.Accum = fp.ValAccum.Accum.Sub(accum)
|
||||
fp.Pool = remainingTokens
|
||||
vi.PoolCommission = vi.PoolCommission.Plus(commission)
|
||||
vi.Pool = vi.Pool.Plus(afterCommission)
|
||||
|
||||
return vi, fp
|
||||
}
|
||||
|
||||
// withdraw commission rewards
|
||||
func (vi ValidatorDistInfo) WithdrawCommission(fp FeePool, height int64,
|
||||
totalBonded, vdTokens, commissionRate sdk.Dec) (vio ValidatorDistInfo, fpo FeePool, withdrawn DecCoins) {
|
||||
|
||||
vi, fp = vi.TakeFeePoolRewards(fp, height, totalBonded, vdTokens, commissionRate)
|
||||
|
||||
withdrawalTokens := vi.PoolCommission
|
||||
vi.PoolCommission = DecCoins{} // zero
|
||||
|
||||
return vi, fp, withdrawalTokens
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTakeFeePoolRewards(t *testing.T) {
|
||||
|
||||
// initialize
|
||||
height := int64(0)
|
||||
fp := InitialFeePool()
|
||||
vi1 := NewValidatorDistInfo(valAddr1, height)
|
||||
vi2 := NewValidatorDistInfo(valAddr2, height)
|
||||
vi3 := NewValidatorDistInfo(valAddr3, height)
|
||||
commissionRate1 := sdk.NewDecWithPrec(2, 2)
|
||||
commissionRate2 := sdk.NewDecWithPrec(3, 2)
|
||||
commissionRate3 := sdk.NewDecWithPrec(4, 2)
|
||||
validatorTokens1 := sdk.NewDec(10)
|
||||
validatorTokens2 := sdk.NewDec(40)
|
||||
validatorTokens3 := sdk.NewDec(50)
|
||||
totalBondedTokens := validatorTokens1.Add(validatorTokens2).Add(validatorTokens3)
|
||||
|
||||
// simulate adding some stake for inflation
|
||||
height = 10
|
||||
fp.Pool = DecCoins{NewDecCoin("stake", 1000)}
|
||||
|
||||
vi1, fp = vi1.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens1, commissionRate1)
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(900), fp.ValAccum.Accum))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(100-2), vi1.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi1.PoolCommission[0].Amount))
|
||||
|
||||
vi2, fp = vi2.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens2, commissionRate2)
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(500), fp.ValAccum.Accum))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(500), fp.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(400-12), vi2.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, vi2.PoolCommission[0].Amount, sdk.NewDec(12)))
|
||||
|
||||
// add more blocks and inflation
|
||||
height = 20
|
||||
fp.Pool[0].Amount = fp.Pool[0].Amount.Add(sdk.NewDec(1000))
|
||||
|
||||
vi3, fp = vi3.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens3, commissionRate3)
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(500), fp.ValAccum.Accum))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(500), fp.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(1000-40), vi3.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, vi3.PoolCommission[0].Amount, sdk.NewDec(40)))
|
||||
}
|
||||
|
||||
func TestWithdrawCommission(t *testing.T) {
|
||||
|
||||
// initialize
|
||||
height := int64(0)
|
||||
fp := InitialFeePool()
|
||||
vi := NewValidatorDistInfo(valAddr1, height)
|
||||
commissionRate := sdk.NewDecWithPrec(2, 2)
|
||||
validatorTokens := sdk.NewDec(10)
|
||||
totalBondedTokens := validatorTokens.Add(sdk.NewDec(90)) // validator-1 is 10% of total power
|
||||
|
||||
// simulate adding some stake for inflation
|
||||
height = 10
|
||||
fp.Pool = DecCoins{NewDecCoin("stake", 1000)}
|
||||
|
||||
// for a more fun staring condition, have an non-withdraw update
|
||||
vi, fp = vi.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens, commissionRate)
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(900), fp.ValAccum.Accum))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(100-2), vi.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi.PoolCommission[0].Amount))
|
||||
|
||||
// add more blocks and inflation
|
||||
height = 20
|
||||
fp.Pool[0].Amount = fp.Pool[0].Amount.Add(sdk.NewDec(1000))
|
||||
|
||||
vi, fp, commissionRecv := vi.WithdrawCommission(fp, height, totalBondedTokens, validatorTokens, commissionRate)
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(1800), fp.ValAccum.Accum))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.Pool[0].Amount))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(200-4), vi.Pool[0].Amount))
|
||||
assert.Zero(t, len(vi.PoolCommission))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(4), commissionRecv[0].Amount))
|
||||
}
|
|
@ -177,28 +177,28 @@ func GetREDByValDstIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.V
|
|||
return key
|
||||
}
|
||||
|
||||
// rearranges the ValSrcIndexKey to get the REDKey
|
||||
func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte {
|
||||
addrs := IndexKey[1:] // remove prefix bytes
|
||||
if len(addrs) != 3*sdk.AddrLen {
|
||||
// GetREDKeyFromValSrcIndexKey rearranges the ValSrcIndexKey to get the REDKey
|
||||
func GetREDKeyFromValSrcIndexKey(indexKey []byte) []byte {
|
||||
// note that first byte is prefix byte
|
||||
if len(indexKey) != 3*sdk.AddrLen+1 {
|
||||
panic("unexpected key length")
|
||||
}
|
||||
valSrcAddr := addrs[:sdk.AddrLen]
|
||||
delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen]
|
||||
valDstAddr := addrs[2*sdk.AddrLen:]
|
||||
valSrcAddr := indexKey[1 : sdk.AddrLen+1]
|
||||
delAddr := indexKey[sdk.AddrLen+1 : 2*sdk.AddrLen+1]
|
||||
valDstAddr := indexKey[2*sdk.AddrLen+1 : 3*sdk.AddrLen+1]
|
||||
|
||||
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
|
||||
}
|
||||
|
||||
// rearranges the ValDstIndexKey to get the REDKey
|
||||
func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte {
|
||||
addrs := IndexKey[1:] // remove prefix bytes
|
||||
if len(addrs) != 3*sdk.AddrLen {
|
||||
// GetREDKeyFromValDstIndexKey rearranges the ValDstIndexKey to get the REDKey
|
||||
func GetREDKeyFromValDstIndexKey(indexKey []byte) []byte {
|
||||
// note that first byte is prefix byte
|
||||
if len(indexKey) != 3*sdk.AddrLen+1 {
|
||||
panic("unexpected key length")
|
||||
}
|
||||
valDstAddr := addrs[:sdk.AddrLen]
|
||||
delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen]
|
||||
valSrcAddr := addrs[2*sdk.AddrLen:]
|
||||
valDstAddr := indexKey[1 : sdk.AddrLen+1]
|
||||
delAddr := indexKey[sdk.AddrLen+1 : 2*sdk.AddrLen+1]
|
||||
valSrcAddr := indexKey[2*sdk.AddrLen+1 : 3*sdk.AddrLen+1]
|
||||
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,30 +2,43 @@ package keeper
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
)
|
||||
|
||||
var (
|
||||
pk1 = ed25519.GenPrivKey().PubKey()
|
||||
pk1 = ed25519.GenPrivKeyFromSecret([]byte{1}).PubKey()
|
||||
pk2 = ed25519.GenPrivKeyFromSecret([]byte{2}).PubKey()
|
||||
pk3 = ed25519.GenPrivKeyFromSecret([]byte{3}).PubKey()
|
||||
addr1 = pk1.Address()
|
||||
addr2 = pk2.Address()
|
||||
addr3 = pk3.Address()
|
||||
)
|
||||
|
||||
func TestGetValidatorPowerRank(t *testing.T) {
|
||||
valAddr1 := sdk.ValAddress(pk1.Bytes())
|
||||
valAddr1 := sdk.ValAddress(addr1)
|
||||
emptyDesc := types.Description{}
|
||||
val1 := types.NewValidator(valAddr1, pk1, emptyDesc)
|
||||
val1.Tokens = sdk.NewDec(12)
|
||||
val1.Tokens = sdk.NewDec(0)
|
||||
val2, val3, val4 := val1, val1, val1
|
||||
val2.Tokens = sdk.NewDec(1)
|
||||
val3.Tokens = sdk.NewDec(10)
|
||||
x := new(big.Int).Exp(big.NewInt(2), big.NewInt(40), big.NewInt(0))
|
||||
val4.Tokens = sdk.NewDecFromBigInt(x)
|
||||
|
||||
tests := []struct {
|
||||
validator types.Validator
|
||||
wantHex string
|
||||
}{
|
||||
{val1, "05303030303030303030303132ffffffffffffffffffff"},
|
||||
{val1, "05303030303030303030303030ffffffffffffffffffff"},
|
||||
{val2, "05303030303030303030303031ffffffffffffffffffff"},
|
||||
{val3, "05303030303030303030303130ffffffffffffffffffff"},
|
||||
{val4, "0531303939353131363237373736ffffffffffffffffffff"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
got := hex.EncodeToString(getValidatorPowerRank(tt.validator))
|
||||
|
@ -33,3 +46,45 @@ func TestGetValidatorPowerRank(t *testing.T) {
|
|||
assert.Equal(t, tt.wantHex, got, "Keys did not match on test case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetREDByValDstIndexKey(t *testing.T) {
|
||||
tests := []struct {
|
||||
delAddr sdk.AccAddress
|
||||
valSrcAddr sdk.ValAddress
|
||||
valDstAddr sdk.ValAddress
|
||||
wantHex string
|
||||
}{
|
||||
{sdk.AccAddress(addr1), sdk.ValAddress(addr1), sdk.ValAddress(addr1),
|
||||
"0c63d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f08609"},
|
||||
{sdk.AccAddress(addr1), sdk.ValAddress(addr2), sdk.ValAddress(addr3),
|
||||
"0c3ab62f0d93849be495e21e3e9013a517038f45bd63d771218209d8bd03c482f69dfba57310f086095ef3b5f25c54946d4a89fc0d09d2f126614540f2"},
|
||||
{sdk.AccAddress(addr2), sdk.ValAddress(addr1), sdk.ValAddress(addr3),
|
||||
"0c3ab62f0d93849be495e21e3e9013a517038f45bd5ef3b5f25c54946d4a89fc0d09d2f126614540f263d771218209d8bd03c482f69dfba57310f08609"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
got := hex.EncodeToString(GetREDByValDstIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr))
|
||||
|
||||
assert.Equal(t, tt.wantHex, got, "Keys did not match on test case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetREDByValSrcIndexKey(t *testing.T) {
|
||||
tests := []struct {
|
||||
delAddr sdk.AccAddress
|
||||
valSrcAddr sdk.ValAddress
|
||||
valDstAddr sdk.ValAddress
|
||||
wantHex string
|
||||
}{
|
||||
{sdk.AccAddress(addr1), sdk.ValAddress(addr1), sdk.ValAddress(addr1),
|
||||
"0b63d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f08609"},
|
||||
{sdk.AccAddress(addr1), sdk.ValAddress(addr2), sdk.ValAddress(addr3),
|
||||
"0b5ef3b5f25c54946d4a89fc0d09d2f126614540f263d771218209d8bd03c482f69dfba57310f086093ab62f0d93849be495e21e3e9013a517038f45bd"},
|
||||
{sdk.AccAddress(addr2), sdk.ValAddress(addr1), sdk.ValAddress(addr3),
|
||||
"0b63d771218209d8bd03c482f69dfba57310f086095ef3b5f25c54946d4a89fc0d09d2f126614540f23ab62f0d93849be495e21e3e9013a517038f45bd"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
got := hex.EncodeToString(GetREDByValSrcIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr))
|
||||
|
||||
assert.Equal(t, tt.wantHex, got, "Keys did not match on test case %d", i)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue