Skip to content

Commit

Permalink
Introduced data transformer
Browse files Browse the repository at this point in the history
commit-id:8d990066
  • Loading branch information
integraledelebesgue committed Oct 2, 2024
1 parent ea09480 commit 6a0a9d2
Show file tree
Hide file tree
Showing 9 changed files with 2,039 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/sncast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@ cairo-lang-casm.workspace = true
cairo-lang-sierra-to-casm.workspace = true
cairo-lang-utils.workspace = true
cairo-lang-sierra.workspace = true
cairo-lang-parser.workspace = true
cairo-lang-syntax.workspace = true
cairo-lang-diagnostics.workspace = true
cairo-lang-filesystem.workspace = true
itertools.workspace = true
num-traits.workspace = true
num-bigint.workspace = true
starknet-types-core.workspace = true
cairo-vm.workspace = true
blockifier.workspace = true
Expand Down
220 changes: 220 additions & 0 deletions crates/sncast/src/helpers/data_transformer/calldata_representation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
use anyhow::{bail, Context};
use conversions::{
byte_array::ByteArray,
bytes31::CairoBytes31,
serde::serialize::{BufferWriter, CairoSerialize},
u256::CairoU256,
u512::CairoU512,
};
use starknet::core::types::Felt;
use std::{any::type_name, str::FromStr};

#[derive(Debug)]
pub(super) struct CalldataStructField(AllowedCalldataArguments);

impl CalldataStructField {
pub fn new(value: AllowedCalldataArguments) -> Self {
Self(value)
}
}

#[derive(Debug)]
pub(super) struct CalldataStruct(Vec<CalldataStructField>);

impl CalldataStruct {
pub fn new(arguments: Vec<CalldataStructField>) -> Self {
Self(arguments)
}
}

#[derive(Debug)]
pub(super) struct CalldataArrayMacro(Vec<AllowedCalldataArguments>);

impl CalldataArrayMacro {
pub fn new(arguments: Vec<AllowedCalldataArguments>) -> Self {
Self(arguments)
}
}

#[derive(Debug)]
pub(super) struct CalldataEnum {
position: usize,
argument: Option<Box<AllowedCalldataArguments>>,
}

impl CalldataEnum {
pub fn new(position: usize, argument: Option<Box<AllowedCalldataArguments>>) -> Self {
Self { position, argument }
}
}

#[derive(Debug)]
pub(super) enum CalldataPrimitive {
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
U256(CairoU256),
U512(CairoU512),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
Felt(Felt),
ByteArray(ByteArray),
}

