You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
12 KiB

  1. # ADR 047: Handling evidence from light client
  2. ## Changelog
  3. * 18-02-2020: Initial draft
  4. * 24-02-2020: Second version
  5. * 13-04-2020: Add PotentialAmnesiaEvidence and a few remarks
  6. * 31-07-2020: Remove PhantomValidatorEvidence
  7. * 14-08-2020: Introduce light traces (listed now as an alternative approach)
  8. * 20-08-2020: Light client produces evidence when detected instead of passing to full node
  9. * 16-09-2020: Post-implementation revision
  10. ### Glossary of Terms
  11. - a `LightBlock` is the unit of data that a light client receives, verifies and stores.
  12. It is composed of a validator set, commit and header all at the same height.
  13. - a **Trace** is seen as an array of light blocks across a range of heights that were
  14. created as a result of skipping verification.
  15. - a **Provider** is a full node that a light client is connected to and serves the light
  16. client signed headers and validator sets.
  17. - `VerifySkipping` (sometimes known as bisection or verify non-adjacent) is a method the
  18. light client uses to verify a target header from a trusted header. The process involves verifying
  19. intermediate headers in between the two by making sure that 1/3 of the validators that signed
  20. the trusted header also signed the untrusted one.
  21. - **Light Bifurcation Point**: If the light client was to run `VerifySkipping` with two providers
  22. (i.e. a primary and a witness), the bifurcation point is the height that the headers
  23. from each of these providers are different yet valid. This signals that one of the providers
  24. may be trying to fool the light client.
  25. ## Context
  26. The bisection method of header verification used by the light client exposes
  27. itself to a potential attack if any block within the light clients trusted period has
  28. a malicious group of validators with power that exceeds the light clients trust level
  29. (default is 1/3). To improve light client (and overall network) security, the light
  30. client has a detector component that compares the verified header provided by the
  31. primary against witness headers. This ADR outlines the process of mitigating attacks
  32. on the light client by using witness nodes to cross reference with.
  33. ## Alternative Approaches
  34. A previously discussed approach to handling evidence was to pass all the data that the
  35. light client had witnessed when it had observed diverging headers for the full node to
  36. process.This was known as a light trace and had the following structure:
  37. ```go
  38. type ConflictingHeadersTrace struct {
  39. Headers []*types.SignedHeader
  40. }
  41. ```
  42. This approach has the advantage of not requiring as much processing on the light
  43. client side in the event that an attack happens. Although, this is not a significant
  44. difference as the light client would in any case have to validate all the headers
  45. from both witness and primary. Using traces would consume a large amount of bandwidth
  46. and adds a DDOS vector to the full node.
  47. ## Decision
  48. The light client will be divided into two components: a `Verifier` (either sequential or
  49. skipping) and a `Detector` (see [Informal's Detector](https://github.com/informalsystems/tendermint-rs/blob/master/docs/spec/lightclient/detection/detection.md))
  50. . The detector will take the trace of headers from the primary and check it against all
  51. witnesses. For a witness with a diverging header, the detector will first verify the header
  52. by bisecting through all the heights defined by the trace that the primary provided. If valid,
  53. the light client will trawl through both traces and find the point of bifurcation where it
  54. can proceed to extract any evidence (as is discussed in detail later).
  55. Upon successfully detecting the evidence, the light client will send it to both primary and
  56. witness before halting. It will not send evidence to other peers nor continue to verify the
  57. primary's header against any other header.
  58. ## Detailed Design
  59. The verification process of the light client will start from a trusted header and use a bisectional
  60. algorithm to verify up to a header at a given height. This becomes the verified header (does not
  61. mean that it is trusted yet). All headers that were verified in between are cached and known as
  62. intermediary headers and the entire array is sometimes referred to as a trace.
  63. The light client's detector then takes all the headers and runs the detect function.
  64. ```golang
  65. func (c *Client) detectDivergence(primaryTrace []*types.LightBlock, now time.Time) error
  66. ```
  67. The function takes the last header it received, the target header and compares it against all the witnesses
  68. it has through the following function:
  69. ```golang
  70. func (c *Client) compareNewHeaderWithWitness(errc chan error, h *types.SignedHeader,
  71. witness provider.Provider, witnessIndex int)
  72. ```
  73. The err channel is used to send back all the outcomes so that they can be processed in parallel.
  74. Invalid headers result in dropping the witness, lack of response or not having the headers is ignored
  75. just as headers that have the same hash. Headers, however,
  76. of a different hash then trigger the detection process between the primary and that particular witness.
  77. This begins with verification of the witness's header via skipping verification which is run in tande
  78. with locating the Light Bifurcation Point
  79. ![](../imgs/light-client-detector.png)
  80. This is done with:
  81. ```golang
  82. func (c *Client) examineConflictingHeaderAgainstTrace(
  83. trace []*types.LightBlock,
  84. divergentHeader *types.SignedHeader,
  85. source provider.Provider, now time.Time) ([]*types.LightBlock, *types.LightBlock, error)
  86. ```
  87. which performs the following
  88. 1. Checking that the trusted header is the same. Currently, they should not theoretically be different
  89. because witnesses cannot be added and removed after the client is initialized. But we do this any way
  90. as a sanity check. If this fails we have to drop the witness.
  91. 2. Querying and verifying the witness's headers using bisection at the same heights of all the
  92. intermediary headers of the primary (In the above example this is A, B, C, D, F, H). If bisection fails or the witness stops responding then
  93. we can call the witness faulty and drop it.
  94. 3. We eventually reach a verified header by the witness which is not the same as the intermediary header (In the above example this is E).
  95. This is the point of bifurcation (This could also be the last header).
  96. This function then returns the trace of blocks from the witness node between the common header and the
  97. divergent header of the primary as it
  98. is likely as seen in the example to the right below that multiple headers where required in order to
  99. verify the divergent one. This trace will
  100. be used later (as is also described later in this document).
  101. ![](../imgs/bifurcation-point.png)
  102. Now, that an attack has been detected, the light client must form evidence to prove it. There are
  103. three types of attacks that either the primary or witness could have done to try fool the light client
  104. into verifying the wrong header: Lunatic, Equivocation and Amnesia. As the consequence is the same and
  105. the data required to prove it is also very similar, we bundle these attack styles together in a single
  106. evidence:
  107. ```golang
  108. type LightClientAttackEvidence struct {
  109. ConflictingBlock *LightBlock
  110. CommonHeight int64
  111. }
  112. ```
  113. The light client takes the stance of first suspecting the primary. Given the bifurcation point found
  114. above, it takes the two divergent headers and compares whether the one from the primary is valid with
  115. respect to the one from the witness. This is done by calling `isInvalidHeader()` which looks to see if
  116. any one of the deterministically derived header fields differ from one another. This could be one of
  117. `ValidatorsHash`, `NextValidatorsHash`, `ConsensusHash`, `AppHash`, and `LastResultsHash`.
  118. In this case we know it's a Lunatic attack and to help the witness verify it we send the height
  119. of the common header which is 1 in the example above or C in the example above that. If all these
  120. hashes are the same then we can infer that it is either Equivocation or Amnesia. In this case we send
  121. the height of the diverged headers because we know that the validator sets are the same, hence the
  122. malicious nodes are still bonded at that height. In the example above, this is height 10 and the
  123. example above that it is the height at E.
  124. The light client now has the evidence and broadcasts it to the witness.
  125. However, it could have been that the header the light client used from the witness against the primary
  126. was forged, so before halting the light client swaps the process and thus suspects the witness and
  127. uses the primary to create evidence. It calls `examineConflictingHeaderAgainstTrace` this time using
  128. the witness trace found earlier.
  129. If the primary was malicious it is likely that it will not respond but if it is innocent then the
  130. light client will produce the same evidence but this time the conflicting
  131. block will come from the witness node instead of the primary. The evidence is then formed and sent to
  132. the primary node.
  133. This then ends the process and the verify function that was called at the start returns the error to
  134. the user.
  135. For a detailed overview of how each of these three attacks can be conducted please refer to the
  136. [fork accountability spec]((https://github.com/tendermint/spec/blob/master/spec/consensus/light-client/accountability.md)).
  137. ## Full Node Verification
  138. When a full node receives evidence from the light client it will need to verify
  139. it for itself before gossiping it to peers and trying to commit it on chain. This process is outlined
  140. in [ADR-059](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-059-evidence-composition-and-lifecycle.md).
  141. ## Status
  142. Implemented.
  143. ## Consequences
  144. ### Positive
  145. * Light client has increased security against Lunatic, Equivocation and Amnesia attacks.
  146. * Do not need intermediate data structures to encapsulate the malicious behavior
  147. * Generalized evidence makes the code simpler
  148. ### Negative
  149. * Breaking change on the light client from versions 0.33.8 and below. Previous
  150. versions will still send `ConflictingHeadersEvidence` but it won't be recognized
  151. by the full node. Light clients will however still refuse the header and shut down.
  152. * Amnesia attacks although detected, will not be able to be punished as it is not
  153. clear from the current information which nodes behaved maliciously.
  154. * Evidence module must handle both individual and grouped evidence.
  155. ### Neutral
  156. ## References
  157. * [Fork accountability spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client/accountability.md)
  158. * [ADR 056: Light client amnesia attacks](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-056-light-client-amnesia-attacks.md)
  159. * [ADR-059: Evidence Composition and Lifecycle](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-059-evidence-composition-and-lifecycle.md)
  160. * [Informal's Light Client Detector](https://github.com/informalsystems/tendermint-rs/blob/master/docs/spec/lightclient/detection/detection.md)
  161. ## Appendix A
  162. PhantomValidatorEvidence was used to capture when a validator that was still staked
  163. (i.e. within the bonded period) but was not in the current validator set had voted for a block.
  164. In later discussions it was argued that although possible to keep phantom validator
  165. evidence, any case a phantom validator that could have the capacity to be involved
  166. in fooling a light client would have to be aided by 1/3+ lunatic validators.
  167. It would also be very unlikely that the new validators injected by the lunatic attack
  168. would be validators that currently still have something staked.
  169. Not only this but there was a large degree of extra computation required in storing all
  170. the currently staked validators that could possibly fall into the group of being
  171. a phantom validator. Given this, it was removed.