github.com/number571/tendermint@v0.34.11-gost/light/client.go (about)

     1  package light
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"fmt"
     8  	"sort"
     9  	"sync"
    10  	"time"
    11  
    12  	tmsync "github.com/number571/tendermint/internal/libs/sync"
    13  	"github.com/number571/tendermint/libs/log"
    14  	tmmath "github.com/number571/tendermint/libs/math"
    15  	"github.com/number571/tendermint/light/provider"
    16  	"github.com/number571/tendermint/light/store"
    17  	"github.com/number571/tendermint/types"
    18  )
    19  
    20  type mode byte
    21  
    22  const (
    23  	sequential mode = iota + 1
    24  	skipping
    25  
    26  	defaultPruningSize = 1000
    27  
    28  	// For verifySkipping, we need an algorithm to find what height to check
    29  	// next to see if it has sufficient validator set overlap. The most
    30  	// intuitive method is to take the halfway point i.e. if you trusted block
    31  	// 1 and were not able to verify block 128 then your next try would be 64.
    32  	//
    33  	// However, because this implementation caches all the prior results, instead of always taking halfpoints
    34  	// it is more efficient to re-check cached blocks. Take this simple example. Say
    35  	// you failed to verify 64 but were able to verify block 32. Following a strict half-way policy,
    36  	// you would start over again and try verify to block 128. If this failed
    37  	// then the halfway point between 32 and 128 is 80. But you already have
    38  	// block 64. Instead of requesting and waiting for another block it is far
    39  	// better to try again with block 64. This is of course not directly in the
    40  	// middle. In fact, no matter how the algrorithm plays out, the blocks in
    41  	// cache are always going to be a little less than the halfway point (
    42  	// maximum 1/8 less). To account for this we add a heuristic, bumping the
    43  	// next height to 9/16 instead of 1/2
    44  	verifySkippingNumerator   = 9
    45  	verifySkippingDenominator = 16
    46  
    47  	// 10s should cover most of the clients.
    48  	// References:
    49  	// - http://vancouver-webpages.com/time/web.html
    50  	// - https://blog.codinghorror.com/keeping-time-on-the-pc/
    51  	defaultMaxClockDrift = 10 * time.Second
    52  
    53  	// 10s is sufficient for most networks.
    54  	defaultMaxBlockLag = 10 * time.Second
    55  )
    56  
    57  // Option sets a parameter for the light client.
    58  type Option func(*Client)
    59  
    60  // SequentialVerification option configures the light client to sequentially
    61  // check the blocks (every block, in ascending height order). Note this is
    62  // much slower than SkippingVerification, albeit more secure.
    63  func SequentialVerification() Option {
    64  	return func(c *Client) {
    65  		c.verificationMode = sequential
    66  	}
    67  }
    68  
    69  // SkippingVerification option configures the light client to skip blocks as
    70  // long as {trustLevel} of the old validator set signed the new header. The
    71  // verifySkipping algorithm from the specification is used for finding the minimal
    72  // "trust path".
    73  //
    74  // trustLevel - fraction of the old validator set (in terms of voting power),
    75  // which must sign the new header in order for us to trust it. NOTE this only
    76  // applies to non-adjacent headers. For adjacent headers, sequential
    77  // verification is used.
    78  func SkippingVerification(trustLevel tmmath.Fraction) Option {
    79  	return func(c *Client) {
    80  		c.verificationMode = skipping
    81  		c.trustLevel = trustLevel
    82  	}
    83  }
    84  
    85  // PruningSize option sets the maximum amount of light blocks that the light
    86  // client stores. When Prune() is run, all light blocks that are earlier than
    87  // the h amount of light blocks will be removed from the store.
    88  // Default: 1000. A pruning size of 0 will not prune the light client at all.
    89  func PruningSize(h uint16) Option {
    90  	return func(c *Client) {
    91  		c.pruningSize = h
    92  	}
    93  }
    94  
    95  // Logger option can be used to set a logger for the client.
    96  func Logger(l log.Logger) Option {
    97  	return func(c *Client) {
    98  		c.logger = l
    99  	}
   100  }
   101  
   102  // MaxClockDrift defines how much new header's time can drift into
   103  // the future relative to the light clients local time. Default: 10s.
   104  func MaxClockDrift(d time.Duration) Option {
   105  	return func(c *Client) {
   106  		c.maxClockDrift = d
   107  	}
   108  }
   109  
   110  // MaxBlockLag represents the maximum time difference between the realtime
   111  // that a block is received and the timestamp of that block.
   112  // One can approximate it to the maximum block production time
   113  //
   114  // As an example, say the light client received block B at a time
   115  // 12:05 (this is the real time) and the time on the block
   116  // was 12:00. Then the lag here is 5 minutes.
   117  // Default: 10s
   118  func MaxBlockLag(d time.Duration) Option {
   119  	return func(c *Client) {
   120  		c.maxBlockLag = d
   121  	}
   122  }
   123  
   124  // Client represents a light client, connected to a single chain, which gets
   125  // light blocks from a primary provider, verifies them either sequentially or by
   126  // skipping some and stores them in a trusted store (usually, a local FS).
   127  //
   128  // Default verification: SkippingVerification(DefaultTrustLevel)
   129  type Client struct {
   130  	chainID          string
   131  	trustingPeriod   time.Duration // see TrustOptions.Period
   132  	verificationMode mode
   133  	trustLevel       tmmath.Fraction
   134  	maxClockDrift    time.Duration
   135  	maxBlockLag      time.Duration
   136  
   137  	// Mutex for locking during changes of the light clients providers
   138  	providerMutex tmsync.Mutex
   139  	// Primary provider of new headers.
   140  	primary provider.Provider
   141  	// Providers used to "witness" new headers.
   142  	witnesses []provider.Provider
   143  
   144  	// Where trusted light blocks are stored.
   145  	trustedStore store.Store
   146  	// Highest trusted light block from the store (height=H).
   147  	latestTrustedBlock *types.LightBlock
   148  
   149  	// See PruningSize option
   150  	pruningSize uint16
   151  
   152  	logger log.Logger
   153  }
   154  
   155  // NewClient returns a new light client. It returns an error if it fails to
   156  // obtain the light block from the primary or they are invalid (e.g. trust
   157  // hash does not match with the one from the headers).
   158  //
   159  // Witnesses are providers, which will be used for cross-checking the primary
   160  // provider. At least one witness must be given when skipping verification is
   161  // used (default). A witness can become a primary iff the current primary is
   162  // unavailable.
   163  //
   164  // See all Option(s) for the additional configuration.
   165  func NewClient(
   166  	ctx context.Context,
   167  	chainID string,
   168  	trustOptions TrustOptions,
   169  	primary provider.Provider,
   170  	witnesses []provider.Provider,
   171  	trustedStore store.Store,
   172  	options ...Option) (*Client, error) {
   173  
   174  	// Check whether the trusted store already has a trusted block. If so, then create
   175  	// a new client from the trusted store instead of the trust options.
   176  	lastHeight, err := trustedStore.LastLightBlockHeight()
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	if lastHeight > 0 {
   181  		return NewClientFromTrustedStore(
   182  			chainID, trustOptions.Period, primary, witnesses, trustedStore, options...,
   183  		)
   184  	}
   185  
   186  	// Validate trust options
   187  	if err := trustOptions.ValidateBasic(); err != nil {
   188  		return nil, fmt.Errorf("invalid TrustOptions: %w", err)
   189  	}
   190  
   191  	// Validate the number of witnesses.
   192  	if len(witnesses) < 1 {
   193  		return nil, ErrNoWitnesses
   194  	}
   195  
   196  	c := &Client{
   197  		chainID:          chainID,
   198  		trustingPeriod:   trustOptions.Period,
   199  		verificationMode: skipping,
   200  		trustLevel:       DefaultTrustLevel,
   201  		maxClockDrift:    defaultMaxClockDrift,
   202  		maxBlockLag:      defaultMaxBlockLag,
   203  		primary:          primary,
   204  		witnesses:        witnesses,
   205  		trustedStore:     trustedStore,
   206  		pruningSize:      defaultPruningSize,
   207  		logger:           log.NewNopLogger(),
   208  	}
   209  
   210  	for _, o := range options {
   211  		o(c)
   212  	}
   213  
   214  	// Validate trust level.
   215  	if err := ValidateTrustLevel(c.trustLevel); err != nil {
   216  		return nil, err
   217  	}
   218  
   219  	// Use the trusted hash and height to fetch the first weakly-trusted block
   220  	// from the primary provider. Assert that all the witnesses have the same block
   221  	if err := c.initializeWithTrustOptions(ctx, trustOptions); err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	return c, nil
   226  }
   227  
   228  // NewClientFromTrustedStore initializes an existing client from the trusted store.
   229  // It does not check that the providers have the same trusted block.
   230  func NewClientFromTrustedStore(
   231  	chainID string,
   232  	trustingPeriod time.Duration,
   233  	primary provider.Provider,
   234  	witnesses []provider.Provider,
   235  	trustedStore store.Store,
   236  	options ...Option) (*Client, error) {
   237  
   238  	c := &Client{
   239  		chainID:          chainID,
   240  		trustingPeriod:   trustingPeriod,
   241  		verificationMode: skipping,
   242  		trustLevel:       DefaultTrustLevel,
   243  		maxClockDrift:    defaultMaxClockDrift,
   244  		maxBlockLag:      defaultMaxBlockLag,
   245  		primary:          primary,
   246  		witnesses:        witnesses,
   247  		trustedStore:     trustedStore,
   248  		pruningSize:      defaultPruningSize,
   249  		logger:           log.NewNopLogger(),
   250  	}
   251  
   252  	for _, o := range options {
   253  		o(c)
   254  	}
   255  
   256  	// Validate the number of witnesses.
   257  	if len(c.witnesses) < 1 {
   258  		return nil, ErrNoWitnesses
   259  	}
   260  
   261  	// Validate trust level.
   262  	if err := ValidateTrustLevel(c.trustLevel); err != nil {
   263  		return nil, err
   264  	}
   265  
   266  	// Check that the trusted store has at least one block and
   267  	if err := c.restoreTrustedLightBlock(); err != nil {
   268  		return nil, err
   269  	}
   270  
   271  	return c, nil
   272  }
   273  
   274  // restoreTrustedLightBlock loads the latest trusted light block from the store
   275  func (c *Client) restoreTrustedLightBlock() error {
   276  	lastHeight, err := c.trustedStore.LastLightBlockHeight()
   277  	if err != nil {
   278  		return fmt.Errorf("can't get last trusted light block height: %w", err)
   279  	}
   280  	if lastHeight <= 0 {
   281  		return errors.New("trusted store is empty")
   282  	}
   283  
   284  	trustedBlock, err := c.trustedStore.LightBlock(lastHeight)
   285  	if err != nil {
   286  		return fmt.Errorf("can't get last trusted light block: %w", err)
   287  	}
   288  	c.latestTrustedBlock = trustedBlock
   289  	c.logger.Info("restored trusted light block", "height", lastHeight)
   290  
   291  	return nil
   292  }
   293  
   294  // initializeWithTrustOptions fetches the weakly-trusted light block from
   295  // primary provider, matches it to the trusted hash, and sets it as the
   296  // lastTrustedBlock. It then asserts that all witnesses have the same light block.
   297  func (c *Client) initializeWithTrustOptions(ctx context.Context, options TrustOptions) error {
   298  	// 1) Fetch and verify the light block. Note that we do not verify the time of the first block
   299  	l, err := c.lightBlockFromPrimary(ctx, options.Height)
   300  	if err != nil {
   301  		return err
   302  	}
   303  
   304  	// 2) Assert that the hashes match
   305  	if !bytes.Equal(l.Header.Hash(), options.Hash) {
   306  		return fmt.Errorf("expected header's hash %X, but got %X", options.Hash, l.Hash())
   307  	}
   308  
   309  	// 3) Ensure that +2/3 of validators signed correctly. This also sanity checks that the
   310  	// chain ID is the same.
   311  	err = l.ValidatorSet.VerifyCommitLight(c.chainID, l.Commit.BlockID, l.Height, l.Commit)
   312  	if err != nil {
   313  		return fmt.Errorf("invalid commit: %w", err)
   314  	}
   315  
   316  	// 4) Cross-verify with witnesses to ensure everybody has the same state.
   317  	if err := c.compareFirstHeaderWithWitnesses(ctx, l.SignedHeader); err != nil {
   318  		return err
   319  	}
   320  
   321  	// 5) Persist both of them and continue.
   322  	return c.updateTrustedLightBlock(l)
   323  }
   324  
   325  // TrustedLightBlock returns a trusted light block at the given height (0 - the latest).
   326  //
   327  // It returns an error if:
   328  //  - there are some issues with the trusted store, although that should not
   329  //  happen normally;
   330  //  - negative height is passed;
   331  //  - header has not been verified yet and is therefore not in the store
   332  //
   333  // Safe for concurrent use by multiple goroutines.
   334  func (c *Client) TrustedLightBlock(height int64) (*types.LightBlock, error) {
   335  	height, err := c.compareWithLatestHeight(height)
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  	return c.trustedStore.LightBlock(height)
   340  }
   341  
   342  func (c *Client) compareWithLatestHeight(height int64) (int64, error) {
   343  	latestHeight, err := c.LastTrustedHeight()
   344  	if err != nil {
   345  		return 0, fmt.Errorf("can't get last trusted height: %w", err)
   346  	}
   347  	if latestHeight == -1 {
   348  		return 0, errors.New("no headers exist")
   349  	}
   350  
   351  	switch {
   352  	case height > latestHeight:
   353  		return 0, fmt.Errorf("unverified header/valset requested (latest: %d)", latestHeight)
   354  	case height == 0:
   355  		return latestHeight, nil
   356  	case height < 0:
   357  		return 0, errors.New("negative height")
   358  	}
   359  
   360  	return height, nil
   361  }
   362  
   363  // Update attempts to advance the state by downloading the latest light
   364  // block and verifying it. It returns a new light block on a successful
   365  // update. Otherwise, it returns nil (plus an error, if any).
   366  func (c *Client) Update(ctx context.Context, now time.Time) (*types.LightBlock, error) {
   367  	lastTrustedHeight, err := c.LastTrustedHeight()
   368  	if err != nil {
   369  		return nil, fmt.Errorf("can't get last trusted height: %w", err)
   370  	}
   371  
   372  	if lastTrustedHeight == -1 {
   373  		// no light blocks yet => wait
   374  		return nil, nil
   375  	}
   376  
   377  	latestBlock, err := c.lightBlockFromPrimary(ctx, 0)
   378  	if err != nil {
   379  		return nil, err
   380  	}
   381  
   382  	if latestBlock.Height > lastTrustedHeight {
   383  		err = c.verifyLightBlock(ctx, latestBlock, now)
   384  		if err != nil {
   385  			return nil, err
   386  		}
   387  		c.logger.Info("advanced to new state", "height", latestBlock.Height, "hash", latestBlock.Hash())
   388  		return latestBlock, nil
   389  	}
   390  
   391  	return nil, nil
   392  }
   393  
   394  // VerifyLightBlockAtHeight fetches the light block at the given height
   395  // and verifies it. It returns the block immediately if it exists in
   396  // the trustedStore (no verification is needed).
   397  //
   398  // height must be > 0.
   399  //
   400  // It returns provider.ErrlightBlockNotFound if light block is not found by
   401  // primary.
   402  //
   403  // It will replace the primary provider if an error from a request to the provider occurs
   404  func (c *Client) VerifyLightBlockAtHeight(ctx context.Context, height int64, now time.Time) (*types.LightBlock, error) {
   405  	if height <= 0 {
   406  		return nil, errors.New("negative or zero height")
   407  	}
   408  
   409  	// Check if the light block is already verified.
   410  	h, err := c.TrustedLightBlock(height)
   411  	if err == nil {
   412  		c.logger.Debug("header has already been verified", "height", height, "hash", h.Hash())
   413  		// Return already trusted light block
   414  		return h, nil
   415  	}
   416  
   417  	// Request the light block from primary
   418  	l, err := c.lightBlockFromPrimary(ctx, height)
   419  	if err != nil {
   420  		return nil, err
   421  	}
   422  
   423  	return l, c.verifyLightBlock(ctx, l, now)
   424  }
   425  
   426  // VerifyHeader verifies a new header against the trusted state. It returns
   427  // immediately if newHeader exists in trustedStore (no verification is
   428  // needed). Else it performs one of the two types of verification:
   429  //
   430  // SequentialVerification: verifies that 2/3 of the trusted validator set has
   431  // signed the new header. If the headers are not adjacent, **all** intermediate
   432  // headers will be requested. Intermediate headers are not saved to database.
   433  //
   434  // SkippingVerification(trustLevel): verifies that {trustLevel} of the trusted
   435  // validator set has signed the new header. If it's not the case and the
   436  // headers are not adjacent, verifySkipping is performed and necessary (not all)
   437  // intermediate headers will be requested. See the specification for details.
   438  // Intermediate headers are not saved to database.
   439  // https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md
   440  //
   441  // If the header, which is older than the currently trusted header, is
   442  // requested and the light client does not have it, VerifyHeader will perform:
   443  //		a) verifySkipping verification if nearest trusted header is found & not expired
   444  //		b) backwards verification in all other cases
   445  //
   446  // It returns ErrOldHeaderExpired if the latest trusted header expired.
   447  //
   448  // If the primary provides an invalid header (ErrInvalidHeader), it is rejected
   449  // and replaced by another provider until all are exhausted.
   450  //
   451  // If, at any moment, a LightBlock is not found by the primary provider as part of
   452  // verification then the provider will be replaced by another and the process will
   453  // restart.
   454  func (c *Client) VerifyHeader(ctx context.Context, newHeader *types.Header, now time.Time) error {
   455  	if newHeader == nil {
   456  		return errors.New("nil header")
   457  	}
   458  	if newHeader.Height <= 0 {
   459  		return errors.New("negative or zero height")
   460  	}
   461  
   462  	// Check if newHeader already verified.
   463  	l, err := c.TrustedLightBlock(newHeader.Height)
   464  	if err == nil {
   465  		// Make sure it's the same header.
   466  		if !bytes.Equal(l.Hash(), newHeader.Hash()) {
   467  			return fmt.Errorf("existing trusted header %X does not match newHeader %X", l.Hash(), newHeader.Hash())
   468  		}
   469  		c.logger.Debug("header has already been verified",
   470  			"height", newHeader.Height, "hash", newHeader.Hash())
   471  		return nil
   472  	}
   473  
   474  	// Request the header and the vals.
   475  	l, err = c.lightBlockFromPrimary(ctx, newHeader.Height)
   476  	if err != nil {
   477  		return fmt.Errorf("failed to retrieve light block from primary to verify against: %w", err)
   478  	}
   479  
   480  	if !bytes.Equal(l.Hash(), newHeader.Hash()) {
   481  		return fmt.Errorf("header from primary %X does not match newHeader %X", l.Hash(), newHeader.Hash())
   482  	}
   483  
   484  	return c.verifyLightBlock(ctx, l, now)
   485  }
   486  
   487  func (c *Client) verifyLightBlock(ctx context.Context, newLightBlock *types.LightBlock, now time.Time) error {
   488  	c.logger.Info("verify light block", "height", newLightBlock.Height, "hash", newLightBlock.Hash())
   489  
   490  	var (
   491  		verifyFunc func(ctx context.Context, trusted *types.LightBlock, new *types.LightBlock, now time.Time) error
   492  		err        error
   493  	)
   494  
   495  	switch c.verificationMode {
   496  	case sequential:
   497  		verifyFunc = c.verifySequential
   498  	case skipping:
   499  		verifyFunc = c.verifySkippingAgainstPrimary
   500  	default:
   501  		panic(fmt.Sprintf("Unknown verification mode: %b", c.verificationMode))
   502  	}
   503  
   504  	firstBlockHeight, err := c.FirstTrustedHeight()
   505  	if err != nil {
   506  		return fmt.Errorf("can't get first light block height: %w", err)
   507  	}
   508  
   509  	switch {
   510  	// Verifying forwards
   511  	case newLightBlock.Height >= c.latestTrustedBlock.Height:
   512  		err = verifyFunc(ctx, c.latestTrustedBlock, newLightBlock, now)
   513  
   514  	// Verifying backwards
   515  	case newLightBlock.Height < firstBlockHeight:
   516  		var firstBlock *types.LightBlock
   517  		firstBlock, err = c.trustedStore.LightBlock(firstBlockHeight)
   518  		if err != nil {
   519  			return fmt.Errorf("can't get first light block: %w", err)
   520  		}
   521  		err = c.backwards(ctx, firstBlock.Header, newLightBlock.Header)
   522  
   523  	// Verifying between first and last trusted light block. In this situation
   524  	// we find the closest block prior to the target height then perform
   525  	// verification forwards.
   526  	default:
   527  		var closestBlock *types.LightBlock
   528  		closestBlock, err = c.trustedStore.LightBlockBefore(newLightBlock.Height)
   529  		if err != nil {
   530  			return fmt.Errorf("can't get signed header before height %d: %w", newLightBlock.Height, err)
   531  		}
   532  		err = verifyFunc(ctx, closestBlock, newLightBlock, now)
   533  	}
   534  	if err != nil {
   535  		c.logger.Error("failed to verify", "err", err)
   536  		return err
   537  	}
   538  
   539  	// Once verified, save and return
   540  	return c.updateTrustedLightBlock(newLightBlock)
   541  }
   542  
   543  // see VerifyHeader
   544  func (c *Client) verifySequential(
   545  	ctx context.Context,
   546  	trustedBlock *types.LightBlock,
   547  	newLightBlock *types.LightBlock,
   548  	now time.Time) error {
   549  
   550  	var (
   551  		verifiedBlock = trustedBlock
   552  		interimBlock  *types.LightBlock
   553  		err           error
   554  		trace         = []*types.LightBlock{trustedBlock}
   555  	)
   556  
   557  	for height := trustedBlock.Height + 1; height <= newLightBlock.Height; height++ {
   558  		// 1) Fetch interim light block if needed.
   559  		if height == newLightBlock.Height { // last light block
   560  			interimBlock = newLightBlock
   561  		} else { // intermediate light blocks
   562  			interimBlock, err = c.lightBlockFromPrimary(ctx, height)
   563  			if err != nil {
   564  				return ErrVerificationFailed{From: verifiedBlock.Height, To: height, Reason: err}
   565  			}
   566  		}
   567  
   568  		// 2) Verify them
   569  		c.logger.Debug("verify adjacent newLightBlock against verifiedBlock",
   570  			"trustedHeight", verifiedBlock.Height,
   571  			"trustedHash", verifiedBlock.Hash(),
   572  			"newHeight", interimBlock.Height,
   573  			"newHash", interimBlock.Hash())
   574  
   575  		err = VerifyAdjacent(verifiedBlock.SignedHeader, interimBlock.SignedHeader, interimBlock.ValidatorSet,
   576  			c.trustingPeriod, now, c.maxClockDrift)
   577  		if err != nil {
   578  			err := ErrVerificationFailed{From: verifiedBlock.Height, To: interimBlock.Height, Reason: err}
   579  
   580  			switch errors.Unwrap(err).(type) {
   581  			case ErrInvalidHeader:
   582  				// If the target header is invalid, return immediately.
   583  				if err.To == newLightBlock.Height {
   584  					c.logger.Debug("target header is invalid", "err", err)
   585  					return err
   586  				}
   587  
   588  				// If some intermediate header is invalid, remove the primary and try again.
   589  				c.logger.Info("primary sent invalid header -> removing", "err", err, "primary", c.primary)
   590  
   591  				replacementBlock, removeErr := c.findNewPrimary(ctx, newLightBlock.Height, true)
   592  				if removeErr != nil {
   593  					c.logger.Debug("failed to replace primary. Returning original error", "err", removeErr)
   594  					return err
   595  				}
   596  
   597  				if !bytes.Equal(replacementBlock.Hash(), newLightBlock.Hash()) {
   598  					c.logger.Debug("replaced primary but new primary has a different block to the initial one")
   599  					return err
   600  				}
   601  
   602  				// attempt to verify header again
   603  				height--
   604  
   605  				continue
   606  			default:
   607  				return err
   608  			}
   609  		}
   610  
   611  		// 3) Update verifiedBlock
   612  		verifiedBlock = interimBlock
   613  
   614  		// 4) Add verifiedBlock to trace
   615  		trace = append(trace, verifiedBlock)
   616  	}
   617  
   618  	// Compare header with the witnesses to ensure it's not a fork.
   619  	// More witnesses we have, more chance to notice one.
   620  	//
   621  	// CORRECTNESS ASSUMPTION: there's at least 1 correct full node
   622  	// (primary or one of the witnesses).
   623  	return c.detectDivergence(ctx, trace, now)
   624  }
   625  
   626  // see VerifyHeader
   627  //
   628  // verifySkipping finds the middle light block between a trusted and new light block,
   629  // reiterating the action until it verifies a light block. A cache of light blocks
   630  // requested from source is kept such that when a verification is made, and the
   631  // light client tries again to verify the new light block in the middle, the light
   632  // client does not need to ask for all the same light blocks again.
   633  //
   634  // If this function errors, it should always wrap it in a `ErrVerifcationFailed`
   635  // struct so that the calling function can determine where it failed and handle
   636  // it accordingly.
   637  func (c *Client) verifySkipping(
   638  	ctx context.Context,
   639  	source provider.Provider,
   640  	trustedBlock *types.LightBlock,
   641  	newLightBlock *types.LightBlock,
   642  	now time.Time) ([]*types.LightBlock, error) {
   643  
   644  	var (
   645  		// The block cache is ordered in height from highest to lowest. We start
   646  		// with the newLightBlock and for any height requested in between we add
   647  		// it.
   648  		blockCache = []*types.LightBlock{newLightBlock}
   649  		depth      = 0
   650  
   651  		verifiedBlock = trustedBlock
   652  		trace         = []*types.LightBlock{trustedBlock}
   653  	)
   654  
   655  	for {
   656  		c.logger.Debug("verify non-adjacent newHeader against verifiedBlock",
   657  			"trustedHeight", verifiedBlock.Height,
   658  			"trustedHash", verifiedBlock.Hash(),
   659  			"newHeight", blockCache[depth].Height,
   660  			"newHash", blockCache[depth].Hash())
   661  
   662  		// Verify the untrusted header. This function is equivalent to
   663  		// ValidAndVerified in the spec
   664  		err := Verify(verifiedBlock.SignedHeader, verifiedBlock.ValidatorSet, blockCache[depth].SignedHeader,
   665  			blockCache[depth].ValidatorSet, c.trustingPeriod, now, c.maxClockDrift, c.trustLevel)
   666  		switch err.(type) {
   667  		case nil:
   668  			// If we have verified the last header then depth will be 0 and we
   669  			// can return a success along with the trace of intermediate headers
   670  			if depth == 0 {
   671  				trace = append(trace, newLightBlock)
   672  				return trace, nil
   673  			}
   674  			// If not, update the lower bound to the previous upper bound
   675  			verifiedBlock = blockCache[depth]
   676  			// Remove the light block at the lower bound in the header cache - it will no longer be needed
   677  			blockCache = blockCache[:depth]
   678  			// Reset the cache depth so that we start from the upper bound again
   679  			depth = 0
   680  			// add verifiedBlock to the trace
   681  			trace = append(trace, verifiedBlock)
   682  
   683  		case ErrNewValSetCantBeTrusted:
   684  			// the light block current passed validation, but the validator
   685  			// set is too different to verify it. We keep the block because it
   686  			// may become valuable later on.
   687  			//
   688  			// If we have reached the end of the cache we need to request a
   689  			// completely new block else we recycle a previously requested one.
   690  			// In both cases we are taking a block with a closer height to the
   691  			// previously verified one in the hope that it has a better chance
   692  			// of having a similar validator set
   693  			if depth == len(blockCache)-1 {
   694  				// schedule what the next height we need to fetch is
   695  				pivotHeight := c.schedule(verifiedBlock.Height, blockCache[depth].Height)
   696  				interimBlock, providerErr := source.LightBlock(ctx, pivotHeight)
   697  				if providerErr != nil {
   698  					return nil, ErrVerificationFailed{From: verifiedBlock.Height, To: pivotHeight, Reason: providerErr}
   699  				}
   700  				blockCache = append(blockCache, interimBlock)
   701  			}
   702  			depth++
   703  
   704  		// for any verification error we abort the operation and return the error
   705  		default:
   706  			return nil, ErrVerificationFailed{From: verifiedBlock.Height, To: blockCache[depth].Height, Reason: err}
   707  		}
   708  	}
   709  }
   710  
   711  // schedule works out the next height to attempt sequential verification
   712  func (c *Client) schedule(lastVerifiedHeight, lastFailedHeight int64) int64 {
   713  	return lastVerifiedHeight +
   714  		(lastFailedHeight-lastVerifiedHeight)*verifySkippingNumerator/verifySkippingDenominator
   715  }
   716  
   717  // verifySkippingAgainstPrimary does verifySkipping plus it compares new header with
   718  // witnesses and replaces primary if it sends the light client an invalid header
   719  func (c *Client) verifySkippingAgainstPrimary(
   720  	ctx context.Context,
   721  	trustedBlock *types.LightBlock,
   722  	newLightBlock *types.LightBlock,
   723  	now time.Time) error {
   724  
   725  	trace, err := c.verifySkipping(ctx, c.primary, trustedBlock, newLightBlock, now)
   726  	if err == nil {
   727  		// Success! Now compare the header with the witnesses to ensure it's not a fork.
   728  		// More witnesses we have, more chance to notice one.
   729  		//
   730  		// CORRECTNESS ASSUMPTION: there's at least 1 correct full node
   731  		// (primary or one of the witnesses).
   732  		if cmpErr := c.detectDivergence(ctx, trace, now); cmpErr != nil {
   733  			return cmpErr
   734  		}
   735  	}
   736  
   737  	var e = &ErrVerificationFailed{}
   738  	// all errors from verify skipping should be `ErrVerificationFailed`
   739  	// if it's not we just return the error directly
   740  	if !errors.As(err, e) {
   741  		return err
   742  	}
   743  
   744  	replace := true
   745  	switch e.Reason.(type) {
   746  	// Verification returned an invalid header
   747  	case ErrInvalidHeader:
   748  		// If it was the target header, return immediately.
   749  		if e.To == newLightBlock.Height {
   750  			c.logger.Debug("target header is invalid", "err", err)
   751  			return err
   752  		}
   753  
   754  		// If some intermediate header is invalid, remove the primary and try
   755  		// again.
   756  
   757  	// An intermediate header expired. We can no longer validate it as there is
   758  	// no longer the ability to punish invalid blocks as evidence of misbehavior
   759  	case ErrOldHeaderExpired:
   760  		return err
   761  
   762  	// This happens if there was a problem in finding the next block or a
   763  	// context was canceled.
   764  	default:
   765  		if errors.Is(e.Reason, context.Canceled) || errors.Is(e.Reason, context.DeadlineExceeded) {
   766  			return e.Reason
   767  		}
   768  
   769  		if !c.providerShouldBeRemoved(e.Reason) {
   770  			replace = false
   771  		}
   772  	}
   773  
   774  	// if we've reached here we're attempting to retry verification with a
   775  	// different provider
   776  	c.logger.Info("primary returned error", "err", e, "primary", c.primary, "replace", replace)
   777  
   778  	replacementBlock, removeErr := c.findNewPrimary(ctx, newLightBlock.Height, replace)
   779  	if removeErr != nil {
   780  		c.logger.Error("failed to replace primary. Returning original error", "err", removeErr)
   781  		return e.Reason
   782  	}
   783  
   784  	if !bytes.Equal(replacementBlock.Hash(), newLightBlock.Hash()) {
   785  		c.logger.Debug("replaced primary but new primary has a different block to the initial one. Returning original error")
   786  		return e.Reason
   787  	}
   788  
   789  	// attempt to verify the header again from the trusted block
   790  	return c.verifySkippingAgainstPrimary(ctx, trustedBlock, replacementBlock, now)
   791  }
   792  
   793  // LastTrustedHeight returns a last trusted height. -1 and nil are returned if
   794  // there are no trusted headers.
   795  //
   796  // Safe for concurrent use by multiple goroutines.
   797  func (c *Client) LastTrustedHeight() (int64, error) {
   798  	return c.trustedStore.LastLightBlockHeight()
   799  }
   800  
   801  // FirstTrustedHeight returns a first trusted height. -1 and nil are returned if
   802  // there are no trusted headers.
   803  //
   804  // Safe for concurrent use by multiple goroutines.
   805  func (c *Client) FirstTrustedHeight() (int64, error) {
   806  	return c.trustedStore.FirstLightBlockHeight()
   807  }
   808  
   809  // ChainID returns the chain ID the light client was configured with.
   810  //
   811  // Safe for concurrent use by multiple goroutines.
   812  func (c *Client) ChainID() string {
   813  	return c.chainID
   814  }
   815  
   816  // Primary returns the primary provider.
   817  //
   818  // NOTE: provider may be not safe for concurrent access.
   819  func (c *Client) Primary() provider.Provider {
   820  	c.providerMutex.Lock()
   821  	defer c.providerMutex.Unlock()
   822  	return c.primary
   823  }
   824  
   825  // Witnesses returns the witness providers.
   826  //
   827  // NOTE: providers may be not safe for concurrent access.
   828  func (c *Client) Witnesses() []provider.Provider {
   829  	c.providerMutex.Lock()
   830  	defer c.providerMutex.Unlock()
   831  	return c.witnesses
   832  }
   833  
   834  // AddProvider adds a providers to the light clients set
   835  //
   836  // NOTE: The light client does not check for uniqueness
   837  func (c *Client) AddProvider(p provider.Provider) {
   838  	c.providerMutex.Lock()
   839  	defer c.providerMutex.Unlock()
   840  	c.witnesses = append(c.witnesses, p)
   841  }
   842  
   843  // Cleanup removes all the data (headers and validator sets) stored. Note: the
   844  // client must be stopped at this point.
   845  func (c *Client) Cleanup() error {
   846  	c.logger.Info("removing all light blocks")
   847  	c.latestTrustedBlock = nil
   848  	return c.trustedStore.Prune(0)
   849  }
   850  
   851  func (c *Client) updateTrustedLightBlock(l *types.LightBlock) error {
   852  	c.logger.Debug("updating trusted light block", "light_block", l)
   853  
   854  	if err := c.trustedStore.SaveLightBlock(l); err != nil {
   855  		return fmt.Errorf("failed to save trusted header: %w", err)
   856  	}
   857  
   858  	if c.pruningSize > 0 {
   859  		if err := c.trustedStore.Prune(c.pruningSize); err != nil {
   860  			return fmt.Errorf("prune: %w", err)
   861  		}
   862  	}
   863  
   864  	if c.latestTrustedBlock == nil || l.Height > c.latestTrustedBlock.Height {
   865  		c.latestTrustedBlock = l
   866  	}
   867  
   868  	return nil
   869  }
   870  
   871  // backwards verification (see VerifyHeaderBackwards func in the spec) verifies
   872  // headers before a trusted header. If a sent header is invalid the primary is
   873  // replaced with another provider and the operation is repeated.
   874  func (c *Client) backwards(
   875  	ctx context.Context,
   876  	trustedHeader *types.Header,
   877  	newHeader *types.Header) error {
   878  
   879  	var (
   880  		verifiedHeader = trustedHeader
   881  		interimHeader  *types.Header
   882  	)
   883  
   884  	for verifiedHeader.Height > newHeader.Height {
   885  		interimBlock, err := c.lightBlockFromPrimary(ctx, verifiedHeader.Height-1)
   886  		if err != nil {
   887  			return fmt.Errorf("failed to obtain the header at height #%d: %w", verifiedHeader.Height-1, err)
   888  		}
   889  		interimHeader = interimBlock.Header
   890  		c.logger.Debug("verify newHeader against verifiedHeader",
   891  			"trustedHeight", verifiedHeader.Height,
   892  			"trustedHash", verifiedHeader.Hash(),
   893  			"newHeight", interimHeader.Height,
   894  			"newHash", interimHeader.Hash())
   895  		if err := VerifyBackwards(interimHeader, verifiedHeader); err != nil {
   896  			// verification has failed
   897  			c.logger.Info("backwards verification failed, replacing primary...", "err", err, "primary", c.primary)
   898  
   899  			// the client tries to see if it can get a witness to continue with the request
   900  			newPrimarysBlock, replaceErr := c.findNewPrimary(ctx, newHeader.Height, true)
   901  			if replaceErr != nil {
   902  				c.logger.Debug("failed to replace primary. Returning original error", "err", replaceErr)
   903  				return err
   904  			}
   905  
   906  			// before continuing we must check that they have the same target header to validate
   907  			if !bytes.Equal(newPrimarysBlock.Hash(), newHeader.Hash()) {
   908  				c.logger.Debug("replaced primary but new primary has a different block to the initial one")
   909  				// return the original error
   910  				return err
   911  			}
   912  
   913  			// try again with the new primary
   914  			return c.backwards(ctx, verifiedHeader, newPrimarysBlock.Header)
   915  		}
   916  		verifiedHeader = interimHeader
   917  	}
   918  
   919  	return nil
   920  }
   921  
   922  // lightBlockFromPrimary retrieves the lightBlock from the primary provider
   923  // at the specified height. This method also handles provider behavior as follows:
   924  //
   925  // 1. If the provider does not respond or does not have the block, it tries again
   926  //    with a different provider
   927  // 2. If all providers return the same error, the light client forwards the error to
   928  //    where the initial request came from
   929  // 3. If the provider provides an invalid light block, is deemed unreliable or returns
   930  //    any other error, the primary is permanently dropped and is replaced by a witness.
   931  func (c *Client) lightBlockFromPrimary(ctx context.Context, height int64) (*types.LightBlock, error) {
   932  	c.providerMutex.Lock()
   933  	l, err := c.primary.LightBlock(ctx, height)
   934  	c.providerMutex.Unlock()
   935  
   936  	switch err {
   937  	case nil:
   938  		// Everything went smoothly. We reset the lightBlockRequests and return the light block
   939  		return l, nil
   940  
   941  	// catch canceled contexts or deadlines
   942  	case context.Canceled, context.DeadlineExceeded:
   943  		return nil, err
   944  
   945  	case provider.ErrNoResponse, provider.ErrLightBlockNotFound, provider.ErrHeightTooHigh:
   946  		// we find a new witness to replace the primary
   947  		c.logger.Info("error from light block request from primary, replacing...",
   948  			"error", err, "height", height, "primary", c.primary)
   949  		return c.findNewPrimary(ctx, height, false)
   950  
   951  	default:
   952  		// The light client has most likely received either provider.ErrUnreliableProvider or provider.ErrBadLightBlock
   953  		// These errors mean that the light client should drop the primary and try with another provider instead
   954  		c.logger.Info("error from light block request from primary, removing...",
   955  			"error", err, "height", height, "primary", c.primary)
   956  		return c.findNewPrimary(ctx, height, true)
   957  	}
   958  }
   959  
   960  // NOTE: requires a providerMutex lock
   961  func (c *Client) removeWitnesses(indexes []int) error {
   962  	// check that we will still have witnesses remaining
   963  	if len(c.witnesses) <= len(indexes) {
   964  		return ErrNoWitnesses
   965  	}
   966  
   967  	// we need to make sure that we remove witnesses by index in the reverse
   968  	// order so as to not affect the indexes themselves
   969  	sort.Ints(indexes)
   970  	for i := len(indexes) - 1; i >= 0; i-- {
   971  		c.witnesses[indexes[i]] = c.witnesses[len(c.witnesses)-1]
   972  		c.witnesses = c.witnesses[:len(c.witnesses)-1]
   973  	}
   974  
   975  	return nil
   976  }
   977  
   978  type witnessResponse struct {
   979  	lb           *types.LightBlock
   980  	witnessIndex int
   981  	err          error
   982  }
   983  
   984  // findNewPrimary concurrently sends a light block request, promoting the first witness to return
   985  // a valid light block as the new primary. The remove option indicates whether the primary should be
   986  // entire removed or just appended to the back of the witnesses list. This method also handles witness
   987  // errors. If no witness is available, it returns the last error of the witness.
   988  func (c *Client) findNewPrimary(ctx context.Context, height int64, remove bool) (*types.LightBlock, error) {
   989  	c.providerMutex.Lock()
   990  	defer c.providerMutex.Unlock()
   991  
   992  	if len(c.witnesses) <= 1 {
   993  		return nil, ErrNoWitnesses
   994  	}
   995  
   996  	var (
   997  		witnessResponsesC = make(chan witnessResponse, len(c.witnesses))
   998  		witnessesToRemove []int
   999  		lastError         error
  1000  		wg                sync.WaitGroup
  1001  	)
  1002  
  1003  	// send out a light block request to all witnesses
  1004  	subctx, cancel := context.WithCancel(ctx)
  1005  	defer cancel()
  1006  	for index := range c.witnesses {
  1007  		wg.Add(1)
  1008  		go func(witnessIndex int, witnessResponsesC chan witnessResponse) {
  1009  			defer wg.Done()
  1010  
  1011  			lb, err := c.witnesses[witnessIndex].LightBlock(subctx, height)
  1012  			witnessResponsesC <- witnessResponse{lb, witnessIndex, err}
  1013  		}(index, witnessResponsesC)
  1014  	}
  1015  
  1016  	// process all the responses as they come in
  1017  	for i := 0; i < cap(witnessResponsesC); i++ {
  1018  		response := <-witnessResponsesC
  1019  		switch response.err {
  1020  		// success! We have found a new primary
  1021  		case nil:
  1022  			cancel() // cancel all remaining requests to other witnesses
  1023  
  1024  			wg.Wait() // wait for all goroutines to finish
  1025  
  1026  			// if we are not intending on removing the primary then append the old primary to the end of the witness slice
  1027  			if !remove {
  1028  				c.witnesses = append(c.witnesses, c.primary)
  1029  			}
  1030  
  1031  			// promote respondent as the new primary
  1032  			c.logger.Debug("found new primary", "primary", c.witnesses[response.witnessIndex])
  1033  			c.primary = c.witnesses[response.witnessIndex]
  1034  
  1035  			// add promoted witness to the list of witnesses to be removed
  1036  			witnessesToRemove = append(witnessesToRemove, response.witnessIndex)
  1037  
  1038  			// remove witnesses marked as bad (the client must do this before we alter the witness slice and change the indexes
  1039  			// of witnesses). Removal is done in descending order
  1040  			if err := c.removeWitnesses(witnessesToRemove); err != nil {
  1041  				return nil, err
  1042  			}
  1043  
  1044  			// return the light block that new primary responded with
  1045  			return response.lb, nil
  1046  
  1047  		// catch canceled contexts or deadlines
  1048  		case context.Canceled, context.DeadlineExceeded:
  1049  			return nil, response.err
  1050  
  1051  		// process benign errors by logging them only
  1052  		case provider.ErrNoResponse, provider.ErrLightBlockNotFound, provider.ErrHeightTooHigh:
  1053  			lastError = response.err
  1054  			c.logger.Info("error on light block request from witness",
  1055  				"error", response.err, "primary", c.witnesses[response.witnessIndex])
  1056  			continue
  1057  
  1058  		// process malevolent errors like ErrUnreliableProvider and ErrBadLightBlock by removing the witness
  1059  		default:
  1060  			lastError = response.err
  1061  			c.logger.Error("error on light block request from witness, removing...",
  1062  				"error", response.err, "primary", c.witnesses[response.witnessIndex])
  1063  			witnessesToRemove = append(witnessesToRemove, response.witnessIndex)
  1064  		}
  1065  	}
  1066  
  1067  	return nil, lastError
  1068  }
  1069  
  1070  // compareFirstHeaderWithWitnesses concurrently compares h with all witnesses. If any
  1071  // witness reports a different header than h, the function returns an error.
  1072  func (c *Client) compareFirstHeaderWithWitnesses(ctx context.Context, h *types.SignedHeader) error {
  1073  	compareCtx, cancel := context.WithCancel(ctx)
  1074  	defer cancel()
  1075  
  1076  	c.providerMutex.Lock()
  1077  	defer c.providerMutex.Unlock()
  1078  
  1079  	if len(c.witnesses) < 1 {
  1080  		return ErrNoWitnesses
  1081  	}
  1082  
  1083  	errc := make(chan error, len(c.witnesses))
  1084  	for i, witness := range c.witnesses {
  1085  		go c.compareNewHeaderWithWitness(compareCtx, errc, h, witness, i)
  1086  	}
  1087  
  1088  	witnessesToRemove := make([]int, 0, len(c.witnesses))
  1089  
  1090  	// handle errors from the header comparisons as they come in
  1091  	for i := 0; i < cap(errc); i++ {
  1092  		err := <-errc
  1093  
  1094  		switch e := err.(type) {
  1095  		case nil:
  1096  			continue
  1097  		case errConflictingHeaders:
  1098  			c.logger.Error(`witness has a different header. Please check primary is
  1099  correct and remove witness. Otherwise, use a different primary`,
  1100  				"Witness", c.witnesses[e.WitnessIndex], "ExpHeader", h.Hash(), "GotHeader", e.Block.Hash())
  1101  			return err
  1102  		case errBadWitness:
  1103  			// If witness sent us an invalid header, then remove it
  1104  			c.logger.Info("witness returned an error, removing...",
  1105  				"err", err)
  1106  			witnessesToRemove = append(witnessesToRemove, e.WitnessIndex)
  1107  		default:
  1108  			// check for canceled contexts or deadlines
  1109  			if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
  1110  				return err
  1111  			}
  1112  
  1113  			// the witness either didn't respond or didn't have the block. We ignore it.
  1114  			c.logger.Debug("unable to compare first header with witness, ignoring",
  1115  				"err", err)
  1116  		}
  1117  
  1118  	}
  1119  
  1120  	// remove all witnesses that misbehaved
  1121  	return c.removeWitnesses(witnessesToRemove)
  1122  }
  1123  
  1124  // providerShouldBeRemoved analyzes the nature of the error and whether the provider
  1125  // should be removed from the light clients set
  1126  func (c *Client) providerShouldBeRemoved(err error) bool {
  1127  	return errors.As(err, &provider.ErrUnreliableProvider{}) ||
  1128  		errors.As(err, &provider.ErrBadLightBlock{}) ||
  1129  		errors.Is(err, provider.ErrConnectionClosed)
  1130  }