Skip to content
This repository has been archived by the owner on Feb 23, 2022. It is now read-only.

Update specification of light client algorithm to align with the code #61

Merged
merged 23 commits into from
Jan 23, 2020
Merged
Changes from 2 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a4b68ec
Add non-recursive specification of Bisection algorithm
milosevic Nov 15, 2019
4ee393c
Clean up error conditions and simplify pseudocode
milosevic Nov 28, 2019
2306108
Apply suggestions from code review
milosevic Dec 2, 2019
afda2d3
some suggestions for pseuodocode changes
Dec 6, 2019
5c58084
Improved error handling
milosevic Dec 6, 2019
069906a
Improve algorithms
milosevic Dec 11, 2019
9ddfc79
Add explanation on difference between trusted models
milosevic Dec 11, 2019
8528cdb
Merge remote-tracking branch 'remotes/origin/master' into zm_lite_cli…
milosevic Dec 11, 2019
4f7c555
Address reviewer's comments
milosevic Dec 12, 2019
ee0cc53
Addressing reviewer's comments
milosevic Dec 25, 2019
0adde9d
Separating algorithm from proofs
milosevic Dec 26, 2019
4a9eb1f
Intermediate commit (aligning spec with the code)
milosevic Dec 31, 2019
7130c2e
Removing Store from API and providing end-to-end timing guarantees
milosevic Jan 6, 2020
146e251
Address reviewer comment's. Intermediate commit
milosevic Jan 8, 2020
f26eb4e
light client dir and readmes
ebuchman Jan 22, 2020
eb9e1f9
titles
ebuchman Jan 22, 2020
e342c21
add redirects
ebuchman Jan 22, 2020
0358389
add diagram
ebuchman Jan 22, 2020
d1bd98d
detection TODO
ebuchman Jan 22, 2020
bd2f41b
fix image
ebuchman Jan 22, 2020
c35d6e7
update readme
ebuchman Jan 22, 2020
dc54206
Merge pull request #73 from tendermint/bucky/light-reorg
milosevic Jan 23, 2020
026fdde
Aligh the correctness arguments with the pseudocode changes
milosevic Jan 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 77 additions & 46 deletions spec/consensus/light-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,33 +193,43 @@ We consider the following set-up:
we will write ```totalVotingPower(V)``` for ```votingpower_in(V,V)```, which returns the total voting power in V.
milosevic marked this conversation as resolved.
Show resolved Hide resolved
We further use the function ```signers(Commit)``` that returns the set of validators that signed the Commit.

**CheckSupport.** The following function checks whether we can trust the header h2 based on header h1 following the trusting period method.
**CheckSupport.** The following function checks whether we can trust the header h2 based on header h1 following the trusting period method. Time constraint is
captured by the `hasExpired` function that depends on trusted period (`tp`) and a parameter `Delta` that denotes minimum duration of header so it is
milosevic marked this conversation as resolved.
Show resolved Hide resolved
not considered expired.

```go
func CheckSupport(h1,h2,trustlevel) bool {
if h1.Header.bfttime + tp < now { // Observation 1
return false // old header was once trusted but it is expired
}
vp_all := totalVotingPower(h1.Header.NextV)
// total sum of voting power of validators in h2

if h2.Header.height == h1.Header.height + 1 {
// specific check for adjacent headers; everything must be
// properly signed.
// also check that h2.Header.V == h1.Header.NextV
// Plus the following check that 2/3 of the voting power
// in h1 signed h2
return (votingpower_in(signers(h2.Commit),h1.Header.NextV) >
2/3 * vp_all)
// signing validators are more than two third in h1.
}
// return true if header has expired, i.e., it is outside its trusted period; otherwise it returns false
func hasExpired(h) bool {
if h.Header.bfttime + tp - Delta < now { // Observation 1
milosevic marked this conversation as resolved.
Show resolved Hide resolved
return true
}
milosevic marked this conversation as resolved.
Show resolved Hide resolved

// return true if header is correctly signed by 2/3+ voting power in the corresponding validator set; otherwise false. Additional checks should be done in the implementation
milosevic marked this conversation as resolved.
Show resolved Hide resolved
// to ensure header is well formed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably specify these somewhere.

func verify(h) bool {
vp_all := totalVotingPower(h.Header.V) // total sum of voting power of validators in h
milosevic marked this conversation as resolved.
Show resolved Hide resolved
return votingpower_in(signers(h.Commit),h.Header.V) > 2/3 * vp_all
}

return (votingpower_in(signers(h2.Commit),h1.Header.NextV) >
max(1/3,trustlevel) * vp_all)
// get validators in h1 that signed h2
// sum of voting powers in h1 of
// validators that signed h2
// is more than a third in h1
// Captures skipping condition. h1 and h2 has already passed basic validation (function `verify`).
milosevic marked this conversation as resolved.
Show resolved Hide resolved
milosevic marked this conversation as resolved.
Show resolved Hide resolved
// returns (true, nil) in case h2 can be trusted based on h1, (false, nil) in case it cannot be trusted but no errors are observed during check and (false, error) in case
// an error is detected (for example adjacent headers are not consistent).
func CheckSupport(h1,h2,trustlevel) (bool, error) {
milosevic marked this conversation as resolved.
Show resolved Hide resolved
assume h1.Header.Height < h2.header.Height

if hasExpired(h1) return (false, ErrHeaderExpired(h1))

// total sum of voting power of validators in h1.NextV
milosevic marked this conversation as resolved.
Show resolved Hide resolved
vp_all := totalVotingPower(h1.Header.NextV)
milosevic marked this conversation as resolved.
Show resolved Hide resolved

// check for adjacent headers
if (h2.Header.height == h1.Header.height + 1) {
milosevic marked this conversation as resolved.
Show resolved Hide resolved
if h1.Header.NextV == h2.Header.V return (true, nil)
milosevic marked this conversation as resolved.
Show resolved Hide resolved
else return (false, ErrInvalidAdjacentHeaders)
milosevic marked this conversation as resolved.
Show resolved Hide resolved
} else {
milosevic marked this conversation as resolved.
Show resolved Hide resolved
// check for non-adjacent headers
return (votingpower_in(signers(h2.Commit),h1.Header.NextV) > max(1/3,trustlevel) * vp_all, nil)
milosevic marked this conversation as resolved.
Show resolved Hide resolved
}
}
```

