From d65fe1ab28e33a23daecb71fc375a5aafc8a72df Mon Sep 17 00:00:00 2001 From: Paul Gebheim Date: Fri, 3 Nov 2023 12:00:07 -0700 Subject: [PATCH] Squashed commit of the following: commit 4f854e69f3b006ebe069c1533d24b08a8c3998a5 Author: wborgeaud Date: Fri Nov 3 13:48:23 2023 +0100 Minor commit fbd4c78f288666c750469517251a0bb237dc8242 Merge: ad580c28 c70a7858 Author: wborgeaud Date: Fri Nov 3 13:42:45 2023 +0100 Merge branch 'feat/type2' into type2/smt_deletion # Conflicts: # evm/src/cpu/kernel/aggregator.rs # evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm # evm/src/cpu/kernel/asm/smt/insert.asm # evm/src/cpu/kernel/asm/smt/utils.asm # evm/src/cpu/kernel/constants/mod.rs # evm/src/cpu/kernel/tests/smt/mod.rs # evm/tests/selfdestruct.rs commit c70a7858c5eee4c05b8d46f41338ecc10c2c275c Author: wborgeaud Date: Fri Nov 3 13:37:19 2023 +0100 Start of SMT implementation for Type 2 zkEVM (#1315) * Add SMT types * Progress * Progress * Working smt hashing * Minor * Fix hash * Working insert * Minor * Add insert test for storage trie * Add missing constraints for DUP/SWAP (#1310) * Refactor wcopy syscalls * Refactor memcpy * Working test_simple_transfer * Modify add11_yml.rs * Refactor codecopy * Fix * Fix calldatacopy * Fix test on interpreter side * Remove new_stack_top_channel from StackBehavior (#1296) * Working add11_yml.rs * All tests compile * Working test_balance * Minor * Working test_extcodesize * All non-ignored tests pass * Fix test_empty_txn_list * Clippy * smt_utils point to github * Comments * Fix kexit_info in test * Review * Update Cargo.toml * Move empty check inside final iteration * Remerge context flags (#1292) * Remerge context flags * Apply comments and revert some unwanted changes * Merge NOT and POP flags. (#1257) * Merge NOT and POP flags * Add comments * Disable remaining memory channels for POP * Apply comments * Fix stack * More of memcpy_bytes * Add some documentation in EVM crate (#1295) Co-authored-by: Linda Guiga * Combine PUSH0 and PC flags. (#1256) * PR feedback * Add context constraints (#1260) * Combine JUMPDEST and KECCAK_GENERAL flags. (#1259) * Combine JUMPDEST and KECCAK_GENERAL flags. * Apply comments * Fix merging of jumpdest and keccak_general. * Add test for selfdestruct (#1321) * Add test for selfdestruct * Comment * Fix test --------- Co-authored-by: Hamy Ratoanina Co-authored-by: Robin Salen Co-authored-by: Linda Guiga <101227802+LindaGuiga@users.noreply.github.com> Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> Co-authored-by: Linda Guiga Co-authored-by: Linda Guiga commit ad580c288b6eb92bbb40e1007cca13d42f5985cd Author: wborgeaud Date: Thu Nov 2 08:40:46 2023 +0100 Clippy commit fe5b8fd435ae9c91af7e91003f1ecd2d9564808d Author: wborgeaud Date: Thu Nov 2 08:39:26 2023 +0100 s/mpt/smt in a bunch of places commit 73dc26238609e41974274fbef9c94f3dce06951a Author: wborgeaud Date: Thu Nov 2 08:15:56 2023 +0100 Selfdestruct test passes commit 539190fdce8f8baaef5a9882bb0aff0ab33f2022 Merge: e1109413 f71f227d Author: wborgeaud Date: Thu Nov 2 07:58:15 2023 +0100 Merge branch 'main' into type2/smt_deletion commit e1109413808b49d467f85d4ccc292f05e05a579f Author: wborgeaud Date: Wed Nov 1 17:04:38 2023 +0100 Minor commit f7fba3564ba1a5a41ab639a8cd9078f45e1d7cae Author: wborgeaud Date: Wed Nov 1 12:24:13 2023 +0100 PR feedback commit e528b89a7e6889c7a487366f10daa8460ed9786d Author: wborgeaud Date: Mon Oct 30 09:11:25 2023 +0100 Update Cargo.toml commit 5eaf83e36f492f56714b95eba86a858b838704af Author: wborgeaud Date: Fri Oct 27 12:34:52 2023 +0200 Comments commit ae9c443b2ceee1a1e4010284e725d642b68c9c10 Author: wborgeaud Date: Fri Oct 27 11:51:16 2023 +0200 smt_utils point to github commit b3d61b7f201c2df104f27233eba4ca132b9119b3 Author: wborgeaud Date: Fri Oct 27 11:49:33 2023 +0200 Clippy commit ccb3d7e0f3e36114cbccb919d3bb7fbddf3a4fe7 Author: wborgeaud Date: Fri Oct 27 10:00:20 2023 +0200 Fix test_empty_txn_list commit 986b01087561561c181c13c591ec386f38f1f0d8 Author: wborgeaud Date: Fri Oct 27 09:48:14 2023 +0200 All non-ignored tests pass commit 7bb0c027cea1bc4c94a040fad9b7e19f7585eed9 Author: wborgeaud Date: Fri Oct 27 09:44:40 2023 +0200 Working test_extcodesize commit b8a85d4c2fa2dd2bae191275062b1709ca88727a Author: wborgeaud Date: Fri Oct 27 09:38:08 2023 +0200 Minor commit 2c01b051173f9df36546dcb7a1a1bfbc9476bf21 Author: wborgeaud Date: Fri Oct 27 09:37:05 2023 +0200 Working test_balance commit e370b62d6b86562a8950209f448f9c362605512f Author: wborgeaud Date: Fri Oct 27 09:13:36 2023 +0200 All tests compile commit f21bc5c0fbe6f5ff91cda733f346852d2cdb9190 Author: wborgeaud Date: Fri Oct 27 08:31:04 2023 +0200 Working add11_yml.rs commit 4e2b3f3f6881442a3911ac4465b04522caae0240 Author: wborgeaud Date: Thu Oct 26 18:50:32 2023 +0200 Modify add11_yml.rs commit c3244127e2385f06e9649fbdfb804531bed0af16 Author: wborgeaud Date: Thu Oct 26 18:28:21 2023 +0200 Working test_simple_transfer commit df55e457ff3b75520b545da5a79e7a4e308ca651 Author: wborgeaud Date: Thu Oct 26 08:54:24 2023 +0200 Add insert test for storage trie commit ca0102f7932f8f87a58fbca296341195d1a48c03 Author: wborgeaud Date: Thu Oct 26 08:42:03 2023 +0200 Minor commit dc273512071150b1a554c7c2646bc7006bf0b741 Author: wborgeaud Date: Thu Oct 26 08:40:57 2023 +0200 Working insert commit f6c406749a096b218b834e37e322d3e9cbda8fc4 Author: wborgeaud Date: Wed Oct 25 08:07:31 2023 +0200 Fix hash commit c6e85eb4413b899b098662901721a727b5a2d541 Author: wborgeaud Date: Wed Oct 18 18:46:32 2023 +0200 Minor commit d95c43057b04a1428ec7602beb7bcb44eade38fc Author: wborgeaud Date: Wed Oct 18 18:32:05 2023 +0200 Working smt hashing commit fd0991555d2315d29605abeb8af7745a5f317418 Author: wborgeaud Date: Wed Oct 18 14:32:38 2023 +0200 Progress commit a706cda4e14fe56073968116df270f44b921f646 Author: wborgeaud Date: Wed Oct 18 07:37:26 2023 +0200 Progress commit 95e5cc16bdec615b376b9ff590db5b6a8ad6c1cf Author: wborgeaud Date: Fri Oct 13 09:19:45 2023 +0200 Add SMT types --- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/core/create.asm | 2 +- .../asm/core/create_contract_account.asm | 4 +- evm/src/cpu/kernel/asm/core/terminate.asm | 2 +- evm/src/cpu/kernel/asm/core/util.asm | 2 +- .../kernel/asm/journal/account_destroyed.asm | 4 +- .../cpu/kernel/asm/journal/code_change.asm | 2 +- .../cpu/kernel/asm/journal/nonce_change.asm | 2 +- .../cpu/kernel/asm/journal/storage_change.asm | 16 +- evm/src/cpu/kernel/asm/mpt/delete/delete.asm | 21 --- .../kernel/asm/mpt/storage/storage_write.asm | 6 +- evm/src/cpu/kernel/asm/smt/delete.asm | 154 ++++++++++++++++++ evm/src/cpu/kernel/asm/smt/insert.asm | 6 + evm/src/cpu/kernel/asm/smt/utils.asm | 12 ++ .../asm/transactions/common_decoding.asm | 11 +- evm/src/cpu/kernel/tests/smt/delete.rs | 87 ++++++++++ evm/src/cpu/kernel/tests/smt/mod.rs | 1 + evm/src/generation/mod.rs | 8 +- evm/src/generation/outputs.rs | 5 +- evm/src/generation/trie_extractor.rs | 3 + 20 files changed, 296 insertions(+), 53 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/smt/delete.asm create mode 100644 evm/src/cpu/kernel/tests/smt/delete.rs diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 522da72a25..bd06bb6194 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -114,6 +114,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/smt/hash.asm"), include_str!("asm/smt/insert.asm"), include_str!("asm/smt/read.asm"), + include_str!("asm/smt/delete.asm"), include_str!("asm/smt/utils.asm"), include_str!("asm/smt/accounts.asm"), include_str!("asm/mpt/delete/delete.asm"), diff --git a/evm/src/cpu/kernel/asm/core/create.asm b/evm/src/cpu/kernel/asm/core/create.asm index 4756b40702..c0d768f9aa 100644 --- a/evm/src/cpu/kernel/asm/core/create.asm +++ b/evm/src/cpu/kernel/asm/core/create.asm @@ -242,7 +242,7 @@ create_too_deep: global set_codehash: // stack: addr, codehash, retdest DUP1 %insert_touched_addresses - DUP1 %mpt_read_state_trie + DUP1 %smt_read_state // stack: account_ptr, addr, codehash, retdest %add_const(3) // stack: codehash_ptr, addr, codehash, retdest 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..ca74dcfe67 100644 --- a/evm/src/cpu/kernel/asm/core/create_contract_account.asm +++ b/evm/src/cpu/kernel/asm/core/create_contract_account.asm @@ -4,7 +4,7 @@ %macro create_contract_account // stack: address DUP1 %insert_touched_addresses - DUP1 %mpt_read_state_trie + DUP1 %smt_read_state // stack: existing_account_ptr, address // If the account doesn't exist, there's no need to check its balance or nonce, // so we can skip ahead, setting existing_balance = existing_account_ptr = 0. @@ -46,7 +46,7 @@ // stack: address, account_ptr %addr_to_state_key // stack: state_key, account_ptr - %mpt_insert_state_trie + %smt_insert_state // stack: (empty) PUSH 0 // success %jump(%%end) diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index bdbd3e5886..a91d664752 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -89,7 +89,7 @@ global sys_selfdestruct: // stack: balance, address, recipient, kexit_info PUSH 0 // stack: 0, balance, address, recipient, kexit_info - DUP3 %mpt_read_state_trie + DUP3 %smt_read_state // stack: account_ptr, 0, balance, address, recipient, kexit_info %add_const(1) // stack: balance_ptr, 0, balance, address, recipient, kexit_info diff --git a/evm/src/cpu/kernel/asm/core/util.asm b/evm/src/cpu/kernel/asm/core/util.asm index a186520cd7..33d60ab709 100644 --- a/evm/src/cpu/kernel/asm/core/util.asm +++ b/evm/src/cpu/kernel/asm/core/util.asm @@ -34,7 +34,7 @@ // Returns 1 if the account is non-existent, 0 otherwise. %macro is_non_existent // stack: addr - %mpt_read_state_trie ISZERO + %smt_read_state ISZERO %endmacro // Returns 1 if the account is empty, 0 otherwise. diff --git a/evm/src/cpu/kernel/asm/journal/account_destroyed.asm b/evm/src/cpu/kernel/asm/journal/account_destroyed.asm index 3806a891dc..152e87bc70 100644 --- a/evm/src/cpu/kernel/asm/journal/account_destroyed.asm +++ b/evm/src/cpu/kernel/asm/journal/account_destroyed.asm @@ -16,7 +16,7 @@ revert_account_destroyed_contd: SWAP1 // Remove `prev_balance` from `target`'s balance. // stack: target, address, prev_balance, retdest - %mpt_read_state_trie + %smt_read_state %add_const(1) // stack: target_balance_ptr, address, prev_balance, retdest DUP3 @@ -25,7 +25,7 @@ revert_account_destroyed_contd: SUB SWAP1 %mstore_trie_data // Set `address`'s balance to `prev_balance`. // stack: address, prev_balance, retdest - %mpt_read_state_trie + %smt_read_state %add_const(1) %mstore_trie_data JUMP diff --git a/evm/src/cpu/kernel/asm/journal/code_change.asm b/evm/src/cpu/kernel/asm/journal/code_change.asm index 5bb637c726..df211135a8 100644 --- a/evm/src/cpu/kernel/asm/journal/code_change.asm +++ b/evm/src/cpu/kernel/asm/journal/code_change.asm @@ -9,7 +9,7 @@ global revert_code_change: POP %journal_load_2 // stack: address, prev_codehash, retdest - %mpt_read_state_trie + %smt_read_state // stack: account_ptr, prev_codehash, retdest %add_const(3) // stack: codehash_ptr, prev_codehash, retdest diff --git a/evm/src/cpu/kernel/asm/journal/nonce_change.asm b/evm/src/cpu/kernel/asm/journal/nonce_change.asm index 3ab8f13677..3c2ab17060 100644 --- a/evm/src/cpu/kernel/asm/journal/nonce_change.asm +++ b/evm/src/cpu/kernel/asm/journal/nonce_change.asm @@ -9,7 +9,7 @@ global revert_nonce_change: POP %journal_load_2 // stack: address, prev_nonce, retdest - %mpt_read_state_trie + %smt_read_state // stack: nonce_ptr, prev_nonce retdest %mstore_trie_data // stack: retdest diff --git a/evm/src/cpu/kernel/asm/journal/storage_change.asm b/evm/src/cpu/kernel/asm/journal/storage_change.asm index 752674d1e1..1a5d7e44c1 100644 --- a/evm/src/cpu/kernel/asm/journal/storage_change.asm +++ b/evm/src/cpu/kernel/asm/journal/storage_change.asm @@ -15,7 +15,7 @@ global revert_storage_change: // stack: storage_key, address, prev_value, retdest PUSH 64 // storage_key has 64 nibbles // stack: 64, storage_key, address, prev_value, retdest - DUP3 %mpt_read_state_trie + DUP3 %smt_read_state DUP1 ISZERO %jumpi(panic) // stack: account_ptr, 64, storage_key, address, prev_value, retdest %add_const(2) @@ -33,20 +33,18 @@ delete: %stack (slot, address, retdest) -> (slot, new_storage_root, address, retdest) %slot_to_storage_key // stack: storage_key, new_storage_root, address, retdest - PUSH 64 // storage_key has 64 nibbles - // stack: 64, storage_key, new_storage_root, address, retdest - DUP4 %mpt_read_state_trie + DUP3 %smt_read_state DUP1 ISZERO %jumpi(panic) - // stack: account_ptr, 64, storage_key, new_storage_root, address, retdest + // stack: account_ptr, storage_key, new_storage_root, address, retdest %add_const(2) - // stack: storage_root_ptr_ptr, 64, storage_key, new_storage_root, address, retdest + // stack: storage_root_ptr_ptr, storage_key, new_storage_root, address, retdest %mload_trie_data - // stack: storage_root_ptr, 64, storage_key, new_storage_root, address, retdest - %jump(mpt_delete) + // stack: storage_root_ptr, storage_key, new_storage_root, address, retdest + %jump(smt_delete) new_storage_root: // stack: new_storage_root_ptr, address, retdest - DUP2 %mpt_read_state_trie + DUP2 %smt_read_state // stack: account_ptr, new_storage_root_ptr, address, retdest // Update account with our new storage root pointer. diff --git a/evm/src/cpu/kernel/asm/mpt/delete/delete.asm b/evm/src/cpu/kernel/asm/mpt/delete/delete.asm index 913ba1fcfb..5df1e283b1 100644 --- a/evm/src/cpu/kernel/asm/mpt/delete/delete.asm +++ b/evm/src/cpu/kernel/asm/mpt/delete/delete.asm @@ -22,24 +22,3 @@ mpt_delete_leaf: %pop4 PUSH 0 // empty node ptr SWAP1 JUMP - -global delete_account: - %stack (address, retdest) -> (address, delete_account_save, retdest) - %addr_to_state_key - // stack: key, delete_account_save, retdest - PUSH 64 - // stack: 64, key, delete_account_save, retdest - %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) - // stack: state_root_prt, 64, key, delete_account_save, retdest - %jump(mpt_delete) -delete_account_save: - // stack: updated_state_root_ptr, retdest - %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) - JUMP - -%macro delete_account - %stack (address) -> (address, %%after) - %jump(delete_account) -%%after: - // stack: (empty) -%endmacro \ No newline at end of file diff --git a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm index 5caafb3b5f..f5b9610cc5 100644 --- a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm +++ b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm @@ -133,14 +133,12 @@ sstore_noop: // Delete the slot from the storage SMT. sstore_delete: - PANIC // TODO: Not implemented for SMT. // stack: slot, value, kexit_info SWAP1 POP PUSH after_storage_insert SWAP1 // stack: slot, after_storage_insert, kexit_info %slot_to_storage_key // stack: storage_key, after_storage_insert, kexit_info - PUSH 64 // storage_key has 64 nibbles %current_storage_smt - // stack: storage_root_ptr, 64, storage_key, after_storage_insert, kexit_info - %jump(mpt_delete) + // stack: storage_root_ptr, storage_key, after_storage_insert, kexit_info + %jump(smt_delete) diff --git a/evm/src/cpu/kernel/asm/smt/delete.asm b/evm/src/cpu/kernel/asm/smt/delete.asm new file mode 100644 index 0000000000..ec6268ef47 --- /dev/null +++ b/evm/src/cpu/kernel/asm/smt/delete.asm @@ -0,0 +1,154 @@ +// Return a copy of the given node with the given key deleted. +// Assumes that the key is in the SMT. +// +// Pre stack: node_ptr, key, retdest +// Post stack: updated_node_ptr +global smt_delete: + // stack: node_ptr, key, retdest + DUP1 %mload_trie_data + // stack: node_type, node_ptr, key, retdest + // Increment node_ptr, so it points to the node payload instead of its type. + SWAP1 %increment SWAP1 + // stack: node_type, node_payload_ptr, key, retdest + + DUP1 %eq_const(@SMT_NODE_INTERNAL) %jumpi(smt_delete_internal) + DUP1 %eq_const(@SMT_NODE_LEAF) %jumpi(smt_delete_leaf) + PANIC // Should never happen. + +smt_delete_leaf: + // stack: node_type, node_payload_ptr, key, retdest + %pop3 + PUSH 0 // empty node ptr + SWAP1 JUMP + +smt_delete_internal: + // stack: node_type, node_payload_ptr, key, retdest + POP + // stack: node_payload_ptr, key, retdest + SWAP1 %pop_bit + %stack (bit, key, node_payload_ptr, retdest) -> (bit, node_payload_ptr, key, internal_update, node_payload_ptr, bit, retdest) + ADD + // stack: child_ptr_ptr, key, internal_update, node_payload_ptr, bit, retdest + %mload_trie_data + // stack: child_ptr, key, internal_update, node_payload_ptr, bit, retdest + %jump(smt_delete) + +// Update the internal node, possibly deleting it, or returning a leaf node. +// TODO: Could replace a lot of `is_empty` check with just ISZERO. +internal_update: + // Update the child first. + // stack: deleted_child_ptr, node_payload_ptr, bit, retdest + DUP3 PUSH 1 SUB + // stack: 1-bit, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP3 ADD + // stack: sibling_ptr_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + %mload_trie_data DUP1 %mload_trie_data + // stack: sibling_node_type, sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP1 %eq_const(@SMT_NODE_HASH) %jumpi(sibling_is_hash) + %eq_const(@SMT_NODE_LEAF) %jumpi(sibling_is_leaf) +sibling_is_internal: + // stack: sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + POP +insert_child: + // stack: deleted_child_ptr, node_payload_ptr, bit, retdest + %stack (deleted_child_ptr, node_payload_ptr, bit) -> (node_payload_ptr, bit, deleted_child_ptr, node_payload_ptr) + ADD %mstore_trie_data + // stack: node_payload_ptr, retdest + %decrement SWAP1 + // stack: retdest, node_ptr + JUMP + +sibling_is_hash: + // stack: sibling_node_type, sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + POP + // stack: sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + %increment %mload_trie_data + // stack: hash, deleted_child_ptr, node_payload_ptr, bit, retdest + %jumpi(insert_child) +sibling_is_empty: + // stack: deleted_child_ptr, node_payload_ptr, bit, retdest + DUP1 %mload_trie_data + // stack: deleted_child_node_type, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP1 %eq_const(@SMT_NODE_HASH) %jumpi(sibling_is_empty_child_is_hash) + DUP1 %eq_const(@SMT_NODE_LEAF) %jumpi(sibling_is_empty_child_is_leaf) +sibling_is_empty_child_is_internal: + // stack: deleted_child_node_type, deleted_child_ptr, node_payload_ptr, bit, retdest + POP + // stack: deleted_child_ptr, node_payload_ptr, bit, retdest + %jump(insert_child) + +sibling_is_empty_child_is_hash: + // stack: deleted_child_node_type, deleted_child_ptr, node_payload_ptr, bit, retdest + POP + // stack: deleted_child_ptr, node_payload_ptr, bit, retdest + DUP1 %increment %mload_trie_data + // stack: hash, deleted_child_ptr, node_payload_ptr, bit, retdest + %jumpi(insert_child) +sibling_is_empty_child_is_empty: + // We can just delete this node. + // stack: deleted_child_ptr, node_payload_ptr, bit, retdest + %pop3 + SWAP1 PUSH 0 + // stack: retdest, 0 + JUMP + +sibling_is_empty_child_is_leaf: + // stack: deleted_child_node_type, deleted_child_ptr, node_payload_ptr, bit, retdest + POP + // stack: deleted_child_ptr, node_payload_ptr, bit, retdest + DUP1 %increment %mload_trie_data + // stack: child_key_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP1 %mload_trie_data + // stack: key, child_key_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + %shl_const(1) + // stack: key<<1, child_key_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP5 ADD + // stack: new_key, child_key_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + SWAP1 %mstore_trie_data + %stack (deleted_child_ptr, node_payload_ptr, bit, retdest) -> (retdest, deleted_child_ptr) + JUMP + +sibling_is_leaf: + // stack: sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP2 %is_non_empty_node + // stack: child_is_non_empty, sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + %jumpi(sibling_is_leaf_child_is_non_empty) +sibling_is_leaf_child_is_empty: + // stack: sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP1 %increment %mload_trie_data + // stack: sibling_key_ptr, sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP1 %mload_trie_data + // stack: sibling_key, sibling_key_ptr, sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + %shl_const(1) + // stack: sibling_key<<1, sibling_key_ptr, sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + DUP6 PUSH 1 SUB + // stack: 1-bit, sibling_key<<1, sibling_key_ptr, sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + ADD SWAP1 %mstore_trie_data + // stack: sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + %stack (sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest) -> (retdest, sibling_ptr) + JUMP + +sibling_is_leaf_child_is_non_empty: + // stack: sibling_ptr, deleted_child_ptr, node_payload_ptr, bit, retdest + POP + // stack: deleted_child_ptr, node_payload_ptr, bit, retdest + %jump(insert_child) + +global delete_account: + %stack (address, retdest) -> (address, delete_account_save, retdest) + %addr_to_state_key + // stack: key, delete_account_save, retdest + %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) + // stack: state_root_prt, key, delete_account_save, retdest + %jump(smt_delete) +delete_account_save: + // stack: updated_state_root_ptr, retdest + %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) + JUMP + +%macro delete_account + %stack (address) -> (address, %%after) + %jump(delete_account) +%%after: + // stack: (empty) +%endmacro diff --git a/evm/src/cpu/kernel/asm/smt/insert.asm b/evm/src/cpu/kernel/asm/smt/insert.asm index 32b248c66a..cc8f58405b 100644 --- a/evm/src/cpu/kernel/asm/smt/insert.asm +++ b/evm/src/cpu/kernel/asm/smt/insert.asm @@ -12,6 +12,12 @@ smt_insert_state_set_root: // stack: retdest JUMP +%macro smt_insert_state + %stack (key, value_ptr) -> (key, value_ptr, %%after) + %jump(smt_insert_state) +%%after: +%endmacro + // Insert a key-value pair in the SMT at `trie_data[node_ptr]`. // `value_ptr` should point to a an empty slot reserved for `rem_key`, followed by the actual value. // Pseudocode: diff --git a/evm/src/cpu/kernel/asm/smt/utils.asm b/evm/src/cpu/kernel/asm/smt/utils.asm index 145f61310a..bc5dd57ee7 100644 --- a/evm/src/cpu/kernel/asm/smt/utils.asm +++ b/evm/src/cpu/kernel/asm/smt/utils.asm @@ -5,3 +5,15 @@ SWAP1 %and_const(1) // stack: key&1, key>>1 %endmacro + +// Returns a non-zero value if the node is non-empty. +%macro is_non_empty_node + // stack: node_ptr + DUP1 %mload_trie_data %jumpi(%%end) // If the node is not a hash node, node_ptr is non-zero. + // The node is a hash node + // stack: node_ptr + %increment %mload_trie_data + // stack: hash + %jump(%%end) +%%end: +%endmacro diff --git a/evm/src/cpu/kernel/asm/transactions/common_decoding.asm b/evm/src/cpu/kernel/asm/transactions/common_decoding.asm index d4df7a6e57..96279b0822 100644 --- a/evm/src/cpu/kernel/asm/transactions/common_decoding.asm +++ b/evm/src/cpu/kernel/asm/transactions/common_decoding.asm @@ -235,17 +235,16 @@ 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 + %stack (storage_key, addr, after_storage_read) -> (addr, storage_key, after_storage_read) + %smt_read_state + // stack: account_ptr, 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 + // stack: account_ptr, 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) + %jump(smt_read) ret_zero: // stack: account_ptr, 64, storage_key, after_storage_read, retdest diff --git a/evm/src/cpu/kernel/tests/smt/delete.rs b/evm/src/cpu/kernel/tests/smt/delete.rs new file mode 100644 index 0000000000..494f1dc8ed --- /dev/null +++ b/evm/src/cpu/kernel/tests/smt/delete.rs @@ -0,0 +1,87 @@ +use anyhow::{anyhow, Result}; +use ethereum_types::{BigEndianHash, H256, U256}; +use rand::{thread_rng, Rng}; +use smt_utils::account::Account; +use smt_utils::smt::Smt; + +use crate::cpu::kernel::aggregator::KERNEL; +use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; +use crate::cpu::kernel::interpreter::Interpreter; +use crate::generation::mpt::{all_mpt_prover_inputs_reversed, state_smt_prover_inputs_reversed}; +use crate::generation::TrieInputs; + +#[test] +fn smt_delete() -> Result<()> { + let mut rng = thread_rng(); + let n = rng.gen_range(0..100); + let rand_node = |_| (U256(rng.gen()).into(), Account::rand(10).into()); + let smt = Smt::new((0..n).map(rand_node)).unwrap(); + + let new_account = Account::rand(0); + test_state_smt(smt, U256(rng.gen()), new_account) +} + +fn test_state_smt(smt: Smt, k: U256, account: Account) -> Result<()> { + let trie_inputs = TrieInputs { + state_smt: smt.serialize(), + transactions_trie: Default::default(), + receipts_trie: Default::default(), + storage_tries: vec![], + }; + let load_all_mpts = KERNEL.global_labels["load_all_mpts"]; + let smt_insert_state = KERNEL.global_labels["smt_insert_state"]; + let smt_delete = KERNEL.global_labels["smt_delete"]; + let smt_hash_state = KERNEL.global_labels["smt_hash_state"]; + + let initial_stack = vec![0xDEADBEEFu32.into()]; + let mut interpreter = Interpreter::new_with_kernel(load_all_mpts, initial_stack); + interpreter.generation_state.state_smt_prover_inputs = + state_smt_prover_inputs_reversed(&trie_inputs); + interpreter.generation_state.mpt_prover_inputs = + all_mpt_prover_inputs_reversed(&trie_inputs).map_err(|_| anyhow!("Invalid MPT data"))?; + interpreter.run()?; + assert_eq!(interpreter.stack(), vec![]); + + // Next, execute smt_insert_state. + interpreter.generation_state.registers.program_counter = smt_insert_state; + let trie_data = interpreter.get_trie_data_mut(); + let value_ptr = trie_data.len(); + trie_data.push(U256::zero()); // For the key. + trie_data.push(account.nonce.into()); + trie_data.push(account.balance); + trie_data.push(U256::zero()); // Empty storage root. + trie_data.push(account.code_hash.into_uint()); + let trie_data_len = trie_data.len().into(); + interpreter.set_global_metadata_field(GlobalMetadata::TrieDataSize, trie_data_len); + interpreter.push(0xDEADBEEFu32.into()); + interpreter.push(value_ptr.into()); // value_ptr + interpreter.push(k); // key + interpreter.run()?; + assert_eq!( + interpreter.stack().len(), + 0, + "Expected empty stack after insert, found {:?}", + interpreter.stack() + ); + + // Next, execute smt_delete, deleting the account we just inserted. + let state_trie_ptr = interpreter.get_global_metadata_field(GlobalMetadata::StateTrieRoot); + interpreter.generation_state.registers.program_counter = smt_delete; + interpreter.push(0xDEADBEEFu32.into()); + interpreter.push(k); + interpreter.push(state_trie_ptr); + interpreter.run()?; + let state_trie_ptr = interpreter.pop(); + interpreter.set_global_metadata_field(GlobalMetadata::StateTrieRoot, state_trie_ptr); + + // Now, execute smt_hash_state. + interpreter.generation_state.registers.program_counter = smt_hash_state; + interpreter.push(0xDEADBEEFu32.into()); + interpreter.run()?; + + let state_smt_hash = H256::from_uint(&interpreter.pop()); + let expected_state_smt_hash = smt.root; + assert_eq!(state_smt_hash, expected_state_smt_hash); + + Ok(()) +} diff --git a/evm/src/cpu/kernel/tests/smt/mod.rs b/evm/src/cpu/kernel/tests/smt/mod.rs index 2d7504cdc5..6a9fd304b2 100644 --- a/evm/src/cpu/kernel/tests/smt/mod.rs +++ b/evm/src/cpu/kernel/tests/smt/mod.rs @@ -1,2 +1,3 @@ +mod delete; mod hash; mod insert; diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index c4d19dca01..d3b1b0c7b2 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -21,7 +21,7 @@ use crate::cpu::bootstrap_kernel::generate_bootstrap_kernel; use crate::cpu::columns::CpuColumnsView; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; -use crate::generation::outputs::{get_outputs, GenerationOutputs}; +use crate::generation::outputs::GenerationOutputs; use crate::generation::state::GenerationState; use crate::memory::segments::Segment; use crate::proof::{BlockHashes, BlockMetadata, ExtraBlockData, PublicValues, TrieRoots}; @@ -255,8 +255,10 @@ pub fn generate_traces, const D: usize>( state.traces.get_lengths() ); - let outputs = get_outputs(&mut state) - .map_err(|err| anyhow!("Failed to generate post-state info: {:?}", err))?; + // TODO: fix this + // let outputs = get_outputs(&mut state) + // .map_err(|err| anyhow!("Failed to generate post-state info: {:?}", err))?; + let outputs = Default::default(); let read_metadata = |field| state.memory.read_global_metadata(field); let trie_roots_before = TrieRoots { diff --git a/evm/src/generation/outputs.rs b/evm/src/generation/outputs.rs index 0ce8708297..ccea75bbf5 100644 --- a/evm/src/generation/outputs.rs +++ b/evm/src/generation/outputs.rs @@ -12,7 +12,7 @@ use crate::util::u256_to_usize; use crate::witness::errors::ProgramError; /// The post-state after trace generation; intended for debugging. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct GenerationOutputs { pub accounts: HashMap, } @@ -31,6 +31,7 @@ pub struct AccountOutput { pub storage: HashMap, } +#[allow(unused)] pub(crate) fn get_outputs( state: &mut GenerationState, ) -> Result { @@ -64,6 +65,7 @@ pub(crate) fn get_outputs( Ok(GenerationOutputs { accounts }) } +#[allow(unused)] fn account_trie_record_to_output( state: &GenerationState, account: AccountTrieRecord, @@ -88,6 +90,7 @@ fn account_trie_record_to_output( }) } +#[allow(unused)] /// Get an account's storage trie, given a pointer to its root. fn get_storage( state: &GenerationState, diff --git a/evm/src/generation/trie_extractor.rs b/evm/src/generation/trie_extractor.rs index 42c50c6d75..dfc9c26f24 100644 --- a/evm/src/generation/trie_extractor.rs +++ b/evm/src/generation/trie_extractor.rs @@ -12,6 +12,7 @@ use crate::witness::errors::ProgramError; use crate::witness::memory::{MemoryAddress, MemoryState}; /// Account data as it's stored in the state trie, with a pointer to the storage trie. +#[allow(unused)] #[derive(Debug)] pub(crate) struct AccountTrieRecord { pub(crate) nonce: u64, @@ -20,6 +21,7 @@ pub(crate) struct AccountTrieRecord { pub(crate) code_hash: H256, } +#[allow(unused)] pub(crate) fn read_state_trie_value(slice: &[U256]) -> Result { Ok(AccountTrieRecord { nonce: slice[0].low_u64(), @@ -29,6 +31,7 @@ pub(crate) fn read_state_trie_value(slice: &[U256]) -> Result U256 { slice[0] }