From a6d553c9375eb608cbd39da1adb8fee19f0378a5 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 27 Apr 2023 17:44:24 +0300 Subject: [PATCH] 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. --- rpc/chain/client.go | 10 ++++++++-- services/wallet/history/balance.go | 3 ++- services/wallet/history/service.go | 4 +++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/rpc/chain/client.go b/rpc/chain/client.go index 0e490d501..c7ad53682 100644 --- a/rpc/chain/client.go +++ b/rpc/chain/client.go @@ -11,6 +11,7 @@ import ( "github.com/afex/hystrix-go/hystrix" "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/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -39,7 +40,8 @@ type ClientWithFallback struct { LastCheckedAt int64 } -var vmErrors = []error{ +// Don't mark connection as failed if we get one of these errors +var propagateErrors = []error{ vm.ErrOutOfGas, vm.ErrCodeStoreOutOfGas, vm.ErrDepth, @@ -53,6 +55,10 @@ var vmErrors = []error{ vm.ErrGasUintOverflow, vm.ErrInvalidCode, vm.ErrNonceUintOverflow, + + // Used by balance history to check state + ethereum.NotFound, + bind.ErrNoCode, } type CommandResult struct { @@ -114,7 +120,7 @@ func isVMError(err error) bool { if strings.HasPrefix(err.Error(), "execution reverted") { return true } - for _, vmError := range vmErrors { + for _, vmError := range propagateErrors { if err == vmError { return true } diff --git a/services/wallet/history/balance.go b/services/wallet/history/balance.go index 7a90cf816..bff1983cb 100644 --- a/services/wallet/history/balance.go +++ b/services/wallet/history/balance.go @@ -172,7 +172,8 @@ func (b *Balance) fetchAndCache(ctx context.Context, source DataSource, address 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 func (b *Balance) update(ctx context.Context, source DataSource, address common.Address, timeInterval TimeInterval) error { startTimestamp := int64(0) diff --git a/services/wallet/history/service.go b/services/wallet/history/service.go index 7b004caf3..c2a7ebfe0 100644 --- a/services/wallet/history/service.go +++ b/services/wallet/history/service.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -171,6 +172,7 @@ func (src *chainClientSource) TimeNow() int64 { return time.Now().UTC().Unix() } +// ERC20 token implementation of DataSource interface type tokenChainClientSource struct { chainClientSource 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) 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 src.firstUnavailableBlockNo = new(big.Int).Set(blockNumber) return big.NewInt(0), nil