You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1063 lines
36 KiB

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