Expand Down Expand Up @@ -257,28 +267,49 @@ Towards Lite Client Completeness:


```go
func Bisection(h1,h2,trustlevel) bool{
if CheckSupport(h1,h2,trustlevel) {
return true
}
if h2.Header.height == h1.Header.height + 1 {
// we have adjacent headers that are not matching (failed
// the CheckSupport)
// we could submit evidence here
return false
}
pivot := (h1.Header.height + h2.Header.height) / 2
hp := Commit(pivot)
// ask a full node for header of height pivot
Store(hp)
// store header hp locally
if Bisection(h1,hp,trustlevel) {
// only check right branch if hp is trusted
// (otherwise a lot of unnecessary computation may be done)
return Bisection(hp,h2,trustlevel)
}
else {
return false
// return (true, nil) in case we can trust header h2 based on header h1; otherwise return (false, error) where error captures the nature of the error.
func Bisection(h1,h2,trustlevel) (bool, error) {
assume h1.Header.Height < h2.header.Height

ok, err = CheckSupport(h1,h2,trustlevel)
if (ok or err != nil) return (ok, err)

milosevic marked this conversation as resolved.
Show resolved Hide resolved
// we cannot verify h2 based on h1, so we try to move trusted header closer to h2 so we can verify h2
th := h1 // th is trusted header
while th.Header.Height <= h2.Header.height - 1 do {
milosevic marked this conversation as resolved.
Show resolved Hide resolved
// try to move trusted header forward with stored headers
milosevic marked this conversation as resolved.
Show resolved Hide resolved
ih := th
for all stored headers h s.t ih.Header.Height < h.Header.height < h2.Header.height do { // try to move trusted header forward
milosevic marked this conversation as resolved.
Show resolved Hide resolved
// we assume here that iteration is done in the order of header heights
ok, err = CheckSupport(th,h,trustlevel)
if err != nil { return (ok, err) }
if ok {
th = h
milosevic marked this conversation as resolved.
Show resolved Hide resolved
}
}

// at this point we have potentially updated th based on stored headers so we try to verify h2 based on new trusted header
milosevic marked this conversation as resolved.
Show resolved Hide resolved
ok, err = CheckSupport(th,h2,trustlevel)
if (ok or err != nil) return (ok, err)

// we cannot verify h2 based on th, so we try to move trusted header closer to h2 by downloading header(s) between th and h2
endHeight = h2.Header.height
milosevic marked this conversation as resolved.
Show resolved Hide resolved
foundPivot = false
while(!foundPivot) {
pivot := (th.Header.height + endHeight) / 2
milosevic marked this conversation as resolved.
Show resolved Hide resolved
hp := Commit(pivot)
if !verify(hp) return (false, ErrInvalidHeader(hp))
Store(hp)
milosevic marked this conversation as resolved.
Show resolved Hide resolved

// try to move trusted header forward to hp
ok, err = CheckSupport(th,hp,trustlevel)
if err != nil { return (ok, err) }
if ok {
th = hp
foundPivot = true
}
endHeight = pivot
}
milosevic marked this conversation as resolved.
Show resolved Hide resolved
milosevic marked this conversation as resolved.
Show resolved Hide resolved
}
}
```
Expand Down