mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-09 09:13:09 +00:00
* Start * Scale TxnFields * Speed-up * Misc fixes * Other fixes * Fix * Fix offset * One more fix * And one more fix * Fix * Fix * Fix init * More interpreter fixes * Final fixes * Add helper methods * Clippy * Apply suggestions * Comments * Update documentation * Regenerate pdf * minor * Rename some macros for consistency * Add utility method for unscaling segments and scaled metadata * Address comments
339 lines
13 KiB
Rust
339 lines
13 KiB
Rust
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::cpu::kernel::tests::account_code::initialize_mpts;
|
|
use crate::generation::mpt::{AccountRlp, LegacyReceiptRlp};
|
|
use crate::generation::rlp::all_rlp_prover_inputs_reversed;
|
|
use crate::generation::TrieInputs;
|
|
use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR};
|
|
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>>,
|
|
) {
|
|
initialize_mpts(interpreter, &trie_inputs);
|
|
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.set_context_metadata_field(0, ContextMetadata::GasLimit, 1_000_000.into());
|
|
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.set_context_metadata_field(0, ContextMetadata::GasLimit, 1_000_000.into());
|
|
interpreter.set_is_kernel(true);
|
|
interpreter
|
|
.run()
|
|
.expect("Proving add11 with exception failed.");
|
|
}
|