Title: RIP_Idea__L2_Transaction_Status_Standard
Category: RIPs

Author: highlander
Date: 2024-07-09T23:30:37.866Z

A recent discussion (June 2024) in the RollCall Telegram Group has yet again shown that a lack of standards around the processing status of an L2 transaction is confusing not only for users and developers (block explorers, wallets, smart contracts, chain analytics) but also for client teams themselves trying to understand what different statuses mean and what trust assumptions have been made for each status. Besides confusion, there are real security risks, especially for L2 bridges based on the processing status of an L2 transaction (finalized on the L2 but not on the L1 vs finalized on the L2 and the L1).
This topic of discussion also arose in the OASIS Ethereum Open Projects L2 Standards WG when discussing the L2 Transaction Fee API specification. The WG decided to make L2 Transaction Statuses their next work item.
To start the discussion, the WG decided to propose a simple set of statuses both as a string and as a hex value, their definitions and trust assumptions. The minimal set of transaction statuses proposed is as follows:

L2 Pending: An L2 transaction submitted to an L2, and waiting to be processed by a sequencer. Trust Assumption: No inclusion guarantee on the L2
L2 Replaced: An L2 transaction that was “Pending” was replaced by another L2 transaction. Trust Assumption: Same as L2 Pending
L2 Dropped: An L2 transaction that was removed from the L2 processing queue. Trust Assumption: NA
L2 Confirmed: An L2 transaction processed by a sequencer and assigned an order in a proposed L2 block by the sequencer by applying an L2 client-specific L2 transaction ordering protocol. Trust Assumption: The L2 transaction order guarantee is based on the security guarantee of the ordering protocol. Inclusion in finalized L2 and L1 blocks is not guaranteed.
L2 Included, L1 Pending: An L2 transaction included in an L2 block but not yet submitted to the L1. Trust Assumption: The L2 inclusion guarantee is dependent on the submission guarantee of the L2 block to the L1 and L1 Finalization.
L2 Included, L1 Included: An L2 transaction included in an L2 block submitted to the L1. Trust Assumption: The L2 inclusion guarantee is dependent on L1 finalization.
L2 Finalized, L1 Finalized: An L2 transaction included in a L2 block that has been included in a finalized L1 transaction. Trust Assumption: The L2 transaction finalization guarantee is equivalent to an L1 transaction finalization guarantee in a finalized L1 block.

Author: ajsutton
Date: 2024-07-09T23:47:17.220Z

highlander:


L2 Finalized, L1 Finalization pending: An L2 transaction included in an L2 block submitted to the L1. Trust Assumption: The L2 finalization guarantee is dependent on L1 finalization.



I don’t see how it makes sense for an L2 transaction to be “finalized” if it hasn’t yet been submitted to the L1. This is what OP Stack would call an unsafe block, available from the latest tag on JSON-RPC and it is the most likely category of block to be reorged. The term finalized should only be used for things that will not change within normal protocol operation (e.g like L1 finalized won’t change without at least 1/3rd of validators being slashed).

Author: highlander
Date: 2024-07-10T00:32:12.572Z

Well, it makes sense for those L2s that do not submit a new L2 block to the L1 every few seconds. That means you can have L2 blocks finalized on the L2, and, therefore, the new state can be used for subsequent L2 transactions, without the L2 block even submitted to the L1.
Would you not agree?

Author: timbeiko
Date: 2024-07-10T18:40:10.993Z

I agree with Adrian that overloading the “Finalized” term, which has a very specific meaning in Ethereum, would be misleading to users. Why not simply rename “L2 Confirmed” to “L2 Included”?
This way, you could also have:

L2 Included, L1 Pending
L2 Included, L1 Included
L2 Finalized, L1 Finalized

Author: highlander
Date: 2024-07-10T21:18:24.301Z

@timbeiko That is a good suggestion, will incorporate

Author: ranchalp
Date: 2024-07-15T14:29:16.946Z

IMO when a transaction is included and attested by some BFT protocol at the L2 consensus level (but not yet even submitted to L1) this should be called L2 finalized, and we should deal with the notion of L2 finality and L1 finality as two different layers of security.
The definition of finality in Ethereum is exactly that: the set of attesters voted on this block and thus this block will not suffer a reorg unless a third of the attesters equivocate. If the number of validators and economic security halved by some event in Ethereum, the definition of L1 finality in Ethereum would remain the same. I believe it is unrealistic to ask of an L2 consensus to choose a different term for the same notion (regardless of what is the economic security and number of validators in that L2).

Author: highlander
Date: 2024-07-16T15:21:16.914Z

@ranchalp I agree with you, except that even if the L2 is finalized based on the finalization conditions of the L2 consensus algorithm an L1 reorg (before L1 finalization) will force an L2 reorg, or minimally a resubmission of the L2 blocks that were reorged on the L1.
Therefore, and only IMHO, for the word finalization to mean the same thing on an L2 and an L1, the L2 state can only be called finalized once the L1 state containing the L2 state is finalized.
The key is that we come up with a set of definitions we can all align with, albeit not necessarily agree with 100% – compromise rules

