github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/privval/retry_signer_client.go (about)

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