-
Notifications
You must be signed in to change notification settings - Fork 20.1k
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
eth/tracers: return proper error from debug_TraceTransaction when tx not found #26211
Conversation
@@ -117,9 +116,6 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) | |||
|
|||
func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { | |||
tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash) | |||
if tx == nil { | |||
return nil, common.Hash{}, 0, 0, errTransactionNotFound | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was removed because the testBackend
implementation of GetTransaction
does not match the real backend:
go-ethereum/eth/api_backend.go
Lines 267 to 270 in c2e0abc
func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { | |
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.eth.ChainDb(), txHash) | |
return tx, blockHash, blockNumber, index, nil | |
} |
eth/tracers/api.go
Outdated
if err != nil { | ||
return nil, err | ||
} | ||
if tx == nil { | ||
return nil, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not return the error errTransactionNotFound
here instead of nil
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing this to
return nil, nil | |
return nil, errors.New("transaction not found") |
We get
> debug.traceTransaction("0x0000000000000000000000000000000000000000000000000000000000000000")
WARN [11-18|10:38:20.230] Served debug_traceTransaction reqid=9 duration="127.204µs" err="transaction not found"
Error: transaction not found
at web3.js:6365:9(45)
at send (web3.js:5099:62(34))
at <eval>:1:23(4)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be written slightly more compact using a switch
switch {
case err != nil:
return nil, err
case tx == nil:
return nil, errors.New("transaction not found")
case blockNumber == 0:
return nil, errors.New("genesis is not traceable")
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not return the error errTransactionNotFound here instead of nil?
I came here to say the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have an existing convention in other RPC APIs returning null
when the requested item is not found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds fine to me too; I was trying to match the behavior of eth_getTransactionByHash
and eth_getTransactionReceipt
which both return nil
for a not-found transaction. But happy to take that suggestion if you think it's better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to return errTransactionNotFound
, we could also do this in the GetTransaction
method:
go-ethereum/eth/api_backend.go
Lines 267 to 270 in c2e0abc
func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { | |
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.eth.ChainDb(), txHash) | |
return tx, blockHash, blockNumber, index, nil | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have an existing convention in other RPC APIs returning null when the requested item is not found.
@fjl so you think the pr as is (return nil
rather than error) is preferrable?
I don't really understand the motivation behind that, personally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The motivation for the behavior of getTransactionByHash
and getTransactionReceipt
is that 'not found' is not an error. You could imagine that, with an RPC client that throws an exception for any error response, the case where the requested item is not found should not raise an exception.
Another reason might be that the people who designed these APIs didn't know that JSON-RPC has error codes. Returning null
provides a way to recognize this specific condition.
Returning errors.New("transaction not found")
here is not great because it will return a generic error code, and callers will not be able to know whether the error is related to a database/disk fault or simply means the item is not there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW it's already returning an error: genesis is not traceable
. So returning transaction not found
would retain the existing behavior, with an error message that makes more sense.
I can somewhat agree that for getTransaction, it might not be an error for it to be missing. There are two expected outcomes, it's there or it's not there. For traceTransaction, however, I think it's an error if the tx is not present. The call implies that the tx exists. It not existing is an error.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
184a8f1
to
1882938
Compare
…not found (ethereum#26211) Currently calling `debug_TraceTransaction` with a transaction hash that doesn't exist returns a confusing error: `genesis is not traceable`. This PR changes the behaviour to instead return an error message saying `transaction not found` Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: Sina Mahmoodi <itz.s1na@gmail.com>
Currently calling
debug_TraceTransaction
with a transacation hash that doesn't exist returns a confusing error:{code=-32000, message=genesis is not traceable}
. This is because theGetTransaction
returnsblockNumber=0
when the transaction doesn't exist.This PR checks if the tx is
nil
and returnsnil
if so. This will match the behavior ofeth_getTransactionByHash
andeth_getTransactionReceipt
for transactions that don't exist or aren't yet included in a block.Fixes #22846.
Example RPC response: