You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

104 lines
2.7 KiB

  1. package privval
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "github.com/tendermint/tendermint/crypto"
  7. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  8. "github.com/tendermint/tendermint/types"
  9. )
  10. // RetrySignerClient wraps SignerClient adding retry for each operation (except
  11. // Ping) w/ a timeout.
  12. type RetrySignerClient struct {
  13. next *SignerClient
  14. retries int
  15. timeout time.Duration
  16. }
  17. // NewRetrySignerClient returns RetrySignerClient. If +retries+ is 0, the
  18. // client will be retrying each operation indefinitely.
  19. func NewRetrySignerClient(sc *SignerClient, retries int, timeout time.Duration) *RetrySignerClient {
  20. return &RetrySignerClient{sc, retries, timeout}
  21. }
  22. var _ types.PrivValidator = (*RetrySignerClient)(nil)
  23. func (sc *RetrySignerClient) Close() error {
  24. return sc.next.Close()
  25. }
  26. func (sc *RetrySignerClient) IsConnected() bool {
  27. return sc.next.IsConnected()
  28. }
  29. func (sc *RetrySignerClient) WaitForConnection(ctx context.Context, maxWait time.Duration) error {
  30. return sc.next.WaitForConnection(ctx, maxWait)
  31. }
  32. //--------------------------------------------------------
  33. // Implement PrivValidator
  34. func (sc *RetrySignerClient) Ping(ctx context.Context) error {
  35. return sc.next.Ping(ctx)
  36. }
  37. func (sc *RetrySignerClient) GetPubKey(ctx context.Context) (crypto.PubKey, error) {
  38. var (
  39. pk crypto.PubKey
  40. err error
  41. )
  42. t := time.NewTimer(sc.timeout)
  43. for i := 0; i < sc.retries || sc.retries == 0; i++ {
  44. pk, err = sc.next.GetPubKey(ctx)
  45. if err == nil {
  46. return pk, nil
  47. }
  48. // If remote signer errors, we don't retry.
  49. if _, ok := err.(*RemoteSignerError); ok {
  50. return nil, err
  51. }
  52. select {
  53. case <-ctx.Done():
  54. return nil, ctx.Err()
  55. case <-t.C:
  56. t.Reset(sc.timeout)
  57. }
  58. }
  59. return nil, fmt.Errorf("exhausted all attempts to get pubkey: %w", err)
  60. }
  61. func (sc *RetrySignerClient) SignVote(ctx context.Context, chainID string, vote *tmproto.Vote) error {
  62. var err error
  63. for i := 0; i < sc.retries || sc.retries == 0; i++ {
  64. err = sc.next.SignVote(ctx, chainID, vote)
  65. if err == nil {
  66. return nil
  67. }
  68. // If remote signer errors, we don't retry.
  69. if _, ok := err.(*RemoteSignerError); ok {
  70. return err
  71. }
  72. time.Sleep(sc.timeout)
  73. }
  74. return fmt.Errorf("exhausted all attempts to sign vote: %w", err)
  75. }
  76. func (sc *RetrySignerClient) SignProposal(ctx context.Context, chainID string, proposal *tmproto.Proposal) error {
  77. var err error
  78. for i := 0; i < sc.retries || sc.retries == 0; i++ {
  79. err = sc.next.SignProposal(ctx, chainID, proposal)
  80. if err == nil {
  81. return nil
  82. }
  83. // If remote signer errors, we don't retry.
  84. if _, ok := err.(*RemoteSignerError); ok {
  85. return err
  86. }
  87. time.Sleep(sc.timeout)
  88. }
  89. return fmt.Errorf("exhausted all attempts to sign proposal: %w", err)
  90. }