github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/tendermint/lite2/client.go (about)

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