internal, eth, core: return RPC error

This commit is contained in:
Gary Rong 2024-01-19 14:06:18 +08:00
parent 64196f9657
commit 4e0eb8b24d
7 changed files with 103 additions and 48 deletions

View file

@ -279,7 +279,7 @@ func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLoo
// The transaction indexing is not finished yet, returning an // The transaction indexing is not finished yet, returning an
// error to explicitly indicate it. // error to explicitly indicate it.
if !progress.done() { if !progress.done() {
return nil, nil, errors.New("transaction is still indexing") return nil, nil, errors.New("transaction indexing still in progress")
} }
// The transaction is already indexed, the transaction is either // The transaction is already indexed, the transaction is either
// not existent or not in the range of index, returning null. // not existent or not in the range of index, returning null.

View file

@ -828,7 +828,7 @@ func containsTx(block *types.Block, hash common.Hash) bool {
func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
found, _, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash) found, _, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
if err != nil { if err != nil {
return nil, err return nil, ethapi.NewTxIndexingError()
} }
// Only mined txes are supported // Only mined txes are supported
if !found { if !found {

View file

@ -113,9 +113,9 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber)
return b.chain.GetBlockByNumber(uint64(number)), nil return b.chain.GetBlockByNumber(uint64(number)), nil
} }
func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) {
tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash) tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash)
return tx, hash, blockNumber, index, nil return true, tx, hash, blockNumber, index, nil
} }
func (b *testBackend) RPCGasCap() uint64 { func (b *testBackend) RPCGasCap() uint64 {

View file

@ -27,7 +27,6 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -1133,37 +1132,6 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap) return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap)
} }
func newRevertError(revert []byte) *revertError {
err := vm.ErrExecutionReverted
reason, errUnpack := abi.UnpackRevert(revert)
if errUnpack == nil {
err = fmt.Errorf("%w: %v", vm.ErrExecutionReverted, reason)
}
return &revertError{
error: err,
reason: hexutil.Encode(revert),
}
}
// revertError is an API error that encompasses an EVM revertal with JSON error
// code and a binary data blob.
type revertError struct {
error
reason string // revert reason hex encoded
}
// ErrorCode returns the JSON error code for a revertal.
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
func (e *revertError) ErrorCode() int {
return 3
}
// ErrorData returns the hex encoded revert reason.
func (e *revertError) ErrorData() interface{} {
return e.reason
}
// Call executes the given transaction on the state for the given block number. // Call executes the given transaction on the state for the given block number.
// //
// Additionally, the caller can specify a batch of contract for fields overriding. // Additionally, the caller can specify a batch of contract for fields overriding.
@ -1658,7 +1626,10 @@ func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H
if tx := s.b.GetPoolTransaction(hash); tx != nil { if tx := s.b.GetPoolTransaction(hash); tx != nil {
return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil
} }
return nil, err if err == nil {
return nil, nil
}
return nil, NewTxIndexingError()
} }
header, err := s.b.HeaderByHash(ctx, blockHash) header, err := s.b.HeaderByHash(ctx, blockHash)
if err != nil { if err != nil {
@ -1672,11 +1643,14 @@ func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash commo
// Retrieve a finalized transaction, or a pooled otherwise // Retrieve a finalized transaction, or a pooled otherwise
found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash) found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash)
if !found { if !found {
if tx = s.b.GetPoolTransaction(hash); tx == nil { if tx = s.b.GetPoolTransaction(hash); tx != nil {
return nil, err return tx.MarshalBinary()
} }
if err == nil {
return nil, nil
}
return nil, NewTxIndexingError()
} }
// Serialize to RLP and return
return tx.MarshalBinary() return tx.MarshalBinary()
} }
@ -1684,7 +1658,7 @@ func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash commo
func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
found, tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) found, tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
if err != nil { if err != nil {
return nil, err // transaction is not fully indexed return nil, NewTxIndexingError() // transaction is not fully indexed
} }
if !found { if !found {
return nil, nil // transaction is not existent or reachable return nil, nil // transaction is not existent or reachable
@ -2079,10 +2053,13 @@ func (s *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hex
// Retrieve a finalized transaction, or a pooled otherwise // Retrieve a finalized transaction, or a pooled otherwise
found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash) found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash)
if !found { if !found {
if tx = s.b.GetPoolTransaction(hash); tx == nil { if tx = s.b.GetPoolTransaction(hash); tx != nil {
// Transaction not found anywhere, abort return tx.MarshalBinary()
return nil, err
} }
if err == nil {
return nil, nil
}
return nil, NewTxIndexingError()
} }
return tx.MarshalBinary() return tx.MarshalBinary()
} }

View file

@ -583,9 +583,9 @@ func (b testBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) even
func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
panic("implement me") panic("implement me")
} }
func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) {
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.db, txHash) tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.db, txHash)
return tx, blockHash, blockNumber, index, nil return true, tx, blockHash, blockNumber, index, nil
} }
func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") } func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") }
func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") } func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") }

78
internal/ethapi/errors.go Normal file
View file

@ -0,0 +1,78 @@
// Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package ethapi
import (
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
)
// revertError is an API error that encompasses an EVM revert with JSON error
// code and a binary data blob.
type revertError struct {
error
reason string // revert reason hex encoded
}
// ErrorCode returns the JSON error code for a revert.
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
func (e *revertError) ErrorCode() int {
return 3
}
// ErrorData returns the hex encoded revert reason.
func (e *revertError) ErrorData() interface{} {
return e.reason
}
// newRevertError creates a revertError instance with the provided revert data.
func newRevertError(revert []byte) *revertError {
err := vm.ErrExecutionReverted
reason, errUnpack := abi.UnpackRevert(revert)
if errUnpack == nil {
err = fmt.Errorf("%w: %v", vm.ErrExecutionReverted, reason)
}
return &revertError{
error: err,
reason: hexutil.Encode(revert),
}
}
// TxIndexingError is an API error that indicates the transaction indexing is not
// fully finished yet with JSON error code and a binary data blob.
type TxIndexingError struct{}
// NewTxIndexingError creates a TxIndexingError instance.
func NewTxIndexingError() *TxIndexingError { return &TxIndexingError{} }
// Error implement error interface, returning the error message.
func (e *TxIndexingError) Error() string {
return "transaction indexing is in progress"
}
// ErrorCode returns the JSON error code for a revert.
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
func (e *TxIndexingError) ErrorCode() int {
return 3 // TODO tbd
}
// ErrorData returns the hex encoded revert reason.
func (e *TxIndexingError) ErrorData() interface{} { return "transaction indexing is in progress" }

View file

@ -379,8 +379,8 @@ func (b *backendMock) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) eve
return nil return nil
} }
func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil } func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil }
func (b *backendMock) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { func (b *backendMock) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) {
return nil, [32]byte{}, 0, 0, nil return false, nil, [32]byte{}, 0, 0, nil
} }
func (b *backendMock) GetPoolTransactions() (types.Transactions, error) { return nil, nil } func (b *backendMock) GetPoolTransactions() (types.Transactions, error) { return nil, nil }
func (b *backendMock) GetPoolTransaction(txHash common.Hash) *types.Transaction { return nil } func (b *backendMock) GetPoolTransaction(txHash common.Hash) *types.Transaction { return nil }