diff --git a/Cargo.lock b/Cargo.lock index 9523471f4f..2e71159eac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8209,6 +8209,7 @@ dependencies = [ "lazy_static", "num-bigint", "num-traits 0.2.19", + "postcard", "rand 0.8.5", "rstest 0.18.2", "serde", diff --git a/Cargo.toml b/Cargo.toml index 891b43e876..9757979d72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -174,6 +174,7 @@ metrics = "0.23.0" num-traits = { version = "0.2", default-features = false } once_cell = "1.0" parking_lot = "0.12.1" +postcard = { version = "1.0.10", features = [ "use-std" ], default-features = false } pretty_assertions = "1.2.1" rand = "0.8.5" rayon = "1.8.0" diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index 6268e9d0a0..cb359ad1d7 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -7,7 +7,6 @@ use katana_primitives::block::{ use katana_primitives::chain_spec::ChainSpec; use katana_primitives::env::BlockEnv; use katana_primitives::transaction::TxHash; -use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_primitives::Felt; use katana_provider::traits::block::{BlockHashProvider, BlockWriter}; use parking_lot::RwLock; @@ -66,7 +65,7 @@ impl Backend { let partial_header = PartialHeader { number: block_number, parent_hash: prev_hash, - version: CURRENT_STARKNET_VERSION, + version: self.chain_spec.version.clone(), timestamp: block_env.timestamp, sequencer_address: block_env.sequencer_address, gas_prices: GasPrices { diff --git a/crates/katana/core/src/service/block_producer.rs b/crates/katana/core/src/service/block_producer.rs index ef0829828d..1507da154f 100644 --- a/crates/katana/core/src/service/block_producer.rs +++ b/crates/katana/core/src/service/block_producer.rs @@ -14,7 +14,6 @@ use katana_primitives::block::{BlockHashOrNumber, ExecutableBlock, PartialHeader use katana_primitives::receipt::Receipt; use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{ExecutableTxWithHash, TxHash, TxWithHash}; -use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_provider::error::ProviderError; use katana_provider::traits::block::{BlockHashProvider, BlockNumberProvider}; use katana_provider::traits::env::BlockEnvProvider; @@ -581,7 +580,7 @@ impl InstantBlockProducer { timestamp: block_env.timestamp, gas_prices: block_env.l1_gas_prices.clone(), sequencer_address: block_env.sequencer_address, - version: CURRENT_STARKNET_VERSION, + version: backend.chain_spec.version.clone(), }, }; diff --git a/crates/katana/executor/tests/fixtures/mod.rs b/crates/katana/executor/tests/fixtures/mod.rs index e677ba743c..5f6ef2dd4b 100644 --- a/crates/katana/executor/tests/fixtures/mod.rs +++ b/crates/katana/executor/tests/fixtures/mod.rs @@ -21,7 +21,7 @@ use katana_primitives::transaction::{ ExecutableTxWithHash, InvokeTx, InvokeTxV1, }; use katana_primitives::utils::class::{parse_compiled_class, parse_sierra_class}; -use katana_primitives::version::Version; +use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_primitives::{address, Felt}; use katana_provider::providers::in_memory::InMemoryProvider; use katana_provider::traits::block::BlockWriter; @@ -88,7 +88,7 @@ pub fn state_provider(chain: &ChainSpec) -> Box { /// [state_provider]. #[rstest::fixture] pub fn valid_blocks() -> [ExecutableBlock; 3] { - let version = Version::new(0, 13, 0); + let version = CURRENT_STARKNET_VERSION; let chain_id = ChainId::parse("KATANA").unwrap(); let sequencer_address = ContractAddress(1u64.into()); @@ -102,7 +102,7 @@ pub fn valid_blocks() -> [ExecutableBlock; 3] { [ ExecutableBlock { header: PartialHeader { - version, + version: version.clone(), number: 1, timestamp: 100, sequencer_address, @@ -150,7 +150,7 @@ pub fn valid_blocks() -> [ExecutableBlock; 3] { }, ExecutableBlock { header: PartialHeader { - version, + version: version.clone(), number: 2, timestamp: 200, sequencer_address, diff --git a/crates/katana/node/src/lib.rs b/crates/katana/node/src/lib.rs index e3e8765c7b..bbff280bad 100644 --- a/crates/katana/node/src/lib.rs +++ b/crates/katana/node/src/lib.rs @@ -33,6 +33,7 @@ use katana_pool::validation::stateful::TxValidator; use katana_pool::TxPool; use katana_primitives::block::FinalityStatus; use katana_primitives::env::{CfgEnv, FeeTokenAddressses}; +use katana_primitives::version::ProtocolVersion; use katana_provider::providers::fork::ForkedProvider; use katana_provider::providers::in_memory::InMemoryProvider; use katana_rpc::dev::DevApi; @@ -204,6 +205,8 @@ pub async fn build(mut config: Config) -> Result { panic!("block to be forked is a pending block") }; + config.chain.version = ProtocolVersion::parse(&block.starknet_version)?; + // adjust the genesis to match the forked block config.chain.genesis.number = block.block_number; config.chain.genesis.state_root = block.new_root; diff --git a/crates/katana/primitives/Cargo.toml b/crates/katana/primitives/Cargo.toml index 8f12ad5ff8..4c66693811 100644 --- a/crates/katana/primitives/Cargo.toml +++ b/crates/katana/primitives/Cargo.toml @@ -28,6 +28,7 @@ num-bigint = "0.4.6" [dev-dependencies] assert_matches.workspace = true +postcard.workspace = true rstest.workspace = true similar-asserts.workspace = true diff --git a/crates/katana/primitives/src/block.rs b/crates/katana/primitives/src/block.rs index 1de908aa74..21579bd2bd 100644 --- a/crates/katana/primitives/src/block.rs +++ b/crates/katana/primitives/src/block.rs @@ -2,7 +2,7 @@ use starknet::core::crypto::compute_hash_on_elements; use crate::contract::ContractAddress; use crate::transaction::{ExecutableTxWithHash, TxHash, TxWithHash}; -use crate::version::Version; +use crate::version::ProtocolVersion; use crate::Felt; pub type BlockIdOrTag = starknet::core::types::BlockId; @@ -37,7 +37,7 @@ pub struct PartialHeader { pub gas_prices: GasPrices, pub timestamp: u64, pub sequencer_address: ContractAddress, - pub version: Version, + pub version: ProtocolVersion, } /// The L1 gas prices. @@ -68,7 +68,7 @@ pub struct Header { pub timestamp: u64, pub state_root: Felt, pub sequencer_address: ContractAddress, - pub version: Version, + pub protocol_version: ProtocolVersion, } impl Header { @@ -76,7 +76,7 @@ impl Header { Self { state_root, number: partial_header.number, - version: partial_header.version, + protocol_version: partial_header.version, timestamp: partial_header.timestamp, gas_prices: partial_header.gas_prices, parent_hash: partial_header.parent_hash, diff --git a/crates/katana/primitives/src/chain_spec.rs b/crates/katana/primitives/src/chain_spec.rs index cbb7beca0c..fe9ee61379 100644 --- a/crates/katana/primitives/src/chain_spec.rs +++ b/crates/katana/primitives/src/chain_spec.rs @@ -20,7 +20,7 @@ use crate::genesis::constant::{ use crate::genesis::Genesis; use crate::state::StateUpdatesWithDeclaredClasses; use crate::utils::split_u256; -use crate::version::CURRENT_STARKNET_VERSION; +use crate::version::{ProtocolVersion, CURRENT_STARKNET_VERSION}; /// A chain specification. // TODO: include l1 core contract @@ -33,6 +33,8 @@ pub struct ChainSpec { pub genesis: Genesis, /// The chain fee token contract. pub fee_contracts: FeeContracts, + /// The protocol version. + pub version: ProtocolVersion, } /// Tokens that can be used for transaction fee payments in the chain. As @@ -49,7 +51,7 @@ pub struct FeeContracts { impl ChainSpec { pub fn block(&self) -> Block { let header = Header { - version: CURRENT_STARKNET_VERSION, + protocol_version: self.version.clone(), number: self.genesis.number, timestamp: self.genesis.timestamp, state_root: self.genesis.state_root, @@ -155,7 +157,7 @@ lazy_static! { let id = ChainId::parse("KATANA").unwrap(); let genesis = Genesis::default(); let fee_contracts = FeeContracts { eth: DEFAULT_ETH_FEE_TOKEN_ADDRESS, strk: DEFAULT_STRK_FEE_TOKEN_ADDRESS }; - ChainSpec { id, genesis, fee_contracts } + ChainSpec { id, genesis, fee_contracts, version: CURRENT_STARKNET_VERSION } }; } @@ -314,6 +316,7 @@ mod tests { ]; let chain_spec = ChainSpec { id: ChainId::SEPOLIA, + version: CURRENT_STARKNET_VERSION, genesis: Genesis { classes, allocations: BTreeMap::from(allocations.clone()), @@ -340,7 +343,7 @@ mod tests { parent_hash: chain_spec.genesis.parent_hash, sequencer_address: chain_spec.genesis.sequencer_address, gas_prices: chain_spec.genesis.gas_prices.clone(), - version: CURRENT_STARKNET_VERSION, + protocol_version: CURRENT_STARKNET_VERSION, }, body: Vec::new(), }; @@ -356,7 +359,7 @@ mod tests { assert_eq!(actual_block.header.parent_hash, expected_block.header.parent_hash); assert_eq!(actual_block.header.sequencer_address, expected_block.header.sequencer_address); assert_eq!(actual_block.header.gas_prices, expected_block.header.gas_prices); - assert_eq!(actual_block.header.version, expected_block.header.version); + assert_eq!(actual_block.header.protocol_version, expected_block.header.protocol_version); assert_eq!(actual_block.body, expected_block.body); if cfg!(feature = "slot") { diff --git a/crates/katana/primitives/src/version.rs b/crates/katana/primitives/src/version.rs index 0c8b7fddf9..bd063b1c88 100644 --- a/crates/katana/primitives/src/version.rs +++ b/crates/katana/primitives/src/version.rs @@ -1,87 +1,177 @@ -use anyhow::anyhow; - /// The currently supported version of the Starknet protocol. -pub static CURRENT_STARKNET_VERSION: Version = Version::new(0, 12, 2); // version 0.12.2 +pub const CURRENT_STARKNET_VERSION: ProtocolVersion = ProtocolVersion::new([0, 13, 1, 1]); // version 0.13.1.1 +// TODO: figure out the exact format of the version string. /// Starknet protocol version. -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Version { - major: u64, - minor: u64, - patch: u64, +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ProtocolVersion { + /// Each segments represents a part of the version number. + segments: [u8; 4], +} + +#[derive(Debug, thiserror::Error)] +pub enum ParseVersionError { + #[error("invalid version format")] + InvalidFormat, + #[error("failed to parse segment: {0}")] + ParseSegment(#[from] std::num::ParseIntError), } -impl Version { - pub const fn new(major: u64, minor: u64, patch: u64) -> Self { - Self { major, minor, patch } +impl ProtocolVersion { + pub const fn new(segments: [u8; 4]) -> Self { + Self { segments } } - pub fn parse(version: &str) -> anyhow::Result { - let mut parts = version.split('.'); + /// Parses a version string in the format `x.y.z.w` where x, y, z, w are u8 numbers. + /// The string can have fewer than 4 segments; missing segments are filled with zeros. + pub fn parse(version: &str) -> Result { + if version.is_empty() { + return Err(ParseVersionError::InvalidFormat); + } + + let segments = version.split('.').collect::>(); - if parts.clone().count() > 3 { - return Err(anyhow!("invalid version format")); + if segments.len() > 4 { + return Err(ParseVersionError::InvalidFormat); } - let major = parts.next().map(|s| s.parse::()).transpose()?.unwrap_or_default(); - let minor = parts.next().map(|s| s.parse::()).transpose()?.unwrap_or_default(); - let patch = parts.next().map(|s| s.parse::()).transpose()?.unwrap_or_default(); + let mut buffer = [0u8; 4]; + for (buf, seg) in buffer.iter_mut().zip(segments) { + *buf = if seg.is_empty() { 0 } else { seg.parse::()? }; + } + + Ok(Self::new(buffer)) + } +} + +impl core::default::Default for ProtocolVersion { + fn default() -> Self { + ProtocolVersion::new([0, 1, 0, 0]) + } +} + +// Formats the version as a string, where each segment is separated by a dot. +// The last segment (fourth part) will not be printed if it's zero. +// +// For example: +// - Version::new([1, 2, 3, 4]) will be displayed as "1.2.3.4" +// - Version::new([1, 2, 3, 0]) will be displayed as "1.2.3" +// - Version::new([0, 2, 3, 0]) will be displayed as "0.2.3" +impl core::fmt::Display for ProtocolVersion { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + for (idx, segment) in self.segments.iter().enumerate() { + // If it's the last segment, don't print it if it's zero. + if idx == self.segments.len() - 1 { + if *segment != 0 { + write!(f, ".{segment}")?; + } + } else if idx == 0 { + write!(f, "{segment}")?; + } else { + write!(f, ".{segment}")?; + } + } - Ok(Self::new(major, minor, patch)) + Ok(()) } } -impl std::fmt::Display for Version { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{major}.{minor}.{patch}", - major = self.major, - minor = self.minor, - patch = self.patch - ) +impl TryFrom for ProtocolVersion { + type Error = ParseVersionError; + fn try_from(value: String) -> Result { + ProtocolVersion::parse(&value) + } +} + +#[cfg(feature = "serde")] +mod serde { + use super::*; + + // We de/serialize the version from/into a human-readable string format to prevent breaking the + // database encoding format if ever decide to change its memory representation. + + impl ::serde::Serialize for ProtocolVersion { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.to_string()) + } + } + + impl<'de> ::serde::Deserialize<'de> for ProtocolVersion { + fn deserialize>(deserializer: D) -> Result { + let s = String::deserialize(deserializer)?; + ProtocolVersion::parse(&s).map_err(::serde::de::Error::custom) + } } } #[cfg(test)] mod tests { + use super::*; #[test] - fn parse_semver_valid() { - let version = "1.9.0"; - let parsed = super::Version::parse(version).unwrap(); - assert_eq!(parsed.major, 1); - assert_eq!(parsed.minor, 9); - assert_eq!(parsed.patch, 0); + fn parse_version_valid() { + let version = "1.9.0.0"; + let parsed = ProtocolVersion::parse(version).unwrap(); + assert_eq!(parsed.segments, [1, 9, 0, 0]); assert_eq!(String::from("1.9.0"), parsed.to_string()); } #[test] - fn parse_semver_missing_parts() { - let version = "1.9"; - let parsed = super::Version::parse(version).unwrap(); - assert_eq!(parsed.major, 1); - assert_eq!(parsed.minor, 9); - assert_eq!(parsed.patch, 0); - assert_eq!(String::from("1.9.0"), parsed.to_string()); + fn parse_version_missing_parts() { + let version = "1.9.0"; + let parsed = ProtocolVersion::parse(version).unwrap(); + assert_eq!(parsed.segments, [1, 9, 0, 0]); + assert_eq!("1.9.0", parsed.to_string()); } #[test] - fn parse_semver_invalid_digit_should_fail() { - let version = "0.fv.1"; - assert!(super::Version::parse(version).is_err()); + fn parse_version_invalid_digit_should_fail() { + let version = "0.fv.1.0"; + assert!(ProtocolVersion::parse(version).is_err()); } #[test] - fn parse_semver_missing_digit_should_fail() { - let version = "1.."; - assert!(super::Version::parse(version).is_err()); + fn parse_version_missing_digit_default_zero() { + let version = "1..."; + let parsed = ProtocolVersion::parse(version).unwrap(); + assert_eq!(parsed.segments, [1, 0, 0, 0]); + assert_eq!("1.0.0", parsed.to_string()); } #[test] - fn parse_semver_too_many_parts_should_fail() { + fn parse_version_many_parts_should_succeed() { let version = "1.2.3.4"; - assert!(super::Version::parse(version).is_err()); + let parsed = ProtocolVersion::parse(version).unwrap(); + assert_eq!(parsed.segments, [1, 2, 3, 4]); + assert_eq!("1.2.3.4", parsed.to_string()); + } + + #[test] + fn parse_invalid_formats() { + let version = ""; + assert!(ProtocolVersion::parse(version).is_err()); + let version = "1.2.3.4.5"; + assert!(ProtocolVersion::parse(version).is_err()); + } + + #[cfg(feature = "serde")] + mod serde { + use super::*; + + #[test] + fn rt_human_readable() { + let version = ProtocolVersion::new([1, 2, 3, 4]); + let serialized = serde_json::to_string(&version).unwrap(); + let deserialized: ProtocolVersion = serde_json::from_str(&serialized).unwrap(); + assert_eq!(version, deserialized); + } + + #[test] + fn rt_non_human_readable() { + let version = ProtocolVersion::new([1, 2, 3, 4]); + let serialized = postcard::to_stdvec(&version).unwrap(); + let deserialized: ProtocolVersion = postcard::from_bytes(&serialized).unwrap(); + assert_eq!(version, deserialized); + } } } diff --git a/crates/katana/rpc/rpc-types/src/block.rs b/crates/katana/rpc/rpc-types/src/block.rs index a9c24e642b..df1e53c184 100644 --- a/crates/katana/rpc/rpc-types/src/block.rs +++ b/crates/katana/rpc/rpc-types/src/block.rs @@ -35,7 +35,7 @@ impl BlockWithTxs { timestamp: block.header.timestamp, block_number: block.header.number, parent_hash: block.header.parent_hash, - starknet_version: block.header.version.to_string(), + starknet_version: block.header.protocol_version.to_string(), sequencer_address: block.header.sequencer_address.into(), status: match finality_status { FinalityStatus::AcceptedOnL1 => BlockStatus::AcceptedOnL1, @@ -112,7 +112,7 @@ impl BlockWithTxHashes { timestamp: block.header.timestamp, block_number: block.header.number, parent_hash: block.header.parent_hash, - starknet_version: block.header.version.to_string(), + starknet_version: block.header.protocol_version.to_string(), sequencer_address: block.header.sequencer_address.into(), status: match finality_status { FinalityStatus::AcceptedOnL1 => BlockStatus::AcceptedOnL1, @@ -219,7 +219,7 @@ impl BlockWithReceipts { price_in_wei: Default::default(), }, l1_da_mode: L1DataAvailabilityMode::Calldata, - starknet_version: header.version.to_string(), + starknet_version: header.protocol_version.to_string(), transactions, }) } diff --git a/crates/katana/rpc/rpc/src/starknet/read.rs b/crates/katana/rpc/rpc/src/starknet/read.rs index e30715544c..c1a65ba735 100644 --- a/crates/katana/rpc/rpc/src/starknet/read.rs +++ b/crates/katana/rpc/rpc/src/starknet/read.rs @@ -2,7 +2,6 @@ use jsonrpsee::core::{async_trait, Error, RpcResult}; use katana_executor::{EntryPointCall, ExecutionResult, ExecutorFactory}; use katana_primitives::block::{BlockHashOrNumber, BlockIdOrTag, FinalityStatus, PartialHeader}; use katana_primitives::transaction::{ExecutableTx, ExecutableTxWithHash, TxHash}; -use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_primitives::Felt; use katana_provider::traits::block::{BlockHashProvider, BlockIdReader, BlockNumberProvider}; use katana_provider::traits::transaction::TransactionProvider; @@ -87,7 +86,7 @@ impl StarknetApiServer for StarknetApi { gas_prices, parent_hash: latest_hash, timestamp: block_env.timestamp, - version: CURRENT_STARKNET_VERSION, + version: this.inner.backend.chain_spec.version.clone(), sequencer_address: block_env.sequencer_address, }; @@ -174,9 +173,9 @@ impl StarknetApiServer for StarknetApi { number: block_env.number, gas_prices, parent_hash: latest_hash, - version: CURRENT_STARKNET_VERSION, timestamp: block_env.timestamp, sequencer_address: block_env.sequencer_address, + version: this.inner.backend.chain_spec.version.clone(), }; // TODO(kariy): create a method that can perform this filtering for us instead @@ -231,7 +230,7 @@ impl StarknetApiServer for StarknetApi { number: block_env.number, gas_prices, parent_hash: latest_hash, - version: CURRENT_STARKNET_VERSION, + version: this.inner.backend.chain_spec.version.clone(), timestamp: block_env.timestamp, sequencer_address: block_env.sequencer_address, }; diff --git a/crates/katana/storage/db/Cargo.toml b/crates/katana/storage/db/Cargo.toml index ce6aaf883b..3677b485cf 100644 --- a/crates/katana/storage/db/Cargo.toml +++ b/crates/katana/storage/db/Cargo.toml @@ -22,11 +22,7 @@ thiserror.workspace = true tracing.workspace = true # codecs -[dependencies.postcard] -default-features = false -features = [ "use-std" ] -optional = true -version = "1.0.8" +postcard = { workspace = true, optional = true } [dependencies.libmdbx] git = "https://github.com/paradigmxyz/reth.git" diff --git a/crates/katana/storage/db/src/version.rs b/crates/katana/storage/db/src/version.rs index f77bc28b2f..c1600f0b0c 100644 --- a/crates/katana/storage/db/src/version.rs +++ b/crates/katana/storage/db/src/version.rs @@ -5,7 +5,7 @@ use std::mem; use std::path::{Path, PathBuf}; /// Current version of the database. -pub const CURRENT_DB_VERSION: u32 = 1; +pub const CURRENT_DB_VERSION: u32 = 2; /// Name of the version file. const DB_VERSION_FILE_NAME: &str = "db.version"; @@ -81,6 +81,6 @@ mod tests { #[test] fn test_current_version() { use super::CURRENT_DB_VERSION; - assert_eq!(CURRENT_DB_VERSION, 1, "Invalid current database version") + assert_eq!(CURRENT_DB_VERSION, 2, "Invalid current database version") } } diff --git a/crates/saya/provider/src/rpc/mod.rs b/crates/saya/provider/src/rpc/mod.rs index 1758a70866..6e049a4325 100644 --- a/crates/saya/provider/src/rpc/mod.rs +++ b/crates/saya/provider/src/rpc/mod.rs @@ -12,7 +12,7 @@ use katana_primitives::chain::ChainId; use katana_primitives::conversion::rpc as rpc_converter; use katana_primitives::state::StateUpdatesWithDeclaredClasses; use katana_primitives::transaction::TxWithHash; -use katana_primitives::version::Version; +use katana_primitives::version::ProtocolVersion; use katana_rpc_api::saya::SayaApiClient; use katana_rpc_types::trace::TxExecutionInfo; use num_traits::ToPrimitive; @@ -100,7 +100,7 @@ impl Provider for JsonRpcProvider { timestamp: block.timestamp, state_root: block.new_root, sequencer_address: block.sequencer_address.into(), - version: Version::parse(&block.starknet_version)?, + protocol_version: ProtocolVersion::parse(&block.starknet_version).unwrap(), }, }, body: txs, diff --git a/examples/rpc/starknet/starknet_getBlockWithReceipts.hurl b/examples/rpc/starknet/starknet_getBlockWithReceipts.hurl index 9df401069a..a572caa629 100644 --- a/examples/rpc/starknet/starknet_getBlockWithReceipts.hurl +++ b/examples/rpc/starknet/starknet_getBlockWithReceipts.hurl @@ -16,6 +16,6 @@ jsonpath "$.result.transactions" isCollection jsonpath "$.result.block_number" isInteger jsonpath "$.result.block_hash" matches /^0x[A-Fa-f0-9]+$/ jsonpath "$.result.parent_hash" matches /^0x[A-Fa-f0-9]+$/ -jsonpath "$.result.starknet_version" matches /^[0-9]+.[0-9]+.[0-9]+$/ +jsonpath "$.result.starknet_version" matches /^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$/ jsonpath "$.result.transactions[*].transaction" exists jsonpath "$.result.transactions[*].receipt" exists diff --git a/examples/rpc/starknet/starknet_getBlockWithTxHashes.hurl b/examples/rpc/starknet/starknet_getBlockWithTxHashes.hurl index e978694681..95d7248c09 100644 --- a/examples/rpc/starknet/starknet_getBlockWithTxHashes.hurl +++ b/examples/rpc/starknet/starknet_getBlockWithTxHashes.hurl @@ -18,5 +18,4 @@ jsonpath "$.result.transactions" isCollection jsonpath "$.result.block_number" isInteger jsonpath "$.result.block_hash" matches /^0x[A-Fa-f0-9]+$/ jsonpath "$.result.parent_hash" matches /^0x[A-Fa-f0-9]+$/ -jsonpath "$.result.starknet_version" matches /^[0-9]+.[0-9]+.[0-9]+$/ - +jsonpath "$.result.starknet_version" matches /^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$/ diff --git a/examples/rpc/starknet/starknet_getBlockWithTxs.hurl b/examples/rpc/starknet/starknet_getBlockWithTxs.hurl index 106716e4a1..4c6f38b646 100644 --- a/examples/rpc/starknet/starknet_getBlockWithTxs.hurl +++ b/examples/rpc/starknet/starknet_getBlockWithTxs.hurl @@ -16,4 +16,4 @@ jsonpath "$.result.transactions" isCollection jsonpath "$.result.block_number" isInteger jsonpath "$.result.block_hash" matches /^0x[A-Fa-f0-9]+$/ jsonpath "$.result.parent_hash" matches /^0x[A-Fa-f0-9]+$/ -jsonpath "$.result.starknet_version" matches /^[0-9]+.[0-9]+.[0-9]+$/ +jsonpath "$.result.starknet_version" matches /^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$/ diff --git a/spawn-and-move-db.tar.gz b/spawn-and-move-db.tar.gz index 9bf8757aa5..9b9a401627 100644 Binary files a/spawn-and-move-db.tar.gz and b/spawn-and-move-db.tar.gz differ diff --git a/types-test-db.tar.gz b/types-test-db.tar.gz index 53f037346c..23e4a715ec 100644 Binary files a/types-test-db.tar.gz and b/types-test-db.tar.gz differ