update valset-changes.md
This commit is contained in:
parent
077ffeb706
commit
0cf51da799
|
@ -1,89 +1,17 @@
|
||||||
# Slashing
|
# Validator Set Changes
|
||||||
|
|
||||||
A validator bond is an economic commitment made by a validator signing key to both the safety and liveness of
|
The validator set may be updated by state transitions that run at the beginning and
|
||||||
the consensus. Validator keys must not sign invalid messages which could
|
end of every block. This can happen one of three ways:
|
||||||
violate consensus safety, and their signed precommit messages must be regularly included in
|
|
||||||
block commits.
|
|
||||||
|
|
||||||
The incentivization of these two goals are treated separately.
|
- voting power of a validator changes due to bonding and unbonding
|
||||||
|
- voting power of validator is "slashed" due to conflicting signed messages
|
||||||
|
- validator is automatically unbonded due to inactivity
|
||||||
|
|
||||||
## Safety
|
## Voting Power Changes
|
||||||
|
|
||||||
Messges which may compromise the safety of the underlying consensus protocol ("equivocations")
|
At the end of every block, we run the following:
|
||||||
result in some amount of the offending validator's shares being removed ("slashed").
|
|
||||||
|
|
||||||
Currently, such messages include only the following:
|
(TODO remove inflation from here)
|
||||||
|
|
||||||
- prevotes by the same validator for more than one BlockID at the same
|
|
||||||
Height and Round
|
|
||||||
- precommits by the same validator for more than one BlockID at the same
|
|
||||||
Height and Round
|
|
||||||
|
|
||||||
We call any such pair of conflicting votes `Evidence`. Full nodes in the network prioritize the
|
|
||||||
detection and gossipping of `Evidence` so that it may be rapidly included in blocks and the offending
|
|
||||||
validators punished.
|
|
||||||
|
|
||||||
For some `evidence` to be valid, it must satisfy:
|
|
||||||
|
|
||||||
`evidence.Height >= block.Height - MAX_EVIDENCE_AGE`
|
|
||||||
|
|
||||||
If valid evidence is included in a block, the offending validator loses
|
|
||||||
a constant `SLASH_PROPORTION` of their current stake:
|
|
||||||
|
|
||||||
```
|
|
||||||
oldShares = validator.shares
|
|
||||||
validator.shares = oldShares * (1 - SLASH_PROPORTION)
|
|
||||||
```
|
|
||||||
|
|
||||||
This ensures that offending validators are punished the same amount whether they
|
|
||||||
act as a single validator with X stake or as N validators with collectively X
|
|
||||||
stake.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Liveness
|
|
||||||
|
|
||||||
Every block includes a set of precommits by the validators for the previous block,
|
|
||||||
known as the LastCommit. A LastCommit is valid so long as it contains precommits from +2/3 of voting power.
|
|
||||||
|
|
||||||
Proposers are incentivized to include precommits from all
|
|
||||||
validators in the LastCommit by receiving additional fees
|
|
||||||
proportional to the difference between the voting power included in the
|
|
||||||
LastCommit and +2/3 (see [TODO](https://github.com/cosmos/cosmos-sdk/issues/967)).
|
|
||||||
|
|
||||||
Validators are penalized for failing to be included in the LastCommit for some
|
|
||||||
number of blocks by being automatically unbonded.
|
|
||||||
|
|
||||||
|
|
||||||
TODO: do we do this by trying to track absence directly in the state, using
|
|
||||||
something like the below, or do we let users notify the app when a validator has
|
|
||||||
been absent using the
|
|
||||||
[TxLivenessCheck](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/spec/staking/spec-technical.md#txlivelinesscheck).
|
|
||||||
|
|
||||||
|
|
||||||
A list, `ValidatorAbsenceInfos`, is stored in the state and used to track how often
|
|
||||||
validators were included in a LastCommit.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Ordered by ValidatorAddress.
|
|
||||||
// One entry for each validator.
|
|
||||||
type ValidatorAbsenceInfos []ValidatorAbsenceInfo
|
|
||||||
|
|
||||||
type ValidatorAbsenceInfo struct {
|
|
||||||
ValidatorAddress []byte // address of the validator
|
|
||||||
FirstHeight int64 // first height the validator was absent
|
|
||||||
Count int64 // number of heights validator was absent since (and including) first
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### BeginBlock Handling
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### EndBlock Handling
|
|
||||||
|
|
||||||
This is where we inflate the Atoms and deal with validator set changes.
|
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
tick(ctx Context):
|
tick(ctx Context):
|
||||||
|
@ -172,3 +100,91 @@ unbondedToBondedPool(candidate Candidate):
|
||||||
|
|
||||||
return transfer(address of the unbonded pool, address of the bonded pool, removedTokens)
|
return transfer(address of the unbonded pool, address of the bonded pool, removedTokens)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Slashing
|
||||||
|
|
||||||
|
Messges which may compromise the safety of the underlying consensus protocol ("equivocations")
|
||||||
|
result in some amount of the offending validator's shares being removed ("slashed").
|
||||||
|
|
||||||
|
Currently, such messages include only the following:
|
||||||
|
|
||||||
|
- prevotes by the same validator for more than one BlockID at the same
|
||||||
|
Height and Round
|
||||||
|
- precommits by the same validator for more than one BlockID at the same
|
||||||
|
Height and Round
|
||||||
|
|
||||||
|
We call any such pair of conflicting votes `Evidence`. Full nodes in the network prioritize the
|
||||||
|
detection and gossipping of `Evidence` so that it may be rapidly included in blocks and the offending
|
||||||
|
validators punished.
|
||||||
|
|
||||||
|
For some `evidence` to be valid, it must satisfy:
|
||||||
|
|
||||||
|
`evidence.Timestamp >= block.Timestamp - MAX_EVIDENCE_AGE`
|
||||||
|
|
||||||
|
where `evidence.Timestamp` is the timestamp in the block at height
|
||||||
|
`evidence.Height` and `block.Timestamp` is the current block timestamp.
|
||||||
|
|
||||||
|
If valid evidence is included in a block, the offending validator loses
|
||||||
|
a constant `SLASH_PROPORTION` of their current stake at the beginning of the block:
|
||||||
|
|
||||||
|
```
|
||||||
|
oldShares = validator.shares
|
||||||
|
validator.shares = oldShares * (1 - SLASH_PROPORTION)
|
||||||
|
```
|
||||||
|
|
||||||
|
This ensures that offending validators are punished the same amount whether they
|
||||||
|
act as a single validator with X stake or as N validators with collectively X
|
||||||
|
stake.
|
||||||
|
|
||||||
|
|
||||||
|
## Automatic Unbonding
|
||||||
|
|
||||||
|
Every block includes a set of precommits by the validators for the previous block,
|
||||||
|
known as the LastCommit. A LastCommit is valid so long as it contains precommits from +2/3 of voting power.
|
||||||
|
|
||||||
|
Proposers are incentivized to include precommits from all
|
||||||
|
validators in the LastCommit by receiving additional fees
|
||||||
|
proportional to the difference between the voting power included in the
|
||||||
|
LastCommit and +2/3 (see [TODO](https://github.com/cosmos/cosmos-sdk/issues/967)).
|
||||||
|
|
||||||
|
Validators are penalized for failing to be included in the LastCommit for some
|
||||||
|
number of blocks by being automatically unbonded.
|
||||||
|
|
||||||
|
The following information is stored with each validator candidate, and is only non-zero if the candidate becomes an active validator:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ValidatorSigningInfo struct {
|
||||||
|
StartHeight int64
|
||||||
|
SignedBlocksBitArray BitArray
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Where:
|
||||||
|
* `StartHeight` is set to the height that the candidate became an active validator (with non-zero voting power).
|
||||||
|
* `SignedBlocksBitArray` is a bit-array of size `SIGNED_BLOCKS_WINDOW` that records, for each of the last `SIGNED_BLOCKS_WINDOW` blocks,
|
||||||
|
whether or not this validator was included in the LastCommit. It uses a `0` if the validator was included, and a `1` if it was not.
|
||||||
|
Note it is initialized with all 0s.
|
||||||
|
|
||||||
|
At the beginning of each block, we update the signing info for each validator and check if they should be automatically unbonded:
|
||||||
|
|
||||||
|
```
|
||||||
|
h = block.Height
|
||||||
|
index = h % SIGNED_BLOCKS_WINDOW
|
||||||
|
|
||||||
|
for val in block.Validators:
|
||||||
|
signInfo = val.SignInfo
|
||||||
|
if val in block.LastCommit:
|
||||||
|
signInfo.SignedBlocksBitArray.Set(index, 0)
|
||||||
|
else
|
||||||
|
signInfo.SignedBlocksBitArray.Set(index, 1)
|
||||||
|
|
||||||
|
// validator must be active for at least SIGNED_BLOCKS_WINDOW
|
||||||
|
// before they can be automatically unbonded for failing to be
|
||||||
|
// included in 50% of the recent LastCommits
|
||||||
|
minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW
|
||||||
|
minSigned = SIGNED_BLOCKS_WINDOW / 2
|
||||||
|
blocksSigned = signInfo.SignedBlocksBitArray.Sum()
|
||||||
|
if h > minHeight AND blocksSigned < minSigned:
|
||||||
|
unbond the validator
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue