Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: block structlog retrieval #682

Merged
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
2 changes: 1 addition & 1 deletion zero/src/bin/leader/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub(crate) enum Command {
#[arg(long, short = 't', default_value = "jerigon")]
rpc_type: RpcType,
/// The source of jumpdest tables.
#[arg(short = 'j', long, default_value_ifs = [("rpc_type", "jerigon", "prover-simulation"), ("rpc_type", "native", "client-fetched-structlogs")], required = false)]
#[arg(short = 'j', long, default_value_ifs = [("rpc_type", "jerigon", "client-fetched-structlogs"), ("rpc_type", "native", "client-fetched-structlogs")], required = false)]
jumpdest_src: JumpdestSrc,
/// The block interval for which to generate a proof.
#[arg(long, short = 'i')]
Expand Down
2 changes: 1 addition & 1 deletion zero/src/bin/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct RpcToolConfig {
#[arg(short = 't', long, default_value = "jerigon")]
rpc_type: RpcType,
/// The source of jumpdest tables.
#[arg(short = 'j', long, default_value_ifs = [("rpc_type", "jerigon", "prover-simulation"), ("rpc_type", "native", "client-fetched-structlogs")], required = false)]
#[arg(short = 'j', long, default_value_ifs = [("rpc_type", "jerigon", "client-fetched-structlogs"), ("rpc_type", "native", "client-fetched-structlogs")], required = false)]
jumpdest_src: JumpdestSrc,
/// Backoff in milliseconds for retry requests.
#[arg(long, default_value_t = 0)]
Expand Down
129 changes: 43 additions & 86 deletions zero/src/rpc/jerigon.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
use core::iter::Iterator;
use std::collections::BTreeMap;
use std::ops::Deref as _;

use __compat_primitive_types::H160;
use alloy::eips::BlockNumberOrTag;
use alloy::{
providers::Provider,
rpc::types::{eth::BlockId, trace::geth::StructLog, Block, BlockTransactionsKind, Transaction},
rpc::types::{eth::BlockId, Block, BlockTransactionsKind},
transports::Transport,
};
use alloy_primitives::Address;
use anyhow::Context as _;
use evm_arithmetization::{jumpdest::JumpDestTableWitness, CodeDb};
use futures::stream::FuturesOrdered;
use futures::StreamExt as _;
use compat::Compat;
use evm_arithmetization::jumpdest::JumpDestTableWitness;
use serde::Deserialize;
use serde_json::json;
use trace_decoder::{BlockTrace, BlockTraceTriePreImages, CombinedPreImages, TxnInfo, TxnTrace};
use tracing::info;
use trace_decoder::{BlockTrace, BlockTraceTriePreImages, CombinedPreImages, TxnInfo};
use tracing::warn;

use super::{
fetch_other_block_data,
jumpdest::{self, get_normalized_structlog},
JumpdestSrc,
};
use super::{fetch_other_block_data, JumpdestSrc};
use crate::prover::BlockProverInput;
use crate::provider::CachedProvider;
use crate::rpc::jumpdest::{generate_jumpdest_table, get_block_normalized_structlogs};

/// Transaction traces retrieved from Erigon zeroTracer.
#[derive(Debug, Deserialize)]
pub struct ZeroTxResult {
Expand Down Expand Up @@ -67,30 +62,31 @@ where
.get_block(target_block_id, BlockTransactionsKind::Full)
.await?;

let jdts: Vec<Option<(JumpDestTableWitness, CodeDb)>> = match jumpdest_src {
let block_jumpdest_table_witnesses: Vec<Option<JumpDestTableWitness>> = match jumpdest_src {
JumpdestSrc::ProverSimulation => vec![None; tx_results.len()],
JumpdestSrc::ClientFetchedStructlogs => {
// In case of the error with retrieving structlogs from the server,
// continue without interruption. Equivalent to `ProverSimulation` case.
process_transactions(
&block,
cached_provider.get_provider().await?.deref(),
tx_results.iter().map(|TxnInfo { traces, meta: _ }| traces), // &tx_traces,
&tx_results,
)
.await?
.await
.unwrap_or_else(|e| {
warn!("failed to fetch server structlogs for block {target_block_id}: {e}");
Vec::new()
})
}
JumpdestSrc::ServerFetchedStructlogs => todo!("hybrid server bulk struct log retrieval/local jumpdest table generation not yet implemented"),
JumpdestSrc::Serverside => todo!(),
};

let mut code_db = CodeDb::default();
// weave in the JDTs
let txn_info = tx_results
.into_iter()
.zip(jdts)
.map(|(mut tx_info, jdt)| {
tx_info.meta.jumpdest_table = jdt.map(|(j, c)| {
code_db.extend(c);
j
});
.zip(block_jumpdest_table_witnesses)
.map(|(mut tx_info, jdtw)| {
tx_info.meta.jumpdest_table = jdtw;
tx_info
})
.collect();
Expand All @@ -106,81 +102,42 @@ where
.context("invalid hex returned from call to eth_getWitness")?,
}),
txn_info,
code_db,
code_db: Default::default(),
},
other_data,
})
}

