Skip to content

Commit

Permalink
Merge branch 'main' into filter-range-checks
Browse files Browse the repository at this point in the history
  • Loading branch information
LindaGuiga committed Dec 18, 2023
2 parents 0f37442 + f67ee25 commit 4d84d26
Show file tree
Hide file tree
Showing 9 changed files with 848 additions and 347 deletions.
833 changes: 548 additions & 285 deletions evm/src/cpu/kernel/interpreter.rs

Large diffs are not rendered by default.

89 changes: 64 additions & 25 deletions evm/src/cpu/kernel/tests/account_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,15 @@ fn prepare_interpreter(
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.try_into_u256().unwrap()); // key
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(value_ptr.into())
.expect("The stack should not overflow"); // value_ptr
interpreter
.push(k.try_into_u256().unwrap())
.expect("The stack should not overflow"); // key

interpreter.run()?;
assert_eq!(
Expand All @@ -129,8 +135,12 @@ fn prepare_interpreter(

// Now, execute mpt_hash_state_trie.
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
interpreter.push(0xDEADBEEFu32.into());
interpreter.push(1.into()); // Initial length of the trie data segment, unused.
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(1.into()) // Initial length of the trie data segment, unused.
.expect("The stack should not overflow");
interpreter.run()?;

assert_eq!(
Expand Down Expand Up @@ -162,11 +172,15 @@ fn test_extcodesize() -> Result<()> {

// Test `extcodesize`
interpreter.generation_state.registers.program_counter = extcodesize;
interpreter.pop();
interpreter.pop();
interpreter.pop().expect("The stack should not be empty");
interpreter.pop().expect("The stack should not be empty");
assert!(interpreter.stack().is_empty());
interpreter.push(0xDEADBEEFu32.into());
interpreter.push(U256::from_big_endian(address.as_bytes()));
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(U256::from_big_endian(address.as_bytes()))
.expect("The stack should not overflow");
interpreter.generation_state.inputs.contract_code =
HashMap::from([(keccak(&code), code.clone())]);
interpreter.run()?;
Expand Down Expand Up @@ -211,14 +225,24 @@ fn test_extcodecopy() -> Result<()> {

// Test `extcodecopy`
interpreter.generation_state.registers.program_counter = extcodecopy;
interpreter.pop();
interpreter.pop();
interpreter.pop().expect("The stack should not be empty");
interpreter.pop().expect("The stack should not be empty");
assert!(interpreter.stack().is_empty());
interpreter.push(size.into());
interpreter.push(offset.into());
interpreter.push(dest_offset.into());
interpreter.push(U256::from_big_endian(address.as_bytes()));
interpreter.push((0xDEADBEEFu64 + (1 << 32)).into()); // kexit_info
interpreter
.push(size.into())
.expect("The stack should not overflow");
interpreter
.push(offset.into())
.expect("The stack should not overflow");
interpreter
.push(dest_offset.into())
.expect("The stack should not overflow");
interpreter
.push(U256::from_big_endian(address.as_bytes()))
.expect("The stack should not overflow");
interpreter
.push((0xDEADBEEFu64 + (1 << 32)).into())
.expect("The stack should not overflow"); // kexit_info
interpreter.generation_state.inputs.contract_code =
HashMap::from([(keccak(&code), code.clone())]);
interpreter.run()?;
Expand Down Expand Up @@ -342,8 +366,12 @@ fn sstore() -> Result<()> {
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
interpreter.set_is_kernel(true);
interpreter.set_context(0);
interpreter.push(0xDEADBEEFu32.into());
interpreter.push(1.into()); // Initia length of the trie data segment, unused.
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(1.into()) // Initial length of the trie data segment, unused.
.expect("The stack should not overflow");
interpreter.run()?;

assert_eq!(
Expand Down Expand Up @@ -402,27 +430,38 @@ fn sload() -> Result<()> {

// Prepare the interpreter by inserting the account in the state trie.
prepare_interpreter_all_accounts(&mut interpreter, trie_inputs, addr, &code)?;

interpreter.run()?;

// The first two elements in the stack are `success` and `leftover_gas`,
// returned by the `sys_stop` opcode.
interpreter.pop();
interpreter.pop();
interpreter
.pop()
.expect("The stack length should not be empty.");
interpreter
.pop()
.expect("The stack length should not be empty.");

// The SLOAD in the provided code should return 0, since
// the storage trie is empty. The last step in the code
// pushes the value 3.
assert_eq!(interpreter.stack(), vec![0x0.into(), 0x3.into()]);
interpreter.pop();
interpreter.pop();
interpreter
.pop()
.expect("The stack length should not be empty.");
interpreter
.pop()
.expect("The stack length should not be empty.");
// Now, execute mpt_hash_state_trie. We check that the state trie has not changed.
let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"];
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
interpreter.set_is_kernel(true);
interpreter.set_context(0);
interpreter.push(0xDEADBEEFu32.into());
interpreter.push(1.into()); // Initia length of the trie data segment, unused.
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow.");
interpreter
.push(1.into()) // Initial length of the trie data segment, unused.
.expect("The stack should not overflow.");
interpreter.run()?;

assert_eq!(
Expand Down
134 changes: 134 additions & 0 deletions evm/src/cpu/kernel/tests/add11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,137 @@ fn test_add11_yml() {
interpreter.set_is_kernel(true);
interpreter.run().expect("Proving add11 failed.");
}

#[test]
fn test_add11_yml_with_exception() {
// In this test, we make sure that the user code throws a stack underflow exception.
let beneficiary = hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba");
let sender = hex!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b");
let to = hex!("095e7baea6a6c7c4c2dfeb977efac326af552d87");

let beneficiary_state_key = keccak(beneficiary);
let sender_state_key = keccak(sender);
let to_hashed = keccak(to);

let beneficiary_nibbles = Nibbles::from_bytes_be(beneficiary_state_key.as_bytes()).unwrap();
let sender_nibbles = Nibbles::from_bytes_be(sender_state_key.as_bytes()).unwrap();
let to_nibbles = Nibbles::from_bytes_be(to_hashed.as_bytes()).unwrap();

let code = [0x60, 0x01, 0x60, 0x01, 0x01, 0x8e, 0x00];
let code_hash = keccak(code);

let mut contract_code = HashMap::new();
contract_code.insert(keccak(vec![]), vec![]);
contract_code.insert(code_hash, code.to_vec());

let beneficiary_account_before = AccountRlp {
nonce: 1.into(),
..AccountRlp::default()
};
let sender_account_before = AccountRlp {
balance: 0x0de0b6b3a7640000u64.into(),
..AccountRlp::default()
};
let to_account_before = AccountRlp {
balance: 0x0de0b6b3a7640000u64.into(),
code_hash,
..AccountRlp::default()
};

let mut state_trie_before = HashedPartialTrie::from(Node::Empty);
state_trie_before.insert(
beneficiary_nibbles,
rlp::encode(&beneficiary_account_before).to_vec(),
);
state_trie_before.insert(sender_nibbles, rlp::encode(&sender_account_before).to_vec());
state_trie_before.insert(to_nibbles, rlp::encode(&to_account_before).to_vec());

let tries_before = TrieInputs {
state_trie: state_trie_before,
transactions_trie: Node::Empty.into(),
receipts_trie: Node::Empty.into(),
storage_tries: vec![(to_hashed, Node::Empty.into())],
};

let txn = hex!("f863800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffb600e63115a7362e7811894a91d8ba4330e526f22121c994c4692035dfdfd5a06198379fcac8de3dbfac48b165df4bf88e2088f294b61efb9a65fe2281c76e16");
let txn_gas_limit = 400_000;
let gas_price = 10;

let initial_stack = vec![];
let mut interpreter = Interpreter::new_with_kernel(0, initial_stack);

prepare_interpreter(&mut interpreter, tries_before.clone(), &txn, contract_code);
// Here, since the transaction fails, it consumes its gas limit, and does nothing else.
let expected_state_trie_after = {
let beneficiary_account_after = beneficiary_account_before;
// This is the only account that changes: the nonce and the balance are updated.
let sender_account_after = AccountRlp {
balance: sender_account_before.balance - txn_gas_limit * gas_price,
nonce: 1.into(),
..AccountRlp::default()
};
let to_account_after = to_account_before;

let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty);
expected_state_trie_after.insert(
beneficiary_nibbles,
rlp::encode(&beneficiary_account_after).to_vec(),
);
expected_state_trie_after
.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec());
expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec());
expected_state_trie_after
};

let receipt_0 = LegacyReceiptRlp {
status: false,
cum_gas_used: txn_gas_limit.into(),
bloom: vec![0; 256].into(),
logs: vec![],
};
let mut receipts_trie = HashedPartialTrie::from(Node::Empty);
receipts_trie.insert(
Nibbles::from_str("0x80").unwrap(),
rlp::encode(&receipt_0).to_vec(),
);
let transactions_trie: HashedPartialTrie = Node::Leaf {
nibbles: Nibbles::from_str("0x80").unwrap(),
value: txn.to_vec(),
}
.into();

let trie_roots_after = TrieRoots {
state_root: expected_state_trie_after.hash(),
transactions_root: transactions_trie.hash(),
receipts_root: receipts_trie.hash(),
};

// Set trie roots after the transaction was executed.
let metadata_to_set = [
(
GlobalMetadata::StateTrieRootDigestAfter,
h2u(trie_roots_after.state_root),
),
(
GlobalMetadata::TransactionTrieRootDigestAfter,
h2u(trie_roots_after.transactions_root),
),
(
GlobalMetadata::ReceiptTrieRootDigestAfter,
h2u(trie_roots_after.receipts_root),
),
// The gas used in this case is the transaction gas limit
(GlobalMetadata::BlockGasUsedAfter, txn_gas_limit.into()),
];
interpreter.set_global_metadata_multi_fields(&metadata_to_set);

let route_txn_label = KERNEL.global_labels["hash_initial_tries"];
// Switch context and initialize memory with the data we need for the tests.
interpreter.generation_state.registers.program_counter = route_txn_label;
interpreter.generation_state.memory.contexts[0].segments[Segment::ContextMetadata as usize]
.set(ContextMetadata::GasLimit as usize, 1_000_000.into());
interpreter.set_is_kernel(true);
interpreter
.run()
.expect("Proving add11 with exception failed.");
}
32 changes: 23 additions & 9 deletions evm/src/cpu/kernel/tests/balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,15 @@ fn prepare_interpreter(
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.try_into_u256().unwrap()); // key
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(value_ptr.into())
.expect("The stack should not overflow"); // value_ptr
interpreter
.push(k.try_into_u256().unwrap())
.expect("The stack should not overflow"); // key

interpreter.run()?;
assert_eq!(
Expand All @@ -72,8 +78,12 @@ fn prepare_interpreter(

// Now, execute mpt_hash_state_trie.
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
interpreter.push(0xDEADBEEFu32.into());
interpreter.push(1.into()); // Initial trie data segment size, unused.
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(1.into()) // Initial trie data segment size, unused.
.expect("The stack should not overflow");
interpreter.run()?;

assert_eq!(
Expand Down Expand Up @@ -104,11 +114,15 @@ fn test_balance() -> Result<()> {

// Test `balance`
interpreter.generation_state.registers.program_counter = KERNEL.global_labels["balance"];
interpreter.pop();
interpreter.pop();
interpreter.pop().expect("The stack should not be empty");
interpreter.pop().expect("The stack should not be empty");
assert!(interpreter.stack().is_empty());
interpreter.push(0xDEADBEEFu32.into());
interpreter.push(U256::from_big_endian(address.as_bytes()));
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(U256::from_big_endian(address.as_bytes()))
.expect("The stack should not overflow");
interpreter.run()?;

assert_eq!(interpreter.stack(), vec![balance]);
Expand Down
Loading

0 comments on commit 4d84d26

Please sign in to comment.