mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 06:43:07 +00:00
Remove logic for multiple txns at once (#1341)
* Have prover take only a single txn at most * Update comment * Apply review
This commit is contained in:
parent
5d5628b59d
commit
954d1a77c6
@ -452,22 +452,22 @@ global invalid_txn:
|
||||
POP
|
||||
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
|
||||
PUSH 0
|
||||
%jump(txn_loop_after)
|
||||
%jump(txn_after)
|
||||
|
||||
global invalid_txn_1:
|
||||
%pop2
|
||||
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
|
||||
PUSH 0
|
||||
%jump(txn_loop_after)
|
||||
%jump(txn_after)
|
||||
|
||||
global invalid_txn_2:
|
||||
%pop3
|
||||
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
|
||||
PUSH 0
|
||||
%jump(txn_loop_after)
|
||||
%jump(txn_after)
|
||||
|
||||
global invalid_txn_3:
|
||||
%pop4
|
||||
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
|
||||
PUSH 0
|
||||
%jump(txn_loop_after)
|
||||
%jump(txn_after)
|
||||
|
||||
@ -14,7 +14,7 @@ global hash_initial_tries:
|
||||
%mpt_hash_txn_trie %mload_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE) %assert_eq
|
||||
%mpt_hash_receipt_trie %mload_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_BEFORE) %assert_eq
|
||||
|
||||
global start_txns:
|
||||
global start_txn:
|
||||
// stack: (empty)
|
||||
// The special case of an empty trie (i.e. for the first transaction)
|
||||
// is handled outside of the kernel.
|
||||
@ -29,24 +29,22 @@ global start_txns:
|
||||
SWAP2
|
||||
// stack: init_gas_used, txn_counter, num_nibbles, txn_nb
|
||||
|
||||
txn_loop:
|
||||
// If the prover has no more txns for us to process, halt.
|
||||
PROVER_INPUT(end_of_txns)
|
||||
// If the prover has no txn for us to process, halt.
|
||||
PROVER_INPUT(no_txn)
|
||||
%jumpi(execute_withdrawals)
|
||||
|
||||
// Call route_txn. When we return, continue the txn loop.
|
||||
PUSH txn_loop_after
|
||||
// Call route_txn. When we return, we will process the txn receipt.
|
||||
PUSH txn_after
|
||||
// stack: retdest, prev_gas_used, txn_counter, num_nibbles, txn_nb
|
||||
DUP4 DUP4 %increment_bounded_rlp
|
||||
%stack (next_txn_counter, next_num_nibbles, retdest, prev_gas_used, txn_counter, num_nibbles) -> (txn_counter, num_nibbles, retdest, prev_gas_used, txn_counter, num_nibbles, next_txn_counter, next_num_nibbles)
|
||||
%jump(route_txn)
|
||||
|
||||
global txn_loop_after:
|
||||
global txn_after:
|
||||
// stack: success, leftover_gas, cur_cum_gas, prev_txn_counter, prev_num_nibbles, txn_counter, num_nibbles, txn_nb
|
||||
%process_receipt
|
||||
// stack: new_cum_gas, txn_counter, num_nibbles, txn_nb
|
||||
SWAP3 %increment SWAP3
|
||||
%jump(txn_loop)
|
||||
|
||||
global execute_withdrawals:
|
||||
// stack: cum_gas, txn_counter, num_nibbles, txn_nb
|
||||
|
||||
@ -46,7 +46,8 @@ pub struct GenerationInputs {
|
||||
pub gas_used_after: U256,
|
||||
pub block_bloom_after: [U256; 8],
|
||||
|
||||
pub signed_txns: Vec<Vec<u8>>,
|
||||
// A None would yield an empty proof, otherwise this contains the encoding of a transaction.
|
||||
pub signed_txn: Option<Vec<u8>>,
|
||||
// Withdrawal pairs `(addr, amount)`. At the end of the txs, `amount` is added to `addr`'s balance. See EIP-4895.
|
||||
pub withdrawals: Vec<(Address, U256)>,
|
||||
pub tries: TrieInputs,
|
||||
@ -122,7 +123,7 @@ fn apply_metadata_and_tries_memops<F: RichField + Extendable<D>, const D: usize>
|
||||
(GlobalMetadata::TxnNumberBefore, inputs.txn_number_before),
|
||||
(
|
||||
GlobalMetadata::TxnNumberAfter,
|
||||
inputs.txn_number_before + inputs.signed_txns.len(),
|
||||
inputs.txn_number_before + if inputs.signed_txn.is_some() { 1 } else { 0 },
|
||||
),
|
||||
(
|
||||
GlobalMetadata::StateTrieRootDigestBefore,
|
||||
|
||||
@ -35,7 +35,7 @@ impl From<Vec<String>> for ProverInputFn {
|
||||
impl<F: Field> GenerationState<F> {
|
||||
pub(crate) fn prover_input(&mut self, input_fn: &ProverInputFn) -> Result<U256, ProgramError> {
|
||||
match input_fn.0[0].as_str() {
|
||||
"end_of_txns" => self.run_end_of_txns(),
|
||||
"no_txn" => self.no_txn(),
|
||||
"ff" => self.run_ff(input_fn),
|
||||
"sf" => self.run_sf(input_fn),
|
||||
"ffe" => self.run_ffe(input_fn),
|
||||
@ -49,14 +49,8 @@ impl<F: Field> GenerationState<F> {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_end_of_txns(&mut self) -> Result<U256, ProgramError> {
|
||||
let end = self.next_txn_index == self.inputs.signed_txns.len();
|
||||
if end {
|
||||
Ok(U256::one())
|
||||
} else {
|
||||
self.next_txn_index += 1;
|
||||
Ok(U256::zero())
|
||||
}
|
||||
fn no_txn(&mut self) -> Result<U256, ProgramError> {
|
||||
Ok(U256::from(self.inputs.signed_txn.is_none() as u8))
|
||||
}
|
||||
|
||||
/// Finite field operations.
|
||||
|
||||
@ -1,18 +1,16 @@
|
||||
use ethereum_types::U256;
|
||||
|
||||
pub(crate) fn all_rlp_prover_inputs_reversed(signed_txns: &[Vec<u8>]) -> Vec<U256> {
|
||||
let mut inputs = all_rlp_prover_inputs(signed_txns);
|
||||
pub(crate) fn all_rlp_prover_inputs_reversed(signed_txn: &[u8]) -> Vec<U256> {
|
||||
let mut inputs = all_rlp_prover_inputs(signed_txn);
|
||||
inputs.reverse();
|
||||
inputs
|
||||
}
|
||||
|
||||
fn all_rlp_prover_inputs(signed_txns: &[Vec<u8>]) -> Vec<U256> {
|
||||
fn all_rlp_prover_inputs(signed_txn: &[u8]) -> Vec<U256> {
|
||||
let mut prover_inputs = vec![];
|
||||
for txn in signed_txns {
|
||||
prover_inputs.push(txn.len().into());
|
||||
for &byte in txn {
|
||||
prover_inputs.push(byte.into());
|
||||
}
|
||||
prover_inputs.push(signed_txn.len().into());
|
||||
for &byte in signed_txn {
|
||||
prover_inputs.push(byte.into());
|
||||
}
|
||||
prover_inputs
|
||||
}
|
||||
|
||||
@ -29,8 +29,6 @@ pub(crate) struct GenerationState<F: Field> {
|
||||
pub(crate) memory: MemoryState,
|
||||
pub(crate) traces: Traces<F>,
|
||||
|
||||
pub(crate) next_txn_index: usize,
|
||||
|
||||
/// Prover inputs containing MPT data, in reverse order so that the next input can be obtained
|
||||
/// via `pop()`.
|
||||
pub(crate) mpt_prover_inputs: Vec<U256>,
|
||||
@ -54,7 +52,7 @@ pub(crate) struct GenerationState<F: Field> {
|
||||
|
||||
impl<F: Field> GenerationState<F> {
|
||||
pub(crate) fn new(inputs: GenerationInputs, kernel_code: &[u8]) -> Result<Self, ProgramError> {
|
||||
log::debug!("Input signed_txns: {:?}", &inputs.signed_txns);
|
||||
log::debug!("Input signed_txn: {:?}", &inputs.signed_txn);
|
||||
log::debug!("Input state_trie: {:?}", &inputs.tries.state_trie);
|
||||
log::debug!(
|
||||
"Input transactions_trie: {:?}",
|
||||
@ -64,7 +62,8 @@ impl<F: Field> GenerationState<F> {
|
||||
log::debug!("Input storage_tries: {:?}", &inputs.tries.storage_tries);
|
||||
log::debug!("Input contract_code: {:?}", &inputs.contract_code);
|
||||
let mpt_prover_inputs = all_mpt_prover_inputs_reversed(&inputs.tries)?;
|
||||
let rlp_prover_inputs = all_rlp_prover_inputs_reversed(&inputs.signed_txns);
|
||||
let rlp_prover_inputs =
|
||||
all_rlp_prover_inputs_reversed(inputs.signed_txn.as_ref().unwrap_or(&vec![]));
|
||||
let withdrawal_prover_inputs = all_withdrawals_prover_inputs_reversed(&inputs.withdrawals);
|
||||
let bignum_modmul_result_limbs = Vec::new();
|
||||
|
||||
@ -73,7 +72,6 @@ impl<F: Field> GenerationState<F> {
|
||||
registers: Default::default(),
|
||||
memory: MemoryState::new(kernel_code),
|
||||
traces: Traces::default(),
|
||||
next_txn_index: 0,
|
||||
mpt_prover_inputs,
|
||||
rlp_prover_inputs,
|
||||
withdrawal_prover_inputs,
|
||||
|
||||
@ -151,7 +151,7 @@ fn add11_yml() -> anyhow::Result<()> {
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn.to_vec()],
|
||||
signed_txn: Some(txn.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
|
||||
@ -183,7 +183,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> {
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn.to_vec()],
|
||||
signed_txn: Some(txn.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
|
||||
@ -48,7 +48,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![],
|
||||
signed_txn: None,
|
||||
withdrawals: vec![],
|
||||
tries: TrieInputs {
|
||||
state_trie,
|
||||
|
||||
@ -159,7 +159,7 @@ fn test_erc20() -> anyhow::Result<()> {
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn.to_vec()],
|
||||
signed_txn: Some(txn.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
|
||||
@ -229,7 +229,7 @@ fn test_log_opcodes() -> anyhow::Result<()> {
|
||||
.unwrap(),
|
||||
];
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn.to_vec()],
|
||||
signed_txn: Some(txn.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
@ -437,7 +437,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
|
||||
};
|
||||
|
||||
let inputs_first = GenerationInputs {
|
||||
signed_txns: vec![txn.to_vec()],
|
||||
signed_txn: Some(txn.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after: tries_after,
|
||||
@ -582,7 +582,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
|
||||
U256::from_dec_str("2722259584404615024560450425766186844160").unwrap(),
|
||||
];
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn_2.to_vec()],
|
||||
signed_txn: Some(txn_2.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
@ -753,184 +753,6 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // Too slow to run on CI.
|
||||
fn test_two_txn() -> anyhow::Result<()> {
|
||||
init_logger();
|
||||
|
||||
let all_stark = AllStark::<F, D>::default();
|
||||
let config = StarkConfig::standard_fast_config();
|
||||
|
||||
let beneficiary = hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba");
|
||||
let sender = hex!("af1276cbb260bb13deddb4209ae99ae6e497f446");
|
||||
// Private key: DCDFF53B4F013DBCDC717F89FE3BF4D8B10512AAE282B48E01D7530470382701
|
||||
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();
|
||||
|
||||
// Set accounts before the transaction.
|
||||
let beneficiary_account_before = AccountRlp {
|
||||
nonce: 1.into(),
|
||||
..AccountRlp::default()
|
||||
};
|
||||
|
||||
let sender_balance_before = 50000000000000000u64;
|
||||
let sender_account_before = AccountRlp {
|
||||
balance: sender_balance_before.into(),
|
||||
..AccountRlp::default()
|
||||
};
|
||||
let to_account_before = AccountRlp {
|
||||
..AccountRlp::default()
|
||||
};
|
||||
|
||||
// Initialize the state trie with three accounts.
|
||||
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())],
|
||||
};
|
||||
|
||||
// Prove two simple transfers.
|
||||
let gas_price = 10;
|
||||
let txn_value = 0x11c37937e08000u64;
|
||||
let txn_0 = hex!("f866800a82520894095e7baea6a6c7c4c2dfeb977efac326af552d878711c37937e080008026a01fcd0ce88ac7600698a771f206df24b70e67981b6f107bd7c1c24ea94f113bcba00d87cc5c7afc2988e4ff200b5a0c7016b0d5498bbc692065ca983fcbbfe02555");
|
||||
let txn_1 = hex!("f866010a82520894095e7baea6a6c7c4c2dfeb977efac326af552d878711c37937e080008026a0d8123f5f537bd3a67283f67eb136f7accdfc4ef012cfbfd3fb1d0ac7fd01b96fa004666d9feef90a1eb568570374dd19977d4da231b289d769e6f95105c06fd672");
|
||||
|
||||
let block_metadata = BlockMetadata {
|
||||
block_beneficiary: Address::from(beneficiary),
|
||||
block_timestamp: 0x03e8.into(),
|
||||
block_number: 1.into(),
|
||||
block_difficulty: 0x020000.into(),
|
||||
block_random: H256::from_uint(&0x020000.into()),
|
||||
block_gaslimit: 0xffffffffu32.into(),
|
||||
block_chain_id: 1.into(),
|
||||
block_base_fee: 0xa.into(),
|
||||
block_gas_used: 0.into(),
|
||||
block_bloom: [0.into(); 8],
|
||||
};
|
||||
|
||||
let mut contract_code = HashMap::new();
|
||||
contract_code.insert(keccak(vec![]), vec![]);
|
||||
|
||||
// Update accounts
|
||||
let beneficiary_account_after = AccountRlp {
|
||||
nonce: 1.into(),
|
||||
..AccountRlp::default()
|
||||
};
|
||||
|
||||
let sender_balance_after = sender_balance_before - gas_price * 21000 * 2 - txn_value * 2;
|
||||
let sender_account_after = AccountRlp {
|
||||
balance: sender_balance_after.into(),
|
||||
nonce: 2.into(),
|
||||
..AccountRlp::default()
|
||||
};
|
||||
let to_account_after = AccountRlp {
|
||||
balance: (2 * txn_value).into(),
|
||||
..AccountRlp::default()
|
||||
};
|
||||
|
||||
// Update the state trie.
|
||||
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());
|
||||
|
||||
// Compute new receipt trie.
|
||||
let mut receipts_trie = HashedPartialTrie::from(Node::Empty);
|
||||
|
||||
let receipt_0 = LegacyReceiptRlp {
|
||||
status: true,
|
||||
cum_gas_used: 21000u64.into(),
|
||||
bloom: [0x00; 256].to_vec().into(),
|
||||
logs: vec![],
|
||||
};
|
||||
|
||||
let receipt_1 = LegacyReceiptRlp {
|
||||
status: true,
|
||||
cum_gas_used: 42000u64.into(),
|
||||
bloom: [0x00; 256].to_vec().into(),
|
||||
logs: vec![],
|
||||
};
|
||||
|
||||
receipts_trie.insert(
|
||||
Nibbles::from_str("0x80").unwrap(),
|
||||
rlp::encode(&receipt_0).to_vec(),
|
||||
);
|
||||
|
||||
receipts_trie.insert(
|
||||
Nibbles::from_str("0x01").unwrap(),
|
||||
rlp::encode(&receipt_1).to_vec(),
|
||||
);
|
||||
|
||||
let mut transactions_trie: HashedPartialTrie = Node::Leaf {
|
||||
nibbles: Nibbles::from_str("0x80").unwrap(),
|
||||
value: txn_0.to_vec(),
|
||||
}
|
||||
.into();
|
||||
|
||||
transactions_trie.insert(Nibbles::from_str("0x01").unwrap(), txn_1.to_vec());
|
||||
|
||||
let trie_roots_after = TrieRoots {
|
||||
state_root: expected_state_trie_after.hash(),
|
||||
transactions_root: transactions_trie.hash(),
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn_0.to_vec(), txn_1.to_vec()],
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
contract_code,
|
||||
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
|
||||
block_metadata,
|
||||
txn_number_before: 0.into(),
|
||||
gas_used_before: 0.into(),
|
||||
gas_used_after: 42000u64.into(),
|
||||
block_bloom_before: [0.into(); 8],
|
||||
block_bloom_after: [0.into(); 8],
|
||||
block_hashes: BlockHashes {
|
||||
prev_hashes: vec![H256::default(); 256],
|
||||
cur_hash: H256::default(),
|
||||
},
|
||||
addresses: vec![],
|
||||
};
|
||||
|
||||
let mut timing = TimingTree::new("prove", log::Level::Debug);
|
||||
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
|
||||
timing.filter(Duration::from_millis(100)).print();
|
||||
|
||||
// Assert trie roots.
|
||||
assert_eq!(
|
||||
proof.public_values.trie_roots_after.state_root,
|
||||
expected_state_trie_after.hash()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
proof.public_values.trie_roots_after.receipts_root,
|
||||
receipts_trie.hash()
|
||||
);
|
||||
|
||||
verify_proof(&all_stark, proof, &config)
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info"));
|
||||
}
|
||||
|
||||
@ -1,247 +0,0 @@
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV};
|
||||
use eth_trie_utils::nibbles::Nibbles;
|
||||
use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie};
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use hex_literal::hex;
|
||||
use keccak_hash::keccak;
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::plonk::config::KeccakGoldilocksConfig;
|
||||
use plonky2::util::timing::TimingTree;
|
||||
use plonky2_evm::all_stark::AllStark;
|
||||
use plonky2_evm::config::StarkConfig;
|
||||
use plonky2_evm::cpu::kernel::opcodes::{get_opcode, get_push_opcode};
|
||||
use plonky2_evm::generation::mpt::{AccountRlp, LegacyReceiptRlp};
|
||||
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
|
||||
use plonky2_evm::proof::{BlockHashes, BlockMetadata, TrieRoots};
|
||||
use plonky2_evm::prover::prove;
|
||||
use plonky2_evm::verifier::verify_proof;
|
||||
use plonky2_evm::Node;
|
||||
|
||||
type F = GoldilocksField;
|
||||
const D: usize = 2;
|
||||
type C = KeccakGoldilocksConfig;
|
||||
|
||||
/// Test the validity of four transactions, where only the first one is valid and the other three abort.
|
||||
#[test]
|
||||
fn test_four_transactions() -> anyhow::Result<()> {
|
||||
init_logger();
|
||||
|
||||
let all_stark = AllStark::<F, D>::default();
|
||||
let config = StarkConfig::standard_fast_config();
|
||||
|
||||
let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
|
||||
let sender = hex!("2c7536e3605d9c16a7a3d7b1898e529396a65c23");
|
||||
let to = hex!("a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0");
|
||||
|
||||
let beneficiary_state_key = keccak(beneficiary);
|
||||
let sender_state_key = keccak(sender);
|
||||
let to_state_key = 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_state_key.as_bytes()).unwrap();
|
||||
|
||||
let push1 = get_push_opcode(1);
|
||||
let add = get_opcode("ADD");
|
||||
let stop = get_opcode("STOP");
|
||||
let code = [push1, 3, push1, 4, add, stop];
|
||||
let code_gas = 3 + 3 + 3;
|
||||
let code_hash = keccak(code);
|
||||
|
||||
let beneficiary_account_before = AccountRlp::default();
|
||||
let sender_account_before = AccountRlp {
|
||||
nonce: 5.into(),
|
||||
|
||||
balance: eth_to_wei(100_000.into()),
|
||||
|
||||
..AccountRlp::default()
|
||||
};
|
||||
let to_account_before = AccountRlp {
|
||||
code_hash,
|
||||
..AccountRlp::default()
|
||||
};
|
||||
|
||||
let state_trie_before = {
|
||||
let mut children = core::array::from_fn(|_| Node::Empty.into());
|
||||
children[sender_nibbles.get_nibble(0) as usize] = Node::Leaf {
|
||||
nibbles: sender_nibbles.truncate_n_nibbles_front(1),
|
||||
|
||||
value: rlp::encode(&sender_account_before).to_vec(),
|
||||
}
|
||||
.into();
|
||||
children[to_nibbles.get_nibble(0) as usize] = Node::Leaf {
|
||||
nibbles: to_nibbles.truncate_n_nibbles_front(1),
|
||||
|
||||
value: rlp::encode(&to_account_before).to_vec(),
|
||||
}
|
||||
.into();
|
||||
Node::Branch {
|
||||
children,
|
||||
value: vec![],
|
||||
}
|
||||
}
|
||||
.into();
|
||||
|
||||
let tries_before = TrieInputs {
|
||||
state_trie: state_trie_before,
|
||||
transactions_trie: Node::Empty.into(),
|
||||
receipts_trie: Node::Empty.into(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
|
||||
// Generated using a little py-evm script.
|
||||
let txn1 = hex!("f861050a8255f094a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0648242421ba02c89eb757d9deeb1f5b3859a9d4d679951ef610ac47ad4608dc142beb1b7e313a05af7e9fbab825455d36c36c7f4cfcafbeafa9a77bdff936b52afb36d4fe4bcdd");
|
||||
let txn2 = hex!("f863800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffb600e63115a7362e7811894a91d8ba4330e526f22121c994c4692035dfdfd5a06198379fcac8de3dbfac48b165df4bf88e2088f294b61efb9a65fe2281c76e16");
|
||||
let txn3 = hex!("f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b");
|
||||
let txn4 = hex!("f866800a82520894095e7baea6a6c7c4c2dfeb977efac326af552d878711c37937e080008026a01fcd0ce88ac7600698a771f206df24b70e67981b6f107bd7c1c24ea94f113bcba00d87cc5c7afc2988e4ff200b5a0c7016b0d5498bbc692065ca983fcbbfe02555");
|
||||
|
||||
let txdata_gas = 2 * 16;
|
||||
let gas_used = 21_000 + code_gas + txdata_gas;
|
||||
|
||||
let value = U256::from(100u32);
|
||||
|
||||
let block_metadata = BlockMetadata {
|
||||
block_beneficiary: Address::from(beneficiary),
|
||||
block_timestamp: 0x03e8.into(),
|
||||
block_number: 1.into(),
|
||||
block_difficulty: 0x020000.into(),
|
||||
block_gaslimit: 0x445566u64.into(),
|
||||
block_chain_id: 1.into(),
|
||||
block_gas_used: gas_used.into(),
|
||||
..BlockMetadata::default()
|
||||
};
|
||||
|
||||
let mut contract_code = HashMap::new();
|
||||
contract_code.insert(keccak(vec![]), vec![]);
|
||||
contract_code.insert(code_hash, code.to_vec());
|
||||
|
||||
// Update trie roots after the 4 transactions.
|
||||
// State trie.
|
||||
let expected_state_trie_after: HashedPartialTrie = {
|
||||
let beneficiary_account_after = AccountRlp {
|
||||
balance: beneficiary_account_before.balance + gas_used * 10,
|
||||
..beneficiary_account_before
|
||||
};
|
||||
let sender_account_after = AccountRlp {
|
||||
balance: sender_account_before.balance - value - gas_used * 10,
|
||||
nonce: sender_account_before.nonce + 1,
|
||||
..sender_account_before
|
||||
};
|
||||
let to_account_after = AccountRlp {
|
||||
balance: to_account_before.balance + value,
|
||||
..to_account_before
|
||||
};
|
||||
|
||||
let mut children = core::array::from_fn(|_| Node::Empty.into());
|
||||
children[beneficiary_nibbles.get_nibble(0) as usize] = Node::Leaf {
|
||||
nibbles: beneficiary_nibbles.truncate_n_nibbles_front(1),
|
||||
|
||||
value: rlp::encode(&beneficiary_account_after).to_vec(),
|
||||
}
|
||||
.into();
|
||||
children[sender_nibbles.get_nibble(0) as usize] = Node::Leaf {
|
||||
nibbles: sender_nibbles.truncate_n_nibbles_front(1),
|
||||
|
||||
value: rlp::encode(&sender_account_after).to_vec(),
|
||||
}
|
||||
.into();
|
||||
children[to_nibbles.get_nibble(0) as usize] = Node::Leaf {
|
||||
nibbles: to_nibbles.truncate_n_nibbles_front(1),
|
||||
|
||||
value: rlp::encode(&to_account_after).to_vec(),
|
||||
}
|
||||
.into();
|
||||
Node::Branch {
|
||||
children,
|
||||
value: vec![],
|
||||
}
|
||||
}
|
||||
.into();
|
||||
|
||||
// Transactions trie.
|
||||
let mut transactions_trie: HashedPartialTrie = Node::Leaf {
|
||||
nibbles: Nibbles::from_str("0x80").unwrap(),
|
||||
value: txn1.to_vec(),
|
||||
}
|
||||
.into();
|
||||
transactions_trie.insert(Nibbles::from_str("0x01").unwrap(), txn2.to_vec());
|
||||
transactions_trie.insert(Nibbles::from_str("0x02").unwrap(), txn3.to_vec());
|
||||
transactions_trie.insert(Nibbles::from_str("0x03").unwrap(), txn4.to_vec());
|
||||
|
||||
// Receipts trie.
|
||||
let mut receipts_trie = HashedPartialTrie::from(Node::Empty);
|
||||
let receipt_0 = LegacyReceiptRlp {
|
||||
status: true,
|
||||
cum_gas_used: gas_used.into(),
|
||||
bloom: [0x00; 256].to_vec().into(),
|
||||
logs: vec![],
|
||||
};
|
||||
let receipt_1 = LegacyReceiptRlp {
|
||||
status: false,
|
||||
cum_gas_used: gas_used.into(),
|
||||
bloom: [0x00; 256].to_vec().into(),
|
||||
logs: vec![],
|
||||
};
|
||||
receipts_trie.insert(
|
||||
Nibbles::from_str("0x80").unwrap(),
|
||||
rlp::encode(&receipt_0).to_vec(),
|
||||
);
|
||||
receipts_trie.insert(
|
||||
Nibbles::from_str("0x01").unwrap(),
|
||||
rlp::encode(&receipt_1).to_vec(),
|
||||
);
|
||||
receipts_trie.insert(
|
||||
Nibbles::from_str("0x02").unwrap(),
|
||||
rlp::encode(&receipt_1).to_vec(),
|
||||
);
|
||||
receipts_trie.insert(
|
||||
Nibbles::from_str("0x03").unwrap(),
|
||||
rlp::encode(&receipt_1).to_vec(),
|
||||
);
|
||||
|
||||
let trie_roots_after = TrieRoots {
|
||||
state_root: expected_state_trie_after.hash(),
|
||||
transactions_root: transactions_trie.hash(),
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn1.to_vec(), txn2.to_vec(), txn3.to_vec(), txn4.to_vec()],
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
|
||||
contract_code,
|
||||
block_metadata,
|
||||
addresses: vec![],
|
||||
block_bloom_before: [0.into(); 8],
|
||||
gas_used_before: 0.into(),
|
||||
gas_used_after: gas_used.into(),
|
||||
txn_number_before: 0.into(),
|
||||
block_bloom_after: [0.into(); 8],
|
||||
block_hashes: BlockHashes {
|
||||
prev_hashes: vec![H256::default(); 256],
|
||||
cur_hash: H256::default(),
|
||||
},
|
||||
};
|
||||
|
||||
let mut timing = TimingTree::new("prove", log::Level::Debug);
|
||||
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
|
||||
timing.filter(Duration::from_millis(100)).print();
|
||||
|
||||
verify_proof(&all_stark, proof, &config)
|
||||
}
|
||||
|
||||
fn eth_to_wei(eth: U256) -> U256 {
|
||||
// 1 ether = 10^18 wei.
|
||||
eth * U256::from(10).pow(18.into())
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info"));
|
||||
}
|
||||
@ -170,7 +170,7 @@ fn self_balance_gas_cost() -> anyhow::Result<()> {
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn.to_vec()],
|
||||
signed_txn: Some(txn.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
|
||||
@ -122,7 +122,7 @@ fn test_selfdestruct() -> anyhow::Result<()> {
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn.to_vec()],
|
||||
signed_txn: Some(txn.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
|
||||
@ -138,7 +138,7 @@ fn test_simple_transfer() -> anyhow::Result<()> {
|
||||
receipts_root: receipts_trie.hash(),
|
||||
};
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![txn.to_vec()],
|
||||
signed_txn: Some(txn.to_vec()),
|
||||
withdrawals: vec![],
|
||||
tries: tries_before,
|
||||
trie_roots_after,
|
||||
|
||||
@ -63,7 +63,7 @@ fn test_withdrawals() -> anyhow::Result<()> {
|
||||
};
|
||||
|
||||
let inputs = GenerationInputs {
|
||||
signed_txns: vec![],
|
||||
signed_txn: None,
|
||||
withdrawals,
|
||||
tries: TrieInputs {
|
||||
state_trie: state_trie_before,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user