diff --git a/crates/starknet-types-core/Cargo.toml b/crates/starknet-types-core/Cargo.toml index 8ebcf930..f9a671b4 100644 --- a/crates/starknet-types-core/Cargo.toml +++ b/crates/starknet-types-core/Cargo.toml @@ -11,10 +11,18 @@ description = "Core types representation for Starknet" readme = "README.md" [dependencies] +crypto-bigint = { version = "0.5.5", default-features = false, features = [ + "generic-array", + "zeroize", +] } +hmac = { version = "0.12.1", default-features = false } lambdaworks-math = { version = "0.7.0", default-features = false } num-traits = { version = "0.2.18", default-features = false } num-bigint = { version = "0.4.4", default-features = false } num-integer = { version = "0.1.45", default-features = false } +rfc6979 = "0.4.0" +sha2 = "0.10.8" +zeroize = "1.8.1" # Optional arbitrary = { version = "1.3.2", optional = true } @@ -26,7 +34,7 @@ parity-scale-codec = { version = "3.6.9", default-features = false, optional = t lazy_static = { version = "1.4.0", default-features = false, optional = true } [features] -default = ["std", "serde", "curve", "num-traits"] +default = ["std", "serde", "curve", "num-traits", "hash"] std = [ "lambdaworks-math/std", "num-traits/std", @@ -57,4 +65,3 @@ lazy_static = { version = "1.4.0", default-features = false } [[bench]] name = "criterion_hashes" harness = false - diff --git a/crates/starknet-types-core/src/curve/mod.rs b/crates/starknet-types-core/src/curve/mod.rs index 7f315a8c..1eedddb9 100644 --- a/crates/starknet-types-core/src/curve/mod.rs +++ b/crates/starknet-types-core/src/curve/mod.rs @@ -1,7 +1,9 @@ mod affine_point; mod curve_errors; mod projective_point; +mod signer; pub use self::affine_point::*; pub use self::curve_errors::*; pub use self::projective_point::*; +pub use self::signer::*; diff --git a/crates/starknet-types-core/src/curve/signer.rs b/crates/starknet-types-core/src/curve/signer.rs new file mode 100644 index 00000000..5f0ecb5b --- /dev/null +++ b/crates/starknet-types-core/src/curve/signer.rs @@ -0,0 +1,303 @@ +use super::{AffinePoint, ProjectivePoint}; +use crate::felt::Felt; +use crate::hash::{Pedersen, StarkHash}; +use core::fmt::{Display, Formatter, Result as CoreResult}; +use core::ops::{Add, Mul}; +use crypto_bigint::{ArrayEncoding, ByteArray, Integer as CryptoInteger, U256}; +use hmac::digest::Digest; +use lambdaworks_math::elliptic_curve::short_weierstrass::curves::stark_curve::StarkCurve; +use num_bigint::BigInt; +use num_integer::Integer; +use num_traits::{One, Zero}; +use sha2::digest::{crypto_common::BlockSizeUser, FixedOutputReset, HashMarker}; +use zeroize::{Zeroize, Zeroizing}; + +const EC_ORDER: Felt = Felt::from_raw([ + 369010039416812937, + 9, + 1143265896874747514, + 8939893405601011193, +]); + +const EC_ORDER_2: U256 = + U256::from_be_hex("0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f"); + +const ELEMENT_UPPER_BOUND: Felt = Felt::from_raw([ + 576459263475450960, + 18446744073709255680, + 160989183, + 18446743986131435553, +]); + +const GENERATOR: AffinePoint = AffinePoint::new_unchecked( + Felt::from_raw([ + 232005955912912577, + 299981207024966779, + 5884444832209845738, + 14484022957141291997, + ]), + Felt::from_raw([ + 405578048423154473, + 18147424675297964973, + 664812301889158119, + 6241159653446987914, + ]), +); + +pub trait Signer { + fn ecdsa_sign( + private_key: &Felt, + message_hash: &Felt, + ) -> Result; +} + +impl Signer for StarkCurve { + fn ecdsa_sign( + private_key: &Felt, + message_hash: &Felt, + ) -> Result { + let mut seed = None; + loop { + let k = generate_k(private_key, message_hash, seed.as_ref()); + + match sign(private_key, message_hash, &k) { + Ok(sig) => { + return Ok(sig); + } + Err(SignError::InvalidMessageHash) => { + return Err(EcdsaSignError::MessageHashOutOfRange) + } + Err(SignError::InvalidK) => { + // Bump seed and retry + seed = match seed { + Some(prev_seed) => Some(prev_seed + Felt::ONE), + None => Some(Felt::ONE), + }; + } + }; + } + } +} + +#[derive(Debug)] +pub enum EcdsaSignError { + MessageHashOutOfRange, +} + +#[cfg(feature = "std")] +impl std::error::Error for EcdsaSignError {} + +impl Display for EcdsaSignError { + fn fmt(&self, f: &mut Formatter<'_>) -> CoreResult { + match self { + Self::MessageHashOutOfRange => write!(f, "message hash out of range"), + } + } +} + +/// Stark ECDSA signature +#[derive(Debug)] +pub struct Signature { + /// The `r` value of a signature + pub r: Felt, + /// The `s` value of a signature + pub s: Felt, +} +/// Stark ECDSA signature with `v` +#[derive(Debug)] +pub struct ExtendedSignature { + /// The `r` value of a signature + pub r: Felt, + /// The `s` value of a signature + pub s: Felt, + /// The `v` value of a signature + pub v: Felt, +} + +impl From for Signature { + fn from(value: ExtendedSignature) -> Self { + Self { + r: value.r, + s: value.s, + } + } +} + +#[derive(Debug)] +pub enum SignError { + InvalidMessageHash, + InvalidK, +} + +pub fn compute_hash_on_elements<'a, ESI, II>(data: II) -> Felt +where + ESI: ExactSizeIterator, + II: IntoIterator, +{ + let mut current_hash = Felt::ZERO; + let data_iter = data.into_iter(); + let data_len = Felt::from(data_iter.len()); + + for elem in data_iter { + current_hash = Pedersen::hash(¤t_hash, elem); + } + + Pedersen::hash(¤t_hash, &data_len) +} + +/// Computes the public key given a Stark private key. +/// +/// ### Arguments +/// +/// * `private_key`: The private key +pub fn get_public_key(private_key: &Felt) -> Felt { + mul_by_bits(&GENERATOR, private_key) + .to_affine() + .unwrap() + .x() +} + +/// Computes ECDSA signature given a Stark private key and message hash. +/// +/// ### Arguments +/// +/// * `private_key`: The private key +/// * `message`: The message hash +/// * `k`: A random `k` value. You **MUST NOT** use the same `k` on different signatures +pub fn sign(private_key: &Felt, message: &Felt, k: &Felt) -> Result { + if message >= &ELEMENT_UPPER_BOUND { + return Err(SignError::InvalidMessageHash); + } + if k == &Felt::ZERO { + return Err(SignError::InvalidK); + } + + let full_r = mul_by_bits(&GENERATOR, k).to_affine().unwrap(); + let r = full_r.x(); + if r == Felt::ZERO || r >= ELEMENT_UPPER_BOUND { + return Err(SignError::InvalidK); + } + + let k_inv = mod_inverse(k, &EC_ORDER); + + let s = mul_mod_floor(&r, private_key, &EC_ORDER); + let s = add_unbounded(&s, message); + let s = bigint_mul_mod_floor(s, &k_inv, &EC_ORDER); + if s == Felt::ZERO || s >= ELEMENT_UPPER_BOUND { + return Err(SignError::InvalidK); + } + + Ok(ExtendedSignature { + r, + s, + v: (full_r.y().to_bigint() & Felt::ONE.to_bigint()).into(), + }) +} + +pub fn add_unbounded(augend: &Felt, addend: &Felt) -> BigInt { + let augend = BigInt::from_bytes_be(num_bigint::Sign::Plus, &augend.to_bytes_be()); + let addend = BigInt::from_bytes_be(num_bigint::Sign::Plus, &addend.to_bytes_be()); + augend.add(addend) +} + +pub fn mul_mod_floor(multiplicand: &Felt, multiplier: &Felt, modulus: &Felt) -> Felt { + let multiplicand = BigInt::from_bytes_be(num_bigint::Sign::Plus, &multiplicand.to_bytes_be()); + bigint_mul_mod_floor(multiplicand, multiplier, modulus) +} + +pub fn bigint_mul_mod_floor(multiplicand: BigInt, multiplier: &Felt, modulus: &Felt) -> Felt { + let multiplier = BigInt::from_bytes_be(num_bigint::Sign::Plus, &multiplier.to_bytes_be()); + let modulus = BigInt::from_bytes_be(num_bigint::Sign::Plus, &modulus.to_bytes_be()); + + let result = multiplicand.mul(multiplier).mod_floor(&modulus); + + let (_, buffer) = result.to_bytes_be(); + let mut result = [0u8; 32]; + result[(32 - buffer.len())..].copy_from_slice(&buffer[..]); + + Felt::from_bytes_be(&result) +} + +#[inline(always)] +fn mul_by_bits(x: &AffinePoint, y: &Felt) -> ProjectivePoint { + &ProjectivePoint::from_affine(x.x(), x.y()).unwrap() * *y +} + +pub fn mod_inverse(operand: &Felt, modulus: &Felt) -> Felt { + let operand = BigInt::from_bytes_be(num_bigint::Sign::Plus, &operand.to_bytes_be()); + let modulus = BigInt::from_bytes_be(num_bigint::Sign::Plus, &modulus.to_bytes_be()); + + // Ported from: + // https://github.com/dignifiedquire/num-bigint/blob/56576b592fea6341b7e1711a1629e4cc1bfc419c/src/algorithms/mod_inverse.rs#L11 + let extended_gcd = operand.extended_gcd(&modulus); + if extended_gcd.gcd != BigInt::one() { + panic!("GCD must be one"); + } + let result = if extended_gcd.x < BigInt::zero() { + extended_gcd.x + modulus + } else { + extended_gcd.x + }; + + let (_, buffer) = result.to_bytes_be(); + let mut result = [0u8; 32]; + result[(32 - buffer.len())..].copy_from_slice(&buffer[..]); + + Felt::from_bytes_be(&result) +} + +/// Deterministically generate ephemeral scalar `k` based on RFC 6979. +fn generate_k(private_key: &Felt, message_hash: &Felt, seed: Option<&Felt>) -> Felt { + let message_hash = U256::from_be_slice(&message_hash.to_bytes_be()).to_be_byte_array(); + let private_key = U256::from_be_slice(&private_key.to_bytes_be()); + + let seed_bytes = match seed { + Some(seed) => seed.to_bytes_be(), + None => [0u8; 32], + }; + + let mut first_non_zero_index = 32; + for (ind, element) in seed_bytes.iter().enumerate() { + if *element != 0u8 { + first_non_zero_index = ind; + break; + } + } + + let k = generate_k_shifted::( + &private_key, + &EC_ORDER_2, + &message_hash, + &seed_bytes[first_non_zero_index..], + ); + + let mut buffer = [0u8; 32]; + buffer[..].copy_from_slice(&k.to_be_byte_array()[..]); + + Felt::from_bytes_be(&buffer) +} + +// Modified from upstream `rfc6979::generate_k` with a hard-coded right bit shift. The more +// idiomatic way of doing this seems to be to implement `U252` which handles bit truncation +// interally. +// TODO: change to use upstream `generate_k` directly. +#[inline] +fn generate_k_shifted(x: &I, n: &I, h: &ByteArray, data: &[u8]) -> Zeroizing +where + D: Default + Digest + BlockSizeUser + FixedOutputReset + HashMarker, + I: ArrayEncoding + CryptoInteger + Zeroize, +{ + let mut x = x.to_be_byte_array(); + let mut hmac_drbg = rfc6979::HmacDrbg::::new(&x, h, data); + x.zeroize(); + + loop { + let mut bytes = ByteArray::::default(); + hmac_drbg.fill_bytes(&mut bytes); + let k = I::from_be_byte_array(bytes) >> 4; + + if (!k.is_zero() & k.ct_lt(n)).into() { + return Zeroizing::new(k); + } + } +} diff --git a/crates/starknet-types-core/src/hash/mod.rs b/crates/starknet-types-core/src/hash/mod.rs index b79e5922..8ec227e2 100644 --- a/crates/starknet-types-core/src/hash/mod.rs +++ b/crates/starknet-types-core/src/hash/mod.rs @@ -1,7 +1,9 @@ mod pedersen; mod poseidon; +mod poseidon_hash; mod traits; pub use self::pedersen::*; pub use self::poseidon::*; +pub use self::poseidon_hash::*; pub use self::traits::*; diff --git a/crates/starknet-types-core/src/hash/poseidon_hash.rs b/crates/starknet-types-core/src/hash/poseidon_hash.rs new file mode 100644 index 00000000..2ba9f563 --- /dev/null +++ b/crates/starknet-types-core/src/hash/poseidon_hash.rs @@ -0,0 +1,95 @@ +use crate::felt::Felt; + +use super::Poseidon; + +#[derive(Debug, Default)] + +pub struct PoseidonHasher { + state: [Felt; 3], + buffer: Option, +} + +impl PoseidonHasher { + /// Creates a new [`PoseidonHasher`]. + pub fn new() -> Self { + Self::default() + } + + /// Absorbs message into the hash. + pub fn update(&mut self, msg: Felt) { + match self.buffer.take() { + Some(previous_message) => { + self.state[0] += previous_message; + self.state[1] += msg; + Poseidon::hades_permutation(&mut self.state); + } + None => { + self.buffer = Some(msg); + } + } + } + + /// Finishes and returns hash. + pub fn finalize(mut self) -> Felt { + // Applies padding + match self.buffer.take() { + Some(last_message) => { + self.state[0] += last_message; + self.state[1] += Felt::ONE; + } + None => { + self.state[0] += Felt::ONE; + } + } + Poseidon::hades_permutation(&mut self.state); + + self.state[0] + } +} + +/// Computes the Starknet Poseidon hash of x and y. +pub fn poseidon_hash(x: Felt, y: Felt) -> Felt { + let mut state = [x, y, Felt::TWO]; + Poseidon::hades_permutation(&mut state); + + state[0] +} + +/// Computes the Starknet Poseidon hash of a single [`Felt`]. +pub fn poseidon_hash_single(x: Felt) -> Felt { + let mut state = [x, Felt::ZERO, Felt::ONE]; + Poseidon::hades_permutation(&mut state); + + state[0] +} + +/// Computes the Starknet Poseidon hash of an arbitrary number of [`Felt`]s. +/// +/// Using this function is the same as using [`PoseidonHasher`]. +pub fn poseidon_hash_many<'a, I: IntoIterator>(msgs: I) -> Felt { + let mut state = [Felt::ZERO, Felt::ZERO, Felt::ZERO]; + let mut iter = msgs.into_iter(); + + loop { + match iter.next() { + Some(v) => state[0] += *v, + None => { + state[0] += Felt::ONE; + break; + } + } + + match iter.next() { + Some(v) => state[1] += *v, + None => { + state[1] += Felt::ONE; + break; + } + } + + Poseidon::hades_permutation(&mut state); + } + Poseidon::hades_permutation(&mut state); + + state[0] +} diff --git a/crates/starknet-types-rpc/src/custom/mod.rs b/crates/starknet-types-rpc/src/custom/mod.rs deleted file mode 100644 index 6b8ecbf9..00000000 --- a/crates/starknet-types-rpc/src/custom/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod block_id; -mod query; -mod syncing_status; - -pub use self::block_id::*; -pub use self::query::*; -pub use self::syncing_status::*; diff --git a/crates/starknet-types-rpc/src/lib.rs b/crates/starknet-types-rpc/src/lib.rs index dfb4ddcd..a4dc259f 100644 --- a/crates/starknet-types-rpc/src/lib.rs +++ b/crates/starknet-types-rpc/src/lib.rs @@ -19,11 +19,12 @@ extern crate alloc; extern crate core; -mod custom; mod custom_serde; // // Generated files. +pub mod v0_5_0; +pub mod v0_6_0; pub mod v0_7_1; pub use self::v0_7_1::*; diff --git a/crates/starknet-types-rpc/src/v0_5_0/block_id.rs b/crates/starknet-types-rpc/src/v0_5_0/block_id.rs new file mode 100644 index 00000000..c288f96d --- /dev/null +++ b/crates/starknet-types-rpc/src/v0_5_0/block_id.rs @@ -0,0 +1,129 @@ +use serde::{Deserialize, Deserializer, Serialize}; + +use super::{BlockHash, BlockNumber, BlockTag}; + +/// A hexadecimal number. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum BlockId { + /// The tag of the block. + Tag(BlockTag), + /// The hash of the block. + Hash(BlockHash), + /// The height of the block. + Number(BlockNumber), +} + +#[derive(Serialize, Deserialize)] +struct BlockHashHelper { + block_hash: BlockHash, +} + +#[derive(Serialize, Deserialize)] +struct BlockNumberHelper { + block_number: BlockNumber, +} + +#[derive(Deserialize)] +#[serde(untagged)] +enum BlockIdHelper { + Tag(BlockTag), + Hash(BlockHashHelper), + Number(BlockNumberHelper), +} + +impl serde::Serialize for BlockId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match *self { + BlockId::Tag(tag) => tag.serialize(serializer), + BlockId::Hash(block_hash) => { + let helper = BlockHashHelper { block_hash }; + helper.serialize(serializer) + } + BlockId::Number(block_number) => { + let helper = BlockNumberHelper { block_number }; + helper.serialize(serializer) + } + } + } +} + +impl<'de> serde::Deserialize<'de> for BlockId { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let helper = BlockIdHelper::deserialize(deserializer)?; + match helper { + BlockIdHelper::Tag(tag) => Ok(BlockId::Tag(tag)), + BlockIdHelper::Hash(helper) => Ok(BlockId::Hash(helper.block_hash)), + BlockIdHelper::Number(helper) => Ok(BlockId::Number(helper.block_number)), + } + } +} + +#[test] +fn block_id_from_hash() { + use starknet_types_core::felt::Felt; + + let s = "{\"block_hash\":\"0x123\"}"; + let block_id: BlockId = serde_json::from_str(s).unwrap(); + assert_eq!(block_id, BlockId::Hash(Felt::from_hex("0x123").unwrap())); +} + +#[test] +fn block_id_from_number() { + let s = "{\"block_number\":123}"; + let block_id: BlockId = serde_json::from_str(s).unwrap(); + assert_eq!(block_id, BlockId::Number(123)); +} + +#[test] +fn block_id_from_latest() { + let s = "\"latest\""; + let block_id: BlockId = serde_json::from_str(s).unwrap(); + assert_eq!(block_id, BlockId::Tag(BlockTag::Latest)); +} + +#[test] +fn block_id_from_pending() { + let s = "\"pending\""; + let block_id: BlockId = serde_json::from_str(s).unwrap(); + assert_eq!(block_id, BlockId::Tag(BlockTag::Pending)); +} + +#[cfg(test)] +#[test] +fn block_id_to_hash() { + use starknet_types_core::felt::Felt; + + let block_id = BlockId::Hash(Felt::from_hex("0x123").unwrap()); + let s = serde_json::to_string(&block_id).unwrap(); + assert_eq!(s, "{\"block_hash\":\"0x123\"}"); +} + +#[cfg(test)] +#[test] +fn block_id_to_number() { + let block_id = BlockId::Number(123); + let s = serde_json::to_string(&block_id).unwrap(); + assert_eq!(s, "{\"block_number\":123}"); +} + +#[cfg(test)] +#[test] +fn block_id_to_latest() { + let block_id = BlockId::Tag(BlockTag::Latest); + let s = serde_json::to_string(&block_id).unwrap(); + assert_eq!(s, "\"latest\""); +} + +#[cfg(test)] +#[test] +fn block_id_to_pending() { + let block_id = BlockId::Tag(BlockTag::Pending); + let s = serde_json::to_string(&block_id).unwrap(); + assert_eq!(s, "\"pending\""); +} diff --git a/crates/starknet-types-rpc/src/v0_5_0/mod.rs b/crates/starknet-types-rpc/src/v0_5_0/mod.rs index 7a43d1bc..98a976fb 100644 --- a/crates/starknet-types-rpc/src/v0_5_0/mod.rs +++ b/crates/starknet-types-rpc/src/v0_5_0/mod.rs @@ -1,16 +1,15 @@ //! v0.5.0 of the API. -pub use starknet_types_core::felt::Felt; - -pub use crate::custom::{ - BlockId, BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, - SyncingStatus, -}; - +mod block_id; +mod query; mod starknet_api_openrpc; mod starknet_trace_api_openrpc; mod starknet_write_api; +mod syncing_status; +pub use self::block_id::*; +pub use self::query::*; pub use self::starknet_api_openrpc::*; pub use self::starknet_trace_api_openrpc::*; pub use self::starknet_write_api::*; +pub use self::syncing_status::*; diff --git a/crates/starknet-types-rpc/src/v0_5_0/query.rs b/crates/starknet-types-rpc/src/v0_5_0/query.rs new file mode 100644 index 00000000..0f9f2820 --- /dev/null +++ b/crates/starknet-types-rpc/src/v0_5_0/query.rs @@ -0,0 +1,48 @@ +// query offset: +// 0x0000000000000000000000000000000100000000000000000000000000000000 + +use serde::{Deserialize, Serialize}; + +use super::{ + BroadcastedDeclareTxnV1, BroadcastedDeclareTxnV2, DeployAccountTxnV1, InvokeTxnV0, InvokeTxnV1, +}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "version")] +pub enum BroadcastedDeclareTxn { + #[serde(rename = "0x1")] + V1(BroadcastedDeclareTxnV1), + #[serde(rename = "0x2")] + V2(BroadcastedDeclareTxnV2), + /// Query-only broadcasted declare transaction. + #[serde(rename = "0x0000000000000000000000000000000100000000000000000000000000000001")] + QueryV1(BroadcastedDeclareTxnV1), + /// Query-only broadcasted declare transaction. + #[serde(rename = "0x100000000000000000000000000000002")] + QueryV2(BroadcastedDeclareTxnV2), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "version")] +pub enum BroadcastedDeployAccountTxn { + #[serde(rename = "0x1")] + V1(DeployAccountTxnV1), + /// Query-only broadcasted deploy account transaction. + #[serde(rename = "0x0000000000000000000000000000000100000000000000000000000000000001")] + QueryV1(DeployAccountTxnV1), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "version")] +pub enum BroadcastedInvokeTxn { + #[serde(rename = "0x0")] + V0(InvokeTxnV0), + #[serde(rename = "0x1")] + V1(InvokeTxnV1), + /// Query-only broadcasted invoke transaction. + #[serde(rename = "0x0000000000000000000000000000000100000000000000000000000000000000")] + QueryV0(InvokeTxnV0), + /// Query-only broadcasted invoke transaction. + #[serde(rename = "0x0000000000000000000000000000000100000000000000000000000000000001")] + QueryV1(InvokeTxnV1), +} diff --git a/crates/starknet-types-rpc/src/v0_5_0/starknet_api_openrpc.rs b/crates/starknet-types-rpc/src/v0_5_0/starknet_api_openrpc.rs index f840fa6e..75c31483 100644 --- a/crates/starknet-types-rpc/src/v0_5_0/starknet_api_openrpc.rs +++ b/crates/starknet-types-rpc/src/v0_5_0/starknet_api_openrpc.rs @@ -8,17 +8,19 @@ // https://github.com/nils-mathieu/openrpc-gen // -use super::{ - BlockId, BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, Felt, -}; +use super::{BlockId, BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn}; use crate::custom_serde::NumAsHex; use alloc::string::String; use alloc::vec::Vec; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize}; +use starknet_types_core::felt::Felt; pub type Address = Felt; +/// Flags that indicate how to simulate a given transaction. By default, the sequencer behavior is replicated locally +pub type SimulationFlagForEstimateFee = String; + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TxnWithHash { #[serde(flatten)] @@ -34,6 +36,9 @@ pub struct BlockHeader { /// The block number (its height) pub block_number: BlockNumber, pub l1_gas_price: ResourcePrice, + pub l1_data_gas_price: ResourcePrice, + pub l1_da_mode: L1DataAvailabilityMode, + /// The new global state root pub new_root: Felt, /// The hash of this block's parent @@ -91,6 +96,14 @@ pub struct BlockWithTxHashes { pub block_header: BlockHeader, } +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub enum L1DataAvailabilityMode { + #[serde(rename = "BLOB")] + Blob, + #[serde(rename = "CALLDATA")] + Calldata, +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BroadcastedDeclareTxnV1 { /// The class to be declared @@ -115,6 +128,8 @@ pub struct BroadcastedDeclareTxnV2 { /// The address of the account contract sending the declaration transaction pub sender_address: Address, pub signature: Signature, + #[serde(rename = "type")] + pub type_: String, } #[derive(Serialize, Deserialize, Clone, Debug)] @@ -141,7 +156,7 @@ pub struct CommonReceiptProperties { /// The events emitted as part of this transaction pub events: Vec, /// The resources consumed by the transaction - pub execution_resources: ExecutionResources, + pub execution_resources: ExecutionResources2, pub execution_status: TxnExecutionStatus, pub finality_status: TxnFinalityStatus, pub messages_sent: Vec, @@ -164,14 +179,13 @@ pub enum ContractAbiEntry { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ContractClass { - /// The class ABI, as supplied by the user declaring the class - #[serde(default)] - pub abi: Option, + /// The list of Sierra instructions of which the program consists + pub sierra_program: Vec, /// The version of the contract class object. Currently, the Starknet OS supports version 0.1.0 pub contract_class_version: String, pub entry_points_by_type: EntryPointsByType, - /// The list of Sierra instructions of which the program consists - pub sierra_program: Vec, + /// The class ABI, as supplied by the user declaring the class + pub abi: String, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -311,6 +325,8 @@ pub struct DeployAccountTxnV1 { pub max_fee: Felt, pub nonce: Felt, pub signature: Signature, + #[serde(rename = "type")] + pub type_: Option, } /// Deploys an account contract, charges fee from the pre-funded account addresses @@ -348,6 +364,35 @@ pub struct DeployTxnReceipt { /// The address of the deployed contract pub contract_address: Felt, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NewDeployTxnReceipt { + pub transaction_hash: TxnHash, + pub actual_fee: FeePayment, + pub messages_sent: Vec, + pub events: Vec, + pub execution_status: TxnExecutionStatus, + pub finality_status: TxnFinalityStatus, + pub block_hash: BlockHash, + pub block_number: BlockNumber, + pub execution_resources: ExecutionResources2, + pub contract_address: Felt, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ExecutionResources2 { + pub steps: u64, + pub memory_holes: u64, + pub range_check_builtin_applications: u64, + pub pedersen_builtin_applications: u64, + pub ec_op_builtin_applications: u64, + pub data_availability: DataAvailability, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DataAvailability { + pub l1_gas: u64, + pub l1_data_gas: u64, +} #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeprecatedCairoEntryPoint { @@ -554,6 +599,8 @@ pub struct InvokeTxnV1 { pub nonce: Felt, pub sender_address: Address, pub signature: Signature, + #[serde(rename = "type")] + pub _type: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -726,19 +773,17 @@ pub struct ResourceLimits { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ResourcePrice { /// the price of one unit of the given resource, denominated in strk - #[serde(with = "NumAsHex")] - pub price_in_strk: u64, + pub price_in_fri: Felt, /// the price of one unit of the given resource, denominated in wei - #[serde(with = "NumAsHex")] - pub price_in_wei: u64, + pub price_in_wei: Felt, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SierraEntryPoint { - /// The index of the function in the program - pub function_idx: u64, /// A unique identifier of the entry point (function) in the program pub selector: Felt, + /// The index of the function in the program + pub function_idx: u64, } /// A transaction signature @@ -799,7 +844,7 @@ pub struct StateUpdate { } /// A storage key. Represented as up to 62 hex digits, 3 bits, and 5 leading zeroes. -pub type StorageKey = String; +pub type StorageKey = Felt; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StructAbiEntry { @@ -2036,6 +2081,8 @@ impl<'de> Deserialize<'de> for CallParams { pub struct EstimateFeeParams { /// The transaction to estimate pub request: Vec, + /// describes what parts of the transaction should be executed + pub simulation_flags: Vec, /// The hash of the requested block, or number (height) of the requested block, or a block tag, for the block referencing the state or call the transaction on. pub block_id: BlockId, } @@ -2048,6 +2095,7 @@ impl Serialize for EstimateFeeParams { { let mut map = serializer.serialize_map(None)?; map.serialize_entry("request", &self.request)?; + map.serialize_entry("simulation_flags", &self.simulation_flags)?; map.serialize_entry("block_id", &self.block_id)?; map.end() } @@ -2074,19 +2122,26 @@ impl<'de> Deserialize<'de> for EstimateFeeParams { { let request: Vec = seq .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(1, &"expected 2 parameters"))?; + .ok_or_else(|| serde::de::Error::invalid_length(1, &"expected 3 parameters"))?; + let simulation_flags: Vec = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(2, &"expected 3 parameters"))?; let block_id: BlockId = seq .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(2, &"expected 2 parameters"))?; + .ok_or_else(|| serde::de::Error::invalid_length(3, &"expected 3 parameters"))?; if seq.next_element::()?.is_some() { return Err(serde::de::Error::invalid_length( - 3, - &"expected 2 parameters", + 4, + &"expected 3 parameters", )); } - Ok(EstimateFeeParams { request, block_id }) + Ok(EstimateFeeParams { + request, + simulation_flags, + block_id, + }) } #[allow(unused_variables)] @@ -2097,6 +2152,7 @@ impl<'de> Deserialize<'de> for EstimateFeeParams { #[derive(Deserialize)] struct Helper { request: Vec, + simulation_flags: Vec, block_id: BlockId, } @@ -2105,6 +2161,7 @@ impl<'de> Deserialize<'de> for EstimateFeeParams { Ok(EstimateFeeParams { request: helper.request, + simulation_flags: helper.simulation_flags, block_id: helper.block_id, }) } @@ -2113,7 +2170,6 @@ impl<'de> Deserialize<'de> for EstimateFeeParams { deserializer.deserialize_any(Visitor) } } - /// Parameters of the `starknet_estimateMessageFee` method. #[derive(Debug, Clone)] pub struct EstimateMessageFeeParams { diff --git a/crates/starknet-types-rpc/src/v0_5_0/starknet_trace_api_openrpc.rs b/crates/starknet-types-rpc/src/v0_5_0/starknet_trace_api_openrpc.rs index 413edf08..c1a4d347 100644 --- a/crates/starknet-types-rpc/src/v0_5_0/starknet_trace_api_openrpc.rs +++ b/crates/starknet-types-rpc/src/v0_5_0/starknet_trace_api_openrpc.rs @@ -9,12 +9,13 @@ // use super::{ - BlockId, BroadcastedTxn, Event, FeeEstimate, Felt, FunctionCall, MsgToL1, StateDiff, TxnHash, + BlockId, BroadcastedTxn, Event, FeeEstimate, FunctionCall, MsgToL1, StateDiff, TxnHash, }; use alloc::string::String; use alloc::vec::Vec; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize}; +use starknet_types_core::felt::Felt; #[derive(Serialize, Deserialize, Copy, PartialEq, Eq, Hash, Clone, Debug)] pub enum CallType { diff --git a/crates/starknet-types-rpc/src/v0_5_0/starknet_write_api.rs b/crates/starknet-types-rpc/src/v0_5_0/starknet_write_api.rs index 00652884..34cc3540 100644 --- a/crates/starknet-types-rpc/src/v0_5_0/starknet_write_api.rs +++ b/crates/starknet-types-rpc/src/v0_5_0/starknet_write_api.rs @@ -8,11 +8,10 @@ // https://github.com/nils-mathieu/openrpc-gen // -use super::{ - BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, Felt, TxnHash, -}; +use super::{BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, TxnHash}; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize}; +use starknet_types_core::felt::Felt; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ClassAndTxnHash { diff --git a/crates/starknet-types-rpc/src/v0_5_0/syncing_status.rs b/crates/starknet-types-rpc/src/v0_5_0/syncing_status.rs new file mode 100644 index 00000000..7877bfc3 --- /dev/null +++ b/crates/starknet-types-rpc/src/v0_5_0/syncing_status.rs @@ -0,0 +1,88 @@ +use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use super::SyncStatus; + +/// The syncing status of a node. +#[derive(Clone, Debug)] +pub enum SyncingStatus { + /// The node is not syncing. + NotSyncing, + /// The node is syncing. + Syncing(SyncStatus), +} + +impl Serialize for SyncingStatus { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + SyncingStatus::NotSyncing => serializer.serialize_bool(false), + SyncingStatus::Syncing(status) => status.serialize(serializer), + } + } +} + +impl<'de> Deserialize<'de> for SyncingStatus { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SyncingStatusVisitor; + + impl<'de> Visitor<'de> for SyncingStatusVisitor { + type Value = SyncingStatus; + + fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + writeln!(formatter, "a syncing status") + } + + fn visit_bool(self, v: bool) -> Result + where + E: serde::de::Error, + { + if v { + Err(serde::de::Error::custom("expected a syncing status")) + } else { + Ok(SyncingStatus::NotSyncing) + } + } + + fn visit_map(self, map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let status = + SyncStatus::deserialize(serde::de::value::MapAccessDeserializer::new(map))?; + + Ok(SyncingStatus::Syncing(status)) + } + } + + deserializer.deserialize_any(SyncingStatusVisitor) + } +} + +#[cfg(test)] +#[test] +fn syncing_status_from_false() { + let s = "false"; + let syncing_status: SyncingStatus = serde_json::from_str(s).unwrap(); + assert!(matches!(syncing_status, SyncingStatus::NotSyncing)); +} + +#[cfg(test)] +#[test] +fn syncing_status_to_false() { + let syncing_status = SyncingStatus::NotSyncing; + let s = serde_json::to_string(&syncing_status).unwrap(); + assert_eq!(s, "false"); +} + +#[cfg(test)] +#[test] +fn syncing_status_from_true() { + let s = "true"; + assert!(serde_json::from_str::(s).is_err()); +} diff --git a/crates/starknet-types-rpc/src/v0_6_0/block_id.rs b/crates/starknet-types-rpc/src/v0_6_0/block_id.rs new file mode 100644 index 00000000..c288f96d --- /dev/null +++ b/crates/starknet-types-rpc/src/v0_6_0/block_id.rs @@ -0,0 +1,129 @@ +use serde::{Deserialize, Deserializer, Serialize}; + +use super::{BlockHash, BlockNumber, BlockTag}; + +/// A hexadecimal number. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum BlockId { + /// The tag of the block. + Tag(BlockTag), + /// The hash of the block. + Hash(BlockHash), + /// The height of the block. + Number(BlockNumber), +} + +#[derive(Serialize, Deserialize)] +struct BlockHashHelper { + block_hash: BlockHash, +} + +#[derive(Serialize, Deserialize)] +struct BlockNumberHelper { + block_number: BlockNumber, +} + +#[derive(Deserialize)] +#[serde(untagged)] +enum BlockIdHelper { + Tag(BlockTag), + Hash(BlockHashHelper), + Number(BlockNumberHelper), +} + +impl serde::Serialize for BlockId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match *self { + BlockId::Tag(tag) => tag.serialize(serializer), + BlockId::Hash(block_hash) => { + let helper = BlockHashHelper { block_hash }; + helper.serialize(serializer) + } + BlockId::Number(block_number) => { + let helper = BlockNumberHelper { block_number }; + helper.serialize(serializer) + } + } + } +} + +impl<'de> serde::Deserialize<'de> for BlockId { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let helper = BlockIdHelper::deserialize(deserializer)?; + match helper { + BlockIdHelper::Tag(tag) => Ok(BlockId::Tag(tag)), + BlockIdHelper::Hash(helper) => Ok(BlockId::Hash(helper.block_hash)), + BlockIdHelper::Number(helper) => Ok(BlockId::Number(helper.block_number)), + } + } +} + +#[test] +fn block_id_from_hash() { + use starknet_types_core::felt::Felt; + + let s = "{\"block_hash\":\"0x123\"}"; + let block_id: BlockId = serde_json::from_str(s).unwrap(); + assert_eq!(block_id, BlockId::Hash(Felt::from_hex("0x123").unwrap())); +} + +#[test] +fn block_id_from_number() { + let s = "{\"block_number\":123}"; + let block_id: BlockId = serde_json::from_str(s).unwrap(); + assert_eq!(block_id, BlockId::Number(123)); +} + +#[test] +fn block_id_from_latest() { + let s = "\"latest\""; + let block_id: BlockId = serde_json::from_str(s).unwrap(); + assert_eq!(block_id, BlockId::Tag(BlockTag::Latest)); +} + +#[test] +fn block_id_from_pending() { + let s = "\"pending\""; + let block_id: BlockId = serde_json::from_str(s).unwrap(); + assert_eq!(block_id, BlockId::Tag(BlockTag::Pending)); +} + +#[cfg(test)] +#[test] +fn block_id_to_hash() { + use starknet_types_core::felt::Felt; + + let block_id = BlockId::Hash(Felt::from_hex("0x123").unwrap()); + let s = serde_json::to_string(&block_id).unwrap(); + assert_eq!(s, "{\"block_hash\":\"0x123\"}"); +} + +#[cfg(test)] +#[test] +fn block_id_to_number() { + let block_id = BlockId::Number(123); + let s = serde_json::to_string(&block_id).unwrap(); + assert_eq!(s, "{\"block_number\":123}"); +} + +#[cfg(test)] +#[test] +fn block_id_to_latest() { + let block_id = BlockId::Tag(BlockTag::Latest); + let s = serde_json::to_string(&block_id).unwrap(); + assert_eq!(s, "\"latest\""); +} + +#[cfg(test)] +#[test] +fn block_id_to_pending() { + let block_id = BlockId::Tag(BlockTag::Pending); + let s = serde_json::to_string(&block_id).unwrap(); + assert_eq!(s, "\"pending\""); +} diff --git a/crates/starknet-types-rpc/src/v0_6_0/mod.rs b/crates/starknet-types-rpc/src/v0_6_0/mod.rs index 4570a01b..db484d76 100644 --- a/crates/starknet-types-rpc/src/v0_6_0/mod.rs +++ b/crates/starknet-types-rpc/src/v0_6_0/mod.rs @@ -1,16 +1,15 @@ //! v0.6.0 of the API. -pub use starknet_types_core::felt::Felt; - -pub use crate::custom::{ - BlockId, BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, - SyncingStatus, -}; - +mod block_id; +mod query; mod starknet_api_openrpc; mod starknet_trace_api_openrpc; mod starknet_write_api; +mod syncing_status; +pub use self::block_id::*; +pub use self::query::*; pub use self::starknet_api_openrpc::*; pub use self::starknet_trace_api_openrpc::*; pub use self::starknet_write_api::*; +pub use self::syncing_status::*; diff --git a/crates/starknet-types-rpc/src/v0_6_0/query.rs b/crates/starknet-types-rpc/src/v0_6_0/query.rs new file mode 100644 index 00000000..0f9f2820 --- /dev/null +++ b/crates/starknet-types-rpc/src/v0_6_0/query.rs @@ -0,0 +1,48 @@ +// query offset: +// 0x0000000000000000000000000000000100000000000000000000000000000000 + +use serde::{Deserialize, Serialize}; + +use super::{ + BroadcastedDeclareTxnV1, BroadcastedDeclareTxnV2, DeployAccountTxnV1, InvokeTxnV0, InvokeTxnV1, +}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "version")] +pub enum BroadcastedDeclareTxn { + #[serde(rename = "0x1")] + V1(BroadcastedDeclareTxnV1), + #[serde(rename = "0x2")] + V2(BroadcastedDeclareTxnV2), + /// Query-only broadcasted declare transaction. + #[serde(rename = "0x0000000000000000000000000000000100000000000000000000000000000001")] + QueryV1(BroadcastedDeclareTxnV1), + /// Query-only broadcasted declare transaction. + #[serde(rename = "0x100000000000000000000000000000002")] + QueryV2(BroadcastedDeclareTxnV2), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "version")] +pub enum BroadcastedDeployAccountTxn { + #[serde(rename = "0x1")] + V1(DeployAccountTxnV1), + /// Query-only broadcasted deploy account transaction. + #[serde(rename = "0x0000000000000000000000000000000100000000000000000000000000000001")] + QueryV1(DeployAccountTxnV1), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "version")] +pub enum BroadcastedInvokeTxn { + #[serde(rename = "0x0")] + V0(InvokeTxnV0), + #[serde(rename = "0x1")] + V1(InvokeTxnV1), + /// Query-only broadcasted invoke transaction. + #[serde(rename = "0x0000000000000000000000000000000100000000000000000000000000000000")] + QueryV0(InvokeTxnV0), + /// Query-only broadcasted invoke transaction. + #[serde(rename = "0x0000000000000000000000000000000100000000000000000000000000000001")] + QueryV1(InvokeTxnV1), +} diff --git a/crates/starknet-types-rpc/src/v0_6_0/starknet_api_openrpc.rs b/crates/starknet-types-rpc/src/v0_6_0/starknet_api_openrpc.rs index eb98689e..f8defe49 100644 --- a/crates/starknet-types-rpc/src/v0_6_0/starknet_api_openrpc.rs +++ b/crates/starknet-types-rpc/src/v0_6_0/starknet_api_openrpc.rs @@ -8,14 +8,13 @@ // https://github.com/nils-mathieu/openrpc-gen // -use super::{ - BlockId, BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, Felt, -}; +use super::{BlockId, BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn}; use crate::custom_serde::NumAsHex; use alloc::string::String; use alloc::vec::Vec; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize}; +use starknet_types_core::felt::Felt; pub type Address = Felt; diff --git a/crates/starknet-types-rpc/src/v0_6_0/starknet_trace_api_openrpc.rs b/crates/starknet-types-rpc/src/v0_6_0/starknet_trace_api_openrpc.rs index 45cb09b9..e81f35b6 100644 --- a/crates/starknet-types-rpc/src/v0_6_0/starknet_trace_api_openrpc.rs +++ b/crates/starknet-types-rpc/src/v0_6_0/starknet_trace_api_openrpc.rs @@ -9,13 +9,14 @@ // use super::{ - BlockId, BroadcastedTxn, Event, ExecutionResources, FeeEstimate, Felt, FunctionCall, MsgToL1, + BlockId, BroadcastedTxn, Event, ExecutionResources, FeeEstimate, FunctionCall, MsgToL1, StateDiff, TxnHash, }; use alloc::string::String; use alloc::vec::Vec; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize}; +use starknet_types_core::felt::Felt; #[derive(Serialize, Deserialize, Copy, PartialEq, Eq, Hash, Clone, Debug)] pub enum CallType { diff --git a/crates/starknet-types-rpc/src/v0_6_0/starknet_write_api.rs b/crates/starknet-types-rpc/src/v0_6_0/starknet_write_api.rs index 00652884..34cc3540 100644 --- a/crates/starknet-types-rpc/src/v0_6_0/starknet_write_api.rs +++ b/crates/starknet-types-rpc/src/v0_6_0/starknet_write_api.rs @@ -8,11 +8,10 @@ // https://github.com/nils-mathieu/openrpc-gen // -use super::{ - BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, Felt, TxnHash, -}; +use super::{BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, TxnHash}; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize}; +use starknet_types_core::felt::Felt; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ClassAndTxnHash { diff --git a/crates/starknet-types-rpc/src/v0_6_0/syncing_status.rs b/crates/starknet-types-rpc/src/v0_6_0/syncing_status.rs new file mode 100644 index 00000000..7877bfc3 --- /dev/null +++ b/crates/starknet-types-rpc/src/v0_6_0/syncing_status.rs @@ -0,0 +1,88 @@ +use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use super::SyncStatus; + +/// The syncing status of a node. +#[derive(Clone, Debug)] +pub enum SyncingStatus { + /// The node is not syncing. + NotSyncing, + /// The node is syncing. + Syncing(SyncStatus), +} + +impl Serialize for SyncingStatus { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + SyncingStatus::NotSyncing => serializer.serialize_bool(false), + SyncingStatus::Syncing(status) => status.serialize(serializer), + } + } +} + +impl<'de> Deserialize<'de> for SyncingStatus { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SyncingStatusVisitor; + + impl<'de> Visitor<'de> for SyncingStatusVisitor { + type Value = SyncingStatus; + + fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + writeln!(formatter, "a syncing status") + } + + fn visit_bool(self, v: bool) -> Result + where + E: serde::de::Error, + { + if v { + Err(serde::de::Error::custom("expected a syncing status")) + } else { + Ok(SyncingStatus::NotSyncing) + } + } + + fn visit_map(self, map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let status = + SyncStatus::deserialize(serde::de::value::MapAccessDeserializer::new(map))?; + + Ok(SyncingStatus::Syncing(status)) + } + } + + deserializer.deserialize_any(SyncingStatusVisitor) + } +} + +#[cfg(test)] +#[test] +fn syncing_status_from_false() { + let s = "false"; + let syncing_status: SyncingStatus = serde_json::from_str(s).unwrap(); + assert!(matches!(syncing_status, SyncingStatus::NotSyncing)); +} + +#[cfg(test)] +#[test] +fn syncing_status_to_false() { + let syncing_status = SyncingStatus::NotSyncing; + let s = serde_json::to_string(&syncing_status).unwrap(); + assert_eq!(s, "false"); +} + +#[cfg(test)] +#[test] +fn syncing_status_from_true() { + let s = "true"; + assert!(serde_json::from_str::(s).is_err()); +} diff --git a/crates/starknet-types-rpc/src/custom/block_id.rs b/crates/starknet-types-rpc/src/v0_7_1/block_id.rs similarity index 98% rename from crates/starknet-types-rpc/src/custom/block_id.rs rename to crates/starknet-types-rpc/src/v0_7_1/block_id.rs index e5b92ebf..9cac1bb6 100644 --- a/crates/starknet-types-rpc/src/custom/block_id.rs +++ b/crates/starknet-types-rpc/src/v0_7_1/block_id.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Deserializer, Serialize}; -use crate::{BlockHash, BlockNumber, BlockTag}; +use super::{BlockHash, BlockNumber, BlockTag}; /// A hexadecimal number. #[derive(Debug, Clone, Eq, Hash, PartialEq)] diff --git a/crates/starknet-types-rpc/src/v0_7_1/mod.rs b/crates/starknet-types-rpc/src/v0_7_1/mod.rs index 2df2c821..a949e5e3 100644 --- a/crates/starknet-types-rpc/src/v0_7_1/mod.rs +++ b/crates/starknet-types-rpc/src/v0_7_1/mod.rs @@ -1,13 +1,15 @@ //! v0.7.1 of the API. -pub use crate::custom::{ - BlockId, BroadcastedDeclareTxn, BroadcastedDeployAccountTxn, BroadcastedInvokeTxn, - SyncingStatus, -}; +mod block_id; +mod query; mod starknet_api_openrpc; mod starknet_trace_api_openrpc; mod starknet_write_api; +mod syncing_status; +pub use self::block_id::*; +pub use self::query::*; pub use self::starknet_api_openrpc::*; pub use self::starknet_trace_api_openrpc::*; pub use self::starknet_write_api::*; +pub use self::syncing_status::*; diff --git a/crates/starknet-types-rpc/src/custom/query.rs b/crates/starknet-types-rpc/src/v0_7_1/query.rs similarity index 99% rename from crates/starknet-types-rpc/src/custom/query.rs rename to crates/starknet-types-rpc/src/v0_7_1/query.rs index a96e2de1..1ee58c01 100644 --- a/crates/starknet-types-rpc/src/custom/query.rs +++ b/crates/starknet-types-rpc/src/v0_7_1/query.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; -use crate::{ +use super::{ BroadcastedDeclareTxnV1, BroadcastedDeclareTxnV2, BroadcastedDeclareTxnV3, DeployAccountTxnV1, DeployAccountTxnV3, InvokeTxnV0, InvokeTxnV1, InvokeTxnV3, }; diff --git a/crates/starknet-types-rpc/src/custom/syncing_status.rs b/crates/starknet-types-rpc/src/v0_7_1/syncing_status.rs similarity index 99% rename from crates/starknet-types-rpc/src/custom/syncing_status.rs rename to crates/starknet-types-rpc/src/v0_7_1/syncing_status.rs index d81b57f0..21993ba7 100644 --- a/crates/starknet-types-rpc/src/custom/syncing_status.rs +++ b/crates/starknet-types-rpc/src/v0_7_1/syncing_status.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use serde::de::Visitor; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::SyncStatus; +use super::SyncStatus; /// The syncing status of a node. #[derive(Clone, Debug)]