Skip to content

Commit d57cbea

Browse files
authored
Merge pull request #2130 from eqlabs/krisztian/versioned-constants-cli
feat: add `--rpc.custom-versioned-constants-json-path` CLI option
2 parents f1c7119 + d17888e commit d57cbea

23 files changed

+145
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
### Added
1313

1414
- Pathfinder now creates a new directory if the database path specified does not exist.
15+
- Pathfinder now has a CLI option (`--rpc.custom-versioned-constants-json-path`) to allow loading a custom versioned constants JSON file. When specified the contents of the file is then used instead of the _latest_ constants built into the blockifier crate during execution of Cairo code.
1516

1617
### Fixed
1718

crates/executor/src/call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use super::execution_state::ExecutionState;
1313
use super::felt::{IntoFelt, IntoStarkFelt};
1414

1515
pub fn call(
16-
mut execution_state: ExecutionState<'_>,
16+
execution_state: ExecutionState<'_>,
1717
contract_address: ContractAddress,
1818
entry_point_selector: EntryPoint,
1919
calldata: Vec<CallParam>,

crates/executor/src/estimate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use super::execution_state::ExecutionState;
66
use super::types::FeeEstimate;
77

88
pub fn estimate(
9-
mut execution_state: ExecutionState<'_>,
9+
execution_state: ExecutionState<'_>,
1010
transactions: Vec<Transaction>,
1111
skip_validate: bool,
1212
) -> Result<Vec<FeeEstimate>, TransactionExecutionError> {

crates/executor/src/execution_state.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub const STRK_FEE_TOKEN_ADDRESS: ContractAddress =
2727
contract_address!("0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d");
2828

2929
mod versioned_constants {
30+
use std::borrow::Cow;
31+
3032
use pathfinder_common::StarknetVersion;
3133

3234
use super::VersionedConstants;
@@ -57,16 +59,21 @@ mod versioned_constants {
5759
serde_json::from_slice(BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_1_1).unwrap();
5860
}
5961

60-
pub(super) fn for_version(version: &StarknetVersion) -> &'static VersionedConstants {
62+
pub(super) fn for_version(
63+
version: &StarknetVersion,
64+
custom_versioned_constants: Option<VersionedConstants>,
65+
) -> Cow<'static, VersionedConstants> {
6166
// We use 0.13.0 for all blocks _before_ 0.13.1.
6267
if version < &STARKNET_VERSION_0_13_1 {
63-
&BLOCKIFIER_VERSIONED_CONSTANTS_0_13_0
68+
Cow::Borrowed(&BLOCKIFIER_VERSIONED_CONSTANTS_0_13_0)
6469
} else if version < &STARKNET_VERSION_0_13_1_1 {
65-
&BLOCKIFIER_VERSIONED_CONSTANTS_0_13_1
70+
Cow::Borrowed(&BLOCKIFIER_VERSIONED_CONSTANTS_0_13_1)
6671
} else if version < &STARKNET_VERSION_0_13_2 {
67-
&BLOCKIFIER_VERSIONED_CONSTANTS_0_13_1_1
72+
Cow::Borrowed(&BLOCKIFIER_VERSIONED_CONSTANTS_0_13_1_1)
6873
} else {
69-
VersionedConstants::latest_constants()
74+
custom_versioned_constants
75+
.map(Cow::Owned)
76+
.unwrap_or_else(|| Cow::Borrowed(VersionedConstants::latest_constants()))
7077
}
7178
}
7279
}
@@ -78,13 +85,14 @@ pub struct ExecutionState<'tx> {
7885
execute_on_parent_state: bool,
7986
pending_state: Option<Arc<StateUpdate>>,
8087
allow_use_kzg_data: bool,
88+
custom_versioned_constants: Option<VersionedConstants>,
8189
}
8290

8391
impl<'tx> ExecutionState<'tx> {
8492
pub(super) fn starknet_state(
85-
&mut self,
93+
self,
8694
) -> anyhow::Result<(
87-
CachedState<PendingStateReader<PathfinderStateReader<'_>>>,
95+
CachedState<PendingStateReader<PathfinderStateReader<'tx>>>,
8896
BlockContext,
8997
)> {
9098
let block_number = if self.execute_on_parent_state {
@@ -126,7 +134,10 @@ impl<'tx> ExecutionState<'tx> {
126134
None
127135
};
128136

129-
let versioned_constants = versioned_constants::for_version(&self.header.starknet_version);
137+
let versioned_constants = versioned_constants::for_version(
138+
&self.header.starknet_version,
139+
self.custom_versioned_constants,
140+
);
130141

131142
pre_process_block(
132143
&mut cached_state,
@@ -137,7 +148,7 @@ impl<'tx> ExecutionState<'tx> {
137148
let block_context = BlockContext::new(
138149
block_info,
139150
chain_info,
140-
versioned_constants.to_owned(),
151+
versioned_constants.into_owned(),
141152
BouncerConfig::max(),
142153
);
143154

@@ -230,6 +241,7 @@ impl<'tx> ExecutionState<'tx> {
230241
chain_id: ChainId,
231242
header: BlockHeader,
232243
pending_state: Option<Arc<StateUpdate>>,
244+
custom_versioned_constants: Option<VersionedConstants>,
233245
) -> Self {
234246
Self {
235247
transaction,
@@ -238,6 +250,7 @@ impl<'tx> ExecutionState<'tx> {
238250
pending_state,
239251
execute_on_parent_state: true,
240252
allow_use_kzg_data: true,
253+
custom_versioned_constants,
241254
}
242255
}
243256

@@ -247,6 +260,7 @@ impl<'tx> ExecutionState<'tx> {
247260
header: BlockHeader,
248261
pending_state: Option<Arc<StateUpdate>>,
249262
l1_blob_data_availability: L1BlobDataAvailability,
263+
custom_versioned_constants: Option<VersionedConstants>,
250264
) -> Self {
251265
Self {
252266
transaction,
@@ -255,6 +269,7 @@ impl<'tx> ExecutionState<'tx> {
255269
pending_state,
256270
execute_on_parent_state: false,
257271
allow_use_kzg_data: l1_blob_data_availability == L1BlobDataAvailability::Enabled,
272+
custom_versioned_constants,
258273
}
259274
}
260275
}

crates/executor/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub mod types;
1515
pub use blockifier::execution::contract_class::ClassInfo;
1616
pub use blockifier::transaction::account_transaction::AccountTransaction;
1717
pub use blockifier::transaction::transaction_execution::Transaction;
18+
pub use blockifier::versioned_constants::VersionedConstants;
1819
pub use call::call;
1920
pub use class::{parse_casm_definition, parse_deprecated_class_definition};
2021
pub use error::{CallError, TransactionExecutionError};

crates/executor/src/simulate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl Default for TraceCache {
7474
}
7575

7676
pub fn simulate(
77-
mut execution_state: ExecutionState<'_>,
77+
execution_state: ExecutionState<'_>,
7878
transactions: Vec<Transaction>,
7979
skip_validate: bool,
8080
skip_fee_charge: bool,
@@ -140,7 +140,7 @@ pub fn simulate(
140140
}
141141

142142
pub fn trace(
143-
mut execution_state: ExecutionState<'_>,
143+
execution_state: ExecutionState<'_>,
144144
cache: TraceCache,
145145
block_hash: BlockHash,
146146
transactions: Vec<Transaction>,

crates/pathfinder/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pathfinder-common = { path = "../common" }
4141
pathfinder-compiler = { path = "../compiler" }
4242
pathfinder-crypto = { path = "../crypto" }
4343
pathfinder-ethereum = { path = "../ethereum" }
44+
pathfinder-executor = { path = "../executor" }
4445
pathfinder-merkle-tree = { path = "../merkle-tree" }
4546
pathfinder-retry = { path = "../retry" }
4647
pathfinder-rpc = { path = "../rpc" }

crates/pathfinder/examples/re_execute.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ fn execute(storage: &mut Storage, chain_id: ChainId, work: Work) {
132132

133133
let db_tx = connection.transaction().expect("Create transaction");
134134

135-
let execution_state = ExecutionState::trace(&db_tx, chain_id, work.header.clone(), None);
135+
let execution_state = ExecutionState::trace(&db_tx, chain_id, work.header.clone(), None, None);
136136

137137
let transactions = work
138138
.transactions
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"invalid": "contents"
3+
}

crates/pathfinder/src/bin/pathfinder/config.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::HashSet;
2+
use std::fs::File;
23
use std::net::SocketAddr;
34
use std::num::NonZeroUsize;
45
use std::path::PathBuf;
@@ -11,6 +12,7 @@ use ipnet::IpNet;
1112
use p2p::libp2p::Multiaddr;
1213
use pathfinder_common::consts::VERGEN_GIT_DESCRIBE;
1314
use pathfinder_common::AllowedOrigins;
15+
use pathfinder_executor::VersionedConstants;
1416
use pathfinder_storage::JournalMode;
1517
use reqwest::Url;
1618

@@ -256,6 +258,13 @@ This should only be enabled for debugging purposes as it adds substantial proces
256258
value_parser = parse_state_tries
257259
)]
258260
state_tries: Option<StateTries>,
261+
262+
#[arg(
263+
long = "rpc.custom-versioned-constants-json-path",
264+
long_help = "Path to a JSON file containing the versioned constants to use for execution",
265+
env = "PATHFINDER_RPC_CUSTOM_VERSIONED_CONSTANTS_JSON_PATH"
266+
)]
267+
custom_versioned_constants_path: Option<PathBuf>,
259268
}
260269

261270
#[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq)]
@@ -618,6 +627,35 @@ enum RpcCorsDomainsParseError {
618627
WildcardAmongOtherValues,
619628
}
620629

630+
fn parse_versioned_constants(
631+
path: PathBuf,
632+
) -> Result<VersionedConstants, ParseVersionedConstantsError> {
633+
let file = File::open(path)?;
634+
let reader = std::io::BufReader::new(file);
635+
let versioned_constants = serde_json::from_reader(reader)?;
636+
637+
Ok(versioned_constants)
638+
}
639+
640+
pub fn parse_versioned_constants_or_exit(path: PathBuf) -> VersionedConstants {
641+
use clap::error::ErrorKind;
642+
643+
match parse_versioned_constants(path) {
644+
Ok(versioned_constants) => versioned_constants,
645+
Err(error) => Cli::command()
646+
.error(ErrorKind::ValueValidation, error)
647+
.exit(),
648+
}
649+
}
650+
651+
#[derive(Debug, thiserror::Error)]
652+
enum ParseVersionedConstantsError {
653+
#[error("IO error while reading versioned constants: {0}.")]
654+
Io(#[from] std::io::Error),
655+
#[error("Parse error while loading versioned constants: {0}.")]
656+
Parse(#[from] serde_json::Error),
657+
}
658+
621659
pub struct Config {
622660
pub data_directory: PathBuf,
623661
pub ethereum: Ethereum,
@@ -644,6 +682,7 @@ pub struct Config {
644682
pub get_events_max_blocks_to_scan: NonZeroUsize,
645683
pub get_events_max_uncached_bloom_filters_to_load: NonZeroUsize,
646684
pub state_tries: Option<StateTries>,
685+
pub custom_versioned_constants: Option<VersionedConstants>,
647686
}
648687

649688
pub struct Ethereum {
@@ -928,6 +967,9 @@ impl Config {
928967
.get_events_max_uncached_bloom_filters_to_load,
929968
gateway_timeout: Duration::from_secs(cli.gateway_timeout.get()),
930969
state_tries: cli.state_tries,
970+
custom_versioned_constants: cli
971+
.custom_versioned_constants_path
972+
.map(parse_versioned_constants_or_exit),
931973
}
932974
}
933975
}
@@ -966,8 +1008,10 @@ pub struct WebsocketConfig {
9661008

9671009
#[cfg(test)]
9681010
mod tests {
1011+
use assert_matches::assert_matches;
1012+
9691013
use super::{AllowedOrigins, RpcCorsDomainsParseError};
970-
use crate::config::parse_cors;
1014+
use crate::config::{parse_cors, ParseVersionedConstantsError};
9711015

9721016
#[test]
9731017
fn parse_cors_domains() {
@@ -1043,4 +1087,29 @@ mod tests {
10431087
)
10441088
});
10451089
}
1090+
1091+
#[test]
1092+
fn parse_versioned_constants_fails_if_file_not_found() {
1093+
assert_matches!(
1094+
super::parse_versioned_constants("./nonexistent_versioned_constants.json".into()).unwrap_err(),
1095+
ParseVersionedConstantsError::Io(err) => assert_eq!(err.kind(), std::io::ErrorKind::NotFound)
1096+
);
1097+
}
1098+
1099+
#[test]
1100+
fn parse_versioned_constants_fails_on_parse_error() {
1101+
assert_matches!(
1102+
super::parse_versioned_constants("resources/invalid_versioned_constants.json".into())
1103+
.unwrap_err(),
1104+
ParseVersionedConstantsError::Parse(_)
1105+
)
1106+
}
1107+
1108+
#[test]
1109+
fn parse_versioned_constants_success() {
1110+
super::parse_versioned_constants(
1111+
"../executor/resources/versioned_constants_13_1_1.json".into(),
1112+
)
1113+
.unwrap();
1114+
}
10461115
}

0 commit comments

Comments
 (0)