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

Return OutOfRange instead of StarknetApiError whenever a method can only return OutOfRange #174

Open
wants to merge 1 commit 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
25 changes: 12 additions & 13 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::crypto::PublicKey;
use crate::hash::{pedersen_hash_array, StarkFelt, StarkHash};
use crate::serde_utils::{BytesAsHex, PrefixedBytesAsHex};
use crate::transaction::{Calldata, ContractAddressSalt};
use crate::{impl_from_through_intermediate, StarknetApiError};
use crate::{impl_from_through_intermediate, OutOfRangeError, StarknetApiError};

/// A chain id.
#[derive(Clone, Debug, Display, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)]
Expand Down Expand Up @@ -78,7 +78,7 @@ pub static L2_ADDRESS_UPPER_BOUND: Lazy<FieldElement> = Lazy::new(|| {
});

impl TryFrom<StarkHash> for ContractAddress {
type Error = StarknetApiError;
type Error = OutOfRangeError;
fn try_from(hash: StarkHash) -> Result<Self, Self::Error> {
Ok(Self(PatriciaKey::try_from(hash)?))
}
Expand All @@ -102,7 +102,7 @@ pub fn calculate_contract_address(
]));
address = address % *L2_ADDRESS_UPPER_BOUND;

ContractAddress::try_from(StarkFelt::from(address))
Ok(ContractAddress::try_from(StarkFelt::from(address))?)
}

/// The hash of a ContractClass.
Expand Down Expand Up @@ -158,12 +158,12 @@ pub struct CompiledClassHash(pub StarkHash);
pub struct Nonce(pub StarkFelt);

