lite2: light client with weak subjectivity (#3989)

Refs #1771

ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md

## Commits:

* add Verifier and VerifyCommitTrusting

* add two more checks

make trustLevel an option

* float32 for trustLevel

* check newHeader time

* started writing lite Client

* unify Verify methods

* ensure h2.Header.bfttime < h1.Header.bfttime + tp

* move trust checks into Verify function

* add more comments

* more docs

* started writing tests

* unbonding period failures

* tests are green

* export ErrNewHeaderTooFarIntoFuture

* make golangci happy

* test for non-adjusted headers

* more precision

* providers and stores

* VerifyHeader and VerifyHeaderAtHeight funcs

* fix compile errors

* remove lastVerifiedHeight, persist new trusted header

* sequential verification

* remove TrustedStore option

* started writing tests for light client

* cover basic cases for linear verification

* bisection tests PASS

* rename BisectingVerification to SkippingVerification

* refactor the code

* add TrustedHeader method

* consolidate sequential verification tests

* consolidate skipping verification tests

* rename trustedVals to trustedNextVals

* start writing docs

* ValidateTrustLevel func and ErrOldHeaderExpired error

* AutoClient and example tests

* fix errors

* update doc

* remove ErrNewHeaderTooFarIntoFuture

This check is unnecessary given existing a) ErrOldHeaderExpired b)
h2.Time > now checks.

* return an error if we're at more recent height

* add comments

* add LastSignedHeaderHeight method to Store

I think it's fine if Store tracks last height

* copy over proxy from old lite package

* make TrustedHeader return latest if height=0

* modify LastSignedHeaderHeight to return an error if no headers exist

* copy over proxy impl

* refactor proxy and start http lite client

* Tx and BlockchainInfo methods

* Block method

* commit method

* code compiles again

* lite client compiles

* extract updateLiteClientIfNeededTo func

* move final parts

* add placeholder for tests

* force usage of lite http client in proxy

* comment out query tests for now

* explicitly mention tp: trusting period

* verify nextVals in VerifyHeader

* refactor bisection

* move the NextValidatorsHash check into updateTrustedHeaderAndVals

+ update the comment

* add ConsensusParams method to RPC client

* add ConsensusParams to rpc/mock/client

* change trustLevel type to a new cmn.Fraction type

+ update SkippingVerification comment

* stress out trustLevel is only used for non-adjusted headers

* fixes after Fede's review

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* compare newHeader with a header from an alternative provider

* save pivot header

Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824

* check header can still be trusted in TrustedHeader

Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424

* lite: update Validators and Block endpoints

- Block no longer contains BlockMeta
- Validators now accept two additional params: page and perPage

* make linter happy
This commit is contained in:
Anton Kaliaev
2019-11-25 19:07:40 +04:00
committed by GitHub
parent ceb105316b
commit fb8b00f1d8
29 changed files with 2934 additions and 25 deletions

95
lite2/example_test.go Normal file
View File

@@ -0,0 +1,95 @@
package lite
//func TestExample_Client(t *testing.T) {
// const (
// chainID = "my-awesome-chain"
// )
// dbDir, err := ioutil.TempDir("", "lite-client-example")
// if err != nil {
// t.Fatal(err)
// }
// defer os.RemoveAll(dbDir)
// // TODO: fetch the "trusted" header from a node
// header := (*types.SignedHeader)(nil)
// /////////////////////////////////////////////////////////////////////////////
// db, err := dbm.NewGoLevelDB("lite-client-db", dbDir)
// if err != nil {
// // return err
// t.Fatal(err)
// }
// c, err := NewClient(
// chainID,
// TrustOptions{
// Period: 504 * time.Hour, // 21 days
// Height: 100,
// Hash: header.Hash(),
// },
// httpp.New(chainID, "tcp://localhost:26657"),
// dbs.New(db, chainID),
// )
// err = c.VerifyHeaderAtHeight(101, time.Now())
// if err != nil {
// fmt.Println("retry?")
// }
// h, err := c.TrustedHeader(101)
// if err != nil {
// fmt.Println("retry?")
// }
// fmt.Println("got header", h)
// // verify some data
//}
//func TestExample_AutoClient(t *testing.T) {
// const (
// chainID = "my-awesome-chain"
// )
// dbDir, err := ioutil.TempDir("", "lite-client-example")
// if err != nil {
// t.Fatal(err)
// }
// defer os.RemoveAll(dbDir)
// // TODO: fetch the "trusted" header from a node
// header := (*types.SignedHeader)(nil)
// /////////////////////////////////////////////////////////////////////////////
// db, err := dbm.NewGoLevelDB("lite-client-db", dbDir)
// if err != nil {
// // return err
// t.Fatal(err)
// }
// base, err := NewClient(
// chainID,
// TrustOptions{
// Period: 504 * time.Hour, // 21 days
// Height: 100,
// Hash: header.Hash(),
// },
// httpp.New(chainID, "tcp://localhost:26657"),
// dbs.New(db, chainID),
// )
// c := NewAutoClient(base, 1*time.Second)
// defer c.Stop()
// select {
// case h := <-c.TrustedHeaders():
// fmt.Println("got header", h)
// // verify some data
// case err := <-c.Err():
// switch errors.Cause(err).(type) {
// case ErrOldHeaderExpired:
// // reobtain trust height and hash
// default:
// // try with another full node
// fmt.Println("got error", err)
// }
// }
//}