github.com/number571/tendermint@v0.34.11-gost/docs/architecture/adr-047-handling-evidence-from-light-client.md (about)

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