lite

package
v0.33.0-dev2 Latest Latest
Warning

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

Go to latest
Published: Feb 7, 2020 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package lite provides a light client implementation.

The concept of light clients was introduced in the Bitcoin white paper. It describes a watcher of distributed consensus process that only validates the consensus algorithm and not the state machine transactions within.

Tendermint light clients allow bandwidth & compute-constrained devices, such as smartphones, low-power embedded chips, or other blockchains to efficiently verify the consensus of a Tendermint blockchain. This forms the basis of safe and efficient state synchronization for new network nodes and inter-blockchain communication (where a light client of one Tendermint instance runs in another chain's state machine).

In a network that is expected to reliably punish validators for misbehavior by slashing bonded stake and where the validator set changes infrequently, clients can take advantage of this assumption to safely synchronize a lite client without downloading the intervening headers.

Light clients (and full nodes) operating in the Proof Of Stake context need a trusted block height from a trusted source that is no older than 1 unbonding window plus a configurable evidence submission synchrony bound. This is called weak subjectivity.

Weak subjectivity is required in Proof of Stake blockchains because it is costless for an attacker to buy up voting keys that are no longer bonded and fork the network at some point in its prior history. See Vitalik's post at [Proof of Stake: How I Learned to Love Weak Subjectivity](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/).

NOTE: Tendermint provides a somewhat different (stronger) light client model than Bitcoin under eclipse, since the eclipsing node(s) can only fool the light client if they have two-thirds of the private keys from the last root-of-trust.

Common 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.

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.

What this package provides

This package provides three major things:

1. Client implementation (see client.go) 2. Pure functions to verify a new header (see verifier.go) 3. Secure RPC proxy

## 1. Client implementation (see client.go)

Example usage:

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)

## 2. Pure functions to verify a new header (see verifier.go)

Verify function verifies a new header against some trusted header. See https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md for details.

## 3. Secure RPC proxy

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. Secure RPC proxy serves as a wrapper, which verifies all the headers, using a light client connected to some other node.

See https://github.com/tendermint/tendermint/blob/master/cmd/tendermint/commands/lite.go for usage example.

Index

Constants

This section is empty.

Variables

View Source
var (
	// DefaultTrustLevel - new header can be trusted if at least one correct old
	// validator signed it.
	DefaultTrustLevel = tmmath.Fraction{Numerator: 1, Denominator: 3}
)

Functions

func HeaderExpired

func HeaderExpired(h *types.SignedHeader, trustingPeriod time.Duration, now time.Time) bool

HeaderExpired return true if the given header expired.

func ValidateTrustLevel

func ValidateTrustLevel(lvl tmmath.Fraction) error

ValidateTrustLevel checks that trustLevel is within the allowed range [1/3, 1]. If not, it returns an error. 1/3 is the minimum amount of trust needed which does not break the security model.

func Verify

func Verify(
	chainID string,
	h1 *types.SignedHeader,
	h1NextVals *types.ValidatorSet,
	h2 *types.SignedHeader,
	h2Vals *types.ValidatorSet,
	trustingPeriod time.Duration,
	now time.Time,
	trustLevel tmmath.Fraction) error

Verify verifies the new header (h2) against the old header (h1). It ensures that:

a) h1 can still be trusted (if not, ErrOldHeaderExpired is returned);
b) h2 is valid;
c) either h2.ValidatorsHash equals h1NextVals.Hash()
	 OR trustLevel ([1/3, 1]) of last trusted validators (h1NextVals) signed
	 correctly  (if not, ErrNewValSetCantBeTrusted is returned);
c) more than 2/3 of new validators (h2Vals) have signed h2 (if not,
   ErrNotEnoughVotingPowerSigned is returned).

Types

type Client

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

Client represents a light client, connected to a single chain, which gets headers from a primary provider, verifies them either sequentially or by skipping some and stores them in a trusted store (usually, a local FS).

By default, the client will poll the primary provider for new headers every 5s (UpdatePeriod). If there are any, it will try to advance the state.

Default verification: SkippingVerification(DefaultTrustLevel)

func NewClient

func NewClient(
	chainID string,
	trustOptions TrustOptions,
	primary provider.Provider,
	witnesses []provider.Provider,
	trustedStore store.Store,
	options ...Option) (*Client, error)

NewClient returns a new light client. It returns an error if it fails to obtain the header & vals from the primary or they are invalid (e.g. trust hash does not match with the one from the header).

