Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement more libfuncs #3

Merged
merged 41 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
faa207d
progress
edg-l Aug 13, 2024
bb9da64
implement more libfuncs
edg-l Aug 14, 2024
2ed025d
progress
edg-l Aug 14, 2024
7697fad
progress
edg-l Aug 14, 2024
dd21f95
more libfuncs
edg-l Aug 14, 2024
b378a54
progress
edg-l Aug 16, 2024
b460614
progress
edg-l Aug 16, 2024
257fc8f
temp progress
edg-l Aug 16, 2024
7ccfcb6
progress
edg-l Aug 16, 2024
e3182e6
progress
edg-l Aug 16, 2024
c2f7da5
add makefile
edg-l Aug 19, 2024
18b4fcd
improve makefile
edg-l Aug 19, 2024
fce18da
gitignore json
edg-l Aug 19, 2024
adaa8fd
basic ci
edg-l Aug 19, 2024
fdaefe5
Merge remote-tracking branch 'origin/main' into progress
edg-l Aug 19, 2024
8e4589c
implement bool libfuncs
edg-l Aug 19, 2024
9bad2a7
fix ci
edg-l Aug 19, 2024
9ff8001
fix bool libfuncs
edg-l Aug 19, 2024
3363eb1
fix ci again
edg-l Aug 19, 2024
f5358b5
u128 from felt
edg-l Aug 19, 2024
d9c410a
fixes
edg-l Aug 19, 2024
c23c883
add contract execution result
edg-l Aug 19, 2024
21abd64
temp
edg-l Aug 20, 2024
8e85c06
add failing test
edg-l Aug 20, 2024
1abf41d
fix
edg-l Aug 20, 2024
ead1a15
implement more syscalls
edg-l Aug 20, 2024
7166e93
implement more syscalls
edg-l Aug 20, 2024
76f18bc
fix warns
edg-l Aug 20, 2024
a44627d
more libfuncs
edg-l Aug 20, 2024
839a92e
bytes31
edg-l Aug 20, 2024
c5dfb21
const libfuncs
edg-l Aug 20, 2024
c4706f2
fixes
edg-l Aug 21, 2024
b671b14
progress
edg-l Aug 22, 2024
d69c6dc
impl ec libfuncs
edg-l Aug 23, 2024
f4bf651
ec progress
edg-l Aug 23, 2024
ecae0eb
fix ec
edg-l Aug 23, 2024
e054744
impl call contract
edg-l Aug 23, 2024
f3ecce8
bitwise
edg-l Aug 26, 2024
d4cce3e
u16
edg-l Aug 26, 2024
f10b211
progress
edg-l Aug 26, 2024
89fb587
uint128 libfuncs
edg-l Aug 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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