fix(wallet) ClientWithFallback handling state errors required by BH

The "not found" and "no contract" expected error is caught and wrapped
by ClientWithFallback. The fetching of balance history of next blocks
is aborted which is not desired.

Fix by not treating the error as a connection error in
ClientWithFallback.
This commit is contained in:
Stefan 2023-04-27 17:44:24 +03:00 committed by Stefan Dunca
parent dd6cb5394d
commit a6d553c937
3 changed files with 13 additions and 4 deletions

View File

@ -11,6 +11,7 @@ import (
"github.com/afex/hystrix-go/hystrix" "github.com/afex/hystrix-go/hystrix"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"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"
@ -39,7 +40,8 @@ type ClientWithFallback struct {
LastCheckedAt int64 LastCheckedAt int64
} }
var vmErrors = []error{ // Don't mark connection as failed if we get one of these errors
var propagateErrors = []error{
vm.ErrOutOfGas, vm.ErrOutOfGas,
vm.ErrCodeStoreOutOfGas, vm.ErrCodeStoreOutOfGas,
vm.ErrDepth, vm.ErrDepth,
@ -53,6 +55,10 @@ var vmErrors = []error{
vm.ErrGasUintOverflow, vm.ErrGasUintOverflow,
vm.ErrInvalidCode, vm.ErrInvalidCode,
vm.ErrNonceUintOverflow, vm.ErrNonceUintOverflow,
// Used by balance history to check state
ethereum.NotFound,
bind.ErrNoCode,
} }
type CommandResult struct { type CommandResult struct {
@ -114,7 +120,7 @@ func isVMError(err error) bool {
if strings.HasPrefix(err.Error(), "execution reverted") { if strings.HasPrefix(err.Error(), "execution reverted") {
return true return true
} }
for _, vmError := range vmErrors { for _, vmError := range propagateErrors {
if err == vmError { if err == vmError {
return true return true
} }

View File

@ -172,7 +172,8 @@ func (b *Balance) fetchAndCache(ctx context.Context, source DataSource, address
return &dataPoint, blockNo, nil return &dataPoint, blockNo, nil
} }
// update fetches the balance history for a given asset from DB first and missing information from the blockchain to minimize the RPC calls // update retrieves the balance history for a specified asset from the database initially
// and supplements any missing information from the blockchain to minimize the number of RPC calls.
// if context is cancelled it will return with error // if context is cancelled it will return with error
func (b *Balance) update(ctx context.Context, source DataSource, address common.Address, timeInterval TimeInterval) error { func (b *Balance) update(ctx context.Context, source DataSource, address common.Address, timeInterval TimeInterval) error {
startTimestamp := int64(0) startTimestamp := int64(0)

View File

@ -10,6 +10,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"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"
@ -171,6 +172,7 @@ func (src *chainClientSource) TimeNow() int64 {
return time.Now().UTC().Unix() return time.Now().UTC().Unix()
} }
// ERC20 token implementation of DataSource interface
type tokenChainClientSource struct { type tokenChainClientSource struct {
chainClientSource chainClientSource
TokenManager *token.Manager TokenManager *token.Manager
@ -193,7 +195,7 @@ func (src *tokenChainClientSource) BalanceAt(ctx context.Context, account common
} }
balance, err := src.TokenManager.GetTokenBalanceAt(ctx, src.chainClient, account, token.Address, blockNumber) balance, err := src.TokenManager.GetTokenBalanceAt(ctx, src.chainClient, account, token.Address, blockNumber)
if err != nil { if err != nil {
if err.Error() == "no contract code at given address" { if err == bind.ErrNoCode {
// Ignore requests before contract deployment and mark this state for future requests // Ignore requests before contract deployment and mark this state for future requests
src.firstUnavailableBlockNo = new(big.Int).Set(blockNumber) src.firstUnavailableBlockNo = new(big.Int).Set(blockNumber)
return big.NewInt(0), nil return big.NewInt(0), nil