Author: dontpanic
Date: 2024-07-17T19:19:18.735Z

In 2018, @expede made efforts to standardize status codes for L1 contracts using erc-1066, akin to HTTP status codes. Hexadecimal codes were preferred there too for their neutrality and parsing simplicity compared to strings. The future evolution of L2 platforms may diverge from current practices. The primary objective was to enhance contract interface understanding of inter-contract message statuses. Is there an opportunity to unify L2 and L1 statuses under a single standard? ERC-1066: Ethereum Status Codes (ESC)

Author: highlander
Date: 2024-07-17T20:22:24.880Z

@dontpanic I looked at 1066. Since it was referring to smart contract codes, I decided not to reference it in the initial write-up. Thank you for sharing.
I think status codes, in addition to a string, are also important and should be included. I think once we can align on the language and meaning of words, we can assign codes.

Author: sbacha
Date: 2024-07-24T00:15:54.518Z

Why not consider an rpc method getTransactionBySenderAndNonce


github.com/ethereum/execution-apis








JSON-RPC edge-cases, nonce management and `eth_getTransactionBySenderAndNonce`



        opened 03:31PM - 22 Nov 23 UTC




          alcuadrado
        







During the JSON-RPC meeting in Istanbul, I made a case that `eth_getTransactionB…ySenderAndNonce` 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](https://github.com/ethereum/execution-apis/assets/176499/ce4f3e1f-b07e-4480-8560-ac6fb92d5d1d)

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?) of the transaction 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?
4. Are there any alternative solution?
1. How many resources would this method require for transactions that are still in the mempool?
5. How many resources would this method require for transactions that were included in a block?
6. How many blocks are really important to solve the problems listed above?
7. 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_






More details:



github.com


rpc-eip-drafts/eth_getTransactionBySenderAndNonce at master ·...
Custom RPC Methods for Ethereum/EVM chains. Contribute to manifoldfinance/rpc-eip-drafts development by creating an account on GitHub.

Author: Eikix
Date: 2024-07-24T10:36:37.285Z

What would happen if there are 5 transactions with same sender and nonce? (Someone trying to replace transactions)

Author: ranchalp
Date: 2024-08-21T12:08:29.446Z

@highlander

I agree with you, except that even if the L2 is finalized based on the finalization conditions of the L2 consensus algorithm an L1 reorg (before L1 finalization) will force an L2 reorg, or minimally a resubmission of the L2 blocks that were reorged on the L1.

Ethereum could tomorrow decide to protect against long-range attacks by checkpointing its state on to Bitcoin as an L0 (as is being discussed for some other PoS L1s, e.g. in Filecoin, or in academia, e.g. [1, 2]), which might also mean that a resubmission of checkpointed snapshots could be necessary in the event of a reorg. But this is IMO orthogonal with the notion of finality, which is internal and Ethereum-specific. I still think the same should be used for L2s.

The key is that we come up with a set of definitions we can all align with, albeit not necessarily agree with 100% – compromise rules 

Is there a manifested support for the terminology used in this RIP vs. some other?
[1] Azouvi, Sarah, and Marko Vukolić. “Pikachu: Securing PoS blockchains from long-range attacks by checkpointing into Bitcoin PoW using Taproot.” Proceedings of the 2022 ACM Workshop on Developments in Consensus . 2022.
[2] Tas, Ertem Nusret, et al. “Babylon: Reusing bitcoin mining to enhance proof-of-stake security.” arXiv preprint arXiv:2201.07946 (2022).

Author: highlander
Date: 2024-08-24T01:16:50.530Z

@ranchalp With the Pectra hardfork, Ethereum will have single slot finality (SSF) which makes this discussion mute. Note the “L2 Included, L1 Included” would only exist for ~12 seconds.
As to manifested support, see the comments here, plus the L2 Standards WG have created and already discussed a draft – See PR
The WG has representatives from all major L2s, and people from RollCall stopped by to discuss the topic too.
Will also organize a RollCall break-out session.

Author: ranchalp
Date: 2024-08-25T15:44:49.677Z

highlander:

@ranchalp With the Pectra hardfork, Ethereum will have single slot finality (SSF) which makes this discussion mute. Note the “L2 Included, L1 Included” would only exist for ~12 seconds.


SSL does not really solve the issue in the example I was suggesting with BTC as an L0 for long-range attack protection, if anything it makes speaking of L2 finality easier to argue for, as there would be no fork in Ethereum and no resubmission/reorg of L2 needed. Is this what you meant?

Author: highlander
Date: 2024-09-04T01:30:19.783Z

@ranchalp Yes, SSF avoids reorgs, and therefore, L2 resubmissions. Therefore, the L2 included and L1 included status is only a very short-lived state ~ 12s, yet still required.