lite

package
v0.25.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 23, 2018 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package lite allows you to securely validate headers without a full node.

This library pulls together all the crypto and algorithms, so given a relatively recent (< unbonding period) known validator set, one can get indisputable proof that data is in the chain (current state) or detect if the node is lying to the client.

Tendermint RPC exposes a lot of info, but a malicious node could return any data it wants to queries, or even to block headers, even making up fake signatures from non-existent validators to justify it. This is a lot of logic to get right, to be contained in a small, easy to use library, that does this for you, so you can just build nice applications.

We design for clients who have no strong trust relationship with any Tendermint node, just the blockchain and validator set as a whole.

Data structures

## SignedHeader

SignedHeader is a block header along with a commit -- enough validator precommit-vote signatures to prove its validity (> 2/3 of the voting power) given the validator set responsible for signing that header. A FullCommit is a SignedHeader along with the current and next validator sets.

The hash of the next validator set is included and signed in the SignedHeader. This lets the lite client keep track of arbitrary changes to the validator set, as every change to the validator set must be approved by inclusion in the header and signed in the commit.

In the worst case, with every block changing the validators around completely, a lite client can sync up with every block header to verify each validator set change on the chain. In practice, most applications will not have frequent drastic updates to the validator set, so the logic defined in this package for lite client syncing is optimized to use intelligent bisection and block-skipping for efficient sourcing and verification of these data structures and updates to the validator set (see the DynamicVerifier for more information).

The FullCommit is also declared in this package as a convenience structure, which includes the SignedHeader along with the full current and next ValidatorSets.

## Verifier

A Verifier validates a new SignedHeader given the currently known state. There are two different types of Verifiers provided.

BaseVerifier - given a validator set and a height, this Verifier verifies that > 2/3 of the voting power of the given validator set had signed the SignedHeader, and that the SignedHeader was to be signed by the exact given validator set, and that the height of the commit is at least height (or greater).

SignedHeader.Commit may be signed by a different validator set, it can get certified with a BaseVerifier as long as sufficient signatures from the previous validator set are present in the commit.

DynamicVerifier - this Verifier implements an auto-update and persistence strategy to certify any SignedHeader of the blockchain.

## Provider and PersistentProvider

A Provider allows us to store and retrieve the FullCommits.

```go

type Provider interface {
	// LatestFullCommit returns the latest commit with
	// minHeight <= height <= maxHeight.
	// If maxHeight is zero, returns the latest where
	// minHeight <= height.
	LatestFullCommit(chainID string, minHeight, maxHeight int64) (FullCommit, error)
}

```

* client.NewHTTPProvider - query Tendermint rpc.

A PersistentProvider is a Provider that also allows for saving state. This is used by the DynamicVerifier for persistence.

```go

type PersistentProvider interface {
	Provider

	// SaveFullCommit saves a FullCommit (without verification).
	SaveFullCommit(fc FullCommit) error
}

```

* DBProvider - persistence provider for use with any tmlibs/DB. * MultiProvider - combine multiple providers.

The suggested use for local light clients is client.NewHTTPProvider(...) for getting new data (Source), and NewMultiProvider(NewDBProvider("label", dbm.NewMemDB()), NewDBProvider("label", db.NewFileDB(...))) to store confirmed full commits (Trusted)

How We Track Validators

Unless you want to blindly trust the node you talk with, you need to trace every response back to a hash in a block header and validate the commit signatures of that block header match the proper validator set. If there is a static validator set, you store it locally upon initialization of the client, and check against that every time.

If the validator set for the blockchain is dynamic, verifying block commits is a bit more involved -- if there is a block at height H with a known (trusted) validator set V, and another block at height H' (H' > H) with validator set V' != V, then we want a way to safely update it.

First, we get the new (unconfirmed) validator set V' and verify that H' is internally consistent and properly signed by this V'. Assuming it is a valid block, we check that at least 2/3 of the validators in V also signed it, meaning it would also be valid under our old assumptions. Then, we accept H' and V' as valid and trusted and use that to validate for heights X > H' until a more recent and updated validator set is found.

If we cannot update directly from H -> H' because there was too much change to the validator set, then we can look for some Hm (H < Hm < H') with a validator set Vm. Then we try to update H -> Hm and then Hm -> H' in two steps. If one of these steps doesn't work, then we continue bisecting, until we eventually have to externally validate the valdiator set changes at every block.

Since we never trust any server in this protocol, only the signatures themselves, it doesn't matter if the seed comes from a (possibly malicious) node or a (possibly malicious) user. We can accept it or reject it based only on our trusted validator set and cryptographic proofs. This makes it extremely important to verify that you have the proper validator set when initializing the client, as that is the root of all trust.

The software currently assumes that the unbonding period is infinite in duration. If the DynamicVerifier hasn't been updated in a while, you should manually verify the block headers using other sources.

TODO: Update the software to handle cases around the unbonding period.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenSecpPrivKeys added in v0.25.0

func GenSecpPrivKeys(n int) privKeys

GenSecpPrivKeys produces an array of secp256k1 private keys to generate commits.

func NewMultiProvider added in v0.25.0

func NewMultiProvider(providers ...PersistentProvider) *multiProvider

NewMultiProvider returns a new provider which wraps multiple other providers.

Types

type BaseVerifier added in v0.25.0

type BaseVerifier struct {
	// contains filtered or unexported fields
}

BaseVerifier lets us check the validity of SignedHeaders at height or later, requiring sufficient votes (> 2/3) from the given valset. To certify blocks produced by a blockchain with mutable validator sets, use the DynamicVerifier. TODO: Handle unbonding time.

