Skip to content

Commit

Permalink
chore(blokifier): unify get entry point for all contract classes
Browse files Browse the repository at this point in the history
  • Loading branch information
meship-starkware committed Sep 19, 2024
1 parent 52760f8 commit 7a4d4ad
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 99 deletions.
83 changes: 48 additions & 35 deletions crates/blockifier/src/execution/contract_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@ use serde::{Deserialize, Deserializer, Serialize};
use starknet_api::core::EntryPointSelector;
use starknet_api::deprecated_contract_class::{
ContractClass as DeprecatedContractClass,
EntryPoint,
EntryPointOffset,
EntryPointType,
EntryPointV0,
Program as DeprecatedProgram,
};
use starknet_types_core::felt::Felt;

use crate::abi::constants::{self};
use crate::execution::entry_point::CallEntryPoint;
use crate::execution::entry_point_execution::get_entry_point;
use crate::execution::errors::{ContractClassError, NativeEntryPointError, PreExecutionError};
use crate::execution::execution_utils::{poseidon_hash_many_cost, sn_api_to_cairo_vm_program};
use crate::execution::native::utils::contract_entrypoint_to_entrypoint_selector;
Expand All @@ -63,6 +64,23 @@ pub enum TrackingResource {
SierraGas, // AKA Sierra mode.
}

#[derive(Clone)]
pub enum EntryPoint {
V0(EntryPointV0),
V1(EntryPointV1),
Native(NativeEntryPoint),
}

impl EntryPoint {
pub fn selector(&self) -> &EntryPointSelector {
match self {
EntryPoint::V0(ep) => &ep.selector,
EntryPoint::V1(ep) => &ep.selector,
EntryPoint::Native(ep) => &ep.selector,
}
}
}

/// Represents a runnable Starknet contract class (meaning, the program is runnable by the VM).
#[derive(Clone, Debug, PartialEq, derive_more::From)]
pub enum ContractClass {
Expand Down Expand Up @@ -101,6 +119,23 @@ impl ContractClass {
}
}

pub fn entry_points_of_same_type(&self, entry_point_type: EntryPointType) -> Vec<EntryPoint> {
match self {
ContractClass::V0(class) => class.entry_points_by_type[&entry_point_type]
.iter()
.map(|ep| EntryPoint::V0(ep.clone()))
.collect(),
ContractClass::V1(class) => class.entry_points_by_type[&entry_point_type]
.iter()
.map(|ep| EntryPoint::V1(ep.clone()))
.collect(),
ContractClass::V1Native(class) => class.entry_points_by_type[entry_point_type]
.iter()
.map(|ep| EntryPoint::Native(ep.clone()))
.collect(),
}
}

pub fn get_visited_segments(
&self,
visited_pcs: &HashSet<usize>,
Expand Down Expand Up @@ -201,7 +236,7 @@ impl ContractClassV0 {
pub struct ContractClassV0Inner {
#[serde(deserialize_with = "deserialize_program")]
pub program: Program,
pub entry_points_by_type: HashMap<EntryPointType, Vec<EntryPoint>>,
pub entry_points_by_type: HashMap<EntryPointType, Vec<EntryPointV0>>,
}

impl TryFrom<DeprecatedContractClass> for ContractClassV0 {
Expand Down Expand Up @@ -247,21 +282,9 @@ impl ContractClassV1 {
&self,
call: &CallEntryPoint,
) -> Result<EntryPointV1, PreExecutionError> {
call.verify_constructor()?;

let entry_points_of_same_type = &self.0.entry_points_by_type[&call.entry_point_type];
let filtered_entry_points: Vec<_> = entry_points_of_same_type
.iter()
.filter(|ep| ep.selector == call.entry_point_selector)
.collect();

match &filtered_entry_points[..] {
[] => Err(PreExecutionError::EntryPointNotFound(call.entry_point_selector)),
[entry_point] => Ok((*entry_point).clone()),
_ => Err(PreExecutionError::DuplicatedEntryPointSelector {
selector: call.entry_point_selector,
typ: call.entry_point_type,
}),
match get_entry_point(&ContractClass::V1(self.clone()), call)? {
EntryPoint::V1(entry_point) => Ok(entry_point),
EntryPoint::V0(_) | EntryPoint::Native(_) => panic!("Unexpected entry point type."),
}
}

Expand Down Expand Up @@ -640,23 +663,13 @@ impl NativeContractClassV1 {
}

/// Returns an entry point into the natively compiled contract.
pub fn get_entry_point(&self, call: &CallEntryPoint) -> Result<&FunctionId, PreExecutionError> {
call.verify_constructor()?;

let entry_points_of_same_type = &self.0.entry_points_by_type[call.entry_point_type];
let filtered_entry_points: Vec<_> = entry_points_of_same_type
.iter()
.filter(|ep| ep.selector == call.entry_point_selector)
.collect();
pub fn get_entry_point(&self, call: &CallEntryPoint) -> Result<FunctionId, PreExecutionError> {
let entry_point = match get_entry_point(&ContractClass::V1Native(self.clone()), call)?{
EntryPoint::Native(entry_point) => entry_point,
EntryPoint::V0(_) | EntryPoint::V1(_) => panic!("Unexpected entry point type."),
};

match &filtered_entry_points[..] {
[] => Err(PreExecutionError::EntryPointNotFound(call.entry_point_selector)),
[entry_point] => Ok(&entry_point.function_id),
_ => Err(PreExecutionError::DuplicatedEntryPointSelector {
selector: call.entry_point_selector,
typ: call.entry_point_type,
}),
}
Ok(entry_point.function_id)
}
}

Expand Down Expand Up @@ -751,9 +764,9 @@ impl Index<EntryPointType> for NativeContractEntryPoints {
}
}

#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
/// Provides a relation between a function in a contract and a compiled contract.
struct NativeEntryPoint {
pub struct NativeEntryPoint {
/// The selector is the key to find the function in the contract.
selector: EntryPointSelector,
/// And the function_id is the key to find the function in the compiled contract.
Expand Down
63 changes: 19 additions & 44 deletions crates/blockifier/src/execution/deprecated_entry_point_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@ use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable};
use cairo_vm::vm::errors::vm_errors::VirtualMachineError;
use cairo_vm::vm::runners::cairo_runner::{CairoArg, CairoRunner, ExecutionResources};
use starknet_api::core::EntryPointSelector;
use starknet_api::deprecated_contract_class::EntryPointType;
use starknet_api::deprecated_contract_class::EntryPointV0;
use starknet_api::hash::StarkHash;


use super::execution_utils::SEGMENT_ARENA_BUILTIN_SIZE;
use crate::abi::abi_utils::selector_from_name;
use crate::abi::constants::{CONSTRUCTOR_ENTRY_POINT_NAME, DEFAULT_ENTRY_POINT_SELECTOR};
use crate::abi::constants::DEFAULT_ENTRY_POINT_SELECTOR;
use crate::execution::call_info::{CallExecution, CallInfo};
use crate::execution::contract_class::ContractClassV0;
use crate::execution::contract_class::{ContractClassV0, ContractClass, EntryPoint};
use crate::execution::deprecated_syscalls::hint_processor::DeprecatedSyscallHintProcessor;
use crate::execution::entry_point::{
CallEntryPoint,
EntryPointExecutionContext,
EntryPointExecutionResult,
};
use crate::execution::entry_point_execution::get_entry_point;
use crate::execution::errors::{PostExecutionError, PreExecutionError};
use crate::execution::execution_utils::{read_execution_retdata, Args, ReadOnlySegments};
use crate::state::state_api::State;
Expand Down Expand Up @@ -124,48 +125,22 @@ pub fn resolve_entry_point_pc(
call: &CallEntryPoint,
contract_class: &ContractClassV0,
) -> Result<usize, PreExecutionError> {
if call.entry_point_type == EntryPointType::Constructor
&& call.entry_point_selector != selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME)
{
return Err(PreExecutionError::InvalidConstructorEntryPointName);
}

let entry_points_of_same_type = &contract_class.entry_points_by_type[&call.entry_point_type];
let filtered_entry_points: Vec<_> = entry_points_of_same_type
.iter()
.filter(|ep| ep.selector == call.entry_point_selector)
.collect();

// Returns the default entrypoint if the given selector is missing.
if filtered_entry_points.is_empty() {
match entry_points_of_same_type.first() {
Some(entry_point) => {
if entry_point.selector
== EntryPointSelector(StarkHash::from(DEFAULT_ENTRY_POINT_SELECTOR))
{
return Ok(entry_point.offset.0);
} else {
return Err(PreExecutionError::EntryPointNotFound(call.entry_point_selector));
}
}
None => {
return Err(PreExecutionError::NoEntryPointOfTypeFound(call.entry_point_type));
}
}
}
let entry_point = match get_entry_point(&ContractClass::V0(contract_class.clone()), call)?{
EntryPoint::V0(entry_point) => entry_point,
EntryPoint::V1(_) | EntryPoint::Native(_) => panic!("Unexpected entry point type."),
};
Ok(entry_point.offset.0)
}

if filtered_entry_points.len() > 1 {
return Err(PreExecutionError::DuplicatedEntryPointSelector {
selector: call.entry_point_selector,
typ: call.entry_point_type,
});
pub fn handle_default_entry_point(
entry_point: &EntryPointV0,
call: &CallEntryPoint,
) -> Result<EntryPointV0, PreExecutionError> {
if entry_point.selector == EntryPointSelector(StarkHash::from(DEFAULT_ENTRY_POINT_SELECTOR)) {
return Ok(entry_point.clone());
} else {
return Err(PreExecutionError::EntryPointNotFound(call.entry_point_selector));
}

// Filtered entry points contain exactly one element.
let entry_point = filtered_entry_points
.first()
.expect("The number of entry points with the given selector is exactly one.");
Ok(entry_point.offset.0)
}

pub fn prepare_call_arguments(
Expand Down
39 changes: 38 additions & 1 deletion crates/blockifier/src/execution/entry_point_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use starknet_api::felt;
use starknet_types_core::felt::Felt;

use crate::execution::call_info::{CallExecution, CallInfo, Retdata};
use crate::execution::contract_class::{ContractClassV1, EntryPointV1};
use crate::execution::contract_class::{ContractClass, ContractClassV1, EntryPoint, EntryPointV1};
use crate::execution::deprecated_entry_point_execution::handle_default_entry_point;
use crate::execution::entry_point::{
CallEntryPoint,
EntryPointExecutionContext,
Expand Down Expand Up @@ -145,6 +146,42 @@ fn register_visited_pcs(
Ok(())
}

pub fn get_entry_point(
contract_class: &ContractClass,
call: &CallEntryPoint,
) -> Result<EntryPoint, PreExecutionError> {
call.verify_constructor()?;

let entry_points_of_same_type =
&contract_class.entry_points_of_same_type(call.entry_point_type);
let filtered_entry_points: Vec<_> = entry_points_of_same_type
.iter()
.filter(|ep| *ep.selector() == call.entry_point_selector)
.collect();

match &filtered_entry_points[..] {
[] => match contract_class {
ContractClass::V0(_contract_class) => match entry_points_of_same_type.first() {
Some(entry_point) => match entry_point {
EntryPoint::V0(entry_point) => Ok(EntryPoint::V0(handle_default_entry_point(&entry_point, call)?)),
EntryPoint::V1(_) | EntryPoint::Native(_) => {
panic!("Unexpected entry point type")
}
},
None => Err(PreExecutionError::EntryPointNotFound(call.entry_point_selector)),
},
ContractClass::V1(_) | ContractClass::V1Native(_) => {
Err(PreExecutionError::EntryPointNotFound(call.entry_point_selector))
}
},
[entry_point] => Ok((**entry_point).clone()),
_ => Err(PreExecutionError::DuplicatedEntryPointSelector {
selector: call.entry_point_selector,
typ: call.entry_point_type,
}),
}
}

pub fn initialize_execution_context<'a>(
call: CallEntryPoint,
contract_class: &'a ContractClassV1,
Expand Down
8 changes: 4 additions & 4 deletions crates/papyrus_protobuf/src/converters/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ impl From<state::ContractClass> for protobuf::Cairo1Class {
}
}

impl TryFrom<protobuf::EntryPoint> for deprecated_contract_class::EntryPoint {
impl TryFrom<protobuf::EntryPoint> for deprecated_contract_class::EntryPointV0 {
type Error = ProtobufConversionError;
fn try_from(value: protobuf::EntryPoint) -> Result<Self, Self::Error> {
let selector_felt =
Expand All @@ -281,12 +281,12 @@ impl TryFrom<protobuf::EntryPoint> for deprecated_contract_class::EntryPoint {
value.offset.try_into().expect("Failed converting u64 to usize"),
);

Ok(deprecated_contract_class::EntryPoint { selector, offset })
Ok(deprecated_contract_class::EntryPointV0 { selector, offset })
}
}

impl From<deprecated_contract_class::EntryPoint> for protobuf::EntryPoint {
fn from(value: deprecated_contract_class::EntryPoint) -> Self {
impl From<deprecated_contract_class::EntryPointV0> for protobuf::EntryPoint {
fn from(value: deprecated_contract_class::EntryPointV0) -> Self {
protobuf::EntryPoint {
selector: Some(value.selector.0.into()),
offset: u64::try_from(value.offset.0).expect("Failed converting usize to u64"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use starknet_api::core::{CompiledClassHash, ContractAddress, Nonce};
use starknet_api::data_availability::DataAvailabilityMode;
use starknet_api::deprecated_contract_class::{
ContractClassAbiEntry as DeprecatedContractClassAbiEntry,
EntryPoint as DeprecatedEntryPoint,
EntryPointType as DeprecatedEntryPointType,
EntryPointV0 as DeprecatedEntryPoint,
EventAbiEntry,
FunctionAbiEntry,
StructAbiEntry,
Expand Down
8 changes: 6 additions & 2 deletions crates/papyrus_rpc/src/v0_6/deprecated_contract_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ use std::collections::HashMap;

use papyrus_storage::db::serialization::StorageSerdeError;
use serde::{Deserialize, Serialize};
use starknet_api::deprecated_contract_class::{ContractClassAbiEntry, EntryPoint, EntryPointType};
use starknet_api::deprecated_contract_class::{
ContractClassAbiEntry,
EntryPointType,
EntryPointV0,
};

use crate::compression_utils::compress_and_encode;

Expand All @@ -12,7 +16,7 @@ pub struct ContractClass {
/// A base64 encoding of the gzip-compressed JSON representation of program.
pub program: String,
/// The selector of each entry point is a unique identifier in the program.
pub entry_points_by_type: HashMap<EntryPointType, Vec<EntryPoint>>,
pub entry_points_by_type: HashMap<EntryPointType, Vec<EntryPointV0>>,
}

impl TryFrom<starknet_api::deprecated_contract_class::ContractClass> for ContractClass {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use starknet_api::core::{CompiledClassHash, ContractAddress, Nonce};
use starknet_api::data_availability::DataAvailabilityMode;
use starknet_api::deprecated_contract_class::{
ContractClassAbiEntry as DeprecatedContractClassAbiEntry,
EntryPoint as DeprecatedEntryPoint,
EntryPointType as DeprecatedEntryPointType,
EntryPointV0 as DeprecatedEntryPoint,
EventAbiEntry,
FunctionAbiEntry,
StructAbiEntry,
Expand Down
8 changes: 6 additions & 2 deletions crates/papyrus_rpc/src/v0_7/deprecated_contract_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ use std::collections::HashMap;

use papyrus_storage::db::serialization::StorageSerdeError;
use serde::{Deserialize, Serialize};
use starknet_api::deprecated_contract_class::{ContractClassAbiEntry, EntryPoint, EntryPointType};
use starknet_api::deprecated_contract_class::{
ContractClassAbiEntry,
EntryPointType,
EntryPointV0,
};

use crate::compression_utils::compress_and_encode;

Expand All @@ -12,7 +16,7 @@ pub struct ContractClass {
/// A base64 encoding of the gzip-compressed JSON representation of program.
pub program: String,
/// The selector of each entry point is a unique identifier in the program.
pub entry_points_by_type: HashMap<EntryPointType, Vec<EntryPoint>>,
pub entry_points_by_type: HashMap<EntryPointType, Vec<EntryPointV0>>,
}

impl TryFrom<starknet_api::deprecated_contract_class::ContractClass> for ContractClass {
Expand Down
2 changes: 1 addition & 1 deletion crates/papyrus_storage/src/serialization/serializers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ use starknet_api::deprecated_contract_class::{
ConstructorType,
ContractClass as DeprecatedContractClass,
ContractClassAbiEntry,
EntryPoint as DeprecatedEntryPoint,
EntryPointOffset,
EntryPointType as DeprecatedEntryPointType,
EntryPointV0 as DeprecatedEntryPoint,
EventAbiEntry,
EventType,
FunctionAbiEntry,
Expand Down
2 changes: 1 addition & 1 deletion crates/papyrus_test_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ use starknet_api::deprecated_contract_class::{
ConstructorType,
ContractClass as DeprecatedContractClass,
ContractClassAbiEntry,
EntryPoint as DeprecatedEntryPoint,
EntryPointOffset,
EntryPointType as DeprecatedEntryPointType,
EntryPointV0 as DeprecatedEntryPoint,
EventAbiEntry,
EventType,
FunctionAbiEntry,
Expand Down
Loading

0 comments on commit 7a4d4ad

Please sign in to comment.