feat: avoid vm error to retry
This commit is contained in:
parent
bb6139aef1
commit
1189fb882e
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/afex/hystrix-go/hystrix"
|
"github.com/afex/hystrix-go/hystrix"
|
||||||
|
@ -12,6 +13,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/status-im/status-go/services/rpcstats"
|
"github.com/status-im/status-go/services/rpcstats"
|
||||||
|
@ -33,6 +35,28 @@ type ClientWithFallback struct {
|
||||||
LastCheckedAt int64
|
LastCheckedAt int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var vmErrors = []error{
|
||||||
|
vm.ErrOutOfGas,
|
||||||
|
vm.ErrCodeStoreOutOfGas,
|
||||||
|
vm.ErrDepth,
|
||||||
|
vm.ErrInsufficientBalance,
|
||||||
|
vm.ErrContractAddressCollision,
|
||||||
|
vm.ErrExecutionReverted,
|
||||||
|
vm.ErrMaxCodeSizeExceeded,
|
||||||
|
vm.ErrInvalidJump,
|
||||||
|
vm.ErrWriteProtection,
|
||||||
|
vm.ErrReturnDataOutOfBounds,
|
||||||
|
vm.ErrGasUintOverflow,
|
||||||
|
vm.ErrInvalidCode,
|
||||||
|
vm.ErrNonceUintOverflow,
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandResult struct {
|
||||||
|
res1 any
|
||||||
|
res2 any
|
||||||
|
vmError error
|
||||||
|
}
|
||||||
|
|
||||||
func NewSimpleClient(main *rpc.Client, chainID uint64) *ClientWithFallback {
|
func NewSimpleClient(main *rpc.Client, chainID uint64) *ClientWithFallback {
|
||||||
hystrix.ConfigureCommand(fmt.Sprintf("ethClient_%d", chainID), hystrix.CommandConfig{
|
hystrix.ConfigureCommand(fmt.Sprintf("ethClient_%d", chainID), hystrix.CommandConfig{
|
||||||
Timeout: 10000,
|
Timeout: 10000,
|
||||||
|
@ -82,16 +106,31 @@ func (c *ClientWithFallback) Close() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isVMError(err error) bool {
|
||||||
|
if strings.HasPrefix(err.Error(), "execution reverted") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, vmError := range vmErrors {
|
||||||
|
if err == vmError {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClientWithFallback) makeCallNoReturn(main func() error, fallback func() error) error {
|
func (c *ClientWithFallback) makeCallNoReturn(main func() error, fallback func() error) error {
|
||||||
output := make(chan struct{}, 1)
|
resultChan := make(chan CommandResult, 1)
|
||||||
c.LastCheckedAt = time.Now().Unix()
|
c.LastCheckedAt = time.Now().Unix()
|
||||||
errChan := hystrix.Go(fmt.Sprintf("ethClient_%d", c.ChainID), func() error {
|
errChan := hystrix.Go(fmt.Sprintf("ethClient_%d", c.ChainID), func() error {
|
||||||
err := main()
|
err := main()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if isVMError(err) {
|
||||||
|
resultChan <- CommandResult{vmError: err}
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.IsConnected = true
|
c.IsConnected = true
|
||||||
output <- struct{}{}
|
resultChan <- CommandResult{}
|
||||||
return nil
|
return nil
|
||||||
}, func(err error) error {
|
}, func(err error) error {
|
||||||
if c.fallback == nil {
|
if c.fallback == nil {
|
||||||
|
@ -104,12 +143,15 @@ func (c *ClientWithFallback) makeCallNoReturn(main func() error, fallback func()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.IsConnected = true
|
c.IsConnected = true
|
||||||
output <- struct{}{}
|
resultChan <- CommandResult{}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-output:
|
case result := <-resultChan:
|
||||||
|
if result.vmError != nil {
|
||||||
|
return result.vmError
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
return err
|
return err
|
||||||
|
@ -117,15 +159,18 @@ func (c *ClientWithFallback) makeCallNoReturn(main func() error, fallback func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClientWithFallback) makeCallSingleReturn(main func() (any, error), fallback func() (any, error)) (any, error) {
|
func (c *ClientWithFallback) makeCallSingleReturn(main func() (any, error), fallback func() (any, error)) (any, error) {
|
||||||
resultChan := make(chan any, 1)
|
resultChan := make(chan CommandResult, 1)
|
||||||
c.LastCheckedAt = time.Now().Unix()
|
c.LastCheckedAt = time.Now().Unix()
|
||||||
errChan := hystrix.Go(fmt.Sprintf("ethClient_%d", c.ChainID), func() error {
|
errChan := hystrix.Go(fmt.Sprintf("ethClient_%d", c.ChainID), func() error {
|
||||||
res, err := main()
|
res, err := main()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if isVMError(err) {
|
||||||
|
resultChan <- CommandResult{vmError: err}
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.IsConnected = true
|
c.IsConnected = true
|
||||||
resultChan <- res
|
resultChan <- CommandResult{res1: res}
|
||||||
return nil
|
return nil
|
||||||
}, func(err error) error {
|
}, func(err error) error {
|
||||||
if c.fallback == nil {
|
if c.fallback == nil {
|
||||||
|
@ -138,28 +183,33 @@ func (c *ClientWithFallback) makeCallSingleReturn(main func() (any, error), fall
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.IsConnected = true
|
c.IsConnected = true
|
||||||
resultChan <- res
|
resultChan <- CommandResult{res1: res}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
case result := <-resultChan:
|
case result := <-resultChan:
|
||||||
return result, nil
|
if result.vmError != nil {
|
||||||
|
return nil, result.vmError
|
||||||
|
}
|
||||||
|
return result.res1, nil
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClientWithFallback) makeCallDoubleReturn(main func() (any, any, error), fallback func() (any, any, error)) (any, any, error) {
|
func (c *ClientWithFallback) makeCallDoubleReturn(main func() (any, any, error), fallback func() (any, any, error)) (any, any, error) {
|
||||||
resultChan := make(chan []any, 1)
|
resultChan := make(chan CommandResult, 1)
|
||||||
c.LastCheckedAt = time.Now().Unix()
|
c.LastCheckedAt = time.Now().Unix()
|
||||||
errChan := hystrix.Go(fmt.Sprintf("ethClient_%d", c.ChainID), func() error {
|
errChan := hystrix.Go(fmt.Sprintf("ethClient_%d", c.ChainID), func() error {
|
||||||
a, b, err := main()
|
a, b, err := main()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if isVMError(err) {
|
||||||
|
resultChan <- CommandResult{vmError: err}
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.IsConnected = true
|
c.IsConnected = true
|
||||||
resultChan <- []any{a, b}
|
resultChan <- CommandResult{res1: a, res2: b}
|
||||||
return nil
|
return nil
|
||||||
}, func(err error) error {
|
}, func(err error) error {
|
||||||
if c.fallback == nil {
|
if c.fallback == nil {
|
||||||
|
@ -172,13 +222,16 @@ func (c *ClientWithFallback) makeCallDoubleReturn(main func() (any, any, error),
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.IsConnected = true
|
c.IsConnected = true
|
||||||
resultChan <- []any{a, b}
|
resultChan <- CommandResult{res1: a, res2: b}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case result := <-resultChan:
|
case result := <-resultChan:
|
||||||
return result[0], result[1], nil
|
if result.vmError != nil {
|
||||||
|
return nil, nil, result.vmError
|
||||||
|
}
|
||||||
|
return result.res1, result.res2, nil
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue