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

     1  <!-- markdown-link-check-disable -->
     2  # Light Client Attack Detector
     3  
     4  In this specification, we strengthen the light client to be resistant
     5  against so-called light client attacks. In a light client attack, all
     6  the correct Cosmos full nodes agree on the sequence of generated
     7  blocks (no fork), but a set of faulty full nodes attack a light client
     8  by generating (signing) a block that deviates from the block of the
     9  same height on the blockchain. In order to do so, some of these faulty
    10  full nodes must have been validators before and violate the assumption
    11  of more than two thirds of "correct voting power"
    12  [[CMBC-FM-2THIRDS]][CMBC-FM-2THIRDS-link], as otherwise, if
    13  [[CMBC-FM-2THIRDS]][CMBC-FM-2THIRDS-link] would hold,
    14  [verification][verification] would satisfy
    15  [[LCV-SEQ-SAFE.1]][LCV-SEQ-SAFE-link].
    16  
    17  An attack detector (or detector for short) is a mechanism that is used
    18  by the light client [supervisor][supervisor] after
    19  [verification][verification] of a new light block
    20  with the primary, to cross-check the newly learned light block with
    21  other peers (secondaries).  It expects as input a light block with some
    22  height *root* (that serves as a root of trust), and a verification
    23  trace (a sequence of lightblocks) that the primary provided.
    24  
    25  In case the detector observes a light client attack, it computes
    26  evidence data that can be used by Cosmos full nodes to isolate a
    27  set of faulty full nodes that are still within the unbonding period
    28  (more than 1/3 of the voting power of the validator set at some block
    29  of the chain), and report them via ABCI (application/blockchain
    30  interface)
    31  to the application of a
    32  Cosmos blockchain in order to punish faulty nodes.
    33  
    34  ## Context of this document
    35  
    36  The light client [verification][verification] specification is
    37  designed for the Cosmos failure model (1/3 assumption)
    38  [[CMBC-FM-2THIRDS]][CMBC-FM-2THIRDS-link].  It is safe under this
    39  assumption, and live if it can reliably (that is, no message loss, no
    40  duplication, and eventually delivered) and timely communicate with a
    41  correct full node. If [[CMBC-FM-2THIRDS]][CMBC-FM-2THIRDS-link]
    42  assumption is violated, the light client can be fooled to trust a
    43  light block that was not generated by Tendermint consensus.
    44  
    45  This specification, the attack detector, is a "second line of
    46  defense", in case the 1/3 assumption is violated.  Its goal is to
    47  detect a light client attack (conflicting light blocks) and collect
    48  evidence. However, it is impractical to probe all full nodes. At this
    49  time we consider a simple scheme of maintaining an address book of
    50  known full nodes from which a small subset (e.g., 4) are chosen
    51  initially to communicate with. More involved book keeping with
    52  probabilistic guarantees can be considered at later stages of the
    53  project.
    54  
    55  The light client maintains a simple address book containing addresses
    56  of full nodes that it can pick as primary and secondaries.  To obtain
    57  a new light block, the light client first does
    58  [verification][verification] with the primary, and then cross-checks
    59  the light block (and the trace of light blocks that led to it) with
    60  the secondaries using this specification.
    61  
    62  # Outline
    63  
    64  - [Part I](#part-i---Tendermint-Consensus-and-Light-Client-Attacks):
    65    Formal definitions of lightclient attacks, based on basic
    66    properties of Tendermint consensus.
    67      - [Node-based characterization of
    68         attacks](#Node-based-characterization-of-attacks). The
    69         definition of attacks used in the problem statement of
    70      this specification.
    71  
    72      - [Block-based characterization of attacks](#Block-based-characterization-of-attacks). Alternative definitions
    73    provided for future reference.
    74  
    75  - [Part II](#part-ii---problem-statement): Problem statement of
    76    lightclient attack detection
    77    
    78      - [Informal Problem Statement](#informal-problem-statement)
    79      - [Assumptions](#Assumptions)
    80      - [Definitions](#definitions)
    81      - [Distributed Problem statement](#Distributed-Problem-statement)
    82    
    83  - [Part III](#part-iii---protocol): The protocol
    84  
    85      - [Functions and Data defined in other Specifications](#Functions-and-Data-defined-in-other-Specifications)
    86      - [Outline of Solution](#Outline-of-solution)
    87      - [Details of the functions](#Details-of-the-functions)
    88      - [Correctness arguments](#Correctness-arguments)
    89  
    90  # Part I - Tendermint Consensus and Light Client Attacks
    91  
    92  In this section we will give some mathematical definitions of what we
    93  mean by light client attacks (that are considered in this
    94  specification) and how they differ from main-chain forks. To this end,
    95  we start by defining some properties of the sequence of blocks that is
    96  decided upon by Tendermint consensus in normal operation (if the
    97  Cosmos failure model holds
    98  [[CMBC-FM-2THIRDS]][CMBC-FM-2THIRDS-link]),
    99  and then define different
   100  deviations that correspond to attack scenarios. We consider the notion
   101  of [light blocks][LCV-LB-link] and [headers][LVC-HD-link].
   102  
   103  #### **[CMBC-GENESIS.1]**
   104  
   105  Let *Genesis* be the agreed-upon initial block (file).
   106  
   107  #### **[CMBC-FUNC-SIGN.1]**
   108  
   109  Let *b* and *c* be two light blocks with *b.Header.Height + 1 =
   110  c.Header.Height*. We define the predicate **signs(b,c)** to hold
   111  iff *c.Header.LastCommit* is in *PossibleCommit(b)*.
   112  [[CMBC-SOUND-DISTR-POSS-COMMIT.1]][CMBC-SOUND-DISTR-POSS-COMMIT-link].
   113  
   114  > The above encodes sequential verification, that is, intuitively,
   115  > b.Header.NextValidators = c.Header.Validators and 2/3 of
   116  > these Validators signed c.
   117  
   118  #### **[CMBC-FUNC-SUPPORT.1]**
   119  
   120  Let *b* and *c* be two light blocks. We define the predicate
   121  **supports(b,c,t)** to hold iff
   122  
   123  - *t - trustingPeriod < b.Header.Time < t*
   124  - the voting power in *b.NextValidators* of nodes in *c.Commit*
   125    is more than 1/3 of *TotalVotingPower(b.Header.NextValidators)*
   126  
   127  > That is, if the [Cosmos failure model][CMBC-FM-2THIRDS-link]
   128  > holds, then *c* has been signed by at least one correct full node, cf.
   129  > [[CMBC-VAL-CONTAINS-CORR.1]][CMBC-VAL-CONTAINS-CORR-link].
   130  > The following formalizes that *b* was properly generated by
   131  > Tendermint; *b* can be traced back to genesis.
   132  
   133  #### **[CMBC-SEQ-ROOTED.1]**
   134  
   135  Let *b* be a light block.
   136  We define *sequ-rooted(b)* iff for all *i*, *1 <= i < h = b.Header.Height*,
   137  there exist light blocks *a(i)* s.t.
   138  
   139  - *a(1) = Genesis* and
   140  - *a(h) = b* and
   141  - *signs( a(i) , a(i+1) )*.
   142  
   143  > The following formalizes that *c* is trusted based on *b* in
   144  > skipping verification. Observe that we do not require here (yet)
   145  > that *b* was properly generated.
   146  
   147  #### **[CMBC-SKIP-TRACE.1]**
   148  
   149  Let *b* and *c* be light blocks. We define *skip-trace(b,c,t)* if at
   150  time t there exists an integer *h* and a sequence *a(1)*, ... *a(h)* s.t.
   151  
   152  - *a(1) = b* and
   153  - *a(h) = c* and
   154  - *supports( a(i), a(i+1), t)*, for all i, *1 <= i < h*.
   155  
   156  We call such a sequence *a(1)*, ... *a(h)* a **verification trace**.
   157  
   158  > The following formalizes that two light blocks of the same height
   159  > should agree on the content of the header. Observe that *b* and *c*
   160  > may disagree on the Commit. This is a special case if the canonical
   161  > commit has not been decided on yet, that is, if b.Header.Height is the
   162  > maximum height of all blocks decided upon by Tendermint at this
   163  > moment.
   164  
   165  #### **[CMBC-SIGN-SKIP-MATCH.1]**
   166  
   167  Let *a*, *b*, *c*, be light blocks and *t* a time, we define
   168  *sign-skip-match(a,b,c,t) = true* iff the following implication
   169  evaluates to true:
   170  
   171  - *sequ-rooted(a)* and
   172  - *b.Header.Height = c.Header.Height* and
   173  - *skip-trace(a,b,t)*
   174  - *skip-trace(a,c,t)*
   175  
   176  implies *b.Header = c.Header*.
   177  
   178  > Observe that *sign-skip-match* is defined via an implication. If it
   179  > evaluates to false this means that the left-hand-side of the
   180  > implication evaluates to true, and the right-hand-side evaluates to
   181  > false. In particular, there are two **different** headers *b* and
   182  > *c* that both can be verified from a common block *a* from the
   183  > chain. Thus, the following describes an attack.
   184  
   185  #### **[CMBC-ATTACK.1]**
   186  
   187  If there exists three light blocks a, b, and c, with
   188  *sign-skip-match(a,b,c,t) = false* then we have an *attack*.  We say
   189  we have **an attack at height** *b.Header.Height* and write
   190  *attack(a,b,c,t)*.
   191  
   192  > The lightblock *a* need not be unique, that is, there may be
   193  > several blocks that satisfy the above requirement for the same
   194  > blocks *b* and *c*.
   195  
   196  [[CMBC-ATTACK.1]](#CMBC-ATTACK1) is a formalization of the violation
   197  of the agreement property based on the result of consensus, that is,
   198  the generated blocks.
   199  
   200  **Remark.**
   201  Violation of agreement is only possible if more than 1/3 of the validators (or
   202  next validators) of some previous block deviated from the protocol. The
   203  upcoming "accountability" specification will describe how to compute
   204  a set of at least 1/3 faulty nodes from two conflicting blocks. []
   205  
   206  There are different ways to characterize forks
   207  and attack scenarios. This specification uses the "node-based
   208  characterization of attacks" which focuses on what kinds of nodes are
   209  affected (light nodes vs. full nodes). For future reference and
   210  discussion we also provide a
   211  "block-based characterization of attacks" below.
   212  
   213  ## Node-based characterization of attacks
   214  
   215  #### **[CMBC-MC-FORK.1]**
   216  
   217  We say there is a (main chain) fork at time *t* if
   218  
   219  - there are two correct full nodes *i* and *j* and
   220  - *i* is different from *j* and
   221  - *i* has decided on *b* and
   222  - *j* has decided on *c* and
   223  - there exist *a* such that *attack(a,b,c,t)*.
   224  
   225  #### **[CMBC-LC-ATTACK.1]**
   226  
   227  We say there is a light client attack at time *t*, if
   228  
   229  - there is **no** (main chain) fork [[CMBC-MC-FORK.1]](#CMBC-MC-FORK1), and
   230  - there exist nodes that have computed light blocks *b* and *c* and
   231  - there exist *a* such that *attack(a,b,c,t)*.
   232  
   233  We say the attack is at height *a.Header.Height*.
   234  
   235  > In this specification we consider detection of light client
   236  > attacks. Intuitively, the case we consider is that
   237  > light block *b* is the one from the
   238  > blockchain, and some attacker has computed *c* and tries to wrongly
   239  > convince
   240  > the light client that *c* is the block from the chain.
   241  
   242  #### **[CMBC-LC-ATTACK-EVIDENCE.1]**
   243  
   244  We consider the following case of a light client attack
   245  [[CMBC-LC-ATTACK.1]](#CMBC-LC-ATTACK1):
   246  
   247  - *attack(a,b,c,t)*
   248  - there is a peer p1 that has a sequence *chain* of blocks from *a* to *b*
   249  - *skip-trace(a,c,t)*: by [[CMBC-SKIP-TRACE.1]](#CMBC-SKIP-TRACE1) there is a
   250    verification trace *v* of the form *a = v(1)*, ... *v(h) = c*
   251  
   252  Evidence for p1 (that proves an attack to p1) consists for index i
   253  of v(i) and v(i+1) such that
   254  
   255  - E1(i). v(i) is equal to the block of *chain* at height v(i).Height, and
   256  - E2(i). v(i+1) that is different from  the block of *chain* at
   257    height v(i+1).height
   258  
   259  > Observe p1 can
   260  >
   261  > - check that v(i+1)  differs from its block at that height, and
   262  > - verify v(i+1) in one step from v(i) as v is a verification trace.
   263  
   264  #### **[CMBC-LC-EVIDENCE-DATA.1]**
   265  
   266  To prove the attack to p1, because of Point E1, it is sufficient to
   267  submit
   268  
   269  - v(i).Height (rather than v(i)).
   270  - v(i+1)
   271  
   272  This information is *evidence for height v(i).Height*.
   273  
   274  ## Block-based characterization of attacks
   275  
   276  In this section we provide a different characterization of attacks. It
   277  is not defined on the nodes that are affected but purely on the
   278  content of the blocks. In that sense these definitions are less
   279  operational.
   280  
   281  > They might be relevant for a closer analysis of fork scenarios on the
   282  > chain, which is out of the scope of this specification.
   283    
   284  #### **[CMBC-SIGN-UNIQUE.1]**
   285  
   286  Let *b* and *c* be  light blocks, we define the predicate
   287  *sign-unique(b,c)* to evaluate to true iff the following implication
   288  evaluates to true:
   289  
   290  - *b.Header.Height =  c.Header.Height* and
   291  - *sequ-rooted(b)* and
   292  - *sequ-rooted(c)*
   293  
   294  implies *b = c*.
   295  
   296  #### **[CMBC-BLOCKS-MCFORK.1]**
   297  
   298  If there exists two light blocks b and c, with *sign-unique(b,c) =
   299  false* then we have a *fork*.
   300  
   301  > The difference of the above definition to
   302  > [[CMBC-MC-FORK.1]](#CMBC-MC-FORK1) is subtle. The latter requires a
   303  > full node being affected by a bad block while
   304  > [[CMBC-BLOCKS-MCFORK.1]](#CMBC-BLOCKS-MCFORK1) just requires that a
   305  > bad block exists, possibly in memory of an attacker.
   306  > The following captures a light client fork. There is no fork up to
   307  > the height of block b. However, c is of that height, is different,
   308  > and passes skipping verification. It is a stricter property than
   309  > [[CMBC-LC-ATTACK.1]](#CMBC-LC-ATTACK1), as
   310  > [[CMBC-LC-ATTACK.1]](#CMBC-LC-ATTACK1) requires that no correct full
   311  > node is affected.
   312  
   313  #### **[CMBC-BLOCKS-LCFORK.1]**
   314  
   315  Let *a*, *b*, *c*, be light blocks and *t* a time. We define
   316  *light-client-fork(a,b,c,t)* iff
   317  
   318  - *sign-skip-match(a,b,c,t) = false* and
   319  - *sequ-rooted(b)* and
   320  - *b* is "unique", that is, for all *d*,  *sequ-rooted(d)* and
   321       *d.Header.Height = b.Header.Height* implies *d = b*
   322  
   323  > Finally, let us also define bogus blocks that have no support.
   324  > Observe that bogus is even defined if there is a fork.
   325  > Also, for the definition it would be sufficient to restrict *a* to
   326  > *a.height < b.height* (which is implied by the definitions which
   327  > unfold until *supports()*).
   328  
   329  #### **[CMBC-BOGUS.1]**
   330  
   331  Let *b* be a light block and *t* a time. We define *bogus(b,t)* iff
   332  
   333  - *sequ-rooted(b) = false* and
   334  - for all *a*, *sequ-rooted(a)* implies *skip-trace(a,b,t) = false*
   335    
   336  # Part II - Problem Statement
   337    
   338  ## Informal Problem statement
   339  
   340  There is no sequential specification: the detector only makes sense
   341  in a distributed systems where some nodes misbehave.
   342  
   343  We work under the assumption that full nodes and validators are
   344  responsible for detecting attacks on the main chain, and the evidence
   345  reactor takes care of broadcasting evidence to communicate
   346  misbehaving nodes via ABCI to the application, and halt the chain in
   347  case of a fork. The point of this specification is to shield a light
   348  clients against attacks that cannot be detected by full nodes, and
   349  are fully addressed at light clients (and consequently IBC relayers,
   350  which use the light client protocols to observe the state of a
   351  blockchain). In order to provide full nodes the incentive to follow
   352  the protocols when communicating with the light client, this
   353  specification also considers the generation of evidence that will
   354  also be processed by the Cosmos blockchain.
   355  
   356  #### **[LCD-IP-MODEL.1]**
   357  
   358  The detector is designed under the assumption that
   359  
   360  - [[CMBC-FM-2THIRDS]][CMBC-FM-2THIRDS-link] may be violated
   361  - there is no fork on the main chain.
   362  
   363  > As a result some faulty full nodes may launch an attack on a light
   364  > client.
   365  
   366  The following requirements are operational in that they describe how
   367  things should be done, rather than what should be done. However, they
   368  do not constitute temporal logic verification conditions. For those,
   369  see [LCD-DIST-*] below.
   370  
   371  The detector is called in the [supervisor][supervisor] as follows
   372  
   373  ```go
   374  Evidences := AttackDetector(root_of_trust, verifiedLS);`
   375  ```
   376  
   377  where
   378  
   379  - `root-of-trust` is a light block that is trusted (that is,
   380  except upon initialization, the primary and the secondaries
   381  agreed on in the past), and
   382  - `verifiedLS` is a lightstore that contains a verification trace that
   383    starts from a lightblock that can be verified with the
   384    `root-of-trust` in one step and ends with a lightblock of the height
   385    requested by the user
   386  - `Evidences` is a list of evidences for misbehavior
   387  
   388  #### **[LCD-IP-STATEMENT.1]**
   389  
   390  Whenever AttackDetector is called, the detector should for each
   391  secondary cross check the largest header in verifiedLS with the
   392  corresponding header of the same height provided by the secondary. If
   393  there is a deviation, the detector should
   394  try to replay the verification trace `verifiedLS` with the
   395  secondary
   396    
   397  - in case replaying leads to detection of a light client attack
   398    (one of the lightblocks differ from the one in verifiedLS with
   399    the same height), we should return evidence
   400  - if the secondary cannot provide a verification trace, we have no
   401    proof for an attack. Block *b* may be bogus. In this case the
   402    secondary is faulty and it should be replaced.
   403  
   404  ## Assumptions
   405  
   406  It is not in the interest of faulty full nodes to talk to the
   407  detector as long as the  detector is connected to at least one
   408  correct full node. This would only increase the likelihood of
   409  misbehavior being detected. Also we cannot punish them easily
   410  (cheaply). The absence of a response need not be the fault of the full
   411  node.
   412  
   413  Correct full nodes have the incentive to respond, because the
   414  detector may help them to understand whether their header is a good
   415  one. We can thus base liveness arguments of the  detector on
   416  the assumptions that correct full nodes reliably talk to the
   417  detector.
   418  
   419  #### **[LCD-A-CorrFull.1]**
   420  
   421  At all times there is at least one correct full
   422  node among the primary and the secondaries.
   423  
   424  > For this version of the detection we take this assumption. It
   425  > allows us to establish the invariant that the lightblock
   426  > `root-of-trust` is always the one from the blockchain, and we can
   427  > use it as starting point for the evidence computation. Moreover, it
   428  > allows us to establish the invariant at the supervisor that any
   429  > lightblock in the (top-level) lightstore is from the blockchain.  
   430  > In the future we might design a lightclient based on the assumption
   431  > that at least in regular intervals the lightclient is connected to a
   432  > correct full node. This will require the detector to reconsider
   433  > `root-of-trust`, and remove lightblocks from the top-level
   434  > lightstore.
   435  
   436  #### **[LCD-A-RelComm.1]**
   437  
   438  Communication between the  detector and a correct full node is
   439  reliable and bounded in time. Reliable communication means that
   440  messages are not lost, not duplicated, and eventually delivered. There
   441  is a (known) end-to-end delay *Delta*, such that if a message is sent
   442  at time *t* then it is received and processed by time *t + Delta*.
   443  This implies that we need a timeout of at least *2 Delta* for remote
   444  procedure calls to ensure that the response of a correct peer arrives
   445  before the timeout expires.
   446  
   447  ## Definitions
   448  
   449  ### Evidence
   450  
   451  Following the definition of
   452  [[CMBC-LC-ATTACK-EVIDENCE.1]](#CMBC-LC-ATTACK-EVIDENCE1), by evidence
   453  we refer to a variable of the following type
   454  
   455  #### **[LC-DATA-EVIDENCE.1]**
   456  
   457  ```go
   458  type LightClientAttackEvidence struct {
   459      ConflictingBlock   LightBlock
   460      CommonHeight       int64
   461  
   462      // Evidence also includes application specific data which is not
   463      // part of verification but is sent to the application once the
   464      // evidence gets committed on chain.
   465  }
   466  ```
   467  
   468  As the above data is computed for a specific peer, the following
   469  data structure wraps the evidence and adds the peerID.
   470  
   471  #### **[LC-DATA-EVIDENCE-INT.1]**
   472  
   473  ```go
   474  type InternalEvidence struct {
   475      Evidence           LightClientAttackEvidence
   476      Peer               PeerID
   477  }
   478  ```
   479  
   480  #### **[LC-SUMBIT-EVIDENCE.1]**
   481  
   482  ```go
   483  func submitEvidence(Evidences []InternalEvidence)
   484  ```
   485  
   486  - Expected postcondition
   487      - for each `ev` in `Evidences`: submit `ev.Evidence` to `ev.Peer`
   488  
   489  ---
   490  
   491  ### LightStore
   492  
   493  Lightblocks and LightStores are defined in the verification
   494  specification [[LCV-DATA-LIGHTBLOCK.1]][LCV-LB-link]
   495  and [[LCV-DATA-LIGHTSTORE.2]][LCV-LS-link]. See
   496  the [verification specification][verification] for details.
   497  
   498  ## Distributed Problem statement
   499  
   500  > As the attack detector is there to reduce the impact of faulty
   501  > nodes, and faulty nodes imply that there is a distributed system,
   502  > there is no sequential specification to which this distributed
   503  > problem statement may refer to.
   504  
   505  The detector gets as input a trusted lightblock called *root* and an
   506  auxiliary lightstore called *primary_trace* with lightblocks that have
   507  been verified before, and that were provided by the primary.
   508  
   509  #### **[LCD-DIST-INV-ATTACK.1]**
   510  
   511  If the detector returns evidence for height *h*
   512  [[CMBC-LC-EVIDENCE-DATA.1]](#CMBC-LC-EVIDENCE-DATA1), then there is an
   513  attack at height *h*. [[CMBC-LC-ATTACK.1]](#CMBC-LC-ATTACK1)
   514  
   515  #### **[LCD-DIST-INV-STORE.1]**
   516  
   517  If the detector does not return evidence, then *primary_trace*
   518  contains only blocks from the blockchain.
   519  
   520  #### **[LCD-DIST-LIVE.1]**
   521  
   522  The detector eventually terminates.
   523  
   524  #### **[LCD-DIST-TERM-NORMAL.1]**
   525  
   526  If
   527  
   528  - the *primary_trace* contains only blocks from the blockchain, and
   529  - there is no attack, and
   530  - *Secondaries* is always non-empty, and
   531  - the age of *root* is always less than the trusting period,
   532  
   533  then the detector does not return evidence.
   534  
   535  #### **[LCD-DIST-TERM-ATTACK.1]**
   536  
   537  If
   538  
   539  - there is an attack, and
   540  - a secondary reports a block that conflicts
   541    with one of the blocks in *primary_trace*, and
   542  - *Secondaries* is always non-empty, and
   543  - the age of *root* is always less than the trusting period,
   544  
   545  then the detector returns evidence.
   546  
   547  > Observe that above we require that "a secondary reports a block that
   548  > conflicts". If there is an attack, but no secondary tries to launch
   549  > it against the detector (or the message from the secondary is lost
   550  > by the network), then there is nothing to detect for us.
   551  
   552  #### **[LCD-DIST-SAFE-SECONDARY.1]**
   553  
   554  No correct secondary is ever replaced.
   555  
   556  #### **[LCD-DIST-SAFE-BOGUS.1]**
   557  
   558  If
   559  
   560  - a secondary reports a bogus lightblock,
   561  - the age of *root* is always less than the trusting period,
   562  
   563  then the secondary is replaced before the detector terminates.
   564  
   565  > The above property is quite operational (e.g., the usage of
   566  > "reports"), but it captures closely the requirement. As the
   567  > detector only makes sense in a distributed setting, and does not
   568  > have a sequential specification, a less "pure" specification are
   569  > acceptable.
   570  
   571  # Part III - Protocol
   572  
   573  ## Functions and Data defined in other Specifications
   574  
   575  ### From the [supervisor][supervisor]
   576  
   577  [[LC-FUNC-REPLACE-SECONDARY.1]][repl]
   578  
   579  ```go
   580  Replace_Secondary(addr Address, root-of-trust LightBlock)
   581  ```
   582  
   583  ### From the [verifier][verification]
   584  
   585  [[LCV-FUNC-MAIN.2]][vtt]
   586  
   587  ```go
   588  func VerifyToTarget(primary PeerID, root LightBlock,
   589                      targetHeight Height) (LightStore, Result)
   590  ```
   591  
   592  Observe that `VerifyToTarget` does communication with the secondaries
   593  via the function [FetchLightBlock][fetch].
   594  
   595  ### Shared data of the light client
   596  
   597  - a pool of full nodes *FullNodes* that have not been contacted before
   598  - peer set called *Secondaries*
   599  - primary
   600  
   601  > Note that the lightStore is not needed to be shared.
   602  
   603  ## Outline of solution
   604  
   605  The problem laid out is solved by calling the function `AttackDetector`
   606  with a lightstore that contains a light block that has just been
   607  verified by the verifier.
   608  
   609  Then `AttackDetector` downloads headers from the secondaries. In case
   610  a conflicting header is downloaded from a secondary, it calls
   611  `CreateEvidenceForPeer` which computes evidence in the case that
   612  indeed an attack is confirmed. It could be that the secondary reports
   613  a bogus block, which means that there need not be an attack, and the
   614  secondary is replaced.
   615    
   616  ## Details of the functions
   617  
   618  #### **[LCD-FUNC-DETECTOR.2]:**
   619  
   620  ```go
   621  func AttackDetector(root LightBlock, primary_trace []LightBlock)
   622                     ([]InternalEvidence) {
   623  
   624      Evidences := new []InternalEvidence;
   625  
   626      for each secondary in Secondaries {
   627          lb, result := FetchLightBlock(secondary,primary_trace.Latest().Header.Height);
   628          if result != ResultSuccess {
   629              Replace_Secondary(root);
   630          }
   631          else if lb.Header != primary_trace.Latest().Header {
   632    
   633              // we replay the primary trace with the secondary, in
   634              // order to generate evidence that we can submit to the
   635              // secondary. We return the evidence + the trace the
   636              // secondary told us that spans the evidence at its local store
   637  
   638              EvidenceForSecondary, newroot, secondary_trace, result :=
   639                      CreateEvidenceForPeer(secondary,
   640                                            root,
   641                                            primary_trace);
   642              if result == FaultyPeer {
   643                  Replace_Secondary(root);
   644              }
   645              else if result == FoundEvidence {
   646                  // the conflict is not bogus
   647                  Evidences.Add(EvidenceForSecondary);
   648                  // we replay the secondary trace with the primary, ...
   649                  EvidenceForPrimary, _, result :=
   650                          CreateEvidenceForPeer(primary,
   651                                                newroot,
   652                                                secondary_trace);
   653                  if result == FoundEvidence {
   654                      Evidences.Add(EvidenceForPrimary);
   655                  }
   656                  // At this point we do not care about the other error
   657                  // codes. We already have generated evidence for an
   658                  // attack and need to stop the lightclient. It does not
   659                  // help to call replace_primary. Also we will use the
   660                  // same primary to check with other secondaries in
   661                  // later iterations of the loop
   662              }
   663              // In the case where the secondary reports NoEvidence
   664              // after initially it reported a conflicting header.
   665              // secondary is faulty
   666              Replace_Secondary(root);
   667          }
   668      }
   669      return Evidences;
   670  }
   671  ```
   672  
   673  - Expected precondition
   674      - root and primary trace are a verification trace
   675  - Expected postcondition
   676      - solves the problem statement (if attack found, then evidence is reported)
   677  - Error condition
   678      - `ErrorTrustExpired`: fails if root expires (outside trusting
   679      period) [[LCV-INV-TP.1]][LCV-INV-TP1-link]
   680      - `ErrorNoPeers`: if no peers are left to replace secondaries, and
   681      no evidence was found before that happened
   682  
   683  ---
   684  
   685  ```go
   686  func CreateEvidenceForPeer(peer PeerID, root LightBlock, trace LightStore)
   687                            (Evidence, LightBlock, LightStore, result) {
   688  
   689      common := root;
   690  
   691      for i in 1 .. len(trace) {
   692          auxLS, result := VerifyToTarget(peer, common, trace[i].Header.Height)
   693    
   694          if result != ResultSuccess {
   695              // something went wrong; peer did not provide a verifiable block
   696              return (nil, nil, nil, FaultyPeer)
   697          }
   698          else {
   699              if auxLS.LatestVerified().Header != trace[i].Header {
   700                  // the header reported by the peer differs from the
   701                  // reference header in trace but both could be
   702                  // verified from common in one step.
   703                  // we can create evidence for submission to the secondary
   704                  ev := new InternalEvidence;
   705                  ev.Evidence.ConflictingBlock := trace[i];
   706                  // CommonHeight is used to indicate the type of attack
   707                  // if the CommonHeight != ConflictingBlock.Height this 
   708                  // is by definition a lunatic attack else it is an
   709                  // equivocation attack
   710                  ev.Evidence.CommonHeight := common.Height;
   711                  ev.Peer := peer
   712                  return (ev, common, auxLS, FoundEvidence)
   713              }
   714              else {
   715                  // the peer agrees with the trace, we move common forward.
   716                  // we could delete auxLS as it will be overwritten in
   717                  // the next iteration
   718                  common := trace[i]
   719              }
   720          }
   721      }
   722      return (nil, nil, nil, NoEvidence)
   723  }
   724  ```
   725  
   726  - Expected precondition
   727      - root and trace are a verification trace
   728  - Expected postcondition
   729      - finds evidence where trace and peer diverge
   730  - Error condition
   731      - `ErrorTrustExpired`: fails if root expires (outside trusting
   732         period) [[LCV-INV-TP.1]][LCV-INV-TP1-link]
   733      - If `VerifyToTarget` returns error but root is not expired then return
   734   `FaultyPeer`
   735  
   736  ---
   737  
   738  ## Correctness arguments
   739  
   740  #### On the existence of evidence
   741  
   742  **Proposition.** In the case of attack,
   743  evidence [[CMBC-LC-ATTACK-EVIDENCE.1]](#CMBC-LC-ATTACK-EVIDENCE1)
   744   exists.  
   745  *Proof.* First observe that
   746  
   747  - (A). (NOT E2(i)) implies E1(i+1)
   748  
   749  Now by contradiction assume there is no evidence. Thus
   750  
   751  - for all i, we have NOT E1(i) or NOT E2(i)
   752  - for i = 1 we have E1(1) and thus NOT E2(1)
   753    thus by induction on i, by (A) we have for all i that **E1(i)**
   754  - from attack we have E2(h-1), and as there is no evidence for
   755    i = h - 1 we get **NOT E1(h-1)**. Contradiction.
   756  QED.
   757  
   758  #### Argument for [[LCD-DIST-INV-ATTACK.1]](#LCD-DIST-INV-ATTACK1)
   759  
   760  Under the assumption that root and trace are a verification trace,
   761  when in `CreateEvidenceForPeer` the detector creates
   762  evidence, then the lightclient has seen two different headers (one via
   763  `trace` and one via `VerifyToTarget`) for the same height that can both
   764  be verified in one step.
   765  
   766  #### Argument for [[LCD-DIST-INV-STORE.1]](#LCD-DIST-INV-STORE1)
   767  
   768  We assume that there is at least one correct peer, and there is no
   769  fork. As a result, the correct peer has the correct sequence of
   770  blocks. Since the primary_trace is checked block-by-block also against
   771  each secondary, and at no point evidence was generated that means at
   772  no point there were conflicting blocks.
   773  
   774  #### Argument for [[LCD-DIST-LIVE.1]](#LCD-DIST-LIVE1)
   775  
   776  At the latest when [[LCV-INV-TP.1]][LCV-INV-TP1-link] is violated,
   777  `AttackDetector` terminates.
   778  
   779  #### Argument for [[LCD-DIST-TERM-NORMAL.1]](#LCD-DIST-TERM-NORMAL1)
   780  
   781  As there are finitely many peers, eventually the main loop
   782  terminates. As there is no attack no evidence can be generated.
   783  
   784  #### Argument for [[LCD-DIST-TERM-ATTACK.1]](#LCD-DIST-TERM-ATTACK1)
   785  
   786  Argument similar to  [[LCD-DIST-TERM-NORMAL.1]](#LCD-DIST-TERM-NORMAL1)
   787  
   788  #### Argument for [[LCD-DIST-SAFE-SECONDARY.1]](#LCD-DIST-SAFE-SECONDARY1)
   789  
   790  Secondaries are only replaced if they time-out or if they report bogus
   791  blocks. The former is ruled out by the timing assumption, the latter
   792  by correct peers only reporting blocks from the chain.
   793  
   794  #### Argument for [[LCD-DIST-SAFE-BOGUS.1]](#LCD-DIST-SAFE-BOGUS1)
   795  
   796  Once a bogus block is recognized as such the secondary is removed.
   797  
   798  # References
   799  
   800  > links to other specifications/ADRs this document refers to
   801  
   802  [[verification]] The specification of the light client verification.
   803  
   804  [[supervisor]] The specification of the light client supervisor.
   805  
   806  [verification]: https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md
   807  
   808  [supervisor]: https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/supervisor/supervisor_001_draft.md
   809  
   810  
   811  [CMBC-FM-2THIRDS-link]: https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#cmbc-fm-2thirds1
   812  
   813  [CMBC-SOUND-DISTR-POSS-COMMIT-link]: https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#cmbc-sound-distr-poss-commit1
   814  
   815  [LCV-SEQ-SAFE-link]:https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#lcv-seq-safe1
   816  
   817  [CMBC-VAL-CONTAINS-CORR-link]:
   818  https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#cmbc-val-contains-corr1
   819  
   820  [fetch]:
   821  https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#lcv-func-fetch1
   822  
   823  [LCV-INV-TP1-link]:
   824  https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#lcv-inv-tp1
   825  
   826  [LCV-LB-link]:
   827  https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#lcv-data-lightblock1
   828  
   829  [LCV-LS-link]:
   830  https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#lcv-data-lightstore2
   831  
   832  [LVC-HD-link]:
   833  https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#cmbc-header-fields2
   834  
   835  [repl]:
   836  https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/supervisor/supervisor_001_draft.md#lc-func-replace-secondary1
   837  
   838  [vtt]:
   839  https://github.com/aakash4dev/cometbft/blob/main/spec/light-client/verification/verification_002_draft.md#lcv-func-main2