Skip to content

Commit

Permalink
feat(blockifier): add deploy syscall implementation (#1554)
Browse files Browse the repository at this point in the history
  • Loading branch information
varex83 authored Nov 14, 2024
1 parent 564ad89 commit d3ffdd6
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 9 deletions.
80 changes: 71 additions & 9 deletions crates/blockifier/src/execution/native/syscall_handler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashSet;
use std::hash::RandomState;
use std::sync::Arc;

use cairo_native::starknet::{
BlockInfo,
Expand All @@ -13,8 +14,9 @@ use cairo_native::starknet::{
U256,
};
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use starknet_api::core::EthAddress;
use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress, EthAddress};
use starknet_api::state::StorageKey;
use starknet_api::transaction::fields::{Calldata, ContractAddressSalt};
use starknet_api::transaction::L2ToL1Payload;
use starknet_types_core::felt::Felt;

Expand All @@ -26,8 +28,13 @@ use crate::execution::call_info::{
Retdata,
};
use crate::execution::common_hints::ExecutionMode;
use crate::execution::entry_point::{CallEntryPoint, EntryPointExecutionContext};
use crate::execution::entry_point::{
CallEntryPoint,
ConstructorContext,
EntryPointExecutionContext,
};
use crate::execution::errors::EntryPointExecutionError;
use crate::execution::execution_utils::execute_deployment;
use crate::execution::syscalls::hint_processor::{
SyscallExecutionError,
INVALID_INPUT_LENGTH_ERROR,
Expand Down Expand Up @@ -244,15 +251,70 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> {

fn deploy(
&mut self,
_class_hash: Felt,
_contract_address_salt: Felt,
_calldata: &[Felt],
_deploy_from_zero: bool,
_remaining_gas: &mut u128,
class_hash: Felt,
contract_address_salt: Felt,
calldata: &[Felt],
deploy_from_zero: bool,
remaining_gas: &mut u128,
) -> SyscallResult<(Felt, Vec<Felt>)> {
todo!("Implement deploy syscall.");
}
self.pre_execute_syscall(remaining_gas, self.context.gas_costs().deploy_gas_cost)?;

let deployer_address = self.call.storage_address;
let deployer_address_for_calculation =
if deploy_from_zero { ContractAddress::default() } else { deployer_address };

let class_hash = ClassHash(class_hash);
let calldata = Calldata(Arc::new(calldata.to_vec()));

let deployed_contract_address = calculate_contract_address(
ContractAddressSalt(contract_address_salt),
class_hash,
&calldata,
deployer_address_for_calculation,
)
.map_err(|err| self.handle_error(remaining_gas, err.into()))?;

let ctor_context = ConstructorContext {
class_hash,
code_address: Some(deployed_contract_address),
storage_address: deployed_contract_address,
caller_address: deployer_address,
};

let mut remaining_gas_u64 =
u64::try_from(*remaining_gas).expect("Failed to convert gas to u64.");

let call_info = execute_deployment(
self.state,
self.resources,
self.context,
ctor_context,
calldata,
// Warning: converting of reference would create a new reference to different data,
// example:
// let mut a: u128 = 1;
// let a_ref: &mut u128 = &mut a;
//
// let mut b: u64 = u64::try_from(*a_ref).unwrap();
//
// assert_eq!(b, 1);
//
// b += 1;
//
// assert_eq!(b, 2);
// assert_eq!(a, 1);
&mut remaining_gas_u64,
)
.map_err(|err| self.handle_error(remaining_gas, err.into()))?;

*remaining_gas = u128::from(remaining_gas_u64);

let constructor_retdata = call_info.execution.retdata.0[..].to_vec();

self.inner_calls.push(call_info);

Ok((Felt::from(deployed_contract_address), constructor_retdata))
}
fn replace_class(&mut self, _class_hash: Felt, _remaining_gas: &mut u128) -> SyscallResult<()> {
todo!("Implement replace_class syscall.");
}
Expand Down
16 changes: 16 additions & 0 deletions crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ use crate::test_utils::initial_test_state::test_state;
use crate::test_utils::{calldata_for_deploy_test, trivial_external_entry_point_new, CairoVersion};

#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 205200;"VM")]
#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native), 215310;"Native")
)]
fn no_constructor(deployer_contract: FeatureContract, expected_gas: u64) {
// TODO(Yoni): share the init code of the tests in this file.

Expand Down Expand Up @@ -63,6 +67,10 @@ fn no_constructor(deployer_contract: FeatureContract, expected_gas: u64) {
}

#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1);"VM")]
#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native);"Native")
)]
fn no_constructor_nonempty_calldata(deployer_contract: FeatureContract) {
let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1);
let class_hash = empty_contract.get_class_hash();
Expand All @@ -89,6 +97,10 @@ fn no_constructor_nonempty_calldata(deployer_contract: FeatureContract) {
}

#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1),214550, 4610;"VM")]
#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native),233890, 13840;"Native")
)]
fn with_constructor(
deployer_contract: FeatureContract,
expected_gas: u64,
Expand Down Expand Up @@ -151,6 +163,10 @@ fn with_constructor(
}

#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1);"VM")]
#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native);"Native")
)]
fn to_unavailable_address(deployer_contract: FeatureContract) {
let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1);
let mut state = test_state(
Expand Down

0 comments on commit d3ffdd6

Please sign in to comment.