impl Nonce {
pub fn try_increment(&self) -> Result<Self, StarknetApiError> {
pub fn try_increment(&self) -> Result<Self, OutOfRangeError> {
let current_nonce = FieldElement::from(self.0);

// Check if an overflow occurred during increment.
match StarkFelt::from(current_nonce + FieldElement::ONE) {
StarkFelt::ZERO => Err(StarknetApiError::OutOfRange { string: format!("{:?}", self) }),
StarkFelt::ZERO => Err(OutOfRangeError { string: format!("{:?}", self) }),
incremented_felt => Ok(Self(incremented_felt)),
}
}
Expand Down Expand Up @@ -229,13 +229,13 @@ impl From<u128> for PatriciaKey {
impl_from_through_intermediate!(u128, PatriciaKey, u8, u16, u32, u64);

impl TryFrom<StarkHash> for PatriciaKey {
type Error = StarknetApiError;
type Error = OutOfRangeError;

fn try_from(value: StarkHash) -> Result<Self, Self::Error> {
if value < *CONTRACT_ADDRESS_DOMAIN_SIZE {
return Ok(PatriciaKey(value));
}
Err(StarknetApiError::OutOfRange { string: format!("[0x0, {PATRICIA_KEY_UPPER_BOUND})") })
Err(OutOfRangeError { string: format!("[0x0, {PATRICIA_KEY_UPPER_BOUND})") })
}
}

Expand Down Expand Up @@ -281,13 +281,13 @@ macro_rules! contract_address {
pub struct EthAddress(pub H160);

impl TryFrom<StarkFelt> for EthAddress {
type Error = StarknetApiError;
type Error = OutOfRangeError;
fn try_from(felt: StarkFelt) -> Result<Self, Self::Error> {
const COMPLIMENT_OF_H160: usize = std::mem::size_of::<StarkFelt>() - H160::len_bytes();

let (rest, h160_bytes) = felt.bytes().split_at(COMPLIMENT_OF_H160);
if rest != [0u8; COMPLIMENT_OF_H160] {
return Err(StarknetApiError::OutOfRange { string: felt.to_string() });
return Err(OutOfRangeError { string: felt.to_string() });
}

Ok(EthAddress(H160::from_slice(h160_bytes)))
Expand All @@ -303,10 +303,9 @@ impl From<EthAddress> for StarkFelt {
}
}

impl TryFrom<PrefixedBytesAsHex<20_usize>> for EthAddress {
type Error = StarknetApiError;
fn try_from(val: PrefixedBytesAsHex<20_usize>) -> Result<Self, Self::Error> {
Ok(EthAddress(H160::from_slice(&val.0)))
impl From<PrefixedBytesAsHex<20_usize>> for EthAddress {
fn from(val: PrefixedBytesAsHex<20_usize>) -> Self {
EthAddress(H160::from_slice(&val.0))
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/core_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use assert_matches::assert_matches;
use starknet_crypto::FieldElement;

use crate::core::{
calculate_contract_address, ClassHash, ContractAddress, EthAddress, Nonce, PatriciaKey,
StarknetApiError, CONTRACT_ADDRESS_PREFIX, L2_ADDRESS_UPPER_BOUND,
calculate_contract_address, ClassHash, ContractAddress, EthAddress, Nonce, OutOfRangeError,
PatriciaKey, CONTRACT_ADDRESS_PREFIX, L2_ADDRESS_UPPER_BOUND,
};
use crate::hash::{pedersen_hash_array, StarkFelt, StarkHash};
use crate::transaction::{Calldata, ContractAddressSalt};
Expand All @@ -21,7 +21,7 @@ fn patricia_key_out_of_range() {
// 2**251
let hash = stark_felt!("0x800000000000000000000000000000000000000000000000000000000000000");
let err = PatriciaKey::try_from(hash);
assert_matches!(err, Err(StarknetApiError::OutOfRange { string: _err_str }));
assert_matches!(err, Err(OutOfRangeError { string: _err_str }));
}

#[test]
Expand Down Expand Up @@ -82,5 +82,5 @@ fn nonce_overflow() {
let max_nonce = Nonce(StarkFelt::from(FieldElement::MAX));

let overflowed_nonce = max_nonce.try_increment();
assert_matches!(overflowed_nonce, Err(StarknetApiError::OutOfRange { string: _err_str }));
assert_matches!(overflowed_nonce, Err(OutOfRangeError { string: _err_str }));
}
12 changes: 6 additions & 6 deletions src/data_availability.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};

use crate::hash::StarkFelt;
use crate::StarknetApiError;
use crate::OutOfRangeError;

#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum DataAvailabilityMode {
Expand All @@ -10,15 +10,15 @@ pub enum DataAvailabilityMode {
}

impl TryFrom<StarkFelt> for DataAvailabilityMode {
type Error = StarknetApiError;
type Error = OutOfRangeError;

fn try_from(felt: StarkFelt) -> Result<Self, StarknetApiError> {
fn try_from(felt: StarkFelt) -> Result<Self, OutOfRangeError> {
match felt {
StarkFelt::ZERO => Ok(DataAvailabilityMode::L1),
StarkFelt::ONE => Ok(DataAvailabilityMode::L2),
_ => Err(StarknetApiError::OutOfRange {
string: format!("Invalid data availability mode: {felt}."),
}),
_ => {
Err(OutOfRangeError { string: format!("Invalid data availability mode: {felt}.") })
}
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use starknet_crypto::{
};

use crate::serde_utils::{bytes_from_hex_str, hex_str_from_bytes, BytesAsHex, PrefixedBytesAsHex};
use crate::{impl_from_through_intermediate, StarknetApiError};
use crate::{impl_from_through_intermediate, OutOfRangeError, StarknetApiError};

/// Genesis state hash.
pub const GENESIS_HASH: &str = "0x0";
Expand Down Expand Up @@ -61,12 +61,12 @@ pub struct StarkFelt([u8; 32]);

impl StarkFelt {
/// Returns a new [`StarkFelt`].
pub fn new(bytes: [u8; 32]) -> Result<StarkFelt, StarknetApiError> {
pub fn new(bytes: [u8; 32]) -> Result<StarkFelt, OutOfRangeError> {
// msb nibble must be 0. This is not a tight bound.
if bytes[0] < 0x10 {
return Ok(Self(bytes));
}
Err(StarknetApiError::OutOfRange { string: hex_str_from_bytes::<32, true>(bytes) })
Err(OutOfRangeError { string: hex_str_from_bytes::<32, true>(bytes) })
}

/// Returns a new *unchecked* [`StarkFelt`]
Expand Down Expand Up @@ -183,7 +183,7 @@ impl StarkFelt {
}

impl TryFrom<PrefixedBytesAsHex<32_usize>> for StarkFelt {
type Error = StarknetApiError;
type Error = OutOfRangeError;
fn try_from(val: PrefixedBytesAsHex<32_usize>) -> Result<Self, Self::Error> {
StarkFelt::new(val.0)
}
Expand All @@ -194,7 +194,7 @@ impl TryFrom<&str> for StarkFelt {
fn try_from(val: &str) -> Result<Self, Self::Error> {
let val = val.trim_start_matches("0x");
let bytes = bytes_from_hex_str::<32, false>(val)?;
Self::new(bytes)
Ok(Self::new(bytes)?)
}
}

Expand Down Expand Up @@ -229,14 +229,14 @@ impl From<StarkFelt> for PrefixedBytesAsHex<32_usize> {
// TODO(Arni, 25/6/2023): Remove impl TryFrom<StarkFelt> for usize. Leave only one conversion from
// StarkFelt to integer type.
impl TryFrom<StarkFelt> for usize {
type Error = StarknetApiError;
type Error = OutOfRangeError;
fn try_from(felt: StarkFelt) -> Result<Self, Self::Error> {
const COMPLIMENT_OF_USIZE: usize =
std::mem::size_of::<StarkFelt>() - std::mem::size_of::<usize>();

let (rest, usize_bytes) = felt.bytes().split_at(COMPLIMENT_OF_USIZE);
if rest != [0u8; COMPLIMENT_OF_USIZE] {
return Err(StarknetApiError::OutOfRange { string: felt.to_string() });
return Err(OutOfRangeError { string: felt.to_string() });
}

Ok(usize::from_be_bytes(
Expand All @@ -247,12 +247,12 @@ impl TryFrom<StarkFelt> for usize {

// TODO(Arni, 1/1/2024): This is a Hack. Remove this and implement arethmetics for StarkFelt.
impl TryFrom<StarkFelt> for u64 {
type Error = StarknetApiError;
type Error = OutOfRangeError;
fn try_from(felt: StarkFelt) -> Result<Self, Self::Error> {
const COMPLIMENT_OF_U64: usize = 24; // 32 - 8
let (rest, u64_bytes) = felt.bytes().split_at(COMPLIMENT_OF_U64);
if rest != [0u8; COMPLIMENT_OF_U64] {
return Err(StarknetApiError::OutOfRange { string: felt.to_string() });
return Err(OutOfRangeError { string: felt.to_string() });
}

let bytes: [u8; 8] = u64_bytes.try_into().unwrap();
Expand Down
7 changes: 2 additions & 5 deletions src/hash_test.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use assert_matches::assert_matches;

use crate::hash::{pedersen_hash, pedersen_hash_array, StarkFelt};
use crate::stark_felt;
use crate::transaction::Fee;
use crate::{stark_felt, StarknetApiError};

#[test]
fn pedersen_hash_correctness() {
Expand Down Expand Up @@ -88,6 +86,5 @@ fn felt_to_u64_and_back() {
// Negative flow.
let value: u128 = u128::from(u64::MAX) + 1;
let another_felt: StarkFelt = value.into();
let err = u64::try_from(another_felt).unwrap_err();
assert_matches!(err, StarknetApiError::OutOfRange { .. });
u64::try_from(another_felt).unwrap_err();
}
16 changes: 14 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,25 @@ 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(transparent)]
OutOfRange(OutOfRangeError),
/// 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),
}

#[derive(thiserror::Error, Clone, Debug)]
#[error("Out of range {string}.")]
pub struct OutOfRangeError {
string: String,
}

impl From<OutOfRangeError> for StarknetApiError {
fn from(error: OutOfRangeError) -> Self {
Self::OutOfRange(error)
}
}
4 changes: 2 additions & 2 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::core::{
};
use crate::deprecated_contract_class::ContractClass as DeprecatedContractClass;
use crate::hash::{StarkFelt, StarkHash};
use crate::{impl_from_through_intermediate, StarknetApiError};
use crate::{impl_from_through_intermediate, OutOfRangeError};

pub type DeclaredClasses = IndexMap<ClassHash, ContractClass>;
pub type DeprecatedDeclaredClasses = IndexMap<ClassHash, DeprecatedContractClass>;
Expand Down Expand Up @@ -149,7 +149,7 @@ impl From<StorageKey> for StarkFelt {
}

impl TryFrom<StarkHash> for StorageKey {
type Error = StarknetApiError;
type Error = OutOfRangeError;

fn try_from(val: StarkHash) -> Result<Self, Self::Error> {
Ok(Self(PatriciaKey::try_from(val)?))
Expand Down
Loading