Witnesses are providers, which will be used for cross-checking the primary provider. At least one witness must be given. A witness can become a primary iff the current primary is unavailable.

See all Option(s) for the additional configuration.

func NewClientFromTrustedStore added in v0.33.1

func NewClientFromTrustedStore(
	chainID string,
	trustingPeriod time.Duration,
	primary provider.Provider,
	witnesses []provider.Provider,
	trustedStore store.Store,
	options ...Option) (*Client, error)

NewClientFromTrustedStore initializes existing client from the trusted store.

See NewClient

func (*Client) ChainID

func (c *Client) ChainID() string

ChainID returns the chain ID the light client was configured with.

Safe for concurrent use by multiple goroutines.

func (*Client) Cleanup

func (c *Client) Cleanup() error

Cleanup removes all the data (headers and validator sets) stored. Note: the client must be stopped at this point.

func (*Client) FirstTrustedHeight added in v0.33.1

func (c *Client) FirstTrustedHeight() (int64, error)

FirstTrustedHeight returns a first trusted height. -1 and nil are returned if there are no trusted headers.

Safe for concurrent use by multiple goroutines.

func (*Client) LastTrustedHeight

func (c *Client) LastTrustedHeight() (int64, error)

LastTrustedHeight returns a last trusted height. -1 and nil are returned if there are no trusted headers.

Safe for concurrent use by multiple goroutines.

func (*Client) Primary added in v0.33.1

func (c *Client) Primary() provider.Provider

Primary returns the primary provider.

NOTE: provider may be not safe for concurrent access.

func (*Client) RemoveNoLongerTrustedHeaders

func (c *Client) RemoveNoLongerTrustedHeaders(now time.Time)

RemoveNoLongerTrustedHeaders removes no longer trusted headers (due to expiration).

Exposed for testing.

func (*Client) Start added in v0.33.1

func (c *Client) Start() error

Start starts two processes: 1) auto updating 2) removing outdated headers.

func (*Client) Stop

func (c *Client) Stop()

Stop stops two processes: 1) auto updating 2) removing outdated headers. Stop only returns after both of them are finished running. If you wish to remove all the data, call Cleanup.

func (*Client) TrustedHeader

func (c *Client) TrustedHeader(height int64, now time.Time) (*types.SignedHeader, error)

TrustedHeader returns a trusted header at the given height (0 - the latest). If a header is missing in trustedStore (e.g. it was skipped during bisection), it will be downloaded from primary.

Headers along with validator sets, which can't be trusted anymore, are removed once a day (can be changed with RemoveNoLongerTrustedHeadersPeriod option). . height must be >= 0.

It returns an error if:

  • header expired, therefore can't be trusted (ErrOldHeaderExpired);
  • there are some issues with the trusted store, although that should not happen normally;
  • negative height is passed;
  • header has not been verified yet

Safe for concurrent use by multiple goroutines.

func (*Client) TrustedValidatorSet added in v0.33.1

func (c *Client) TrustedValidatorSet(height int64, now time.Time) (*types.ValidatorSet, error)

TrustedValidatorSet returns a trusted validator set at the given height. If a validator set is missing in trustedStore (e.g. the associated header was skipped during bisection), it will be downloaded from primary. The second return parameter is height validator set corresponds to (useful when you pass 0).

height must be >= 0.

Headers along with validator sets, which can't be trusted anymore, are removed once a day (can be changed with RemoveNoLongerTrustedHeadersPeriod option).

It returns an error if:

  • header signed by that validator set expired (ErrOldHeaderExpired)
  • there are some issues with the trusted store, although that should not happen normally;
  • negative height is passed;
  • header signed by that validator set has not been verified yet

Safe for concurrent use by multiple goroutines.

func (*Client) Update added in v0.33.1

func (c *Client) Update(now time.Time) error

Update attempts to advance the state making exponential steps (note: when SequentialVerification is being used, the client will still be downloading all intermediate headers).

Exposed for testing.

func (*Client) VerifyHeader

func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.ValidatorSet, now time.Time) error

VerifyHeader verifies new header against the trusted state.

SequentialVerification: verifies that 2/3 of the trusted validator set has signed the new header. If the headers are not adjacent, **all** intermediate headers will be requested.

SkippingVerification(trustLevel): verifies that {trustLevel} of the trusted validator set has signed the new header. If it's not the case and the headers are not adjacent, bisection is performed and necessary (not all) intermediate headers will be requested. See the specification for details. https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md

