Skip to content

Commit

Permalink
Merge pull request #3 from lambdaclass/progress
Browse files Browse the repository at this point in the history
Implement more libfuncs
  • Loading branch information
edg-l authored Aug 27, 2024
2 parents 3348e9c + 89fb587 commit ccbb1fb
Show file tree
Hide file tree
Showing 35 changed files with 2,986 additions and 183 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Test

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

env:
CARGO_TERM_COLOR: always

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Retreive cached dependecies
uses: Swatinem/rust-cache@v2
- name: Deps
run: make deps
- name: Build
run: cargo build --all-features --verbose
- name: Run tests
run: make test
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,11 @@ Cargo.lock
*.pdb

# End of https://www.toptal.com/developers/gitignore/api/rust

cairo2/

corelib

*.tar

*.json
18 changes: 13 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,30 @@ version = "0.1.0"
edition = "2021"

[dependencies]
cairo-lang-sierra = "2.7.0"
cairo-lang-utils = "2.7.0"
clap = { version = "4.5.11", features = ["derive"] }
cairo-lang-sierra = "2.7.1"
cairo-lang-utils = "2.7.1"
clap = { version = "4.5.16", features = ["derive"] }
k256 = "0.13.3"
keccak = "0.1.5"
num-bigint = "0.4.6"
num-traits = "0.2.19"
p256 = "0.13.2"
rand = "0.8.5"
sec1 = { version = "0.7.3", features = ["std"] }
serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.121"
serde = { version = "1.0.208", features = ["derive"] }
serde_json = "1.0.125"
sha2 = { version = "0.10.8", features = ["compress"] }
smallvec = "1.13.2"
starknet-crypto = "0.7.1"
starknet-curve = "0.5.0"
starknet-types-core = "0.1.2"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }

[dev-dependencies]
cairo-lang-compiler = "2.7.0"
cairo-lang-starknet = "2.7.0"

# On dev optimize dependencies a bit so it's not as slow.
[profile.dev.package."*"]
opt-level = 1
75 changes: 75 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.PHONY: usage deps build check needs-cairo2 deps-macos build-cairo-2-compiler-macos decompress-cairo install-scarb clean

UNAME := $(shell uname)

CAIRO_2_VERSION=2.7.0
SCARB_VERSION = 2.7.0

needs-cairo2:
ifeq ($(wildcard ./cairo2/.),)
$(error You are missing the Starknet Cairo 1 compiler, please run 'make deps' to install the necessary dependencies.)
endif
./scripts/check-corelib-version.sh $(CAIRO_2_VERSION)

usage:
@echo "Usage:"
@echo " deps: Installs the necesarry dependencies."
@echo " build: Builds the cairo-native library and binaries."
@echo " check: Checks format and lints."
@echo " test: Runs all tests."
@echo " clean: Cleans the built artifacts."

build:
cargo build --release --all-features

check:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings

test: needs-cairo2
cargo test --all-features

clean:
cargo clean

deps:
ifeq ($(UNAME), Linux)
deps: build-cairo-2-compiler install-scarb
endif
ifeq ($(UNAME), Darwin)
deps: deps-macos
endif
-rm -rf corelib
-ln -s cairo2/corelib corelib

deps-macos: build-cairo-2-compiler-macos install-scarb-macos

cairo-repo-2-dir = cairo2
cairo-repo-2-dir-macos = cairo2-macos

build-cairo-2-compiler-macos: | $(cairo-repo-2-dir-macos)

$(cairo-repo-2-dir-macos): cairo-${CAIRO_2_VERSION}-macos.tar
$(MAKE) decompress-cairo SOURCE=$< TARGET=cairo2/

build-cairo-2-compiler: | $(cairo-repo-2-dir)

$(cairo-repo-2-dir): cairo-${CAIRO_2_VERSION}.tar
$(MAKE) decompress-cairo SOURCE=$< TARGET=cairo2/

