github.com/soomindae/tendermint@v0.0.5-0.20210528140126-84a0c70c8162/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/soomindae/tendermint/libs/log"
    13  	tmmath "github.com/soomindae/tendermint/libs/math"
    14  	tmsync "github.com/soomindae/tendermint/libs/sync"
    15  	"github.com/soomindae/tendermint/light/provider"
    16  	"github.com/soomindae/tendermint/light/store"
    17  	"github.com/soomindae/tendermint/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) < 1 {
   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/soomindae/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  				if providerErr != nil {
   752  					return nil, ErrVerificationFailed{From: verifiedBlock.Height, To: pivotHeight, Reason: providerErr}
   753  				}
   754  				blockCache = append(blockCache, interimBlock)
   755  			}
   756  			depth++
   757  
   758  		default:
   759  			return nil, ErrVerificationFailed{From: verifiedBlock.Height, To: blockCache[depth].Height, Reason: err}
   760  		}
   761  	}
   762  }
   763  
   764  // verifySkippingAgainstPrimary does verifySkipping plus it compares new header with
   765  // witnesses and replaces primary if it sends the light client an invalid header
   766  func (c *Client) verifySkippingAgainstPrimary(
   767  	ctx context.Context,
   768  	trustedBlock *types.LightBlock,
   769  	newLightBlock *types.LightBlock,
   770  	now time.Time) error {
   771  
   772  	trace, err := c.verifySkipping(ctx, c.primary, trustedBlock, newLightBlock, now)
   773  
   774  	switch errors.Unwrap(err).(type) {
   775  	case ErrInvalidHeader:
   776  		// If the target header is invalid, return immediately.
   777  		invalidHeaderHeight := err.(ErrVerificationFailed).To
   778  		if invalidHeaderHeight == newLightBlock.Height {
   779  			c.logger.Debug("Target header is invalid", "err", err)
   780  			return err
   781  		}
   782  
   783  		// If some intermediate header is invalid, replace the primary and try
   784  		// again.
   785  		c.logger.Error("primary sent invalid header -> replacing", "err", err)
   786  
   787  		replacementBlock, removeErr := c.findNewPrimary(ctx, newLightBlock.Height, true)
   788  		if removeErr != nil {
   789  			c.logger.Error("failed to replace primary. Returning original error", "err", removeErr)
   790  			return err
   791  		}
   792  
   793  		if !bytes.Equal(replacementBlock.Hash(), newLightBlock.Hash()) {
   794  			c.logger.Error("Replacement provider has a different light block",
   795  				"newHash", newLightBlock.Hash(),
   796  				"replHash", replacementBlock.Hash())
   797  			// return original error
   798  			return err
   799  		}
   800  
   801  		// attempt to verify the header again
   802  		return c.verifySkippingAgainstPrimary(ctx, trustedBlock, replacementBlock, now)
   803  	case nil:
   804  		// Compare header with the witnesses to ensure it's not a fork.
   805  		// More witnesses we have, more chance to notice one.
   806  		//
   807  		// CORRECTNESS ASSUMPTION: there's at least 1 correct full node
   808  		// (primary or one of the witnesses).
   809  		if cmpErr := c.detectDivergence(ctx, trace, now); cmpErr != nil {
   810  			return cmpErr
   811  		}
   812  	default:
   813  		return err
   814  	}
   815  
   816  	return nil
   817  }
   818  
   819  // LastTrustedHeight returns a last trusted height. -1 and nil are returned if
   820  // there are no trusted headers.
   821  //
   822  // Safe for concurrent use by multiple goroutines.
   823  func (c *Client) LastTrustedHeight() (int64, error) {
   824  	return c.trustedStore.LastLightBlockHeight()
   825  }
   826  
   827  // FirstTrustedHeight returns a first trusted height. -1 and nil are returned if
   828  // there are no trusted headers.
   829  //
   830  // Safe for concurrent use by multiple goroutines.
   831  func (c *Client) FirstTrustedHeight() (int64, error) {
   832  	return c.trustedStore.FirstLightBlockHeight()
   833  }
   834  
   835  // ChainID returns the chain ID the light client was configured with.
   836  //
   837  // Safe for concurrent use by multiple goroutines.
   838  func (c *Client) ChainID() string {
   839  	return c.chainID
   840  }
   841  
   842  // Primary returns the primary provider.
   843  //
   844  // NOTE: provider may be not safe for concurrent access.
   845  func (c *Client) Primary() provider.Provider {
   846  	c.providerMutex.Lock()
   847  	defer c.providerMutex.Unlock()
   848  	return c.primary
   849  }
   850  
   851  // Witnesses returns the witness providers.
   852  //
   853  // NOTE: providers may be not safe for concurrent access.
   854  func (c *Client) Witnesses() []provider.Provider {
   855  	c.providerMutex.Lock()
   856  	defer c.providerMutex.Unlock()
   857  	return c.witnesses
   858  }
   859  
   860  // Cleanup removes all the data (headers and validator sets) stored. Note: the
   861  // client must be stopped at this point.
   862  func (c *Client) Cleanup() error {
   863  	c.logger.Info("Removing all the data")
   864  	c.latestTrustedBlock = nil
   865  	return c.trustedStore.Prune(0)
   866  }
   867  
   868  // cleanupAfter deletes all headers & validator sets after +height+. It also
   869  // resets latestTrustedBlock to the latest header.
   870  func (c *Client) cleanupAfter(height int64) error {
   871  	prevHeight := c.latestTrustedBlock.Height
   872  
   873  	for {
   874  		h, err := c.trustedStore.LightBlockBefore(prevHeight)
   875  		if err == store.ErrLightBlockNotFound || (h != nil && h.Height <= height) {
   876  			break
   877  		} else if err != nil {
   878  			return fmt.Errorf("failed to get header before %d: %w", prevHeight, err)
   879  		}
   880  
   881  		err = c.trustedStore.DeleteLightBlock(h.Height)
   882  		if err != nil {
   883  			c.logger.Error("can't remove a trusted header & validator set", "err", err,
   884  				"height", h.Height)
   885  		}
   886  
   887  		prevHeight = h.Height
   888  	}
   889  
   890  	c.latestTrustedBlock = nil
   891  	err := c.restoreTrustedLightBlock()
   892  	if err != nil {
   893  		return err
   894  	}
   895  
   896  	return nil
   897  }
   898  
   899  func (c *Client) updateTrustedLightBlock(l *types.LightBlock) error {
   900  	c.logger.Debug("updating trusted light block", "light_block", l)
   901  
   902  	if err := c.trustedStore.SaveLightBlock(l); err != nil {
   903  		return fmt.Errorf("failed to save trusted header: %w", err)
   904  	}
   905  
   906  	if c.pruningSize > 0 {
   907  		if err := c.trustedStore.Prune(c.pruningSize); err != nil {
   908  			return fmt.Errorf("prune: %w", err)
   909  		}
   910  	}
   911  
   912  	if c.latestTrustedBlock == nil || l.Height > c.latestTrustedBlock.Height {
   913  		c.latestTrustedBlock = l
   914  	}
   915  
   916  	return nil
   917  }
   918  
   919  // backwards verification (see VerifyHeaderBackwards func in the spec) verifies
   920  // headers before a trusted header. If a sent header is invalid the primary is
   921  // replaced with another provider and the operation is repeated.
   922  func (c *Client) backwards(
   923  	ctx context.Context,
   924  	trustedHeader *types.Header,
   925  	newHeader *types.Header) error {
   926  
   927  	var (
   928  		verifiedHeader = trustedHeader
   929  		interimHeader  *types.Header
   930  	)
   931  
   932  	for verifiedHeader.Height > newHeader.Height {
   933  		interimBlock, err := c.lightBlockFromPrimary(ctx, verifiedHeader.Height-1)
   934  		if err != nil {
   935  			return fmt.Errorf("failed to obtain the header at height #%d: %w", verifiedHeader.Height-1, err)
   936  		}
   937  		interimHeader = interimBlock.Header
   938  		c.logger.Debug("Verify newHeader against verifiedHeader",
   939  			"trustedHeight", verifiedHeader.Height,
   940  			"trustedHash", verifiedHeader.Hash(),
   941  			"newHeight", interimHeader.Height,
   942  			"newHash", interimHeader.Hash())
   943  		if err := VerifyBackwards(interimHeader, verifiedHeader); err != nil {
   944  			// verification has failed
   945  			c.logger.Error("backwards verification failed, replacing primary...", "err", err, "primary", c.primary)
   946  
   947  			// the client tries to see if it can get a witness to continue with the request
   948  			newPrimarysBlock, replaceErr := c.findNewPrimary(ctx, newHeader.Height, true)
   949  			if replaceErr != nil {
   950  				c.logger.Debug("failed to replace primary. Returning original error", "err", replaceErr)
   951  				return err
   952  			}
   953  
   954  			// before continuing we must check that they have the same target header to validate
   955  			if !bytes.Equal(newPrimarysBlock.Hash(), newHeader.Hash()) {
   956  				c.logger.Debug("replaced primary but new primary has a different block to the initial one")
   957  				// return the original error
   958  				return err
   959  			}
   960  
   961  			// try again with the new primary
   962  			return c.backwards(ctx, verifiedHeader, newPrimarysBlock.Header)
   963  		}
   964  		verifiedHeader = interimHeader
   965  	}
   966  
   967  	return nil
   968  }
   969  
   970  // lightBlockFromPrimary retrieves the lightBlock from the primary provider
   971  // at the specified height. This method also handles provider behavior as follows:
   972  //
   973  // 1. If the provider does not respond or does not have the block, it tries again
   974  //    with a different provider
   975  // 2. If all providers return the same error, the light client forwards the error to
   976  //    where the initial request came from
   977  // 3. If the provider provides an invalid light block, is deemed unreliable or returns
   978  //    any other error, the primary is permanently dropped and is replaced by a witness.
   979  func (c *Client) lightBlockFromPrimary(ctx context.Context, height int64) (*types.LightBlock, error) {
   980  	c.providerMutex.Lock()
   981  	l, err := c.primary.LightBlock(ctx, height)
   982  	c.providerMutex.Unlock()
   983  
   984  	switch err {
   985  	case nil:
   986  		// Everything went smoothly. We reset the lightBlockRequests and return the light block
   987  		return l, nil
   988  
   989  	case provider.ErrNoResponse, provider.ErrLightBlockNotFound:
   990  		// we find a new witness to replace the primary
   991  		c.logger.Debug("error from light block request from primary, replacing...",
   992  			"error", err, "height", height, "primary", c.primary)
   993  		return c.findNewPrimary(ctx, height, false)
   994  
   995  	default:
   996  		// The light client has most likely received either provider.ErrUnreliableProvider or provider.ErrBadLightBlock
   997  		// These errors mean that the light client should drop the primary and try with another provider instead
   998  		c.logger.Error("error from light block request from primary, removing...",
   999  			"error", err, "height", height, "primary", c.primary)
  1000  		return c.findNewPrimary(ctx, height, true)
  1001  	}
  1002  }
  1003  
  1004  // NOTE: requires a providerMutex lock
  1005  func (c *Client) removeWitnesses(indexes []int) error {
  1006  	// check that we will still have witnesses remaining
  1007  	if len(c.witnesses) <= len(indexes) {
  1008  		return ErrNoWitnesses
  1009  	}
  1010  
  1011  	// we need to make sure that we remove witnesses by index in the reverse
  1012  	// order so as to not affect the indexes themselves
  1013  	sort.Ints(indexes)
  1014  	for i := len(indexes) - 1; i >= 0; i-- {
  1015  		c.witnesses[indexes[i]] = c.witnesses[len(c.witnesses)-1]
  1016  		c.witnesses = c.witnesses[:len(c.witnesses)-1]
  1017  	}
  1018  
  1019  	return nil
  1020  }
  1021  
  1022  type witnessResponse struct {
  1023  	lb           *types.LightBlock
  1024  	witnessIndex int
  1025  	err          error
  1026  }
  1027  
  1028  // findNewPrimary concurrently sends a light block request, promoting the first witness to return
  1029  // a valid light block as the new primary. The remove option indicates whether the primary should be
  1030  // entire removed or just appended to the back of the witnesses list. This method also handles witness
  1031  // errors. If no witness is available, it returns the last error of the witness.
  1032  func (c *Client) findNewPrimary(ctx context.Context, height int64, remove bool) (*types.LightBlock, error) {
  1033  	c.providerMutex.Lock()
  1034  	defer c.providerMutex.Unlock()
  1035  
  1036  	if len(c.witnesses) <= 1 {
  1037  		return nil, ErrNoWitnesses
  1038  	}
  1039  
  1040  	var (
  1041  		witnessResponsesC = make(chan witnessResponse, len(c.witnesses))
  1042  		witnessesToRemove []int
  1043  		lastError         error
  1044  		wg                sync.WaitGroup
  1045  	)
  1046  
  1047  	// send out a light block request to all witnesses
  1048  	subctx, cancel := context.WithCancel(ctx)
  1049  	defer cancel()
  1050  	for index := range c.witnesses {
  1051  		wg.Add(1)
  1052  		go func(witnessIndex int, witnessResponsesC chan witnessResponse) {
  1053  			defer wg.Done()
  1054  
  1055  			lb, err := c.witnesses[witnessIndex].LightBlock(subctx, height)
  1056  			witnessResponsesC <- witnessResponse{lb, witnessIndex, err}
  1057  		}(index, witnessResponsesC)
  1058  	}
  1059  
  1060  	// process all the responses as they come in
  1061  	for i := 0; i < cap(witnessResponsesC); i++ {
  1062  		response := <-witnessResponsesC
  1063  		switch response.err {
  1064  		// success! We have found a new primary
  1065  		case nil:
  1066  			cancel() // cancel all remaining requests to other witnesses
  1067  
  1068  			wg.Wait() // wait for all goroutines to finish
  1069  
  1070  			// if we are not intending on removing the primary then append the old primary to the end of the witness slice
  1071  			if !remove {
  1072  				c.witnesses = append(c.witnesses, c.primary)
  1073  			}
  1074  
  1075  			// promote respondent as the new primary
  1076  			c.logger.Debug("found new primary", "primary", c.witnesses[response.witnessIndex])
  1077  			c.primary = c.witnesses[response.witnessIndex]
  1078  
  1079  			// add promoted witness to the list of witnesses to be removed
  1080  			witnessesToRemove = append(witnessesToRemove, response.witnessIndex)
  1081  
  1082  			// remove witnesses marked as bad (the client must do this before we alter the witness slice and change the indexes
  1083  			// of witnesses). Removal is done in descending order
  1084  			if err := c.removeWitnesses(witnessesToRemove); err != nil {
  1085  				return nil, err
  1086  			}
  1087  
  1088  			// return the light block that new primary responded with
  1089  			return response.lb, nil
  1090  
  1091  		// process benign errors by logging them only
  1092  		case provider.ErrNoResponse, provider.ErrLightBlockNotFound:
  1093  			lastError = response.err
  1094  			c.logger.Debug("error on light block request from witness",
  1095  				"error", response.err, "primary", c.witnesses[response.witnessIndex])
  1096  			continue
  1097  
  1098  		// process malevolent errors like ErrUnreliableProvider and ErrBadLightBlock by removing the witness
  1099  		default:
  1100  			lastError = response.err
  1101  			c.logger.Error("error on light block request from witness, removing...",
  1102  				"error", response.err, "primary", c.witnesses[response.witnessIndex])
  1103  			witnessesToRemove = append(witnessesToRemove, response.witnessIndex)
  1104  		}
  1105  	}
  1106  
  1107  	return nil, lastError
  1108  }
  1109  
  1110  // compareFirstHeaderWithWitnesses compares h with all witnesses. If any
  1111  // witness reports a different header than h, the function returns an error.
  1112  func (c *Client) compareFirstHeaderWithWitnesses(ctx context.Context, h *types.SignedHeader) error {
  1113  	compareCtx, cancel := context.WithCancel(ctx)
  1114  	defer cancel()
  1115  
  1116  	c.providerMutex.Lock()
  1117  	defer c.providerMutex.Unlock()
  1118  
  1119  	if len(c.witnesses) < 1 {
  1120  		return errNoWitnesses{}
  1121  	}
  1122  
  1123  	errc := make(chan error, len(c.witnesses))
  1124  	for i, witness := range c.witnesses {
  1125  		go c.compareNewHeaderWithWitness(compareCtx, errc, h, witness, i)
  1126  	}
  1127  
  1128  	witnessesToRemove := make([]int, 0, len(c.witnesses))
  1129  
  1130  	// handle errors from the header comparisons as they come in
  1131  	for i := 0; i < cap(errc); i++ {
  1132  		err := <-errc
  1133  
  1134  		switch e := err.(type) {
  1135  		case nil:
  1136  			continue
  1137  		case errConflictingHeaders:
  1138  			c.logger.Error(fmt.Sprintf(`Witness #%d has a different header. Please check primary is correct
  1139  and remove witness. Otherwise, use the different primary`, e.WitnessIndex), "witness", c.witnesses[e.WitnessIndex])
  1140  			return err
  1141  		case errBadWitness:
  1142  			// If witness sent us an invalid header, then remove it. If it didn't
  1143  			// respond or couldn't find the block, then we ignore it and move on to
  1144  			// the next witness.
  1145  			if _, ok := e.Reason.(provider.ErrBadLightBlock); ok {
  1146  				c.logger.Info("Witness sent us invalid header / vals -> removing it",
  1147  					"witness", c.witnesses[e.WitnessIndex], "err", err)
  1148  				witnessesToRemove = append(witnessesToRemove, e.WitnessIndex)
  1149  			}
  1150  		}
  1151  
  1152  	}
  1153  
  1154  	// remove witnesses that have misbehaved
  1155  	if err := c.removeWitnesses(witnessesToRemove); err != nil {
  1156  		return err
  1157  	}
  1158  
  1159  	return nil
  1160  }