Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Fix/Refactor State::count actual storage changes + Support DeployAccount in the RpcStateReader #1096

Merged
merged 9 commits into from
Oct 24, 2023
7 changes: 4 additions & 3 deletions rpc_state_reader/src/rpc_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ impl RpcState {
contract_address.0.key().clone().to_string()
]),
)
.unwrap();
.unwrap_or_default();

ClassHash(hash)
}
Expand All @@ -431,7 +431,8 @@ impl RpcState {
contract_address.0.key().clone().to_string()
]),
)
.unwrap()
// When running deploy_account transactions, the nonce doesn't exist on the previous block so we return 0
.unwrap_or_default()
}

pub fn get_storage_at(
Expand All @@ -450,7 +451,7 @@ impl RpcState {
self.block.to_value().unwrap()
]),
)
.unwrap()
.unwrap_or_default()
}

/// Requests the given transaction to the Feeder Gateway API.
Expand Down
3 changes: 3 additions & 0 deletions rpc_state_reader/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ pub fn deserialize_transaction_json(
"unimplemented invoke version: {x}"
))),
},
"DEPLOY_ACCOUNT" => Ok(Transaction::DeployAccount(serde_json::from_value(
transaction,
)?)),
x => Err(serde::de::Error::custom(format!(
"unimplemented transaction type deserialization: {x}"
))),
Expand Down
34 changes: 31 additions & 3 deletions rpc_state_reader/tests/blockifier_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use blockifier::{
state_api::{StateReader, StateResult},
},
transaction::{
account_transaction::AccountTransaction, objects::TransactionExecutionInfo,
transactions::ExecutableTransaction,
account_transaction::AccountTransaction,
objects::TransactionExecutionInfo,
transactions::{DeployAccountTransaction, ExecutableTransaction},
},
};
use blockifier::{
Expand All @@ -27,7 +28,10 @@ use starknet::core::types::ContractClass as SNContractClass;
use starknet_api::{
block::BlockNumber,
contract_address,
core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey},
core::{
calculate_contract_address, ClassHash, CompiledClassHash, ContractAddress, Nonce,
PatriciaKey,
},
hash::{StarkFelt, StarkHash},
patricia_key, stark_felt,
state::StorageKey,
Expand Down Expand Up @@ -176,6 +180,20 @@ pub fn execute_tx(
let invoke = InvokeTransaction { tx, tx_hash };
AccountTransaction::Invoke(invoke)
}
SNTransaction::DeployAccount(tx) => {
let contract_address = calculate_contract_address(
tx.contract_address_salt,
tx.class_hash,
&tx.constructor_calldata,
ContractAddress::default(),
)
.unwrap();
AccountTransaction::DeployAccount(DeployAccountTransaction {
tx,
tx_hash,
contract_address,
})
}
_ => unimplemented!(),
};

Expand Down Expand Up @@ -286,6 +304,16 @@ fn blockifier_test_recent_tx() {
186551, // real block 186552
RpcChain::MainNet
)]
#[test_case(
"0x1cbc74e101a1533082a021ce53235cfd744899b0ff948d1949a64646e0f15c2",
885298, // real block 885299
RpcChain::TestNet
)]
#[test_case(
"0x5a5de1f42f6005f3511ea6099daed9bcbcf9de334ee714e8563977e25f71601",
281513, // real block 281514
RpcChain::MainNet
)]
fn blockifier_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) {
let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number));

Expand Down
17 changes: 16 additions & 1 deletion rpc_state_reader/tests/sir_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use starknet_in_rust::{
state_cache::StorageEntry,
BlockInfo,
},
transaction::InvokeFunction,
transaction::{DeployAccount, InvokeFunction},
utils::{Address, ClassHash},
};

Expand Down Expand Up @@ -143,6 +143,11 @@ pub fn execute_tx_configurable(
SNTransaction::Invoke(tx) => InvokeFunction::from_invoke_transaction(tx, chain_id)
.unwrap()
.create_for_simulation(skip_validate, false, false, false, skip_nonce_check),
SNTransaction::DeployAccount(tx) => {
DeployAccount::from_sn_api_transaction(tx, chain_id.to_felt())
.unwrap()
.create_for_simulation(skip_validate, false, false, false)
}
_ => unimplemented!(),
};

Expand Down Expand Up @@ -277,6 +282,16 @@ fn test_get_gas_price() {
317092, // real block 317093
RpcChain::MainNet
)]
#[test_case(
"0x1cbc74e101a1533082a021ce53235cfd744899b0ff948d1949a64646e0f15c2",
885298, // real block 885299
RpcChain::TestNet
)]
#[test_case(
"0x5a5de1f42f6005f3511ea6099daed9bcbcf9de334ee714e8563977e25f71601",
281513, // real block 281514
RpcChain::MainNet
)]
fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) {
let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number));

Expand Down
2 changes: 1 addition & 1 deletion src/definitions/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::collections::HashMap;

