Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

feat: expose versioned constants from past versions #2049

Merged
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
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ num-rational = { version = "0.4", features = ["serde"] }
num-traits = "0.2"
once_cell = "1.19.0"
papyrus_storage = "0.4.0-dev.4"
paste = "1.0.15"
phf = { version = "0.11", features = ["macros"] }
pretty_assertions = "1.2.1"
pyo3 = "0.19.1"
Expand Down
1 change: 1 addition & 0 deletions crates/blockifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ num-integer.workspace = true
num-rational.workspace = true
num-traits.workspace = true
once_cell.workspace = true
paste.workspace = true
phf.workspace = true
rand = { workspace = true, optional = true }
rstest = { workspace = true, optional = true }
Expand Down
13 changes: 7 additions & 6 deletions crates/blockifier/src/test_utils/struct_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::transaction::objects::{
DeprecatedTransactionInfo, FeeType, TransactionFeeResult, TransactionInfo, TransactionResources,
};
use crate::versioned_constants::{
GasCosts, OsConstants, VersionedConstants, DEFAULT_CONSTANTS_JSON,
GasCosts, OsConstants, VersionedConstants, VERSIONED_CONSTANTS_LATEST_JSON,
};

impl CallEntryPoint {
Expand Down Expand Up @@ -109,11 +109,12 @@ impl TransactionResources {
impl GasCosts {
pub fn create_for_testing_from_subset(subset_of_os_constants: &str) -> Self {
let subset_of_os_constants: Value = serde_json::from_str(subset_of_os_constants).unwrap();
let mut os_constants: Value = serde_json::from_str::<Value>(DEFAULT_CONSTANTS_JSON)
.unwrap()
.get("os_constants")
.unwrap()
.clone();
let mut os_constants: Value =
serde_json::from_str::<Value>(VERSIONED_CONSTANTS_LATEST_JSON)
.unwrap()
.get("os_constants")
.unwrap()
.clone();
update_json_value(&mut os_constants, subset_of_os_constants);
let os_constants: OsConstants = serde_json::from_value(os_constants).unwrap();
os_constants.gas_costs
Expand Down
59 changes: 52 additions & 7 deletions crates/blockifier/src/versioned_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use indexmap::{IndexMap, IndexSet};
use num_rational::Ratio;
use once_cell::sync::Lazy;
use paste::paste;
use serde::de::Error as DeserializationError;
use serde::{Deserialize, Deserializer};
use serde_json::{Map, Number, Value};
use strum::IntoEnumIterator;
use strum_macros::{EnumCount, EnumIter};
use thiserror::Error;

use crate::execution::deprecated_syscalls::hint_processor::SyscallCounter;
Expand All @@ -26,18 +28,56 @@ use crate::transaction::transaction_types::TransactionType;
#[path = "versioned_constants_test.rs"]
pub mod test;

pub(crate) const DEFAULT_CONSTANTS_JSON: &str =
include_str!("../resources/versioned_constants.json");
static DEFAULT_CONSTANTS: Lazy<VersionedConstants> = Lazy::new(|| {
serde_json::from_str(DEFAULT_CONSTANTS_JSON)
.expect("Versioned constants JSON file is malformed")
});
/// Auto-generate getters for listed versioned constants versions.
macro_rules! define_versioned_constants {
($(($variant:ident, $path_to_json:expr)),* $(,)?) => {
/// Enum of all the Starknet versions supporting versioned constants.
#[derive(Clone, Debug, EnumCount, EnumIter, Hash, Eq, PartialEq)]
pub enum StarknetVersion {
$($variant,)*
}

// Static (lazy) instances of the versioned constants.
// For internal use only; for access to a static instance use the `StarknetVersion` enum.
paste! {
$(
pub(crate) const [<VERSIONED_CONSTANTS_ $variant:upper _JSON>]: &str =
include_str!($path_to_json);
static [<VERSIONED_CONSTANTS_ $variant:upper>]: Lazy<VersionedConstants> = Lazy::new(|| {
serde_json::from_str([<VERSIONED_CONSTANTS_ $variant:upper _JSON>])
.expect(&format!("Versioned constants {} is malformed.", $path_to_json))
});
)*
}

/// API to access a static instance of the versioned constants.
impl From<StarknetVersion> for &'static VersionedConstants {
fn from(version: StarknetVersion) -> Self {
match version {
$(
StarknetVersion::$variant => {
& paste! { [<VERSIONED_CONSTANTS_ $variant:upper>] }
}
)*
}
}
}
};
}

define_versioned_constants! {
(V0_13_0, "../resources/versioned_constants_13_0.json"),
(V0_13_1, "../resources/versioned_constants_13_1.json"),
(V0_13_1_1, "../resources/versioned_constants_13_1_1.json"),
(Latest, "../resources/versioned_constants.json"),
}

pub type ResourceCost = Ratio<u128>;

/// Contains constants for the Blockifier that may vary between versions.
/// Additional constants in the JSON file, not used by Blockifier but included for transparency, are
/// automatically ignored during deserialization.
/// Instances of this struct for specific Starknet versions can be selected by using the above enum.
#[derive(Clone, Debug, Default, Deserialize)]
pub struct VersionedConstants {
// Limits.
Expand Down Expand Up @@ -68,10 +108,15 @@ pub struct VersionedConstants {
}

impl VersionedConstants {
/// Get the constants for the specified Starknet version.
pub fn get(version: StarknetVersion) -> &'static Self {
version.into()
}

/// Get the constants that shipped with the current version of the Blockifier.
/// To use custom constants, initialize the struct from a file using `try_from`.
pub fn latest_constants() -> &'static Self {
&DEFAULT_CONSTANTS
Self::get(StarknetVersion::Latest)
}

/// Returns the initial gas of any transaction to run with.
Expand Down
19 changes: 14 additions & 5 deletions crates/blockifier/src/versioned_constants_test.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
use cairo_vm::types::builtin_name::BuiltinName;
use glob::glob;
use glob::{glob, Paths};
use pretty_assertions::assert_eq;

use super::*;

// TODO: Test Starknet OS validation.
// TODO: Add an unallowed field scenario for GasCost parsing.

/// Returns all JSON files in the resources directory (should be all versioned constants files).
fn all_jsons_in_dir() -> Paths {
glob(format!("{}/resources/*.json", env!("CARGO_MANIFEST_DIR")).as_str()).unwrap()
}

#[test]
fn test_successful_gas_costs_parsing() {
let json_data = r#"
Expand Down Expand Up @@ -70,7 +75,7 @@ fn get_json_value_without_defaults() -> serde_json::Value {
"max_recursion_depth": 2
}"#;
// Fill the os constants with the gas cost values (do not have a default value).
let mut os_constants: Value = serde_json::from_str::<Value>(DEFAULT_CONSTANTS_JSON)
let mut os_constants: Value = serde_json::from_str::<Value>(VERSIONED_CONSTANTS_LATEST_JSON)
.unwrap()
.get("os_constants")
.unwrap()
Expand All @@ -91,7 +96,7 @@ fn get_json_value_without_defaults() -> serde_json::Value {
#[test]
fn test_versioned_constants_base_overrides() {
// Create a versioned constants copy with a modified value for `invoke_tx_max_n_steps`.
let mut versioned_constants_base_overrides = DEFAULT_CONSTANTS.clone();
let mut versioned_constants_base_overrides = VERSIONED_CONSTANTS_LATEST.clone();
versioned_constants_base_overrides.invoke_tx_max_n_steps += 1;

let result = VersionedConstants::get_versioned_constants(VersionedConstantsOverrides {
Expand Down Expand Up @@ -218,9 +223,13 @@ fn test_invalid_number() {

#[test]
fn test_old_json_parsing() {
let files = glob(format!("{}/resources/*.json", env!("CARGO_MANIFEST_DIR")).as_str()).unwrap();
for file in files.map(Result::unwrap) {
for file in all_jsons_in_dir().map(Result::unwrap) {
serde_json::from_reader::<_, VersionedConstants>(&std::fs::File::open(&file).unwrap())
.unwrap_or_else(|_| panic!("Versioned constants JSON file {file:#?} is malformed"));
}
}

#[test]
fn test_all_jsons_in_enum() {
assert_eq!(StarknetVersion::iter().count(), all_jsons_in_dir().count());
}
Loading