Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
refactor(execution): bouncer update function
Browse files Browse the repository at this point in the history
  • Loading branch information
Yael-Starkware committed Mar 12, 2024
1 parent 2669e02 commit 9d036f9
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 15 deletions.
99 changes: 88 additions & 11 deletions crates/blockifier/src/bouncer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::execution::call_info::{CallInfo, MessageL1CostInfo};
use crate::fee::gas_usage::{get_messages_gas_usage, get_onchain_data_segment_length};
use crate::state::cached_state::{StateChangesKeys, StorageEntry, TransactionalState};
use crate::state::state_api::StateReader;
use crate::transaction::errors::TransactionExecutionError;
use crate::transaction::objects::TransactionExecutionInfo;
use crate::utils::usize_from_u128;

Expand All @@ -37,6 +38,11 @@ macro_rules! impl_checked_sub {

pub type HashMapWrapper = HashMap<String, usize>;

pub struct BouncerConfig {
pub block_max_capacity: BouncerWeights,
pub block_max_capacity_with_keccak: BouncerWeights,
}

#[derive(
Clone, Copy, Debug, Default, derive_more::Add, derive_more::Sub, Deserialize, PartialEq,
)]
Expand Down Expand Up @@ -127,17 +133,19 @@ pub struct Bouncer {
pub executed_class_hashes: HashSet<ClassHash>,
pub visited_storage_entries: HashSet<StorageEntry>,
pub state_changes_keys: StateChangesKeys,
pub block_contains_keccak: bool,
// The capacity is calculated based of the values of the other Bouncer fields.
capacity: BouncerWeights,
available_capacity: BouncerWeights,
}

