Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
225 changes: 102 additions & 123 deletions Cargo.lock

Large diffs are not rendered by default.

64 changes: 46 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,27 @@ ark-secp256k1 = "0.5.0"
ark-secp256r1 = "0.5.0"
bincode = "2.0.1"
bumpalo = "3.16.0"
cairo-lang-casm = "~2.19.0-rc.3"
cairo-lang-compiler = "~2.19.0-rc.3"
cairo-lang-defs = "~2.19.0-rc.3"
cairo-lang-filesystem = "~2.19.0-rc.3"
cairo-lang-lowering = "~2.19.0-rc.3"
cairo-lang-runner = "~2.19.0-rc.3"
cairo-lang-semantic = "~2.19.0-rc.3"
cairo-lang-sierra = "~2.19.0-rc.3"
cairo-lang-sierra-ap-change = "~2.19.0-rc.3"
cairo-lang-sierra-gas = "~2.19.0-rc.3"
cairo-lang-sierra-generator = "~2.19.0-rc.3"
cairo-lang-sierra-to-casm = "~2.19.0-rc.3"
cairo-lang-sierra-type-size = "~2.19.0-rc.3"
cairo-lang-starknet = "~2.19.0-rc.3"
cairo-lang-starknet-classes = "~2.19.0-rc.3"
cairo-lang-test-plugin = "~2.19.0-rc.3"
cairo-lang-test-runner = "~2.19.0-rc.3"
cairo-lang-utils = "~2.19.0-rc.3"
# NOTE(deploy_v2): bumped from "~2.19.0-rc.3" to the release carrying the `DeployV2` Sierra libfunc
# variant. That release is not yet published, so the `[patch.crates-io]` block at the bottom of this
# file redirects these to the local cairo checkout during development (see the note there).
cairo-lang-casm = "2.19.3"
cairo-lang-compiler = "2.19.3"
cairo-lang-defs = "2.19.3"
cairo-lang-filesystem = "2.19.3"
cairo-lang-lowering = "2.19.3"
cairo-lang-runner = "2.19.3"
cairo-lang-semantic = "2.19.3"
cairo-lang-sierra = "2.19.3"
cairo-lang-sierra-ap-change = "2.19.3"
cairo-lang-sierra-gas = "2.19.3"
cairo-lang-sierra-generator = "2.19.3"
cairo-lang-sierra-to-casm = "2.19.3"
cairo-lang-sierra-type-size = "2.19.3"
cairo-lang-starknet = "2.19.3"
cairo-lang-starknet-classes = "2.19.3"
cairo-lang-test-plugin = "2.19.3"
cairo-lang-test-runner = "2.19.3"
cairo-lang-utils = "2.19.3"
cairo-native-bin-utils.path = "binaries/cairo-native-bin-utils"
cairo-native = { path = ".", version = "0.9.0-rc.7" }
cairo-starknet-syscalls = { path = "cairo-starknet-syscalls", version = "0.9.0-rc.7" }
Expand Down Expand Up @@ -249,3 +252,28 @@ required-features = [ "testing" ]
[[example]]
name = "easy_api"
required-features = [ "testing" ]

# --- TEMPORARY dev override (deploy_v2) ---
# The `deploy_v2` syscall needs the `DeployV2` Sierra libfunc variant, which is not yet in a
# published cairo-lang-* release. Until one is, build against the cairo `deploy_v2` compiler branch
# (https://github.com/starkware-libs/cairo/pull/10214). Remove this block once a release carries the
# variant — the version pins above already target it.
[patch.crates-io]
cairo-lang-casm = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-compiler = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-defs = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-filesystem = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-lowering = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-runner = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-semantic = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-sierra = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-sierra-ap-change = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-sierra-gas = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-sierra-generator = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-sierra-to-casm = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-sierra-type-size = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-starknet = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-starknet-classes = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-test-plugin = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-test-runner = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
cairo-lang-utils = { git = "https://github.com/starkware-libs/cairo", branch = "ron/deploy-v2/compiler" }
11 changes: 11 additions & 0 deletions cairo-starknet-syscalls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,17 @@ pub trait StarknetSyscallHandler {
remaining_gas: &mut u64,
) -> SyscallResult<(Felt, Vec<Felt>)>;

/// Deploys a contract, deriving its address with the Blake-escaped derivation instead of
/// Pedersen (the `deploy_v2` syscall). Same request/response as [`Self::deploy`].
fn deploy_v2(
&mut self,
class_hash: Felt,
contract_address_salt: Felt,
calldata: &[Felt],
deploy_from_zero: bool,
remaining_gas: &mut u64,
) -> SyscallResult<(Felt, Vec<Felt>)>;

fn replace_class(&mut self, class_hash: Felt, remaining_gas: &mut u64) -> SyscallResult<()>;

fn library_call(
Expand Down
6 changes: 5 additions & 1 deletion debug_utils/sierra-emu/programs/syscalls.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use starknet::ClassHash;
use starknet::{
call_contract_syscall, ContractAddress,
deploy_syscall, emit_event_syscall, ExecutionInfo, get_block_hash_syscall,
deploy_syscall, deploy_v2_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,
Expand Down Expand Up @@ -29,6 +29,10 @@ fn deploy() -> SyscallResult<(ContractAddress, Span<felt252>)> {
deploy_syscall(ZERO_CLASS_HASH, 0, array![].span(), false)
}

fn deploy_v2() -> SyscallResult<(ContractAddress, Span<felt252>)> {
deploy_v2_syscall(ZERO_CLASS_HASH, 0, array![].span(), false)
}

fn replace_class() -> SyscallResult<()> {
replace_class_syscall(ZERO_CLASS_HASH)
}
Expand Down
1 change: 1 addition & 0 deletions debug_utils/sierra-emu/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ pub fn libfunc_to_name(value: &CoreConcreteLibfunc) -> &'static str {
StarknetConcreteLibfunc::GetExecutionInfo(_) => "get_exec_info_v1",
StarknetConcreteLibfunc::GetExecutionInfoV2(_) => "get_exec_info_v2",
StarknetConcreteLibfunc::Deploy(_) => "deploy",
StarknetConcreteLibfunc::DeployV2(_) => "deploy_v2",
StarknetConcreteLibfunc::Keccak(_) => "keccak",
StarknetConcreteLibfunc::LibraryCall(_) => "library_call",
StarknetConcreteLibfunc::ReplaceClass(_) => "replace_class",
Expand Down
12 changes: 12 additions & 0 deletions debug_utils/sierra-emu/src/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ impl StarknetSyscallHandler for StubSyscallHandler {
unimplemented!()
}

fn deploy_v2(
&mut self,
_class_hash: Felt,
_contract_address_salt: Felt,
_calldata: &[Felt],
_deploy_from_zero: bool,
_remaining_gas: &mut u64,
) -> SyscallResult<(Felt, Vec<Felt>)> {
// Deployment requires constructor execution, which the stub doesn't model.
unimplemented!()
}

fn replace_class(&mut self, _class_hash: Felt, _remaining_gas: &mut u64) -> SyscallResult<()> {
// Class replacement updates a registry the stub doesn't track.
unimplemented!()
Expand Down
87 changes: 87 additions & 0 deletions debug_utils/sierra-emu/src/vm/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ pub fn eval(
eval_get_execution_info_v2(registry, info, args, syscall_handler)
}
StarknetConcreteLibfunc::Deploy(info) => eval_deploy(registry, info, args, syscall_handler),
StarknetConcreteLibfunc::DeployV2(info) => {
eval_deploy_v2(registry, info, args, syscall_handler)
}
StarknetConcreteLibfunc::Keccak(info) => eval_keccak(registry, info, args, syscall_handler),
StarknetConcreteLibfunc::Sha256ProcessBlock(info) => {
eval_sha256_process_block(registry, info, args, syscall_handler)
Expand Down Expand Up @@ -1094,6 +1097,90 @@ fn eval_deploy(
}
}

/// Same request/response layout as [`eval_deploy`], but dispatches to the handler's `deploy_v2`
/// method (Blake-escaped address derivation).
fn eval_deploy_v2(
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
info: &SignatureOnlyConcreteLibfunc,
args: Vec<Value>,
syscall_handler: &mut impl StarknetSyscallHandler,
) -> EvalAction {
let [Value::U64(mut gas), system, Value::Felt(class_hash), Value::Felt(contract_address_salt), Value::Struct(calldata), Value::Enum {
self_ty: _,
index: deploy_from_zero,
payload: _,
}]: [Value; 6] = args.try_into().unwrap()
else {
panic!()
};

let deploy_from_zero = deploy_from_zero != 0;

let [Value::Array {
ty: _,
data: calldata,
}]: [Value; 1] = calldata.try_into().unwrap()
else {
panic!()
};

let calldata = calldata
.into_iter()
.map(|x| match x {
Value::Felt(x) => x,
_ => unreachable!(),
})
.collect::<Vec<_>>();

// get felt type from the error branch array
let felt_ty = {
match registry
.get_type(&info.branch_signatures()[1].vars[2].ty)
.unwrap()
{
CoreTypeConcrete::Array(info) => info.ty.clone(),
_ => unreachable!(),
}
};

let result = syscall_handler.deploy_v2(
class_hash,
contract_address_salt,
&calldata,
deploy_from_zero,
&mut gas,
);

match result {
Ok((contract_address, return_values)) => EvalAction::NormalBranch(
0,
smallvec![
Value::U64(gas),
system,
Value::Felt(contract_address),
Value::Struct(vec![Value::Array {
ty: felt_ty,
data: return_values
.into_iter()
.map(Value::Felt)
.collect::<Vec<_>>(),
}])
],
),
Err(e) => EvalAction::NormalBranch(
1,
smallvec![
Value::U64(gas),
system,
Value::Array {
ty: felt_ty,
data: e.into_iter().map(Value::Felt).collect::<Vec<_>>(),
}
],
),
}
}

fn eval_keccak(
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
info: &SignatureOnlyConcreteLibfunc,
Expand Down
15 changes: 15 additions & 0 deletions examples/erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@ impl StarknetSyscallHandler for SyscallHandler {
))
}

fn deploy_v2(
&mut self,
class_hash: Felt,
contract_address_salt: Felt,
calldata: &[Felt],
deploy_from_zero: bool,
_gas: &mut u64,
) -> SyscallResult<(Felt, Vec<Felt>)> {
println!("Called `deploy_v2({class_hash}, {contract_address_salt}, {calldata:?}, {deploy_from_zero})` from MLIR.");
Ok((
class_hash + contract_address_salt,
calldata.iter().map(|x| x + Felt::ONE).collect(),
))
}

fn replace_class(&mut self, class_hash: Felt, _gas: &mut u64) -> SyscallResult<()> {
println!("Called `replace_class({class_hash})` from MLIR.");
Ok(())
Expand Down
15 changes: 15 additions & 0 deletions examples/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@ impl StarknetSyscallHandler for SyscallHandler {
))
}

fn deploy_v2(
&mut self,
class_hash: Felt,
contract_address_salt: Felt,
calldata: &[Felt],
deploy_from_zero: bool,
_gas: &mut u64,
) -> SyscallResult<(Felt, Vec<Felt>)> {
println!("Called `deploy_v2({class_hash}, {contract_address_salt}, {calldata:?}, {deploy_from_zero})` from MLIR.");
Ok((
class_hash + contract_address_salt,
calldata.iter().map(|x| x + Felt::ONE).collect(),
))
}

fn replace_class(&mut self, class_hash: Felt, _gas: &mut u64) -> SyscallResult<()> {
println!("Called `replace_class({class_hash})` from MLIR.");
Ok(())
Expand Down
1 change: 1 addition & 0 deletions src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ pub const fn libfunc_to_name(value: &CoreConcreteLibfunc) -> &'static str {
StarknetConcreteLibfunc::GetExecutionInfoV2(_) => "get_exec_info_v2",
StarknetConcreteLibfunc::GetExecutionInfoV3(_) => "get_exec_info_v3",
StarknetConcreteLibfunc::Deploy(_) => "deploy",
StarknetConcreteLibfunc::DeployV2(_) => "deploy_v2",
StarknetConcreteLibfunc::Keccak(_) => "keccak",
StarknetConcreteLibfunc::LibraryCall(_) => "library_call",
StarknetConcreteLibfunc::ReplaceClass(_) => "replace_class",
Expand Down
55 changes: 52 additions & 3 deletions src/libfuncs/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ pub fn build<'ctx, 'this>(
StarknetConcreteLibfunc::Deploy(info) => {
build_deploy(context, registry, entry, location, helper, metadata, info)
}
StarknetConcreteLibfunc::DeployV2(info) => {
build_deploy_v2(context, registry, entry, location, helper, metadata, info)
}
StarknetConcreteLibfunc::Keccak(info) => {
build_keccak(context, registry, entry, location, helper, metadata, info)
}
Expand Down Expand Up @@ -1177,6 +1180,54 @@ pub fn build_deploy<'ctx, 'this>(
helper: &LibfuncHelper<'ctx, 'this>,
metadata: &mut MetadataStorage,
info: &SignatureOnlyConcreteLibfunc,
) -> Result<()> {
build_deploy_impl(
context,
registry,
entry,
location,
helper,
metadata,
info,
StarknetSyscallHandlerCallbacks::<()>::DEPLOY,
)
}

/// Same request/response layout as [`build_deploy`], but dispatches to the handler's `deploy_v2`
/// method (Blake-escaped address derivation) via its vtable offset.
pub fn build_deploy_v2<'ctx, 'this>(
context: &'ctx Context,
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
entry: &'this Block<'ctx>,
location: Location<'ctx>,
helper: &LibfuncHelper<'ctx, 'this>,
metadata: &mut MetadataStorage,
info: &SignatureOnlyConcreteLibfunc,
) -> Result<()> {
build_deploy_impl(
context,
registry,
entry,
location,
helper,
metadata,
info,
StarknetSyscallHandlerCallbacks::<()>::DEPLOY_V2,
)
}

/// Shared body of [`build_deploy`] and [`build_deploy_v2`]; `callback_offset` selects which handler
/// vtable entry (`DEPLOY` or `DEPLOY_V2`) the syscall dispatches to.
#[allow(clippy::too_many_arguments)]
fn build_deploy_impl<'ctx, 'this>(
context: &'ctx Context,
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
entry: &'this Block<'ctx>,
location: Location<'ctx>,
helper: &LibfuncHelper<'ctx, 'this>,
metadata: &mut MetadataStorage,
info: &SignatureOnlyConcreteLibfunc,
callback_offset: usize,
) -> Result<()> {
// Extract self pointer.
let ptr = entry.load(
Expand Down Expand Up @@ -1314,9 +1365,7 @@ pub fn build_deploy<'ctx, 'this>(
context,
location,
entry.arg(1)?,
&[GepIndex::Const(
StarknetSyscallHandlerCallbacks::<()>::DEPLOY.try_into()?,
)],
&[GepIndex::Const(callback_offset.try_into()?)],
pointer(context, 0),
)?;
let fn_ptr = entry.load(context, location, fn_ptr, llvm::r#type::pointer(context, 0))?;
Expand Down
Loading
Loading