github.com/Team-Kujira/tendermint@v0.34.24-indexer/spec/light-client/verification/verification_002_draft.md (about) 1 # Light Client Verification 2 3 The light client implements a read operation of a 4 [header][TMBC-HEADER-link] from the [blockchain][TMBC-SEQ-link], by 5 communicating with full nodes. As some full nodes may be faulty, this 6 functionality must be implemented in a fault-tolerant way. 7 8 In the Tendermint blockchain, the validator set may change with every 9 new block. The staking and unbonding mechanism induces a [security 10 model][TMBC-FM-2THIRDS-link]: starting at time *Time* of the 11 [header][TMBC-HEADER-link], 12 more than two-thirds of the next validators of a new block are correct 13 for the duration of *TrustedPeriod*. The fault-tolerant read 14 operation is designed for this security model. 15 16 The challenge addressed here is that the light client might have a 17 block of height *h1* and needs to read the block of height *h2* 18 greater than *h1*. Checking all headers of heights from *h1* to *h2* 19 might be too costly (e.g., in terms of energy for mobile devices). 20 This specification tries to reduce the number of intermediate blocks 21 that need to be checked, by exploiting the guarantees provided by the 22 [security model][TMBC-FM-2THIRDS-link]. 23 24 # Status 25 26 ## Previous Versions 27 28 - [[001_published]](./verification_001_published.md) 29 is thoroughly reviewed, and the protocol has been 30 formalized in TLA+ and model checked. 31 32 ## Issues that are addressed in this revision 33 34 As it is part of the larger light node, its data structures and 35 functions interact with the attack dectection functionality of the light 36 client. As a result of the work on 37 38 - [attack detection](https://github.com/tendermint/spec/pull/164) for light nodes 39 40 - attack detection for IBC and [relayer requirements](https://github.com/informalsystems/tendermint-rs/issues/497) 41 42 - light client 43 [supervisor](https://github.com/tendermint/spec/pull/159) (also in 44 [Rust proposal](https://github.com/informalsystems/tendermint-rs/pull/509)) 45 46 adaptations to the semantics and functions exposed by the LightStore 47 needed to be made. In contrast to [version 48 001](./verification_001_published.md) we specify the following: 49 50 - `VerifyToTarget` and `Backwards` are called with a single lightblock 51 as root of trust in contrast to passing the complete lightstore. 52 53 - During verification, we record for each lightblock which other 54 lightblock can be used to verify it in one step. This is needed to 55 generate verification traces that are needed for IBC. 56 57 # Outline 58 59 - [Part I](#part-i---tendermint-blockchain): Introduction of 60 relevant terms of the Tendermint 61 blockchain. 62 63 - [Part II](#part-ii---sequential-definition-of-the-verification-problem): Introduction 64 of the problem addressed by the Lightclient Verification protocol. 65 - [Verification Informal Problem 66 statement](#Verification-Informal-Problem-statement): For the general 67 audience, that is, engineers who want to get an overview over what 68 the component is doing from a bird's eye view. 69 - [Sequential Problem statement](#Sequential-Problem-statement): 70 Provides a mathematical definition of the problem statement in 71 its sequential form, that is, ignoring the distributed aspect of 72 the implementation of the blockchain. 73 74 - [Part III](#part-iii---light-client-as-distributed-system): Distributed 75 aspects of the light client, system assumptions and temporal 76 logic specifications. 77 78 - [Incentives](#incentives): how faulty full nodes may benefit from 79 misbehaving and how correct full nodes benefit from cooperating. 80 81 - [Computational Model](#Computational-Model): 82 timing and correctness assumptions. 83 84 - [Distributed Problem Statement](#Distributed-Problem-Statement): 85 temporal properties that formalize safety and liveness 86 properties in the distributed setting. 87 88 - [Part IV](#part-iv---light-client-verification-protocol): 89 Specification of the protocols. 90 91 - [Definitions](#Definitions): Describes inputs, outputs, 92 variables used by the protocol, auxiliary functions 93 94 - [Core Verification](#core-verification): gives an outline of the solution, 95 and details of the functions used (with preconditions, 96 postconditions, error conditions). 97 98 - [Liveness Scenarios](#liveness-scenarios): when the light 99 client makes progress depends heavily on the changes in the 100 validator sets of the blockchain. We discuss some typical scenarios. 101 102 - [Part V](#part-v---supporting-the-ibc-relayer): The above parts 103 focus on a common case where the last verified block has height *h1* 104 and the 105 requested height *h2* satisfies *h2 > h1*. For IBC, there are 106 scenarios where this might not be the case. In this part, we provide 107 some preliminaries for supporting this. As not all details of the 108 IBC requirements are clear by now, we do not provide a complete 109 specification at this point. We mark with "Open Question" points 110 that need to be addressed in order to finalize this specification. 111 It should be noted that the technically 112 most challenging case is the one specified in Part IV. 113 114 In this document we quite extensively use tags in order to be able to 115 reference assumptions, invariants, etc. in future communication. In 116 these tags we frequently use the following short forms: 117 118 - TMBC: Tendermint blockchain 119 - SEQ: for sequential specifications 120 - LCV: Lightclient Verification 121 - LIVE: liveness 122 - SAFE: safety 123 - FUNC: function 124 - INV: invariant 125 - A: assumption 126 127 # Part I - Tendermint Blockchain 128 129 ## Header Fields necessary for the Light Client 130 131 #### **[TMBC-HEADER.1]** 132 133 A set of blockchain transactions is stored in a data structure called 134 *block*, which contains a field called *header*. (The data structure 135 *block* is defined [here][block]). As the header contains hashes to 136 the relevant fields of the block, for the purpose of this 137 specification, we will assume that the blockchain is a list of 138 headers, rather than a list of blocks. 139 140 #### **[TMBC-HASH-UNIQUENESS.1]** 141 142 We assume that every hash in the header identifies the data it hashes. 143 Therefore, in this specification, we do not distinguish between hashes and the 144 data they represent. 145 146 #### **[TMBC-HEADER-FIELDS.2]** 147 148 A header contains the following fields: 149 150 - `Height`: non-negative integer 151 - `Time`: time (non-negative integer) 152 - `LastBlockID`: Hashvalue 153 - `LastCommit` DomainCommit 154 - `Validators`: DomainVal 155 - `NextValidators`: DomainVal 156 - `Data`: DomainTX 157 - `AppState`: DomainApp 158 - `LastResults`: DomainRes 159 160 #### **[TMBC-SEQ.1]** 161 162 The Tendermint blockchain is a list *chain* of headers. 163 164 #### **[TMBC-VALIDATOR-PAIR.1]** 165 166 Given a full node, a 167 *validator pair* is a pair *(peerID, voting_power)*, where 168 169 - *peerID* is the PeerID (public key) of a full node, 170 - *voting_power* is an integer (representing the full node's 171 voting power in a certain consensus instance). 172 173 > In the Golang implementation the data type for *validator 174 pair* is called `Validator` 175 176 #### **[TMBC-VALIDATOR-SET.1]** 177 178 A *validator set* is a set of validator pairs. For a validator set 179 *vs*, we write *TotalVotingPower(vs)* for the sum of the voting powers 180 of its validator pairs. 181 182 #### **[TMBC-VOTE.1]** 183 184 A *vote* contains a `prevote` or `precommit` message sent and signed by 185 a validator node during the execution of [consensus][arXiv]. Each 186 message contains the following fields 187 188 - `Type`: prevote or precommit 189 - `Height`: positive integer 190 - `Round` a positive integer 191 - `BlockID` a Hashvalue of a block (not necessarily a block of the chain) 192 193 #### **[TMBC-COMMIT.1]** 194 195 A commit is a set of `precommit` message. 196 197 ## Tendermint Failure Model 198 199 #### **[TMBC-AUTH-BYZ.1]** 200 201 We assume the authenticated Byzantine fault model in which no node (faulty or 202 correct) may break digital signatures, but otherwise, no additional 203 assumption is made about the internal behavior of faulty 204 nodes. That is, faulty nodes are only limited in that they cannot forge 205 messages. 206 207 #### **[TMBC-TIME-PARAMS.1]** 208 209 A Tendermint blockchain has the following configuration parameters: 210 211 - *unbondingPeriod*: a time duration. 212 - *trustingPeriod*: a time duration smaller than *unbondingPeriod*. 213 214 #### **[TMBC-CORRECT.1]** 215 216 We define a predicate *correctUntil(n, t)*, where *n* is a node and *t* is a 217 time point. 218 The predicate *correctUntil(n, t)* is true if and only if the node *n* 219 follows all the protocols (at least) until time *t*. 220 221 #### **[TMBC-FM-2THIRDS.1]** 222 223 If a block *h* is in the chain, 224 then there exists a subset *CorrV* 225 of *h.NextValidators*, such that: 226 227 - *TotalVotingPower(CorrV) > 2/3 228 TotalVotingPower(h.NextValidators)*; cf. [TMBC-VALIDATOR-SET.1] 229 - For every validator pair *(n,p)* in *CorrV*, it holds *correctUntil(n, 230 h.Time + trustingPeriod)*; cf. [TMBC-CORRECT.1] 231 232 > The definition of correct 233 > [**[TMBC-CORRECT.1]**][TMBC-CORRECT-link] refers to realtime, while it 234 > is used here with *Time* and *trustingPeriod*, which are "hardware 235 > times". We do not make a distinction here. 236 237 #### **[TMBC-CORR-FULL.1]** 238 239 Every correct full node locally stores a prefix of the 240 current list of headers from [**[TMBC-SEQ.1]**][TMBC-SEQ-link]. 241 242 ## What the Light Client Checks 243 244 > From [TMBC-FM-2THIRDS.1] we directly derive the following observation: 245 246 #### **[TMBC-VAL-CONTAINS-CORR.1]** 247 248 Given a (trusted) block *tb* of the blockchain, a given set of full nodes 249 *N* contains a correct node at a real-time *t*, if 250 251 - *t - trustingPeriod < tb.Time < t* 252 - the voting power in tb.NextValidators of nodes in *N* is more 253 than 1/3 of *TotalVotingPower(tb.NextValidators)* 254 255 > The following describes how a commit for a given block *b* must look 256 > like. 257 258 #### **[TMBC-SOUND-DISTR-POSS-COMMIT.1]** 259 260 For a block *b*, each element *pc* of *PossibleCommit(b)* satisfies: 261 262 - *pc* contains only votes (cf. [TMBC-VOTE.1]) 263 by validators from *b.Validators* 264 - the sum of the voting powers in *pc* is greater than 2/3 265 *TotalVotingPower(b.Validators)* 266 - and there is an *r* such that each vote *v* in *pc* satisfies 267 - v.Type = precommit 268 - v.Height = b.Height 269 - v.Round = r 270 - v.blockID = hash(b) 271 272 > The following property comes from the validity of the [consensus][arXiv]: A 273 > correct validator node only sends `prevote` or `precommit`, if 274 > `BlockID` of the new (to-be-decided) block is equal to the hash of 275 > the last block. 276 277 #### **[TMBC-VAL-COMMIT.1]** 278 279 If for a block *b*, a commit *c* 280 281 - contains at least one validator pair *(v,p)* such that *v* is a 282 **correct** validator node, and 283 - is contained in *PossibleCommit(b)* 284 285 then the block *b* is on the blockchain. 286 287 ## Context of this document 288 289 In this document we specify the light client verification component, 290 called *Core Verification*. The *Core Verification* communicates with 291 a full node. As full nodes may be faulty, it cannot trust the 292 received information, but the light client has to check whether the 293 header it receives coincides with the one generated by Tendermint 294 consensus. 295 296 The two 297 properties [[TMBC-VAL-CONTAINS-CORR.1]][TMBC-VAL-CONTAINS-CORR-link] and 298 [[TMBC-VAL-COMMIT]][TMBC-VAL-COMMIT-link] formalize the checks done 299 by this specification: 300 Given a trusted block *tb* and an untrusted block *ub* with a commit *cub*, 301 one has to check that *cub* is in *PossibleCommit(ub)*, and that *cub* 302 contains a correct node using *tb*. 303 304 # Part II - Sequential Definition of the Verification Problem 305 306 ## Verification Informal Problem statement 307 308 Given a height *targetHeight* as an input, the *Verifier* eventually 309 stores a header *h* of height *targetHeight* locally. This header *h* 310 is generated by the Tendermint [blockchain][block]. In 311 particular, a header that was not generated by the blockchain should 312 never be stored. 313 314 ## Sequential Problem statement 315 316 #### **[LCV-SEQ-LIVE.1]** 317 318 The *Verifier* gets as input a height *targetHeight*, and eventually stores the 319 header of height *targetHeight* of the blockchain. 320 321 #### **[LCV-SEQ-SAFE.1]** 322 323 The *Verifier* never stores a header which is not in the blockchain. 324 325 # Part III - Light Client as Distributed System 326 327 ## Incentives 328 329 Faulty full nodes may benefit from lying to the light client, by making the 330 light client accept a block that deviates (e.g., contains additional 331 transactions) from the one generated by Tendermint consensus. 332 Users using the light client might be harmed by accepting a forged header. 333 334 The [attack detector][attack-detector] of the light client may help the 335 correct full nodes to understand whether their header is a good one. 336 Hence, in combination with the light client detector, the correct full 337 nodes have the incentive to respond. We can thus base liveness 338 arguments on the assumption that correct full nodes reliably talk to 339 the light client. 340 341 ## Computational Model 342 343 #### **[LCV-A-PEER.1]** 344 345 The verifier communicates with a full node called *primary*. No assumption is made about the full node (it may be correct or faulty). 346 347 #### **[LCV-A-COMM.1]** 348 349 Communication between the light client and a correct full node is 350 reliable and bounded in time. Reliable communication means that 351 messages are not lost, not duplicated, and eventually delivered. There 352 is a (known) end-to-end delay *Delta*, such that if a message is sent 353 at time *t* then it is received and processes by time *t + Delta*. 354 This implies that we need a timeout of at least *2 Delta* for remote 355 procedure calls to ensure that the response of a correct peer arrives 356 before the timeout expires. 357 358 #### **[LCV-A-TFM.1]** 359 360 The Tendermint blockchain satisfies the Tendermint failure model [**[TMBC-FM-2THIRDS.1]**][TMBC-FM-2THIRDS-link]. 361 362 #### **[LCV-A-VAL.1]** 363 364 The system satisfies [**[TMBC-AUTH-BYZ.1]**][TMBC-Auth-Byz-link] and 365 [**[TMBC-FM-2THIRDS.1]**][TMBC-FM-2THIRDS-link]. Thus, there is a 366 blockchain that satisfies the soundness requirements (that is, the 367 validation rules in [[block]]). 368 369 ## Distributed Problem Statement 370 371 ### Two Kinds of Termination 372 373 We do not assume that *primary* is correct. Under this assumption no 374 protocol can guarantee the combination of the sequential 375 properties. Thus, in the (unreliable) distributed setting, we consider 376 two kinds of termination (successful and failure) and we will specify 377 below under what (favorable) conditions *Core Verification* ensures to 378 terminate successfully, and satisfy the requirements of the sequential 379 problem statement: 380 381 #### **[LCV-DIST-TERM.1]** 382 383 *Core Verification* either *terminates 384 successfully* or it *terminates with failure*. 385 386 ### Design choices 387 388 #### **[LCV-DIST-STORE.2]** 389 390 *Core Verification* returns a data structure called *LightStore* that 391 contains light blocks (that contain a header). 392 393 #### **[LCV-DIST-INIT.2]** 394 395 *Core Verification* is called with 396 397 - *primary*: the PeerID of a full node (with verification communicates) 398 - *root*: a light block (the root of trust) 399 - *targetHeight*: a height (the height of a header that should be obtained) 400 401 ### Temporal Properties 402 403 #### **[LCV-DIST-SAFE.2]** 404 405 It is always the case that every header in *LightStore* was 406 generated by an instance of Tendermint consensus. 407 408 #### **[LCV-DIST-LIVE.2]** 409 410 If a new instance of *Core Verification* is called with a 411 height *targetHeight* greater than root.Header.Height it must 412 must eventually terminate. 413 414 - If 415 - the *primary* is correct (and locally has the block of 416 *targetHeight*), and 417 - the age of root is always less than the trusting period, 418 then *Core Verification* adds a verified header *hd* with height 419 *targetHeight* to *LightStore* and it **terminates successfully** 420 421 > These definitions imply that if the primary is faulty, a header may or 422 > may not be added to *LightStore*. In any case, 423 > [**[LCV-DIST-SAFE.2]**](#lcv-dist-safe2) must hold. 424 > The invariant [**[LCV-DIST-SAFE.2]**](#lcv-dist-safe2) and the liveness 425 > requirement [**[LCV-DIST-LIVE.2]**](#lcv-dist-life) 426 > allow that verified headers are added to *LightStore* whose 427 > height was not passed 428 > to the verifier (e.g., intermediate headers used in bisection; see below). 429 > Note that for liveness, initially having a *root* within 430 > the *trustinPeriod* is not sufficient. However, as this 431 > specification will leave some freedom with respect to the strategy 432 > in which order to download intermediate headers, we do not give a 433 > more precise liveness specification here. After giving the 434 > specification of the protocol, we will discuss some liveness 435 > scenarios [below](#liveness-scenarios). 436 437 ### Solving the sequential specification 438 439 This specification provides a partial solution to the sequential specification. 440 The *Verifier* solves the invariant of the sequential part 441 442 [**[LCV-DIST-SAFE.2]**](#lcv-dist-safe2) => [**[LCV-SEQ-SAFE.1]**](#lcv-seq-safe1) 443 444 In the case the primary is correct, and *root* is a recent header in *LightStore*, the verifier satisfies the liveness requirements. 445 446 ⋀ *primary is correct* 447 ⋀ *root.header.Time* > *now* - *trustingPeriod* 448 ⋀ [**[LCV-A-Comm.1]**](#lcv-a-comm) ⋀ ( 449 ( [**[TMBC-CorrFull.1]**][TMBC-CorrFull-link] ⋀ 450 [**[LCV-DIST-LIVE.2]**](#lcv-dist-live2) ) 451 ⟹ [**[LCV-SEQ-LIVE.1]**](#lcv-seq-live1) 452 ) 453 454 # Part IV - Light Client Verification Protocol 455 456 We provide a specification for Light Client Verification. The local 457 code for verification is presented by a sequential function 458 `VerifyToTarget` to highlight the control flow of this functionality. 459 We note that if a different concurrency model is considered for 460 an implementation, the sequential flow of the function may be 461 implemented with mutexes, etc. However, the light client verification 462 is partitioned into three blocks that can be implemented and tested 463 independently: 464 465 - `FetchLightBlock` is called to download a light block (header) of a 466 given height from a peer. 467 - `ValidAndVerified` is a local code that checks the header. 468 - `Schedule` decides which height to try to verify next. We keep this 469 underspecified as different implementations (currently in Goland and 470 Rust) may implement different optimizations here. We just provide 471 necessary conditions on how the height may evolve. 472 473 <!-- > `ValidAndVerified` is the function that is sometimes called "Light --> 474 <!-- > Client" in the IBC context. --> 475 476 ## Definitions 477 478 ### Data Types 479 480 The core data structure of the protocol is the LightBlock. 481 482 #### **[LCV-DATA-LIGHTBLOCK.1]** 483 484 ```go 485 type LightBlock struct { 486 Header Header 487 Commit Commit 488 Validators ValidatorSet 489 } 490 ``` 491 492 #### **[LCV-DATA-LIGHTSTORE.2]** 493 494 LightBlocks are stored in a structure which stores all LightBlock from 495 initialization or received from peers. 496 497 ```go 498 type LightStore struct { 499 ... 500 } 501 502 ``` 503 504 #### **[LCV-DATA-LS-ROOT.2]** 505 506 For each lightblock in a lightstore we record in a field `verification-root` of 507 type Height. 508 509 > `verification-root` records the height of a lightblock that can be used to verify 510 > the lightblock in one step 511 512 #### **[LCV-INV-LS-ROOT.2]** 513 514 At all times, if a lightblock *b* in a lightstore has *b.verification-root = h*, 515 then 516 517 - the lightstore contains a lightblock with height *h*, or 518 - *b* has the minimal height of all lightblocks in lightstore, then 519 b.verification-root should be nil. 520 521 The LightStore exposes the following functions to query stored LightBlocks. 522 523 #### **[LCV-DATA-LS-STATE.1]** 524 525 Each LightBlock is in one of the following states: 526 527 ```go 528 type VerifiedState int 529 530 const ( 531 StateUnverified = iota + 1 532 StateVerified 533 StateFailed 534 StateTrusted 535 ) 536 ``` 537 538 #### **[LCV-FUNC-GET.1]** 539 540 ```go 541 func (ls LightStore) Get(height Height) (LightBlock, bool) 542 ``` 543 544 - Expected postcondition 545 - returns a LightBlock at a given height or false in the second argument if 546 the LightStore does not contain the specified LightBlock. 547 548 #### **[LCV-FUNC-LATEST.1]** 549 550 ```go 551 func (ls LightStore) Latest() LightBlock 552 ``` 553 554 - Expected postcondition 555 - returns the highest light block 556 557 #### **[LCV-FUNC-ADD.1]** 558 559 ```go 560 func (ls LightStore) Add(newBlock) 561 ``` 562 563 - Expected precondition 564 - the lightstore is empty 565 - Expected postcondition 566 - adds newBlock into light store 567 568 #### **[LCV-FUNC-STORE.1]** 569 570 ```go 571 func (ls LightStore) store_chain(newLS LightStore) 572 ``` 573 574 - Expected postcondition 575 - adds `newLS` to the lightStore. 576 577 #### **[LCV-FUNC-LATEST-VERIF.2]** 578 579 ```go 580 func (ls LightStore) LatestVerified() LightBlock 581 ``` 582 583 - Expected postcondition 584 - returns the highest light block whose state is `StateVerified` 585 586 #### **[LCV-FUNC-FILTER.1]** 587 588 ```go 589 func (ls LightStore) FilterVerified() LightStore 590 ``` 591 592 - Expected postcondition 593 - returns all the lightblocks of the lightstore with state `StateVerified` 594 595 #### **[LCV-FUNC-UPDATE.2]** 596 597 ```go 598 func (ls LightStore) Update(lightBlock LightBlock, verfiedState 599 VerifiedState, root-height Height) 600 ``` 601 602 - Expected postcondition 603 - the lightblock is part of the lightstore 604 - The state of the LightBlock is set to *verifiedState*. 605 - The verification-root of the LightBlock is set to *root-height* 606 607 ```go 608 func (ls LightStore) TraceTo(lightBlock LightBlock) (LightBlock, LightStore) 609 ``` 610 611 - Expected postcondition 612 - returns a **trusted** lightblock `root` from the lightstore with a height 613 less than `lightBlock` 614 - returns a lightstore that contains lightblocks that constitute a 615 [verification trace](TODOlinkToDetectorSpecOnceThere) from 616 `root` to `lightBlock` (including `lightBlock`) 617 618 ### Inputs 619 620 - *root*: A light block that is trusted 621 - *primary*: peerID 622 - *targetHeight*: the height of the needed header 623 624 ### Configuration Parameters 625 626 - *trustThreshold*: a float. Can be used if correctness should not be based on more voting power and 1/3. 627 - *trustingPeriod*: a time duration [**[TMBC-TIME_PARAMS.1]**][TMBC-TIME_PARAMS-link]. 628 - *clockDrift*: a time duration. Correction parameter dealing with only approximately synchronized clocks. 629 630 ### Variables 631 632 - *nextHeight*: initially *targetHeight* 633 > *nextHeight* should be thought of the "height of the next header we need 634 > to download and verify" 635 636 ### Assumptions 637 638 #### **[LCV-A-INIT.2]** 639 640 - *root* is from the blockchain 641 642 - *targetHeight > root.Header.Height* 643 644 ### Invariants 645 646 #### **[LCV-INV-TP.1]** 647 648 It is always the case that *LightStore.LatestTrusted.Header.Time > now - trustingPeriod*. 649 650 > If the invariant is violated, the light client does not have a 651 > header it can trust. A trusted header must be obtained externally, 652 > its trust can only be based on social consensus. 653 > We use the convention that root is assumed to be verified. 654 655 ### Used Remote Functions 656 657 We use the functions `commit` and `validators` that are provided 658 by the [RPC client for Tendermint][RPC]. 659 660 ```go 661 func Commit(height int64) (SignedHeader, error) 662 ``` 663 664 - Implementation remark 665 - RPC to full node *n* 666 - JSON sent: 667 668 ```javascript 669 // POST /commit 670 { 671 "jsonrpc": "2.0", 672 "id": "ccc84631-dfdb-4adc-b88c-5291ea3c2cfb", // UUID v4, unique per request 673 "method": "commit", 674 "params": { 675 "height": 1234 676 } 677 } 678 ``` 679 680 - Expected precondition 681 - header of `height` exists on blockchain 682 - Expected postcondition 683 - if *n* is correct: Returns the signed header of height `height` 684 from the blockchain if communication is timely (no timeout) 685 - if *n* is faulty: Returns a signed header with arbitrary content 686 - Error condition 687 - if *n* is correct: precondition violated or timeout 688 - if *n* is faulty: arbitrary error 689 690 ----; 691 692 ```go 693 func Validators(height int64) (ValidatorSet, error) 694 ``` 695 696 - Implementation remark 697 - RPC to full node *n* 698 - JSON sent: 699 700 ```javascript 701 // POST /validators 702 { 703 "jsonrpc": "2.0", 704 "id": "ccc84631-dfdb-4adc-b88c-5291ea3c2cfb", // UUID v4, unique per request 705 "method": "validators", 706 "params": { 707 "height": 1234 708 } 709 } 710 ``` 711 712 - Expected precondition 713 - header of `height` exists on blockchain 714 - Expected postcondition 715 - if *n* is correct: Returns the validator set of height `height` 716 from the blockchain if communication is timely (no timeout) 717 - if *n* is faulty: Returns arbitrary validator set 718 - Error condition 719 - if *n* is correct: precondition violated or timeout 720 - if *n* is faulty: arbitrary error 721 722 ----; 723 724 ### Communicating Function 725 726 #### **[LCV-FUNC-FETCH.1]** 727 728 ```go 729 func FetchLightBlock(peer PeerID, height Height) LightBlock 730 ``` 731 732 - Implementation remark 733 - RPC to peer at *PeerID* 734 - calls `Commit` for *height* and `Validators` for *height* and *height+1* 735 - Expected precondition 736 - `height` is less than or equal to height of the peer **[LCV-IO-PRE-HEIGHT.1]** 737 - Expected postcondition: 738 - if *node* is correct: 739 - Returns the LightBlock *lb* of height `height` 740 that is consistent with the blockchain 741 - *lb.provider = peer* **[LCV-IO-POST-PROVIDER.1]** 742 - *lb.Header* is a header consistent with the blockchain 743 - *lb.Validators* is the validator set of the blockchain at height *nextHeight* 744 - *lb.NextValidators* is the validator set of the blockchain at height *nextHeight + 1* 745 - if *node* is faulty: Returns a LightBlock with arbitrary content 746 [**[TMBC-AUTH-BYZ.1]**][TMBC-Auth-Byz-link] 747 - Error condition 748 - if *n* is correct: precondition violated 749 - if *n* is faulty: arbitrary error 750 - if *lb.provider != peer* 751 - times out after 2 Delta (by assumption *n* is faulty) 752 753 ----; 754 755 ## Core Verification 756 757 ### Outline 758 759 The `VerifyToTarget` is the main function and uses the following functions. 760 761 - `FetchLightBlock` is called to download the next light block. It is 762 the only function that communicates with other nodes 763 - `ValidAndVerified` checks whether header is valid and checks if a 764 new lightBlock should be trusted 765 based on a previously verified lightBlock. 766 - `Schedule` decides which height to try to verify next 767 768 In the following description of `VerifyToTarget` we do not deal with error 769 handling. If any of the above function returns an error, VerifyToTarget just 770 passes the error on. 771 772 #### **[LCV-FUNC-MAIN.2]** 773 774 ```go 775 func VerifyToTarget(primary PeerID, root LightBlock, 776 targetHeight Height) (LightStore, Result) { 777 778 lightStore = new LightStore; 779 lightStore.Update(root, StateVerified, root.verifiedBy); 780 nextHeight := targetHeight; 781 782 for lightStore.LatestVerified.height < targetHeight { 783 784 // Get next LightBlock for verification 785 current, found := lightStore.Get(nextHeight) 786 if !found { 787 current = FetchLightBlock(primary, nextHeight) 788 lightStore.Update(current, StateUnverified, nil) 789 } 790 791 // Verify 792 verdict = ValidAndVerified(lightStore.LatestVerified, current) 793 794 // Decide whether/how to continue 795 if verdict == SUCCESS { 796 lightStore.Update(current, StateVerified, lightStore.LatestVerified.Height) 797 } 798 else if verdict == NOT_ENOUGH_TRUST { 799 // do nothing 800 // the light block current passed validation, but the validator 801 // set is too different to verify it. We keep the state of 802 // current at StateUnverified. For a later iteration, Schedule 803 // might decide to try verification of that light block again. 804 } 805 else { 806 // verdict is some error code 807 lightStore.Update(current, StateFailed, nil) 808 return (nil, ResultFailure) 809 } 810 nextHeight = Schedule(lightStore, nextHeight, targetHeight) 811 } 812 return (lightStore.FilterVerified, ResultSuccess) 813 } 814 ``` 815 816 - Expected precondition 817 - *root* is within the *trustingPeriod* **[LCV-PRE-TP.1]** 818 - *targetHeight* is greater than the height of *root* 819 - Expected postcondition: 820 - returns *lightStore* that contains a LightBlock that corresponds to a block 821 of the blockchain of height *targetHeight* 822 (that is, the LightBlock has been added to *lightStore*) **[LCV-POST-LS.1]** 823 - Error conditions 824 - if the precondition is violated 825 - if `ValidAndVerified` or `FetchLightBlock` report an error 826 - if [**[LCV-INV-TP.1]**](#LCV-INV-TP.1) is violated 827 828 ### Details of the Functions 829 830 #### **[LCV-FUNC-VALID.2]** 831 832 ```go 833 func ValidAndVerified(trusted LightBlock, untrusted LightBlock) Result 834 ``` 835 836 - Expected precondition: 837 - *untrusted* is valid, that is, satisfies the soundness [checks][block] 838 - *untrusted* is **well-formed**, that is, 839 - *untrusted.Header.Time < now + clockDrift* 840 - *untrusted.Validators = hash(untrusted.Header.Validators)* 841 - *untrusted.NextValidators = hash(untrusted.Header.NextValidators)* 842 - *trusted.Header.Time > now - trustingPeriod* 843 - the `Height` and `Time` of `trusted` are smaller than the Height and 844 `Time` of `untrusted`, respectively 845 - the *untrusted.Header* is well-formed (passes the tests from 846 [[block]]), and in particular 847 - if the untrusted header `unstrusted.Header` is the immediate 848 successor of `trusted.Header`, then it holds that 849 - *trusted.Header.NextValidators = 850 untrusted.Header.Validators*, and 851 moreover, 852 - *untrusted.Header.Commit* 853 - contains signatures by more than two-thirds of the validators 854 - contains no signature from nodes that are not in *trusted.Header.NextValidators* 855 - Expected postcondition: 856 - Returns `SUCCESS`: 857 - if *untrusted* is the immediate successor of *trusted*, or otherwise, 858 - if the signatures of a set of validators that have more than 859 *max(1/3,trustThreshold)* of voting power in 860 *trusted.Nextvalidators* is contained in 861 *untrusted.Commit* (that is, header passes the tests 862 [**[TMBC-VAL-CONTAINS-CORR.1]**][TMBC-VAL-CONTAINS-CORR-link] 863 and [**[TMBC-VAL-COMMIT.1]**][TMBC-VAL-COMMIT-link]) 864 - Returns `NOT_ENOUGH_TRUST` if: 865 - *untrusted* is *not* the immediate successor of 866 *trusted* 867 and the *max(1/3,trustThreshold)* threshold is not reached 868 (that is, if 869 [**[TMBC-VAL-CONTAINS-CORR.1]**][TMBC-VAL-CONTAINS-CORR-link] 870 fails and header is does not violate the soundness 871 checks [[block]]). 872 - Error condition: 873 - if precondition violated 874 875 ----; 876 877 #### **[LCV-FUNC-SCHEDULE.1]** 878 879 ```go 880 func Schedule(lightStore, nextHeight, targetHeight) Height 881 ``` 882 883 - Implementation remark: If picks the next height to be verified. 884 We keep the precise choice of the next header under-specified. It is 885 subject to performance optimizations that do not influence the correctness 886 - Expected postcondition: **[LCV-SCHEDULE-POST.1]** 887 Return *H* s.t. 888 1. if *lightStore.LatestVerified.Height = nextHeight* and 889 *lightStore.LatestVerified < targetHeight* then 890 *nextHeight < H <= targetHeight* 891 2. if *lightStore.LatestVerified.Height < nextHeight* and 892 *lightStore.LatestVerified.Height < targetHeight* then 893 *lightStore.LatestVerified.Height < H < nextHeight* 894 3. if *lightStore.LatestVerified.Height = targetHeight* then 895 *H = targetHeight* 896 897 > Case i. captures the case where the light block at height *nextHeight* 898 > has been verified, and we can choose a height closer to the *targetHeight*. 899 > As we get the *lightStore* as parameter, the choice of the next height can 900 > depend on the *lightStore*, e.g., we can pick a height for which we have 901 > already downloaded a light block. 902 > In Case ii. the header of *nextHeight* could not be verified, and we need to pick a smaller height. 903 > In Case iii. is a special case when we have verified the *targetHeight*. 904 905 ### Solving the distributed specification 906 907 Analogous to [[001_published]](./verification_001_published.md#solving-the-distributed-specification) 908 909 ## Liveness Scenarios 910 911 Analogous to [[001_published]](./verification_001_published.md#liveness-scenarios) 912 913 # Part V - Supporting the IBC Relayer 914 915 The above specification focuses on the most common case, which also 916 constitutes the most challenging task: using the Tendermint [security 917 model][TMBC-FM-2THIRDS-link] to verify light blocks without 918 downloading all intermediate blocks. To focus on this challenge, above 919 we have restricted ourselves to the case where *targetHeight* is 920 greater than the height of any trusted header. This simplified 921 presentation of the algorithm as initially 922 `lightStore.LatestVerified()` is less than *targetHeight*, and in the 923 process of verification `lightStore.LatestVerified()` increases until 924 *targetHeight* is reached. 925 926 For [IBC][ibc-rs] there are two additional challenges: 927 928 1. it might be that some "older" header is needed, that is, 929 *targetHeight < lightStore.LatestVerified()*. The 930 [supervisor](../supervisor/supervisor.md) checks whether it is in this 931 case by calling `LatestPrevious` and `MinVerified` and if so it calls 932 `Backwards`. All these functions are specified below. 933 934 2. In order to submit proof of a light client attack, a relayer may 935 need to submit a verification trace. This it is important to 936 compute such a trace efficiently. That it can be done is based on 937 the invariant [[LCV-INV-LS-ROOT.2]](#LCV-INV-LS-ROOT2) that needs 938 to be maintained by the light client. In particular 939 `VerifyToTarget` and `Backwards` need to take care of setting 940 `verification-root`. 941 942 #### **[LCV-FUNC-LATEST-PREV.2]** 943 944 ```go 945 func (ls LightStore) LatestPrevious(height Height) (LightBlock, bool) 946 ``` 947 948 - Expected postcondition 949 - returns a light block *lb* that satisfies: 950 - *lb* is in lightStore 951 - *lb* is in StateTrusted 952 - *lb* is not expired 953 - *lb.Header.Height < height* 954 - for all *b* in lightStore s.t. *b* is trusted and not expired it 955 holds *lb.Header.Height >= b.Header.Height* 956 - *false* in the second argument if 957 the LightStore does not contain such an *lb*. 958 959 ----; 960 961 #### **[LCV-FUNC-LOWEST.2]** 962 963 ```go 964 func (ls LightStore) Lowest() (LightBlock) 965 ``` 966 967 - Expected postcondition 968 - returns the lowest trusted light block within trusting period 969 970 ----; 971 972 #### **[LCV-FUNC-MIN.2]** 973 974 ```go 975 func (ls LightStore) MinVerified() (LightBlock, bool) 976 ``` 977 978 - Expected postcondition 979 - returns a light block *lb* that satisfies: 980 - *lb* is in lightStore 981 - *lb.Header.Height* is minimal in the lightStore 982 - *false* in the second argument if 983 the LightStore does not contain such an *lb*. 984 985 If a height that is smaller than the smallest height in the lightstore 986 is required, we check the hashes backwards. This is done with the 987 following function: 988 989 #### **[LCV-FUNC-BACKWARDS.2]** 990 991 ```go 992 func Backwards (primary PeerID, root LightBlock, targetHeight Height) 993 (LightStore, Result) { 994 995 lb := root; 996 lightStore := new LightStore; 997 lightStore.Update(lb, StateTrusted, lb.verifiedBy) 998 999 latest := lb.Header 1000 for i := lb.Header.height - 1; i >= targetHeight; i-- { 1001 // here we download height-by-height. We might first download all 1002 // headers down to targetHeight and then check them. 1003 current := FetchLightBlock(primary,i) 1004 if (hash(current) != latest.Header.LastBlockId) { 1005 return (nil, ResultFailure) 1006 } 1007 else { 1008 // latest and current are linked together by LastBlockId 1009 // therefore it is not relevant which we verified first 1010 // for consistency, we store latest was veried using 1011 // current so that the verifiedBy is always pointing down 1012 // the chain 1013 lightStore.Update(current, StateTrusted, nil) 1014 lightStore.Update(latest, StateTrusted, current.Header.Height) 1015 } 1016 latest = current 1017 } 1018 return (lightStore, ResultSuccess) 1019 } 1020 ``` 1021 1022 # References 1023 1024 [[block]] Specification of the block data structure. 1025 1026 [[RPC]] RPC client for Tendermint 1027 1028 [[attack-detector]] The specification of the light client attack detector. 1029 1030 [[fullnode]] Specification of the full node API 1031 1032 [[ibc-rs]] Rust implementation of IBC modules and relayer. 1033 1034 [[lightclient]] The light client ADR [77d2651 on Dec 27, 2019]. 1035 1036 [RPC]: https://docs.tendermint.com/v0.34/rpc/ 1037 1038 [block]: https://github.com/tendermint/spec/blob/d46cd7f573a2c6a2399fcab2cde981330aa63f37/spec/core/data_structures.md 1039 1040 [TMBC-HEADER-link]: #tmbc-header1 1041 [TMBC-SEQ-link]: #tmbc-seq1 1042 [TMBC-CorrFull-link]: #tmbc-corr-full1 1043 [TMBC-Auth-Byz-link]: #tmbc-auth-byz1 1044 [TMBC-TIME_PARAMS-link]: #tmbc-time-params1 1045 [TMBC-FM-2THIRDS-link]: #tmbc-fm-2thirds1 1046 [TMBC-VAL-CONTAINS-CORR-link]: #tmbc-val-contains-corr1 1047 [TMBC-VAL-COMMIT-link]: #tmbc-val-commit1 1048 [TMBC-SOUND-DISTR-POSS-COMMIT-link]: #tmbc-sound-distr-poss-commit1 1049 1050 [lightclient]: https://github.com/interchainio/tendermint-rs/blob/e2cb9aca0b95430fca2eac154edddc9588038982/docs/architecture/adr-002-lite-client.md 1051 [attack-detector]: https://github.com/tendermint/spec/blob/master/rust-spec/lightclient/detection/detection_001_reviewed.md 1052 [fullnode]: https://github.com/tendermint/tendermint/blob/v0.34.x/spec/blockchain/fullnode.md 1053 1054 [ibc-rs]:https://github.com/informalsystems/ibc-rs 1055 1056 [blockchain-validator-set]: https://github.com/tendermint/tendermint/blob/v0.34.x/spec/blockchain/blockchain.md#data-structures 1057 [fullnode-data-structures]: https://github.com/tendermint/tendermint/blob/v0.34.x/spec/blockchain/fullnode.md#data-structures 1058 1059 [FN-ManifestFaulty-link]: https://github.com/tendermint/tendermint/blob/v0.34.x/spec/blockchain/fullnode.md#fn-manifestfaulty 1060 1061 [arXiv]: https://arxiv.org/abs/1807.04938