mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-04 04:04:00 +00:00
200 lines
8.1 KiB
Markdown
200 lines
8.1 KiB
Markdown
# 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.
|