If the trusted header is more recent than one here, an error is returned.

If, at any moment, SignedHeader or ValidatorSet are not found by the primary provider, provider.ErrSignedHeaderNotFound / provider.ErrValidatorSetNotFound error is returned.

func (*Client) VerifyHeaderAtHeight

func (c *Client) VerifyHeaderAtHeight(height int64, now time.Time) (*types.SignedHeader, error)

VerifyHeaderAtHeight fetches the header and validators at the given height and calls VerifyHeader.

If the trusted header is more recent than one here, an error is returned. If the header is not found by the primary provider, provider.ErrSignedHeaderNotFound error is returned.

func (*Client) Witnesses added in v0.33.1

func (c *Client) Witnesses() []provider.Provider

Witnesses returns the witness providers.

NOTE: providers may be not safe for concurrent access.

type ErrNewValSetCantBeTrusted

type ErrNewValSetCantBeTrusted struct {
	Reason types.ErrNotEnoughVotingPowerSigned
}

ErrNewValSetCantBeTrusted means the new validator set cannot be trusted because < 1/3rd (+trustLevel+) of the old validator set has signed.

func (ErrNewValSetCantBeTrusted) Error

type ErrOldHeaderExpired

type ErrOldHeaderExpired struct {
	At  time.Time
	Now time.Time
}

ErrOldHeaderExpired means the old (trusted) header has expired according to the given trustingPeriod and current time. If so, the light client must be reset subjectively.

func (ErrOldHeaderExpired) Error

func (e ErrOldHeaderExpired) Error() string

type Option

type Option func(*Client)

Option sets a parameter for the light client.

func ConfirmationFunction

func ConfirmationFunction(fn func(action string) bool) Option

ConfirmationFunction option can be used to prompt to confirm an action. For example, remove newer headers if the light client is being reset with an older header. No confirmation is required by default!

func Logger added in v0.33.1

func Logger(l log.Logger) Option

Logger option can be used to set a logger for the client.

func MaxRetryAttempts added in v0.33.1

func MaxRetryAttempts(max uint16) Option

MaxRetryAttempts option can be used to set max attempts before replacing primary with a witness.

func RemoveNoLongerTrustedHeadersPeriod

func RemoveNoLongerTrustedHeadersPeriod(d time.Duration) Option

RemoveNoLongerTrustedHeadersPeriod option can be used to define how often the routine, which cleans up no longer trusted headers (outside of trusting period), is run. Default: once a day. When set to zero, the routine won't be started.

func SequentialVerification

func SequentialVerification() Option

SequentialVerification option configures the light client to sequentially check the headers (every header, in ascending height order). Note this is much slower than SkippingVerification, albeit more secure.

func SkippingVerification

func SkippingVerification(trustLevel tmmath.Fraction) Option

SkippingVerification option configures the light client to skip headers as long as {trustLevel} of the old validator set signed the new header. The bisection algorithm from the specification is used for finding the minimal "trust path".

trustLevel - fraction of the old validator set (in terms of voting power), which must sign the new header in order for us to trust it. NOTE this only applies to non-adjacent headers. For adjacent headers, sequential verification is used.

func UpdatePeriod added in v0.33.1

func UpdatePeriod(d time.Duration) Option

UpdatePeriod option can be used to change default polling period (5s).

type TrustOptions

type TrustOptions struct {
	// tp: trusting period.
	//
	// Should be significantly less than the unbonding period (e.g. unbonding
	// period = 3 weeks, trusting period = 2 weeks).
	//
	// More specifically, trusting period + time needed to check headers + time
	// needed to report and punish misbehavior should be less than the unbonding
	// period.
	Period time.Duration

	// Header's Height and Hash must both be provided to force the trusting of a
	// particular header.
	Height int64
	Hash   []byte
}

TrustOptions are the trust parameters needed when a new light client connects to the network or when an existing light client that has been offline for longer than the trusting period connects to the network.

The expectation is the user will get this information from a trusted source like a validator, a friend, or a secure website. A more user friendly solution with trust tradeoffs is that we establish an https based protocol with a default end point that populates this information. Also an on-chain registry of roots-of-trust (e.g. on the Cosmos Hub) seems likely in the future.

func (TrustOptions) ValidateBasic added in v0.33.1

func (opts TrustOptions) ValidateBasic() error

ValidateBasic performs basic validation.

Directories

Path Synopsis
db

Jump to

Keyboard shortcuts

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