github.com/aakash4dev/cometbft@v0.38.2/spec/light-client/detection/discussions.md (about)

     1  # Results of Discussions and Decisions
     2  
     3  - Generating a minimal proof of fork (as suggested in [Issue #5083](https://github.com/tendermint/tendermint/issues/5083)) is too costly at the light client
     4      - we do not know all lightblocks from the primary
     5      - therefore there are many scenarios. we might even need to ask
     6        the primary again for additional lightblocks to isolate the
     7        branch.
     8  
     9  > For instance, the light node starts with block at height 1 and the
    10  > primary provides a block of height 10 that the light node can
    11  > verify immediately. In cross-checking, a secondary now provides a
    12  > conflicting header b10 of height 10 that needs another header b5
    13  > of height 5 to
    14  > verify. Now, in order for the light node to convince the primary:
    15  >
    16  > - The light node cannot just sent b5, as it is not clear whether
    17  >     the fork happened before or after 5
    18  > - The light node cannot just send b10, as the primary would also
    19  >     need  b5 for verification
    20  > - In order to minimize the evidence, the light node may try to
    21  >     figure out where the branch happens, e.g., by asking the primary
    22  >     for height 5 (it might be that more queries are required, also
    23  >     to the secondary. However, assuming that in this scenario the
    24  >     primary is faulty it may not respond.
    25  
    26     As the main goal is to catch misbehavior of the primary,
    27        evidence generation and punishment must not depend on their
    28        cooperation. So the moment we have proof of fork (even if it
    29        contains several light blocks) we should submit right away.
    30  
    31  - decision: "full" proof of fork consists of two traces that originate in the
    32    same lightblock and lead to conflicting headers of the same height.
    33    
    34  - For submission of proof of fork, we may do some optimizations, for
    35    instance, we might just submit  a trace of lightblocks that verifies a block
    36    different from the one the full node knows (we do not send the trace
    37    the primary gave us back to the primary)
    38  
    39  - The light client attack is via the primary. Thus we try to
    40    catch if the primary installs a bad light block
    41      - We do not check secondary against secondary
    42      - For each secondary, we check the primary against one secondary
    43  
    44  - Observe that just two blocks for the same height are not
    45  sufficient proof of fork.
    46  One of the blocks may be bogus [CMBC-BOGUS.1] which does
    47  not constitute slashable behavior.  
    48  Which leads to the question whether the light node should try to do
    49  fork detection on its initial block (from subjective
    50  initialization). This could be done by doing backwards verification
    51  (with the hashes) until a bifurcation block is found.
    52  While there are scenarios where a
    53  fork could be found, there is also the scenario where a faulty full
    54  node feeds the light node with bogus light blocks and forces the light
    55  node to check hashes until a bogus chain is out of the trusting period.
    56  As a result, the light client
    57  should not try to detect a fork for its initial header. **The initial
    58  header must be trusted as is.**
    59  
    60  # Light Client Sequential Supervisor
    61  
    62  **TODO:** decide where (into which specification) to put the
    63  following:
    64  
    65  We describe the context on which the fork detector is called by giving
    66  a sequential version of the supervisor function.
    67  Roughly, it alternates two phases namely:
    68  
    69  - Light Client Verification. As a result, a header of the required
    70       height has been downloaded from and verified with the primary.
    71  - Light Client Fork Detections. As a result the header has been
    72       cross-checked with the secondaries. In case there is a fork we
    73       submit "proof of fork" and exit.
    74  
    75  #### **[LC-FUNC-SUPERVISOR.1]:**
    76  
    77  ```go
    78  func Sequential-Supervisor () (Error) {
    79      loop {
    80       // get the next height
    81          nextHeight := input();
    82    
    83    // Verify
    84          result := NoResult;
    85          while result != ResultSuccess {
    86              lightStore,result := VerifyToTarget(primary, lightStore, nextHeight);
    87              if result == ResultFailure {
    88      // pick new primary (promote a secondary to primary)
    89      /// and delete all lightblocks above
    90               // LastTrusted (they have not been cross-checked)
    91               Replace_Primary();
    92     }
    93          }
    94    
    95    // Cross-check
    96          PoFs := Forkdetector(lightStore, PoFs);
    97          if PoFs.Empty {
    98        // no fork detected with secondaries, we trust the new
    99     // lightblock
   100              LightStore.Update(testedLB, StateTrusted);
   101          }
   102          else {
   103        // there is a fork, we submit the proofs and exit
   104              for i, p range PoFs {
   105                  SubmitProofOfFork(p);
   106              }
   107              return(ErrorFork);
   108          }
   109      }
   110  }
   111  ```
   112  
   113  **TODO:** finish conditions
   114  
   115  - Implementation remark
   116  - Expected precondition
   117      - *lightStore* initialized with trusted header
   118      - *PoFs* empty
   119  - Expected postcondition
   120      - runs forever, or
   121      - is terminated by user and satisfies LightStore invariant, or **TODO**
   122      - has submitted proof of fork upon detecting a fork
   123  - Error condition
   124      - none
   125  
   126  ----
   127  
   128  # Semantics of the LightStore
   129  
   130  Currently, a lightblock in the lightstore can be in one of the
   131  following states:
   132  
   133  - StateUnverified
   134  - StateVerified
   135  - StateFailed
   136  - StateTrusted
   137  
   138  The intuition is that `StateVerified` captures that the lightblock has
   139  been verified with the primary, and `StateTrusted` is the state after
   140  successful cross-checking with the secondaries.
   141  
   142  Assuming there is **always one correct node among primary and
   143  secondaries**, and there is no fork on the blockchain, lightblocks that
   144  are in `StateTrusted` can be used by the user with the guarantee of
   145  "finality". If a block in  `StateVerified` is used, it might be that
   146  detection later finds a fork, and a roll-back might be needed.
   147  
   148  **Remark:** The assumption of one correct node, does not render
   149  verification useless. It is true that if the primary and the
   150  secondaries return the same block we may trust it. However, if there
   151  is a node that provides a different block, the light node still needs
   152  verification to understand whether there is a fork, or whether the
   153  different block is just bogus (without any support of some previous
   154  validator set).
   155  
   156  **Remark:** A light node may choose the full nodes it communicates
   157  with (the light node and the full node might even belong to the same
   158  stakeholder) so the assumption might be justified in some cases.
   159  
   160  In the future, we will do the following changes
   161  
   162  - we assume that only from time to time, the light node is
   163       connected to a correct full node
   164  - this means for some limited time, the light node might have no
   165       means to defend against light client attacks
   166  - as a result we do not have finality
   167  - once the light node reconnects with a correct full node, it
   168       should detect the light client attack and submit evidence.
   169  
   170  Under these assumptions, `StateTrusted` loses its meaning. As a
   171  result, it should be removed from the API. We suggest that we replace
   172  it with a flag "trusted" that can be used
   173  
   174  - internally for efficiency reasons (to maintain
   175    [LCD-INV-TRUSTED-AGREED.1] until a fork is detected)
   176  - by light client based on the "one correct full node" assumption
   177  
   178  ----