Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for no-std environment #155

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
31 changes: 23 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
1 change: 1 addition & 0 deletions src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
13 changes: 5 additions & 8 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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};

Expand Down Expand Up @@ -209,13 +210,12 @@ impl TryFrom<StarkHash> 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) => {
Expand All @@ -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) => {
Expand All @@ -234,15 +233,13 @@ 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) => {
ContractAddress(patricia_key!($s))
};
}

/// An Ethereum address.
#[derive(
Debug, Copy, Clone, Default, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord,
)]
Expand All @@ -252,7 +249,7 @@ pub struct EthAddress(pub H160);
impl TryFrom<StarkFelt> for EthAddress {
type Error = StarknetApiError;
fn try_from(felt: StarkFelt) -> Result<Self, Self::Error> {
const COMPLIMENT_OF_H160: usize = std::mem::size_of::<StarkFelt>() - H160::len_bytes();
const COMPLIMENT_OF_H160: usize = mem::size_of::<StarkFelt>() - H160::len_bytes();

let (rest, h160_bytes) = felt.bytes().split_at(COMPLIMENT_OF_H160);
if rest != [0u8; COMPLIMENT_OF_H160] {
Expand Down
1 change: 1 addition & 0 deletions src/data_availability.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
8 changes: 5 additions & 3 deletions src/deprecated_contract_class.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use std::collections::HashMap;

use cairo_lang_starknet::casm_contract_class::CasmContractEntryPoint;
use serde::de::Error as DeserializationError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
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.
Expand Down Expand Up @@ -168,7 +170,7 @@ pub fn number_or_string<'de, D: Deserializer<'de>>(deserializer: D) -> Result<us
Ok(usize_value)
}

fn hex_string_try_into_usize(hex_string: &str) -> Result<usize, std::num::ParseIntError> {
fn hex_string_try_into_usize(hex_string: &str) -> Result<usize, num::ParseIntError> {
usize::from_str_radix(hex_string.trim_start_matches("0x"), 16)
}

Expand Down
19 changes: 12 additions & 7 deletions src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`].
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<Self> {
let mut res = [0u8; 32];
Expand All @@ -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()
}
Expand Down Expand Up @@ -201,8 +208,7 @@ impl From<StarkFelt> for PrefixedBytesAsHex<32_usize> {
impl TryFrom<StarkFelt> for usize {
type Error = StarknetApiError;
fn try_from(felt: StarkFelt) -> Result<Self, Self::Error> {
const COMPLIMENT_OF_USIZE: usize =
std::mem::size_of::<StarkFelt>() - std::mem::size_of::<usize>();
const COMPLIMENT_OF_USIZE: usize = mem::size_of::<StarkFelt>() - mem::size_of::<usize>();

let (rest, usize_bytes) = felt.bytes().split_at(COMPLIMENT_OF_USIZE);
if rest != [0u8; COMPLIMENT_OF_USIZE] {
Expand Down Expand Up @@ -231,19 +237,18 @@ impl TryFrom<StarkFelt> 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) => {
Expand Down
66 changes: 47 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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::*;
9 changes: 7 additions & 2 deletions src/serde_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<const N: usize> = BytesAsHex<N, true>;
Expand All @@ -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<N, PREFIXED> {
type Value = BytesAsHex<N, PREFIXED>;

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")
}

Expand Down Expand Up @@ -76,7 +81,7 @@ impl<const N: usize, const PREFIXED: bool> Serialize for BytesAsHex<N, PREFIXED>
}

/// 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)]
Expand Down
7 changes: 4 additions & 3 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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<ClassHash, ContractClass>;
Expand Down
3 changes: 1 addition & 2 deletions src/state_test.rs
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down
Loading