decompress-cairo:
rm -rf $(TARGET) \
&& tar -xzvf $(SOURCE) \
&& mv cairo/ $(TARGET)

cairo-%-macos.tar:
curl -L -o "$@" "https://github.com/starkware-libs/cairo/releases/download/v$*/release-aarch64-apple-darwin.tar"

cairo-%.tar:
curl -L -o "$@" "https://github.com/starkware-libs/cairo/releases/download/v$*/release-x86_64-unknown-linux-musl.tar.gz"

install-scarb:
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh| sh -s -- --no-modify-path --version $(SCARB_VERSION)

install-scarb-macos:
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh| sh -s -- --version $(SCARB_VERSION)
114 changes: 114 additions & 0 deletions programs/syscalls.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use core::starknet::{
call_contract_syscall, class_hash_const, contract_address_const, ContractAddress,
deploy_syscall, emit_event_syscall, ExecutionInfo, get_block_hash_syscall,
keccak_syscall,
library_call_syscall, replace_class_syscall, send_message_to_l1_syscall,
storage_address_try_from_felt252, storage_read_syscall, storage_write_syscall, SyscallResult,
testing::cheatcode,
};
use core::starknet::syscalls::get_execution_info_syscall;
use core::starknet::syscalls::get_execution_info_v2_syscall;

fn get_block_hash() -> SyscallResult<felt252> {
get_block_hash_syscall(0)
}

fn get_execution_info() -> SyscallResult<Box<core::starknet::info::ExecutionInfo>> {
get_execution_info_syscall()
}

fn get_execution_info_v2() -> SyscallResult<Box<core::starknet::info::v2::ExecutionInfo>> {
get_execution_info_v2_syscall()
}

fn deploy() -> SyscallResult<(ContractAddress, Span<felt252>)> {
deploy_syscall(class_hash_const::<0>(), 0, array![].span(), false)
}

fn replace_class() -> SyscallResult<()> {
replace_class_syscall(class_hash_const::<0>())
}

fn library_call() -> SyscallResult<Span<felt252>> {
library_call_syscall(class_hash_const::<0>(), 0, array![].span())
}

fn call_contract() -> SyscallResult<Span<felt252>> {
call_contract_syscall(contract_address_const::<0>(), 0, array![].span())
}

fn storage_read() -> felt252 {
storage_read_syscall(0, storage_address_try_from_felt252(0).unwrap()).unwrap()
}

fn storage_write() {
storage_write_syscall(0, storage_address_try_from_felt252(0).unwrap(), 0).unwrap()
}

fn emit_event() -> SyscallResult<()> {
emit_event_syscall(array![].span(), array![].span())
}

fn send_message_to_l1() -> SyscallResult<()> {
send_message_to_l1_syscall(3, array![2].span())
}

fn keccak() -> SyscallResult<u256> {
keccak_syscall(array![].span())
}

fn set_sequencer_address(address: felt252) -> Span<felt252> {
return cheatcode::<'set_sequencer_address'>(array![address].span());
}

fn set_account_contract_address(address: felt252) -> Span<felt252> {
return cheatcode::<'set_account_contract_address'>(array![address].span());
}

fn set_block_number(number: felt252) -> Span<felt252> {
return cheatcode::<'set_block_number'>(array![number].span());
}

fn set_block_timestamp(timestamp: felt252) -> Span<felt252> {
return cheatcode::<'set_block_timestamp'>(array![timestamp].span());
}

fn set_caller_address(address: felt252) -> Span<felt252> {
return cheatcode::<'set_caller_address'>(array![address].span());
}

fn set_chain_id(id: felt252) -> Span<felt252> {
return cheatcode::<'set_chain_id'>(array![id].span());
}

fn set_contract_address(address: felt252) -> Span<felt252> {
return cheatcode::<'set_contract_address'>(array![address].span());
}

fn set_max_fee(fee: felt252) -> Span<felt252> {
return cheatcode::<'set_max_fee'>(array![fee].span());
}

