From d08b263b364649de87a77ee79c644ca0e0c4287f Mon Sep 17 00:00:00 2001 From: Hamy Ratoanina Date: Fri, 27 Oct 2023 16:19:29 -0400 Subject: [PATCH 1/3] Implement EIP-6780 (new SELFDESTRUCT) --- .../asm/core/create_contract_account.asm | 19 +++++++- .../cpu/kernel/asm/core/selfdestruct_list.asm | 43 ++++++++++++++++++- evm/src/cpu/kernel/asm/core/terminate.asm | 14 +++--- evm/src/cpu/kernel/asm/core/transfer.asm | 4 +- .../kernel/asm/journal/account_created.asm | 18 ++++++-- .../cpu/kernel/constants/global_metadata.rs | 8 +++- evm/src/memory/segments.rs | 7 ++- 7 files changed, 93 insertions(+), 20 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/create_contract_account.asm b/evm/src/cpu/kernel/asm/core/create_contract_account.asm index b45d45ca5c..051540e173 100644 --- a/evm/src/cpu/kernel/asm/core/create_contract_account.asm +++ b/evm/src/cpu/kernel/asm/core/create_contract_account.asm @@ -27,7 +27,12 @@ %%add_account: // stack: existing_balance, address - DUP2 %journal_add_account_created + DUP2 PUSH 1 + // stack: is_contract, address, existing_balance, addr + %journal_add_account_created + // stack: existing_balance, addr + DUP2 + %append_created_contracts %%do_insert: // stack: new_acct_value, address // Write the new account's data to MPT data, and get a pointer to it. @@ -60,3 +65,15 @@ %%end: // stack: status %endmacro + +%macro append_created_contracts + // stack: address + %mload_global_metadata(@GLOBAL_METADATA_CREATED_CONTRACTS_LEN) + // stack: nb_created_contracts, address + SWAP1 DUP2 + // stack: nb_created_contracts, address, nb_created_contracts + %mstore_kernel(@SEGMENT_CREATED_CONTRACTS) + // stack: nb_created_contracts + %increment + %mstore_global_metadata(@GLOBAL_METADATA_CREATED_CONTRACTS_LEN) +%endmacro diff --git a/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm b/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm index 5084541aa2..f5f798722e 100644 --- a/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm +++ b/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm @@ -12,8 +12,43 @@ %mstore_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN) // Store new length. %endmacro +global maybe_insert_selfdestruct_list: + // stack: addr, retdest + %mload_global_metadata(@GLOBAL_METADATA_CREATED_CONTRACTS_LEN) + // stack: nb_created_contracts, addr, retdest + PUSH 0 +maybe_insert_selfdestruct_list_loop: + %stack (i, nb_created_contracts, addr, retdest) -> (i, nb_created_contracts, i, nb_created_contracts, addr, retdest) + EQ %jumpi(contract_not_created) + // stack: i, nb_created_contracts, addr, retdest + DUP1 %mload_kernel(@SEGMENT_CREATED_CONTRACTS) + // stack: addr_created_contract, i, nb_created_contracts, addr, retdest + DUP4 + // stack: addr, addr_created_contract, i, nb_created_contracts, addr, retdest + EQ %jumpi(contract_just_created) + // stack: i, nb_created_contracts, addr, retdest + %increment + %jump(maybe_insert_selfdestruct_list_loop) +contract_just_created: + // stack: i, nb_created_contracts, addr, retdest + %pop2 + // stack: addr, retdest + %insert_selfdestruct_list + // stack: retdest + JUMP +contract_not_created: + // stack: i, nb_created_contracts, addr, retdest + %pop3 + JUMP + +%macro maybe_insert_selfdestruct_list + %stack (addr) -> (addr, %%after) + %jump(maybe_insert_selfdestruct_list) +%%after: +%endmacro + /// Remove one occurrence of the address from the list. -/// Panics if the address is not in the list. +/// No effect if the address is not in the list. global remove_selfdestruct_list: // stack: addr, retdest %mload_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN) @@ -21,7 +56,7 @@ global remove_selfdestruct_list: PUSH 0 remove_selfdestruct_list_loop: %stack (i, len, addr, retdest) -> (i, len, i, len, addr, retdest) - EQ %jumpi(panic) + EQ %jumpi(remove_self_dstruct_not_found) // stack: i, len, addr, retdest DUP1 %mload_kernel(@SEGMENT_SELFDESTRUCT_LIST) // stack: loaded_addr, i, len, addr, retdest @@ -40,6 +75,10 @@ remove_selfdestruct_list_found: SWAP1 %mstore_kernel(@SEGMENT_SELFDESTRUCT_LIST) // Store the last address at the position of the removed address. JUMP +remove_self_dstruct_not_found: + // stack: i, len, addr, retdest + %pop3 + JUMP global delete_all_selfdestructed_addresses: // stack: retdest diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index 7bb7842fe3..b965447ad0 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -81,9 +81,10 @@ global sys_selfdestruct: %charge_gas %stack (kexit_info, balance, address, recipient) -> (balance, address, recipient, kexit_info) - // Insert address into the selfdestruct set. + // EIP-6780: insert address into the selfdestruct set if contact has been created + // during the current transaction. // stack: balance, address, recipient, kexit_info - DUP2 %insert_selfdestruct_list + DUP2 %maybe_insert_selfdestruct_list // Set the balance of the address to 0. // stack: balance, address, recipient, kexit_info @@ -95,14 +96,9 @@ global sys_selfdestruct: // stack: balance_ptr, 0, balance, address, recipient, kexit_info %mstore_trie_data + // Send the balance to the recipient. %stack (balance, address, recipient, kexit_info) -> - (address, recipient, address, recipient, balance, kexit_info) - - // If the recipient is the same as the address, then we're done. - // Otherwise, send the balance to the recipient. - // stack: address, recipient, address, recipient, balance, kexit_info - EQ %jumpi(sys_selfdestruct_journal_add) - %stack (address, recipient, balance, kexit_info) -> (recipient, balance, address, recipient, balance, kexit_info) + (recipient, balance, address, recipient, balance, kexit_info) %add_eth sys_selfdestruct_journal_add: diff --git a/evm/src/cpu/kernel/asm/core/transfer.asm b/evm/src/cpu/kernel/asm/core/transfer.asm index 0517cf3a8f..8a5aad9fef 100644 --- a/evm/src/cpu/kernel/asm/core/transfer.asm +++ b/evm/src/cpu/kernel/asm/core/transfer.asm @@ -85,7 +85,9 @@ global add_eth_new_account: POP // stack: addr, amount, retdest DUP2 ISZERO %jumpi(add_eth_new_account_zero) - DUP1 %journal_add_account_created + DUP1 PUSH 0 + // stack: is_eoa, addr, addr, amount, retdest + %journal_add_account_created %get_trie_data_size // pointer to new account we're about to create // stack: new_account_ptr, addr, amount, retdest SWAP2 diff --git a/evm/src/cpu/kernel/asm/journal/account_created.asm b/evm/src/cpu/kernel/asm/journal/account_created.asm index 4748d5cbcb..2fd4c15fae 100644 --- a/evm/src/cpu/kernel/asm/journal/account_created.asm +++ b/evm/src/cpu/kernel/asm/journal/account_created.asm @@ -1,13 +1,23 @@ -// struct AccountCreated { address } +// struct AccountCreated { account_type, address } +// account_type is 0 for an EOA, 1 for a contract. %macro journal_add_account_created - %journal_add_1(@JOURNAL_ENTRY_ACCOUNT_CREATED) + %journal_add_2(@JOURNAL_ENTRY_ACCOUNT_CREATED) %endmacro global revert_account_created: // stack: entry_type, ptr, retdest POP - %journal_load_1 - // stack: address, retdest + %journal_load_2 + // stack: account_type, address, retdest + %jumpi(decrement_created_contracts_len) + +revert_account_finish: %delete_account JUMP + +decrement_created_contracts_len: + %mload_global_metadata(@GLOBAL_METADATA_CREATED_CONTRACTS_LEN) + %decrement + %mstore_global_metadata(@GLOBAL_METADATA_CREATED_CONTRACTS_LEN) + %jump(revert_account_finish) diff --git a/evm/src/cpu/kernel/constants/global_metadata.rs b/evm/src/cpu/kernel/constants/global_metadata.rs index b3d9600d57..77e64fe25d 100644 --- a/evm/src/cpu/kernel/constants/global_metadata.rs +++ b/evm/src/cpu/kernel/constants/global_metadata.rs @@ -79,17 +79,19 @@ pub(crate) enum GlobalMetadata { ContractCreation = 38, IsPrecompileFromEoa = 39, CallStackDepth = 40, - /// Transaction logs list length + /// Transaction logs list length. LogsLen = 41, LogsDataLen = 42, LogsPayloadLen = 43, TxnNumberBefore = 44, TxnNumberAfter = 45, BlockBlobBaseFee = 46, + /// Number of created contracts during the current transaction. + CreatedContractsLen = 47, } impl GlobalMetadata { - pub(crate) const COUNT: usize = 47; + pub(crate) const COUNT: usize = 48; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -140,6 +142,7 @@ impl GlobalMetadata { Self::TxnNumberBefore, Self::TxnNumberAfter, Self::BlockBlobBaseFee, + Self::CreatedContractsLen, ] } @@ -193,6 +196,7 @@ impl GlobalMetadata { Self::TxnNumberBefore => "GLOBAL_METADATA_TXN_NUMBER_BEFORE", Self::TxnNumberAfter => "GLOBAL_METADATA_TXN_NUMBER_AFTER", Self::BlockBlobBaseFee => "GLOBAL_METADATA_BLOCK_BLOB_BASE_FEE", + Self::CreatedContractsLen => "GLOBAL_METADATA_CREATED_CONTRACTS_LEN", } } } diff --git a/evm/src/memory/segments.rs b/evm/src/memory/segments.rs index afaaf503b0..ede0ad5513 100644 --- a/evm/src/memory/segments.rs +++ b/evm/src/memory/segments.rs @@ -70,10 +70,12 @@ pub enum Segment { ContextCheckpoints = 35, /// List of 256 previous block hashes. BlockHashes = 36, + /// List of contracts which have been created during the current transaction. + CreatedContracts = 37, } impl Segment { - pub(crate) const COUNT: usize = 37; + pub(crate) const COUNT: usize = 38; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -114,6 +116,7 @@ impl Segment { Self::TouchedAddresses, Self::ContextCheckpoints, Self::BlockHashes, + Self::CreatedContracts, ] } @@ -157,6 +160,7 @@ impl Segment { Segment::TouchedAddresses => "SEGMENT_TOUCHED_ADDRESSES", Segment::ContextCheckpoints => "SEGMENT_CONTEXT_CHECKPOINTS", Segment::BlockHashes => "SEGMENT_BLOCK_HASHES", + Segment::CreatedContracts => "SEGMENT_CREATED_CONTRACTS", } } @@ -200,6 +204,7 @@ impl Segment { Segment::TouchedAddresses => 256, Segment::ContextCheckpoints => 256, Segment::BlockHashes => 256, + Segment::CreatedContracts => 256, } } } From 496e2191559dc023a61fba7a430fbdfdeaa45256 Mon Sep 17 00:00:00 2001 From: Hamy Ratoanina Date: Mon, 6 Nov 2023 18:52:38 -0500 Subject: [PATCH 2/3] Fix balance transfer logic --- .../cpu/kernel/asm/core/selfdestruct_list.asm | 39 +---------- evm/src/cpu/kernel/asm/core/terminate.asm | 66 +++++++++++++++++-- 2 files changed, 63 insertions(+), 42 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm b/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm index f5f798722e..b3903f71a0 100644 --- a/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm +++ b/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm @@ -12,41 +12,6 @@ %mstore_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN) // Store new length. %endmacro -global maybe_insert_selfdestruct_list: - // stack: addr, retdest - %mload_global_metadata(@GLOBAL_METADATA_CREATED_CONTRACTS_LEN) - // stack: nb_created_contracts, addr, retdest - PUSH 0 -maybe_insert_selfdestruct_list_loop: - %stack (i, nb_created_contracts, addr, retdest) -> (i, nb_created_contracts, i, nb_created_contracts, addr, retdest) - EQ %jumpi(contract_not_created) - // stack: i, nb_created_contracts, addr, retdest - DUP1 %mload_kernel(@SEGMENT_CREATED_CONTRACTS) - // stack: addr_created_contract, i, nb_created_contracts, addr, retdest - DUP4 - // stack: addr, addr_created_contract, i, nb_created_contracts, addr, retdest - EQ %jumpi(contract_just_created) - // stack: i, nb_created_contracts, addr, retdest - %increment - %jump(maybe_insert_selfdestruct_list_loop) -contract_just_created: - // stack: i, nb_created_contracts, addr, retdest - %pop2 - // stack: addr, retdest - %insert_selfdestruct_list - // stack: retdest - JUMP -contract_not_created: - // stack: i, nb_created_contracts, addr, retdest - %pop3 - JUMP - -%macro maybe_insert_selfdestruct_list - %stack (addr) -> (addr, %%after) - %jump(maybe_insert_selfdestruct_list) -%%after: -%endmacro - /// Remove one occurrence of the address from the list. /// No effect if the address is not in the list. global remove_selfdestruct_list: @@ -56,7 +21,7 @@ global remove_selfdestruct_list: PUSH 0 remove_selfdestruct_list_loop: %stack (i, len, addr, retdest) -> (i, len, i, len, addr, retdest) - EQ %jumpi(remove_self_dstruct_not_found) + EQ %jumpi(remove_selfdestruct_not_found) // stack: i, len, addr, retdest DUP1 %mload_kernel(@SEGMENT_SELFDESTRUCT_LIST) // stack: loaded_addr, i, len, addr, retdest @@ -75,7 +40,7 @@ remove_selfdestruct_list_found: SWAP1 %mstore_kernel(@SEGMENT_SELFDESTRUCT_LIST) // Store the last address at the position of the removed address. JUMP -remove_self_dstruct_not_found: +remove_selfdestruct_not_found: // stack: i, len, addr, retdest %pop3 JUMP diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index b965447ad0..91b2ab8fd0 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -81,11 +81,6 @@ global sys_selfdestruct: %charge_gas %stack (kexit_info, balance, address, recipient) -> (balance, address, recipient, kexit_info) - // EIP-6780: insert address into the selfdestruct set if contact has been created - // during the current transaction. - // stack: balance, address, recipient, kexit_info - DUP2 %maybe_insert_selfdestruct_list - // Set the balance of the address to 0. // stack: balance, address, recipient, kexit_info PUSH 0 @@ -96,6 +91,14 @@ global sys_selfdestruct: // stack: balance_ptr, 0, balance, address, recipient, kexit_info %mstore_trie_data + + // EIP-6780: insert address into the selfdestruct set only if contract has been created + // during the current transaction. + // stack: balance, address, recipient, kexit_info + DUP2 %contract_just_created + // stack: is_just_created, balance, address, recipient, kexit_info + %jumpi(sys_selfdestruct_just_created) + // Send the balance to the recipient. %stack (balance, address, recipient, kexit_info) -> (recipient, balance, address, recipient, balance, kexit_info) @@ -111,6 +114,21 @@ sys_selfdestruct_journal_add: PUSH 1 // success %jump(terminate_common) +sys_selfdestruct_just_created: + // Send funds to beneficiary only if the recipient isn't the same as the address. + %stack (balance, address, recipient, kexit_info) -> (address, recipient, balance, address, recipient, balance, kexit_info) + EQ ISZERO + // stack: address ≠ recipient, balance, address, recipient, balance, kexit_info + MUL + // stack: maybe_balance, address, recipient, balance, kexit_info + DUP3 + // stack: recipient, maybe_balance, address, recipient, balance, kexit_info + %add_eth + // stack: address, recipient, balance, kexit_info + DUP1 + %insert_selfdestruct_list + %jump(sys_selfdestruct_journal_add) + global sys_revert: // stack: kexit_info, offset, size %stack (kexit_info, offset, size) -> (offset, size, kexit_info, offset, size) @@ -205,3 +223,41 @@ global terminate_common: // stack: parent_pc, success, leftover_gas JUMP + + + + +// Returns 1 if the address is present in SEGMENT_CREATED_CONTRACTS, meaning that it has been +// created during this transaction. Returns 0 otherwise. +// Pre stack: addr +// Post stack: is_just_created +%macro contract_just_created + // stack: addr + %mload_global_metadata(@GLOBAL_METADATA_CREATED_CONTRACTS_LEN) + // stack: nb_created_contracts, addr + PUSH 0 +%%maybe_insert_selfdestruct_list_loop: + %stack (i, nb_created_contracts, addr) -> (i, nb_created_contracts, i, nb_created_contracts, addr) + EQ %jumpi(%%contract_not_created) + // stack: i, nb_created_contracts, addr + DUP1 %mload_kernel(@SEGMENT_CREATED_CONTRACTS) + // stack: addr_created_contract, i, nb_created_contracts, addr + DUP4 + // stack: addr, addr_created_contract, i, nb_created_contracts, addr + EQ %jumpi(%%contract_just_created) + // stack: i, nb_created_contracts, addr + %increment + %jump(%%maybe_insert_selfdestruct_list_loop) +%%contract_just_created: + // stack: i, nb_created_contracts, addr + %pop3 + PUSH 1 + // stack: 1 + %jump(%%after) +%%contract_not_created: + // stack: i, nb_created_contracts, addr + %pop3 + PUSH 0 + // stack: 0 +%%after: +%endmacro From a44cd559e5bdbc4aa86de86c2f7da643e0b44ff2 Mon Sep 17 00:00:00 2001 From: Hamy Ratoanina Date: Tue, 7 Nov 2023 09:28:15 -0500 Subject: [PATCH 3/3] Apply comment --- evm/src/cpu/kernel/asm/core/terminate.asm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index 91b2ab8fd0..6811234a9a 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -236,25 +236,25 @@ global terminate_common: %mload_global_metadata(@GLOBAL_METADATA_CREATED_CONTRACTS_LEN) // stack: nb_created_contracts, addr PUSH 0 -%%maybe_insert_selfdestruct_list_loop: +%%contract_just_created_loop: %stack (i, nb_created_contracts, addr) -> (i, nb_created_contracts, i, nb_created_contracts, addr) - EQ %jumpi(%%contract_not_created) + EQ %jumpi(%%contract_just_created_false) // stack: i, nb_created_contracts, addr DUP1 %mload_kernel(@SEGMENT_CREATED_CONTRACTS) // stack: addr_created_contract, i, nb_created_contracts, addr DUP4 // stack: addr, addr_created_contract, i, nb_created_contracts, addr - EQ %jumpi(%%contract_just_created) + EQ %jumpi(%%contract_just_created_true) // stack: i, nb_created_contracts, addr %increment - %jump(%%maybe_insert_selfdestruct_list_loop) -%%contract_just_created: + %jump(%%contract_just_created_loop) +%%contract_just_created_true: // stack: i, nb_created_contracts, addr %pop3 PUSH 1 // stack: 1 %jump(%%after) -%%contract_not_created: +%%contract_just_created_false: // stack: i, nb_created_contracts, addr %pop3 PUSH 0