Types like ClassHash
, CompiledClassHash
, Nonce
, EntryPointSelector
are just wrappers over StarkHash
which is itself an alias for StarkFelt
, which is a wrapper over [u8; 32]
.
They don't implement any specific method and their inner value is pub
.
Accessing the underlying value force to do stuff like this
let inner_repr = contract_address.0.0.0;
Which is really ugly, inexpressive, and tedious. It tends to make us uncertain about what we are actually acceding.
For those types that don't add anything, aliasing is enough:
type ClassHash = StarkHash;
Same thing for initialization:
ContractAddress(PatriciaKey(StarkFelt(test_addr))
This a really bad code to write.
Other types like PatriciaKey
implement some logic (TryInto
for PatriciaKey
), therefore they totally require a new type pattern. But I can't help to remark that its inner representation is public:
pub struct PatriciaKey(pub StarkHash);
anybody can change the inner value to whatever it likes, even values that are supposed to be impossible as defined by the TryFrom implem:
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})") })
}
The exact same thing happened with the StarkFelt
type. Some values are supposed to be not supported:
pub fn new(bytes: [u8; 32]) -> Result<StarkFelt, StarknetApiError> {
// 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) })
}
but because its inner representation is public, it is possible to create StarkFelt
with unsupported inner values.
The solution for those types is to make their inner representation private, only accessible through getter functions, and only settable through setter functions that perform the required tests.
Wdyt?