func NewBaseVerifier added in v0.25.0

func NewBaseVerifier(chainID string, height int64, valset *types.ValidatorSet) *BaseVerifier

NewBaseVerifier returns a new Verifier initialized with a validator set at some height.

func (*BaseVerifier) Certify added in v0.25.0

func (bc *BaseVerifier) Certify(signedHeader types.SignedHeader) error

Implements Verifier.

func (*BaseVerifier) ChainID added in v0.25.0

func (bc *BaseVerifier) ChainID() string

Implements Verifier.

type DBProvider added in v0.25.0

type DBProvider struct {
	// contains filtered or unexported fields
}

func NewDBProvider added in v0.25.0

func NewDBProvider(label string, db dbm.DB) *DBProvider

func (*DBProvider) LatestFullCommit added in v0.25.0

func (dbp *DBProvider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (
	FullCommit, error)

Implements Provider.

func (*DBProvider) SaveFullCommit added in v0.25.0

func (dbp *DBProvider) SaveFullCommit(fc FullCommit) error

Implements PersistentProvider.

func (*DBProvider) SetLimit added in v0.25.0

func (dbp *DBProvider) SetLimit(limit int) *DBProvider

func (*DBProvider) SetLogger added in v0.25.0

func (dbp *DBProvider) SetLogger(logger log.Logger)

func (*DBProvider) ValidatorSet added in v0.25.0

func (dbp *DBProvider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error)

type DynamicVerifier added in v0.25.0

type DynamicVerifier struct {
	// contains filtered or unexported fields
}

DynamicVerifier implements an auto-updating Verifier. It uses a "source" provider to obtain the needed FullCommits to securely sync with validator set changes. It stores properly validated data on the "trusted" local system.

func NewDynamicVerifier added in v0.25.0

func NewDynamicVerifier(chainID string, trusted PersistentProvider, source Provider) *DynamicVerifier

NewDynamicVerifier returns a new DynamicVerifier. It uses the trusted provider to store validated data and the source provider to obtain missing data (e.g. FullCommits).

The trusted provider should a CacheProvider, MemProvider or files.Provider. The source provider should be a client.HTTPProvider.

func (*DynamicVerifier) Certify added in v0.25.0

func (ic *DynamicVerifier) Certify(shdr types.SignedHeader) error

Implements Verifier.

If the validators have changed since the last known time, it looks to ic.trusted and ic.source to prove the new validators. On success, it will try to store the SignedHeader in ic.trusted if the next validator can be sourced.

func (*DynamicVerifier) ChainID added in v0.25.0

func (ic *DynamicVerifier) ChainID() string

Implements Verifier.

func (*DynamicVerifier) LastTrustedHeight added in v0.25.0

func (ic *DynamicVerifier) LastTrustedHeight() int64

func (*DynamicVerifier) SetLogger added in v0.25.0

func (ic *DynamicVerifier) SetLogger(logger log.Logger)

type FullCommit

type FullCommit struct {
	SignedHeader   types.SignedHeader  `json:"signed_header"`
	Validators     *types.ValidatorSet `json:"validator_set"`
	NextValidators *types.ValidatorSet `json:"next_validator_set"`
}

FullCommit is a signed header (the block header and a commit that signs it), the validator set which signed the commit, and the next validator set. The next validator set (which is proven from the block header) allows us to revert to block-by-block updating of lite Verifier's latest validator set, even in the face of arbitrarily large power changes.

func NewFullCommit

func NewFullCommit(signedHeader types.SignedHeader, valset, nextValset *types.ValidatorSet) FullCommit

NewFullCommit returns a new FullCommit.

func (FullCommit) ChainID added in v0.25.0

func (fc FullCommit) ChainID() string

ChainID returns the chainID of the header.

func (FullCommit) Height added in v0.25.0

func (fc FullCommit) Height() int64

Height returns the height of the header.

func (FullCommit) ValidateFull added in v0.25.0

func (fc FullCommit) ValidateFull(chainID string) error

Validate the components and check for consistency. This also checks to make sure that Validators actually signed the SignedHeader.Commit. If > 2/3 did not sign the Commit from fc.Validators, it is not a valid commit!

type PersistentProvider added in v0.25.0

type PersistentProvider interface {
	Provider

	// SaveFullCommit saves a FullCommit (without verification).
	SaveFullCommit(fc FullCommit) error
}

A provider that can also persist new information. Examples: MemProvider, files.Provider, CacheProvider.

type Provider

type Provider interface {

	// LatestFullCommit returns the latest commit with minHeight <= height <=
	// maxHeight.
	// If maxHeight is zero, returns the latest where minHeight <= height.
	LatestFullCommit(chainID string, minHeight, maxHeight int64) (FullCommit, error)

	// Get the valset that corresponds to chainID and height and return.
	// Height must be >= 1.
	ValidatorSet(chainID string, height int64) (*types.ValidatorSet, error)

	// Set a logger.
	SetLogger(logger log.Logger)
}

Provider provides information for the lite client to sync validators. Examples: MemProvider, files.Provider, client.Provider, CacheProvider.

type Verifier added in v0.25.0

type Verifier interface {
	Certify(sheader types.SignedHeader) error
	ChainID() string
}

Verifier checks the votes to make sure the block really is signed properly. Verifier must know the current or recent set of validitors by some other means.

Directories

Path Synopsis
Package client defines a provider that uses a rpcclient to get information, which is used to get new headers and validators directly from a Tendermint client.
Package client defines a provider that uses a rpcclient to get information, which is used to get new headers and validators directly from a Tendermint client.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL