Skip to content

JSON-RPC edge-cases, nonce management and eth_getTransactionBySenderAndNonce #494

@alcuadrado

Description

@alcuadrado

During the JSON-RPC meeting in Istanbul, I made a case that eth_getTransactionBySenderAndNonce would be useful for dapp and tool developers. I'm opening this issue to continue the discussion here, and to go into more detail.

Problems with the JSON-RPC

These are the problems that I think could be solved with eth_getTransactionBySenderAndNonce.

Problem 1: Losing track of a transaction

I created this pictures of how a the normal workflow of sending a transaction from a dapp or tool that interacts with a wallet looks like:

image

As shown above, the flow would be something like this:

  1. The dapp/tool wants to send a transaction, so it calls into a library like ethers/web3/viem.
  2. The library is connected to a wallet, which exposes the same JSON-RPC interface as a client. Note that the wallet doesn't just forward things to a client, it has its own implementation of some methods, like eth_sendTransaction.
  3. To send a transaction, the library sends an eth_sendTransaction to the wallet.
  4. The wallet receives that request and creates and signs a transaction locally.
  5. At this point, the wallet is already aware of the full tx body and hence its hash, but it hasn't communicated it to the the library yet.
  6. The wallet will then do an eth_sendRawTransaction, sending the full tx body to an EL client, which will broadcast it.
  7. The wallet returns a hash as the response of eth_sendTransaction, which the library receives and passes to the dapp.

If after sending the tx to the EL client anything goes wrong with the wallet, library or dapp, a transaction will be broadcasted as requested by the dapp, but the dapp will never be able to access it.

Note that the order of 6 and 7 are unspecified. The wallet could return the hash before sending the raw transaction. As it's unclear, we are forced to assume the worst situation is possible.

If we had eth_getTransactionBySenderAndNonce a dapp could keep track of the nonce and transaction params, and resume from errors if needed, by checking if a transaction with that sender and nonce exists, and if it has the same params as the one that it intended to send.

Problem 2: Replaced and dropped transactions

When a dapp/tool sends a transaction, the tx can be replaced by another one with the same nonce and sender, or dropped from the mempool. What's more, replacement transactions can be equivalent to the one you sent (e.g. just higher fees), or a completely different one (e.g. to a different account).

All of these situations manifest as a eth_getTransactionByHash returning null.

The way to distinguish between some of them (replaced vs dropped) is by using eth_getTransactionCount with different blocktags and analyzing a pretty complex set of cases, including making tons of assumptions about how "pending" works in this case.

If we had eth_getTransactionBySenderAndNonce a dapp could use it to understand what happened if eth_getTransactionByHash returns null.

Proposal

Add a method eth_getTransactionBySenderAndNonce with two parameters:

  1. An address: the sender of the transaction.
  2. A quantity: the nonce of the transaction.

The JSON-RPC server should return the hash of a transaction (or the full tx?) transaction object sent from the provided address using that nonce. If no such transaction exists, it should return null.

If multiple transactions from a sender and nonce were received, I assume there's one that can be considered the best candidate for inclusion (e.g. pays more fees), and that one should be used.

Things to consider

  1. Does this method have other use cases?
  2. Are there any alternative solution?
  3. How many resources would this method require for transactions that are still in the mempool?
  4. How many resources would this method require for transactions that were included in a block?
  5. How many blocks are really important to solve the problems listed above?
  6. How can RPC/Node providers (e.g. Infura) support this?

Tagging people present on the in-person discussion, or who I've discussed this in the past: @s1na @lightclient @sambacha @kanej

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions