|
@ -18,8 +18,10 @@ var ( |
|
|
// This is very brittle, see: https://github.com/tendermint/tendermint/issues/4740
|
|
|
// This is very brittle, see: https://github.com/tendermint/tendermint/issues/4740
|
|
|
regexpMissingHeight = regexp.MustCompile(`height \d+ (must be less than or equal to|is not available)`) |
|
|
regexpMissingHeight = regexp.MustCompile(`height \d+ (must be less than or equal to|is not available)`) |
|
|
|
|
|
|
|
|
defaultMaxRetryAttempts = 10 |
|
|
|
|
|
defaultTimeout = 5 * time.Second |
|
|
|
|
|
|
|
|
defaultOptions = Options{ |
|
|
|
|
|
MaxRetryAttempts: 10, |
|
|
|
|
|
Timeout: 5 * time.Second, |
|
|
|
|
|
} |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
// http provider uses an RPC client to obtain the necessary information.
|
|
|
// http provider uses an RPC client to obtain the necessary information.
|
|
@ -30,39 +32,46 @@ type http struct { |
|
|
maxRetryAttempts int |
|
|
maxRetryAttempts int |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type Options struct { |
|
|
|
|
|
// -1 means no limit
|
|
|
|
|
|
MaxRetryAttempts int |
|
|
|
|
|
// 0 means no timeout.
|
|
|
|
|
|
Timeout time.Duration |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// New creates a HTTP provider, which is using the rpchttp.HTTP client under
|
|
|
// New creates a HTTP provider, which is using the rpchttp.HTTP client under
|
|
|
// the hood. If no scheme is provided in the remote URL, http will be used by
|
|
|
// the hood. If no scheme is provided in the remote URL, http will be used by
|
|
|
// default. The 5s timeout is used for all requests.
|
|
|
// default. The 5s timeout is used for all requests.
|
|
|
func New(chainID, remote string) (provider.Provider, error) { |
|
|
func New(chainID, remote string) (provider.Provider, error) { |
|
|
return NewWithOptions(chainID, remote, defaultMaxRetryAttempts, defaultTimeout) |
|
|
|
|
|
|
|
|
return NewWithOptions(chainID, remote, defaultOptions) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// NewWithOptions is an extension to creating a new http provider that allows the addition
|
|
|
// NewWithOptions is an extension to creating a new http provider that allows the addition
|
|
|
// of a specified timeout and maxRetryAttempts
|
|
|
// of a specified timeout and maxRetryAttempts
|
|
|
func NewWithOptions(chainID, remote string, maxRetryAttempts int, timeout time.Duration) (provider.Provider, error) { |
|
|
|
|
|
|
|
|
func NewWithOptions(chainID, remote string, options Options) (provider.Provider, error) { |
|
|
// Ensure URL scheme is set (default HTTP) when not provided.
|
|
|
// Ensure URL scheme is set (default HTTP) when not provided.
|
|
|
if !strings.Contains(remote, "://") { |
|
|
if !strings.Contains(remote, "://") { |
|
|
remote = "http://" + remote |
|
|
remote = "http://" + remote |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
httpClient, err := rpchttp.NewWithTimeout(remote, "/websocket", timeout) |
|
|
|
|
|
|
|
|
httpClient, err := rpchttp.NewWithTimeout(remote, "/websocket", options.Timeout) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, err |
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return NewWithClientAndOptions(chainID, httpClient, maxRetryAttempts), nil |
|
|
|
|
|
|
|
|
return NewWithClientAndOptions(chainID, httpClient, options), nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func NewWithClient(chainID string, client rpcclient.RemoteClient) provider.Provider { |
|
|
func NewWithClient(chainID string, client rpcclient.RemoteClient) provider.Provider { |
|
|
return NewWithClientAndOptions(chainID, client, defaultMaxRetryAttempts) |
|
|
|
|
|
|
|
|
return NewWithClientAndOptions(chainID, client, defaultOptions) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// NewWithClient allows you to provide a custom client.
|
|
|
// NewWithClient allows you to provide a custom client.
|
|
|
func NewWithClientAndOptions(chainID string, client rpcclient.RemoteClient, maxRetryAttempts int) provider.Provider { |
|
|
|
|
|
|
|
|
func NewWithClientAndOptions(chainID string, client rpcclient.RemoteClient, options Options) provider.Provider { |
|
|
return &http{ |
|
|
return &http{ |
|
|
client: client, |
|
|
client: client, |
|
|
chainID: chainID, |
|
|
chainID: chainID, |
|
|
maxRetryAttempts: maxRetryAttempts, |
|
|
|
|
|
|
|
|
maxRetryAttempts: options.MaxRetryAttempts, |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -121,7 +130,9 @@ func (p *http) validatorSet(ctx context.Context, height *int64) (*types.Validato |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
for len(vals) != total && page <= maxPages { |
|
|
for len(vals) != total && page <= maxPages { |
|
|
for attempt := 1; attempt <= p.maxRetryAttempts; attempt++ { |
|
|
|
|
|
|
|
|
// create another for loop to control retries. If p.maxRetryAttempts
|
|
|
|
|
|
// is negative we will keep repeating.
|
|
|
|
|
|
for attempt := 0; attempt != p.maxRetryAttempts+1; attempt++ { |
|
|
res, err := p.client.Validators(ctx, height, &page, &perPage) |
|
|
res, err := p.client.Validators(ctx, height, &page, &perPage) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
// TODO: standardize errors on the RPC side
|
|
|
// TODO: standardize errors on the RPC side
|
|
@ -166,7 +177,9 @@ func (p *http) validatorSet(ctx context.Context, height *int64) (*types.Validato |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (p *http) signedHeader(ctx context.Context, height *int64) (*types.SignedHeader, error) { |
|
|
func (p *http) signedHeader(ctx context.Context, height *int64) (*types.SignedHeader, error) { |
|
|
for attempt := 1; attempt <= p.maxRetryAttempts; attempt++ { |
|
|
|
|
|
|
|
|
// create a for loop to control retries. If p.maxRetryAttempts
|
|
|
|
|
|
// is negative we will keep repeating.
|
|
|
|
|
|
for attempt := 0; attempt != p.maxRetryAttempts+1; attempt++ { |
|
|
commit, err := p.client.Commit(ctx, height) |
|
|
commit, err := p.client.Commit(ctx, height) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
// TODO: standardize errors on the RPC side
|
|
|
// TODO: standardize errors on the RPC side
|
|
|