Merge branch 'develop' into release/v0.30.0
This commit is contained in:
commit
5ab744082a
|
@ -10,6 +10,7 @@
|
|||
|
||||
# Build
|
||||
vendor
|
||||
vendor-deps
|
||||
.vendor-new
|
||||
build
|
||||
tools/bin/*
|
||||
|
|
|
@ -33,6 +33,7 @@ BREAKING CHANGES
|
|||
* [\#3249\(https://github.com/cosmos/cosmos-sdk/issues/3249) `tendermint`'s `show-validator` and `show-address` `--json` flags removed in favor of `--output-format=json`.
|
||||
|
||||
* SDK
|
||||
* [distribution] \#3359 Always round down when calculating rewards-to-be-withdrawn in F1 fee distribution
|
||||
* [#3336](https://github.com/cosmos/cosmos-sdk/issues/3336) Ensure all SDK
|
||||
messages have their signature bytes contain canonical fields `value` and `type`.
|
||||
* [\#3333](https://github.com/cosmos/cosmos-sdk/issues/3333) - F1 storage efficiency improvements - automatic withdrawals when unbonded, historical reward reference counting
|
||||
|
|
10
Makefile
10
Makefile
|
@ -62,13 +62,13 @@ else
|
|||
go build $(BUILD_FLAGS) -o build/gaiakeyutil ./cmd/gaia/cmd/gaiakeyutil
|
||||
endif
|
||||
|
||||
build-linux:
|
||||
build-linux: vendor-deps
|
||||
LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build
|
||||
|
||||
update_gaia_lite_docs:
|
||||
@statik -src=client/lcd/swagger-ui -dest=client/lcd -f
|
||||
|
||||
install: check-ledger update_gaia_lite_docs
|
||||
install: vendor-deps check-ledger update_gaia_lite_docs
|
||||
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
|
||||
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
|
||||
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiareplay
|
||||
|
@ -156,15 +156,15 @@ test_sim_gaia_fast:
|
|||
|
||||
test_sim_gaia_import_export:
|
||||
@echo "Running Gaia import/export simulation. This may take several minutes..."
|
||||
@bash scripts/multisim.sh 50 TestGaiaImportExport
|
||||
@bash scripts/multisim.sh 50 5 TestGaiaImportExport
|
||||
|
||||
test_sim_gaia_simulation_after_import:
|
||||
@echo "Running Gaia simulation-after-import. This may take several minutes..."
|
||||
@bash scripts/multisim.sh 50 TestGaiaSimulationAfterImport
|
||||
@bash scripts/multisim.sh 50 5 TestGaiaSimulationAfterImport
|
||||
|
||||
test_sim_gaia_multi_seed:
|
||||
@echo "Running multi-seed Gaia simulation. This may take awhile!"
|
||||
@bash scripts/multisim.sh 400 TestFullGaiaSimulation
|
||||
@bash scripts/multisim.sh 400 5 TestFullGaiaSimulation
|
||||
|
||||
SIM_NUM_BLOCKS ?= 500
|
||||
SIM_BLOCK_SIZE ?= 200
|
||||
|
|
|
@ -64,9 +64,13 @@ type GenesisAccount struct {
|
|||
Coins sdk.Coins `json:"coins"`
|
||||
Sequence uint64 `json:"sequence_number"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
Vesting bool `json:"vesting"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
EndTime int64 `json:"end_time"`
|
||||
|
||||
// vesting account fields
|
||||
OriginalVesting sdk.Coins `json:"original_vesting"` // total vesting coins upon initialization
|
||||
DelegatedFree sdk.Coins `json:"delegated_free"` // delegated vested coins at time of delegation
|
||||
DelegatedVesting sdk.Coins `json:"delegated_vesting"` // delegated vesting coins at time of delegation
|
||||
StartTime int64 `json:"start_time"` // vesting start time
|
||||
EndTime int64 `json:"end_time"` // vesting end time
|
||||
}
|
||||
|
||||
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||
|
@ -88,7 +92,9 @@ func NewGenesisAccountI(acc auth.Account) GenesisAccount {
|
|||
|
||||
vacc, ok := acc.(auth.VestingAccount)
|
||||
if ok {
|
||||
gacc.Vesting = true
|
||||
gacc.OriginalVesting = vacc.GetOriginalVesting()
|
||||
gacc.DelegatedFree = vacc.GetDelegatedFree()
|
||||
gacc.DelegatedVesting = vacc.GetDelegatedVesting()
|
||||
gacc.StartTime = vacc.GetStartTime()
|
||||
gacc.EndTime = vacc.GetEndTime()
|
||||
}
|
||||
|
@ -105,11 +111,24 @@ func (ga *GenesisAccount) ToAccount() auth.Account {
|
|||
Sequence: ga.Sequence,
|
||||
}
|
||||
|
||||
if ga.Vesting {
|
||||
if !ga.OriginalVesting.IsZero() {
|
||||
baseVestingAcc := &auth.BaseVestingAccount{
|
||||
BaseAccount: bacc,
|
||||
OriginalVesting: ga.OriginalVesting,
|
||||
DelegatedFree: ga.DelegatedFree,
|
||||
DelegatedVesting: ga.DelegatedVesting,
|
||||
EndTime: ga.EndTime,
|
||||
}
|
||||
|
||||
if ga.StartTime != 0 && ga.EndTime != 0 {
|
||||
return auth.NewContinuousVestingAccount(bacc, ga.StartTime, ga.EndTime)
|
||||
return &auth.ContinuousVestingAccount{
|
||||
BaseVestingAccount: baseVestingAcc,
|
||||
StartTime: ga.StartTime,
|
||||
}
|
||||
} else if ga.EndTime != 0 {
|
||||
return auth.NewDelayedVestingAccount(bacc, ga.EndTime)
|
||||
return &auth.DelayedVestingAccount{
|
||||
BaseVestingAccount: baseVestingAcc,
|
||||
}
|
||||
} else {
|
||||
panic(fmt.Sprintf("invalid genesis vesting account: %+v", ga))
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ func TestToAccount(t *testing.T) {
|
|||
priv := ed25519.GenPrivKey()
|
||||
addr := sdk.AccAddress(priv.PubKey().Address())
|
||||
authAcc := auth.NewBaseAccountWithAddress(addr)
|
||||
authAcc.SetCoins(sdk.Coins{sdk.NewInt64Coin(bondDenom, 150)})
|
||||
genAcc := NewGenesisAccount(&authAcc)
|
||||
acc := genAcc.ToAccount()
|
||||
require.IsType(t, &auth.BaseAccount{}, acc)
|
||||
|
|
|
@ -425,8 +425,10 @@ func TestGaiaImportExport(t *testing.T) {
|
|||
storeB := ctxB.KVStore(storeKeyB)
|
||||
kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB, prefixes)
|
||||
fmt.Printf("Compared %d key/value pairs between %s and %s\n", count, storeKeyA, storeKeyB)
|
||||
require.True(t, equal, "unequal stores: %s / %s:\nstore A %s (%X) => %s (%X)\nstore B %s (%X) => %s (%X)",
|
||||
storeKeyA, storeKeyB, kvA.Key, kvA.Key, kvA.Value, kvA.Value, kvB.Key, kvB.Key, kvB.Value, kvB.Value)
|
||||
require.True(t, equal,
|
||||
"unequal stores: %s / %s:\nstore A %X => %X\nstore B %X => %X",
|
||||
storeKeyA, storeKeyB, kvA.Key, kvA.Value, kvB.Key, kvB.Value,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,14 +16,15 @@ This module will be used in the Cosmos Hub.
|
|||
1. **[State](state.md)**
|
||||
1. [Accounts](state.md#accounts)
|
||||
1. [Account Interface](state.md#account-interface)
|
||||
1. [Base Account](state.md#baseaccount)
|
||||
1. [Vesting Account](state.md#vestingaccount)
|
||||
2. [Base Account](state.md#baseaccount)
|
||||
3. [Vesting Account](state.md#vestingaccount)
|
||||
1. **[Types](types.md)**
|
||||
1. [StdFee](types.md#stdfee)
|
||||
1. [StdSignature](types.md#stdsignature)
|
||||
1. [StdTx](types.md#stdtx)
|
||||
1. [StdSignDoc](types.md#stdsigndoc)
|
||||
2. [StdSignature](types.md#stdsignature)
|
||||
3. [StdTx](types.md#stdtx)
|
||||
4. [StdSignDoc](types.md#stdsigndoc)
|
||||
1. **[Keepers](keepers.md)**
|
||||
1. [AccountKeeper](keepers.md#account-keeper)
|
||||
1. **[Handlers](handlers.md)**
|
||||
1. [Ante Handler](handlers.md#ante-handler)
|
||||
1. **[Gas & Fees](gas_fees.md)**
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# Gas & Fees
|
||||
|
||||
Fees serve two purposes for an operator of the network.
|
||||
|
||||
Fees limit the growth of the state stored by every full node and allow for
|
||||
general purpose censorship of transactions of little economic value. Fees
|
||||
are best suited as an anti-spam mechanism where validators are disinterested in
|
||||
the use of the network and identities of users.
|
||||
|
||||
Fees are determined by the gas limits and gas prices transactions provide.
|
||||
Operators should set minimum gas prices when starting their nodes. They must set
|
||||
the unit costs of gas in each token denomination they wish to support:
|
||||
|
||||
`gaiad start ... --minimum-gas-prices=0.00001steak,0.05photinos`
|
||||
|
||||
When adding transactions to mempool or gossipping transactions, validators check
|
||||
if the transaction's gas prices, which are determined by the provided fees, meet
|
||||
any of the validator's minimum gas prices. In other words, a transaction must
|
||||
provide a fee of at least one denomination that matches a validator's minimum
|
||||
gas price.
|
||||
|
||||
Tendermint does not currently provide fee based mempool prioritization, and fee
|
||||
based mempool filtering is local to node and not part of consensus. But with
|
||||
minimum gas prices set, such a mechanism could be implemented by node operators.
|
||||
|
||||
Because the market value for tokens will fluctuate, validators are expected to
|
||||
dynamically adjust their minimum gas prices to a level that would encourage the
|
||||
use of the network.
|
|
@ -316,19 +316,22 @@ and return the correct accounts accordingly based off of these new fields.
|
|||
type GenesisAccount struct {
|
||||
// ...
|
||||
|
||||
Vesting bool
|
||||
EndTime int64
|
||||
StartTime int64
|
||||
// vesting account fields
|
||||
OriginalVesting sdk.Coins `json:"original_vesting"`
|
||||
DelegatedFree sdk.Coins `json:"delegated_free"`
|
||||
DelegatedVesting sdk.Coins `json:"delegated_vesting"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
EndTime int64 `json:"end_time"`
|
||||
}
|
||||
|
||||
func ToAccount(gacc GenesisAccount) Account {
|
||||
bacc := NewBaseAccount(gacc)
|
||||
|
||||
if gacc.Vesting {
|
||||
if gacc.OriginalVesting > 0 {
|
||||
if ga.StartTime != 0 && ga.EndTime != 0 {
|
||||
return NewContinuousVestingAccount(bacc, gacc.StartTime, gacc.EndTime)
|
||||
// return a continuous vesting account
|
||||
} else if ga.EndTime != 0 {
|
||||
return NewDelayedVestingAccount(bacc, gacc.EndTime)
|
||||
// return a delayed vesting account
|
||||
} else {
|
||||
// invalid genesis vesting account provided
|
||||
panic()
|
||||
|
|
|
@ -23,7 +23,7 @@ sim() {
|
|||
file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -u +"%Y-%m-%dT%H:%M:%S+00:00").stdout"
|
||||
echo "Writing stdout to $file..."
|
||||
go test ./cmd/gaia/app -run $testname -SimulationEnabled=true -SimulationNumBlocks=$blocks \
|
||||
-SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$seed -SimulationPeriod=$period -v -timeout 24h | tee $file
|
||||
-SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$seed -SimulationPeriod=$period -v -timeout 24h > $file
|
||||
}
|
||||
|
||||
i=0
|
||||
|
|
|
@ -201,6 +201,19 @@ func (coins DecCoins) MulDec(d Dec) DecCoins {
|
|||
return res
|
||||
}
|
||||
|
||||
// multiply all the coins by a decimal, truncating
|
||||
func (coins DecCoins) MulDecTruncate(d Dec) DecCoins {
|
||||
res := make([]DecCoin, len(coins))
|
||||
for i, coin := range coins {
|
||||
product := DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount.MulTruncate(d),
|
||||
}
|
||||
res[i] = product
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// divide all the coins by a decimal
|
||||
func (coins DecCoins) QuoDec(d Dec) DecCoins {
|
||||
res := make([]DecCoin, len(coins))
|
||||
|
@ -214,6 +227,19 @@ func (coins DecCoins) QuoDec(d Dec) DecCoins {
|
|||
return res
|
||||
}
|
||||
|
||||
// divide all the coins by a decimal, truncating
|
||||
func (coins DecCoins) QuoDecTruncate(d Dec) DecCoins {
|
||||
res := make([]DecCoin, len(coins))
|
||||
for i, coin := range coins {
|
||||
quotient := DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount.QuoTruncate(d),
|
||||
}
|
||||
res[i] = quotient
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// returns the amount of a denom from deccoins
|
||||
func (coins DecCoins) AmountOf(denom string) Dec {
|
||||
switch len(coins) {
|
||||
|
|
|
@ -228,6 +228,17 @@ func (d Dec) Mul(d2 Dec) Dec {
|
|||
return Dec{chopped}
|
||||
}
|
||||
|
||||
// multiplication truncate
|
||||
func (d Dec) MulTruncate(d2 Dec) Dec {
|
||||
mul := new(big.Int).Mul(d.Int, d2.Int)
|
||||
chopped := chopPrecisionAndTruncate(mul)
|
||||
|
||||
if chopped.BitLen() > 255+DecimalPrecisionBits {
|
||||
panic("Int overflow")
|
||||
}
|
||||
return Dec{chopped}
|
||||
}
|
||||
|
||||
// multiplication
|
||||
func (d Dec) MulInt(i Int) Dec {
|
||||
mul := new(big.Int).Mul(d.Int, i.i)
|
||||
|
@ -254,6 +265,22 @@ func (d Dec) Quo(d2 Dec) Dec {
|
|||
return Dec{chopped}
|
||||
}
|
||||
|
||||
// quotient truncate
|
||||
func (d Dec) QuoTruncate(d2 Dec) Dec {
|
||||
|
||||
// multiply precision twice
|
||||
mul := new(big.Int).Mul(d.Int, precisionReuse)
|
||||
mul.Mul(mul, precisionReuse)
|
||||
|
||||
quo := new(big.Int).Quo(mul, d2.Int)
|
||||
chopped := chopPrecisionAndTruncate(quo)
|
||||
|
||||
if chopped.BitLen() > 255+DecimalPrecisionBits {
|
||||
panic("Int overflow")
|
||||
}
|
||||
return Dec{chopped}
|
||||
}
|
||||
|
||||
// quotient
|
||||
func (d Dec) QuoInt(i Int) Dec {
|
||||
mul := new(big.Int).Quo(d.Int, i.i)
|
||||
|
|
|
@ -55,6 +55,10 @@ type VestingAccount interface {
|
|||
|
||||
GetStartTime() int64
|
||||
GetEndTime() int64
|
||||
|
||||
GetOriginalVesting() sdk.Coins
|
||||
GetDelegatedFree() sdk.Coins
|
||||
GetDelegatedVesting() sdk.Coins
|
||||
}
|
||||
|
||||
// AccountDecoder unmarshals account bytes
|
||||
|
@ -179,18 +183,20 @@ type BaseVestingAccount struct {
|
|||
|
||||
// String implements fmt.Stringer
|
||||
func (bva BaseVestingAccount) String() string {
|
||||
return fmt.Sprintf(`Vesting Account %s:
|
||||
return fmt.Sprintf(`Vesting Account:
|
||||
Address: %s
|
||||
Coins: %s
|
||||
PubKey: %s
|
||||
AccountNumber: %d
|
||||
Sequence: %d
|
||||
OriginalVesting: %s
|
||||
DelegatedFree: %s
|
||||
DelegatedVesting: %s
|
||||
EndTime: %d `, bva.Address, bva.Coins,
|
||||
bva.PubKey.Address(), bva.AccountNumber, bva.Sequence,
|
||||
EndTime: %d `,
|
||||
bva.Address, bva.Coins,
|
||||
bva.AccountNumber, bva.Sequence,
|
||||
bva.OriginalVesting, bva.DelegatedFree,
|
||||
bva.DelegatedVesting, bva.EndTime)
|
||||
bva.DelegatedVesting, bva.EndTime,
|
||||
)
|
||||
}
|
||||
|
||||
// spendableCoins returns all the spendable coins for a vesting account given a
|
||||
|
@ -342,6 +348,23 @@ func (bva *BaseVestingAccount) TrackUndelegation(amount sdk.Coins) {
|
|||
}
|
||||
}
|
||||
|
||||
// GetOriginalVesting returns a vesting account's original vesting amount
|
||||
func (bva BaseVestingAccount) GetOriginalVesting() sdk.Coins {
|
||||
return bva.OriginalVesting
|
||||
}
|
||||
|
||||
// GetDelegatedFree returns a vesting account's delegation amount that is not
|
||||
// vesting.
|
||||
func (bva BaseVestingAccount) GetDelegatedFree() sdk.Coins {
|
||||
return bva.DelegatedFree
|
||||
}
|
||||
|
||||
// GetDelegatedVesting returns a vesting account's delegation amount that is
|
||||
// still vesting.
|
||||
func (bva BaseVestingAccount) GetDelegatedVesting() sdk.Coins {
|
||||
return bva.DelegatedVesting
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Continuous Vesting Account
|
||||
|
||||
|
@ -372,19 +395,21 @@ func NewContinuousVestingAccount(
|
|||
}
|
||||
|
||||
func (cva ContinuousVestingAccount) String() string {
|
||||
return fmt.Sprintf(`Vesting Account %s:
|
||||
return fmt.Sprintf(`Continuous Vesting Account:
|
||||
Address: %s
|
||||
Coins: %s
|
||||
PubKey: %s
|
||||
AccountNumber: %d
|
||||
Sequence: %d
|
||||
OriginalVesting: %s
|
||||
DelegatedFree: %s
|
||||
DelegatedVesting: %s
|
||||
StartTime: %d
|
||||
EndTime: %d `, cva.Address, cva.Coins,
|
||||
cva.PubKey.Address(), cva.AccountNumber, cva.Sequence,
|
||||
EndTime: %d `,
|
||||
cva.Address, cva.Coins,
|
||||
cva.AccountNumber, cva.Sequence,
|
||||
cva.OriginalVesting, cva.DelegatedFree,
|
||||
cva.DelegatedVesting, cva.StartTime, cva.EndTime)
|
||||
cva.DelegatedVesting, cva.StartTime, cva.EndTime,
|
||||
)
|
||||
}
|
||||
|
||||
// GetVestedCoins returns the total number of vested coins. If no coins are vested,
|
||||
|
|
|
@ -28,24 +28,36 @@ func SimulateDeductFee(m auth.AccountKeeper, f auth.FeeCollectionKeeper) simulat
|
|||
}
|
||||
|
||||
denomIndex := r.Intn(len(initCoins))
|
||||
amt, err := randPositiveInt(r, initCoins[denomIndex].Amount)
|
||||
randCoin := initCoins[denomIndex]
|
||||
|
||||
amt, err := randPositiveInt(r, randCoin.Amount)
|
||||
if err != nil {
|
||||
event(fmt.Sprintf("auth/SimulateDeductFee/false"))
|
||||
return action, nil, nil
|
||||
}
|
||||
|
||||
coins := sdk.Coins{sdk.NewCoin(initCoins[denomIndex].Denom, amt)}
|
||||
err = stored.SetCoins(initCoins.Minus(coins))
|
||||
if err != nil {
|
||||
// Create a random fee and verify the fees are within the account's spendable
|
||||
// balance.
|
||||
fees := sdk.Coins{sdk.NewCoin(randCoin.Denom, amt)}
|
||||
spendableCoins := stored.SpendableCoins(ctx.BlockHeader().Time)
|
||||
if _, hasNeg := spendableCoins.SafeMinus(fees); hasNeg {
|
||||
event(fmt.Sprintf("auth/SimulateDeductFee/false"))
|
||||
return action, nil, nil
|
||||
}
|
||||
|
||||
// get the new account balance
|
||||
newCoins, hasNeg := initCoins.SafeMinus(fees)
|
||||
if hasNeg {
|
||||
event(fmt.Sprintf("auth/SimulateDeductFee/false"))
|
||||
return action, nil, nil
|
||||
}
|
||||
|
||||
if err := stored.SetCoins(newCoins); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
m.SetAccount(ctx, stored)
|
||||
if !coins.IsNotNegative() {
|
||||
panic("setting negative fees")
|
||||
}
|
||||
|
||||
f.AddCollectedFees(ctx, coins)
|
||||
|
||||
f.AddCollectedFees(ctx, fees)
|
||||
event(fmt.Sprintf("auth/SimulateDeductFee/true"))
|
||||
|
||||
action = "TestDeductFee"
|
||||
|
|
|
@ -11,28 +11,41 @@ func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sd
|
|||
// period has already been incremented - we want to store the period ended by this delegation action
|
||||
previousPeriod := k.GetValidatorCurrentRewards(ctx, val).Period - 1
|
||||
|
||||
// increment reference count for the period we're going to track
|
||||
k.incrementReferenceCount(ctx, val, previousPeriod)
|
||||
|
||||
validator := k.stakingKeeper.Validator(ctx, val)
|
||||
delegation := k.stakingKeeper.Delegation(ctx, del, val)
|
||||
|
||||
// calculate delegation stake in tokens
|
||||
// we don't store directly, so multiply delegation shares * (tokens per share)
|
||||
stake := delegation.GetShares().Mul(validator.GetDelegatorShareExRate())
|
||||
// note: necessary to truncate so we don't allow withdrawing more rewards than owed
|
||||
stake := delegation.GetShares().MulTruncate(validator.GetDelegatorShareExRate())
|
||||
k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight())))
|
||||
}
|
||||
|
||||
// calculate the rewards accrued by a delegation between two periods
|
||||
func (k Keeper) calculateDelegationRewardsBetween(ctx sdk.Context, val sdk.Validator,
|
||||
startingPeriod, endingPeriod uint64, staking sdk.Dec) (rewards sdk.DecCoins) {
|
||||
startingPeriod, endingPeriod uint64, stake sdk.Dec) (rewards sdk.DecCoins) {
|
||||
// sanity check
|
||||
if startingPeriod > endingPeriod {
|
||||
panic("startingPeriod cannot be greater than endingPeriod")
|
||||
}
|
||||
|
||||
// sanity check
|
||||
if stake.LT(sdk.ZeroDec()) {
|
||||
panic("stake should not be negative")
|
||||
}
|
||||
|
||||
// return staking * (ending - starting)
|
||||
starting := k.GetValidatorHistoricalRewards(ctx, val.GetOperator(), startingPeriod)
|
||||
ending := k.GetValidatorHistoricalRewards(ctx, val.GetOperator(), endingPeriod)
|
||||
difference := ending.CumulativeRewardRatio.Minus(starting.CumulativeRewardRatio)
|
||||
rewards = difference.MulDec(staking)
|
||||
if difference.HasNegative() {
|
||||
panic("negative rewards should not be possible")
|
||||
}
|
||||
// note: necessary to truncate so we don't allow withdrawing more rewards than owed
|
||||
rewards = difference.MulDecTruncate(stake)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -54,7 +67,8 @@ func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val sdk.Validator, d
|
|||
func(height uint64, event types.ValidatorSlashEvent) (stop bool) {
|
||||
endingPeriod := event.ValidatorPeriod
|
||||
rewards = rewards.Plus(k.calculateDelegationRewardsBetween(ctx, val, startingPeriod, endingPeriod, stake))
|
||||
stake = stake.Mul(sdk.OneDec().Sub(event.Fraction))
|
||||
// note: necessary to truncate so we don't allow withdrawing more rewards than owed
|
||||
stake = stake.MulTruncate(sdk.OneDec().Sub(event.Fraction))
|
||||
startingPeriod = endingPeriod
|
||||
return false
|
||||
},
|
||||
|
|
|
@ -30,13 +30,13 @@ func TestCalculateRewardsBasic(t *testing.T) {
|
|||
del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
||||
|
||||
// historical count should be 2 (once for validator init, once for delegation init)
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalRewardCount(ctx))
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
||||
|
||||
// end period
|
||||
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
||||
|
||||
// historical count should be 3 (since we ended the period, and haven't yet decremented a reference)
|
||||
require.Equal(t, uint64(3), k.GetValidatorHistoricalRewardCount(ctx))
|
||||
// historical count should be 2 still
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
||||
|
||||
// calculate delegation rewards
|
||||
rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
||||
|
@ -283,13 +283,13 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) {
|
|||
k.AllocateTokensToValidator(ctx, val, tokens)
|
||||
|
||||
// historical count should be 2 (initial + latest for delegation)
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalRewardCount(ctx))
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
||||
|
||||
// withdraw rewards
|
||||
require.Nil(t, k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1))
|
||||
|
||||
// historical count should still be 2 (added one record, cleared one)
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalRewardCount(ctx))
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
||||
|
||||
// assert correct balance
|
||||
require.Equal(t, sdk.Coins{{staking.DefaultBondDenom, sdk.NewInt(balance - bond + (initial / 2))}}, ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins())
|
||||
|
@ -460,14 +460,14 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) {
|
|||
k.AllocateTokensToValidator(ctx, val, tokens)
|
||||
|
||||
// historical count should be 2 (validator init, delegation init)
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalRewardCount(ctx))
|
||||
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
||||
|
||||
// second delegation
|
||||
msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(staking.DefaultBondDenom, sdk.NewInt(100)))
|
||||
require.True(t, sh(ctx, msg2).IsOK())
|
||||
|
||||
// historical count should be 3 (second delegation init)
|
||||
require.Equal(t, uint64(3), k.GetValidatorHistoricalRewardCount(ctx))
|
||||
require.Equal(t, uint64(3), k.GetValidatorHistoricalReferenceCount(ctx))
|
||||
|
||||
// fetch updated validator
|
||||
val = sk.Validator(ctx, valOpAddr1)
|
||||
|
@ -486,7 +486,7 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) {
|
|||
k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1)
|
||||
|
||||
// historical count should be 3 (validator init + two delegations)
|
||||
require.Equal(t, uint64(3), k.GetValidatorHistoricalRewardCount(ctx))
|
||||
require.Equal(t, uint64(3), k.GetValidatorHistoricalReferenceCount(ctx))
|
||||
|
||||
// validator withdraws commission
|
||||
k.WithdrawValidatorCommission(ctx, valOpAddr1)
|
||||
|
|
|
@ -175,13 +175,15 @@ func (k Keeper) DeleteAllValidatorHistoricalRewards(ctx sdk.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// historical record count (used for testcases)
|
||||
func (k Keeper) GetValidatorHistoricalRewardCount(ctx sdk.Context) (count uint64) {
|
||||
// historical reference count (used for testcases)
|
||||
func (k Keeper) GetValidatorHistoricalReferenceCount(ctx sdk.Context) (count uint64) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iter := sdk.KVStorePrefixIterator(store, ValidatorHistoricalRewardsPrefix)
|
||||
defer iter.Close()
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
count++
|
||||
var rewards types.ValidatorHistoricalRewards
|
||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &rewards)
|
||||
count += uint64(rewards.ReferenceCount)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -38,12 +38,16 @@ func (k Keeper) incrementValidatorPeriod(ctx sdk.Context, val sdk.Validator) uin
|
|||
|
||||
current = sdk.DecCoins{}
|
||||
} else {
|
||||
current = rewards.Rewards.QuoDec(sdk.NewDecFromInt(val.GetTokens()))
|
||||
// note: necessary to truncate so we don't allow withdrawing more rewards than owed
|
||||
current = rewards.Rewards.QuoDecTruncate(sdk.NewDecFromInt(val.GetTokens()))
|
||||
}
|
||||
|
||||
// fetch historical rewards for last period
|
||||
historical := k.GetValidatorHistoricalRewards(ctx, val.GetOperator(), rewards.Period-1).CumulativeRewardRatio
|
||||
|
||||
// decrement reference count
|
||||
k.decrementReferenceCount(ctx, val.GetOperator(), rewards.Period-1)
|
||||
|
||||
// set new historical rewards with reference count of 1
|
||||
k.SetValidatorHistoricalRewards(ctx, val.GetOperator(), rewards.Period, types.NewValidatorHistoricalRewards(historical.Plus(current), 1))
|
||||
|
||||
|
@ -56,8 +60,8 @@ func (k Keeper) incrementValidatorPeriod(ctx sdk.Context, val sdk.Validator) uin
|
|||
// increment the reference count for a historical rewards value
|
||||
func (k Keeper) incrementReferenceCount(ctx sdk.Context, valAddr sdk.ValAddress, period uint64) {
|
||||
historical := k.GetValidatorHistoricalRewards(ctx, valAddr, period)
|
||||
if historical.ReferenceCount > 1 {
|
||||
panic("reference count should never exceed 1")
|
||||
if historical.ReferenceCount > 2 {
|
||||
panic("reference count should never exceed 2")
|
||||
}
|
||||
historical.ReferenceCount++
|
||||
k.SetValidatorHistoricalRewards(ctx, valAddr, period, historical)
|
||||
|
@ -78,6 +82,9 @@ func (k Keeper) decrementReferenceCount(ctx sdk.Context, valAddr sdk.ValAddress,
|
|||
}
|
||||
|
||||
func (k Keeper) updateValidatorSlashFraction(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) {
|
||||
if fraction.GT(sdk.OneDec()) {
|
||||
panic("fraction greater than one")
|
||||
}
|
||||
height := uint64(ctx.BlockHeight())
|
||||
currentFraction := sdk.ZeroDec()
|
||||
endedPeriod := k.GetValidatorCurrentRewards(ctx, valAddr).Period - 1
|
||||
|
@ -91,9 +98,14 @@ func (k Keeper) updateValidatorSlashFraction(ctx sdk.Context, valAddr sdk.ValAdd
|
|||
val := k.stakingKeeper.Validator(ctx, valAddr)
|
||||
// increment current period
|
||||
endedPeriod = k.incrementValidatorPeriod(ctx, val)
|
||||
// increment reference count on period we need to track
|
||||
k.incrementReferenceCount(ctx, valAddr, endedPeriod)
|
||||
}
|
||||
currentMultiplicand := sdk.OneDec().Sub(currentFraction)
|
||||
newMultiplicand := sdk.OneDec().Sub(fraction)
|
||||
updatedFraction := sdk.OneDec().Sub(currentMultiplicand.Mul(newMultiplicand))
|
||||
if updatedFraction.LT(sdk.ZeroDec()) {
|
||||
panic("negative slash fraction")
|
||||
}
|
||||
k.SetValidatorSlashEvent(ctx, valAddr, height, types.NewValidatorSlashEvent(endedPeriod, updatedFraction))
|
||||
}
|
||||
|
|
|
@ -85,12 +85,12 @@ func ReferenceCountInvariant(k distr.Keeper, sk staking.Keeper) simulation.Invar
|
|||
return false
|
||||
})
|
||||
|
||||
// one record per validator (zeroeth period), one record per delegation (previous period), one record per slash (previous period)
|
||||
// one record per validator (last tracked period), one record per delegation (previous period), one record per slash (previous period)
|
||||
expected := valCount + uint64(len(dels)) + slashCount
|
||||
count := k.GetValidatorHistoricalReferenceCount(ctx)
|
||||
|
||||
count := k.GetValidatorHistoricalRewardCount(ctx)
|
||||
if count != expected {
|
||||
return fmt.Errorf("unexpected number of historical rewards records: expected %v, got %v", expected, count)
|
||||
return fmt.Errorf("unexpected number of historical rewards records: expected %v (%v vals + %v dels + %v slashes), got %v", expected, valCount, len(dels), slashCount, count)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -34,7 +34,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
|
|||
// Manually set indices for the first time
|
||||
keeper.SetValidatorByConsAddr(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator)
|
||||
keeper.AfterValidatorCreated(ctx, validator.OperatorAddr)
|
||||
if !data.Exported {
|
||||
keeper.AfterValidatorCreated(ctx, validator.OperatorAddr)
|
||||
}
|
||||
|
||||
// Set timeslice if necessary
|
||||
if validator.Status == sdk.Unbonding {
|
||||
|
@ -43,9 +45,13 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
|
|||
}
|
||||
|
||||
for _, delegation := range data.Bonds {
|
||||
keeper.BeforeDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
if !data.Exported {
|
||||
keeper.BeforeDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
keeper.AfterDelegationModified(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
if !data.Exported {
|
||||
keeper.AfterDelegationModified(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ubd := range data.UnbondingDelegations {
|
||||
|
|
|
@ -77,7 +77,6 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) {
|
|||
store := ctx.KVStore(k.storeKey)
|
||||
b := types.MustMarshalDelegation(k.cdc, delegation)
|
||||
store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b)
|
||||
k.AfterDelegationModified(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
}
|
||||
|
||||
// remove a delegation from store
|
||||
|
@ -468,6 +467,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co
|
|||
// Update delegation
|
||||
delegation.Shares = delegation.Shares.Add(newShares)
|
||||
k.SetDelegation(ctx, delegation)
|
||||
k.AfterDelegationModified(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
|
||||
return newShares, nil
|
||||
}
|
||||
|
@ -512,6 +512,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
|||
} else {
|
||||
// update the delegation
|
||||
k.SetDelegation(ctx, delegation)
|
||||
k.AfterDelegationModified(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
}
|
||||
|
||||
// remove the coins from the validator
|
||||
|
@ -569,10 +570,13 @@ func (k Keeper) Undelegate(ctx sdk.Context, delAddr sdk.AccAddress,
|
|||
|
||||
// no need to create the ubd object just complete now
|
||||
if completeNow {
|
||||
_, err := k.bankKeeper.UndelegateCoins(ctx, delAddr, sdk.Coins{balance})
|
||||
if err != nil {
|
||||
return completionTime, err
|
||||
// track undelegation only when remaining or truncated shares are non-zero
|
||||
if !balance.IsZero() {
|
||||
if _, err := k.bankKeeper.UndelegateCoins(ctx, delAddr, sdk.Coins{balance}); err != nil {
|
||||
return completionTime, err
|
||||
}
|
||||
}
|
||||
|
||||
return completionTime, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,12 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
|
|||
|
||||
// we need to calculate the *effective* slash fraction for distribution
|
||||
if validator.Tokens.GT(sdk.ZeroInt()) {
|
||||
k.BeforeValidatorSlashed(ctx, operatorAddress, slashAmountDec.Quo(sdk.NewDecFromInt(validator.Tokens)))
|
||||
effectiveFraction := slashAmountDec.Quo(sdk.NewDecFromInt(validator.Tokens))
|
||||
// possible if power has changed
|
||||
if effectiveFraction.GT(sdk.OneDec()) {
|
||||
effectiveFraction = sdk.OneDec()
|
||||
}
|
||||
k.BeforeValidatorSlashed(ctx, operatorAddress, effectiveFraction)
|
||||
}
|
||||
|
||||
// Track remaining slash amount for the validator
|
||||
|
|
Loading…
Reference in New Issue