/// Processes the transactions in the given block and updates the code db.
pub async fn process_transactions<'i, I, ProviderT, TransportT>(
/// Processes the transactions in the given block, generating jumpdest tables
/// and updates the code database
pub async fn process_transactions<'i, ProviderT, TransportT>(
block: &Block,
provider: &ProviderT,
tx_traces: I,
) -> anyhow::Result<Vec<Option<(JumpDestTableWitness, CodeDb)>>>
tx_results: &[TxnInfo],
) -> anyhow::Result<Vec<Option<JumpDestTableWitness>>>
where
ProviderT: Provider<TransportT>,
TransportT: Transport + Clone,
I: Iterator<Item = &'i BTreeMap<H160, TxnTrace>>,
{
let futures = block
let block_structlogs =
get_block_normalized_structlogs(provider, &BlockNumberOrTag::from(block.header.number))
.await?;

let tx_traces = tx_results
.iter()
.map(|tx| tx.traces.iter().map(|(h, t)| (h.compat(), t)));

let block_jumpdest_tables = block
.transactions
.as_transactions()
.context("No transactions in block")?
.context("no transactions in block")?
.iter()
.zip(block_structlogs)
.zip(tx_traces)
.map(|(tx, tx_trace)| process_transaction(provider, tx, tx_trace))
.collect::<FuturesOrdered<_>>();

futures
.collect::<Vec<_>>()
.await
.into_iter()
.collect::<Result<Vec<_>, _>>()
}

/// Processes the transaction with the given transaction hash and updates the
/// accounts state.
pub async fn process_transaction<ProviderT, TransportT>(
provider: &ProviderT,
tx: &Transaction,
tx_trace: &BTreeMap<H160, TxnTrace>,
) -> anyhow::Result<Option<(JumpDestTableWitness, CodeDb)>>
where
ProviderT: Provider<TransportT>,
TransportT: Transport + Clone,
{
let tx_traces = tx_trace
.iter()
.map(|(h, t)| (Address::from(h.to_fixed_bytes()), t.clone()))
.collect();

let structlog_opt: Option<Vec<StructLog>> = get_normalized_structlog(provider, &tx.hash)
.await
.ok()
.flatten();

let jc: Option<(JumpDestTableWitness, CodeDb)> = structlog_opt.and_then(|struct_log| {
jumpdest::generate_jumpdest_table(tx, &struct_log, &tx_traces).map_or_else(
|error| {
info!(
"{:#?}: JumpDestTable generation failed with reason: {}",
tx.hash, error
);
None
},
|(jdt, code_db)| {
info!(
"{:#?}: JumpDestTable generation succeeded with result: {}",
tx.hash, jdt
);
Some((jdt, code_db))
},
)
});

// TODO
// let jumpdest_table = jc.map(|(j, c)| j);
.map(|((tx, structlog), tx_trace)| {
structlog.and_then(|it| generate_jumpdest_table(tx, &it.1, tx_trace).ok())
})
.collect::<Vec<_>>();

Ok(jc)
Ok(block_jumpdest_tables)
}
Loading
Loading