Browse Source

light: improve timeout functionality (#6145)

pull/6151/head
Callum Waters 4 years ago
committed by GitHub
parent
commit
29360f955c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 34 deletions
  1. +5
    -5
      cmd/tendermint/commands/light.go
  2. +25
    -24
      light/provider/http/http.go
  3. +1
    -1
      light/rpc/client.go
  4. +1
    -4
      rpc/jsonrpc/client/http_json_client.go

+ 5
- 5
cmd/tendermint/commands/light.go View File

@ -206,11 +206,6 @@ func runProxy(cmd *cobra.Command, args []string) error {
return err return err
} }
rpcClient, err := rpchttp.New(primaryAddr, "/websocket")
if err != nil {
return fmt.Errorf("http client for %s: %w", primaryAddr, err)
}
cfg := rpcserver.DefaultConfig() cfg := rpcserver.DefaultConfig()
cfg.MaxBodyBytes = config.RPC.MaxBodyBytes cfg.MaxBodyBytes = config.RPC.MaxBodyBytes
cfg.MaxHeaderBytes = config.RPC.MaxHeaderBytes cfg.MaxHeaderBytes = config.RPC.MaxHeaderBytes
@ -222,6 +217,11 @@ func runProxy(cmd *cobra.Command, args []string) error {
cfg.WriteTimeout = config.RPC.TimeoutBroadcastTxCommit + 1*time.Second cfg.WriteTimeout = config.RPC.TimeoutBroadcastTxCommit + 1*time.Second
} }
rpcClient, err := rpchttp.NewWithTimeout(primaryAddr, "/websocket", cfg.WriteTimeout)
if err != nil {
return fmt.Errorf("failed to create http client for %s: %w", primaryAddr, err)
}
p := lproxy.Proxy{ p := lproxy.Proxy{
Addr: listenAddr, Addr: listenAddr,
Config: cfg, Config: cfg,


+ 25
- 24
light/provider/http/http.go View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/rand" "math/rand"
"net/url"
"strings" "strings"
"time" "time"
@ -17,8 +18,8 @@ import (
) )
var defaultOptions = Options{ var defaultOptions = Options{
MaxRetryAttempts: 10,
Timeout: 5 * time.Second,
MaxRetryAttempts: 5,
Timeout: 3 * time.Second,
} }
// http provider uses an RPC client to obtain the necessary information. // http provider uses an RPC client to obtain the necessary information.
@ -146,29 +147,26 @@ func (p *http) validatorSet(ctx context.Context, height *int64) (*types.Validato
} }
} }
case *rpctypes.RPCError:
// Check if we got something other than internal error. This shouldn't happen unless the RPC module
// or light client has been tampered with. If we do get this error, stop the connection with the
// peer and return an error
if e.Code != -32603 {
return nil, provider.ErrBadLightBlock{Reason: errors.New(e.Data)}
case *url.Error:
if e.Timeout() {
// request timed out: we wait and try again with exponential backoff
time.Sleep(backoffTimeout(uint16(attempt)))
continue
} }
return nil, provider.ErrBadLightBlock{Reason: e}
case *rpctypes.RPCError:
// check if the error indicates that the peer doesn't have the block // check if the error indicates that the peer doesn't have the block
if strings.Contains(e.Data, ctypes.ErrHeightNotAvailable.Error()) || if strings.Contains(e.Data, ctypes.ErrHeightNotAvailable.Error()) ||
strings.Contains(e.Data, ctypes.ErrHeightExceedsChainHead.Error()) { strings.Contains(e.Data, ctypes.ErrHeightExceedsChainHead.Error()) {
return nil, provider.ErrLightBlockNotFound return nil, provider.ErrLightBlockNotFound
} }
// we wait and try again with exponential backoff
// TODO: If we can, we should check if the error is purely because the node failed to respond in
// time. If this is the case then we continue, else we should stop straight away
time.Sleep(backoffTimeout(uint16(attempt)))
continue
return nil, provider.ErrBadLightBlock{Reason: e}
default: default:
// something has happened to the RPC module if we are not receiving errors of type RPCError
panic(fmt.Errorf("unexpected error type: %w", err))
// If we don't know the error then by default we return a bad light block error and
// terminate the connection with the peer.
return nil, provider.ErrBadLightBlock{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
@ -196,6 +194,14 @@ func (p *http) signedHeader(ctx context.Context, height *int64) (*types.SignedHe
case nil: // success!! case nil: // success!!
return &commit.SignedHeader, nil return &commit.SignedHeader, nil
case *url.Error:
if e.Timeout() {
// we wait and try again with exponential backoff
time.Sleep(backoffTimeout(uint16(attempt)))
continue
}
return nil, provider.ErrBadLightBlock{Reason: e}
case *rpctypes.RPCError: case *rpctypes.RPCError:
// Check if we got something other than internal error. This shouldn't happen unless the RPC module // Check if we got something other than internal error. This shouldn't happen unless the RPC module
// or light client has been tampered with. If we do get this error, stop the connection with the // or light client has been tampered with. If we do get this error, stop the connection with the
@ -210,15 +216,10 @@ func (p *http) signedHeader(ctx context.Context, height *int64) (*types.SignedHe
return nil, provider.ErrLightBlockNotFound return nil, provider.ErrLightBlockNotFound
} }
// we wait and try again with exponential backoff
// TODO: If we can, we should check if the error is purely because the node failed to respond in
// time. If this is the case then we continue, else we should stop straight away
time.Sleep(backoffTimeout(uint16(attempt)))
continue
default: default:
// something has happened to the RPC module if we are not receiving errors of type RPCError
panic(fmt.Errorf("unexpected error type: %w", err))
// If we don't know the error then by default we return a bad light block error and
// terminate the connection with the peer.
return nil, provider.ErrBadLightBlock{Reason: e}
} }
} }
return nil, provider.ErrNoResponse return nil, provider.ErrNoResponse


+ 1
- 1
light/rpc/client.go View File

@ -507,7 +507,7 @@ func (c *Client) updateLightClientIfNeededTo(ctx context.Context, height *int64)
l, err = c.lc.VerifyLightBlockAtHeight(ctx, *height, time.Now()) l, err = c.lc.VerifyLightBlockAtHeight(ctx, *height, time.Now())
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to update light client to %d: %w", height, err)
return nil, fmt.Errorf("failed to update light client: %w", err)
} }
return l, nil return l, nil
} }


+ 1
- 4
rpc/jsonrpc/client/http_json_client.go View File

@ -183,11 +183,8 @@ func (c *Client) Call(
} }
httpResponse, err := c.client.Do(httpRequest) httpResponse, err := c.client.Do(httpRequest)
if e, ok := err.(*url.Error); ok && e.Timeout() {
panic("Hello world")
}
if err != nil { if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
return nil, err
} }
defer httpResponse.Body.Close() defer httpResponse.Body.Close()


Loading…
Cancel
Save