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.

1061 lines
36 KiB

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