Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Classify Arbitrum rpc server errors #15488

Merged
merged 8 commits into from
Dec 12, 2024
Merged
38 changes: 30 additions & 8 deletions core/chains/evm/client/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ const (
ServiceUnavailable
TerminallyStuck
TooManyResults
ServiceTimeout
ServiceTemporarilyUnavailable
)

type ClientErrors map[int]*regexp.Regexp
Expand Down Expand Up @@ -153,14 +155,16 @@ var arbitrumFatal = regexp.MustCompile(`(: |^)(invalid message format|forbidden
var arbitrum = ClientErrors{
// TODO: Arbitrum returns this in case of low or high nonce. Update this when Arbitrum fix it
// Archived ticket: story/16801/add-full-support-for-incorrect-nonce-on-arbitrum
NonceTooLow: regexp.MustCompile(`(: |^)invalid transaction nonce$|(: |^)nonce too low(:|$)`),
NonceTooHigh: regexp.MustCompile(`(: |^)nonce too high(:|$)`),
TerminallyUnderpriced: regexp.MustCompile(`(: |^)gas price too low$`),
InsufficientEth: regexp.MustCompile(`(: |^)(not enough funds for gas|insufficient funds for gas \* price \+ value)`),
Fatal: arbitrumFatal,
L2FeeTooLow: regexp.MustCompile(`(: |^)max fee per gas less than block base fee(:|$)`),
L2Full: regexp.MustCompile(`(: |^)(queue full|sequencer pending tx pool full, please try again)(:|$)`),
ServiceUnavailable: regexp.MustCompile(`(: |^)502 Bad Gateway: [\s\S]*$|network is unreachable|i/o timeout`),
NonceTooLow: regexp.MustCompile(`(: |^)invalid transaction nonce$|(: |^)nonce too low(:|$)`),
NonceTooHigh: regexp.MustCompile(`(: |^)nonce too high(:|$)`),
TerminallyUnderpriced: regexp.MustCompile(`(: |^)gas price too low$`),
InsufficientEth: regexp.MustCompile(`(: |^)(not enough funds for gas|insufficient funds for gas \* price \+ value)`),
Fatal: arbitrumFatal,
L2FeeTooLow: regexp.MustCompile(`(: |^)max fee per gas less than block base fee(:|$)`),
L2Full: regexp.MustCompile(`(: |^)(queue full|sequencer pending tx pool full, please try again)(:|$)`),
ServiceUnavailable: regexp.MustCompile(`(: |^)502 Bad Gateway: [\s\S]*$|network is unreachable|i/o timeout`),
ServiceTemporarilyUnavailable: regexp.MustCompile(`(: |^)503 Service Temporarily Unavailable(:|$)`),
DylanTinianov marked this conversation as resolved.
Show resolved Hide resolved
ServiceTimeout: regexp.MustCompile(`(: |^)408 Request Timeout(:|$)`),
DylanTinianov marked this conversation as resolved.
Show resolved Hide resolved
}

// Treasure
Expand Down Expand Up @@ -398,6 +402,16 @@ func (s *SendError) IsServiceUnavailable(configErrors *ClientErrors) bool {
return s.is(ServiceUnavailable, configErrors) || pkgerrors.Is(s.err, commonclient.ErroringNodeError)
}

// IsServiceTemporarilyUnavailable indicates if the error was caused by a service being temporarily unavailable
func (s *SendError) IsServiceTemporarilyUnavailable(configErrors *ClientErrors) bool {
return s.is(ServiceTemporarilyUnavailable, configErrors)
}

// IsServiceTimeout indicates if the error was caused by a service timeout
func (s *SendError) IsServiceTimeout(configErrors *ClientErrors) bool {
return s.is(ServiceTimeout, configErrors)
}

// IsTerminallyStuck indicates if a transaction was stuck without any chance of inclusion
func (s *SendError) IsTerminallyStuckConfigError(configErrors *ClientErrors) bool {
return s.is(TerminallyStuck, configErrors)
Expand Down Expand Up @@ -619,6 +633,14 @@ func ClassifySendError(err error, clientErrors config.ClientErrors, lggr logger.
lggr.Errorw(fmt.Sprintf("service unavailable while sending transaction %x", tx.Hash()), "err", sendError, "etx", tx)
return commonclient.Retryable
}
if sendError.IsServiceTemporarilyUnavailable(configErrors) {
lggr.Errorw(fmt.Sprintf("service temporarily unavailable while sending transaction %x", tx.Hash()), "err", sendError, "etx", tx)
return commonclient.Retryable
}
if sendError.IsServiceTimeout(configErrors) {
lggr.Errorw(fmt.Sprintf("service timed out while sending transaction %x", tx.Hash()), "err", sendError, "etx", tx)
return commonclient.Retryable
}
if sendError.IsTimeout() {
lggr.Errorw(fmt.Sprintf("timeout while sending transaction %x", tx.Hash()), "err", sendError, "etx", tx)
return commonclient.Retryable
Expand Down
27 changes: 27 additions & 0 deletions core/chains/evm/client/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,33 @@ func Test_Eth_Errors(t *testing.T) {
}
})

t.Run("IsServiceTemporarilyUnavailable", func(t *testing.T) {
tests := []errorCase{
{"call failed: 503 Service Temporarily Unavailable: <html>\r\n<head><title>503 Service Temporarily Unavailable</title></head>\r\n<body>\r\n<center><h1>503 Service Temporarily Unavailable</h1></center>\r\n</body>\r\n</html>\r\n", true, "Arbitrum"},
{"client error service unavailable", false, "tomlConfig"},
}
for _, test := range tests {
err = evmclient.NewSendErrorS(test.message)
assert.Equal(t, err.IsServiceTemporarilyUnavailable(clientErrors), test.expect)
err = newSendErrorWrapped(test.message)
assert.Equal(t, err.IsServiceTemporarilyUnavailable(clientErrors), test.expect)
}
})

t.Run("IsServiceTimeout", func(t *testing.T) {
tests := []errorCase{
{"call failed: 408 Request Timeout: {", true, "Arbitrum"},
{"408 Request Timeout: {\"id\":303,\"jsonrpc\":\"2.0\",\"error\":{\"code\\\":-32009,\\\"message\\\":\\\"request timeout\\\"}}\",\"errVerbose\":\"408 Request Timeout:\n", true, "Arbitrum"},
{"request timeout", false, "tomlConfig"},
}
for _, test := range tests {
err = evmclient.NewSendErrorS(test.message)
assert.Equal(t, err.IsServiceTimeout(clientErrors), test.expect)
err = newSendErrorWrapped(test.message)
assert.Equal(t, err.IsServiceTimeout(clientErrors), test.expect)
}
})

t.Run("IsTxFeeExceedsCap", func(t *testing.T) {
tests := []errorCase{
{"tx fee (1.10 ether) exceeds the configured cap (1.00 ether)", true, "geth"},
Expand Down
Loading