Support for type-1 transactions (#1051)

* Type 1 txn

* Remove magic constants

* Remove useless stack element

* Read correct original value for sk

* EIP-3651

* Fix encoding when TO is 0

* Minor
This commit is contained in:
wborgeaud 2023-05-23 09:21:27 +02:00 committed by GitHub
parent 15dec6faf9
commit 9b0092ab1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 234 additions and 12 deletions

View File

@ -87,7 +87,7 @@ remove_accessed_addresses_found:
%stack (addr, key, value) -> (addr, key, value, %%after) %stack (addr, key, value) -> (addr, key, value, %%after)
%jump(insert_accessed_storage_keys) %jump(insert_accessed_storage_keys)
%%after: %%after:
// stack: cold_access // stack: cold_access, original_value
%endmacro %endmacro
/// Inserts the storage key and value into the access list if it is not already present. /// Inserts the storage key and value into the access list if it is not already present.

View File

@ -23,7 +23,7 @@ global sys_call:
%u256_to_addr // Truncate to 160 bits %u256_to_addr // Truncate to 160 bits
DUP1 %insert_accessed_addresses DUP1 %insert_accessed_addresses
%checkpoint // Checkpoint %checkpoint // Checkpoint
DUP1 %insert_touched_addresses DUP2 %insert_touched_addresses
%call_charge_gas(1, 1) %call_charge_gas(1, 1)
@ -123,7 +123,7 @@ global sys_staticcall:
%u256_to_addr // Truncate to 160 bits %u256_to_addr // Truncate to 160 bits
DUP1 %insert_accessed_addresses DUP1 %insert_accessed_addresses
%checkpoint // Checkpoint %checkpoint // Checkpoint
DUP1 %insert_touched_addresses DUP2 %insert_touched_addresses
// Add a value of 0 to the stack. Slightly inefficient but that way we can reuse %call_charge_gas. // Add a value of 0 to the stack. Slightly inefficient but that way we can reuse %call_charge_gas.
%stack (cold_access, address, gas, kexit_info) -> (cold_access, address, gas, kexit_info, 0) %stack (cold_access, address, gas, kexit_info) -> (cold_access, address, gas, kexit_info, 0)

View File

@ -65,12 +65,11 @@ count_zeros_finish:
PUSH @GAS_TRANSACTION PUSH @GAS_TRANSACTION
// stack: gas_txn, gas_creation, gas_txndata, retdest // stack: gas_txn, gas_creation, gas_txndata, retdest
// TODO: Add num_access_list_addresses * GAS_ACCESSLISTADDRESS
// TODO: Add num_access_list_slots * GAS_ACCESSLISTSTORAGE
ADD ADD
ADD ADD
// stack: total_gas, retdest // stack: total_gas, retdest
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_DATA_COST)
ADD
SWAP1 SWAP1
JUMP JUMP

View File

@ -77,6 +77,11 @@ global increment_sender_nonce:
%mload_txn_field(@TXN_FIELD_ORIGIN) %mload_txn_field(@TXN_FIELD_ORIGIN)
%increment_nonce %increment_nonce
// EIP-3651
global warm_coinbase:
%mload_global_metadata(@GLOBAL_METADATA_BLOCK_BENEFICIARY)
%insert_accessed_addresses_no_return
global process_based_on_type: global process_based_on_type:
%is_contract_creation %is_contract_creation
%jumpi(process_contract_creation_txn) %jumpi(process_contract_creation_txn)

View File

