EIP-2930: Optional access lists

A companion EIP to #eip-2929.

Adds a transaction type which contains an access list, a list of addresses and storage keys that the transaction plans to access. Accesses outside the list are possible, but become more expensive. Intended as a mitigation to contract breakage risks introduced by EIP 2929 and simultaneously a stepping stone toward broader use of access lists in other contexts.

1 Like

Really interesting concept. Seems like a stepping stone towards stateless clients.

The EIP mentions that the discount for transactions using access lists will increase over time as more tools are developed and access-list generation matures. What kind of tools will need to be developed? Is it just for access-list generation, or also for validation?

Just for access list generation. The code for determining whether or not accesses are part of the access list and doing things based on that is already in 2929.

1 Like

Transaction Format Options

// RLP multi-pass
3 || rlp([nonce, gasPrice, gasLimit, to, value, data, access_list, sendrV, senderR, senderS])
// RLP single-pass
3 || rlp([[senderV, senderR, senderS], rlp([3, nonce, gasPrice, gasLimit, to, value, data, access_list])])
// SSZ deduped
ssz([3, nonce, gasPrice, gasLimit, to, value, data, access_list]) || ssz([sendrV, senderR, senderS])
// SSZ duped
3 || senderV || senderR || senderS, ssz([3, nonce, gasPrice, gasLimit, to, value, data, access_list])
  • RLP Multi-Pass
    • Advantages
      • No new encoding format
      • No data duplication
    • Disadvantages
      • Requires an RLP encoder and decoder to validate
      • Validation has decode-split-encode-validate flow
  • RLP Single-Pass
    • Advantages
      • No new encoding format
      • Can validate signature without needing an RLP encoder
      • Supports decode-validate flow
    • Disadvantages
      • Duplicates the transaction type byte
      • Requires RLP decoder to validate
  • SSZ Deduped
    • Advantages
      • No data duplication
      • Can validate signature without needing an SSZ encoder
      • Supports decode-validate flow
    • Disadvantages
      • Requires SSZ encoder for creating
      • Requires SSZ decoder for validating
      • Requires retaining access to the leading type byte when processing (or re-inserting it)
  • SSZ Duped
    • Advantages
      • Can validate without an SSZ encoder
      • Can validate without an SSZ decoder
      • Supports fixed offset extraction of signature
      • Supports pluck-validate flow
    • Disadvantages
      • Requires SSZ encoder for creating
      • Duplicates the transaction byte

This is a great summary, thanks @MicahZoltu.

Why does the second option need to have 3 in multiple places? Couldn’t we alternatively enforce keccak(3 || rlp([nonce, gasPrice, gasLimit, to, value, data, accessList])) be the hash that is signed over? It would require minimal assemble and would avoid the weird edge case where the outer type doesn’t match the inner type.

I believe this option would work, but it means we would have two different encoding schemes at play, which is a bit unfortunate. Part of the goal with these 4 proposals was to minimize the complexity of encoding, and having to encode most of the signed data and then encode that along with some more data to get the final signed thing increases complexity.

If people believe that this proposed solution is superior to the 4 options above, I don’t mind adding it to the list to be discussed though!

At the All Core Devs call we decided on no SSZ for Berlin. After some discussion in Discord, we have decided to go with multi-pass as it saves a byte and aligns pretty closely to with how we already deal with transactions. We also decided to switch over to yParity rather than v to pay down a bit of technical debt around v (EIP-155 and Bitcoin baggage).

The tentative final transaction format will be:

1 || rlp([chain_id, nonce, gas_price, gas_limit, to, value, data, access_list, y_parity, r, s])