From 9f9143d6f6ff0e36d32dd907dcff11453388a56d Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 2 Oct 2022 11:14:07 -0700 Subject: [PATCH 1/2] Finish some misc storage logic --- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/core/transfer.asm | 33 +++++++- evm/src/cpu/kernel/asm/main.asm | 8 +- evm/src/cpu/kernel/asm/mpt/hash.asm | 47 +---------- .../cpu/kernel/asm/mpt/hash_trie_specific.asm | 80 +++++++++++++++++++ evm/src/cpu/kernel/asm/mpt/read.asm | 20 ++++- evm/src/cpu/kernel/asm/mpt/write.asm | 1 + evm/src/cpu/kernel/global_metadata.rs | 32 ++++---- evm/src/generation/mod.rs | 10 +-- evm/tests/empty_txn_list.rs | 2 +- 10 files changed, 160 insertions(+), 74 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/mpt/hash_trie_specific.asm diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 76091a2e..002a84fb 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -43,6 +43,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/rlp/decode.asm"), include_str!("asm/rlp/read_to_memory.asm"), include_str!("asm/mpt/hash.asm"), + include_str!("asm/mpt/hash_trie_specific.asm"), include_str!("asm/mpt/hex_prefix.asm"), include_str!("asm/mpt/load.asm"), include_str!("asm/mpt/read.asm"), diff --git a/evm/src/cpu/kernel/asm/core/transfer.asm b/evm/src/cpu/kernel/asm/core/transfer.asm index 0ed48f4d..b12bc9de 100644 --- a/evm/src/cpu/kernel/asm/core/transfer.asm +++ b/evm/src/cpu/kernel/asm/core/transfer.asm @@ -1,11 +1,15 @@ // Transfers some ETH from one address to another. The amount is given in wei. // Pre stack: from, to, amount, retdest // Post stack: (empty) - global transfer_eth: // stack: from, to, amount, retdest - // TODO: Replace with actual implementation. - %pop3 + %stack (from, to, amount, retdest) + -> (from, amount, to, amount) + %deduct_eth + // TODO: Handle exception from %deduct_eth? + // stack: to, amount, retdest + %add_eth + // stack: retdest JUMP // Convenience macro to call transfer_eth and return where we left off. @@ -26,3 +30,26 @@ global transfer_eth: %transfer_eth %%after: %endmacro + +global deduct_eth: + // stack: addr, amount, retdest + %jump(mpt_read_state_trie) +deduct_eth_after_read: + PANIC // TODO + +// Convenience macro to call deduct_eth and return where we left off. +%macro deduct_eth + %stack (addr, amount) -> (addr, amount, %%after) + %jump(deduct_eth) +%%after: +%endmacro + +global add_eth: + PANIC // TODO + +// Convenience macro to call add_eth and return where we left off. +%macro add_eth + %stack (addr, amount) -> (addr, amount, %%after) + %jump(add_eth) +%%after: +%endmacro diff --git a/evm/src/cpu/kernel/asm/main.asm b/evm/src/cpu/kernel/asm/main.asm index a27a1527..e8c8e3e4 100644 --- a/evm/src/cpu/kernel/asm/main.asm +++ b/evm/src/cpu/kernel/asm/main.asm @@ -4,7 +4,9 @@ global main: %jump(load_all_mpts) hash_initial_tries: - // TODO: Hash each trie and set @GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE, etc. + %mpt_hash_state_trie %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE) + %mpt_hash_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE) + %mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_BEFORE) txn_loop: // If the prover has no more txns for us to process, halt. @@ -16,5 +18,7 @@ txn_loop: %jump(route_txn) hash_final_tries: - // TODO: Hash each trie and set @GLOBAL_METADATA_STATE_TRIE_DIGEST_AFTER, etc. + %mpt_hash_state_trie %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_DIGEST_AFTER) + %mpt_hash_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_AFTER) + %mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_AFTER) %jump(halt) diff --git a/evm/src/cpu/kernel/asm/mpt/hash.asm b/evm/src/cpu/kernel/asm/mpt/hash.asm index eb896208..053f357c 100644 --- a/evm/src/cpu/kernel/asm/mpt/hash.asm +++ b/evm/src/cpu/kernel/asm/mpt/hash.asm @@ -1,46 +1,3 @@ -global mpt_hash_state_trie: - // stack: retdest - %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) - // stack: node_ptr, retdest - %mpt_hash(encode_account) - -encode_account: - // stack: rlp_pos, value_ptr, retdest - // First, we compute the length of the RLP data we're about to write. - // The nonce and balance fields are variable-length, so we need to load them - // to determine their contribution, while the other two fields are fixed - // 32-bytes integers. - DUP2 %mload_trie_data // nonce = value[0] - %scalar_rlp_len - // stack: nonce_rlp_len, rlp_pos, value_ptr, retdest - DUP3 %add_const(1) %mload_trie_data // balance = value[1] - %scalar_rlp_len - // stack: balance_rlp_lenm, nonce_rlp_len, rlp_pos, value_ptr, retdest - PUSH 66 // storage_root and code_hash fields each take 1 + 32 bytes - ADD ADD - // stack: payload_len, rlp_pos, value_ptr, retdest - SWAP1 - %encode_rlp_list_prefix - // stack: rlp_pos', value_ptr, retdest - DUP2 %mload_trie_data // nonce = value[0] - // stack: nonce, rlp_pos', value_ptr, retdest - SWAP1 %encode_rlp_scalar - // stack: rlp_pos'', value_ptr, retdest - DUP2 %add_const(1) %mload_trie_data // balance = value[1] - // stack: balance, rlp_pos'', value_ptr, retdest - SWAP1 %encode_rlp_scalar - // stack: rlp_pos''', value_ptr, retdest - DUP2 %add_const(2) %mload_trie_data // storage_root = value[2] - // stack: storage_root, rlp_pos''', value_ptr, retdest - SWAP1 %encode_rlp_256 - // stack: rlp_pos'''', value_ptr, retdest - SWAP1 %add_const(3) %mload_trie_data // code_hash = value[3] - // stack: code_hash, rlp_pos'''', retdest - SWAP1 %encode_rlp_256 - // stack: rlp_pos''''', retdest - SWAP1 - JUMP - // Computes the Merkle root of the given trie node. // // The encode_value function should take as input @@ -111,11 +68,11 @@ encode_account: JUMP %endmacro -mpt_hash_empty: +global mpt_hash_empty: %stack (node_type, node_payload_ptr, retdest) -> (retdest, @EMPTY_NODE_HASH) JUMP -mpt_hash_hash: +global mpt_hash_hash: // stack: node_type, node_payload_ptr, retdest POP // stack: node_payload_ptr, retdest diff --git a/evm/src/cpu/kernel/asm/mpt/hash_trie_specific.asm b/evm/src/cpu/kernel/asm/mpt/hash_trie_specific.asm new file mode 100644 index 00000000..30ea730f --- /dev/null +++ b/evm/src/cpu/kernel/asm/mpt/hash_trie_specific.asm @@ -0,0 +1,80 @@ +// Hashing logic specific to a particular trie. + +global mpt_hash_state_trie: + // stack: retdest + %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) + // stack: node_ptr, retdest + %mpt_hash(encode_account) + +%macro mpt_hash_state_trie + PUSH %%after + %jump(mpt_hash_state_trie) +%%after: +%endmacro + +global mpt_hash_txn_trie: + // stack: retdest + %mload_global_metadata(@GLOBAL_METADATA_TXN_TRIE_ROOT) + // stack: node_ptr, retdest + %mpt_hash(encode_txn) + +%macro mpt_hash_txn_trie + PUSH %%after + %jump(mpt_hash_txn_trie) +%%after: +%endmacro + +global mpt_hash_receipt_trie: + // stack: retdest + %mload_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_ROOT) + // stack: node_ptr, retdest + %mpt_hash(encode_receipt) + +%macro mpt_hash_receipt_trie + PUSH %%after + %jump(mpt_hash_receipt_trie) +%%after: +%endmacro + +encode_account: + // stack: rlp_pos, value_ptr, retdest + // First, we compute the length of the RLP data we're about to write. + // The nonce and balance fields are variable-length, so we need to load them + // to determine their contribution, while the other two fields are fixed + // 32-bytes integers. + DUP2 %mload_trie_data // nonce = value[0] + %scalar_rlp_len + // stack: nonce_rlp_len, rlp_pos, value_ptr, retdest + DUP3 %add_const(1) %mload_trie_data // balance = value[1] + %scalar_rlp_len + // stack: balance_rlp_lenm, nonce_rlp_len, rlp_pos, value_ptr, retdest + PUSH 66 // storage_root and code_hash fields each take 1 + 32 bytes + ADD ADD + // stack: payload_len, rlp_pos, value_ptr, retdest + SWAP1 + %encode_rlp_list_prefix + // stack: rlp_pos', value_ptr, retdest + DUP2 %mload_trie_data // nonce = value[0] + // stack: nonce, rlp_pos', value_ptr, retdest + SWAP1 %encode_rlp_scalar + // stack: rlp_pos'', value_ptr, retdest + DUP2 %add_const(1) %mload_trie_data // balance = value[1] + // stack: balance, rlp_pos'', value_ptr, retdest + SWAP1 %encode_rlp_scalar + // stack: rlp_pos''', value_ptr, retdest + DUP2 %add_const(2) %mload_trie_data // storage_root = value[2] + // stack: storage_root, rlp_pos''', value_ptr, retdest + SWAP1 %encode_rlp_256 + // stack: rlp_pos'''', value_ptr, retdest + SWAP1 %add_const(3) %mload_trie_data // code_hash = value[3] + // stack: code_hash, rlp_pos'''', retdest + SWAP1 %encode_rlp_256 + // stack: rlp_pos''''', retdest + SWAP1 + JUMP + +encode_txn: + PANIC // TODO + +encode_receipt: + PANIC // TODO diff --git a/evm/src/cpu/kernel/asm/mpt/read.asm b/evm/src/cpu/kernel/asm/mpt/read.asm index 934b6bbf..aec0c776 100644 --- a/evm/src/cpu/kernel/asm/mpt/read.asm +++ b/evm/src/cpu/kernel/asm/mpt/read.asm @@ -1,3 +1,22 @@ +// Given an address, return a pointer to the associated account data, which +// consists of four words (nonce, balance, storage_root, code_hash), in the +// state trie. Returns 0 if the address is not found. +global mpt_read_state_trie: + // stack: addr, retdest + // The key is the hash of the address. Since KECCAK_GENERAL takes input from + // memory, we will write addr bytes to SEGMENT_KERNEL_GENERAL[0..20] first. + %stack (addr) -> (0, @SEGMENT_KERNEL_GENERAL, 0, addr, 20, mpt_read_state_trie_after_mstore) + %jump(mstore_unpacking) +mpt_read_state_trie_after_mstore: + // stack: retdest + %stack () -> (0, @SEGMENT_KERNEL_GENERAL, 0, 20) // context, segment, offset, len + KECCAK_GENERAL + // stack: key, retdest + PUSH 64 // num_nibbles + %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) // node_ptr + // stack: node_ptr, num_nibbles, key, retdest + %jump(mpt_read) + // Read a value from a MPT. // // Arguments: @@ -6,7 +25,6 @@ // - the number of nibbles in the key (should start at 64) // // This function returns a pointer to the leaf, or 0 if the key is not found. - global mpt_read: // stack: node_ptr, num_nibbles, key, retdest DUP1 diff --git a/evm/src/cpu/kernel/asm/mpt/write.asm b/evm/src/cpu/kernel/asm/mpt/write.asm index be593a97..5b59d016 100644 --- a/evm/src/cpu/kernel/asm/mpt/write.asm +++ b/evm/src/cpu/kernel/asm/mpt/write.asm @@ -1,2 +1,3 @@ global mpt_write: + // stack: node_ptr, num_nibbles, key, retdest // TODO diff --git a/evm/src/cpu/kernel/global_metadata.rs b/evm/src/cpu/kernel/global_metadata.rs index ddc3c839..f3f34e7a 100644 --- a/evm/src/cpu/kernel/global_metadata.rs +++ b/evm/src/cpu/kernel/global_metadata.rs @@ -24,13 +24,13 @@ pub(crate) enum GlobalMetadata { // The root digests of each Merkle trie before these transactions. StateTrieRootDigestBefore = 8, - TransactionsTrieRootDigestBefore = 9, - ReceiptsTrieRootDigestBefore = 10, + TransactionTrieRootDigestBefore = 9, + ReceiptTrieRootDigestBefore = 10, // The root digests of each Merkle trie after these transactions. StateTrieRootDigestAfter = 11, - TransactionsTrieRootDigestAfter = 12, - ReceiptsTrieRootDigestAfter = 13, + TransactionTrieRootDigestAfter = 12, + ReceiptTrieRootDigestAfter = 13, } impl GlobalMetadata { @@ -47,11 +47,11 @@ impl GlobalMetadata { Self::ReceiptTrieRoot, Self::NumStorageTries, Self::StateTrieRootDigestBefore, - Self::TransactionsTrieRootDigestBefore, - Self::ReceiptsTrieRootDigestBefore, + Self::TransactionTrieRootDigestBefore, + Self::ReceiptTrieRootDigestBefore, Self::StateTrieRootDigestAfter, - Self::TransactionsTrieRootDigestAfter, - Self::ReceiptsTrieRootDigestAfter, + Self::TransactionTrieRootDigestAfter, + Self::ReceiptTrieRootDigestAfter, ] } @@ -67,18 +67,18 @@ impl GlobalMetadata { GlobalMetadata::ReceiptTrieRoot => "GLOBAL_METADATA_RECEIPT_TRIE_ROOT", GlobalMetadata::NumStorageTries => "GLOBAL_METADATA_NUM_STORAGE_TRIES", GlobalMetadata::StateTrieRootDigestBefore => "GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE", - GlobalMetadata::TransactionsTrieRootDigestBefore => { - "GLOBAL_METADATA_TXNS_TRIE_DIGEST_BEFORE" + GlobalMetadata::TransactionTrieRootDigestBefore => { + "GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE" } - GlobalMetadata::ReceiptsTrieRootDigestBefore => { - "GLOBAL_METADATA_RECEIPTS_TRIE_DIGEST_BEFORE" + GlobalMetadata::ReceiptTrieRootDigestBefore => { + "GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_BEFORE" } GlobalMetadata::StateTrieRootDigestAfter => "GLOBAL_METADATA_STATE_TRIE_DIGEST_AFTER", - GlobalMetadata::TransactionsTrieRootDigestAfter => { - "GLOBAL_METADATA_TXNS_TRIE_DIGEST_AFTER" + GlobalMetadata::TransactionTrieRootDigestAfter => { + "GLOBAL_METADATA_TXN_TRIE_DIGEST_AFTER" } - GlobalMetadata::ReceiptsTrieRootDigestAfter => { - "GLOBAL_METADATA_RECEIPTS_TRIE_DIGEST_AFTER" + GlobalMetadata::ReceiptTrieRootDigestAfter => { + "GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_AFTER" } } } diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index a24f44d5..11fbd879 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -89,18 +89,16 @@ pub(crate) fn generate_traces, const D: usize>( let trie_roots_before = TrieRoots { state_root: H256::from_uint(&read_metadata(GlobalMetadata::StateTrieRootDigestBefore)), transactions_root: H256::from_uint(&read_metadata( - GlobalMetadata::TransactionsTrieRootDigestBefore, - )), - receipts_root: H256::from_uint(&read_metadata( - GlobalMetadata::ReceiptsTrieRootDigestBefore, + GlobalMetadata::TransactionTrieRootDigestBefore, )), + receipts_root: H256::from_uint(&read_metadata(GlobalMetadata::ReceiptTrieRootDigestBefore)), }; let trie_roots_after = TrieRoots { state_root: H256::from_uint(&read_metadata(GlobalMetadata::StateTrieRootDigestAfter)), transactions_root: H256::from_uint(&read_metadata( - GlobalMetadata::TransactionsTrieRootDigestAfter, + GlobalMetadata::TransactionTrieRootDigestAfter, )), - receipts_root: H256::from_uint(&read_metadata(GlobalMetadata::ReceiptsTrieRootDigestAfter)), + receipts_root: H256::from_uint(&read_metadata(GlobalMetadata::ReceiptTrieRootDigestAfter)), }; let GenerationState { diff --git a/evm/tests/empty_txn_list.rs b/evm/tests/empty_txn_list.rs index a9c71026..6e16fa47 100644 --- a/evm/tests/empty_txn_list.rs +++ b/evm/tests/empty_txn_list.rs @@ -17,7 +17,7 @@ type C = PoseidonGoldilocksConfig; /// Execute the empty list of transactions, i.e. a no-op. #[test] -#[ignore] // TODO: Won't work until storage, etc. are implemented. +#[ignore] // TODO: Won't work until witness generation logic is finished. fn test_empty_txn_list() -> anyhow::Result<()> { let all_stark = AllStark::::default(); let config = StarkConfig::standard_fast_config(); From 0de392b3358ae0bb70a3256240c9ecb406600d02 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 2 Oct 2022 11:41:44 -0700 Subject: [PATCH 2/2] Fix optimization --- evm/src/cpu/kernel/optimizer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/optimizer.rs b/evm/src/cpu/kernel/optimizer.rs index e23bf520..e2504203 100644 --- a/evm/src/cpu/kernel/optimizer.rs +++ b/evm/src/cpu/kernel/optimizer.rs @@ -80,9 +80,9 @@ fn no_op_jumps(code: &mut Vec) { replace_windows(code, |window| { if let [Push(Label(l)), StandardOp(jump), decl] = window && &jump == "JUMP" - && (decl == LocalLabelDeclaration(l.clone()) || decl == GlobalLabelDeclaration(l.clone())) + && (decl == LocalLabelDeclaration(l.clone()) || decl == GlobalLabelDeclaration(l)) { - Some(vec![LocalLabelDeclaration(l)]) + Some(vec![decl]) } else { None }