2022-09-21 15:40:11 -06:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
2023-03-28 14:38:58 -06:00
|
|
|
use eth_trie_utils::partial_trie::HashedPartialTrie;
|
2023-03-12 21:35:04 -07:00
|
|
|
use ethereum_types::{Address, BigEndianHash, H256, U256};
|
2022-06-15 09:33:52 -07:00
|
|
|
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;
|
2022-09-23 10:54:17 -07:00
|
|
|
use plonky2::util::timing::TimingTree;
|
2022-09-19 11:05:48 -06:00
|
|
|
use serde::{Deserialize, Serialize};
|
2022-12-02 13:56:52 -08:00
|
|
|
use GlobalMetadata::{
|
|
|
|
|
ReceiptTrieRootDigestAfter, ReceiptTrieRootDigestBefore, StateTrieRootDigestAfter,
|
|
|
|
|
StateTrieRootDigestBefore, TransactionTrieRootDigestAfter, TransactionTrieRootDigestBefore,
|
|
|
|
|
};
|
2022-06-15 09:33:52 -07:00
|
|
|
|
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;
|
2022-06-15 09:33:52 -07:00
|
|
|
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;
|
2023-03-16 13:32:34 -07:00
|
|
|
use crate::generation::outputs::{get_outputs, GenerationOutputs};
|
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};
|
2023-04-14 21:55:44 +08:00
|
|
|
use crate::witness::memory::{MemoryAddress, MemoryChannel, MemoryOp, MemoryOpKind};
|
2022-11-30 12:55:41 -08:00
|
|
|
use crate::witness::transition::transition;
|
2022-06-15 09:33:52 -07:00
|
|
|
|
2022-12-03 21:09:57 -08:00
|
|
|
pub mod mpt;
|
2023-03-16 13:32:34 -07:00
|
|
|
pub mod outputs;
|
2022-09-18 09:45:31 -07:00
|
|
|
pub(crate) mod prover_input;
|
2022-09-29 23:09:32 -07:00
|
|
|
pub(crate) mod rlp;
|
2022-06-15 09:33:52 -07:00
|
|
|
pub(crate) mod state;
|
2023-03-05 21:56:01 -08:00
|
|
|
mod trie_extractor;
|
2023-03-16 13:32:34 -07:00
|
|
|
|
2023-03-12 21:35:04 -07:00
|
|
|
use crate::witness::util::mem_write_log;
|
2022-06-15 09:33:52 -07:00
|
|
|
|
2022-08-25 22:11:25 -07:00
|
|
|
/// Inputs needed for trace generation.
|
2023-03-16 13:32:34 -07:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
|
2022-08-25 22:11:25 -07:00
|
|
|
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,
|
2023-03-16 14:08:31 -07:00
|
|
|
|
|
|
|
|
/// A list of known addresses in the input state trie (which itself doesn't hold addresses,
|
|
|
|
|
/// only state keys). This is only useful for debugging, so that we can return addresses in the
|
|
|
|
|
/// post-state rather than state keys. (See `GenerationOutputs`, and in particular
|
|
|
|
|
/// `AddressOrStateKey`.) If the caller is not interested in the post-state, this can be left
|
|
|
|
|
/// empty.
|
|
|
|
|
pub addresses: Vec<Address>,
|
2022-09-22 20:09:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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.
|
2023-03-28 14:38:58 -06:00
|
|
|
pub state_trie: HashedPartialTrie,
|
2022-08-24 20:41:32 -07:00
|
|
|
|
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.
|
2023-03-28 14:38:58 -06:00
|
|
|
pub transactions_trie: HashedPartialTrie,
|
2022-08-24 20:41:32 -07:00
|
|
|
|
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.
|
2023-03-28 14:38:58 -06:00
|
|
|
pub receipts_trie: HashedPartialTrie,
|
2022-08-24 20:41:32 -07:00
|
|
|
|
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.
|
2023-05-16 13:49:57 -06:00
|
|
|
pub storage_tries: Vec<(H256, HashedPartialTrie)>,
|
2022-06-15 09:33:52 -07:00
|
|
|
}
|
|
|
|
|
|
2023-03-12 21:35:04 -07:00
|
|
|
fn apply_metadata_memops<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
state: &mut GenerationState<F>,
|
|
|
|
|
metadata: &BlockMetadata,
|
|
|
|
|
) {
|
|
|
|
|
let fields = [
|
|
|
|
|
(
|
|
|
|
|
GlobalMetadata::BlockBeneficiary,
|
|
|
|
|
U256::from_big_endian(&metadata.block_beneficiary.0),
|
|
|
|
|
),
|
|
|
|
|
(GlobalMetadata::BlockTimestamp, metadata.block_timestamp),
|
|
|
|
|
(GlobalMetadata::BlockNumber, metadata.block_number),
|
|
|
|
|
(GlobalMetadata::BlockDifficulty, metadata.block_difficulty),
|
|
|
|
|
(GlobalMetadata::BlockGasLimit, metadata.block_gaslimit),
|
|
|
|
|
(GlobalMetadata::BlockChainId, metadata.block_chain_id),
|
|
|
|
|
(GlobalMetadata::BlockBaseFee, metadata.block_base_fee),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let channel = MemoryChannel::GeneralPurpose(0);
|
|
|
|
|
let ops = fields.map(|(field, val)| {
|
|
|
|
|
mem_write_log(
|
|
|
|
|
channel,
|
|
|
|
|
MemoryAddress::new(0, Segment::GlobalMetadata, field as usize),
|
|
|
|
|
state,
|
|
|
|
|
val,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
state.memory.apply_ops(&ops);
|
|
|
|
|
state.traces.memory_ops.extend(ops);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-14 21:55:44 +08:00
|
|
|
fn apply_trie_memops<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
state: &mut GenerationState<F>,
|
|
|
|
|
trie_roots_before: &TrieRoots,
|
|
|
|
|
trie_roots_after: &TrieRoots,
|
|
|
|
|
) {
|
|
|
|
|
let fields = [
|
|
|
|
|
(
|
|
|
|
|
GlobalMetadata::StateTrieRootDigestBefore,
|
|
|
|
|
trie_roots_before.state_root,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
GlobalMetadata::TransactionTrieRootDigestBefore,
|
|
|
|
|
trie_roots_before.transactions_root,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
GlobalMetadata::ReceiptTrieRootDigestBefore,
|
|
|
|
|
trie_roots_before.receipts_root,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
GlobalMetadata::StateTrieRootDigestAfter,
|
|
|
|
|
trie_roots_after.state_root,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
GlobalMetadata::TransactionTrieRootDigestAfter,
|
|
|
|
|
trie_roots_after.transactions_root,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
GlobalMetadata::ReceiptTrieRootDigestAfter,
|
|
|
|
|
trie_roots_after.receipts_root,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let channel = MemoryChannel::GeneralPurpose(0);
|
|
|
|
|
|
|
|
|
|
let ops = fields.map(|(field, hash)| {
|
|
|
|
|
let val = hash.into_uint();
|
|
|
|
|
MemoryOp::new(
|
|
|
|
|
channel,
|
|
|
|
|
state.traces.cpu.len(),
|
|
|
|
|
MemoryAddress::new(0, Segment::GlobalMetadata, field as usize),
|
|
|
|
|
MemoryOpKind::Read,
|
|
|
|
|
val,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
state.traces.memory_ops.extend(ops);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 20:05:39 +02:00
|
|
|
pub fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
|
2022-06-15 09:33:52 -07:00
|
|
|
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,
|
2022-09-23 10:54:17 -07:00
|
|
|
timing: &mut TimingTree,
|
2023-03-16 13:32:34 -07:00
|
|
|
) -> anyhow::Result<(
|
|
|
|
|
[Vec<PolynomialValues<F>>; NUM_TABLES],
|
|
|
|
|
PublicValues,
|
|
|
|
|
GenerationOutputs,
|
|
|
|
|
)> {
|
2022-12-01 11:15:51 -08:00
|
|
|
let mut state = GenerationState::<F>::new(inputs.clone(), &KERNEL.code);
|
2023-05-10 17:35:28 -04:00
|
|
|
|
2023-03-12 21:35:04 -07:00
|
|
|
apply_metadata_memops(&mut state, &inputs.block_metadata);
|
|
|
|
|
|
2022-12-01 11:15:51 -08:00
|
|
|
generate_bootstrap_kernel::<F>(&mut state);
|
2022-06-15 09:33:52 -07:00
|
|
|
|
2023-02-25 07:59:51 -08:00
|
|
|
timed!(timing, "simulate CPU", simulate_cpu(&mut state)?);
|
2022-08-25 12:24:22 -07:00
|
|
|
|
2023-03-17 13:10:58 -07:00
|
|
|
assert!(
|
|
|
|
|
state.mpt_prover_inputs.is_empty(),
|
|
|
|
|
"All MPT data should have been consumed"
|
|
|
|
|
);
|
|
|
|
|
|
2022-12-03 22:58:51 -08:00
|
|
|
log::info!(
|
|
|
|
|
"Trace lengths (before padding): {:?}",
|
|
|
|
|
state.traces.checkpoint()
|
|
|
|
|
);
|
2022-12-03 22:44:54 -08:00
|
|
|
|
2023-03-16 13:32:34 -07:00
|
|
|
let outputs = get_outputs(&mut state);
|
2023-03-05 21:56:01 -08:00
|
|
|
|
2023-03-16 13:32:34 -07:00
|
|
|
let read_metadata = |field| state.memory.read_global_metadata(field);
|
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
|
|
|
};
|
|
|
|
|
|
2023-04-14 21:55:44 +08:00
|
|
|
apply_trie_memops(&mut state, &trie_roots_before, &trie_roots_after);
|
|
|
|
|
|
2022-08-25 12:24:22 -07:00
|
|
|
let public_values = PublicValues {
|
|
|
|
|
trie_roots_before,
|
|
|
|
|
trie_roots_after,
|
|
|
|
|
block_metadata: inputs.block_metadata,
|
2023-06-21 20:05:39 +02:00
|
|
|
cpu_trace_len: state.traces.clock(),
|
2022-08-25 12:24:22 -07:00
|
|
|
};
|
|
|
|
|
|
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
|
|
|
);
|
2023-03-16 13:32:34 -07:00
|
|
|
Ok((tables, public_values, outputs))
|
2022-12-02 14:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
2023-02-25 07:59:51 -08:00
|
|
|
fn simulate_cpu<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
state: &mut GenerationState<F>,
|
|
|
|
|
) -> anyhow::Result<()> {
|
2022-12-02 14:49:32 -08:00
|
|
|
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;
|
2023-06-13 10:42:37 +02:00
|
|
|
let in_halt_loop = state.registers.is_kernel && (pc == halt_pc0 || pc == halt_pc1);
|
2022-12-02 14:49:32 -08:00
|
|
|
if in_halt_loop && !already_in_halt_loop {
|
|
|
|
|
log::info!("CPU halted after {} cycles", state.traces.clock());
|
|
|
|
|
}
|
|
|
|
|
already_in_halt_loop |= in_halt_loop;
|
2022-12-09 10:35:00 -08:00
|
|
|
|
2023-02-25 07:59:51 -08:00
|
|
|
transition(state)?;
|
2022-12-09 10:35:00 -08:00
|
|
|
|
2022-12-02 14:49:32 -08:00
|
|
|
if already_in_halt_loop && state.traces.clock().is_power_of_two() {
|
|
|
|
|
log::info!("CPU trace padded to {} cycles", state.traces.clock());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-25 07:59:51 -08:00
|
|
|
|
|
|
|
|
Ok(())
|
2022-06-15 09:33:52 -07:00
|
|
|
}
|