pub(crate) const L2_TO_L1_MSG_HEADER_SIZE: usize = 3;
pub(crate) const L1_TO_L2_MSG_HEADER_SIZE: usize = 5;
pub(crate) const DEPLOYMENT_INFO_SIZE: usize = 1;
pub(crate) const CLASS_UPDATE_SIZE: usize = 1;
pub(crate) const CONSUMED_MSG_TO_L2_N_TOPICS: usize = 3;
pub(crate) const LOG_MSG_TO_L1_N_TOPICS: usize = 2;
pub(crate) const N_DEFAULT_TOPICS: usize = 1; // Events have one default topic.
Expand Down
47 changes: 25 additions & 22 deletions src/execution/gas_usage.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::definitions::constants::*;
use crate::execution::L2toL1MessageInfo;
use crate::services::eth_definitions::eth_gas_constants::*;
use crate::state::state_api::StateChangesCount;

/// Estimates L1 gas usage by Starknet's update state and the verifier
///
Expand All @@ -19,16 +20,13 @@ use crate::services::eth_definitions::eth_gas_constants::*;
/// The estimation of L1 gas usage as a `usize` value.
pub fn calculate_tx_gas_usage(
l2_to_l1_messages: Vec<L2toL1MessageInfo>,
n_modified_contracts: usize,
n_storage_changes: usize,
state_changes: &StateChangesCount,
l1_handler_payload_size: Option<usize>,
n_deployments: usize,
) -> usize {
let residual_message_segment_length =
get_message_segment_lenght(&l2_to_l1_messages, l1_handler_payload_size);

let residual_onchain_data_segment_length =
get_onchain_data_segment_length(n_modified_contracts, n_storage_changes, n_deployments);
let residual_onchain_data_segment_length = get_onchain_data_segment_length(state_changes);

let n_l2_to_l1_messages = l2_to_l1_messages.len();
let n_l1_to_l2_messages = match l1_handler_payload_size {
Expand Down Expand Up @@ -95,22 +93,18 @@ pub fn get_message_segment_lenght(
}

/// Calculates the amount of `felt252` added to the output message's segment by the given operations.
///
/// # Parameters:
///
/// - `n_modified_contracts`: The number of contracts modified by the transaction.
/// - `n_storage_changes`: The number of storage changes made by the transaction.
/// - `n_deployments`: The number of contracts deployed by the transaction.
///
/// # Returns:
///
/// The on-chain data segment length
pub const fn get_onchain_data_segment_length(
n_modified_contracts: usize,
n_storage_changes: usize,
n_deployments: usize,
) -> usize {
n_modified_contracts * 2 + n_deployments * DEPLOYMENT_INFO_SIZE + n_storage_changes * 2
pub const fn get_onchain_data_segment_length(state_changes: &StateChangesCount) -> usize {
// For each newly modified contract:
// contract address (1 word).
// + 1 word with the following info: A flag indicating whether the class hash was updated, the
// number of entry updates, and the new nonce.
state_changes.n_modified_contracts * 2
// For each class updated (through a deploy or a class replacement).
+ state_changes.n_class_hash_updates * CLASS_UPDATE_SIZE
// For each modified storage cell: key, new value.
+ state_changes.n_storage_updates * 2
// For each compiled class updated (through declare): class_hash, compiled_class_hash
+ state_changes.n_compiled_class_hash_updates * 2
}

/// Calculates the cost of ConsumedMessageToL2 event emissions caused by an L1 handler with the given
Expand Down Expand Up @@ -261,7 +255,16 @@ mod test {
let message2 = L2toL1MessageInfo::new(ord_ev2, Address(1235.into()));

assert_eq!(
calculate_tx_gas_usage(vec![message1, message2], 2, 2, Some(2), 1),
calculate_tx_gas_usage(
vec![message1, message2],
&StateChangesCount {
n_storage_updates: 2,
n_class_hash_updates: 1,
n_compiled_class_hash_updates: 0,
n_modified_contracts: 2
},
Some(2)
),
76439
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/services/api/contract_classes/compiled_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl From<StarknetRsContractClass> for CompiledClass {
)
})
.collect::<Vec<ContractEntryPoint>>();
entry_points_by_type.insert(EntryPointType::Constructor, l1_handler_entries);
entry_points_by_type.insert(EntryPointType::L1Handler, l1_handler_entries);

let v = serde_json::to_value(&_deprecated_contract_class.abi).unwrap();
let abi: Option<AbiType> = serde_json::from_value(v).unwrap();
Expand Down
39 changes: 26 additions & 13 deletions src/state/cached_state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
state_api::{State, StateReader},
state_api::{State, StateChangesCount, StateReader},
state_cache::{StateCache, StorageEntry},
};
use crate::{
Expand Down Expand Up @@ -283,10 +283,10 @@ impl<T: StateReader> State for CachedState<T> {
Ok(())
}

fn count_actual_storage_changes(
fn count_actual_state_changes(
&mut self,
fee_token_and_sender_address: Option<(&Address, &Address)>,
) -> Result<(usize, usize), StateError> {
) -> Result<StateChangesCount, StateError> {
self.update_initial_values_of_write_only_accesses()?;

let mut storage_updates = subtract_mappings(
Expand All @@ -296,17 +296,24 @@ impl<T: StateReader> State for CachedState<T> {

let storage_unique_updates = storage_updates.keys().map(|k| k.0.clone());

let class_hash_updates = subtract_mappings_keys(
let class_hash_updates: Vec<&Address> = subtract_mappings_keys(
&self.cache.class_hash_writes,
&self.cache.class_hash_initial_values,
)
.collect();
let n_class_hash_updates = class_hash_updates.len();

let compiled_class_hash_updates = subtract_mappings_keys(
&self.cache.compiled_class_hash_writes,
&self.cache.compiled_class_hash_initial_values,
);

let nonce_updates =
subtract_mappings_keys(&self.cache.nonce_writes, &self.cache.nonce_initial_values);

let mut modified_contracts: HashSet<Address> = HashSet::new();
modified_contracts.extend(storage_unique_updates);
modified_contracts.extend(class_hash_updates.cloned());
modified_contracts.extend(class_hash_updates.into_iter().cloned());
modified_contracts.extend(nonce_updates.cloned());

// Add fee transfer storage update before actually charging it, as it needs to be included in the
Expand All @@ -320,7 +327,12 @@ impl<T: StateReader> State for CachedState<T> {
modified_contracts.remove(fee_token_address);
}

Ok((modified_contracts.len(), storage_updates.len()))
Ok(StateChangesCount {
n_storage_updates: storage_updates.len(),
n_class_hash_updates,
n_compiled_class_hash_updates: compiled_class_hash_updates.count(),
n_modified_contracts: modified_contracts.len(),
})
}

/// Returns the class hash for a given contract address.
Expand Down Expand Up @@ -800,7 +812,7 @@ mod tests {

/// This test calculate the number of actual storage changes.
#[test]
fn count_actual_storage_changes_test() {
fn count_actual_state_changes_test() {
let state_reader = InMemoryStateReader::default();

let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new());
Expand All @@ -822,14 +834,15 @@ mod tests {
let fee_token_address = Address(123.into());
let sender_address = Address(321.into());

let expected_changes = {
let n_storage_updates = 3 + 1; // + 1 fee transfer balance update
let n_modified_contracts = 2;

(n_modified_contracts, n_storage_updates)
let expected_changes = StateChangesCount {
n_storage_updates: 3 + 1, // + 1 fee transfer balance update,
n_class_hash_updates: 0,
n_compiled_class_hash_updates: 0,
n_modified_contracts: 2,
};

let changes = cached_state
.count_actual_storage_changes(Some((&fee_token_address, &sender_address)))
.count_actual_state_changes(Some((&fee_token_address, &sender_address)))
.unwrap();

assert_eq!(changes, expected_changes);
Expand Down
14 changes: 11 additions & 3 deletions src/state/state_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ pub trait StateReader {
) -> Result<CompiledClassHash, StateError>;
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct StateChangesCount {
pub n_storage_updates: usize,
pub n_class_hash_updates: usize,
pub n_compiled_class_hash_updates: usize,
pub n_modified_contracts: usize,
}

pub trait State {
fn set_contract_class(
&mut self,
Expand Down Expand Up @@ -63,11 +71,11 @@ pub trait State {

fn apply_state_update(&mut self, sate_updates: &StateDiff) -> Result<(), StateError>;

/// Counts the amount of modified contracts and the updates to the storage
fn count_actual_storage_changes(
/// Counts the amount of state changes
fn count_actual_state_changes(
&mut self,
fee_token_and_sender_address: Option<(&Address, &Address)>,
) -> Result<(usize, usize), StateError>;
) -> Result<StateChangesCount, StateError>;

/// Returns the class hash of the contract class at the given address.
/// Returns zero by default if the value is not present
Expand Down
2 changes: 1 addition & 1 deletion src/transaction/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl Declare {
} else {
self.run_validate_entrypoint(state, &mut resources_manager, block_context)?
};
let changes = state.count_actual_storage_changes(Some((
let changes = state.count_actual_state_changes(Some((
&block_context.starknet_os_config.fee_token_address,
&self.sender_address,
)))?;
Expand Down
2 changes: 1 addition & 1 deletion src/transaction/declare_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ impl DeclareV2 {
(info, gas)
};

let storage_changes = state.count_actual_storage_changes(Some((
let storage_changes = state.count_actual_state_changes(Some((
&block_context.starknet_os_config.fee_token_address,
&self.sender_address,
)))?;
Expand Down
4 changes: 2 additions & 2 deletions src/transaction/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl Deploy {

let resources_manager = ExecutionResourcesManager::default();

let changes = state.count_actual_storage_changes(None)?;
let changes = state.count_actual_state_changes(None)?;
let actual_resources = calculate_tx_resources(
resources_manager,
&[Some(call_info.clone())],
Expand Down Expand Up @@ -250,7 +250,7 @@ impl Deploy {
block_context.validate_max_n_steps,
)?;

let changes = state.count_actual_storage_changes(None)?;
let changes = state.count_actual_state_changes(None)?;
let actual_resources = calculate_tx_resources(
resources_manager,
&[call_info.clone()],
Expand Down
Loading