mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-30 03:35:34 +00:00
rpc/client: take context as first param (#5347)
Closes #5145 also applies to light/client
This commit is contained in:
+37
-31
@@ -2,6 +2,7 @@ package light
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
@@ -151,6 +152,7 @@ type Client struct {
|
||||
//
|
||||
// See all Option(s) for the additional configuration.
|
||||
func NewClient(
|
||||
ctx context.Context,
|
||||
chainID string,
|
||||
trustOptions TrustOptions,
|
||||
primary provider.Provider,
|
||||
@@ -169,14 +171,14 @@ func NewClient(
|
||||
|
||||
if c.latestTrustedBlock != nil {
|
||||
c.logger.Info("Checking trusted light block using options")
|
||||
if err := c.checkTrustedHeaderUsingOptions(trustOptions); err != nil {
|
||||
if err := c.checkTrustedHeaderUsingOptions(ctx, trustOptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if c.latestTrustedBlock == nil || c.latestTrustedBlock.Height < trustOptions.Height {
|
||||
c.logger.Info("Downloading trusted light block using options")
|
||||
if err := c.initializeWithTrustOptions(trustOptions); err != nil {
|
||||
if err := c.initializeWithTrustOptions(ctx, trustOptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -277,11 +279,11 @@ func (c *Client) restoreTrustedLightBlock() error {
|
||||
//
|
||||
// The intuition here is the user is always right. I.e. if she decides to reset
|
||||
// the light client with an older header, there must be a reason for it.
|
||||
func (c *Client) checkTrustedHeaderUsingOptions(options TrustOptions) error {
|
||||
func (c *Client) checkTrustedHeaderUsingOptions(ctx context.Context, options TrustOptions) error {
|
||||
var primaryHash []byte
|
||||
switch {
|
||||
case options.Height > c.latestTrustedBlock.Height:
|
||||
h, err := c.lightBlockFromPrimary(c.latestTrustedBlock.Height)
|
||||
h, err := c.lightBlockFromPrimary(ctx, c.latestTrustedBlock.Height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -336,9 +338,9 @@ func (c *Client) checkTrustedHeaderUsingOptions(options TrustOptions) error {
|
||||
|
||||
// initializeWithTrustOptions fetches the weakly-trusted light block from
|
||||
// primary provider.
|
||||
func (c *Client) initializeWithTrustOptions(options TrustOptions) error {
|
||||
func (c *Client) initializeWithTrustOptions(ctx context.Context, options TrustOptions) error {
|
||||
// 1) Fetch and verify the light block.
|
||||
l, err := c.lightBlockFromPrimary(options.Height)
|
||||
l, err := c.lightBlockFromPrimary(ctx, options.Height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -405,7 +407,7 @@ func (c *Client) compareWithLatestHeight(height int64) (int64, error) {
|
||||
// Update attempts to advance the state by downloading the latest light
|
||||
// block and verifying it. It returns a new light block on a successful
|
||||
// update. Otherwise, it returns nil (plus an error, if any).
|
||||
func (c *Client) Update(now time.Time) (*types.LightBlock, error) {
|
||||
func (c *Client) Update(ctx context.Context, now time.Time) (*types.LightBlock, error) {
|
||||
lastTrustedHeight, err := c.LastTrustedHeight()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get last trusted height: %w", err)
|
||||
@@ -416,13 +418,13 @@ func (c *Client) Update(now time.Time) (*types.LightBlock, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
latestBlock, err := c.lightBlockFromPrimary(0)
|
||||
latestBlock, err := c.lightBlockFromPrimary(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if latestBlock.Height > lastTrustedHeight {
|
||||
err = c.verifyLightBlock(latestBlock, now)
|
||||
err = c.verifyLightBlock(ctx, latestBlock, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -443,7 +445,7 @@ func (c *Client) Update(now time.Time) (*types.LightBlock, error) {
|
||||
// primary.
|
||||
//
|
||||
// It will replace the primary provider if an error from a request to the provider occurs
|
||||
func (c *Client) VerifyLightBlockAtHeight(height int64, now time.Time) (*types.LightBlock, error) {
|
||||
func (c *Client) VerifyLightBlockAtHeight(ctx context.Context, height int64, now time.Time) (*types.LightBlock, error) {
|
||||
if height <= 0 {
|
||||
return nil, errors.New("negative or zero height")
|
||||
}
|
||||
@@ -457,12 +459,12 @@ func (c *Client) VerifyLightBlockAtHeight(height int64, now time.Time) (*types.L
|
||||
}
|
||||
|
||||
// Request the light block from primary
|
||||
l, err := c.lightBlockFromPrimary(height)
|
||||
l, err := c.lightBlockFromPrimary(ctx, height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return l, c.verifyLightBlock(l, now)
|
||||
return l, c.verifyLightBlock(ctx, l, now)
|
||||
}
|
||||
|
||||
// VerifyHeader verifies a new header against the trusted state. It returns
|
||||
@@ -493,7 +495,7 @@ func (c *Client) VerifyLightBlockAtHeight(height int64, now time.Time) (*types.L
|
||||
// If, at any moment, a LightBlock is not found by the primary provider as part of
|
||||
// verification then the provider will be replaced by another and the process will
|
||||
// restart.
|
||||
func (c *Client) VerifyHeader(newHeader *types.Header, now time.Time) error {
|
||||
func (c *Client) VerifyHeader(ctx context.Context, newHeader *types.Header, now time.Time) error {
|
||||
if newHeader == nil {
|
||||
return errors.New("nil header")
|
||||
}
|
||||
@@ -514,7 +516,7 @@ func (c *Client) VerifyHeader(newHeader *types.Header, now time.Time) error {
|
||||
}
|
||||
|
||||
// Request the header and the vals.
|
||||
l, err = c.lightBlockFromPrimary(newHeader.Height)
|
||||
l, err = c.lightBlockFromPrimary(ctx, newHeader.Height)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve light block from primary to verify against: %w", err)
|
||||
}
|
||||
@@ -523,14 +525,14 @@ func (c *Client) VerifyHeader(newHeader *types.Header, now time.Time) error {
|
||||
return fmt.Errorf("light block header %X does not match newHeader %X", l.Hash(), newHeader.Hash())
|
||||
}
|
||||
|
||||
return c.verifyLightBlock(l, now)
|
||||
return c.verifyLightBlock(ctx, l, now)
|
||||
}
|
||||
|
||||
func (c *Client) verifyLightBlock(newLightBlock *types.LightBlock, now time.Time) error {
|
||||
func (c *Client) verifyLightBlock(ctx context.Context, newLightBlock *types.LightBlock, now time.Time) error {
|
||||
c.logger.Info("VerifyHeader", "height", newLightBlock.Height, "hash", hash2str(newLightBlock.Hash()))
|
||||
|
||||
var (
|
||||
verifyFunc func(trusted *types.LightBlock, new *types.LightBlock, now time.Time) error
|
||||
verifyFunc func(ctx context.Context, trusted *types.LightBlock, new *types.LightBlock, now time.Time) error
|
||||
err error
|
||||
)
|
||||
|
||||
@@ -551,7 +553,7 @@ func (c *Client) verifyLightBlock(newLightBlock *types.LightBlock, now time.Time
|
||||
switch {
|
||||
// Verifying forwards
|
||||
case newLightBlock.Height >= c.latestTrustedBlock.Height:
|
||||
err = verifyFunc(c.latestTrustedBlock, newLightBlock, now)
|
||||
err = verifyFunc(ctx, c.latestTrustedBlock, newLightBlock, now)
|
||||
|
||||
// Verifying backwards
|
||||
case newLightBlock.Height < firstBlockHeight:
|
||||
@@ -560,7 +562,7 @@ func (c *Client) verifyLightBlock(newLightBlock *types.LightBlock, now time.Time
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get first light block: %w", err)
|
||||
}
|
||||
err = c.backwards(firstBlock.Header, newLightBlock.Header)
|
||||
err = c.backwards(ctx, firstBlock.Header, newLightBlock.Header)
|
||||
|
||||
// Verifying between first and last trusted light block
|
||||
default:
|
||||
@@ -569,7 +571,7 @@ func (c *Client) verifyLightBlock(newLightBlock *types.LightBlock, now time.Time
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get signed header before height %d: %w", newLightBlock.Height, err)
|
||||
}
|
||||
err = verifyFunc(closestBlock, newLightBlock, now)
|
||||
err = verifyFunc(ctx, closestBlock, newLightBlock, now)
|
||||
}
|
||||
if err != nil {
|
||||
c.logger.Error("Can't verify", "err", err)
|
||||
@@ -582,6 +584,7 @@ func (c *Client) verifyLightBlock(newLightBlock *types.LightBlock, now time.Time
|
||||
|
||||
// see VerifyHeader
|
||||
func (c *Client) verifySequential(
|
||||
ctx context.Context,
|
||||
trustedBlock *types.LightBlock,
|
||||
newLightBlock *types.LightBlock,
|
||||
now time.Time) error {
|
||||
@@ -597,7 +600,7 @@ func (c *Client) verifySequential(
|
||||
if height == newLightBlock.Height { // last light block
|
||||
interimBlock = newLightBlock
|
||||
} else { // intermediate light blocks
|
||||
interimBlock, err = c.lightBlockFromPrimary(height)
|
||||
interimBlock, err = c.lightBlockFromPrimary(ctx, height)
|
||||
if err != nil {
|
||||
return ErrVerificationFailed{From: verifiedBlock.Height, To: height, Reason: err}
|
||||
}
|
||||
@@ -633,7 +636,7 @@ func (c *Client) verifySequential(
|
||||
return err
|
||||
}
|
||||
|
||||
replacementBlock, fErr := c.lightBlockFromPrimary(newLightBlock.Height)
|
||||
replacementBlock, fErr := c.lightBlockFromPrimary(ctx, newLightBlock.Height)
|
||||
if fErr != nil {
|
||||
c.logger.Error("Can't fetch light block from primary", "err", fErr)
|
||||
// return original error
|
||||
@@ -672,6 +675,7 @@ func (c *Client) verifySequential(
|
||||
// light client tries again to verify the new light block in the middle, the light
|
||||
// client does not need to ask for all the same light blocks again.
|
||||
func (c *Client) verifySkipping(
|
||||
ctx context.Context,
|
||||
source provider.Provider,
|
||||
trustedBlock *types.LightBlock,
|
||||
newLightBlock *types.LightBlock,
|
||||
@@ -715,7 +719,7 @@ func (c *Client) verifySkipping(
|
||||
if depth == len(blockCache)-1 {
|
||||
pivotHeight := verifiedBlock.Height + (blockCache[depth].Height-verifiedBlock.
|
||||
Height)*verifySkippingNumerator/verifySkippingDenominator
|
||||
interimBlock, providerErr := source.LightBlock(pivotHeight)
|
||||
interimBlock, providerErr := source.LightBlock(ctx, pivotHeight)
|
||||
if providerErr != nil {
|
||||
return nil, ErrVerificationFailed{From: verifiedBlock.Height, To: pivotHeight, Reason: providerErr}
|
||||
}
|
||||
@@ -732,11 +736,12 @@ func (c *Client) verifySkipping(
|
||||
// verifySkippingAgainstPrimary does verifySkipping plus it compares new header with
|
||||
// witnesses and replaces primary if it sends the light client an invalid header
|
||||
func (c *Client) verifySkippingAgainstPrimary(
|
||||
ctx context.Context,
|
||||
trustedBlock *types.LightBlock,
|
||||
newLightBlock *types.LightBlock,
|
||||
now time.Time) error {
|
||||
|
||||
trace, err := c.verifySkipping(c.primary, trustedBlock, newLightBlock, now)
|
||||
trace, err := c.verifySkipping(ctx, c.primary, trustedBlock, newLightBlock, now)
|
||||
|
||||
switch errors.Unwrap(err).(type) {
|
||||
case ErrInvalidHeader:
|
||||
@@ -757,7 +762,7 @@ func (c *Client) verifySkippingAgainstPrimary(
|
||||
return err
|
||||
}
|
||||
|
||||
replacementBlock, fErr := c.lightBlockFromPrimary(newLightBlock.Height)
|
||||
replacementBlock, fErr := c.lightBlockFromPrimary(ctx, newLightBlock.Height)
|
||||
if fErr != nil {
|
||||
c.logger.Error("Can't fetch light block from primary", "err", fErr)
|
||||
// return original error
|
||||
@@ -773,14 +778,14 @@ func (c *Client) verifySkippingAgainstPrimary(
|
||||
}
|
||||
|
||||
// attempt to verify the header again
|
||||
return c.verifySkippingAgainstPrimary(trustedBlock, replacementBlock, now)
|
||||
return c.verifySkippingAgainstPrimary(ctx, trustedBlock, replacementBlock, now)
|
||||
case nil:
|
||||
// Compare header with the witnesses to ensure it's not a fork.
|
||||
// More witnesses we have, more chance to notice one.
|
||||
//
|
||||
// CORRECTNESS ASSUMPTION: there's at least 1 correct full node
|
||||
// (primary or one of the witnesses).
|
||||
if cmpErr := c.detectDivergence(trace, now); cmpErr != nil {
|
||||
if cmpErr := c.detectDivergence(ctx, trace, now); cmpErr != nil {
|
||||
return cmpErr
|
||||
}
|
||||
default:
|
||||
@@ -892,6 +897,7 @@ func (c *Client) updateTrustedLightBlock(l *types.LightBlock) error {
|
||||
// headers before a trusted header. If a sent header is invalid the primary is
|
||||
// replaced with another provider and the operation is repeated.
|
||||
func (c *Client) backwards(
|
||||
ctx context.Context,
|
||||
trustedHeader *types.Header,
|
||||
newHeader *types.Header) error {
|
||||
|
||||
@@ -901,7 +907,7 @@ func (c *Client) backwards(
|
||||
)
|
||||
|
||||
for verifiedHeader.Height > newHeader.Height {
|
||||
interimBlock, err := c.lightBlockFromPrimary(verifiedHeader.Height - 1)
|
||||
interimBlock, err := c.lightBlockFromPrimary(ctx, verifiedHeader.Height-1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to obtain the header at height #%d: %w", verifiedHeader.Height-1, err)
|
||||
}
|
||||
@@ -960,9 +966,9 @@ func (c *Client) replacePrimaryProvider() error {
|
||||
// lightBlockFromPrimary retrieves the lightBlock from the primary provider
|
||||
// at the specified height. Handles dropout by the primary provider by swapping
|
||||
// with an alternative provider.
|
||||
func (c *Client) lightBlockFromPrimary(height int64) (*types.LightBlock, error) {
|
||||
func (c *Client) lightBlockFromPrimary(ctx context.Context, height int64) (*types.LightBlock, error) {
|
||||
c.providerMutex.Lock()
|
||||
l, err := c.primary.LightBlock(height)
|
||||
l, err := c.primary.LightBlock(ctx, height)
|
||||
c.providerMutex.Unlock()
|
||||
if err != nil {
|
||||
c.logger.Debug("Error on light block request from primary", "error", err)
|
||||
@@ -971,7 +977,7 @@ func (c *Client) lightBlockFromPrimary(height int64) (*types.LightBlock, error)
|
||||
return nil, fmt.Errorf("%v. Tried to replace primary but: %w", err.Error(), replaceErr)
|
||||
}
|
||||
// replace primary and request a light block again
|
||||
return c.lightBlockFromPrimary(height)
|
||||
return c.lightBlockFromPrimary(ctx, height)
|
||||
}
|
||||
return l, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user