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