Browse Source

light: update ADR 47 with light traces (#5250)

* update adr 47 with light traces

* implement suggestions

* add second downside to alternative approach
pull/5255/head
Callum Waters 4 years ago
committed by GitHub
parent
commit
22ef3f6e7a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 67 additions and 65 deletions
  1. +67
    -65
      docs/architecture/adr-047-handling-evidence-from-light-client.md

+ 67
- 65
docs/architecture/adr-047-handling-evidence-from-light-client.md View File

@ -5,99 +5,99 @@
* 24-02-2020: Second version
* 13-04-2020: Add PotentialAmnesiaEvidence and a few remarks
* 31-07-2020: Remove PhantomValidatorEvidence
* 14-08-2020: Introduce light traces
## Context
If the light client is under attack, either directly -> lunatic
attack (light fork) or indirectly -> full fork, it's supposed to halt and
send evidence of misbehavior to a correct full node. Upon receiving an
evidence, the full node should punish malicious validators (if possible).
The bisection method of header verification used by the light client exposes
itself to a potential attack if any block within the light clients trusted period has
a malicious group of validators with power that exceeds the light clients trust level
(default is 1/3). To improve light client (and overall network) security, the light
client has a detector component that compares the verified header provided by the
primary against witness headers. This ADR outlines the decision that ensues when
the light client detector receives two conflicting headers
## Alternative Approaches
One of the key arguments surrounding the decision is whether the processing required
to extract verifiable evidence should be on the light client side or the full node side.
As light client, indicated in it's name, is supposed to stay light, the natural
inclination is to avoid any load and pass it directly to the full node who also has
the advantage of having a full state. It remains possible in future discussions to have the
light client form the evidence types itself. The other minor downsides apart from the
load will be that around half the evidence produced by the light client will be invalid and
that, in the event of modified logic, it's easier and expected that the full node be up
to date than the light clients.
## Decision
When a light client sees two conflicting headers (`H1.Hash() != H2.Hash()`,
`H1.Height == H2.Height`), both having 1/3+ of the voting power of the
currently trusted validator set, it will submit a `ConflictingHeadersEvidence`
to all full nodes it's connected to. Evidence needs to be submitted to all full
nodes since there's no way to determine which full node is correct (honest).
When two headers have different hashes, the light client must first verify via
bisection that the signed header provided by the witness is also valid.
It then collects all the headers that were fetched as part of bisection into two traces.
One containing the primary's headers and the other containing the witness's headers.
The light client sends the trace to the opposite provider (i.e. the primary's trace
to the witness and the witness's trace to the primary) as the light client is
incapable of deciding which one is malicious.
Assuming one of the two providers is honest, that full node will then take the trace
and extract out the relevant evidence and propogate it until it ends up on chain.
*NOTE: We do not send evidence to other connected peers*
*NOTE: The light client halts then and does not verify with any other witness*
## Detailed Design
The traces will have the following data structure:
```go
type ConflictingHeadersEvidence struct {
H1 types.SignedHeader
H2 types.SignedHeader
type ConflictingHeadersTrace struct {
Headers []*types.SignedHeader
}
```
_Remark_: Theoretically, only the header, which differs from what a full node
has, needs to be sent. But sending two headers a) makes evidence easily
verifiable b) simplifies the light client, which does not have query each
witness as to which header it possesses.
When a full node receives the `ConflictingHeadersEvidence` evidence, it should
When a full node receives a `ConflictingHeadersTrace`, it should
a) validate it b) figure out if malicious behaviour is obvious (immediately
slashable) or the fork accountability protocol needs to be started.
slashable) or run the amnesia protocol.
### Validating headers
Check both headers are valid (`ValidateBasic`), have the same height, and
signed by 1/3+ of the validator set that the full node had at height
`H1.Height`.
Check headers are valid (`ValidateBasic`), are in order of ascending height, and do not exceed the `MaxTraceSize`.
- Q: What if light client validator set is not equal to full node's validator
set (i.e. from full node's point of view both headers are not properly signed;
this includes the case where none of the two headers were committed on the
main chain)
### Finding Block Bifurcation
Reject the evidence. It means light client is following a fork, but, hey, at
least it will halt.
The node pulls the block ID's for the respective heights of the trace headers from its own block store.
- Q: Don't we want to punish validators who signed something else even if they
have less or equal than 1/3?
First it checks to see that the first header hash matches its first `BlockID` else it can discard it.
No consensus so far. Ethan said no, Zarko said yes.
https://github.com/tendermint/spec/pull/71#discussion_r374210533
If the last header hash matches the nodes last `BlockID` then it can also discard it on the assumption that a fork can not remerge and hence this is just a trace of valid headers.
### Figuring out if malicious behaviour is immediately slashable
The node then continues to loop in descending order checking that the headers hash doesn't match it's own blockID for that height. Once it reaches the height that the block ID matches the hash it then sends the common header, the trusted header and the diverged header (common header is needed for lunatic evidence) to determine if the divergence is a real offense to the tendermint protocol or if it is just fabricated.
Let's say H1 was committed from this full node's perspective (see Appendix A).
_If neither of the headers (H1 and H2) were committed from the full node's
perspective, the evidence must be rejected._
### Figuring out if malicious behaviour
Intersect validator sets of H1 and H2.
The node first examines the case of a lunatic attack:
* if there are signers(H2) that are not part of validators(H1), they misbehaved as
they are signing protocol messages in heights they are not validators =>
immediately slashable (#F4).
* The validator set of the common header must have at least 1/3 validator power that signed in the divergedHeaders commit
* if `H1.Round == H2.Round`, and some signers signed different precommit
messages in both commits, then it is an equivocation misbehavior => immediately
slashable (#F1).
* One of the deterministically derived hashes (`ValidatorsHash`, `NextValidatorsHash`, `ConsensusHash`,
`AppHash`, or `LastResultsHash`) of the header must not match:
* if `H1.Round != H2.Round` we need to run full detection procedure => not
immediately slashable.
* We then take every validator that voted for the invalid header and was a validator in the common headers validator set and create `LunaticValidatorEvidence`
* if `ValidatorsHash`, `NextValidatorsHash`, `ConsensusHash`,
`AppHash`, and `LastResultsHash` in H2 are different (incorrect application
state transition), then it is a lunatic misbehavior => immediately slashable (#F5).
If this fails then we examine the case of Equivocation (either duplicate vote or amnesia):
If evidence is not immediately slashable, fork accountability needs to invoked
(ADR does not yet exist).
*This only requires the trustedHeader and the divergedHeader*
It's unclear if we should further break up `ConflictingHeadersEvidence` or
gossip and commit it directly. See
https://github.com/tendermint/tendermint/issues/4182#issuecomment-590339233
* if `trustedHeader.Round == divergedHeader.Round`, and a validator signed for the block in both headers then DuplicateVoteEvidence can be immediately formed
If we'd go without breaking evidence, all we'll need to do is to strip the
committed header from `ConflictingHeadersEvidence` (H1) and leave only the
uncommitted header (H2):
* if `trustedHeader.Round != divergedHeader.Round` then we form PotentialAmnesiaEvidence as some validators in this set have behaved maliciously and protocol in ADR 56 needs to be run.
```go
type ConflictingHeaderEvidence struct {
H types.SignedHeader
}
```
*The node does not check that there is a 1/3 overlap between headers as this may not be point of the fork and validator sets may have since changed*
If we'd go with breaking evidence, here are the types we'll need:
If no evidence can be formed from a light trace, it is not a legitimate trace and thus the
connection with the peer should be stopped
### F1. Equivocation
@ -172,7 +172,7 @@ punish those who conducted an amnesia attack.
See ADR-056 for the architecture of the handling amnesia attacks.
NOTE: Conflicting headers evidence used to also create PhantomValidatorEvidence
NOTE: Conflicting headers trace used to also create PhantomValidatorEvidence
but this has since been removed. Refer to Appendix B.
## Status
@ -183,14 +183,15 @@ Proposed.
### Positive
* Light client has increased secuirty against Lunatic attacks.
* Tendermint will be able to detect & punish new types of misbehavior
* light clients connected to multiple full nodes can help full nodes notice a
fork faster
### Negative
* Accepting `ConflictingHeadersEvidence` from light clients opens up a DDOS
attack vector (same is fair for any RPC endpoint open to public; remember that
* Accepting `ConflictingHeadersEvidence` from light clients opens up a large DDOS
attack vector(same is fair for any RPC endpoint open to public; remember that
RPC is not open by default).
### Neutral
@ -198,6 +199,7 @@ RPC is not open by default).
## References
* [Fork accountability spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client/accountability.md)
* [ADR 056: Proving amnesia attakcs](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-056-proving-amnesia-attacks.md)
## Appendix A


Loading…
Cancel
Save