Skip to content

Commit 111668e

Browse files
committed
Added VisitedPcsSet as abstraction layer to visited_pcs in
`CachedState`.
1 parent 497a36f commit 111668e

31 files changed

+423
-258
lines changed

crates/blockifier/src/blockifier/stateful_validator.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::fee::fee_checks::PostValidationReport;
1515
use crate::state::cached_state::CachedState;
1616
use crate::state::errors::StateError;
1717
use crate::state::state_api::StateReader;
18+
use crate::state::visited_pcs::VisitedPcs;
1819
use crate::transaction::account_transaction::AccountTransaction;
1920
use crate::transaction::errors::{TransactionExecutionError, TransactionPreValidationError};
2021
use crate::transaction::transaction_execution::Transaction;
@@ -39,12 +40,12 @@ pub enum StatefulValidatorError {
3940
pub type StatefulValidatorResult<T> = Result<T, StatefulValidatorError>;
4041

4142
/// Manages state related transaction validations for pre-execution flows.
42-
pub struct StatefulValidator<S: StateReader> {
43-
tx_executor: TransactionExecutor<S>,
43+
pub struct StatefulValidator<S: StateReader, V: VisitedPcs> {
44+
tx_executor: TransactionExecutor<S, V>,
4445
}
4546

46-
impl<S: StateReader> StatefulValidator<S> {
47-
pub fn create(state: CachedState<S>, block_context: BlockContext) -> Self {
47+
impl<S: StateReader, V: VisitedPcs> StatefulValidator<S, V> {
48+
pub fn create(state: CachedState<S, V>, block_context: BlockContext) -> Self {
4849
let tx_executor =
4950
TransactionExecutor::new(state, block_context, TransactionExecutorConfig::default());
5051
Self { tx_executor }

crates/blockifier/src/blockifier/transaction_executor.rs

+18-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::fmt::Debug;
12
#[cfg(feature = "concurrency")]
23
use std::panic::{self, catch_unwind, AssertUnwindSafe};
34
#[cfg(feature = "concurrency")]
@@ -18,6 +19,7 @@ use crate::context::BlockContext;
1819
use crate::state::cached_state::{CachedState, CommitmentStateDiff, TransactionalState};
1920
use crate::state::errors::StateError;
2021
use crate::state::state_api::StateReader;
22+
use crate::state::visited_pcs::VisitedPcs;
2123
use crate::transaction::errors::TransactionExecutionError;
2224
use crate::transaction::objects::TransactionExecutionInfo;
2325
use crate::transaction::transaction_execution::Transaction;
@@ -43,7 +45,7 @@ pub type TransactionExecutorResult<T> = Result<T, TransactionExecutorError>;
4345
pub type VisitedSegmentsMapping = Vec<(ClassHash, Vec<usize>)>;
4446

4547
// TODO(Gilad): make this hold TransactionContext instead of BlockContext.
46-
pub struct TransactionExecutor<S: StateReader> {
48+
pub struct TransactionExecutor<S: StateReader, V: VisitedPcs> {
4749
pub block_context: BlockContext,
4850
pub bouncer: Bouncer,
4951
// Note: this config must not affect the execution result (e.g. state diff and traces).
@@ -54,12 +56,12 @@ pub struct TransactionExecutor<S: StateReader> {
5456
// block state to the worker executor - operating at the chunk level - and gets it back after
5557
// committing the chunk. The block state is wrapped with an Option<_> to allow setting it to
5658
// `None` while it is moved to the worker executor.
57-
pub block_state: Option<CachedState<S>>,
59+
pub block_state: Option<CachedState<S, V>>,
5860
}
5961

60-
impl<S: StateReader> TransactionExecutor<S> {
62+
impl<S: StateReader, V: VisitedPcs> TransactionExecutor<S, V> {
6163
pub fn new(
62-
block_state: CachedState<S>,
64+
block_state: CachedState<S, V>,
6365
block_context: BlockContext,
6466
config: TransactionExecutorConfig,
6567
) -> Self {
@@ -85,9 +87,10 @@ impl<S: StateReader> TransactionExecutor<S> {
8587
&mut self,
8688
tx: &Transaction,
8789
) -> TransactionExecutorResult<TransactionExecutionInfo> {
88-
let mut transactional_state = TransactionalState::create_transactional(
89-
self.block_state.as_mut().expect(BLOCK_STATE_ACCESS_ERR),
90-
);
90+
let mut transactional_state: TransactionalState<'_, _, V> =
91+
TransactionalState::create_transactional(
92+
self.block_state.as_mut().expect(BLOCK_STATE_ACCESS_ERR),
93+
);
9194
// Executing a single transaction cannot be done in a concurrent mode.
9295
let execution_flags =
9396
ExecutionFlags { charge_fee: true, validate: true, concurrency_mode: false };
@@ -157,7 +160,8 @@ impl<S: StateReader> TransactionExecutor<S> {
157160
.as_ref()
158161
.expect(BLOCK_STATE_ACCESS_ERR)
159162
.get_compiled_contract_class(*class_hash)?;
160-
Ok((*class_hash, contract_class.get_visited_segments(class_visited_pcs)?))
163+
let class_visited_pcs = V::to_set(class_visited_pcs.clone());
164+
Ok((*class_hash, contract_class.get_visited_segments(&class_visited_pcs)?))
161165
})
162166
.collect::<TransactionExecutorResult<_>>()?;
163167

@@ -170,7 +174,7 @@ impl<S: StateReader> TransactionExecutor<S> {
170174
}
171175
}
172176

173-
impl<S: StateReader + Send + Sync> TransactionExecutor<S> {
177+
impl<S: StateReader + Send + Sync, V: VisitedPcs + Send + Sync> TransactionExecutor<S, V> {
174178
/// Executes the given transactions on the state maintained by the executor.
175179
/// Stops if and when there is no more room in the block, and returns the executed transactions'
176180
/// results.
@@ -219,7 +223,7 @@ impl<S: StateReader + Send + Sync> TransactionExecutor<S> {
219223
chunk: &[Transaction],
220224
) -> Vec<TransactionExecutorResult<TransactionExecutionInfo>> {
221225
use crate::concurrency::utils::AbortIfPanic;
222-
use crate::state::cached_state::VisitedPcs;
226+
use crate::concurrency::worker_logic::ExecutionTaskOutput;
223227

224228
let block_state = self.block_state.take().expect("The block state should be `Some`.");
225229

@@ -263,20 +267,20 @@ impl<S: StateReader + Send + Sync> TransactionExecutor<S> {
263267

264268
let n_committed_txs = worker_executor.scheduler.get_n_committed_txs();
265269
let mut tx_execution_results = Vec::new();
266-
let mut visited_pcs: VisitedPcs = VisitedPcs::new();
270+
let mut visited_pcs: V = V::new();
267271
for execution_output in worker_executor.execution_outputs.iter() {
268272
if tx_execution_results.len() >= n_committed_txs {
269273
break;
270274
}
271-
let locked_execution_output = execution_output
275+
let locked_execution_output: ExecutionTaskOutput<V> = execution_output
272276
.lock()
273277
.expect("Failed to lock execution output.")
274278
.take()
275279
.expect("Output must be ready.");
276280
tx_execution_results
277281
.push(locked_execution_output.result.map_err(TransactionExecutorError::from));
278-
for (class_hash, class_visited_pcs) in locked_execution_output.visited_pcs {
279-
visited_pcs.entry(class_hash).or_default().extend(class_visited_pcs);
282+
for (class_hash, class_visited_pcs) in locked_execution_output.visited_pcs.iter() {
283+
visited_pcs.extend(class_hash, class_visited_pcs);
280284
}
281285
}
282286

crates/blockifier/src/blockifier/transaction_executor_test.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::bouncer::{Bouncer, BouncerWeights};
1313
use crate::context::BlockContext;
1414
use crate::state::cached_state::CachedState;
1515
use crate::state::state_api::StateReader;
16+
use crate::state::visited_pcs::VisitedPcs;
1617
use crate::test_utils::contracts::FeatureContract;
1718
use crate::test_utils::declare::declare_tx;
1819
use crate::test_utils::deploy_account::deploy_account_tx;
@@ -30,8 +31,8 @@ use crate::transaction::transaction_execution::Transaction;
3031
use crate::transaction::transactions::L1HandlerTransaction;
3132
use crate::{declare_tx_args, deploy_account_tx_args, invoke_tx_args, nonce};
3233

33-
fn tx_executor_test_body<S: StateReader>(
34-
state: CachedState<S>,
34+
fn tx_executor_test_body<S: StateReader, V: VisitedPcs>(
35+
state: CachedState<S, V>,
3536
block_context: BlockContext,
3637
tx: Transaction,
3738
expected_bouncer_weights: BouncerWeights,

crates/blockifier/src/bouncer_test.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::bouncer::{verify_tx_weights_in_bounds, Bouncer, BouncerWeights, Built
1313
use crate::context::BlockContext;
1414
use crate::execution::call_info::ExecutionSummary;
1515
use crate::state::cached_state::{StateChangesKeys, TransactionalState};
16+
use crate::state::visited_pcs::VisitedPcsSet;
1617
use crate::storage_key;
1718
use crate::test_utils::initial_test_state::test_state;
1819
use crate::transaction::errors::TransactionExecutionError;
@@ -187,7 +188,8 @@ fn test_bouncer_try_update(
187188
use crate::transaction::objects::TransactionResources;
188189

189190
let state = &mut test_state(&BlockContext::create_for_account_testing().chain_info, 0, &[]);
190-
let mut transactional_state = TransactionalState::create_transactional(state);
191+
let mut transactional_state: TransactionalState<'_, _, VisitedPcsSet> =
192+
TransactionalState::create_transactional(state);
191193

192194
// Setup the bouncer.
193195
let block_max_capacity = BouncerWeights {

crates/blockifier/src/concurrency/fee_utils.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::execution::call_info::CallInfo;
1010
use crate::fee::fee_utils::get_sequencer_balance_keys;
1111
use crate::state::cached_state::{ContractClassMapping, StateMaps};
1212
use crate::state::state_api::UpdatableState;
13+
use crate::state::visited_pcs::VisitedPcs;
1314
use crate::transaction::objects::TransactionExecutionInfo;
1415

1516
#[cfg(test)]
@@ -22,10 +23,10 @@ mod test;
2223
pub(crate) const STORAGE_READ_SEQUENCER_BALANCE_INDICES: (usize, usize) = (2, 3);
2324

2425
// Completes the fee transfer flow if needed (if the transfer was made in concurrent mode).
25-
pub fn complete_fee_transfer_flow(
26+
pub fn complete_fee_transfer_flow<V: VisitedPcs, U: UpdatableState<T = V>>(
2627
tx_context: &TransactionContext,
2728
tx_execution_info: &mut TransactionExecutionInfo,
28-
state: &mut impl UpdatableState,
29+
state: &mut U,
2930
) {
3031
if tx_context.is_sequencer_the_sender() {
3132
// When the sequencer is the sender, we use the sequential (full) fee transfer.
@@ -93,9 +94,9 @@ pub fn fill_sequencer_balance_reads(
9394
storage_read_values[high_index] = high;
9495
}
9596

96-
pub fn add_fee_to_sequencer_balance(
97+
pub fn add_fee_to_sequencer_balance<V: VisitedPcs, U: UpdatableState<T = V>>(
9798
fee_token_address: ContractAddress,
98-
state: &mut impl UpdatableState,
99+
state: &mut U,
99100
actual_fee: Fee,
100101
block_context: &BlockContext,
101102
sequencer_balance: (Felt, Felt),
@@ -120,5 +121,5 @@ pub fn add_fee_to_sequencer_balance(
120121
]),
121122
..StateMaps::default()
122123
};
123-
state.apply_writes(&writes, &ContractClassMapping::default(), &HashMap::default());
124+
state.apply_writes(&writes, &ContractClassMapping::default(), &V::default());
124125
}

crates/blockifier/src/concurrency/flow_test.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ use starknet_api::{contract_address, felt, patricia_key};
99
use crate::abi::sierra_types::{SierraType, SierraU128};
1010
use crate::concurrency::scheduler::{Scheduler, Task, TransactionStatus};
1111
use crate::concurrency::test_utils::{safe_versioned_state_for_testing, DEFAULT_CHUNK_SIZE};
12-
use crate::concurrency::versioned_state::ThreadSafeVersionedState;
12+
use crate::concurrency::versioned_state::{ThreadSafeVersionedState, VersionedStateProxy};
1313
use crate::state::cached_state::{CachedState, ContractClassMapping, StateMaps};
1414
use crate::state::state_api::UpdatableState;
15+
use crate::state::visited_pcs::VisitedPcsSet;
1516
use crate::storage_key;
1617
use crate::test_utils::dict_state_reader::DictStateReader;
1718

@@ -27,6 +28,9 @@ fn scheduler_flow_test(
2728
// transactions with multiple threads, where every transaction depends on its predecessor. Each
2829
// transaction sequentially advances a counter by reading the previous value and bumping it by
2930
// 1.
31+
32+
use crate::concurrency::versioned_state::VersionedStateProxy;
33+
use crate::state::visited_pcs::VisitedPcsSet;
3034
let scheduler = Arc::new(Scheduler::new(DEFAULT_CHUNK_SIZE));
3135
let versioned_state =
3236
safe_versioned_state_for_testing(CachedState::from(DictStateReader::default()));
@@ -53,7 +57,7 @@ fn scheduler_flow_test(
5357
state_proxy.apply_writes(
5458
&new_writes,
5559
&ContractClassMapping::default(),
56-
&HashMap::default(),
60+
&VisitedPcsSet::default(),
5761
);
5862
scheduler.finish_execution_during_commit(tx_index);
5963
}
@@ -66,13 +70,14 @@ fn scheduler_flow_test(
6670
versioned_state.pin_version(tx_index).apply_writes(
6771
&writes,
6872
&ContractClassMapping::default(),
69-
&HashMap::default(),
73+
&VisitedPcsSet::default(),
7074
);
7175
scheduler.finish_execution(tx_index);
7276
Task::AskForTask
7377
}
7478
Task::ValidationTask(tx_index) => {
75-
let state_proxy = versioned_state.pin_version(tx_index);
79+
let state_proxy: VersionedStateProxy<_, VisitedPcsSet> =
80+
versioned_state.pin_version(tx_index);
7681
let (reads, writes) =
7782
get_reads_writes_for(Task::ValidationTask(tx_index), &versioned_state);
7883
let read_set_valid = state_proxy.validate_reads(&reads);
@@ -120,11 +125,11 @@ fn scheduler_flow_test(
120125

121126
fn get_reads_writes_for(
122127
task: Task,
123-
versioned_state: &ThreadSafeVersionedState<CachedState<DictStateReader>>,
128+
versioned_state: &ThreadSafeVersionedState<CachedState<DictStateReader, VisitedPcsSet>>,
124129
) -> (StateMaps, StateMaps) {
125130
match task {
126131
Task::ExecutionTask(tx_index) => {
127-
let state_proxy = match tx_index {
132+
let state_proxy: VersionedStateProxy<_, VisitedPcsSet> = match tx_index {
128133
0 => {
129134
return (
130135
state_maps_with_single_storage_entry(0),
@@ -146,7 +151,8 @@ fn get_reads_writes_for(
146151
)
147152
}
148153
Task::ValidationTask(tx_index) => {
149-
let state_proxy = versioned_state.pin_version(tx_index);
154+
let state_proxy: VersionedStateProxy<_, VisitedPcsSet> =
155+
versioned_state.pin_version(tx_index);
150156
let tx_written_value = SierraU128::from_storage(
151157
&state_proxy,
152158
&contract_address!(CONTRACT_ADDRESS),

crates/blockifier/src/concurrency/test_utils.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::context::BlockContext;
77
use crate::execution::call_info::CallInfo;
88
use crate::state::cached_state::{CachedState, TransactionalState};
99
use crate::state::state_api::StateReader;
10+
use crate::state::visited_pcs::{VisitedPcs, VisitedPcsSet};
1011
use crate::test_utils::dict_state_reader::DictStateReader;
1112
use crate::transaction::account_transaction::AccountTransaction;
1213
use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags};
@@ -61,21 +62,22 @@ macro_rules! default_scheduler {
6162

6263
// TODO(meshi, 01/06/2024): Consider making this a macro.
6364
pub fn safe_versioned_state_for_testing(
64-
block_state: CachedState<DictStateReader>,
65-
) -> ThreadSafeVersionedState<CachedState<DictStateReader>> {
65+
block_state: CachedState<DictStateReader, VisitedPcsSet>,
66+
) -> ThreadSafeVersionedState<CachedState<DictStateReader, VisitedPcsSet>> {
6667
ThreadSafeVersionedState::new(VersionedState::new(block_state))
6768
}
6869

6970
// Utils.
7071

7172
// Note: this function does not mutate the state.
72-
pub fn create_fee_transfer_call_info<S: StateReader>(
73-
state: &mut CachedState<S>,
73+
pub fn create_fee_transfer_call_info<S: StateReader, V: VisitedPcs>(
74+
state: &mut CachedState<S, V>,
7475
account_tx: &AccountTransaction,
7576
concurrency_mode: bool,
7677
) -> CallInfo {
7778
let block_context = BlockContext::create_for_account_testing();
78-
let mut transactional_state = TransactionalState::create_transactional(state);
79+
let mut transactional_state: TransactionalState<'_, _, V> =
80+
TransactionalState::create_transactional(state);
7981
let execution_flags = ExecutionFlags { charge_fee: true, validate: true, concurrency_mode };
8082
let execution_info =
8183
account_tx.execute_raw(&mut transactional_state, &block_context, execution_flags).unwrap();

crates/blockifier/src/concurrency/versioned_state.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::marker::PhantomData;
12
use std::sync::{Arc, Mutex, MutexGuard};
23

34
use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce};
@@ -7,9 +8,10 @@ use starknet_types_core::felt::Felt;
78
use crate::concurrency::versioned_storage::VersionedStorage;
89
use crate::concurrency::TxIndex;
910
use crate::execution::contract_class::ContractClass;
10-
use crate::state::cached_state::{ContractClassMapping, StateMaps, VisitedPcs};
11+
use crate::state::cached_state::{ContractClassMapping, StateMaps};
1112
use crate::state::errors::StateError;
1213
use crate::state::state_api::{StateReader, StateResult, UpdatableState};
14+
use crate::state::visited_pcs::VisitedPcs;
1315

1416
#[cfg(test)]
1517
#[path = "versioned_state_test.rs"]
@@ -197,11 +199,11 @@ impl<S: StateReader> VersionedState<S> {
197199
}
198200
}
199201

200-
impl<U: UpdatableState> VersionedState<U> {
202+
impl<V: VisitedPcs, U: UpdatableState<T = V>> VersionedState<U> {
201203
pub fn commit_chunk_and_recover_block_state(
202204
mut self,
203205
n_committed_txs: usize,
204-
visited_pcs: VisitedPcs,
206+
visited_pcs: V,
205207
) -> U {
206208
if n_committed_txs == 0 {
207209
return self.into_initial_state();
@@ -228,8 +230,8 @@ impl<S: StateReader> ThreadSafeVersionedState<S> {
228230
ThreadSafeVersionedState(Arc::new(Mutex::new(versioned_state)))
229231
}
230232

231-
pub fn pin_version(&self, tx_index: TxIndex) -> VersionedStateProxy<S> {
232-
VersionedStateProxy { tx_index, state: self.0.clone() }
233+
pub fn pin_version<V: VisitedPcs>(&self, tx_index: TxIndex) -> VersionedStateProxy<S, V> {
234+
VersionedStateProxy { tx_index, state: self.0.clone(), _marker: PhantomData }
233235
}
234236

235237
pub fn into_inner_state(self) -> VersionedState<S> {
@@ -251,12 +253,13 @@ impl<S: StateReader> Clone for ThreadSafeVersionedState<S> {
251253
}
252254
}
253255

254-
pub struct VersionedStateProxy<S: StateReader> {
256+
pub struct VersionedStateProxy<S: StateReader, V: VisitedPcs> {
255257
pub tx_index: TxIndex,
256258
pub state: Arc<Mutex<VersionedState<S>>>,
259+
_marker: PhantomData<V>,
257260
}
258261

259-
impl<S: StateReader> VersionedStateProxy<S> {
262+
impl<S: StateReader, V: VisitedPcs> VersionedStateProxy<S, V> {
260263
fn state(&self) -> LockedVersionedState<'_, S> {
261264
self.state.lock().expect("Failed to acquire state lock.")
262265
}
@@ -271,18 +274,20 @@ impl<S: StateReader> VersionedStateProxy<S> {
271274
}
272275

273276
// TODO(Noa, 15/5/24): Consider using visited_pcs.
274-
impl<S: StateReader> UpdatableState for VersionedStateProxy<S> {
277+
impl<V: VisitedPcs, S: StateReader> UpdatableState for VersionedStateProxy<S, V> {
278+
type T = V;
279+
275280
fn apply_writes(
276281
&mut self,
277282
writes: &StateMaps,
278283
class_hash_to_class: &ContractClassMapping,
279-
_visited_pcs: &VisitedPcs,
284+
_visited_pcs: &V,
280285
) {
281286
self.state().apply_writes(self.tx_index, writes, class_hash_to_class)
282287
}
283288
}
284289

285-
impl<S: StateReader> StateReader for VersionedStateProxy<S> {
290+
impl<V: VisitedPcs, S: StateReader> StateReader for VersionedStateProxy<S, V> {
286291
fn get_storage_at(
287292
&self,
288293
contract_address: ContractAddress,

0 commit comments

Comments
 (0)