-
Couldn't load subscription status.
- Fork 31
Slashing Notes
There are two ways that eveidence been handled.
- Submit through a
MsgSubmitEvidence. (It seems ourchain-maindoes not register the route for handling this Msg) - Tendermint submit evidence to
BeginBlocker().
In both way, the evidence should be handled by x/evidence/keeper/infraction.go HandleEquivocationEvidence().
Slashing is triggered due to missing validator signatures in multiple blocks (maybe due to validator is down).
This section targets to give a general picture of the execution stack when evidence is submitted.
x/evidence/abci.go BeginBlocker()
-
k.HandleEquivocationEvidence()->x/evidence/keeper/infraction.go HandleEquivocationEvidence()-
Check evidence validness, check validator existence.
-
distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay
-
sdk.ValidatorUpdateDelaydefault is1. - https://github.com/cosmos/cosmos-sdk/blob/314e1d52c248e61847e0d78be165fc9d843ef812/types/staking.go#L18
-
We need to retrieve the stake distribution which signed the block, so we subtract ValidatorUpdateDelay from the evidence height.
-
k.slashingKeeper.Slash()->x/slashing/keeper/keeper.go Slash()
- https://github.com/cosmos/cosmos-sdk/blob/314e1d52c248e61847e0d78be165fc9d843ef812/x/slashing/keeper/keeper.go#L68
-
k.sk.Slash()->x/staking/keeper/slash.go Slash(): - Emit a
slashevent, which wraps the amount of tokens slashed on this validator.
-
Jail the validator if it is not in jail.
-
Validator is tombstoned (unrecoverable)
-
The most important logic is in this function. Validator token balance changes also happens here.
x/staking/keeper/slash.go Slash()
Be aware of the inputs:
-
poweris from the infraction height -
infractionHeightis in fact, 1 block ahead of the infration height
-
Calculate slash amount based on power at infration height, let's call it
TotalSlash. -
Get
Validatorfrom store. -
If input
infrationHeight < currentBlockHeight, loop throughUnbondingDelegationandRedelegationon that validator.
-
k.GetUnbondingDelegationsFromValidator(): get the unbinding delegations on the validator -
k.SlashUnbondingDelegation()-
For each
UnbindingDelegationentry:- Calculate the amount to slash on the
UnbindingDelegationentry (entry.InitalBalance * slashFactor) - Reduce the
BalanceofUnbindingDelegationentry, and update it to store. - Burn the slashed tokens on module accounts (
NotBondedPool,BondedPool). The total supply is decreased.
- Calculate the amount to slash on the
-
k.GetRedelegationsFromSrcValidator(): get the redelegations on the validator -
k.SlashRedelegation()-
For each
Redelegationentry:- Calculate the amount to slash on that entry (
entry.InitalBalance * slashFactor) -
k.Unbond(): Unbond the tokens and shares on Destination Validator, destinationValidator.Tokensis changed. - Burn the slashed tokens on module accounts (
NotBondedPool,BondedPool). The total supply is decreased. -
Redelegationentry is not changed in the above process.
- Calculate the amount to slash on that entry (
-
Calculate total amount slashed on the
UnbondingDelegationandRedelegationentries, let's call itSlashOnX. -
Removed tokens from
Validator.Tokens.
- The real amount removed from
Validator.TokensisSlashOnValidator=TotalSlash-SlashOnX.
-
SlashOnValidatortokens are burned from module accounts (NotBondedPool,BondedPool). The total supply is decreased. -
SlashOnValidatoris returned and later, wrapped inslashevent.
When a slash event is detected, it includes the amount of tokens slashed on the validator that committed the misbehavior, which is good.
Slashed on UnbindingDelegation (Undelegation) is also fine, as it will not affect any validator's balance.
But the problem is on Redelegation.
Say if a user do a redelegation from Validator A to Validator B.
Before the redelegation, the Validator A committed a misbehavior (let's say double sign two blocks).
Then when the evidence on this misbehavior is committed, Validator B will also be slashed. And there is no message or event indicating the amount of tokens slashed on Validator B.
To calculate the slash amount on redelegation destination validator, on our indexing server, we need track many things:
- We need to keep track of all
Redelegationentries, which is to find the destination validator and to calculate the shares to slash. - We need to keep track of all
Delegationentries. - We need to keep track of all
Validatorentries, so that we could convert the shares to real amount of tokens to slash.
The last part is not a good news for us.
- If we assume the blocks come in a ordered manner, then it is fine.
- But if we want to scale the projections, multiple goroutine running in parallel, it will be impossible. As at the moment of calculating the slash amount on destination validator, you need to know the tokens balance of validator before the slashing.