|
|
@ -0,0 +1,199 @@ |
|
|
|
# Evidence |
|
|
|
|
|
|
|
Evidence is an important component of Tendermint's security model. Whilst the core |
|
|
|
consensus protocol provides correctness gaurantees for state machine replication |
|
|
|
that can tolerate less than 1/3 failures, the evidence system looks to detect and |
|
|
|
gossip byzantine faults whose combined power is greater than or equal to 1/3. It is worth noting that |
|
|
|
the evidence system is designed purely to detect possible attacks, gossip them, |
|
|
|
commit them on chain and inform the application running on top of Tendermint. |
|
|
|
Evidence in itself does not punish "bad actors", this is left to the discretion |
|
|
|
of the application. A common form of punishment is slashing where the validators |
|
|
|
that were caught violating the protocol have all or a portion of their voting |
|
|
|
power removed. Evidence, given the assumption that 1/3+ of the network is still |
|
|
|
byzantine, is susceptible to censorship and should therefore be considered added |
|
|
|
security on a "best effort" basis. |
|
|
|
|
|
|
|
This document walks through the various forms of evidence, how they are detected, |
|
|
|
gossiped, verified and committed. |
|
|
|
|
|
|
|
> NOTE: Evidence here is internal to tendermint and should not be confused with |
|
|
|
> application evidence |
|
|
|
|
|
|
|
## Detection |
|
|
|
|
|
|
|
### Equivocation |
|
|
|
|
|
|
|
Equivocation is the most fundamental of byzantine faults. Simply put, to prevent |
|
|
|
replication of state across all nodes, a validator tries to convince some subset |
|
|
|
of nodes to commit one block whilst convincing another subset to commit a |
|
|
|
different block. This is achieved by double voting (hence |
|
|
|
`DuplicateVoteEvidence`). A successful duplicate vote attack requires greater |
|
|
|
than 1/3 voting power and a (temporary) network partition between the aforementioned |
|
|
|
subsets. This is because in consensus, votes are gossiped around. When a node |
|
|
|
observes two conflicting votes from the same peer, it will use the two votes of |
|
|
|
evidence and begin gossiping this evidence to other nodes. [Verification](#duplicatevoteevidence) is addressed further down. |
|
|
|
|
|
|
|
```go |
|
|
|
type DuplicateVoteEvidence struct { |
|
|
|
VoteA Vote |
|
|
|
VoteB Vote |
|
|
|
|
|
|
|
// and abci specific fields |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
### Light Client Attacks |
|
|
|
|
|
|
|
Light clients also comply with the 1/3+ security model, however, by using a |
|
|
|
different, more lightweight verification method they are subject to a |
|
|
|
different kind of 1/3+ attack whereby the byzantine validators could sign an |
|
|
|
alternative light block that the light client will think is valid. Detection, |
|
|
|
explained in greater detail |
|
|
|
[here](../light-client/detection/detection_003_reviewed.md), involves comparison |
|
|
|
with multiple other nodes in the hope that at least one is "honest". An "honest" |
|
|
|
node will return a challenging light block for the light client to validate. If |
|
|
|
this challenging light block also meets the |
|
|
|
[validation criteria](../light-client/verification/verification_001_published.md) |
|
|
|
then the light client sends the "forged" light block to the node. |
|
|
|
[Verification](#lightclientattackevidence) is addressed further down. |
|
|
|
|
|
|
|
```go |
|
|
|
type LightClientAttackEvidence struct { |
|
|
|
ConflictingBlock LightBlock |
|
|
|
CommonHeight int64 |
|
|
|
|
|
|
|
// and abci specific fields |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
## Verification |
|
|
|
|
|
|
|
If a node receives evidence, it will first try to verify it, then persist it. |
|
|
|
Evidence of byzantine behavior should only be committed once (uniqueness) and |
|
|
|
should be committed within a certain period from the point that it occurred |
|
|
|
(timely). Timelines is defined by the `EvidenceParams`: `MaxAgeNumBlocks` and |
|
|
|
`MaxAgeDuration`. In Proof of Stake chains where validators are bonded, evidence |
|
|
|
age should be less than the unbonding period so validators still can be |
|
|
|
punished. Given these two propoerties the following initial checks are made. |
|
|
|
|
|
|
|
1. Has the evidence expired? This is done by taking the height of the `Vote` |
|
|
|
within `DuplicateVoteEvidence` or `CommonHeight` within |
|
|
|
`LightClientAttakEvidence`. The evidence height is then used to retrieve the |
|
|
|
header and thus the time of the block that corresponds to the evidence. If |
|
|
|
`CurrentHeight - MaxAgeNumBlocks > EvidenceHeight` && `CurrentTime - |
|
|
|
MaxAgeDuration > EvidenceTime`, the evidence is considered expired and |
|
|
|
ignored. |
|
|
|
|
|
|
|
2. Has the evidence already been committed? The evidence pool tracks the hash of |
|
|
|
all committed evidence and uses this to determine uniqueness. If a new |
|
|
|
evidence has the same hash as a committed one, the new evidence will be |
|
|
|
ignored. |
|
|
|
|
|
|
|
### DuplicateVoteEvidence |
|
|
|
|
|
|
|
Valid `DuplicateVoteEvidence` must adhere to the following rules: |
|
|
|
|
|
|
|
- Validator Address, Height, Round and Type must be the same for both votes |
|
|
|
|
|
|
|
- BlockID must be different for both votes (BlockID can be for a nil block) |
|
|
|
|
|
|
|
- Validator must have been in the validator set at that height |
|
|
|
|
|
|
|
- Vote signature must be correctly signed. This also uses `ChainID` so we know |
|
|
|
that the fault occurred on this chain |
|
|
|
|
|
|
|
### LightClientAttackEvidence |
|
|
|
|
|
|
|
Valid Light Client Attack Evidence must adhere to the following rules: |
|
|
|
|
|
|
|
- If the header of the light block is invalid, thus indicating a lunatic attack, |
|
|
|
the node must check that they can use `verifySkipping` from their header at |
|
|
|
the common height to the conflicting header |
|
|
|
|
|
|
|
- If the header is valid, then the validator sets are the same and this is |
|
|
|
either a form of equivocation or amnesia. We therefore check that 2/3 of the |
|
|
|
validator set also signed the conflicting header. |
|
|
|
|
|
|
|
- The nodes own header at the same height as the conflicting header must have a |
|
|
|
different hash to the conflicting header. |
|
|
|
|
|
|
|
- If the nodes latest header is less in height to the conflicting header, then |
|
|
|
the node must check that the conflicting block has a time that is less than |
|
|
|
this latest header (This is a forward lunatic attack). |
|
|
|
|
|
|
|
## Gossiping |
|
|
|
|
|
|
|
If a node verifies evidence it then broadcasts it to all peers, continously sending |
|
|
|
the same evidence once every 10 seconds until the evidence is seen on chain or |
|
|
|
expires. |
|
|
|
|
|
|
|
## Commiting on Chain |
|
|
|
|
|
|
|
Evidence takes strict priority over regular transactions, thus a block is filled |
|
|
|
with evidence first and transactions take up the remainder of the space. To |
|
|
|
mitigate the threat of an already punished node from spamming the network with |
|
|
|
more evidence, the size of the evidence in a block can be capped by |
|
|
|
`EvidenceParams.MaxBytes`. Nodes receiving blocks with evidence will validate |
|
|
|
the evidence before sending `Prevote` and `Precommit` votes. The evidence pool |
|
|
|
will usually cache verifications so that this process is much quicker. |
|
|
|
|
|
|
|
## Sending Evidence to the Application |
|
|
|
|
|
|
|
After evidence is committed, the block is then processed by the block executor |
|
|
|
which delivers the evidence to the application via `EndBlock`. Evidence is |
|
|
|
stripped of the actual proof, split up per faulty validator and only the |
|
|
|
validator, height, time and evidence type is sent. |
|
|
|
|
|
|
|
```proto |
|
|
|
enum EvidenceType { |
|
|
|
UNKNOWN = 0; |
|
|
|
DUPLICATE_VOTE = 1; |
|
|
|
LIGHT_CLIENT_ATTACK = 2; |
|
|
|
} |
|
|
|
|
|
|
|
message Evidence { |
|
|
|
EvidenceType type = 1; |
|
|
|
// The offending validator |
|
|
|
Validator validator = 2 [(gogoproto.nullable) = false]; |
|
|
|
// The height when the offense occurred |
|
|
|
int64 height = 3; |
|
|
|
// The corresponding time where the offense occurred |
|
|
|
google.protobuf.Timestamp time = 4 [ |
|
|
|
(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; |
|
|
|
// Total voting power of the validator set in case the ABCI application does |
|
|
|
// not store historical validators. |
|
|
|
// https://github.com/tendermint/tendermint/issues/4581 |
|
|
|
int64 total_voting_power = 5; |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
`DuplicateVoteEvidence` and `LightClientAttackEvidence` are self-contained in |
|
|
|
the sense that the evidence can be used to derive the `abci.Evidence` that is |
|
|
|
sent to the application. Because of this, extra fields are necessary: |
|
|
|
|
|
|
|
```go |
|
|
|
type DuplicateVoteEvidence struct { |
|
|
|
VoteA *Vote |
|
|
|
VoteB *Vote |
|
|
|
|
|
|
|
// abci specific information |
|
|
|
TotalVotingPower int64 |
|
|
|
ValidatorPower int64 |
|
|
|
Timestamp time.Time |
|
|
|
} |
|
|
|
|
|
|
|
type LightClientAttackEvidence struct { |
|
|
|
ConflictingBlock *LightBlock |
|
|
|
CommonHeight int64 |
|
|
|
|
|
|
|
// abci specific information |
|
|
|
ByzantineValidators []*Validator |
|
|
|
TotalVotingPower int64 |
|
|
|
Timestamp time.Time |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
These ABCI specific fields don't affect validity of the evidence itself but must |
|
|
|
be consistent amongst nodes and agreed upon on chain. If evidence with the |
|
|
|
incorrect abci information is sent, a node will create new evidence from it and |
|
|
|
replace the ABCI fields with the correct information. |