-
Notifications
You must be signed in to change notification settings - Fork 28
Slashing Notes
There are two ways that eveidence been handled.
- Submit through a
MsgSubmitEvidence
. (It seems ourchain-main
does 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.ValidatorUpdateDelay
default 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
slash
event, 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:
-
power
is from the infraction height -
infractionHeight
is in fact, 1 block ahead of the infration height
-
Calculate slash amount based on power at infration height, let's call it
TotalSlash
. -
Get
Validator
from store. -
If input
infrationHeight < currentBlockHeight
, loop throughUnbondingDelegation
andRedelegation
on that validator.
-
k.GetUnbondingDelegationsFromValidator()
: get the unbinding delegations on the validator -
k.SlashUnbondingDelegation()
-
For each
UnbindingDelegation
entry:- Calculate the amount to slash on the
UnbindingDelegation
entry (entry.InitalBalance * slashFactor
) - Reduce the
Balance
ofUnbindingDelegation
entry, 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
Redelegation
entry:- Calculate the amount to slash on that entry (
entry.InitalBalance * slashFactor
) -
k.Unbond()
: Unbond the tokens and shares on Destination Validator, destinationValidator.Tokens
is changed. - Burn the slashed tokens on module accounts (
NotBondedPool
,BondedPool
). The total supply is decreased. -
Redelegation
entry is not changed in the above process.
- Calculate the amount to slash on that entry (
-
Calculate total amount slashed on the
UnbondingDelegation
andRedelegation
entries, let's call itSlashOnX
. -
Removed tokens from
Validator.Tokens
.
- The real amount removed from
Validator.Tokens
isSlashOnValidator
=TotalSlash
-SlashOnX
.
-
SlashOnValidator
tokens are burned from module accounts (NotBondedPool
,BondedPool
). The total supply is decreased. -
SlashOnValidator
is returned and later, wrapped inslash
event.
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
Redelegation
entries, which is to find the destination validator and to calculate the shares to slash. - We need to keep track of all
Delegation
entries. - We need to keep track of all
Validator
entries, 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.