⛓️Transaction Nonce

Ethereum's enhanced nonce system, breaking it into a 192-bit key and a 64-bit sequence. This offers flexibility in transaction management and replay protection.

In Ethereum, every transaction has a unique identifier called a nonce. This nonce serves three main purposes:

  1. Replay Protection: Ensures a transaction can't be re-sent or "replayed" unintentionally.

  2. Ordering: Determines the correct order in which transactions are included in blocks.

  3. Uniqueness: Contributes to making every transaction distinct. A single transaction, from the same sender with the same nonce, cannot be added to the chain twice.

But here's a problem: This nonce system, which is just a single growing number, limits the ability of senders to set their own rules or logic for how transactions should be ordered or protected.

A New Approach to Nonce

To offer more flexibility, instead of using a single growing number, a new nonce mechanism has been introduced. This new nonce breaks the single value into two parts:

  1. Key (192-bit): Think of this as a customizable label or identifier.

  2. Sequence (64-bit): This is a growing number, just like the traditional nonce.

On the Ethereum chain, these values are visible and managed within the EntryPoint contract, which is a kind of central hub for managing these UserOperations.

To help users access and understand these values, there's a function:

function getNonce(address sender, uint192 key) external view returns (uint256 nonce);

This function lets anyone check the current nonce (which includes both the key and sequence) for any sender and key combo.

For every distinct "key", the sequence grows in order. However, if someone wants to use a new key, they can start its associated sequence at any number they choose.

The Benefit

This design preserves the core function of ensuring each UserOperation (a kind of transaction) is unique on the chain. At the same time, it gives wallets a wide, 192-bit space to play with and set their own rules or logic using the "key", all while keeping things compact within the standard 32-byte Ethereum word size.

Using the Enhanced Nonce Mechanism

The new nonce mechanism we discussed divides the nonce into a "key" and a "sequence". Here are some practical ways this can be used.

Classic Sequential Nonce

If you want your Ethereum wallet to behave just like it always has with a simple, increasing number for the nonce, you can ensure this by adding a check in the validation function:

require(userOp.nonce < type(uint64).max)

This line ensures that the nonce stays within the range of a classic 64-bit unsigned integer, keeping things traditional and sequential.

Ordered Administrative Events

Imagine you have an account that needs two channels: one for regular actions and another for special "administrative" actions. With the new nonce mechanism, you can achieve this by using the "key" part of the nonce to differentiate between the two:

bytes4 sig = bytes4(userOp.callData[0 : 4]);  // Extracting the method signature
uint key = userOp.nonce >> 64;  // Shifting to get the "key" from the nonce

if (sig == ADMIN_METHODSIG) {  // If the method signature matches the admin one
    require(key == ADMIN_KEY, "wrong nonce-key for admin operation");  // Ensure the key is set to the admin value
} else {
    require(key == 0, "wrong nonce-key for normal operation");  // Otherwise, ensure it's set to the default value for regular actions
}

Here's the breakdown:

  • First, the method signature from the call data is extracted.

  • Then, the "key" part of the nonce is retrieved.

  • Depending on the method signature, the system checks if the correct "key" has been used. Admin actions should use the ADMIN_KEY, while regular actions should use a key of 0.

This way, with the enhanced nonce mechanism, users have flexibility in how they structure and order their transactions, while still ensuring security and orderliness.

Last updated