diff --git a/evm/src/cpu/kernel/asm/mpt/delete/delete_branch.asm b/evm/src/cpu/kernel/asm/mpt/delete/delete_branch.asm index 69c97943..775e4e11 100644 --- a/evm/src/cpu/kernel/asm/mpt/delete/delete_branch.asm +++ b/evm/src/cpu/kernel/asm/mpt/delete/delete_branch.asm @@ -77,14 +77,16 @@ loop_end: // stack: i, updated_child_ptr, first_nibble, node_payload_ptr, retdest DUP4 ADD %mload_trie_data // stack: only_child_ptr, updated_child_ptr, first_nibble, node_payload_ptr, retdest - DUP1 %mload_trie_data %eq_const(@MPT_NODE_BRANCH) %jumpi(maybe_normalize_branch_branch) + DUP1 %mload_trie_data %eq_const(@MPT_NODE_BRANCH) %jumpi(maybe_normalize_branch_branchhash) + DUP1 %mload_trie_data %eq_const(@MPT_NODE_HASH) %jumpi(maybe_normalize_branch_branchhash) DUP1 %mload_trie_data %eq_const(@MPT_NODE_EXTENSION) %jumpi(maybe_normalize_branch_leafext) DUP1 %mload_trie_data %eq_const(@MPT_NODE_LEAF) %jumpi(maybe_normalize_branch_leafext) PANIC // This should never happen. -// The only child of the branch node is a branch node. +// The only child of the branch node is a branch node or a hash node. // Transform the branch node into an extension node of length 1. -maybe_normalize_branch_branch: +// This assumes that the hash node does not contain a leaf or an extension node (in which case this implementation is incorrect). +maybe_normalize_branch_branchhash: // stack: only_child_ptr, updated_child_ptr, first_nibble, node_payload_ptr, retdest %get_trie_data_size // pointer to the extension node we're about to create // stack: extension_ptr, only_child_ptr, updated_child_ptr, first_nibble, node_payload_ptr, retdest diff --git a/evm/src/cpu/kernel/tests/mpt/delete.rs b/evm/src/cpu/kernel/tests/mpt/delete.rs index 42e8caf9..074eea26 100644 --- a/evm/src/cpu/kernel/tests/mpt/delete.rs +++ b/evm/src/cpu/kernel/tests/mpt/delete.rs @@ -36,6 +36,17 @@ fn mpt_delete_leaf_overlapping_keys() -> Result<()> { test_state_trie(state_trie, nibbles_64(0xADE), test_account_2()) } +#[test] +fn mpt_delete_branch_into_hash() -> Result<()> { + let hash = Node::Hash(H256::random()); + let state_trie = Node::Extension { + nibbles: nibbles_64(0xADF), + child: hash.into(), + } + .into(); + test_state_trie(state_trie, nibbles_64(0xADE), test_account_2()) +} + /// Note: The account's storage_root is ignored, as we can't insert a new storage_root without the /// accompanying trie data. An empty trie's storage_root is used instead. fn test_state_trie(