Skip to content
This repository has been archived by the owner on Feb 21, 2024. It is now read-only.

Commit

Permalink
Changes in interpreter and implement interpreter version for add11 (0…
Browse files Browse the repository at this point in the history
…xPolygonZero#1359)

* Fix interpreter, turn syscall opcodes into actual syscalls, create interpreter test for add11

* Rename test_add11 to test_add11_yml

* Apply comments

* Cleanup add11_yml interpreter test

* Make stack_top() return a Result, and remove Result from add11_yml test

* Apply comment
  • Loading branch information
LindaGuiga authored Nov 28, 2023
1 parent 6dd2e31 commit 96f3faf
Show file tree
Hide file tree
Showing 6 changed files with 504 additions and 528 deletions.
718 changes: 231 additions & 487 deletions evm/src/cpu/kernel/interpreter.rs

Large diffs are not rendered by default.

58 changes: 40 additions & 18 deletions evm/src/cpu/kernel/tests/account_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::cpu::kernel::tests::mpt::nibbles_64;
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp};
use crate::generation::TrieInputs;
use crate::memory::segments::Segment;
use crate::witness::memory::MemoryAddress;
use crate::Node;

// Test account with a given code hash.
Expand Down Expand Up @@ -146,19 +147,20 @@ fn test_extcodecopy() -> Result<()> {
// Prepare the interpreter by inserting the account in the state trie.
prepare_interpreter(&mut interpreter, address, &account)?;

interpreter.generation_state.memory.contexts[interpreter.context].segments
let context = interpreter.context();
interpreter.generation_state.memory.contexts[context].segments
[Segment::ContextMetadata as usize]
.set(GasLimit as usize, U256::from(1000000000000u64) << 192);
.set(GasLimit as usize, U256::from(1000000000000u64));

let extcodecopy = KERNEL.global_labels["sys_extcodecopy"];

// Put random data in main memory and the `KernelAccountCode` segment for realism.
let mut rng = thread_rng();
for i in 0..2000 {
interpreter.generation_state.memory.contexts[interpreter.context].segments
interpreter.generation_state.memory.contexts[context].segments
[Segment::MainMemory as usize]
.set(i, U256::from(rng.gen::<u8>()));
interpreter.generation_state.memory.contexts[interpreter.context].segments
interpreter.generation_state.memory.contexts[context].segments
[Segment::KernelAccountCode as usize]
.set(i, U256::from(rng.gen::<u8>()));
}
Expand All @@ -176,15 +178,15 @@ fn test_extcodecopy() -> Result<()> {
interpreter.push(offset.into());
interpreter.push(dest_offset.into());
interpreter.push(U256::from_big_endian(address.as_bytes()));
interpreter.push(0xDEADBEEFu32.into()); // kexit_info
interpreter.push((0xDEADBEEFu64 + (1 << 32)).into()); // kexit_info
interpreter.generation_state.inputs.contract_code =
HashMap::from([(keccak(&code), code.clone())]);
interpreter.run()?;

assert!(interpreter.stack().is_empty());
// Check that the code was correctly copied to memory.
for i in 0..size {
let memory = interpreter.generation_state.memory.contexts[interpreter.context].segments
let memory = interpreter.generation_state.memory.contexts[context].segments
[Segment::MainMemory as usize]
.get(dest_offset + i);
assert_eq!(
Expand Down Expand Up @@ -226,10 +228,24 @@ fn prepare_interpreter_all_accounts(
);
interpreter.generation_state.memory.contexts[1].segments[Segment::ContextMetadata as usize]
.set(ContextMetadata::GasLimit as usize, 100_000.into());
interpreter.context = 1;
interpreter.generation_state.registers.context = 1;
interpreter.generation_state.registers.is_kernel = false;
interpreter.kernel_mode = false;
interpreter.set_context(1);
interpreter.set_is_kernel(false);
interpreter.generation_state.memory.set(
MemoryAddress::new(
1,
Segment::ContextMetadata,
ContextMetadata::ParentProgramCounter as usize,
),
0xdeadbeefu32.into(),
);
interpreter.generation_state.memory.set(
MemoryAddress::new(
1,
Segment::ContextMetadata,
ContextMetadata::ParentContext as usize,
),
1.into(),
);

Ok(())
}
Expand Down Expand Up @@ -272,6 +288,11 @@ fn sstore() -> Result<()> {

interpreter.run()?;

// The first two elements in the stack are `success` and `leftover_gas`,
// returned by the `sys_stop` opcode.
interpreter.pop();
interpreter.pop();

// The code should have added an element to the storage of `to_account`. We run
// `mpt_hash_state_trie` to check that.
let account_after = AccountRlp {
Expand All @@ -287,10 +308,8 @@ fn sstore() -> Result<()> {
// Now, execute mpt_hash_state_trie.
let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"];
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
interpreter.context = 0;
interpreter.generation_state.registers.context = 0;
interpreter.generation_state.registers.is_kernel = true;
interpreter.kernel_mode = true;
interpreter.set_is_kernel(true);
interpreter.set_context(0);
interpreter.push(0xDEADBEEFu32.into());
interpreter.run()?;

Expand Down Expand Up @@ -353,6 +372,11 @@ fn sload() -> Result<()> {

interpreter.run()?;

// The first two elements in the stack are `success` and `leftover_gas`,
// returned by the `sys_stop` opcode.
interpreter.pop();
interpreter.pop();

// 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.
Expand All @@ -362,10 +386,8 @@ fn sload() -> Result<()> {
// 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.context = 0;
interpreter.generation_state.registers.context = 0;
interpreter.generation_state.registers.is_kernel = true;
interpreter.kernel_mode = true;
interpreter.set_is_kernel(true);
interpreter.set_context(0);
interpreter.push(0xDEADBEEFu32.into());
interpreter.run()?;

Expand Down
212 changes: 212 additions & 0 deletions evm/src/cpu/kernel/tests/add11.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
use std::collections::HashMap;
use std::str::FromStr;

use anyhow::{anyhow, Result};
use eth_trie_utils::nibbles::Nibbles;
use eth_trie_utils::partial_trie::{HashedPartialTrie, Node, PartialTrie};
use ethereum_types::{Address, H256, U256};
use hex_literal::hex;
use keccak_hash::keccak;

use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::constants::context_metadata::ContextMetadata;
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
use crate::cpu::kernel::interpreter::Interpreter;
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp, LegacyReceiptRlp};
use crate::generation::rlp::all_rlp_prover_inputs_reversed;
use crate::generation::TrieInputs;
use crate::memory::segments::Segment;
use crate::proof::TrieRoots;
use crate::util::h2u;

// Stolen from `tests/mpt/insert.rs`
// Prepare the interpreter by loading the initial MPTs and
// by setting all `GlobalMetadata` and necessary code into memory.
fn prepare_interpreter(
interpreter: &mut Interpreter,
trie_inputs: TrieInputs,
transaction: &[u8],
contract_code: HashMap<H256, Vec<u8>>,
) {
let load_all_mpts = KERNEL.global_labels["load_all_mpts"];

interpreter.generation_state.registers.program_counter = load_all_mpts;
interpreter.push(0xDEADBEEFu32.into());

interpreter.generation_state.mpt_prover_inputs =
all_mpt_prover_inputs_reversed(&trie_inputs).expect("Invalid MPT data.");
interpreter.run().expect("MPT loading failed.");
assert_eq!(interpreter.stack(), vec![]);

// Set necessary `GlobalMetadata`.
let global_metadata_to_set = [
(
GlobalMetadata::StateTrieRootDigestBefore,
h2u(trie_inputs.state_trie.hash()),
),
(
GlobalMetadata::TransactionTrieRootDigestBefore,
h2u(trie_inputs.transactions_trie.hash()),
),
(
GlobalMetadata::ReceiptTrieRootDigestBefore,
h2u(trie_inputs.receipts_trie.hash()),
),
(GlobalMetadata::TxnNumberAfter, 1.into()),
(GlobalMetadata::BlockGasUsedAfter, 0xa868u64.into()),
(GlobalMetadata::BlockGasLimit, 1_000_000.into()),
(GlobalMetadata::BlockBaseFee, 10.into()),
(
GlobalMetadata::BlockBeneficiary,
U256::from_big_endian(
&Address::from(hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba")).0,
),
),
];

interpreter.set_global_metadata_multi_fields(&global_metadata_to_set);

// Set contract code and transaction.
interpreter.generation_state.inputs.contract_code = contract_code;

interpreter.generation_state.inputs.signed_txn = Some(transaction.to_vec());
let rlp_prover_inputs = all_rlp_prover_inputs_reversed(transaction);
interpreter.generation_state.rlp_prover_inputs = rlp_prover_inputs;
}

#[test]
fn test_add11_yml() {
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, 0x60, 0x00, 0x55, 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 initial_stack = vec![];
let mut interpreter = Interpreter::new_with_kernel(0, initial_stack);

prepare_interpreter(&mut interpreter, tries_before.clone(), &txn, contract_code);
let expected_state_trie_after = {
let beneficiary_account_after = AccountRlp {
nonce: 1.into(),
..AccountRlp::default()
};
let sender_account_after = AccountRlp {
balance: 0xde0b6b3a75be550u64.into(),
nonce: 1.into(),
..AccountRlp::default()
};
let to_account_after = AccountRlp {
balance: 0xde0b6b3a76586a0u64.into(),
code_hash,
// Storage map: { 0 => 2 }
storage_root: HashedPartialTrie::from(Node::Leaf {
nibbles: Nibbles::from_h256_be(keccak([0u8; 32])),
value: vec![2],
})
.hash(),
..AccountRlp::default()
};

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: true,
cum_gas_used: 0xa868u64.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),
),
];
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 failed.");
}
Loading

0 comments on commit 96f3faf

Please sign in to comment.