Skip to content

Latest commit

 

History

History
141 lines (94 loc) · 5.39 KB

rip-7712.md

File metadata and controls

141 lines (94 loc) · 5.39 KB
rip title description author discussions-to status type category created requires
7712
Enable RIP-7560 transactions using a two-dimensional nonce
An RIP-7560 transaction modification that allows Smart Contract Accounts to define their own transaction sequencing
Vitalik Buterin (@vbuterin), Yoav Weiss (@yoavw), Alex Forshtat (@forshtat), Dror Tirosh (@drortirosh), Shahaf Nacson (@shahafn)
Draft
Standards Track
Core
2023-09-01
7560

Abstract

An RIP-7560 transaction modification that replaces the existing nonce-based sequencing mechanism of Ethereum with an on-chain pre-deployed contract in order to provide Smart Contract Accounts with the flexibility they need to support some advanced use cases.

Motivation

The traditional nonce-based system provides guarantees of transaction ordering and replay protection, but does so at the expanse of configurability. Accounts are not able to express their intentions like "allow these three transactions to be mined in whatever order" or "these two sets of transactions must have separate sequential nonces".

However, with Smart Contract Accounts this creates a bottleneck for some use-cases. For example, Smart Contract Accounts designed to be operated by multiple participants simultaneously, will require these participants to coordinate their transactions to avoid invalidating each other.

Another example when this can also be a limitation is a case where there are separate execution flows. A configuration change may require multiple participants to co-sign a transaction but a regular operation does not. With sequential nonces, all operations will have to be halted until the configuration change is executed.

Having a more agile ordering and replay protection system will significantly improve the user experience with RIP-7560.

Additionally, this change is required for the Native Account Abstraction to achieve feature parity and compatibility with ERC-4337, as all ERC-4337 Smart Contract Accounts already use the solution described below.

Specification

Non-sequential nonce support

We propose an introduction of a separate 2-dimensional nonce value used when contracts initiate a transaction.

The nonce parameter of the transaction is to be interpreted as uint192 key || uint64 seq value. The contract account nonce is then defined as a mapping address account => uint192 key => uint64 seq. This approach guarantees unique transaction nonce and hash but removes the requirement of nonces being sequential numbers.

This nonce is exposed to the EVM in a NonceManager pre-deployed contract located at the AA_NONCE_MANAGER address.

The nonce is validated and incremented on-chain before the rest of the validation code.

The old nonce account parameter use

The old 64-bit nonce account parameter is used when the key of the AA_TX_TYPE transaction's nonce is set to 0. Notice that this also prevents the previously signed transactions from becoming valid again.

The old nonce account parameter remains in use for transactions initiated by EOAs and for the CREATE opcode. It is not incremented when sender makes the AA_TX_TYPE transaction.

Nonce validation frame

Before the first validation frame is applied during the validation phase, the NonceManager is invoked with the following data:

sender{20 bytes} nonceKey{24 bytes} nonceSeq{8 bytes}

The gas costs of this execution frame are counted towards the total for a transaction.

NonceManager Pseudocode


if evm.caller == AA_ENTRY_POINT:
    validate_increment()
else:
    get()

def get():
    if len(evm.calldata) != 44:
        evm.revert()

    // address sender, uint192 key
    address = to_uint160_be(evm.calldata[0:20])
    key = to_uint192_be(evm.calldata[20:44])

    nonce = storage.get(keccak(address, key))

    evm.return((key << 64) + nonce)

def validate_increment():

    address = to_uint160_be(evm.calldata[0:20])
    key = to_uint192_be(evm.calldata[20:44])
    nonce = to_uint64_be(evm.calldata[44:52])

    current_nonce = storage.get(keccak(address, key))

    if (nonce != current_nonce):
        evm.revert()

    storage.set(kecca
    k(address, key), current_nonce + 1)

NonceManager Bytecode and deployment

TODO.

Rationale

Creating a pre-deployed contract instead of modifying an account data structure

While there is no technical benefit to either option, allowing EVM code to control the nonce seems to be a smaller change to the Ethereum protocol and is more aligned with the vision of Account Abstraction.

Backwards Compatibility

As actual nonce value was never observable inside the EVM, there should be no major complications caused by the migration to a different nonce mechanism.

Smart Contract Accounts could access the uint256 nonce value in the TransactionType4 struct and ignore the higher 192 bits assuming nonce cannot exceed 64 bits. This assumption is wrong and is broken by the proposed change.

Security Considerations

Smart Contract Accounts that need to enforce the sequence of transaction execution must apply appropriate restrictions on the uint192 key value.

In order to require the incremental sequential nonce behaviour on-chain, the contracts may choose to require(key == 0).

Copyright

Copyright and related rights waived via CC0.