Skip to content
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

Merged
merged 6 commits into from
Dec 10, 2022

Conversation

mdehoog
Copy link
Contributor

@mdehoog mdehoog commented Nov 18, 2022

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 the GetTransaction returns blockNumber=0 when the transaction doesn't exist.

This PR checks if the tx is nil and returns nil if so. This will match the behavior of eth_getTransactionByHash and eth_getTransactionReceipt for transactions that don't exist or aren't yet included in a block.

Fixes #22846.

Example RPC response:

> curl -d '{"id":0,"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0x0000000000000000000000000000000000000000000000000000000000000000"]}' -H "Content-Type: application/json" http://localhost:8545
{"jsonrpc":"2.0","id":0,"result":null}

@mdehoog mdehoog requested a review from s1na as a code owner November 18, 2022 02:25
@@ -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
}
Copy link
Contributor Author

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:

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
}

if err != nil {
return nil, err
}
if tx == nil {
return nil, nil
Copy link
Contributor

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?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing this to

Suggested change
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)

Copy link
Contributor

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")
	}

Copy link
Contributor

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

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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:

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
}

Copy link
Contributor

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.

Copy link
Contributor

@fjl fjl Nov 22, 2022

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.

Copy link
Contributor Author

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.

@holiman holiman changed the title Return null from debug_TraceTransaction when transaction does not exist eth/tracers: return null from debug_TraceTransaction when transaction does not exist Nov 18, 2022
@holiman
Copy link
Contributor

holiman commented Nov 22, 2022 via email

@fjl fjl self-assigned this Dec 6, 2022
@fjl fjl removed the status:triage label Dec 6, 2022
@holiman holiman added this to the 1.11.0 milestone Dec 9, 2022
@holiman holiman changed the title eth/tracers: return null from debug_TraceTransaction when transaction does not exist eth/tracers: return proper error from debug_TraceTransaction when tx not found Dec 9, 2022
@holiman holiman assigned holiman and unassigned fjl Dec 9, 2022
Copy link
Contributor

@s1na s1na left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

eth/tracers/api_test.go Outdated Show resolved Hide resolved
eth/tracers/api_test.go Outdated Show resolved Hide resolved
@holiman holiman merged commit 262bd38 into ethereum:master Dec 10, 2022
@mdehoog mdehoog deleted the trace-tx-not-found branch March 9, 2023 16:17
shekhirin pushed a commit to shekhirin/go-ethereum that referenced this pull request Jun 6, 2023
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unexpected response from debug_traceTransaction
4 participants