fn set_nonce(nonce: felt252) -> Span<felt252> {
return cheatcode::<'set_nonce'>(array![nonce].span());
}

fn set_signature(signature: Array<felt252>) -> Span<felt252> {
return cheatcode::<'set_signature'>(signature.span());
}

fn set_transaction_hash(hash: felt252) -> Span<felt252> {
return cheatcode::<'set_transaction_hash'>(array![hash].span());
}

fn set_version(version: felt252) -> Span<felt252> {
return cheatcode::<'set_version'>(array![version].span());
}

fn pop_log(log: felt252) -> Span<felt252> {
return cheatcode::<'pop_log'>(array![log].span());
}

fn pop_l2_to_l1_message(message: felt252) -> Span<felt252> {
return cheatcode::<'pop_l2_to_l1_message'>(array![message].span());
}
10 changes: 10 additions & 0 deletions scripts/check-corelib-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

# Script to check the corelib version matches.

_result=$(grep "version = \"$1\"" corelib/Scarb.toml)

if [ $? -ne 0 ]; then
echo "corelib version mismatch, please re-run 'make deps'"
exit 1
fi
77 changes: 74 additions & 3 deletions src/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ use crate::value::Value;
use cairo_lang_sierra::{ids::VarId, program::StatementIdx};
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
use serde::{ser::SerializeMap, Serialize};
use starknet_crypto::Felt;
use std::collections::BTreeMap;

#[derive(Clone, Debug, Default, Serialize)]
pub struct ProgramTrace {
states: Vec<StateDump>,
pub states: Vec<StateDump>,
// TODO: Syscall data.
}

Expand All @@ -22,8 +23,8 @@ impl ProgramTrace {

#[derive(Clone, Debug)]
pub struct StateDump {
statement_idx: StatementIdx,
items: BTreeMap<u64, Value>,
pub statement_idx: StatementIdx,
pub items: BTreeMap<u64, Value>,
}

impl StateDump {
Expand Down Expand Up @@ -51,3 +52,73 @@ impl Serialize for StateDump {
s.end()
}
}

#[derive(Debug, Clone)]
pub struct ContractExecutionResult {
pub remaining_gas: u128,
pub failure_flag: bool,
pub return_values: Vec<Felt>,
pub error_msg: Option<String>,
}

impl ContractExecutionResult {
pub fn from_trace(trace: &ProgramTrace) -> Option<Self> {
let last = trace.states.last()?;

let mut remaining_gas = None;
let mut error_msg = None;
let mut failure_flag = false;
let mut return_values = Vec::new();

for value in last.items.values() {
match value {
Value::U128(gas) => remaining_gas = Some(*gas),
Value::Enum {
self_ty: _,
index,
payload,
} => {
failure_flag = (*index) != 0;

if let Value::Struct(inner) = &**payload {
if !failure_flag {
if let Value::Struct(inner) = &inner[0] {
if let Value::Array { ty: _, data } = &inner[0] {
for value in data.iter() {
if let Value::Felt(x) = value {
return_values.push(*x);
}
}
}
}
} else if let Value::Array { ty: _, data } = &inner[1] {
let mut error_felt_vec = Vec::new();
for value in data.iter() {
if let Value::Felt(x) = value {
error_felt_vec.push(*x);
}
}
let bytes_err: Vec<_> = error_felt_vec
.iter()
.flat_map(|felt| felt.to_bytes_be().to_vec())
// remove null chars
.filter(|b| *b != 0)
.collect();
let str_error = String::from_utf8(bytes_err).unwrap().to_owned();
error_msg = Some(str_error);
}
}
}
Value::Unit => {}
_ => None?,
}
}

Some(Self {
remaining_gas: remaining_gas.unwrap_or(0),
return_values,
error_msg,
failure_flag,
})
}
}
Loading

0 comments on commit ccbb1fb

Please sign in to comment.