rpc/client: take context as first param (#5347)

Closes #5145

also applies to light/client
This commit is contained in:
Anton Kaliaev
2020-09-23 09:21:57 +04:00
committed by GitHub
parent 0aecda68fc
commit 85a4be87a7
41 changed files with 706 additions and 503 deletions
+37 -31
View File
@@ -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
}
+9 -5
View File
@@ -1,6 +1,7 @@
package light_test
import (
"context"
"testing"
"time"
@@ -22,11 +23,12 @@ import (
// Remember that none of these benchmarks account for network latency.
var (
benchmarkFullNode = mockp.New(genMockNode(chainID, 1000, 100, 1, bTime))
genesisBlock, _ = benchmarkFullNode.LightBlock(1)
genesisBlock, _ = benchmarkFullNode.LightBlock(context.Background(), 1)
)
func BenchmarkSequence(b *testing.B) {
c, err := light.NewClient(
context.Background(),
chainID,
light.TrustOptions{
Period: 24 * time.Hour,
@@ -45,7 +47,7 @@ func BenchmarkSequence(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, err = c.VerifyLightBlockAtHeight(1000, bTime.Add(1000*time.Minute))
_, err = c.VerifyLightBlockAtHeight(context.Background(), 1000, bTime.Add(1000*time.Minute))
if err != nil {
b.Fatal(err)
}
@@ -54,6 +56,7 @@ func BenchmarkSequence(b *testing.B) {
func BenchmarkBisection(b *testing.B) {
c, err := light.NewClient(
context.Background(),
chainID,
light.TrustOptions{
Period: 24 * time.Hour,
@@ -71,7 +74,7 @@ func BenchmarkBisection(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, err = c.VerifyLightBlockAtHeight(1000, bTime.Add(1000*time.Minute))
_, err = c.VerifyLightBlockAtHeight(context.Background(), 1000, bTime.Add(1000*time.Minute))
if err != nil {
b.Fatal(err)
}
@@ -79,8 +82,9 @@ func BenchmarkBisection(b *testing.B) {
}
func BenchmarkBackwards(b *testing.B) {
trustedBlock, _ := benchmarkFullNode.LightBlock(0)
trustedBlock, _ := benchmarkFullNode.LightBlock(context.Background(), 0)
c, err := light.NewClient(
context.Background(),
chainID,
light.TrustOptions{
Period: 24 * time.Hour,
@@ -98,7 +102,7 @@ func BenchmarkBackwards(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, err = c.VerifyLightBlockAtHeight(1, bTime)
_, err = c.VerifyLightBlockAtHeight(context.Background(), 1, bTime)
if err != nil {
b.Fatal(err)
}
+47 -25
View File
@@ -1,6 +1,7 @@
package light_test
import (
"context"
"sync"
"testing"
"time"
@@ -23,6 +24,7 @@ const (
)
var (
ctx = context.Background()
keys = genPrivKeys(4)
vals = keys.ToValidators(20, 10)
bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
@@ -111,7 +113,7 @@ func TestValidateTrustOptions(t *testing.T) {
}
func TestMock(t *testing.T) {
l, _ := fullNode.LightBlock(3)
l, _ := fullNode.LightBlock(ctx, 3)
assert.Equal(t, int64(3), l.Height)
}
@@ -216,6 +218,7 @@ func TestClient_SequentialVerification(t *testing.T) {
tc := tc
t.Run(tc.name, func(t *testing.T) {
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
mockp.New(
@@ -240,7 +243,7 @@ func TestClient_SequentialVerification(t *testing.T) {
require.NoError(t, err)
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(3*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(3*time.Hour))
if tc.verifyErr {
assert.Error(t, err)
} else {
@@ -340,6 +343,7 @@ func TestClient_SkippingVerification(t *testing.T) {
tc := tc
t.Run(tc.name, func(t *testing.T) {
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
mockp.New(
@@ -363,7 +367,7 @@ func TestClient_SkippingVerification(t *testing.T) {
require.NoError(t, err)
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(3*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(3*time.Hour))
if tc.verifyErr {
assert.Error(t, err)
} else {
@@ -378,9 +382,10 @@ func TestClient_SkippingVerification(t *testing.T) {
// the appropriate range
func TestClientLargeBisectionVerification(t *testing.T) {
veryLargeFullNode := mockp.New(genMockNode(chainID, 100, 3, 0, bTime))
trustedLightBlock, err := veryLargeFullNode.LightBlock(5)
trustedLightBlock, err := veryLargeFullNode.LightBlock(ctx, 5)
require.NoError(t, err)
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
@@ -393,15 +398,16 @@ func TestClientLargeBisectionVerification(t *testing.T) {
light.SkippingVerification(light.DefaultTrustLevel),
)
require.NoError(t, err)
h, err := c.Update(bTime.Add(100 * time.Minute))
h, err := c.Update(ctx, bTime.Add(100*time.Minute))
assert.NoError(t, err)
h2, err := veryLargeFullNode.LightBlock(100)
h2, err := veryLargeFullNode.LightBlock(ctx, 100)
require.NoError(t, err)
assert.Equal(t, h, h2)
}
func TestClientBisectionBetweenTrustedHeaders(t *testing.T) {
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
@@ -415,7 +421,7 @@ func TestClientBisectionBetweenTrustedHeaders(t *testing.T) {
)
require.NoError(t, err)
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(2*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(2*time.Hour))
require.NoError(t, err)
// confirm that the client already doesn't have the light block
@@ -423,12 +429,13 @@ func TestClientBisectionBetweenTrustedHeaders(t *testing.T) {
require.Error(t, err)
// verify using bisection the light block between the two trusted light blocks
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(1*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(1*time.Hour))
assert.NoError(t, err)
}
func TestClient_Cleanup(t *testing.T) {
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
fullNode,
@@ -458,6 +465,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
require.NoError(t, err)
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
fullNode,
@@ -494,6 +502,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
)
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
@@ -525,6 +534,7 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
require.NoError(t, err)
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
@@ -570,6 +580,7 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
)
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
@@ -603,6 +614,7 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
require.NoError(t, err)
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
fullNode,
@@ -657,6 +669,7 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
)
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
@@ -686,6 +699,7 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
func TestClient_Update(t *testing.T) {
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
fullNode,
@@ -696,7 +710,7 @@ func TestClient_Update(t *testing.T) {
require.NoError(t, err)
// should result in downloading & verifying header #3
l, err := c.Update(bTime.Add(2 * time.Hour))
l, err := c.Update(ctx, bTime.Add(2*time.Hour))
assert.NoError(t, err)
if assert.NotNil(t, l) {
assert.EqualValues(t, 3, l.Height)
@@ -706,6 +720,7 @@ func TestClient_Update(t *testing.T) {
func TestClient_Concurrency(t *testing.T) {
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
fullNode,
@@ -715,7 +730,7 @@ func TestClient_Concurrency(t *testing.T) {
)
require.NoError(t, err)
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(2*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour))
require.NoError(t, err)
var wg sync.WaitGroup
@@ -746,6 +761,7 @@ func TestClient_Concurrency(t *testing.T) {
func TestClientReplacesPrimaryWithWitnessIfPrimaryIsUnavailable(t *testing.T) {
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
deadNode,
@@ -756,7 +772,7 @@ func TestClientReplacesPrimaryWithWitnessIfPrimaryIsUnavailable(t *testing.T) {
)
require.NoError(t, err)
_, err = c.Update(bTime.Add(2 * time.Hour))
_, err = c.Update(ctx, bTime.Add(2*time.Hour))
require.NoError(t, err)
assert.NotEqual(t, c.Primary(), deadNode)
@@ -765,8 +781,9 @@ func TestClientReplacesPrimaryWithWitnessIfPrimaryIsUnavailable(t *testing.T) {
func TestClient_BackwardsVerification(t *testing.T) {
{
trustHeader, _ := largeFullNode.LightBlock(6)
trustHeader, _ := largeFullNode.LightBlock(ctx, 6)
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Minute,
@@ -781,28 +798,28 @@ func TestClient_BackwardsVerification(t *testing.T) {
require.NoError(t, err)
// 1) verify before the trusted header using backwards => expect no error
h, err := c.VerifyLightBlockAtHeight(5, bTime.Add(6*time.Minute))
h, err := c.VerifyLightBlockAtHeight(ctx, 5, bTime.Add(6*time.Minute))
require.NoError(t, err)
if assert.NotNil(t, h) {
assert.EqualValues(t, 5, h.Height)
}
// 2) untrusted header is expired but trusted header is not => expect no error
h, err = c.VerifyLightBlockAtHeight(3, bTime.Add(8*time.Minute))
h, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(8*time.Minute))
assert.NoError(t, err)
assert.NotNil(t, h)
// 3) already stored headers should return the header without error
h, err = c.VerifyLightBlockAtHeight(5, bTime.Add(6*time.Minute))
h, err = c.VerifyLightBlockAtHeight(ctx, 5, bTime.Add(6*time.Minute))
assert.NoError(t, err)
assert.NotNil(t, h)
// 4a) First verify latest header
_, err = c.VerifyLightBlockAtHeight(9, bTime.Add(9*time.Minute))
_, err = c.VerifyLightBlockAtHeight(ctx, 9, bTime.Add(9*time.Minute))
require.NoError(t, err)
// 4b) Verify backwards using bisection => expect no error
_, err = c.VerifyLightBlockAtHeight(7, bTime.Add(9*time.Minute))
_, err = c.VerifyLightBlockAtHeight(ctx, 7, bTime.Add(9*time.Minute))
assert.NoError(t, err)
// shouldn't have verified this header in the process
_, err = c.TrustedLightBlock(8)
@@ -810,7 +827,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
// 5) Try bisection method, but closest header (at 7) has expired
// so expect error
_, err = c.VerifyLightBlockAtHeight(8, bTime.Add(12*time.Minute))
_, err = c.VerifyLightBlockAtHeight(ctx, 8, bTime.Add(12*time.Minute))
assert.Error(t, err)
}
@@ -848,6 +865,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
for idx, tc := range testCases {
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 1 * time.Hour,
@@ -861,7 +879,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
)
require.NoError(t, err, idx)
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(1*time.Hour).Add(1*time.Second))
_, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(1*time.Hour).Add(1*time.Second))
assert.Error(t, err, idx)
}
}
@@ -917,10 +935,11 @@ func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) {
},
)
lb1, _ := badProvider1.LightBlock(2)
lb1, _ := badProvider1.LightBlock(ctx, 2)
require.NotEqual(t, lb1.Hash(), l1.Hash())
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
fullNode,
@@ -934,14 +953,14 @@ func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) {
assert.EqualValues(t, 2, len(c.Witnesses()))
// witness behaves incorrectly -> removed from list, no error
l, err := c.VerifyLightBlockAtHeight(2, bTime.Add(2*time.Hour))
l, err := c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour))
assert.NoError(t, err)
assert.EqualValues(t, 1, len(c.Witnesses()))
// light block should still be verified
assert.EqualValues(t, 2, l.Height)
// remaining witnesses don't have light block -> error
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(2*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(2*time.Hour))
if assert.Error(t, err) {
assert.Equal(t, light.ErrFailedHeaderCrossReferencing, err)
}
@@ -970,6 +989,7 @@ func TestClient_TrustedValidatorSet(t *testing.T) {
)
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
fullNode,
@@ -980,13 +1000,14 @@ func TestClient_TrustedValidatorSet(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 2, len(c.Witnesses()))
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(2*time.Hour).Add(1*time.Second))
_, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour).Add(1*time.Second))
assert.NoError(t, err)
assert.Equal(t, 1, len(c.Witnesses()))
}
func TestClientPrunesHeadersAndValidatorSets(t *testing.T) {
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
fullNode,
@@ -999,7 +1020,7 @@ func TestClientPrunesHeadersAndValidatorSets(t *testing.T) {
_, err = c.TrustedLightBlock(1)
require.NoError(t, err)
h, err := c.Update(bTime.Add(2 * time.Hour))
h, err := c.Update(ctx, bTime.Add(2*time.Hour))
require.NoError(t, err)
require.Equal(t, int64(3), h.Height)
@@ -1059,6 +1080,7 @@ func TestClientEnsureValidHeadersAndValSets(t *testing.T) {
tc.vals,
)
c, err := light.NewClient(
ctx,
chainID,
trustOptions,
badNode,
@@ -1068,7 +1090,7 @@ func TestClientEnsureValidHeadersAndValSets(t *testing.T) {
)
require.NoError(t, err)
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(2*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(2*time.Hour))
if tc.err {
assert.Error(t, err)
} else {
+26 -14
View File
@@ -2,6 +2,7 @@ package light
import (
"bytes"
"context"
"errors"
"fmt"
"time"
@@ -25,7 +26,7 @@ import (
//
// If there are no conflictinge headers, the light client deems the verified target header
// trusted and saves it to the trusted store.
func (c *Client) detectDivergence(primaryTrace []*types.LightBlock, now time.Time) error {
func (c *Client) detectDivergence(ctx context.Context, primaryTrace []*types.LightBlock, now time.Time) error {
if primaryTrace == nil || len(primaryTrace) < 2 {
return errors.New("nil or single block primary trace")
}
@@ -48,7 +49,7 @@ func (c *Client) detectDivergence(primaryTrace []*types.LightBlock, now time.Tim
// and compare it with the header from the primary
errc := make(chan error, len(c.witnesses))
for i, witness := range c.witnesses {
go c.compareNewHeaderWithWitness(errc, lastVerifiedHeader, witness, i)
go c.compareNewHeaderWithWitness(ctx, errc, lastVerifiedHeader, witness, i)
}
// handle errors from the header comparisons as they come in
@@ -66,8 +67,13 @@ func (c *Client) detectDivergence(primaryTrace []*types.LightBlock, now time.Tim
// We combine these actions together, verifying the witnesses headers and outputting the trace
// which captures the bifurcation point and if successful provides the information to create
supportingWitness := c.witnesses[e.WitnessIndex]
witnessTrace, primaryBlock, err := c.examineConflictingHeaderAgainstTrace(primaryTrace, e.Block.SignedHeader,
supportingWitness, now)
witnessTrace, primaryBlock, err := c.examineConflictingHeaderAgainstTrace(
ctx,
primaryTrace,
e.Block.SignedHeader,
supportingWitness,
now,
)
if err != nil {
c.logger.Info("Error validating witness's divergent header", "witness", supportingWitness, "err", err)
witnessesToRemove = append(witnessesToRemove, e.WitnessIndex)
@@ -90,13 +96,18 @@ func (c *Client) detectDivergence(primaryTrace []*types.LightBlock, now time.Tim
}
c.logger.Error("Attack detected. Sending evidence againt primary by witness", "ev", ev,
"primary", c.primary, "witness", supportingWitness)
c.sendEvidence(ev, supportingWitness)
c.sendEvidence(ctx, ev, supportingWitness)
// This may not be valid because the witness itself is at fault. So now we reverse it, examining the
// trace provided by the witness and holding the primary as the source of truth. Note: primary may not
// respond but this is okay as we will halt anyway.
primaryTrace, witnessBlock, err := c.examineConflictingHeaderAgainstTrace(witnessTrace, primaryBlock.SignedHeader,
c.primary, now)
primaryTrace, witnessBlock, err := c.examineConflictingHeaderAgainstTrace(
ctx,
witnessTrace,
primaryBlock.SignedHeader,
c.primary,
now,
)
if err != nil {
c.logger.Info("Error validating primary's divergent header", "primary", c.primary, "err", err)
continue
@@ -117,7 +128,7 @@ func (c *Client) detectDivergence(primaryTrace []*types.LightBlock, now time.Tim
}
c.logger.Error("Sending evidence against witness by primary", "ev", ev,
"primary", c.primary, "witness", supportingWitness)
c.sendEvidence(ev, c.primary)
c.sendEvidence(ctx, ev, c.primary)
// We return the error and don't process anymore witnesses
return e
@@ -154,10 +165,10 @@ func (c *Client) detectDivergence(primaryTrace []*types.LightBlock, now time.Tim
// 2: errBadWitness -> the witness has either not responded, doesn't have the header or has given us an invalid one
// Note: In the case of an invalid header we remove the witness
// 3: nil -> the hashes of the two headers match
func (c *Client) compareNewHeaderWithWitness(errc chan error, h *types.SignedHeader,
func (c *Client) compareNewHeaderWithWitness(ctx context.Context, errc chan error, h *types.SignedHeader,
witness provider.Provider, witnessIndex int) {
lightBlock, err := witness.LightBlock(h.Height)
lightBlock, err := witness.LightBlock(ctx, h.Height)
if err != nil {
errc <- errBadWitness{Reason: err, WitnessIndex: witnessIndex}
return
@@ -172,8 +183,8 @@ func (c *Client) compareNewHeaderWithWitness(errc chan error, h *types.SignedHea
}
// sendEvidence sends evidence to a provider on a best effort basis.
func (c *Client) sendEvidence(ev *types.LightClientAttackEvidence, receiver provider.Provider) {
err := receiver.ReportEvidence(ev)
func (c *Client) sendEvidence(ctx context.Context, ev *types.LightClientAttackEvidence, receiver provider.Provider) {
err := receiver.ReportEvidence(ctx, ev)
if err != nil {
c.logger.Error("Failed to report evidence to provider", "ev", ev, "provider", receiver)
}
@@ -188,6 +199,7 @@ func (c *Client) sendEvidence(ev *types.LightClientAttackEvidence, receiver prov
// 2. The source stops responding, doesn't have the block or sends an invalid header in which case we
// return the error and remove the witness
func (c *Client) examineConflictingHeaderAgainstTrace(
ctx context.Context,
trace []*types.LightBlock,
divergentHeader *types.SignedHeader,
source provider.Provider, now time.Time) ([]*types.LightBlock, *types.LightBlock, error) {
@@ -197,7 +209,7 @@ func (c *Client) examineConflictingHeaderAgainstTrace(
for idx, traceBlock := range trace {
// The first block in the trace MUST be the same to the light block that the source produces
// else we cannot continue with verification.
sourceBlock, err := source.LightBlock(traceBlock.Height)
sourceBlock, err := source.LightBlock(ctx, traceBlock.Height)
if err != nil {
return nil, nil, err
}
@@ -213,7 +225,7 @@ func (c *Client) examineConflictingHeaderAgainstTrace(
// we check that the source provider can verify a block at the same height of the
// intermediate height
trace, err := c.verifySkipping(source, previouslyVerifiedBlock, sourceBlock, now)
trace, err := c.verifySkipping(ctx, source, previouslyVerifiedBlock, sourceBlock, now)
if err != nil {
return nil, nil, fmt.Errorf("verifySkipping of conflicting header failed: %w", err)
}
+9 -5
View File
@@ -45,6 +45,7 @@ func TestLightClientAttackEvidence_Lunatic(t *testing.T) {
primary := mockp.New(chainID, primaryHeaders, primaryValidators)
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
@@ -60,7 +61,7 @@ func TestLightClientAttackEvidence_Lunatic(t *testing.T) {
require.NoError(t, err)
// Check verification returns an error.
_, err = c.VerifyLightBlockAtHeight(10, bTime.Add(1*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 10, bTime.Add(1*time.Hour))
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "does not match primary")
}
@@ -118,6 +119,7 @@ func TestLightClientAttackEvidence_Equivocation(t *testing.T) {
primary := mockp.New(chainID, primaryHeaders, primaryValidators)
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
@@ -133,7 +135,7 @@ func TestLightClientAttackEvidence_Equivocation(t *testing.T) {
require.NoError(t, err)
// Check verification returns an error.
_, err = c.VerifyLightBlockAtHeight(10, bTime.Add(1*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 10, bTime.Add(1*time.Hour))
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "does not match primary")
}
@@ -162,11 +164,12 @@ func TestLightClientAttackEvidence_Equivocation(t *testing.T) {
func TestClientDivergentTraces(t *testing.T) {
primary := mockp.New(genMockNode(chainID, 10, 5, 2, bTime))
firstBlock, err := primary.LightBlock(1)
firstBlock, err := primary.LightBlock(ctx, 1)
require.NoError(t, err)
witness := mockp.New(genMockNode(chainID, 10, 5, 2, bTime))
c, err := light.NewClient(
ctx,
chainID,
light.TrustOptions{
Height: 1,
@@ -183,7 +186,7 @@ func TestClientDivergentTraces(t *testing.T) {
// 1. Different nodes therefore a divergent header is produced but the
// light client can't verify it because it has a different trusted header.
_, err = c.VerifyLightBlockAtHeight(10, bTime.Add(1*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 10, bTime.Add(1*time.Hour))
assert.Error(t, err)
assert.Equal(t, 0, len(c.Witnesses()))
@@ -191,6 +194,7 @@ func TestClientDivergentTraces(t *testing.T) {
// verification should be successful and all the witnesses should remain
c, err = light.NewClient(
ctx,
chainID,
light.TrustOptions{
Height: 1,
@@ -204,7 +208,7 @@ func TestClientDivergentTraces(t *testing.T) {
light.MaxRetryAttempts(1),
)
require.NoError(t, err)
_, err = c.VerifyLightBlockAtHeight(10, bTime.Add(1*time.Hour))
_, err = c.VerifyLightBlockAtHeight(ctx, 10, bTime.Add(1*time.Hour))
assert.NoError(t, err)
assert.Equal(t, 3, len(c.Witnesses()))
}
+7 -4
View File
@@ -1,6 +1,7 @@
package light_test
import (
"context"
"fmt"
"io/ioutil"
stdlog "log"
@@ -40,7 +41,7 @@ func ExampleClient_Update() {
stdlog.Fatal(err)
}
block, err := primary.LightBlock(2)
block, err := primary.LightBlock(context.Background(), 2)
if err != nil {
stdlog.Fatal(err)
}
@@ -51,6 +52,7 @@ func ExampleClient_Update() {
}
c, err := light.NewClient(
context.Background(),
chainID,
light.TrustOptions{
Period: 504 * time.Hour, // 21 days
@@ -77,7 +79,7 @@ func ExampleClient_Update() {
// monotonic component (see types/time/time.go) b) single instance is being
// run.
// https://github.com/tendermint/tendermint/issues/4489
h, err := c.Update(time.Now().Add(30 * time.Minute))
h, err := c.Update(context.Background(), time.Now().Add(30*time.Minute))
if err != nil {
stdlog.Fatal(err)
}
@@ -111,7 +113,7 @@ func ExampleClient_VerifyLightBlockAtHeight() {
stdlog.Fatal(err)
}
block, err := primary.LightBlock(2)
block, err := primary.LightBlock(context.Background(), 2)
if err != nil {
stdlog.Fatal(err)
}
@@ -122,6 +124,7 @@ func ExampleClient_VerifyLightBlockAtHeight() {
}
c, err := light.NewClient(
context.Background(),
chainID,
light.TrustOptions{
Period: 504 * time.Hour, // 21 days
@@ -142,7 +145,7 @@ func ExampleClient_VerifyLightBlockAtHeight() {
}
}()
_, err = c.VerifyLightBlockAtHeight(3, time.Now())
_, err = c.VerifyLightBlockAtHeight(context.Background(), 3, time.Now())
if err != nil {
stdlog.Fatal(err)
}
+10 -9
View File
@@ -1,6 +1,7 @@
package http
import (
"context"
"fmt"
"math/rand"
"regexp"
@@ -61,18 +62,18 @@ func (p *http) String() string {
// LightBlock fetches a LightBlock at the given height and checks the
// chainID matches.
func (p *http) LightBlock(height int64) (*types.LightBlock, error) {
func (p *http) LightBlock(ctx context.Context, height int64) (*types.LightBlock, error) {
h, err := validateHeight(height)
if err != nil {
return nil, provider.ErrBadLightBlock{Reason: err}
}
sh, err := p.signedHeader(h)
sh, err := p.signedHeader(ctx, h)
if err != nil {
return nil, err
}
vs, err := p.validatorSet(h)
vs, err := p.validatorSet(ctx, h)
if err != nil {
return nil, err
}
@@ -91,12 +92,12 @@ func (p *http) LightBlock(height int64) (*types.LightBlock, error) {
}
// ReportEvidence calls `/broadcast_evidence` endpoint.
func (p *http) ReportEvidence(ev types.Evidence) error {
_, err := p.client.BroadcastEvidence(ev)
func (p *http) ReportEvidence(ctx context.Context, ev types.Evidence) error {
_, err := p.client.BroadcastEvidence(ctx, ev)
return err
}
func (p *http) validatorSet(height *int64) (*types.ValidatorSet, error) {
func (p *http) validatorSet(ctx context.Context, height *int64) (*types.ValidatorSet, error) {
var (
maxPerPage = 100
vals = []*types.Validator{}
@@ -105,7 +106,7 @@ func (p *http) validatorSet(height *int64) (*types.ValidatorSet, error) {
for len(vals)%maxPerPage == 0 {
for attempt := 1; attempt <= maxRetryAttempts; attempt++ {
res, err := p.client.Validators(height, &page, &maxPerPage)
res, err := p.client.Validators(ctx, height, &page, &maxPerPage)
if err != nil {
// TODO: standardize errors on the RPC side
if regexpMissingHeight.MatchString(err.Error()) {
@@ -138,9 +139,9 @@ func (p *http) validatorSet(height *int64) (*types.ValidatorSet, error) {
return valSet, nil
}
func (p *http) signedHeader(height *int64) (*types.SignedHeader, error) {
func (p *http) signedHeader(ctx context.Context, height *int64) (*types.SignedHeader, error) {
for attempt := 1; attempt <= maxRetryAttempts; attempt++ {
commit, err := p.client.Commit(height)
commit, err := p.client.Commit(ctx, height)
if err != nil {
// TODO: standardize errors on the RPC side
if regexpMissingHeight.MatchString(err.Error()) {
+5 -4
View File
@@ -1,6 +1,7 @@
package http_test
import (
"context"
"fmt"
"os"
"testing"
@@ -65,7 +66,7 @@ func TestProvider(t *testing.T) {
require.NoError(t, err)
// let's get the highest block
sh, err := p.LightBlock(0)
sh, err := p.LightBlock(context.Background(), 0)
require.NoError(t, err)
assert.True(t, sh.Height < 1000)
@@ -74,16 +75,16 @@ func TestProvider(t *testing.T) {
// historical queries now work :)
lower := sh.Height - 3
sh, err = p.LightBlock(lower)
sh, err = p.LightBlock(context.Background(), lower)
require.NoError(t, err)
assert.Equal(t, lower, sh.Height)
// fetching missing heights (both future and pruned) should return appropriate errors
_, err = p.LightBlock(1000)
_, err = p.LightBlock(context.Background(), 1000)
require.Error(t, err)
assert.Equal(t, provider.ErrLightBlockNotFound, err)
_, err = p.LightBlock(1)
_, err = p.LightBlock(context.Background(), 1)
require.Error(t, err)
assert.Equal(t, provider.ErrLightBlockNotFound, err)
}
+3 -2
View File
@@ -1,6 +1,7 @@
package mock
import (
"context"
"errors"
"github.com/tendermint/tendermint/light/provider"
@@ -22,10 +23,10 @@ func (p *deadMock) ChainID() string { return p.chainID }
func (p *deadMock) String() string { return "deadMock" }
func (p *deadMock) LightBlock(height int64) (*types.LightBlock, error) {
func (p *deadMock) LightBlock(_ context.Context, height int64) (*types.LightBlock, error) {
return nil, errNoResp
}
func (p *deadMock) ReportEvidence(ev types.Evidence) error {
func (p *deadMock) ReportEvidence(_ context.Context, ev types.Evidence) error {
return errNoResp
}
+3 -2
View File
@@ -1,6 +1,7 @@
package mock
import (
"context"
"errors"
"fmt"
"strings"
@@ -48,7 +49,7 @@ func (p *Mock) String() string {
return fmt.Sprintf("Mock{headers: %s, vals: %v}", headers.String(), vals.String())
}
func (p *Mock) LightBlock(height int64) (*types.LightBlock, error) {
func (p *Mock) LightBlock(_ context.Context, height int64) (*types.LightBlock, error) {
var lb *types.LightBlock
if height == 0 && len(p.headers) > 0 {
sh := p.headers[int64(len(p.headers))]
@@ -79,7 +80,7 @@ func (p *Mock) LightBlock(height int64) (*types.LightBlock, error) {
return lb, nil
}
func (p *Mock) ReportEvidence(ev types.Evidence) error {
func (p *Mock) ReportEvidence(_ context.Context, ev types.Evidence) error {
p.evidenceToReport[string(ev.Hash())] = ev
return nil
}
+4 -2
View File
@@ -1,6 +1,8 @@
package provider
import (
"context"
"github.com/tendermint/tendermint/types"
)
@@ -20,8 +22,8 @@ type Provider interface {
// issues, an error will be returned.
// If there's no LightBlock for the given height, ErrLightBlockNotFound
// error is returned.
LightBlock(height int64) (*types.LightBlock, error)
LightBlock(ctx context.Context, height int64) (*types.LightBlock, error)
// ReportEvidence reports an evidence of misbehavior.
ReportEvidence(ev types.Evidence) error
ReportEvidence(context.Context, types.Evidence) error
}
+23 -23
View File
@@ -53,7 +53,7 @@ type rpcHealthFunc func(ctx *rpctypes.Context) (*ctypes.ResultHealth, error)
func makeHealthFunc(c *lrpc.Client) rpcHealthFunc {
return func(ctx *rpctypes.Context) (*ctypes.ResultHealth, error) {
return c.Health()
return c.Health(ctx.Context())
}
}
@@ -62,7 +62,7 @@ type rpcStatusFunc func(ctx *rpctypes.Context) (*ctypes.ResultStatus, error)
// nolint: interfacer
func makeStatusFunc(c *lrpc.Client) rpcStatusFunc {
return func(ctx *rpctypes.Context) (*ctypes.ResultStatus, error) {
return c.Status()
return c.Status(ctx.Context())
}
}
@@ -70,7 +70,7 @@ type rpcNetInfoFunc func(ctx *rpctypes.Context, minHeight, maxHeight int64) (*ct
func makeNetInfoFunc(c *lrpc.Client) rpcNetInfoFunc {
return func(ctx *rpctypes.Context, minHeight, maxHeight int64) (*ctypes.ResultNetInfo, error) {
return c.NetInfo()
return c.NetInfo(ctx.Context())
}
}
@@ -78,7 +78,7 @@ type rpcBlockchainInfoFunc func(ctx *rpctypes.Context, minHeight, maxHeight int6
func makeBlockchainInfoFunc(c *lrpc.Client) rpcBlockchainInfoFunc {
return func(ctx *rpctypes.Context, minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
return c.BlockchainInfo(minHeight, maxHeight)
return c.BlockchainInfo(ctx.Context(), minHeight, maxHeight)
}
}
@@ -86,7 +86,7 @@ type rpcGenesisFunc func(ctx *rpctypes.Context) (*ctypes.ResultGenesis, error)
func makeGenesisFunc(c *lrpc.Client) rpcGenesisFunc {
return func(ctx *rpctypes.Context) (*ctypes.ResultGenesis, error) {
return c.Genesis()
return c.Genesis(ctx.Context())
}
}
@@ -94,7 +94,7 @@ type rpcBlockFunc func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultBloc
func makeBlockFunc(c *lrpc.Client) rpcBlockFunc {
return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultBlock, error) {
return c.Block(height)
return c.Block(ctx.Context(), height)
}
}
@@ -102,7 +102,7 @@ type rpcBlockByHashFunc func(ctx *rpctypes.Context, hash []byte) (*ctypes.Result
func makeBlockByHashFunc(c *lrpc.Client) rpcBlockByHashFunc {
return func(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error) {
return c.BlockByHash(hash)
return c.BlockByHash(ctx.Context(), hash)
}
}
@@ -110,7 +110,7 @@ type rpcBlockResultsFunc func(ctx *rpctypes.Context, height *int64) (*ctypes.Res
func makeBlockResultsFunc(c *lrpc.Client) rpcBlockResultsFunc {
return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultBlockResults, error) {
return c.BlockResults(height)
return c.BlockResults(ctx.Context(), height)
}
}
@@ -118,7 +118,7 @@ type rpcCommitFunc func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultCom
func makeCommitFunc(c *lrpc.Client) rpcCommitFunc {
return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultCommit, error) {
return c.Commit(height)
return c.Commit(ctx.Context(), height)
}
}
@@ -126,7 +126,7 @@ type rpcTxFunc func(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.Res
func makeTxFunc(c *lrpc.Client) rpcTxFunc {
return func(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) {
return c.Tx(hash, prove)
return c.Tx(ctx.Context(), hash, prove)
}
}
@@ -136,7 +136,7 @@ type rpcTxSearchFunc func(ctx *rpctypes.Context, query string, prove bool,
func makeTxSearchFunc(c *lrpc.Client) rpcTxSearchFunc {
return func(ctx *rpctypes.Context, query string, prove bool, page, perPage *int, orderBy string) (
*ctypes.ResultTxSearch, error) {
return c.TxSearch(query, prove, page, perPage, orderBy)
return c.TxSearch(ctx.Context(), query, prove, page, perPage, orderBy)
}
}
@@ -145,7 +145,7 @@ type rpcValidatorsFunc func(ctx *rpctypes.Context, height *int64,
func makeValidatorsFunc(c *lrpc.Client) rpcValidatorsFunc {
return func(ctx *rpctypes.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error) {
return c.Validators(height, page, perPage)
return c.Validators(ctx.Context(), height, page, perPage)
}
}
@@ -153,7 +153,7 @@ type rpcDumpConsensusStateFunc func(ctx *rpctypes.Context) (*ctypes.ResultDumpCo
func makeDumpConsensusStateFunc(c *lrpc.Client) rpcDumpConsensusStateFunc {
return func(ctx *rpctypes.Context) (*ctypes.ResultDumpConsensusState, error) {
return c.DumpConsensusState()
return c.DumpConsensusState(ctx.Context())
}
}
@@ -161,7 +161,7 @@ type rpcConsensusStateFunc func(ctx *rpctypes.Context) (*ctypes.ResultConsensusS
func makeConsensusStateFunc(c *lrpc.Client) rpcConsensusStateFunc {
return func(ctx *rpctypes.Context) (*ctypes.ResultConsensusState, error) {
return c.ConsensusState()
return c.ConsensusState(ctx.Context())
}
}
@@ -169,7 +169,7 @@ type rpcConsensusParamsFunc func(ctx *rpctypes.Context, height *int64) (*ctypes.
func makeConsensusParamsFunc(c *lrpc.Client) rpcConsensusParamsFunc {
return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultConsensusParams, error) {
return c.ConsensusParams(height)
return c.ConsensusParams(ctx.Context(), height)
}
}
@@ -177,7 +177,7 @@ type rpcUnconfirmedTxsFunc func(ctx *rpctypes.Context, limit *int) (*ctypes.Resu
func makeUnconfirmedTxsFunc(c *lrpc.Client) rpcUnconfirmedTxsFunc {
return func(ctx *rpctypes.Context, limit *int) (*ctypes.ResultUnconfirmedTxs, error) {
return c.UnconfirmedTxs(limit)
return c.UnconfirmedTxs(ctx.Context(), limit)
}
}
@@ -185,7 +185,7 @@ type rpcNumUnconfirmedTxsFunc func(ctx *rpctypes.Context) (*ctypes.ResultUnconfi
func makeNumUnconfirmedTxsFunc(c *lrpc.Client) rpcNumUnconfirmedTxsFunc {
return func(ctx *rpctypes.Context) (*ctypes.ResultUnconfirmedTxs, error) {
return c.NumUnconfirmedTxs()
return c.NumUnconfirmedTxs(ctx.Context())
}
}
@@ -193,7 +193,7 @@ type rpcBroadcastTxCommitFunc func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.
func makeBroadcastTxCommitFunc(c *lrpc.Client) rpcBroadcastTxCommitFunc {
return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
return c.BroadcastTxCommit(tx)
return c.BroadcastTxCommit(ctx.Context(), tx)
}
}
@@ -201,7 +201,7 @@ type rpcBroadcastTxSyncFunc func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.Re
func makeBroadcastTxSyncFunc(c *lrpc.Client) rpcBroadcastTxSyncFunc {
return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return c.BroadcastTxSync(tx)
return c.BroadcastTxSync(ctx.Context(), tx)
}
}
@@ -209,7 +209,7 @@ type rpcBroadcastTxAsyncFunc func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.R
func makeBroadcastTxAsyncFunc(c *lrpc.Client) rpcBroadcastTxAsyncFunc {
return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return c.BroadcastTxAsync(tx)
return c.BroadcastTxAsync(ctx.Context(), tx)
}
}
@@ -217,7 +217,7 @@ type rpcABCIQueryFunc func(ctx *rpctypes.Context, path string, data bytes.HexByt
func makeABCIQueryFunc(c *lrpc.Client) rpcABCIQueryFunc {
return func(ctx *rpctypes.Context, path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
return c.ABCIQuery(path, data)
return c.ABCIQuery(ctx.Context(), path, data)
}
}
@@ -225,7 +225,7 @@ type rpcABCIInfoFunc func(ctx *rpctypes.Context) (*ctypes.ResultABCIInfo, error)
func makeABCIInfoFunc(c *lrpc.Client) rpcABCIInfoFunc {
return func(ctx *rpctypes.Context) (*ctypes.ResultABCIInfo, error) {
return c.ABCIInfo()
return c.ABCIInfo(ctx.Context())
}
}
@@ -234,6 +234,6 @@ type rpcBroadcastEvidenceFunc func(ctx *rpctypes.Context, ev types.Evidence) (*c
// nolint: interfacer
func makeBroadcastEvidenceFunc(c *lrpc.Client) rpcBroadcastEvidenceFunc {
return func(ctx *rpctypes.Context, ev types.Evidence) (*ctypes.ResultBroadcastEvidence, error) {
return c.BroadcastEvidence(ev)
return c.BroadcastEvidence(ctx.Context(), ev)
}
}
+62 -62
View File
@@ -61,24 +61,24 @@ func (c *Client) OnStop() {
}
}
func (c *Client) Status() (*ctypes.ResultStatus, error) {
return c.next.Status()
func (c *Client) Status(ctx context.Context) (*ctypes.ResultStatus, error) {
return c.next.Status(ctx)
}
func (c *Client) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return c.next.ABCIInfo()
func (c *Client) ABCIInfo(ctx context.Context) (*ctypes.ResultABCIInfo, error) {
return c.next.ABCIInfo(ctx)
}
func (c *Client) ABCIQuery(path string, data tmbytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
return c.ABCIQueryWithOptions(path, data, rpcclient.DefaultABCIQueryOptions)
func (c *Client) ABCIQuery(ctx context.Context, path string, data tmbytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
return c.ABCIQueryWithOptions(ctx, path, data, rpcclient.DefaultABCIQueryOptions)
}
// GetWithProofOptions is useful if you want full access to the ABCIQueryOptions.
// XXX Usage of path? It's not used, and sometimes it's /, sometimes /key, sometimes /store.
func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes,
func (c *Client) ABCIQueryWithOptions(ctx context.Context, path string, data tmbytes.HexBytes,
opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
res, err := c.next.ABCIQueryWithOptions(path, data, opts)
res, err := c.next.ABCIQueryWithOptions(ctx, path, data, opts)
if err != nil {
return nil, err
}
@@ -97,7 +97,7 @@ func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes,
// Update the light client if we're behind.
// NOTE: AppHash for height H is in header H+1.
l, err := c.updateLightClientIfNeededTo(resp.Height + 1)
l, err := c.updateLightClientIfNeededTo(ctx, resp.Height+1)
if err != nil {
return nil, err
}
@@ -129,44 +129,44 @@ func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes,
return &ctypes.ResultABCIQuery{Response: resp}, nil
}
func (c *Client) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
return c.next.BroadcastTxCommit(tx)
func (c *Client) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
return c.next.BroadcastTxCommit(ctx, tx)
}
func (c *Client) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return c.next.BroadcastTxAsync(tx)
func (c *Client) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return c.next.BroadcastTxAsync(ctx, tx)
}
func (c *Client) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return c.next.BroadcastTxSync(tx)
func (c *Client) BroadcastTxSync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return c.next.BroadcastTxSync(ctx, tx)
}
func (c *Client) UnconfirmedTxs(limit *int) (*ctypes.ResultUnconfirmedTxs, error) {
return c.next.UnconfirmedTxs(limit)
func (c *Client) UnconfirmedTxs(ctx context.Context, limit *int) (*ctypes.ResultUnconfirmedTxs, error) {
return c.next.UnconfirmedTxs(ctx, limit)
}
func (c *Client) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
return c.next.NumUnconfirmedTxs()
func (c *Client) NumUnconfirmedTxs(ctx context.Context) (*ctypes.ResultUnconfirmedTxs, error) {
return c.next.NumUnconfirmedTxs(ctx)
}
func (c *Client) CheckTx(tx types.Tx) (*ctypes.ResultCheckTx, error) {
return c.next.CheckTx(tx)
func (c *Client) CheckTx(ctx context.Context, tx types.Tx) (*ctypes.ResultCheckTx, error) {
return c.next.CheckTx(ctx, tx)
}
func (c *Client) NetInfo() (*ctypes.ResultNetInfo, error) {
return c.next.NetInfo()
func (c *Client) NetInfo(ctx context.Context) (*ctypes.ResultNetInfo, error) {
return c.next.NetInfo(ctx)
}
func (c *Client) DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
return c.next.DumpConsensusState()
func (c *Client) DumpConsensusState(ctx context.Context) (*ctypes.ResultDumpConsensusState, error) {
return c.next.DumpConsensusState(ctx)
}
func (c *Client) ConsensusState() (*ctypes.ResultConsensusState, error) {
return c.next.ConsensusState()
func (c *Client) ConsensusState(ctx context.Context) (*ctypes.ResultConsensusState, error) {
return c.next.ConsensusState(ctx)
}
func (c *Client) ConsensusParams(height *int64) (*ctypes.ResultConsensusParams, error) {
res, err := c.next.ConsensusParams(height)
func (c *Client) ConsensusParams(ctx context.Context, height *int64) (*ctypes.ResultConsensusParams, error) {
res, err := c.next.ConsensusParams(ctx, height)
if err != nil {
return nil, err
}
@@ -180,7 +180,7 @@ func (c *Client) ConsensusParams(height *int64) (*ctypes.ResultConsensusParams,
}
// Update the light client if we're behind.
l, err := c.updateLightClientIfNeededTo(res.BlockHeight)
l, err := c.updateLightClientIfNeededTo(ctx, res.BlockHeight)
if err != nil {
return nil, err
}
@@ -194,14 +194,14 @@ func (c *Client) ConsensusParams(height *int64) (*ctypes.ResultConsensusParams,
return res, nil
}
func (c *Client) Health() (*ctypes.ResultHealth, error) {
return c.next.Health()
func (c *Client) Health(ctx context.Context) (*ctypes.ResultHealth, error) {
return c.next.Health(ctx)
}
// BlockchainInfo calls rpcclient#BlockchainInfo and then verifies every header
// returned.
func (c *Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
res, err := c.next.BlockchainInfo(minHeight, maxHeight)
func (c *Client) BlockchainInfo(ctx context.Context, minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
res, err := c.next.BlockchainInfo(ctx, minHeight, maxHeight)
if err != nil {
return nil, err
}
@@ -219,7 +219,7 @@ func (c *Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlock
// Update the light client if we're behind.
if len(res.BlockMetas) > 0 {
lastHeight := res.BlockMetas[len(res.BlockMetas)-1].Header.Height
if _, err := c.updateLightClientIfNeededTo(lastHeight); err != nil {
if _, err := c.updateLightClientIfNeededTo(ctx, lastHeight); err != nil {
return nil, err
}
}
@@ -239,13 +239,13 @@ func (c *Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlock
return res, nil
}
func (c *Client) Genesis() (*ctypes.ResultGenesis, error) {
return c.next.Genesis()
func (c *Client) Genesis(ctx context.Context) (*ctypes.ResultGenesis, error) {
return c.next.Genesis(ctx)
}
// Block calls rpcclient#Block and then verifies the result.
func (c *Client) Block(height *int64) (*ctypes.ResultBlock, error) {
res, err := c.next.Block(height)
func (c *Client) Block(ctx context.Context, height *int64) (*ctypes.ResultBlock, error) {
res, err := c.next.Block(ctx, height)
if err != nil {
return nil, err
}
@@ -263,7 +263,7 @@ func (c *Client) Block(height *int64) (*ctypes.ResultBlock, error) {
}
// Update the light client if we're behind.
l, err := c.updateLightClientIfNeededTo(res.Block.Height)
l, err := c.updateLightClientIfNeededTo(ctx, res.Block.Height)
if err != nil {
return nil, err
}
@@ -278,8 +278,8 @@ func (c *Client) Block(height *int64) (*ctypes.ResultBlock, error) {
}
// BlockByHash calls rpcclient#BlockByHash and then verifies the result.
func (c *Client) BlockByHash(hash []byte) (*ctypes.ResultBlock, error) {
res, err := c.next.BlockByHash(hash)
func (c *Client) BlockByHash(ctx context.Context, hash []byte) (*ctypes.ResultBlock, error) {
res, err := c.next.BlockByHash(ctx, hash)
if err != nil {
return nil, err
}
@@ -297,7 +297,7 @@ func (c *Client) BlockByHash(hash []byte) (*ctypes.ResultBlock, error) {
}
// Update the light client if we're behind.
l, err := c.updateLightClientIfNeededTo(res.Block.Height)
l, err := c.updateLightClientIfNeededTo(ctx, res.Block.Height)
if err != nil {
return nil, err
}
@@ -313,10 +313,10 @@ func (c *Client) BlockByHash(hash []byte) (*ctypes.ResultBlock, error) {
// BlockResults returns the block results for the given height. If no height is
// provided, the results of the block preceding the latest are returned.
func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error) {
func (c *Client) BlockResults(ctx context.Context, height *int64) (*ctypes.ResultBlockResults, error) {
var h int64
if height == nil {
res, err := c.next.Status()
res, err := c.next.Status(ctx)
if err != nil {
return nil, fmt.Errorf("can't get latest height: %w", err)
}
@@ -327,7 +327,7 @@ func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error)
h = *height
}
res, err := c.next.BlockResults(&h)
res, err := c.next.BlockResults(ctx, &h)
if err != nil {
return nil, err
}
@@ -338,7 +338,7 @@ func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error)
}
// Update the light client if we're behind.
trustedBlock, err := c.updateLightClientIfNeededTo(h + 1)
trustedBlock, err := c.updateLightClientIfNeededTo(ctx, h+1)
if err != nil {
return nil, err
}
@@ -374,8 +374,8 @@ func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error)
return res, nil
}
func (c *Client) Commit(height *int64) (*ctypes.ResultCommit, error) {
res, err := c.next.Commit(height)
func (c *Client) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) {
res, err := c.next.Commit(ctx, height)
if err != nil {
return nil, err
}
@@ -389,7 +389,7 @@ func (c *Client) Commit(height *int64) (*ctypes.ResultCommit, error) {
}
// Update the light client if we're behind.
l, err := c.updateLightClientIfNeededTo(res.Height)
l, err := c.updateLightClientIfNeededTo(ctx, res.Height)
if err != nil {
return nil, err
}
@@ -405,8 +405,8 @@ func (c *Client) Commit(height *int64) (*ctypes.ResultCommit, error) {
// Tx calls rpcclient#Tx method and then verifies the proof if such was
// requested.
func (c *Client) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
res, err := c.next.Tx(hash, prove)
func (c *Client) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) {
res, err := c.next.Tx(ctx, hash, prove)
if err != nil || !prove {
return res, err
}
@@ -417,7 +417,7 @@ func (c *Client) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
}
// Update the light client if we're behind.
l, err := c.updateLightClientIfNeededTo(res.Height)
l, err := c.updateLightClientIfNeededTo(ctx, res.Height)
if err != nil {
return nil, err
}
@@ -426,17 +426,17 @@ func (c *Client) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
return res, res.Proof.Validate(l.DataHash)
}
func (c *Client) TxSearch(query string, prove bool, page, perPage *int, orderBy string) (
func (c *Client) TxSearch(ctx context.Context, query string, prove bool, page, perPage *int, orderBy string) (
*ctypes.ResultTxSearch, error) {
return c.next.TxSearch(query, prove, page, perPage, orderBy)
return c.next.TxSearch(ctx, query, prove, page, perPage, orderBy)
}
// Validators fetches and verifies validators.
//
// WARNING: only full validator sets are verified (when length of validators is
// less than +perPage+. +perPage+ default is 30, max is 100).
func (c *Client) Validators(height *int64, page, perPage *int) (*ctypes.ResultValidators, error) {
res, err := c.next.Validators(height, page, perPage)
func (c *Client) Validators(ctx context.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error) {
res, err := c.next.Validators(ctx, height, page, perPage)
if err != nil {
return nil, err
}
@@ -454,7 +454,7 @@ func (c *Client) Validators(height *int64, page, perPage *int) (*ctypes.ResultVa
}
// Update the light client if we're behind.
l, err := c.updateLightClientIfNeededTo(updateHeight)
l, err := c.updateLightClientIfNeededTo(ctx, updateHeight)
if err != nil {
return nil, err
}
@@ -480,8 +480,8 @@ func (c *Client) Validators(height *int64, page, perPage *int) (*ctypes.ResultVa
return res, nil
}
func (c *Client) BroadcastEvidence(ev types.Evidence) (*ctypes.ResultBroadcastEvidence, error) {
return c.next.BroadcastEvidence(ev)
func (c *Client) BroadcastEvidence(ctx context.Context, ev types.Evidence) (*ctypes.ResultBroadcastEvidence, error) {
return c.next.BroadcastEvidence(ctx, ev)
}
func (c *Client) Subscribe(ctx context.Context, subscriber, query string,
@@ -497,8 +497,8 @@ func (c *Client) UnsubscribeAll(ctx context.Context, subscriber string) error {
return c.next.UnsubscribeAll(ctx, subscriber)
}
func (c *Client) updateLightClientIfNeededTo(height int64) (*types.LightBlock, error) {
l, err := c.lc.VerifyLightBlockAtHeight(height, time.Now())
func (c *Client) updateLightClientIfNeededTo(ctx context.Context, height int64) (*types.LightBlock, error) {
l, err := c.lc.VerifyLightBlockAtHeight(ctx, height, time.Now())
if err != nil {
return nil, fmt.Errorf("failed to update light client to %d: %w", height, err)
}
+3
View File
@@ -1,6 +1,7 @@
package light
import (
"context"
"time"
"github.com/tendermint/tendermint/light/provider"
@@ -15,6 +16,7 @@ import (
// See all Option(s) for the additional configuration.
// See NewClient.
func NewHTTPClient(
ctx context.Context,
chainID string,
trustOptions TrustOptions,
primaryAddress string,
@@ -28,6 +30,7 @@ func NewHTTPClient(
}
return NewClient(
ctx,
chainID,
trustOptions,
providers[len(providers)-1],