@ -105,10 +105,15 @@
%macro decode_and_store_access_list %macro decode_and_store_access_list
// stack: pos // stack: pos
DUP1 %mstore_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START)
%decode_rlp_list_len %decode_rlp_list_len
%stack (pos, len) -> (len, pos) %stack (pos, len) -> (len, len, pos, %%after)
%jumpi(todo_access_lists_not_supported_yet) %jumpi(decode_and_store_access_list)
// stack: len, pos, %%after
POP SWAP1 POP
// stack: pos // stack: pos
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START) DUP2 SUB %mstore_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN)
%%after:
%endmacro %endmacro
%macro decode_and_store_y_parity %macro decode_and_store_y_parity
@ -135,5 +140,96 @@
// stack: pos // stack: pos
%endmacro %endmacro
global todo_access_lists_not_supported_yet:
PANIC // The access list is of the form `[[{20 bytes}, [{32 bytes}...]]...]`.
global decode_and_store_access_list:
// stack: len, pos
DUP2 ADD
// stack: end_pos, pos
// Store the RLP length.
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START) DUP2 SUB %mstore_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN)
SWAP1
decode_and_store_access_list_loop:
// stack: pos, end_pos
DUP2 DUP2 EQ %jumpi(decode_and_store_access_list_finish)
// stack: pos, end_pos
%decode_rlp_list_len // Should be a list `[{20 bytes}, [{32 bytes}...]]`
// stack: pos, internal_len, end_pos
SWAP1 POP // We don't need the length of this list.
// stack: pos, end_pos
%decode_rlp_scalar // Address // TODO: Should panic when address is not 20 bytes?
// stack: pos, addr, end_pos
SWAP1
// stack: addr, pos, end_pos
DUP1 %insert_accessed_addresses_no_return
// stack: addr, pos, end_pos
%add_address_cost
// stack: addr, pos, end_pos
SWAP1
// stack: pos, addr, end_pos
%decode_rlp_list_len // Should be a list of storage keys `[{32 bytes}...]`
// stack: pos, sk_len, addr, end_pos
SWAP1 DUP2 ADD
// stack: sk_end_pos, pos, addr, end_pos
SWAP1
// stack: pos, sk_end_pos, addr, end_pos
sk_loop:
DUP2 DUP2 EQ %jumpi(end_sk)
// stack: pos, sk_end_pos, addr, end_pos
%decode_rlp_scalar // Storage key // TODO: Should panic when key is not 32 bytes?
%stack (pos, key, sk_end_pos, addr, end_pos) ->
(addr, key, sk_loop_contd, pos, sk_end_pos, addr, end_pos)
%jump(insert_accessed_storage_keys_with_original_value)
sk_loop_contd:
// stack: pos, sk_end_pos, addr, end_pos
%add_storage_key_cost
%jump(sk_loop)
end_sk:
%stack (pos, sk_end_pos, addr, end_pos) -> (pos, end_pos)
%jump(decode_and_store_access_list_loop)
decode_and_store_access_list_finish:
%stack (pos, end_pos, retdest) -> (retdest, pos)
JUMP
%macro add_address_cost
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_DATA_COST)
%add_const(@GAS_ACCESSLISTADDRESS)
%mstore_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_DATA_COST)
%endmacro
%macro add_storage_key_cost
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_DATA_COST)
%add_const(@GAS_ACCESSLISTSTORAGE)
%mstore_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_DATA_COST)
%endmacro
insert_accessed_storage_keys_with_original_value:
%stack (addr, key, retdest) -> (key, addr, after_read, addr, key, retdest)
%jump(sload_with_addr)
after_read:
%stack (value, addr, key, retdest) -> ( addr, key, value, retdest)
%insert_accessed_storage_keys
%pop2
JUMP
sload_with_addr:
%stack (slot, addr) -> (slot, addr, after_storage_read)
%slot_to_storage_key
// stack: storage_key, addr, after_storage_read
PUSH 64 // storage_key has 64 nibbles
%stack (n64, storage_key, addr, after_storage_read) -> (addr, n64, storage_key, after_storage_read)
%mpt_read_state_trie
// stack: account_ptr, 64, storage_key, after_storage_read
DUP1 ISZERO %jumpi(ret_zero) // TODO: Fix this. This should never happen.
// stack: account_ptr, 64, storage_key, after_storage_read
%add_const(2)
// stack: storage_root_ptr_ptr
%mload_trie_data
// stack: storage_root_ptr, 64, storage_key, after_storage_read
%jump(mpt_read)
ret_zero:
// stack: account_ptr, 64, storage_key, after_storage_read, retdest
%pop4
PUSH 0 SWAP1 JUMP

View File

@ -102,9 +102,16 @@ type_0_compute_signed_data:
// stack: rlp_pos, rlp_start, retdest // stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_TO) %mload_txn_field(@TXN_FIELD_TO)
DUP1 %jumpi(nonzero_to)
// stack: to, rlp_pos, rlp_start, retdest
SWAP1 %encode_rlp_scalar
%jump(after_to)
nonzero_to:
// stack: to, rlp_pos, rlp_start, retdest
SWAP1 %encode_rlp_160 SWAP1 %encode_rlp_160
// stack: rlp_pos, rlp_start, retdest // stack: rlp_pos, rlp_start, retdest
after_to:
%mload_txn_field(@TXN_FIELD_VALUE) %mload_txn_field(@TXN_FIELD_VALUE)
SWAP1 %encode_rlp_scalar SWAP1 %encode_rlp_scalar
// stack: rlp_pos, rlp_start, retdest // stack: rlp_pos, rlp_start, retdest

View File

