Skip to content
Draft
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
19 changes: 18 additions & 1 deletion crates/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::ops::Rem;
use std::str::FromStr;

use anyhow::Context;
use fake::Dummy;
use fake::{Dummy, Fake, Faker};
use pathfinder_crypto::hash::HashChain;
use pathfinder_crypto::Felt;
use primitive_types::H160;
Expand Down Expand Up @@ -342,6 +342,23 @@ impl<T> Dummy<T> for EthereumAddress {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum SettlementLayerAddress {
Ethereum(EthereumAddress),
Starknet(ContractAddress),
}

impl<T> Dummy<T> for SettlementLayerAddress {
fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &T, rng: &mut R) -> Self {
if rng.gen_bool(0.5) {
Self::Ethereum(EthereumAddress(H160::random_using(rng)))
} else {
Self::Starknet(Faker.fake_with_rng(rng))
}
}
}


#[derive(Debug, thiserror::Error)]
#[error("expected slice length of 16 or less, got {0}")]
pub struct FromSliceError(usize);
Expand Down
4 changes: 4 additions & 0 deletions crates/consensus-fetcher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ fn get_proposer_contract_address(
pub fn get_validators_at_height(
storage: &Storage,
chain_id: ChainId,
is_l3: bool,
height: u64,
) -> Result<Vec<ValidatorInfo>, ConsensusFetcherError> {
let mut db_conn = storage
Expand All @@ -146,6 +147,7 @@ pub fn get_validators_at_height(
// Create execution state for call
let execution_state = ExecutionState::simulation(
chain_id,
is_l3,
header,
None, // No pending state for this call
L1BlobDataAvailability::Disabled,
Expand Down Expand Up @@ -182,6 +184,7 @@ pub fn get_validators_at_height(
pub fn get_proposers_at_height(
storage: &Storage,
chain_id: ChainId,
is_l3: bool,
height: u64,
) -> Result<Vec<ProposerInfo>, ConsensusFetcherError> {
let mut db_conn = storage
Expand All @@ -205,6 +208,7 @@ pub fn get_proposers_at_height(
// Create execution state for call
let execution_state = ExecutionState::simulation(
chain_id,
is_l3,
header,
None, // No pending state for this call
L1BlobDataAvailability::Disabled,
Expand Down
11 changes: 11 additions & 0 deletions crates/executor/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ type ReceiptAndEvents = (Receipt, Vec<pathfinder_common::event::Event>);
impl BlockExecutor {
pub fn new(
chain_id: ChainId,
is_l3: bool,
block_info: BlockInfo,
eth_fee_address: ContractAddress,
strk_fee_address: ContractAddress,
db_conn: pathfinder_storage::Connection,
) -> anyhow::Result<Self> {
let execution_state = ExecutionState::validation(
chain_id,
is_l3,
block_info,
None,
Default::default(),
Expand Down Expand Up @@ -67,6 +69,7 @@ impl BlockExecutor {
/// the final state of a previous executor
pub fn new_with_initial_state(
chain_id: ChainId,
is_l3: bool,
block_info: BlockInfo,
eth_fee_address: ContractAddress,
strk_fee_address: ContractAddress,
Expand All @@ -75,6 +78,7 @@ impl BlockExecutor {
) -> anyhow::Result<Self> {
let execution_state = ExecutionState::validation(
chain_id,
is_l3,
block_info,
None,
Default::default(),
Expand Down Expand Up @@ -505,6 +509,7 @@ mod tests {
// Execute them all in a single executor
let mut single_executor = BlockExecutor::new(
chain_id,
false,
block_info,
ETH_FEE_TOKEN_ADDRESS,
STRK_FEE_TOKEN_ADDRESS,
Expand All @@ -527,6 +532,7 @@ mod tests {
// Execute batch 1
let mut executor1 = BlockExecutor::new(
chain_id,
false,
block_info,
ETH_FEE_TOKEN_ADDRESS,
STRK_FEE_TOKEN_ADDRESS,
Expand All @@ -542,6 +548,7 @@ mod tests {
// Execute batch 2 with state from batch 1
let mut executor2 = BlockExecutor::new_with_initial_state(
chain_id,
false,
block_info,
ETH_FEE_TOKEN_ADDRESS,
STRK_FEE_TOKEN_ADDRESS,
Expand All @@ -558,6 +565,7 @@ mod tests {
// Execute batch 3 with state from batch 2
let mut executor3 = BlockExecutor::new_with_initial_state(
chain_id,
false,
block_info,
ETH_FEE_TOKEN_ADDRESS,
STRK_FEE_TOKEN_ADDRESS,
Expand Down Expand Up @@ -616,6 +624,7 @@ mod tests {
// Single executor execution
let mut single_executor = BlockExecutor::new(
chain_id,
false,
block_info,
ETH_FEE_TOKEN_ADDRESS,
STRK_FEE_TOKEN_ADDRESS,
Expand Down Expand Up @@ -643,6 +652,7 @@ mod tests {

let mut current_executor = BlockExecutor::new(
chain_id,
false,
block_info,
ETH_FEE_TOKEN_ADDRESS,
STRK_FEE_TOKEN_ADDRESS,
Expand All @@ -655,6 +665,7 @@ mod tests {
for batch in batches.into_iter() {
current_executor = BlockExecutor::new(
chain_id,
false,
block_info,
ETH_FEE_TOKEN_ADDRESS,
STRK_FEE_TOKEN_ADDRESS,
Expand Down
9 changes: 8 additions & 1 deletion crates/executor/src/execution_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ pub struct ExecutionState {
eth_fee_address: ContractAddress,
strk_fee_address: ContractAddress,
native_class_cache: Option<NativeClassCache>,
is_l3: bool,
}

pub fn create_executor<S: StorageAdapter + Clone>(
Expand Down Expand Up @@ -320,7 +321,7 @@ impl ExecutionState {
strk_fee_token_address,
eth_fee_token_address,
},
is_l3: false,
is_l3: self.is_l3,
})
}

Expand Down Expand Up @@ -401,6 +402,7 @@ impl ExecutionState {
#[allow(clippy::too_many_arguments)]
pub fn trace(
chain_id: ChainId,
is_l3: bool,
header: BlockHeader,
pending_state: Option<Arc<StateUpdate>>,
versioned_constants_map: VersionedConstantsMap,
Expand All @@ -418,12 +420,14 @@ impl ExecutionState {
eth_fee_address,
strk_fee_address,
native_class_cache,
is_l3,
}
}

#[allow(clippy::too_many_arguments)]
pub fn simulation(
chain_id: ChainId,
is_l3: bool,
header: BlockHeader,
pending_state: Option<Arc<StateUpdate>>,
l1_blob_data_availability: L1BlobDataAvailability,
Expand All @@ -442,12 +446,14 @@ impl ExecutionState {
eth_fee_address,
strk_fee_address,
native_class_cache,
is_l3,
}
}

#[allow(clippy::too_many_arguments)]
pub fn validation(
chain_id: ChainId,
is_l3: bool,
block_info: BlockInfo,
pending_state: Option<Arc<StateUpdate>>,
versioned_constants_map: VersionedConstantsMap,
Expand All @@ -465,6 +471,7 @@ impl ExecutionState {
eth_fee_address,
strk_fee_address,
native_class_cache,
is_l3,
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions crates/gateway-types/src/reply.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Structures used for deserializing replies from Starkware's sequencer REST
//! API.
use pathfinder_common::prelude::*;
use pathfinder_serde::{EthereumAddressAsHexStr, GasPriceAsHexStr};
use pathfinder_common::{SettlementLayerAddress, prelude::*};
use pathfinder_serde::{GasPriceAsHexStr, SettlementLayerAddressAsHexStr};
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
pub use transaction::DataAvailabilityMode;
Expand Down Expand Up @@ -269,12 +269,12 @@ pub mod transaction_status {
/// Types used when deserializing L2 transaction related data.
pub mod transaction {
use fake::{Dummy, Fake, Faker};
use pathfinder_common::prelude::*;
use pathfinder_common::{SettlementLayerAddress, prelude::*};
use pathfinder_crypto::Felt;
use pathfinder_serde::{
CallParamAsDecimalStr,
ConstructorParamAsDecimalStr,
EthereumAddressAsHexStr,
SettlementLayerAddressAsHexStr,
L1ToL2MessagePayloadElemAsDecimalStr,
L2ToL1MessagePayloadElemAsDecimalStr,
ResourceAmountAsHexStr,
Expand Down Expand Up @@ -535,8 +535,8 @@ pub mod transaction {
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct L1ToL2Message {
#[serde_as(as = "EthereumAddressAsHexStr")]
pub from_address: EthereumAddress,
#[serde_as(as = "SettlementLayerAddressAsHexStr")]
pub from_address: SettlementLayerAddress,
#[serde_as(as = "Vec<L1ToL2MessagePayloadElemAsDecimalStr>")]
pub payload: Vec<L1ToL2MessagePayloadElem>,
pub selector: EntryPoint,
Expand Down Expand Up @@ -2220,8 +2220,8 @@ pub mod state_update {
#[derive(Clone, Debug, Deserialize)]
pub struct EthContractAddresses {
#[serde(rename = "Starknet")]
#[serde_as(as = "EthereumAddressAsHexStr")]
pub starknet: EthereumAddress,
#[serde_as(as = "SettlementLayerAddressAsHexStr")]
pub starknet: SettlementLayerAddress,

pub strk_l2_token_address: Option<ContractAddress>,

Expand Down
1 change: 1 addition & 0 deletions crates/pathfinder/examples/re_execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ fn execute(

let execution_state = ExecutionState::trace(
chain_id,
false,
work.header.clone(),
None,
Default::default(),
Expand Down
40 changes: 35 additions & 5 deletions crates/pathfinder/src/bin/pathfinder/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ Hint: This is usually caused by exceeding the file descriptor limit of your syst
execution_storage,
sync_state.clone(),
pathfinder_context.network_id,
pathfinder_context.is_l3,
pathfinder_context.contract_addresses,
pathfinder_context.gateway.clone(),
rx_pending.clone(),
Expand Down Expand Up @@ -736,6 +737,7 @@ If you are trying to connect to a custom Starknet on another Ethereum network, p
struct PathfinderContext {
network: Chain,
network_id: ChainId,
is_l3: bool,
gateway: starknet_gateway_client::Client,
database: PathBuf,
contract_addresses: EthContractAddresses,
Expand All @@ -747,7 +749,7 @@ mod pathfinder_context {
use std::time::Duration;

use anyhow::Context;
use pathfinder_common::{Chain, ChainId};
use pathfinder_common::{Chain, ChainId, SettlementLayerAddress};
use pathfinder_ethereum::core_addr;
use pathfinder_rpc::context::EthContractAddresses;
use reqwest::Url;
Expand All @@ -767,20 +769,23 @@ mod pathfinder_context {
NetworkConfig::Mainnet => Self {
network: Chain::Mainnet,
network_id: ChainId::MAINNET,
is_l3: false,
gateway: GatewayClient::mainnet(gateway_timeout).with_api_key(api_key),
database: data_directory.join("mainnet.sqlite"),
contract_addresses: EthContractAddresses::new_known(core_addr::MAINNET),
},
NetworkConfig::SepoliaTestnet => Self {
network: Chain::SepoliaTestnet,
network_id: ChainId::SEPOLIA_TESTNET,
is_l3: false,
gateway: GatewayClient::sepolia_testnet(gateway_timeout).with_api_key(api_key),
database: data_directory.join("testnet-sepolia.sqlite"),
contract_addresses: EthContractAddresses::new_known(core_addr::SEPOLIA_TESTNET),
},
NetworkConfig::SepoliaIntegration => Self {
network: Chain::SepoliaIntegration,
network_id: ChainId::SEPOLIA_INTEGRATION,
is_l3: false,
gateway: GatewayClient::sepolia_integration(gateway_timeout)
.with_api_key(api_key),
database: data_directory.join("integration-sepolia.sqlite"),
Expand All @@ -792,10 +797,12 @@ mod pathfinder_context {
gateway,
feeder_gateway,
chain_id,
is_l3,
} => Self::configure_custom(
gateway,
feeder_gateway,
chain_id,
is_l3,
data_directory,
api_key,
gateway_timeout,
Expand All @@ -815,6 +822,7 @@ mod pathfinder_context {
gateway: Url,
feeder: Url,
chain_id: String,
is_l3: bool,
data_directory: &Path,
api_key: Option<String>,
gateway_timeout: Duration,
Expand All @@ -833,7 +841,30 @@ mod pathfinder_context {
.eth_contract_addresses()
.await
.context("Downloading starknet L1 address from gateway for proxy check")?;
let l1_core_address = reply_contract_addresses.starknet.0;

let l1_core_address = if is_l3 {
// For L3 networks, assert we got Starknet variant (ContractAddress)
match reply_contract_addresses.starknet {
SettlementLayerAddress::Starknet(_contract_address) => {
// TODO(mehul 14/11/2025): This is a placeholder return. L1 syncing for L3 networks would
// require significant changes that are not prioritized for pathfinder.
// Returning 0 address as a dummy return
primitive_types::H160::zero()
Comment thread
Mohiiit marked this conversation as resolved.
}
SettlementLayerAddress::Ethereum(_) => {
anyhow::bail!("L3 networks should have ContractAddress (Starknet variant) in starknet field, but got EthereumAddress (Ethereum variant)");
}
}
} else {
// For L2 networks, assert we got Ethereum variant (EthereumAddress)
match reply_contract_addresses.starknet {
SettlementLayerAddress::Starknet(_) => {
anyhow::bail!("L2 networks should have EthereumAddress (Ethereum variant) in starknet field, but got ContractAddress (Starknet variant)");
}
SettlementLayerAddress::Ethereum(address) => address.0,
}
};

let contract_addresses = EthContractAddresses::new_custom(
l1_core_address,
reply_contract_addresses.eth_l2_token_address,
Expand All @@ -856,6 +887,7 @@ mod pathfinder_context {
let context = Self {
network,
network_id,
is_l3,
gateway,
database: data_directory.join("custom.sqlite"),
contract_addresses,
Expand Down Expand Up @@ -902,9 +934,7 @@ async fn verify_database(

if let Some(database_genesis) = db_genesis {
use pathfinder_common::consts::{
MAINNET_GENESIS_HASH,
SEPOLIA_INTEGRATION_GENESIS_HASH,
SEPOLIA_TESTNET_GENESIS_HASH,
MAINNET_GENESIS_HASH, SEPOLIA_INTEGRATION_GENESIS_HASH, SEPOLIA_TESTNET_GENESIS_HASH,
};

let db_network = match database_genesis {
Expand Down
Loading