diff --git a/agents/agents/executor/executor.go b/agents/agents/executor/executor.go index bbd8855d51..1f96ad7993 100644 --- a/agents/agents/executor/executor.go +++ b/agents/agents/executor/executor.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" ethTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/jpillora/backoff" "github.com/synapsecns/sanguine/agents/agents/executor/db" execTypes "github.com/synapsecns/sanguine/agents/agents/executor/types" "github.com/synapsecns/sanguine/agents/config/executor" @@ -24,6 +23,7 @@ import ( "github.com/synapsecns/sanguine/agents/types" "github.com/synapsecns/sanguine/core/merkle" "github.com/synapsecns/sanguine/core/metrics" + "github.com/synapsecns/sanguine/core/retry" ethergoChain "github.com/synapsecns/sanguine/ethergo/chain" agentsConfig "github.com/synapsecns/sanguine/ethergo/signer/config" "github.com/synapsecns/sanguine/ethergo/signer/signer" @@ -87,6 +87,8 @@ type Executor struct { handler metrics.Handler // txSubmitter is the transaction submitter. txSubmitter submitter.TransactionSubmitter + // retryConfig is the retry configuration for RPC calls. + retryConfig []retry.WithBackoffConfigurator // NowFunc returns the current time. NowFunc func() time.Time } @@ -99,7 +101,6 @@ type logOrderInfo struct { const ( logChanSize = 1000 - rpcRetry = 7 scribeConnectTimeout = 30 * time.Second ) @@ -148,6 +149,14 @@ func NewExecutor(ctx context.Context, config executor.Config, executorDB db.Exec txSubmitter := submitter.NewTransactionSubmitter(handler, executorSigner, omniRPCClient, executorDB.SubmitterDB(), &config.SubmitterConfig) + if config.MaxRetrySeconds == 0 { + config.MaxRetrySeconds = 30 + } + + retryConfig := []retry.WithBackoffConfigurator{ + retry.WithMaxAttemptTime(time.Second * time.Duration(config.MaxRetrySeconds)), + } + if config.ExecuteInterval == 0 { config.ExecuteInterval = 2 } @@ -239,6 +248,7 @@ func NewExecutor(ctx context.Context, config executor.Config, executorDB db.Exec chainExecutors: chainExecutors, handler: handler, txSubmitter: txSubmitter, + retryConfig: retryConfig, NowFunc: time.Now, }, nil } @@ -340,8 +350,16 @@ func (e Executor) Execute(parentCtx context.Context, message types.Message) (_ b return false, nil } - proof, err := e.chainExecutors[message.OriginDomain()].merkleTree.MerkleProof(*nonce-1, (*state).Nonce()) + var proof [][]byte + contractCall := func(ctx context.Context) error { + proof, err = e.chainExecutors[message.OriginDomain()].merkleTree.MerkleProof(*nonce-1, (*state).Nonce()) + if err != nil { + return fmt.Errorf("could not get merkle proof: %w", err) + } + return nil + } + err = retry.WithBackoff(ctx, contractCall, e.retryConfig...) if err != nil { return false, fmt.Errorf("could not get merkle proof: %w", err) } @@ -425,12 +443,31 @@ func (e Executor) Execute(parentCtx context.Context, message types.Message) (_ b // verifyMessageMerkleProof verifies a message against the merkle tree at the state of the given nonce. func (e Executor) verifyMessageMerkleProof(message types.Message) (bool, error) { - root, err := e.chainExecutors[message.OriginDomain()].merkleTree.Root(message.Nonce()) + var root []byte + contractCall := func(ctx context.Context) error { + var err error + root, err = e.chainExecutors[message.OriginDomain()].merkleTree.Root(message.Nonce()) + if err != nil { + return fmt.Errorf("could not get root: %w", err) + } + + return nil + } + err := retry.WithBackoff(context.Background(), contractCall, e.retryConfig...) if err != nil { return false, fmt.Errorf("could not get root: %w", err) } - proof, err := e.chainExecutors[message.OriginDomain()].merkleTree.MerkleProof(message.Nonce()-1, message.Nonce()) + var proof [][]byte + contractCall = func(ctx context.Context) error { + proof, err = e.chainExecutors[message.OriginDomain()].merkleTree.MerkleProof(message.Nonce()-1, message.Nonce()) + if err != nil { + return fmt.Errorf("could not get merkle proof: %w", err) + } + + return nil + } + err = retry.WithBackoff(context.Background(), contractCall, e.retryConfig...) if err != nil { return false, fmt.Errorf("could not get merkle proof: %w", err) } @@ -523,38 +560,25 @@ func (e Executor) verifyMessageOptimisticPeriod(parentCtx context.Context, messa return nil, nil } - b := &backoff.Backoff{ - Factor: 2, - Jitter: true, - Min: 30 * time.Millisecond, - Max: 3 * time.Second, - } - - timeout := time.Duration(0) - var currentTime uint64 + chainCall := func(ctx context.Context) error { + var err error + latestHeader, err := e.chainExecutors[chainID].rpcClient.HeaderByNumber(ctx, nil) + if err != nil { + return fmt.Errorf("could not get latest header: %w", err) + } -retryLoop: - for { - select { - case <-ctx.Done(): - return nil, fmt.Errorf("context canceled: %w", ctx.Err()) - case <-time.After(timeout): - if b.Attempt() >= rpcRetry { - return nil, fmt.Errorf("could not get latest header: %w", err) - } - - latestHeader, err := e.chainExecutors[destinationDomain].rpcClient.HeaderByNumber(ctx, nil) - if err != nil { - timeout = b.Duration() - - continue - } + if latestHeader == nil { + return fmt.Errorf("latest header is nil") + } - currentTime = latestHeader.Time + currentTime = latestHeader.Time - break retryLoop - } + return nil + } + err = retry.WithBackoff(ctx, chainCall, e.retryConfig...) + if err != nil { + return nil, fmt.Errorf("could not get latest header: %w", err) } if *messageMinimumTime > currentTime { @@ -616,43 +640,28 @@ func (e Executor) checkIfExecuted(parentCtx context.Context, message types.Messa metrics.EndSpanWithErr(span, err) }() - b := &backoff.Backoff{ - Factor: 2, - Jitter: true, - Min: 30 * time.Millisecond, - Max: 3 * time.Second, - } - - timeout := time.Duration(0) - - for { - select { - case <-ctx.Done(): - return false, fmt.Errorf("context canceled: %w", ctx.Err()) - case <-time.After(timeout): - if b.Attempt() >= rpcRetry { - return false, fmt.Errorf("could not get executed status: %w", ctx.Err()) - } - - executed, err := e.chainExecutors[message.DestinationDomain()].boundDestination.MessageStatus(ctx, message) - if err != nil { - timeout = b.Duration() - span.AddEvent("could not get executed status", - trace.WithAttributes(attribute.String("error", err.Error())), - trace.WithAttributes(attribute.String("timeout", timeout.String())), - ) - continue - } + var executed uint8 + contractCall := func(ctx context.Context) error { + var err error + executed, err = e.chainExecutors[message.DestinationDomain()].boundDestination.MessageStatus(ctx, message) + if err != nil { + return fmt.Errorf("could not get executed status: %w", err) + } - if execTypes.MessageStatusType(executed) == execTypes.Success { - span.AddEvent("message executed") - return true, nil - } + return nil + } + err = retry.WithBackoff(ctx, contractCall, e.retryConfig...) + if err != nil { + return false, fmt.Errorf("could not get executed status: %w", err) + } - span.AddEvent("message not executed") - return false, nil - } + if execTypes.MessageStatusType(executed) == execTypes.Success { + span.AddEvent("message executed") + return true, nil } + + span.AddEvent("message not executed") + return false, nil } // streamLogs uses gRPC to stream logs into a channel. diff --git a/agents/agents/executor/executor_utils.go b/agents/agents/executor/executor_utils.go index 5133432c45..026940aa76 100644 --- a/agents/agents/executor/executor_utils.go +++ b/agents/agents/executor/executor_utils.go @@ -4,16 +4,15 @@ import ( "context" "fmt" "math/big" - "time" "github.com/ethereum/go-ethereum/common" ethTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/jpillora/backoff" "github.com/synapsecns/sanguine/agents/contracts/inbox" "github.com/synapsecns/sanguine/agents/contracts/lightinbox" "github.com/synapsecns/sanguine/agents/contracts/origin" "github.com/synapsecns/sanguine/agents/contracts/summit" "github.com/synapsecns/sanguine/agents/types" + "github.com/synapsecns/sanguine/core/retry" ) // logToMessage converts the log to a leaf data. @@ -154,19 +153,30 @@ func (e Executor) processMessage(ctx context.Context, message types.Message, log // processAttestation processes and stores an attestation. func (e Executor) processSnapshot(ctx context.Context, snapshot types.Snapshot, logBlockNumber uint64) error { - for _, state := range snapshot.States() { + for _, s := range snapshot.States() { + state := s statePayload, err := state.Encode() if err != nil { return fmt.Errorf("could not encode state: %w", err) } // Verify that the state is valid w.r.t. Origin. - valid, err := e.chainExecutors[state.Origin()].boundOrigin.IsValidState( - ctx, - statePayload, - ) + var valid bool + contractCall := func(ctx context.Context) error { + valid, err = e.chainExecutors[state.Origin()].boundOrigin.IsValidState( + ctx, + statePayload, + ) + if err != nil { + return fmt.Errorf("could not check validity of state: %w", err) + } + + return nil + } + err = retry.WithBackoff(ctx, contractCall, e.retryConfig...) if err != nil { return fmt.Errorf("could not check validity of state: %w", err) } + if !valid { stateRoot := state.Root() logger.Infof("snapshot has invalid state. Origin: %d. SnapshotRoot: %s", state.Origin(), common.BytesToHash(stateRoot[:]).String()) @@ -199,36 +209,23 @@ func (e Executor) processAttestation(ctx context.Context, attestation types.Atte } // If the attestation is on a remote chain, we need to fetch the timestamp via an RPC call. - b := &backoff.Backoff{ - Factor: 2, - Jitter: true, - Min: 30 * time.Millisecond, - Max: 3 * time.Second, - } - - timeout := time.Duration(0) - var logHeader *ethTypes.Header var err error + contractCall := func(ctx context.Context) error { + logHeader, err = e.chainExecutors[chainID].rpcClient.HeaderByNumber(ctx, big.NewInt(int64(logBlockNumber))) + if err != nil { + return fmt.Errorf("could not get log header: %w", err) + } -retryLoop: - for { - select { - case <-ctx.Done(): - return fmt.Errorf("context canceled: %w", ctx.Err()) - case <-time.After(timeout): - if b.Attempt() >= rpcRetry { - return fmt.Errorf("could not get log header: %w", err) - } - logHeader, err = e.chainExecutors[chainID].rpcClient.HeaderByNumber(ctx, big.NewInt(int64(logBlockNumber))) - if err != nil { - timeout = b.Duration() - - continue - } + return nil + } + err = retry.WithBackoff(ctx, contractCall, e.retryConfig...) + if err != nil { + return fmt.Errorf("could not get log header: %w", err) + } - break retryLoop - } + if logHeader == nil { + return fmt.Errorf("could not get log header") } err = e.executorDB.StoreAttestation(ctx, attestation, chainID, logBlockNumber, logHeader.Time) diff --git a/agents/agents/guard/guard.go b/agents/agents/guard/guard.go index 929978b4df..1596c209fe 100644 --- a/agents/agents/guard/guard.go +++ b/agents/agents/guard/guard.go @@ -178,6 +178,11 @@ func NewGuard(ctx context.Context, cfg config.AgentConfig, omniRPCClient omnirpc guard.originLatestStates = make(map[uint32]types.State, len(guard.domains)) guard.handler = handler guard.txSubmitter = submitter.NewTransactionSubmitter(handler, guard.unbondedSigner, omniRPCClient, guardDB.SubmitterDB(), &cfg.SubmitterConfig) + + if cfg.MaxRetrySeconds == 0 { + cfg.MaxRetrySeconds = 60 + } + guard.retryConfig = []retry.WithBackoffConfigurator{ retry.WithMaxAttemptTime(time.Second * time.Duration(cfg.MaxRetrySeconds)), } @@ -276,16 +281,19 @@ func (g Guard) loadSummitLatestStates(parentCtx context.Context) { )) originID := domain.Config().DomainID - latestState, err := g.domains[g.summitDomainID].Summit().GetLatestAgentState(ctx, originID, g.bondedSigner) - if err != nil { - latestState = nil - logger.Errorf("Failed calling GetLatestAgentState for originID %d on the Summit contract: err = %v", originID, err) - span.AddEvent("Failed calling GetLatestAgentState for originID on the Summit contract", trace.WithAttributes( - attribute.Int("originID", int(originID)), - attribute.String("err", err.Error()), - )) + + var latestState types.State + var err error + contractCall := func(ctx context.Context) error { + latestState, err = g.domains[g.summitDomainID].Summit().GetLatestAgentState(ctx, originID, g.bondedSigner) + if err != nil { + return fmt.Errorf("failed calling GetLatestAgentState for originID %d on the Summit contract: err = %w", originID, err) + } + + return nil } - if latestState != nil && latestState.Nonce() > uint32(0) { + err = retry.WithBackoff(ctx, contractCall, g.retryConfig...) + if err == nil && latestState.Nonce() > uint32(0) { g.summitLatestStates[originID] = latestState } @@ -295,12 +303,15 @@ func (g Guard) loadSummitLatestStates(parentCtx context.Context) { //nolint:cyclop func (g Guard) loadOriginLatestStates(parentCtx context.Context) { - for _, domain := range g.domains { + for _, d := range g.domains { + domain := d ctx, span := g.handler.Tracer().Start(parentCtx, "loadOriginLatestStates", trace.WithAttributes( attribute.Int("domain", int(domain.Config().DomainID)), )) originID := domain.Config().DomainID + + // TODO: Wrap this with a retry if `Start` behavior changes. latestState, err := domain.Origin().SuggestLatestState(ctx) if err != nil { latestState = nil diff --git a/agents/agents/notary/notary.go b/agents/agents/notary/notary.go index 974c34c3bc..77a5fa2b09 100644 --- a/agents/agents/notary/notary.go +++ b/agents/agents/notary/notary.go @@ -7,22 +7,22 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/synapsecns/sanguine/agents/agents/notary/db" - "github.com/synapsecns/sanguine/core/metrics" - signerConfig "github.com/synapsecns/sanguine/ethergo/signer/config" - "github.com/synapsecns/sanguine/ethergo/submitter" - omnirpcClient "github.com/synapsecns/sanguine/services/omnirpc/client" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" - - "github.com/ethereum/go-ethereum/common" "github.com/synapsecns/sanguine/agents/config" "github.com/synapsecns/sanguine/agents/contracts/summit" "github.com/synapsecns/sanguine/agents/domains" "github.com/synapsecns/sanguine/agents/domains/evm" "github.com/synapsecns/sanguine/agents/types" + "github.com/synapsecns/sanguine/core/metrics" + "github.com/synapsecns/sanguine/core/retry" + signerConfig "github.com/synapsecns/sanguine/ethergo/signer/config" "github.com/synapsecns/sanguine/ethergo/signer/signer" + "github.com/synapsecns/sanguine/ethergo/submitter" + omnirpcClient "github.com/synapsecns/sanguine/services/omnirpc/client" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "golang.org/x/sync/errgroup" ) @@ -42,6 +42,7 @@ type Notary struct { summitParser summit.Parser lastSummitBlock uint64 handler metrics.Handler + retryConfig []retry.WithBackoffConfigurator txSubmitter submitter.TransactionSubmitter } @@ -90,6 +91,13 @@ func NewNotary(ctx context.Context, cfg config.AgentConfig, omniRPCClient omnirp } notary.handler = handler + if cfg.MaxRetrySeconds == 0 { + cfg.MaxRetrySeconds = 30 + } + + notary.retryConfig = []retry.WithBackoffConfigurator{ + retry.WithMaxAttemptTime(time.Second * time.Duration(cfg.MaxRetrySeconds)), + } notary.txSubmitter = submitter.NewTransactionSubmitter(handler, notary.unbondedSigner, omniRPCClient, txDB.SubmitterDB(), &cfg.SubmitterConfig) @@ -124,13 +132,15 @@ func (n *Notary) loadSummitMyLatestStates(parentCtx context.Context) { //nolint:cyclop func (n *Notary) loadSummitGuardLatestStates(parentCtx context.Context) { - for _, domain := range n.domains { + for _, d := range n.domains { + domain := d ctx, span := n.handler.Tracer().Start(parentCtx, "loadSummitGuardLatestStates", trace.WithAttributes( attribute.Int(metrics.ChainID, int(domain.Config().DomainID)), )) originID := domain.Config().DomainID + // TODO: Wrap this with a retry loop if we deviate from the current `Start` behavior. guardLatestState, err := n.summitDomain.Summit().GetLatestState(ctx, originID) if err != nil { guardLatestState = nil @@ -153,12 +163,22 @@ func (n *Notary) loadNotaryLatestAttestation(parentCtx context.Context) { )) defer span.End() - latestNotaryAttestation, err := n.summitDomain.Summit().GetLatestNotaryAttestation(ctx, n.bondedSigner) + var latestNotaryAttestation types.NotaryAttestation + contractCall := func(ctx context.Context) (err error) { + latestNotaryAttestation, err = n.summitDomain.Summit().GetLatestNotaryAttestation(ctx, n.bondedSigner) + if err != nil { + return fmt.Errorf("could not get latest notary attestation: %w", err) + } + + return nil + } + err := retry.WithBackoff(ctx, contractCall, n.retryConfig...) if err != nil { span.AddEvent("GetLatestNotaryAttestation failed", trace.WithAttributes( attribute.String("err", err.Error()), )) } + if latestNotaryAttestation != nil { if n.myLatestNotaryAttestation == nil || latestNotaryAttestation.Attestation().SnapshotRoot() != n.myLatestNotaryAttestation.Attestation().SnapshotRoot() { @@ -173,20 +193,39 @@ func (n *Notary) shouldNotaryRegisteredOnDestination(parentCtx context.Context) attribute.Int(metrics.ChainID, int(n.destinationDomain.Config().DomainID)), )) defer span.End() + var bondingManagerAgentRoot [32]byte + contractCall := func(ctx context.Context) (err error) { + bondingManagerAgentRoot, err = n.summitDomain.BondingManager().GetAgentRoot(ctx) + if err != nil { + return fmt.Errorf("could not get agent root: %w", err) + } - bondingManagerAgentRoot, err := n.summitDomain.BondingManager().GetAgentRoot(ctx) + return nil + } + err := retry.WithBackoff(ctx, contractCall, n.retryConfig...) if err != nil { span.AddEvent("GetAgentRoot failed on bonding manager", trace.WithAttributes( attribute.String("err", err.Error()), )) + return false, false } - destinationLightManagerAgentRoot, err := n.destinationDomain.LightManager().GetAgentRoot(ctx) + var destinationLightManagerAgentRoot [32]byte + contractCall = func(ctx context.Context) (err error) { + destinationLightManagerAgentRoot, err = n.destinationDomain.LightManager().GetAgentRoot(ctx) + if err != nil { + return fmt.Errorf("could not get agent root: %w", err) + } + + return nil + } + err = retry.WithBackoff(ctx, contractCall, n.retryConfig...) if err != nil { span.AddEvent("GetAgentRoot failed on destination light manager", trace.WithAttributes( attribute.String("err", err.Error()), )) + return false, false } @@ -195,13 +234,24 @@ func (n *Notary) shouldNotaryRegisteredOnDestination(parentCtx context.Context) return false, false } - agentStatus, err := n.destinationDomain.LightManager().GetAgentStatus(ctx, n.bondedSigner.Address()) + var agentStatus types.AgentStatus + contractCall = func(ctx context.Context) (err error) { + agentStatus, err = n.destinationDomain.LightManager().GetAgentStatus(ctx, n.bondedSigner.Address()) + if err != nil { + return fmt.Errorf("could not get agent status: %w", err) + } + + return nil + } + err = retry.WithBackoff(ctx, contractCall, n.retryConfig...) if err != nil { span.AddEvent("GetAgentStatus failed", trace.WithAttributes( attribute.String("err", err.Error()), )) + return false, false } + if agentStatus.Flag() == types.AgentFlagUnknown { // Here we want to add the Notary and proceed with sending to destination return true, true @@ -227,12 +277,22 @@ func (n *Notary) checkDidSubmitNotaryLatestAttestation(parentCtx context.Context return } - attNonce, err := n.destinationDomain.Destination().GetAttestationNonce(ctx, n.myLatestNotaryAttestation.Attestation().SnapshotRoot()) + var attNonce uint32 + contractCall := func(ctx context.Context) (err error) { + attNonce, err = n.destinationDomain.Destination().GetAttestationNonce(ctx, n.myLatestNotaryAttestation.Attestation().SnapshotRoot()) + if err != nil { + return fmt.Errorf("could not get attestation nonce: %w", err) + } + + return nil + } + err := retry.WithBackoff(ctx, contractCall, n.retryConfig...) if err != nil { - span.AddEvent("checkDidSubmitNotaryLatestAttestation failed", trace.WithAttributes( + span.AddEvent("GetAttestationNonce failed", trace.WithAttributes( attribute.String("err", err.Error()), )) } + if attNonce > 0 { n.didSubmitMyLatestNotaryAttestation = true } @@ -253,7 +313,16 @@ func (n *Notary) isValidOnOrigin(parentCtx context.Context, state types.State, d defer span.End() - stateOnOrigin, err := domain.Origin().SuggestState(ctx, state.Nonce()) + var stateOnOrigin types.State + contractCall := func(ctx context.Context) (err error) { + stateOnOrigin, err = domain.Origin().SuggestState(ctx, state.Nonce()) + if err != nil { + return fmt.Errorf("could not suggest state: %w", err) + } + + return nil + } + err := retry.WithBackoff(ctx, contractCall, n.retryConfig...) if err != nil { span.AddEvent("SuggestState failed", trace.WithAttributes( attribute.String("err", err.Error()), @@ -412,28 +481,47 @@ func (n *Notary) submitLatestSnapshot(parentCtx context.Context) { } } -// codebeat:disable[CYCLO,DEPTH,LOC] -// //nolint:cyclop func (n *Notary) registerNotaryOnDestination(parentCtx context.Context) bool { ctx, span := n.handler.Tracer().Start(parentCtx, "registerNotaryOnDestination") defer span.End() - agentProof, err := n.summitDomain.BondingManager().GetProof(ctx, n.bondedSigner.Address()) + var agentProof [][32]byte + contractCall := func(ctx context.Context) (err error) { + agentProof, err = n.summitDomain.BondingManager().GetProof(ctx, n.bondedSigner.Address()) + if err != nil { + return fmt.Errorf("could not get agent proof: %w", err) + } + + return nil + } + err := retry.WithBackoff(ctx, contractCall, n.retryConfig...) if err != nil { - logger.Errorf("Error getting agent proof: %v", err) - span.AddEvent("Error getting agent proof", trace.WithAttributes( + span.AddEvent("GetProof on bonding manager failed", trace.WithAttributes( attribute.String("err", err.Error()), )) + return false } - agentStatus, err := n.summitDomain.BondingManager().GetAgentStatus(ctx, n.bondedSigner.Address()) + + var agentStatus types.AgentStatus + contractCall = func(ctx context.Context) (err error) { + agentStatus, err = n.summitDomain.BondingManager().GetAgentStatus(ctx, n.bondedSigner.Address()) + if err != nil { + return fmt.Errorf("could not get agent status: %w", err) + } + + return nil + } + err = retry.WithBackoff(ctx, contractCall, n.retryConfig...) if err != nil { span.AddEvent("GetAgentStatus on bonding manager failed", trace.WithAttributes( attribute.String("err", err.Error()), )) + return false } + _, err = n.txSubmitter.SubmitTransaction(ctx, big.NewInt(int64(n.destinationDomain.Config().DomainID)), func(transactor *bind.TransactOpts) (tx *ethTypes.Transaction, err error) { tx, err = n.destinationDomain.LightManager().UpdateAgentStatus( transactor, @@ -500,8 +588,6 @@ func (n *Notary) submitMyLatestAttestation(parentCtx context.Context) { // Start starts the notary. // -// codebeat:disable[CYCLO,DEPTH] -// //nolint:cyclop func (n *Notary) Start(parentCtx context.Context) error { g, ctx := errgroup.WithContext(parentCtx) diff --git a/agents/config/executor/config.go b/agents/config/executor/config.go index 5d0b178063..3ae01e82a2 100644 --- a/agents/config/executor/config.go +++ b/agents/config/executor/config.go @@ -3,14 +3,15 @@ package executor import ( "context" "fmt" + "os" + "path/filepath" + "github.com/davecgh/go-spew/spew" "github.com/jftuga/ellipsis" "github.com/synapsecns/sanguine/agents/config" signerConfig "github.com/synapsecns/sanguine/ethergo/signer/config" submitterConfig "github.com/synapsecns/sanguine/ethergo/submitter/config" "gopkg.in/yaml.v2" - "os" - "path/filepath" ) // Config is used to configure an Executor agent. @@ -44,6 +45,8 @@ type Config struct { DBPrefix string `yaml:"db_prefix"` // SubmitterConfig is the config for the submitter. SubmitterConfig submitterConfig.Config `yaml:"submitter_config"` + // MaxRetrySeconds is the maximum number of seconds to retry an RPC call (not a transaction). + MaxRetrySeconds uint32 `yaml:"max_retry_seconds"` } // IsValid makes sure the config is valid. This is done by calling IsValid() on each diff --git a/agents/go.mod b/agents/go.mod index 8eac1f944b..2820dfab1a 100644 --- a/agents/go.mod +++ b/agents/go.mod @@ -16,7 +16,6 @@ require ( github.com/ipfs/go-log v1.0.5 github.com/jftuga/ellipsis v1.0.0 github.com/jftuga/termsize v1.0.2 - github.com/jpillora/backoff v1.0.0 github.com/libs4go/crypto v0.0.1 github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/richardwilkes/toolbox v1.74.0 @@ -42,7 +41,10 @@ require ( gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 ) -require dario.cat/mergo v1.0.0 // indirect +require ( + dario.cat/mergo v1.0.0 // indirect + github.com/jpillora/backoff v1.0.0 // indirect +) require ( bitbucket.org/tentontrain/math v0.0.0-20220519191623-a4e86beba92a // indirect