diff --git a/Cargo.toml b/Cargo.toml index ab430925..d4fdfb7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,21 +8,36 @@ license-file = "LICENSE" description = "Starknet Rust types related to computation and execution." [features] -testing = [] +default = ["std"] +std = [ + "serde/std", + "serde_json/std", + "indexmap/std", + "starknet-crypto/std", + "thiserror-no-std/std" +] +testing = ["std"] [dependencies] -cairo-lang-starknet = "2.4.0-rc2" +cairo-lang-starknet = { version = "2.4.0-rc2", default-features = false } derive_more = "0.99.17" -hex = "0.4.3" -indexmap = { version = "1.9.2", features = ["serde"] } +hex = { version = "0.4.3", default-features = false } +hashbrown = { version = "0.14.0", features = ["serde"] } +indexmap = { version = "1.9.2", features = ["serde"], default-features = false } once_cell = "1.17.1" primitive-types = { version = "0.12.1", features = ["serde"] } -serde = { version = "1.0.130", features = ["derive", "rc"] } -serde_json = "1.0.81" -starknet-crypto = "0.5.1" +serde = { version = "1.0.130", features = ["alloc", "derive", "rc"], default-features = false } +serde_json = { version = "1.0.81", features = [ + "arbitrary_precision", + "alloc", +], default-features = false } +starknet-crypto = { version = "0.5.1", default-features = false, features = [ + "signature-display", + "alloc", +] } strum = "0.24.1" strum_macros = "0.24.3" -thiserror = "1.0.31" +thiserror-no-std = { version = "2.0.2", default-features = false } [dev-dependencies] assert_matches = "1.5.0" diff --git a/src/block.rs b/src/block.rs index c26afa7e..4390c24a 100644 --- a/src/block.rs +++ b/src/block.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; use crate::core::{ContractAddress, GlobalRoot}; use crate::hash::StarkHash; use crate::serde_utils::{BytesAsHex, PrefixedBytesAsHex}; +use crate::stdlib::vec::Vec; use crate::transaction::{Transaction, TransactionHash, TransactionOutput}; /// A block. diff --git a/src/core.rs b/src/core.rs index 25d5cbc6..8c6c7fcd 100644 --- a/src/core.rs +++ b/src/core.rs @@ -2,8 +2,6 @@ #[path = "core_test.rs"] mod core_test; -use std::fmt::Debug; - use derive_more::Display; use once_cell::sync::Lazy; use primitive_types::H160; @@ -12,6 +10,9 @@ use starknet_crypto::FieldElement; use crate::hash::{pedersen_hash_array, StarkFelt, StarkHash}; use crate::serde_utils::{BytesAsHex, PrefixedBytesAsHex}; +use crate::stdlib::fmt::Debug; +use crate::stdlib::string::{String, ToString}; +use crate::stdlib::{fmt, format, mem}; use crate::transaction::{Calldata, ContractAddressSalt}; use crate::{impl_from_through_intermediate, StarknetApiError}; @@ -209,13 +210,12 @@ impl TryFrom for PatriciaKey { } impl Debug for PatriciaKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("PatriciaKey").field(&self.0).finish() } } /// A utility macro to create a [`PatriciaKey`] from a hex string / unsigned integer representation. -#[cfg(any(feature = "testing", test))] #[macro_export] macro_rules! patricia_key { ($s:expr) => { @@ -224,7 +224,6 @@ macro_rules! patricia_key { } /// A utility macro to create a [`ClassHash`] from a hex string / unsigned integer representation. -#[cfg(any(feature = "testing", test))] #[macro_export] macro_rules! class_hash { ($s:expr) => { @@ -234,7 +233,6 @@ macro_rules! class_hash { /// A utility macro to create a [`ContractAddress`] from a hex string / unsigned integer /// representation. -#[cfg(any(feature = "testing", test))] #[macro_export] macro_rules! contract_address { ($s:expr) => { @@ -242,7 +240,6 @@ macro_rules! contract_address { }; } -/// An Ethereum address. #[derive( Debug, Copy, Clone, Default, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord, )] @@ -252,7 +249,7 @@ pub struct EthAddress(pub H160); impl TryFrom for EthAddress { type Error = StarknetApiError; fn try_from(felt: StarkFelt) -> Result { - const COMPLIMENT_OF_H160: usize = std::mem::size_of::() - H160::len_bytes(); + const COMPLIMENT_OF_H160: usize = mem::size_of::() - H160::len_bytes(); let (rest, h160_bytes) = felt.bytes().split_at(COMPLIMENT_OF_H160); if rest != [0u8; COMPLIMENT_OF_H160] { diff --git a/src/data_availability.rs b/src/data_availability.rs index d494ca84..abe2cc1d 100644 --- a/src/data_availability.rs +++ b/src/data_availability.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; use crate::hash::StarkFelt; +use crate::stdlib::format; use crate::StarknetApiError; #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] diff --git a/src/deprecated_contract_class.rs b/src/deprecated_contract_class.rs index d7c00fd8..028a1f27 100644 --- a/src/deprecated_contract_class.rs +++ b/src/deprecated_contract_class.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use cairo_lang_starknet::casm_contract_class::CasmContractEntryPoint; use serde::de::Error as DeserializationError; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -7,6 +5,10 @@ use serde_json::Value; use crate::core::EntryPointSelector; use crate::serde_utils::deserialize_optional_contract_class_abi_entry_vector; +use crate::stdlib::collections::HashMap; +use crate::stdlib::string::String; +use crate::stdlib::vec::Vec; +use crate::stdlib::{format, num}; use crate::StarknetApiError; /// A deprecated contract class. @@ -168,7 +170,7 @@ pub fn number_or_string<'de, D: Deserializer<'de>>(deserializer: D) -> Result Result { +fn hex_string_try_into_usize(hex_string: &str) -> Result { usize::from_str_radix(hex_string.trim_start_matches("0x"), 16) } diff --git a/src/hash.rs b/src/hash.rs index ee48b358..fcd2b0e2 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -2,20 +2,25 @@ #[path = "hash_test.rs"] mod hash_test; -use std::fmt::{Debug, Display}; +#[cfg(feature = "std")] use std::io::Error; use serde::{Deserialize, Serialize}; use starknet_crypto::{pedersen_hash as starknet_crypto_pedersen_hash, FieldElement}; use crate::serde_utils::{bytes_from_hex_str, hex_str_from_bytes, BytesAsHex, PrefixedBytesAsHex}; +use crate::stdlib::fmt::{Debug, Display}; +use crate::stdlib::string::ToString; +use crate::stdlib::{fmt, format, mem}; use crate::{impl_from_through_intermediate, StarknetApiError}; /// Genesis state hash. pub const GENESIS_HASH: &str = "0x0"; // Felt encoding constants. +#[cfg(feature = "std")] const CHOOSER_FULL: u8 = 15; +#[cfg(feature = "std")] const CHOOSER_HALF: u8 = 14; /// An alias for [`StarkFelt`]. @@ -80,6 +85,7 @@ impl StarkFelt { Self(bytes) } + #[cfg(feature = "std")] /// Storage efficient serialization for field elements. pub fn serialize(&self, res: &mut impl std::io::Write) -> Result<(), Error> { // We use the fact that bytes[0] < 0x10 and encode the size of the felt in the 4 most @@ -120,6 +126,7 @@ impl StarkFelt { Ok(()) } + #[cfg(feature = "std")] /// Storage efficient deserialization for field elements. pub fn deserialize(bytes: &mut impl std::io::Read) -> Option { let mut res = [0u8; 32]; @@ -146,7 +153,7 @@ impl StarkFelt { &self.0 } - fn str_format(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn str_format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = format!("0x{}", hex::encode(self.0)); f.debug_tuple("StarkFelt").field(&s).finish() } @@ -201,8 +208,7 @@ impl From for PrefixedBytesAsHex<32_usize> { impl TryFrom for usize { type Error = StarknetApiError; fn try_from(felt: StarkFelt) -> Result { - const COMPLIMENT_OF_USIZE: usize = - std::mem::size_of::() - std::mem::size_of::(); + const COMPLIMENT_OF_USIZE: usize = mem::size_of::() - mem::size_of::(); let (rest, usize_bytes) = felt.bytes().split_at(COMPLIMENT_OF_USIZE); if rest != [0u8; COMPLIMENT_OF_USIZE] { @@ -231,19 +237,18 @@ impl TryFrom for u64 { } impl Debug for StarkFelt { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.str_format(f) } } impl Display for StarkFelt { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{}", hex::encode(self.0)) } } /// A utility macro to create a [`StarkFelt`] from a hex string representation. -#[cfg(any(feature = "testing", test))] #[macro_export] macro_rules! stark_felt { ($s:expr) => { diff --git a/src/lib.rs b/src/lib.rs index 5403a0ce..9a975ac7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,14 @@ //! //! [`Starknet`]: https://starknet.io/ +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "std")] +include!("./with_std.rs"); + +#[cfg(not(feature = "std"))] +include!("./without_std.rs"); + pub mod block; pub mod core; pub mod data_availability; @@ -12,23 +20,43 @@ pub mod state; pub mod transaction; pub mod type_utils; -use std::num::ParseIntError; - -use serde_utils::InnerDeserializationError; - -/// The error type returned by StarknetApi. -#[derive(thiserror::Error, Clone, Debug)] -pub enum StarknetApiError { - /// Error in the inner deserialization of the node. - #[error(transparent)] - InnerDeserialization(#[from] InnerDeserializationError), - #[error("Out of range {string}.")] - /// An error for when a value is out of range. - OutOfRange { string: String }, - /// Error when serializing into number. - #[error(transparent)] - ParseIntError(#[from] ParseIntError), - /// Missing resource type / duplicated resource type. - #[error("Missing resource type / duplicated resource type; got {0}.")] - InvalidResourceMappingInitializer(String), +pub mod stdlib { + pub mod collections { + #[cfg(feature = "std")] + pub use crate::with_std::collections::*; + #[cfg(not(feature = "std"))] + pub use crate::without_std::collections::*; + } + + #[cfg(feature = "std")] + pub use crate::with_std::*; + #[cfg(not(feature = "std"))] + pub use crate::without_std::*; } + +mod api_error { + use thiserror_no_std::Error; + + use crate::serde_utils::InnerDeserializationError; + use crate::stdlib::num; + use crate::stdlib::string::String; + + /// The error type returned by StarknetApi. + #[derive(Error, Clone, Debug)] + pub enum StarknetApiError { + /// Error in the inner deserialization of the node. + #[error(transparent)] + InnerDeserialization(#[from] InnerDeserializationError), + #[error("Out of range {string}.")] + /// An error for when a value is out of range. + OutOfRange { string: String }, + /// Error when serializing into number. + #[error(transparent)] + ParseIntError(#[from] num::ParseIntError), + /// Missing resource type / duplicated resource type. + #[error("Missing resource type / duplicated resource type; got {0}.")] + InvalidResourceMappingInitializer(String), + } +} + +pub use api_error::*; diff --git a/src/serde_utils.rs b/src/serde_utils.rs index 52144e41..162e295b 100644 --- a/src/serde_utils.rs +++ b/src/serde_utils.rs @@ -6,8 +6,13 @@ mod serde_utils_test; use serde::de::{Deserialize, Visitor}; use serde::ser::{Serialize, SerializeTuple}; use serde::Deserializer; +use thiserror_no_std::Error; use crate::deprecated_contract_class::ContractClassAbiEntry; +use crate::stdlib::borrow::ToOwned; +use crate::stdlib::string::{String, ToString}; +use crate::stdlib::vec::Vec; +use crate::stdlib::{fmt, format, vec}; /// A [BytesAsHex](`crate::serde_utils::BytesAsHex`) prefixed with '0x'. pub type PrefixedBytesAsHex = BytesAsHex; @@ -28,7 +33,7 @@ impl<'de, const N: usize, const PREFIXED: bool> Deserialize<'de> for BytesAsHex< impl<'de, const N: usize, const PREFIXED: bool> Visitor<'de> for ByteArrayVisitor { type Value = BytesAsHex; - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a byte array") } @@ -76,7 +81,7 @@ impl Serialize for BytesAsHex } /// The error type returned by the inner deserialization. -#[derive(thiserror::Error, Clone, Debug)] +#[derive(Error, Clone, Debug)] pub enum InnerDeserializationError { /// Error parsing the hex string. #[error(transparent)] diff --git a/src/state.rs b/src/state.rs index 133b5807..d023603c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -2,9 +2,6 @@ #[path = "state_test.rs"] mod state_test; -use std::collections::HashMap; -use std::fmt::Debug; - use indexmap::IndexMap; use serde::{Deserialize, Serialize}; @@ -15,6 +12,10 @@ use crate::core::{ }; use crate::deprecated_contract_class::ContractClass as DeprecatedContractClass; use crate::hash::{StarkFelt, StarkHash}; +use crate::stdlib::collections::HashMap; +use crate::stdlib::fmt::Debug; +use crate::stdlib::string::String; +use crate::stdlib::vec::Vec; use crate::{impl_from_through_intermediate, StarknetApiError}; pub type DeclaredClasses = IndexMap; diff --git a/src/state_test.rs b/src/state_test.rs index 3e49b9de..ff996471 100644 --- a/src/state_test.rs +++ b/src/state_test.rs @@ -1,8 +1,7 @@ -use std::collections::HashMap; - use serde_json::json; use crate::deprecated_contract_class::EntryPointOffset; +use crate::stdlib::collections::HashMap; #[test] fn entry_point_offset_from_json_str() { diff --git a/src/transaction.rs b/src/transaction.rs index 1122beff..54075257 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,7 +1,3 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::fmt::Display; -use std::sync::Arc; - use derive_more::From; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use strum::IntoEnumIterator; @@ -14,6 +10,12 @@ use crate::core::{ use crate::data_availability::DataAvailabilityMode; use crate::hash::{StarkFelt, StarkHash}; use crate::serde_utils::PrefixedBytesAsHex; +use crate::stdlib::collections::{BTreeMap, HashMap, HashSet}; +use crate::stdlib::fmt; +use crate::stdlib::fmt::Display; +use crate::stdlib::string::String; +use crate::stdlib::sync::Arc; +use crate::stdlib::vec::Vec; use crate::StarknetApiError; /// A transaction. @@ -422,7 +424,7 @@ impl From for StarkFelt { pub struct TransactionHash(pub StarkHash); impl Display for TransactionHash { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } diff --git a/src/with_std.rs b/src/with_std.rs new file mode 100644 index 00000000..61807e43 --- /dev/null +++ b/src/with_std.rs @@ -0,0 +1,15 @@ +pub mod with_std { + pub use std::borrow; + pub use std::fmt; + pub use std::format; + pub use std::mem; + pub use std::num; + + pub use std::string; + pub use std::sync; + pub use std::vec; + + pub mod collections { + pub use std::collections::{BTreeMap, HashMap, HashSet}; + } +} \ No newline at end of file diff --git a/src/without_std.rs b/src/without_std.rs new file mode 100644 index 00000000..2921fa56 --- /dev/null +++ b/src/without_std.rs @@ -0,0 +1,26 @@ +#[macro_use] +pub extern crate alloc; + +pub mod without_std { + pub use core::fmt; + pub use core::hash; + pub use core::mem; + pub use core::num; + + pub use alloc::boxed; + pub use alloc::format; + pub use alloc::rc; + pub use alloc::string; + pub use alloc::sync; + pub use alloc::vec; + + pub mod collections { + pub use alloc::collections::BTreeMap; + pub use hashbrown::{HashMap, HashSet}; + } + + pub mod borrow { + pub use alloc::borrow::*; + pub use core::borrow::*; + } +} \ No newline at end of file