impl Bouncer {
pub fn new(capacity: BouncerWeights) -> Self {
pub fn new(capacity: BouncerWeights, block_contains_keccak: bool) -> Self {
Bouncer {
executed_class_hashes: HashSet::new(),
state_changes_keys: StateChangesKeys::default(),
visited_storage_entries: HashSet::new(),
capacity,
available_capacity: capacity,
block_contains_keccak,
}
}

Expand All @@ -149,25 +157,94 @@ impl Bouncer {
self.executed_class_hashes.extend(other.executed_class_hashes);
self.state_changes_keys.extend(&other.state_changes_keys);
self.visited_storage_entries.extend(other.visited_storage_entries);
self.capacity = other.capacity;
self.block_contains_keccak = other.block_contains_keccak;
self.available_capacity = other.available_capacity;
}
}

#[derive(Clone)]
pub struct TransactionalBouncer {
// The bouncer can be modified only through the merge method.
// The block bouncer can be modified only through the merge method.
bouncer: Bouncer,
// The transactional bouncer can be modified only through the update method.
// The transaction bouncer can be modified only through the update method.
transactional: Bouncer,
}

impl TransactionalBouncer {
pub fn new(parent: Bouncer) -> TransactionalBouncer {
let capacity = parent.capacity;
TransactionalBouncer { bouncer: parent, transactional: Bouncer::new(capacity) }
pub fn new(block_bouncer: Bouncer) -> TransactionalBouncer {
let transactional =
Bouncer::new(block_bouncer.available_capacity, block_bouncer.block_contains_keccak);
TransactionalBouncer { bouncer: block_bouncer, transactional }
}

pub fn update<S: StateReader>(
&mut self,
bouncer_config: &BouncerConfig,
state: &mut TransactionalState<'_, S>,
tx_execution_info: &TransactionExecutionInfo,
l1_handler_payload_size: Option<usize>,
) -> TransactionExecutorResult<()> {
self.update_auxiliary_info(state, tx_execution_info)?;
self.update_capacity(bouncer_config, state, tx_execution_info, l1_handler_payload_size)?;

Ok(())
}

fn update_capacity<S: StateReader>(
&mut self,
bouncer_config: &BouncerConfig,
state: &mut TransactionalState<'_, S>,
tx_execution_info: &TransactionExecutionInfo,
l1_handler_payload_size: Option<usize>,
) -> TransactionExecutorResult<()> {
let tx_weights = self.get_tx_weights(state, tx_execution_info, l1_handler_payload_size)?;

if !self.transactional.block_contains_keccak && tx_weights.builtin_count.keccak > 0 {
self.update_available_capacity_with_keccak(bouncer_config)?;
}

// Check if the transaction is too large to fit any block.
let mut max_capacity = bouncer_config.block_max_capacity;
if self.transactional.block_contains_keccak {
max_capacity = bouncer_config.block_max_capacity_with_keccak;
}
max_capacity.checked_sub(tx_weights).ok_or(TransactionExecutionError::TxTooLarge)?;

// Check if the transaction can fit the current block available capacity.
self.transactional.available_capacity = self
.transactional
.available_capacity
.checked_sub(tx_weights)
.ok_or(TransactionExecutionError::BlockFull)?;
Ok(())
}

// TODO update function (in the next PRs)
fn update_available_capacity_with_keccak(
&mut self,
bouncer_config: &BouncerConfig,
) -> TransactionExecutorResult<()> {
// First zero the keccak capacity to be able to subtract the max_capacity_with_keccak from
// max_capacity (that is without keccak).
let mut max_capacity_with_keccak_tmp = bouncer_config.block_max_capacity_with_keccak;
max_capacity_with_keccak_tmp.builtin_count.keccak = 0;
// compute the diff between the max_capacity and the max_capacity_with_keccak.
let max_capacity_with_keccak_diff = bouncer_config
.block_max_capacity
.checked_sub(max_capacity_with_keccak_tmp)
.expect("max_capacity_with_keccak should be smaller than max_capacity");
// Subtract the diff from the available capacity.
self.transactional.available_capacity = self
.transactional
.available_capacity
.checked_sub(max_capacity_with_keccak_diff)
.ok_or(TransactionExecutionError::BlockFull)?;
// Add back the keccack capacity that was reset at the beggining.
self.transactional.available_capacity.builtin_count.keccak =
bouncer_config.block_max_capacity_with_keccak.builtin_count.keccak;
// Mark this block as contains keccak.
self.transactional.block_contains_keccak = true;
Ok(())
}

pub fn get_tx_weights<S: StateReader>(
&mut self,
Expand Down Expand Up @@ -220,8 +297,8 @@ impl TransactionalBouncer {

pub fn update_auxiliary_info<S: StateReader>(
&mut self,
tx_execution_info: &TransactionExecutionInfo,
state: &mut TransactionalState<'_, S>,
tx_execution_info: &TransactionExecutionInfo,
) -> TransactionExecutorResult<()> {
let tx_execution_summary = tx_execution_info.summarize();
self.transactional.executed_class_hashes.extend(tx_execution_summary.executed_class_hashes);
Expand Down
8 changes: 4 additions & 4 deletions crates/blockifier/src/bouncer_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ fn test_transactional_bouncer() {
state_diff_size: 2,
};

let bouncer = Bouncer::new(initial_bouncer_weights);
let bouncer = Bouncer::new(initial_bouncer_weights, true);
let mut transactional_bouncer = bouncer.create_transactional();
transactional_bouncer.transactional.capacity = weights_to_commit;
transactional_bouncer.transactional.available_capacity = weights_to_commit;

// Test transactional bouncer abort.
let final_weights = transactional_bouncer.clone().abort();
assert!(final_weights.capacity == initial_bouncer_weights);
assert!(final_weights.available_capacity == initial_bouncer_weights);

// Test transactional bouncer commit.
let final_weights = transactional_bouncer.commit();
assert!(final_weights.capacity == weights_to_commit);
assert!(final_weights.available_capacity == weights_to_commit);
}
4 changes: 4 additions & 0 deletions crates/blockifier/src/transaction/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ pub enum TransactionFeeError {

#[derive(Debug, Error)]
pub enum TransactionExecutionError {
#[error("Transaction cannot be added to the current block, block capacity reached.")]
BlockFull,
#[error(
"Declare transaction version {declare_version:?} must have a contract class of Cairo \
version {cairo_version:?}."
Expand Down Expand Up @@ -92,6 +94,8 @@ pub enum TransactionExecutionError {
UnexpectedHoles { object: String, order: usize },
#[error(transparent)]
TryFromIntError(#[from] std::num::TryFromIntError),
#[error("Transaction size exceeds the maximum block capacity.")]
TxTooLarge,
// TODO(Zuphit): add `gen_transaction_execution_error_trace` if needed.
#[error("Transaction validation has failed: {error}")]
ValidateTransactionError { error: EntryPointExecutionError, storage_address: ContractAddress },
Expand Down

0 comments on commit 9d036f9

Please sign in to comment.