@ -31,6 +31,109 @@ global process_type_1_txn:
POP POP
// stack: retdest // stack: retdest
// TODO: Check signature. // From EIP-2930:
// The signatureYParity, signatureR, signatureS elements of this transaction represent a secp256k1 signature
// over keccak256(0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList])).
type_1_compute_signed_data:
%alloc_rlp_block
// stack: rlp_start, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID)
// stack: chain_id, rlp_start, retdest
DUP2
// stack: rlp_pos, chain_id, rlp_start, retdest
%encode_rlp_scalar
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_NONCE)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_TO)
DUP1 %jumpi(nonzero_to)
// stack: to, rlp_pos, rlp_start, retdest
SWAP1 %encode_rlp_scalar
%jump(after_to)
nonzero_to:
// stack: to, rlp_pos, rlp_start, retdest
SWAP1 %encode_rlp_160
// stack: rlp_pos, rlp_start, retdest
after_to:
%mload_txn_field(@TXN_FIELD_VALUE)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, rlp_start, retdest
// Encode txn data.
%mload_txn_field(@TXN_FIELD_DATA_LEN)
PUSH 0 // ADDR.virt
PUSH @SEGMENT_TXN_DATA
PUSH 0 // ADDR.context
// stack: ADDR: 3, len, rlp_pos, rlp_start, retdest
PUSH after_serializing_txn_data
// stack: after_serializing_txn_data, ADDR: 3, len, rlp_pos, rlp_start, retdest
SWAP5
// stack: rlp_pos, ADDR: 3, len, after_serializing_txn_data, rlp_start, retdest
%jump(encode_rlp_string)
after_serializing_txn_data:
// Instead of manually encoding the access list, we just copy the raw RLP from the transaction.
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START)
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN)
%stack (al_len, al_start, rlp_pos, rlp_start, retdest) ->
(
0, @SEGMENT_RLP_RAW, rlp_pos,
0, @SEGMENT_RLP_RAW, al_start,
al_len,
after_serializing_access_list,
rlp_pos, rlp_start, retdest)
%jump(memcpy)
after_serializing_access_list:
// stack: rlp_pos, rlp_start, retdest
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) ADD
// stack: rlp_pos, rlp_start, retdest
%prepend_rlp_list_prefix
// stack: prefix_start_pos, rlp_len, retdest
// Store a `1` in front of the RLP
%decrement
%stack (pos) -> (0, @SEGMENT_RLP_RAW, pos, 1, pos)
MSTORE_GENERAL
// stack: pos, rlp_len, retdest
// Hash the RLP + the leading `1`
SWAP1 %increment SWAP1
PUSH @SEGMENT_RLP_RAW
PUSH 0 // context
// stack: ADDR: 3, len, retdest
KECCAK_GENERAL
// stack: hash, retdest
%mload_txn_field(@TXN_FIELD_S)
%mload_txn_field(@TXN_FIELD_R)
%mload_txn_field(@TXN_FIELD_Y_PARITY) %add_const(27) // ecrecover interprets v as y_parity + 27
PUSH store_origin
// stack: store_origin, v, r, s, hash, retdest
SWAP4
// stack: hash, v, r, s, store_origin, retdest
%jump(ecrecover)
store_origin:
// stack: address, retdest
// If ecrecover returned u256::MAX, that indicates failure.
DUP1
%eq_const(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
%jumpi(panic)
// stack: address, retdest
%mstore_txn_field(@TXN_FIELD_ORIGIN)
// stack: retdest
%jump(process_normalized_txn) %jump(process_normalized_txn)

View File

@ -59,10 +59,16 @@ pub(crate) enum GlobalMetadata {
/// Current checkpoint. /// Current checkpoint.
CurrentCheckpoint = 28, CurrentCheckpoint = 28,
TouchedAddressesLen = 29, TouchedAddressesLen = 29,
// Gas cost for the access list in type-1 txns. See EIP-2930.
AccessListDataCost = 30,
// Start of the access list in the RLP for type-1 txns.
AccessListRlpStart = 31,
// Length of the access list in the RLP for type-1 txns.
AccessListRlpLen = 32,
} }
impl GlobalMetadata { impl GlobalMetadata {
pub(crate) const COUNT: usize = 29; pub(crate) const COUNT: usize = 32;
pub(crate) fn all() -> [Self; Self::COUNT] { pub(crate) fn all() -> [Self; Self::COUNT] {
[ [
@ -95,6 +101,9 @@ impl GlobalMetadata {
Self::JournalDataLen, Self::JournalDataLen,
Self::CurrentCheckpoint, Self::CurrentCheckpoint,
Self::TouchedAddressesLen, Self::TouchedAddressesLen,
Self::AccessListDataCost,
Self::AccessListRlpStart,
Self::AccessListRlpLen,
] ]
} }
@ -130,6 +139,9 @@ impl GlobalMetadata {
Self::JournalDataLen => "GLOBAL_METADATA_JOURNAL_DATA_LEN", Self::JournalDataLen => "GLOBAL_METADATA_JOURNAL_DATA_LEN",
Self::CurrentCheckpoint => "GLOBAL_METADATA_CURRENT_CHECKPOINT", Self::CurrentCheckpoint => "GLOBAL_METADATA_CURRENT_CHECKPOINT",
Self::TouchedAddressesLen => "GLOBAL_METADATA_TOUCHED_ADDRESSES_LEN", Self::TouchedAddressesLen => "GLOBAL_METADATA_TOUCHED_ADDRESSES_LEN",
Self::AccessListDataCost => "GLOBAL_METADATA_ACCESS_LIST_DATA_COST",
Self::AccessListRlpStart => "GLOBAL_METADATA_ACCESS_LIST_RLP_START",
Self::AccessListRlpLen => "GLOBAL_METADATA_ACCESS_LIST_RLP_LEN",
} }
} }
} }