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.

96 lines
2.5 KiB

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