Skip to content

Commit f28b70b

Browse files
committed
fix: assert ascii chainID
1 parent 357ce41 commit f28b70b

3 files changed

Lines changed: 48 additions & 4 deletions

File tree

src/core.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,27 @@ use serde::{Deserialize, Serialize};
1111
use starknet_crypto::FieldElement;
1212

1313
use crate::hash::{pedersen_hash_array, StarkFelt, StarkHash};
14-
use crate::serde_utils::{BytesAsHex, PrefixedBytesAsHex};
14+
use crate::serde_utils::{deserialize_ascii_string, BytesAsHex, PrefixedBytesAsHex};
1515
use crate::transaction::{Calldata, ContractAddressSalt};
1616
use crate::{impl_from_through_intermediate, StarknetApiError};
1717

18-
/// A chain id.
18+
/// A chain id. Must contain only ASCII characters.
1919
#[derive(Clone, Debug, Display, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)]
20-
pub struct ChainId(pub String);
20+
pub struct ChainId(#[serde(deserialize_with = "deserialize_ascii_string")] String);
2121

2222
impl ChainId {
23+
/// Returns a new [`ChainId`].
24+
pub fn new(chain_id: String) -> Result<Self, StarknetApiError> {
25+
match chain_id.chars().all(|c| c.is_ascii()) {
26+
true => Ok(Self(chain_id)),
27+
false => Err(StarknetApiError::OutOfRange { string: chain_id }),
28+
}
29+
}
30+
31+
pub fn as_str(&self) -> &str {
32+
&self.0
33+
}
34+
2335
pub fn as_hex(&self) -> String {
2436
format!("0x{}", hex::encode(&self.0))
2537
}

src/serde_utils.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
#[path = "serde_utils_test.rs"]
44
mod serde_utils_test;
55

6-
use serde::de::{Deserialize, Visitor};
6+
use serde::de::{Deserialize, Error as DeserializationError, Visitor};
77
use serde::ser::{Serialize, SerializeTuple};
88
use serde::Deserializer;
9+
use serde_json::Value;
910

1011
use crate::deprecated_contract_class::ContractClassAbiEntry;
1112

@@ -144,3 +145,20 @@ where
144145
Err(_) => Ok(None),
145146
}
146147
}
148+
149+
pub fn deserialize_ascii_string<'de, D: Deserializer<'de>>(
150+
deserializer: D,
151+
) -> Result<String, D::Error> {
152+
let chian_id: _ = match Value::deserialize(deserializer)? {
153+
Value::String(string) => match string.chars().all(|c| c.is_ascii()) {
154+
true => string,
155+
false => {
156+
return Err(DeserializationError::custom(format!(
157+
"Chain id ({string}) must contain only ASCII characters."
158+
)));
159+
}
160+
},
161+
_ => return Err(DeserializationError::custom("Cannot cast value into String.")),
162+
};
163+
Ok(chian_id)
164+
}

src/serde_utils_test.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,17 @@ fn deserialize_optional_contract_class_abi_entry_vector_none() {
175175
let res: DummyContractClass = serde_json::from_str(json).unwrap();
176176
assert_eq!(res, DummyContractClass { abi: None });
177177
}
178+
179+
#[test]
180+
fn chain_id_non_ascii() {
181+
let chain_id_str = r#""חלודה""#;
182+
let chain_id = serde_json::from_str::<crate::core::ChainId>(chain_id_str);
183+
assert_matches!(chain_id, Err(serde_json::Error { .. }));
184+
}
185+
186+
#[test]
187+
fn valid_chain_id() {
188+
let chain_id_str = r#""123""#;
189+
let chain_id = serde_json::from_str::<crate::core::ChainId>(chain_id_str).unwrap();
190+
assert_eq!(chain_id_str, serde_json::to_string(&chain_id).unwrap())
191+
}

0 commit comments

Comments
 (0)