Skip to content

Commit

Permalink
Introduced Data Transformer (#2555)
Browse files Browse the repository at this point in the history
**Stack**:
- #2555
- #2548
- #2547
- #2546
- #2545
  • Loading branch information
integraledelebesgue authored Oct 16, 2024
1 parent 4472f34 commit a2e3c7d
Show file tree
Hide file tree
Showing 42 changed files with 3,243 additions and 152 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ jobs:
- name: Run Cheatnet tests
run: cargo test --release -p cheatnet

test-data-transformer:
name: Test Data Transformer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84
- name: Run Data Transformer tests
run: cargo test --release -p data-transformer

test-forge-scarb-plugin:
name: Test Forge Scarb Plugin
runs-on: ubuntu-latest
Expand Down
35 changes: 35 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ members = [
"crates/cheatnet",
"crates/conversions",
"crates/conversions/cairo-serde-macros",
"crates/data-transformer",
"crates/runtime",
"crates/scarb-api",
"crates/configuration",
Expand Down
1 change: 1 addition & 0 deletions crates/cheatnet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ conversions.workspace = true
scarb-metadata.workspace = true
fs2.workspace = true
flate2.workspace = true
data-transformer = { path = "../data-transformer" }
scarb-api = { path = "../scarb-api" }
runtime = { path = "../runtime" }
universal-sierra-compiler-api = { path = "../universal-sierra-compiler-api" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ use cairo_vm::vm::{
use cairo_vm::Felt252;
use conversions::byte_array::ByteArray;
use conversions::felt252::TryInferFormat;
use conversions::serde::deserialize::{BufferReader, CairoDeserialize};
use conversions::serde::deserialize::BufferReader;
use conversions::serde::serialize::CairoSerialize;
use data_transformer::cairo_types::CairoU256;
use runtime::{
CheatcodeHandlingResult, EnhancedHintError, ExtendedRuntime, ExtensionLogic,
SyscallHandlingResult,
Expand Down Expand Up @@ -491,30 +492,6 @@ impl<'a> ExtensionLogic for ForgeExtension<'a> {
}
}

#[derive(CairoDeserialize, CairoSerialize)]
struct CairoU256 {
low: u128,
high: u128,
}

impl CairoU256 {
fn from_bytes(bytes: &[u8]) -> Self {
Self {
low: u128::from_be_bytes(bytes[16..32].try_into().unwrap()),
high: u128::from_be_bytes(bytes[0..16].try_into().unwrap()),
}
}

fn to_be_bytes(&self) -> [u8; 32] {
let mut result = [0; 32];

result[16..].copy_from_slice(&self.low.to_be_bytes());
result[..16].copy_from_slice(&self.high.to_be_bytes());

result
}
}

#[derive(CairoSerialize)]
enum SignError {
InvalidSecretKey,
Expand Down
2 changes: 2 additions & 0 deletions crates/conversions/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ thiserror.workspace = true
serde_json.workspace = true
serde.workspace = true
num-traits.workspace = true
num-bigint.workspace = true
itertools.workspace = true
cairo-serde-macros = { path = "cairo-serde-macros" }

[dev-dependencies]
ctor.workspace = true
indoc.workspace = true
test-case.workspace = true
6 changes: 6 additions & 0 deletions crates/conversions/src/serde/serialize/serialize_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,12 @@ impl_serialize_for_num_type!(u64);
impl_serialize_for_num_type!(u128);
impl_serialize_for_num_type!(usize);

impl_serialize_for_num_type!(i8);
impl_serialize_for_num_type!(i16);
impl_serialize_for_num_type!(i32);
impl_serialize_for_num_type!(i64);
impl_serialize_for_num_type!(i128);

impl_serialize_for_tuple!();
impl_serialize_for_tuple!(A);
impl_serialize_for_tuple!(A, B);
Expand Down
28 changes: 28 additions & 0 deletions crates/data-transformer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "data-transformer"
version = "1.0.0"
edition.workspace = true

[dependencies]
anyhow.workspace = true
serde_json.workspace = true
serde.workspace = true
starknet.workspace = true
cairo-lang-utils.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
test-case.workspace = true
thiserror.workspace = true
conversions = { path = "../conversions" }
cairo-serde-macros = { path = "../conversions/cairo-serde-macros" }

[dev-dependencies]
indoc.workspace = true
primitive-types.workspace = true
tokio.workspace = true
url.workspace = true
50 changes: 50 additions & 0 deletions crates/data-transformer/src/cairo_types/bytes31.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use cairo_serde_macros::{CairoDeserialize, CairoSerialize};
use starknet::core::types::{Felt, FromStrError};
use std::str::FromStr;

#[derive(CairoDeserialize, CairoSerialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct CairoBytes31 {
inner: Felt,
}

impl CairoBytes31 {
pub const MAX: CairoBytes31 = CairoBytes31 {
inner: Felt::from_hex_unchecked(
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
};
}

#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum ParseBytes31Error {
#[error("Failed to parse as Cairo type")]
CairoFromStrError, // `FromStrError` thrown on unsuccessful Felt parsing is useless. We cannot write anything beyond that
#[error("Number is too large to fit in 31 bytes")]
Overflow,
}

impl From<FromStrError> for ParseBytes31Error {
fn from(_value: FromStrError) -> Self {
ParseBytes31Error::CairoFromStrError
}
}

impl FromStr for CairoBytes31 {
type Err = ParseBytes31Error;

fn from_str(input: &str) -> Result<Self, Self::Err> {
let inner = input.parse::<Felt>()?;

if inner > CairoBytes31::MAX.inner {
return Err(ParseBytes31Error::Overflow);
}

Ok(CairoBytes31 { inner })
}
}

impl From<CairoBytes31> for Felt {
fn from(value: CairoBytes31) -> Self {
value.inner
}
}
68 changes: 68 additions & 0 deletions crates/data-transformer/src/cairo_types/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use num_bigint::BigUint;
use thiserror;

#[derive(Clone, Debug)]
pub enum RadixInput {
Decimal(Box<[u8]>),
Hexadecimal(Box<[u8]>),
}

#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum ParseRadixError {
#[error("Input contains invalid digit")]
InvalidString,
#[error(transparent)]
ParseIntError(#[from] std::num::ParseIntError),
}

impl<'input> TryFrom<&'input [u8]> for RadixInput {
type Error = ParseRadixError;

fn try_from(bytes: &'input [u8]) -> Result<Self, Self::Error> {
let mut is_hex = false;

if bytes.len() > 2 {
is_hex = bytes[1] == b'x';
}

let result = bytes
.iter()
.skip_while(|&&byte| byte == b'0' || byte == b'x')
.filter(|&&byte| byte != b'_')
.map(|&byte| {
if byte.is_ascii_digit() {
Ok(byte - b'0')
} else if (b'a'..b'g').contains(&byte) {
is_hex = true;
Ok(byte - b'a' + 10)
} else if (b'A'..b'G').contains(&byte) {
is_hex = true;
Ok(byte - b'A' + 10)
} else {
return Err(ParseRadixError::InvalidString);
}
})
.collect::<Result<Box<[u8]>, ParseRadixError>>()?;

Ok(if is_hex {
Self::Hexadecimal(result)
} else {
Self::Decimal(result)
})
}
}

impl TryFrom<RadixInput> for BigUint {
type Error = ParseRadixError;

fn try_from(value: RadixInput) -> Result<Self, Self::Error> {
match value {
RadixInput::Decimal(digits) => {
BigUint::from_radix_be(&digits, 10).ok_or(ParseRadixError::InvalidString)
}
RadixInput::Hexadecimal(digits) => {
BigUint::from_radix_be(&digits, 16).ok_or(ParseRadixError::InvalidString)
}
}
}
}
12 changes: 12 additions & 0 deletions crates/data-transformer/src/cairo_types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
mod bytes31;
mod helpers;
mod u256;
mod u384;
mod u512;
mod u96;

pub use bytes31::{CairoBytes31, ParseBytes31Error};
pub use u256::{CairoU256, ParseCairoU256Error};
pub use u384::{CairoU384, ParseCairoU384Error};
pub use u512::{CairoU512, ParseCairoU512Error};
pub use u96::{CairoU96, ParseCairoU96Error};
Loading

0 comments on commit a2e3c7d

Please sign in to comment.