Skip to content

Commit

Permalink
Fix data transformer integration (#2624)
Browse files Browse the repository at this point in the history
<!-- Reference any GitHub issues resolved by this PR -->

Closes #2588

## Introduced changes

<!-- A brief description of the changes -->

Previous data transformer integration used `--calldata` argument (along
with the old serialized input) and used `()` to indicate data used for
transformation. `()` are special characters in bash so it did not work
in most shells, requiring wrapping in `''` anyway. This PR changes this
integration so data for transformation is passed as a single string to a
new `--arguments` argument and doesn't require any special wrapping.

- Changed the syntax of data transformer so it works better with shells
- Introduced new `--arguments` argument to `sncast` to distinguish data
transformation
- Fixed support for shortstrings in data transformer
- Added tests using `.sh` scripts for data transformation

## Checklist

<!-- Make sure all of these are complete -->

- [x] Linked relevant issue
- [x] Updated relevant documentation
- [x] Added relevant tests
- [x] Performed self-review of the code
- [x] Added changes to `CHANGELOG.md`
  • Loading branch information
cptartur authored Oct 31, 2024
1 parent 647483a commit 2ff15ec
Show file tree
Hide file tree
Showing 18 changed files with 410 additions and 550 deletions.
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Scarb features work with optimized compilation
- Custom test targets are now supported with optimized compilation

## [0.32.0] - 2024-10-16

### Cast

#### Added

- Data transformer for passing calldata to transactions as Cairo expressions for automatic conversion instead of serialized form
- New `--arguments` flag to `call`, `invoke` and `deploy` for automatic conversion of Cairo expressions instead of serialized form.

## [0.32.0] - 2024-10-16

### Cast

#### Changed

Expand Down
43 changes: 7 additions & 36 deletions crates/data-transformer/src/calldata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,23 @@ use serde::{Deserialize, Serialize};
use starknet::core::types::{ContractClass, Felt};

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Calldata {
Serialized(Vec<Felt>),
Expressions(String),
pub struct Calldata {
expressions: String,
}

impl From<Vec<String>> for Calldata {
fn from(calldata: Vec<String>) -> Self {
let maybe_serialized = calldata
.iter()
.map(|arg| {
if arg
.chars()
.all(|c| c.is_ascii_hexdigit() || c == 'x' || c == 'X')
{
Felt::from_dec_str(arg)
.or_else(|_| Felt::from_hex(arg))
.ok()
} else {
None
}
})
.collect::<Option<Vec<_>>>();

if let Some(serialized) = maybe_serialized {
Self::Serialized(serialized)
} else {
Self::Expressions(calldata.join(" "))
}
impl Calldata {
#[must_use]
pub fn new(expressions: String) -> Self {
Self { expressions }
}
}

impl Calldata {
/// Serialize the calldata.
/// If it's given as a list of `Felt`s, return it immediately.
/// Otherwise, try to interpret is as a comma-separated sequence of Cairo expressions.
pub fn serialized(
self,
class_definition: ContractClass,
function_selector: &Felt,
) -> anyhow::Result<Vec<Felt>> {
match self {
Calldata::Serialized(serialized) => Ok(serialized),
Calldata::Expressions(ref expressions) => {
transform(expressions, class_definition, function_selector)
}
}
transform(&self.expressions, class_definition, function_selector)
}
}
5 changes: 5 additions & 0 deletions crates/data-transformer/src/sierra_abi/data_representation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::cairo_types::{CairoBytes31, CairoU256, CairoU384, CairoU512, CairoU96};
use anyhow::{bail, Context};
use conversions::felt252::FromShortString;
use conversions::{
byte_array::ByteArray,
serde::serialize::{BufferWriter, CairoSerialize},
Expand Down Expand Up @@ -100,6 +101,10 @@ impl CalldataPrimitive {
// 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())),
"shortstring" => {
let felt = Felt::from_short_string(value)?;
Ok(Self::Felt(felt))
}
"felt252" | "felt" | "ContractAddress" | "ClassHash" | "StorageAddress"
| "EthAddress" => {
let felt = Felt::from_dec_str(value)
Expand Down
6 changes: 6 additions & 0 deletions crates/data-transformer/src/sierra_abi/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ impl SupportedCalldataKind for TerminalShortString {
.string_value(db)
.context("Invalid shortstring passed as an argument")?;

// TODO(#2623) add better handling
let expected_type = match expected_type.split("::").last() {
Some("felt" | "felt252") => "shortstring",
_ => expected_type,
};

Ok(AllowedCalldataArgument::Primitive(
CalldataPrimitive::try_from_str_with_type(&value, expected_type)?,
))
Expand Down
7 changes: 6 additions & 1 deletion crates/data-transformer/src/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ pub fn transform(
}

fn split_expressions(input: &str, db: &SimpleParserDatabase) -> Result<Vec<Expr>> {
let expr = parse_expression(input, db)?;
// We need to convert our comma-separated string of expressions into something that is a valid
// Cairo expression, so we can parse it.
//
// We convert to tuple by wrapping in `()` with a trailing `,` to handle case of a single argument
let input = format!("({input},)");
let expr = parse_expression(&input, db)?;

match expr {
Expr::Tuple(tuple) => Ok(tuple.expressions(db).elements(db)),
Expand Down
Loading

0 comments on commit 2ff15ec

Please sign in to comment.