Browse Source

light: fix provider error plumbing (#7610)

The custom error types in the provider package did not propagate their wrapped
underlying reasons, making it difficult for the test to check that the correct
error was observed.

- Fix the custom errors to have a true underlying error (not just a string).
- Add Unwrap methods to support inspection by errors.Is.
- Update usage in a few places.
- Fix the test to check for acceptable variation.

Fixes #7609.
pull/7614/head
M. J. Fromberger 3 years ago
committed by GitHub
parent
commit
679b6a65b8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 17 additions and 10 deletions
  1. +1
    -1
      internal/statesync/dispatcher.go
  2. +7
    -3
      light/provider/errors.go
  3. +4
    -4
      light/provider/http/http.go
  4. +5
    -2
      light/provider/http/http_test.go

+ 1
- 1
internal/statesync/dispatcher.go View File

@ -195,7 +195,7 @@ func (p *BlockProvider) LightBlock(ctx context.Context, height int64) (*types.Li
case errPeerAlreadyBusy: case errPeerAlreadyBusy:
return nil, provider.ErrLightBlockNotFound return nil, provider.ErrLightBlockNotFound
default: default:
return nil, provider.ErrUnreliableProvider{Reason: err.Error()}
return nil, provider.ErrUnreliableProvider{Reason: err}
} }
// check that the height requested is the same one returned // check that the height requested is the same one returned


+ 7
- 3
light/provider/errors.go View File

@ -28,16 +28,20 @@ type ErrBadLightBlock struct {
} }
func (e ErrBadLightBlock) Error() string { func (e ErrBadLightBlock) Error() string {
return fmt.Sprintf("client provided bad signed header: %s", e.Reason.Error())
return fmt.Sprintf("client provided bad signed header: %v", e.Reason)
} }
func (e ErrBadLightBlock) Unwrap() error { return e.Reason }
// ErrUnreliableProvider is a generic error that indicates that the provider isn't // ErrUnreliableProvider is a generic error that indicates that the provider isn't
// behaving in a reliable manner to the light client. The light client will // behaving in a reliable manner to the light client. The light client will
// remove the provider // remove the provider
type ErrUnreliableProvider struct { type ErrUnreliableProvider struct {
Reason string
Reason error
} }
func (e ErrUnreliableProvider) Error() string { func (e ErrUnreliableProvider) Error() string {
return fmt.Sprintf("client deemed unreliable: %s", e.Reason)
return fmt.Sprintf("client deemed unreliable: %v", e.Reason)
} }
func (e ErrUnreliableProvider) Unwrap() error { return e.Reason }

+ 4
- 4
light/provider/http/http.go View File

@ -212,7 +212,7 @@ func (p *http) validatorSet(ctx context.Context, height *int64) (*types.Validato
// If we don't know the error then by default we return an unreliable provider error and // If we don't know the error then by default we return an unreliable provider error and
// terminate the connection with the peer. // terminate the connection with the peer.
return nil, provider.ErrUnreliableProvider{Reason: e.Error()}
return nil, provider.ErrUnreliableProvider{Reason: e}
} }
// update the total and increment the page index so we can fetch the // update the total and increment the page index so we can fetch the
@ -268,7 +268,7 @@ func (p *http) signedHeader(ctx context.Context, height *int64) (*types.SignedHe
// If we don't know the error then by default we return an unreliable provider error and // If we don't know the error then by default we return an unreliable provider error and
// terminate the connection with the peer. // terminate the connection with the peer.
return nil, provider.ErrUnreliableProvider{Reason: e.Error()}
return nil, provider.ErrUnreliableProvider{Reason: e}
} }
} }
return nil, p.noResponse() return nil, p.noResponse()
@ -278,7 +278,7 @@ func (p *http) noResponse() error {
p.noResponseCount++ p.noResponseCount++
if p.noResponseCount > p.noResponseThreshold { if p.noResponseCount > p.noResponseThreshold {
return provider.ErrUnreliableProvider{ return provider.ErrUnreliableProvider{
Reason: fmt.Sprintf("failed to respond after %d attempts", p.noResponseCount),
Reason: fmt.Errorf("failed to respond after %d attempts", p.noResponseCount),
} }
} }
return provider.ErrNoResponse return provider.ErrNoResponse
@ -288,7 +288,7 @@ func (p *http) noBlock(e error) error {
p.noBlockCount++ p.noBlockCount++
if p.noBlockCount > p.noBlockThreshold { if p.noBlockCount > p.noBlockThreshold {
return provider.ErrUnreliableProvider{ return provider.ErrUnreliableProvider{
Reason: fmt.Sprintf("failed to provide a block after %d attempts", p.noBlockCount),
Reason: fmt.Errorf("failed to provide a block after %d attempts", p.noBlockCount),
} }
} }
return e return e


+ 5
- 2
light/provider/http/http_test.go View File

@ -2,6 +2,7 @@ package http_test
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"testing" "testing"
"time" "time"
@ -100,8 +101,10 @@ func TestProvider(t *testing.T) {
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
lb, err = p.LightBlock(ctx, lower+2) lb, err = p.LightBlock(ctx, lower+2)
// we should see a connection refused
// Either the connection should be refused, or the context canceled.
require.Error(t, err) require.Error(t, err)
require.Nil(t, lb) require.Nil(t, lb)
assert.Equal(t, provider.ErrConnectionClosed, err)
if !errors.Is(err, provider.ErrConnectionClosed) && !errors.Is(err, context.Canceled) {
assert.Fail(t, "Incorrect error", "wanted connection closed or context canceled, got %v", err)
}
} }

Loading…
Cancel
Save