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