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