131 lines
4.8 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
use eth_trie_utils::partial_trie::PartialTrie;
use ethereum_types::{Address, BigEndianHash, H256};
use plonky2::field::extension::Extendable;
use plonky2::field::polynomial::PolynomialValues;
use plonky2::hash::hash_types::RichField;
2022-12-02 14:49:32 -08:00
use plonky2::timed;
use plonky2::util::timing::TimingTree;
use serde::{Deserialize, Serialize};
2022-12-02 13:56:52 -08:00
use GlobalMetadata::{
ReceiptTrieRootDigestAfter, ReceiptTrieRootDigestBefore, StateTrieRootDigestAfter,
StateTrieRootDigestBefore, TransactionTrieRootDigestAfter, TransactionTrieRootDigestBefore,
};
2022-08-26 10:12:45 +02:00
use crate::all_stark::{AllStark, NUM_TABLES};
2022-08-26 18:30:26 +02:00
use crate::config::StarkConfig;
use crate::cpu::bootstrap_kernel::generate_bootstrap_kernel;
2022-11-30 12:55:41 -08:00
use crate::cpu::kernel::aggregator::KERNEL;
2022-10-03 12:08:29 -07:00
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
2022-12-01 11:15:51 -08:00
use crate::generation::state::GenerationState;
2022-08-25 12:24:22 -07:00
use crate::memory::segments::Segment;
use crate::proof::{BlockMetadata, PublicValues, TrieRoots};
2022-12-01 11:15:51 -08:00
use crate::witness::memory::MemoryAddress;
2022-11-30 12:55:41 -08:00
use crate::witness::transition::transition;
pub(crate) mod mpt;
pub(crate) mod prover_input;
2022-09-29 23:09:32 -07:00
pub(crate) mod rlp;
pub(crate) mod state;
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
2022-08-25 22:11:25 -07:00
/// Inputs needed for trace generation.
pub struct GenerationInputs {
2022-08-25 12:24:22 -07:00
pub signed_txns: Vec<Vec<u8>>,
2022-09-22 20:09:48 -07:00
pub tries: TrieInputs,
/// Mapping between smart contract code hashes and the contract byte code.
/// All account smart contracts that are invoked will have an entry present.
pub contract_code: HashMap<H256, Vec<u8>>,
pub block_metadata: BlockMetadata,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
pub struct TrieInputs {
2022-08-25 23:35:38 -07:00
/// A partial version of the state trie prior to these transactions. It should include all nodes
/// that will be accessed by these transactions.
pub state_trie: PartialTrie,
2022-08-25 23:35:38 -07:00
/// A partial version of the transaction trie prior to these transactions. It should include all
/// nodes that will be accessed by these transactions.
2022-08-25 12:24:22 -07:00
pub transactions_trie: PartialTrie,
2022-08-25 23:35:38 -07:00
/// A partial version of the receipt trie prior to these transactions. It should include all nodes
/// that will be accessed by these transactions.
2022-08-25 12:24:22 -07:00
pub receipts_trie: PartialTrie,
2022-08-25 23:35:38 -07:00
/// A partial version of each storage trie prior to these transactions. It should include all
/// storage tries, and nodes therein, that will be accessed by these transactions.
pub storage_tries: Vec<(Address, PartialTrie)>,
}
2022-08-25 12:24:22 -07:00
pub(crate) fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
all_stark: &AllStark<F, D>,
2022-08-25 22:11:25 -07:00
inputs: GenerationInputs,
2022-08-26 18:30:26 +02:00
config: &StarkConfig,
timing: &mut TimingTree,
2022-08-26 10:12:45 +02:00
) -> ([Vec<PolynomialValues<F>>; NUM_TABLES], PublicValues) {
2022-12-01 11:15:51 -08:00
let mut state = GenerationState::<F>::new(inputs.clone(), &KERNEL.code);
2022-12-01 11:15:51 -08:00
generate_bootstrap_kernel::<F>(&mut state);
2022-12-02 14:49:32 -08:00
timed!(timing, "simulate CPU", simulate_cpu(&mut state));
2022-08-25 12:24:22 -07:00
2022-11-30 12:55:41 -08:00
let read_metadata = |field| {
2022-12-01 11:15:51 -08:00
state.memory.get(MemoryAddress::new(
2022-08-25 12:24:22 -07:00
0,
2022-11-30 17:45:31 -08:00
Segment::GlobalMetadata,
2022-08-25 12:24:22 -07:00
field as usize,
2022-11-30 12:55:41 -08:00
))
2022-08-25 12:24:22 -07:00
};
let trie_roots_before = TrieRoots {
2022-12-02 13:56:52 -08:00
state_root: H256::from_uint(&read_metadata(StateTrieRootDigestBefore)),
transactions_root: H256::from_uint(&read_metadata(TransactionTrieRootDigestBefore)),
receipts_root: H256::from_uint(&read_metadata(ReceiptTrieRootDigestBefore)),
2022-08-25 12:24:22 -07:00
};
let trie_roots_after = TrieRoots {
2022-12-02 13:56:52 -08:00
state_root: H256::from_uint(&read_metadata(StateTrieRootDigestAfter)),
transactions_root: H256::from_uint(&read_metadata(TransactionTrieRootDigestAfter)),
receipts_root: H256::from_uint(&read_metadata(ReceiptTrieRootDigestAfter)),
2022-08-25 12:24:22 -07:00
};
let public_values = PublicValues {
trie_roots_before,
trie_roots_after,
block_metadata: inputs.block_metadata,
};
2022-12-02 14:49:32 -08:00
let tables = timed!(
timing,
"convert trace data to tables",
2022-12-02 17:06:30 -08:00
state.traces.into_tables(all_stark, config, timing)
2022-12-02 14:49:32 -08:00
);
(tables, public_values)
}
fn simulate_cpu<F: RichField + Extendable<D>, const D: usize>(state: &mut GenerationState<F>) {
let halt_pc0 = KERNEL.global_labels["halt_pc0"];
let halt_pc1 = KERNEL.global_labels["halt_pc1"];
let mut already_in_halt_loop = false;
loop {
// If we've reached the kernel's halt routine, and our trace length is a power of 2, stop.
let pc = state.registers.program_counter;
let in_halt_loop = pc == halt_pc0 || pc == halt_pc1;
if in_halt_loop && !already_in_halt_loop {
log::info!("CPU halted after {} cycles", state.traces.clock());
}
already_in_halt_loop |= in_halt_loop;
if already_in_halt_loop && state.traces.clock().is_power_of_two() {
log::info!("CPU trace padded to {} cycles", state.traces.clock());
break;
}
transition(state);
}
}