fn neat_parsing_error_message(value: &str, parsing_type: &str, reason: Option<&str>) -> String {
if let Some(message) = reason {
format!(r#"Failed to parse value "{value}" into type "{parsing_type}": {message}"#)
} else {
format!(r#"Failed to parse value "{value}" into type "{parsing_type}""#)
}
}

fn parse_with_type<T: FromStr>(value: &str) -> anyhow::Result<T>
where
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
{
value
.parse::<T>()
.context(neat_parsing_error_message(value, type_name::<T>(), None))
}

impl CalldataPrimitive {
pub(super) fn try_new(type_with_path: &str, value: &str) -> anyhow::Result<Self> {
let type_str = type_with_path
.split("::")
.last()
.context("Couldn't parse parameter type from ABI")?;

// TODO add all corelib types (Issue #2550)
match type_str {
"u8" => Ok(Self::U8(parse_with_type(value)?)),
"u16" => Ok(Self::U16(parse_with_type(value)?)),
"u32" => Ok(Self::U32(parse_with_type(value)?)),
"u64" => Ok(Self::U64(parse_with_type(value)?)),
"u128" => Ok(Self::U128(parse_with_type(value)?)),
"u256" => Ok(Self::U256(parse_with_type(value)?)),
"u512" => Ok(Self::U512(parse_with_type(value)?)),
"i8" => Ok(Self::I8(parse_with_type(value)?)),
"i16" => Ok(Self::I16(parse_with_type(value)?)),
"i32" => Ok(Self::I32(parse_with_type(value)?)),
"i64" => Ok(Self::I64(parse_with_type(value)?)),
"i128" => Ok(Self::I128(parse_with_type(value)?)),
// bytes31 is a helper type defined in Cairo corelib;
// (e.g. alexandria_data_structures::bit_array::BitArray uses that)
// https://github.com/starkware-libs/cairo/blob/bf48e658b9946c2d5446eeb0c4f84868e0b193b5/corelib/src/bytes_31.cairo#L14
// It's actually felt under the hood. Although conversion from felt252 to bytes31 returns Result, it never fails.
"bytes31" => Ok(Self::Felt(parse_with_type::<CairoBytes31>(value)?.into())),
"felt252" | "felt" | "ContractAddress" | "ClassHash" | "StorageAddress"
| "EthAddress" => {
let felt = Felt::from_dec_str(value)
.with_context(|| neat_parsing_error_message(value, type_with_path, None))?;
Ok(Self::Felt(felt))
}
"bool" => Ok(Self::Bool(parse_with_type(value)?)),
"ByteArray" => Ok(Self::ByteArray(ByteArray::from(value))),
_ => {
bail!(neat_parsing_error_message(
value,
type_with_path,
Some(&format!("unsupported type {type_with_path}"))
))
}
}
}
}

#[derive(Debug)]
pub(super) struct CalldataTuple(Vec<AllowedCalldataArguments>);

impl CalldataTuple {
pub fn new(arguments: Vec<AllowedCalldataArguments>) -> Self {
Self(arguments)
}
}

#[derive(Debug)]
pub(super) enum AllowedCalldataArguments {
Struct(CalldataStruct),
ArrayMacro(CalldataArrayMacro),
Enum(CalldataEnum),
Primitive(CalldataPrimitive),
Tuple(CalldataTuple),
}

impl CairoSerialize for CalldataPrimitive {
// https://docs.starknet.io/architecture-and-concepts/smart-contracts/serialization-of-cairo-types/
fn serialize(&self, output: &mut BufferWriter) {
match self {
CalldataPrimitive::Bool(value) => value.serialize(output),
CalldataPrimitive::U8(value) => value.serialize(output),
CalldataPrimitive::U16(value) => value.serialize(output),
CalldataPrimitive::U32(value) => value.serialize(output),
CalldataPrimitive::U64(value) => value.serialize(output),
CalldataPrimitive::U128(value) => value.serialize(output),
CalldataPrimitive::U256(value) => value.serialize(output),
CalldataPrimitive::U512(value) => value.serialize(output),
CalldataPrimitive::I8(value) => value.serialize(output),
CalldataPrimitive::I16(value) => value.serialize(output),
CalldataPrimitive::I32(value) => value.serialize(output),
CalldataPrimitive::I64(value) => value.serialize(output),
CalldataPrimitive::I128(value) => value.serialize(output),
CalldataPrimitive::Felt(value) => value.serialize(output),
CalldataPrimitive::ByteArray(value) => value.serialize(output),
};
}
}

impl CairoSerialize for CalldataStructField {
// Every argument serialized in order of occurrence
fn serialize(&self, output: &mut BufferWriter) {
self.0.serialize(output);
}
}

impl CairoSerialize for CalldataStruct {
// https://docs.starknet.io/architecture-and-concepts/smart-contracts/serialization-of-cairo-types/#serialization_of_structs
fn serialize(&self, output: &mut BufferWriter) {
self.0.iter().for_each(|field| field.serialize(output));
}
}

impl CairoSerialize for CalldataTuple {
fn serialize(&self, output: &mut BufferWriter) {
self.0.iter().for_each(|field| field.serialize(output));
}
}

impl CairoSerialize for CalldataArrayMacro {
// https://docs.starknet.io/architecture-and-concepts/smart-contracts/serialization-of-cairo-types/#serialization_of_arrays
fn serialize(&self, output: &mut BufferWriter) {
self.0.len().serialize(output);
self.0.iter().for_each(|field| field.serialize(output));
}
}

impl CairoSerialize for CalldataEnum {
// https://docs.starknet.io/architecture-and-concepts/smart-contracts/serialization-of-cairo-types/#serialization_of_enums
fn serialize(&self, output: &mut BufferWriter) {
self.position.serialize(output);
if self.argument.is_some() {
self.argument.as_ref().unwrap().serialize(output);
}
}
}
impl CairoSerialize for AllowedCalldataArguments {
fn serialize(&self, output: &mut BufferWriter) {
match self {
AllowedCalldataArguments::Struct(value) => value.serialize(output),
AllowedCalldataArguments::ArrayMacro(value) => value.serialize(output),
AllowedCalldataArguments::Enum(value) => value.serialize(output),
AllowedCalldataArguments::Primitive(value) => value.serialize(output),
AllowedCalldataArguments::Tuple(value) => value.serialize(output),
}
}
}
3 changes: 3 additions & 0 deletions crates/sncast/src/helpers/data_transformer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod calldata_representation;
pub mod sierra_abi;
pub mod transformer;
Loading

0 comments on commit 6a0a9d2

Please sign in to comment.