Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions bin/debug-trace-server/src/block_data_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ const AUTHORIZATION_BYTES: u64 = 192;
/// which quick_cache re-invokes on admission, promotion, and eviction, under a shard
/// lock — never re-walks the payload.
pub fn block_data_weight(data: &BlockData) -> u64 {
let witness = light_witness_memory_bytes(&data.witness) as u64;
let witness = (light_witness_memory_bytes(data.witness.light_witness()) +
data.witness.lookup_table_memory_bytes()) as u64;
let contracts: u64 = data.contracts.values().map(bytecode_weight).sum();
let block = BLOCK_FIXED_OVERHEAD +
match &data.block.transactions {
Expand Down Expand Up @@ -246,7 +247,8 @@ mod tests {
#[test]
fn weigher_charges_witness_contracts_and_transactions() {
let data = fixture_block_data();
let witness_bytes = light_witness_memory_bytes(&data.witness) as u64;
let witness_bytes = (light_witness_memory_bytes(data.witness.light_witness()) +
data.witness.lookup_table_memory_bytes()) as u64;
let contract_bytes: u64 = data.contracts.values().map(bytecode_weight).sum();

let weight = block_data_weight(&data);
Expand Down
22 changes: 15 additions & 7 deletions bin/debug-trace-server/src/data_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ use quick_cache::sync::Cache;
use revm::state::Bytecode;
use stateless_common::{CodeFetchError, RpcClient, RpcDeadlineExceeded, WitnessSizeBreakdown};
use stateless_core::{
ContractStore, LightWitness, StoreResult, db::StoreError, withdrawals::MptWitness,
ContractStore, LightWitness, LightWitnessExecutor, StoreResult, db::StoreError,
withdrawals::MptWitness,
};
use stateless_db::ContractCache;
use tracing::{debug, instrument, trace, warn};
Expand Down Expand Up @@ -110,8 +111,11 @@ impl WitnessFetchConfig {
pub struct BlockData {
/// The block with full transaction data.
pub block: Block<Transaction>,
/// Light witness without expensive EC point validation.
pub witness: LightWitness,
/// The witness wrapped in its execution form. Built once per block here, so every
/// trace request served from this `BlockData` shares one witness and one
/// direct-lookup table instead of deep-cloning the maps and rebuilding the table
/// per request.
pub witness: LightWitnessExecutor,
/// Contract bytecodes keyed by code hash, required for EVM execution.
/// `Bytecode` is internally reference-counted, so values share their underlying allocation
/// with the `ContractCache` (and across `BlockData` clones) via cheap refcount-bump clones.
Expand Down Expand Up @@ -835,7 +839,7 @@ impl DataProvider {
);
}

Ok(Some(BlockData { block, witness, contracts }))
Ok(Some(BlockData { block, witness: LightWitnessExecutor::from(witness), contracts }))
}

/// Single-flight fetch via [`futures::future::Shared`]: concurrent callers for the same
Expand Down Expand Up @@ -1045,7 +1049,7 @@ async fn do_fetch_block_data(
);
}

Ok(BlockData { block, witness, contracts })
Ok(BlockData { block, witness: LightWitnessExecutor::from(witness), contracts })
}

/// Reads the local DB's canonical tip height, `None` when no DB is configured or the tip is
Expand Down Expand Up @@ -1316,7 +1320,7 @@ pub(crate) mod test_support {
let witness = LightWitness::from(&fixtures.salt_witnesses[&hash]);
let contracts: HashMap<B256, Bytecode> =
fixtures.contracts.iter().map(|(h, code)| (*h, code.clone())).collect();
BlockData { block, witness, contracts }
BlockData { block, witness: LightWitnessExecutor::from(witness), contracts }
}

/// Minimal self-consistent RPC `Header` for `number`: `hash` is the real `hash_slow()`
Expand Down Expand Up @@ -1463,6 +1467,7 @@ mod tests {
/// code hash the witness references, so DB-served fetches never fall through to RPC.
fn fixture_block_and_cache() -> (Block<Transaction>, LightWitness, Arc<ContractCache>) {
let BlockData { block, witness, contracts } = test_support::fixture_block_data();
let witness = witness.light_witness().clone();
let contract_cache = test_support::noop_contract_cache();
let codes: Vec<(B256, Bytecode)> = crate::tracing_executor::extract_code_hashes(&witness)
.into_iter()
Expand Down Expand Up @@ -1555,7 +1560,10 @@ mod tests {
let (block, witness, contract_cache) = fixture_block_and_cache();
let hash = block.header.hash;
let cache = Arc::new(BlockDataCache::new(1024 * 1024 * 1024));
cache.insert(hash, Arc::new(BlockData { block, witness, contracts: HashMap::default() }));
cache.insert(
hash,
Arc::new(BlockData { block, witness: witness.into(), contracts: HashMap::default() }),
);
let provider =
provider_with_tiers(&test_support::hanging_url(), None, Some(cache), contract_cache);

Expand Down
10 changes: 5 additions & 5 deletions bin/debug-trace-server/src/rpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ impl RpcContext {
crate::tracing_executor::trace_block(
&self.chain_spec,
&data.block,
data.witness.clone(),
&data.witness,
&data.contracts,
opts,
)
Expand Down Expand Up @@ -633,7 +633,7 @@ impl DebugTraceRpcServer for RpcContext {
&self.chain_spec,
&data.block,
tx_index,
data.witness.clone(),
&data.witness,
&data.contracts,
opts,
)
Expand Down Expand Up @@ -715,7 +715,7 @@ impl TraceRpcServer for RpcContext {
crate::tracing_executor::parity_trace_block(
&self.chain_spec,
&data.block,
data.witness.clone(),
&data.witness,
&data.contracts,
)
})
Expand Down Expand Up @@ -762,7 +762,7 @@ impl TraceRpcServer for RpcContext {
&self.chain_spec,
&data.block,
tx_index,
data.witness.clone(),
&data.witness,
&data.contracts,
)
.map_err(|e| {
Expand Down Expand Up @@ -1055,7 +1055,7 @@ mod tests {

// Data-attributable: the same block cached with a witness that cannot replay it.
let mut data = fixture_block_data();
data.witness = empty_light_witness();
data.witness = empty_light_witness().into();
let left = entries_left_after_failed_trace(chain_spec, data, None).await;
assert_eq!(left, 0, "a data error must evict the poisoned entry");
}
Expand Down
32 changes: 16 additions & 16 deletions bin/debug-trace-server/src/tracing_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,23 +108,23 @@ struct TracingEnv<'a> {
>,
block_ctx: MegaBlockExecutionCtx,
evm_env: alloy_evm::EvmEnv<mega_evm::MegaSpecId>,
light_witness_executor: LightWitnessExecutor,
light_witness_executor: &'a LightWitnessExecutor,
}

impl<'a> TracingEnv<'a> {
fn new(
chain_spec: &ChainSpec,
block: &'a Block<OpTransaction>,
light_witness: LightWitness,
witness: &'a LightWitnessExecutor,
) -> Result<Self, ValidationError> {
let BlockTransactions::Full(transactions) = &block.transactions else {
return Err(ValidationError::BlockIncomplete);
};

let ext_env = WitnessExternalEnv::from_light_witness(&light_witness, block.header.number)
.map_err(ValidationError::EnvOracleConstructionFailed)?;
let ext_env =
WitnessExternalEnv::from_light_witness(witness.light_witness(), block.header.number)
.map_err(ValidationError::EnvOracleConstructionFailed)?;

let light_witness_executor = LightWitnessExecutor::from(light_witness);
let evm_env = create_evm_env(&block.header.inner, chain_spec);

let evm_factory = MegaEvmFactory::new().with_external_env_factory(ext_env);
Expand Down Expand Up @@ -155,15 +155,15 @@ impl<'a> TracingEnv<'a> {
executor_factory,
block_ctx,
evm_env,
light_witness_executor,
light_witness_executor: witness,
})
}

fn create_witness_db<'b>(
&'b self,
contracts: &'b HashMap<B256, Bytecode>,
) -> WitnessDatabase<'b, LightWitnessExecutor> {
WitnessDatabase { header: self.header, witness: &self.light_witness_executor, contracts }
WitnessDatabase { header: self.header, witness: self.light_witness_executor, contracts }
}
}

Expand Down Expand Up @@ -490,7 +490,7 @@ fn trace_tx_with_tracing_inspector(
pub fn trace_block(
chain_spec: &ChainSpec,
block: &Block<OpTransaction>,
witness: LightWitness,
witness: &LightWitnessExecutor,
contracts: &HashMap<B256, Bytecode>,
opts: GethDebugTracingOptions,
) -> Result<Vec<TraceResult>, TraceError> {
Expand Down Expand Up @@ -703,7 +703,7 @@ pub fn trace_transaction(
chain_spec: &ChainSpec,
block: &Block<OpTransaction>,
tx_index: usize,
light_witness: LightWitness,
light_witness: &LightWitnessExecutor,
contracts: &HashMap<B256, Bytecode>,
opts: GethDebugTracingOptions,
) -> Result<GethTrace, TraceError> {
Expand Down Expand Up @@ -826,7 +826,7 @@ pub fn trace_transaction(
pub fn parity_trace_block(
chain_spec: &ChainSpec,
block: &Block<OpTransaction>,
light_witness: LightWitness,
light_witness: &LightWitnessExecutor,
contracts: &HashMap<B256, Bytecode>,
) -> Result<Vec<LocalizedTransactionTrace>, TraceError> {
let env = TracingEnv::new(chain_spec, block, light_witness)?;
Expand Down Expand Up @@ -877,7 +877,7 @@ pub fn parity_trace_transaction(
chain_spec: &ChainSpec,
block: &Block<OpTransaction>,
tx_index: usize,
light_witness: LightWitness,
light_witness: &LightWitnessExecutor,
contracts: &HashMap<B256, Bytecode>,
) -> Result<Vec<LocalizedTransactionTrace>, TraceError> {
let env = TracingEnv::new(chain_spec, block, light_witness)?;
Expand Down Expand Up @@ -1058,7 +1058,7 @@ mod tests {
let err = trace_block(
&chain_spec,
&block,
witness.clone(),
&witness,
&HashMap::default(),
GethDebugTracingOptions::default(),
)
Expand All @@ -1070,7 +1070,7 @@ mod tests {
tracer_config: GethDebugTracerConfig(serde_json::json!({"bogusTracer": {}})),
..Default::default()
};
let err = trace_block(&chain_spec, &block, witness, &contracts, opts)
let err = trace_block(&chain_spec, &block, &witness, &contracts, opts)
.expect_err("an unparsable mux config must be rejected");
assert!(matches!(err, TraceError::Request(_)), "got: {err:?}");
}
Expand Down Expand Up @@ -1107,14 +1107,14 @@ mod tests {
..Default::default()
};

let err = trace_block(&chain_spec, &block, witness.clone(), &contracts, opts.clone())
let err = trace_block(&chain_spec, &block, &witness, &contracts, opts.clone())
.expect_err("malformed config must fail the block trace");
assert!(
matches!(&err, TraceError::Request(msg) if msg.contains("tracerConfig")),
"got: {err:?}"
);

let err = trace_transaction(&chain_spec, &block, 0, witness.clone(), &contracts, opts)
let err = trace_transaction(&chain_spec, &block, 0, &witness, &contracts, opts)
.expect_err("malformed config must fail the tx trace");
assert!(
matches!(&err, TraceError::Request(msg) if msg.contains("tracerConfig")),
Expand All @@ -1130,7 +1130,7 @@ mod tests {
tracer_config: GethDebugTracerConfig(serde_json::json!({"onlyTopCall": true})),
..Default::default()
};
trace_block(&chain_spec, &block, witness, &contracts, opts)
trace_block(&chain_spec, &block, &witness, &contracts, opts)
.expect("a well-formed config must trace");
}
}
13 changes: 13 additions & 0 deletions crates/stateless-core/src/light_witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,19 @@ impl LightWitnessExecutor {
pub fn kvs(&self) -> &BTreeMap<SaltKey, Option<SaltValue>> {
&self.light_witness.kvs
}

/// The wrapped witness.
pub fn light_witness(&self) -> &LightWitness {
&self.light_witness
}

/// Estimated heap bytes of the direct-lookup table, in the same
/// per-entry-term style as `light_witness_memory_bytes`: the plain-key
/// bytes plus the map entry (key header, `SaltKey`).
pub fn lookup_table_memory_bytes(&self) -> usize {
let entry = size_of::<Vec<u8>>() + size_of::<SaltKey>();
self.direct_lookup_tbl.keys().map(|k| k.len() + entry).sum()
}
}

#[cfg(test)]
Expand Down
Loading