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 17, 2024
1 parent 76ecbe7 commit a9602c9
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 16 deletions.
114 changes: 102 additions & 12 deletions crates/blockifier/src/bouncer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use crate::fee::gas_usage::{
};
use crate::state::cached_state::{StateChangesKeys, StorageEntry, TransactionalState};
use crate::state::state_api::StateReader;
use crate::transaction::objects::ResourcesMapping;
use crate::transaction::errors::TransactionExecutionError;
use crate::transaction::objects::{ResourcesMapping, TransactionExecutionInfo};
use crate::utils::usize_from_u128;

#[cfg(test)]
Expand All @@ -38,6 +39,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 @@ -116,17 +122,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 @@ -138,25 +146,107 @@ 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<()> {
let tx_execution_summary = tx_execution_info.summarize();
self.update_auxiliary_info(state, &tx_execution_summary)?;
self.update_capacity(
bouncer_config,
state,
&tx_execution_summary,
&tx_execution_info.bouncer_resources,
l1_handler_payload_size,
)?;

Ok(())
}

fn update_capacity<S: StateReader>(
&mut self,
bouncer_config: &BouncerConfig,
state: &mut TransactionalState<'_, S>,
tx_execution_summary: &ExecutionSummary,
bouncer_resources: &ResourcesMapping,
l1_handler_payload_size: Option<usize>,
) -> TransactionExecutorResult<()> {
let tx_weights = self.get_tx_weights(
state,
tx_execution_summary,
bouncer_resources,
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 @@ -226,8 +316,8 @@ impl TransactionalBouncer {

pub fn update_auxiliary_info<S: StateReader>(
&mut self,
tx_execution_summary: &ExecutionSummary,
state: &mut TransactionalState<'_, S>,
tx_execution_summary: &ExecutionSummary,
) -> TransactionExecutorResult<()> {
self.transactional
.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 @@ -85,6 +87,8 @@ pub enum TransactionExecutionError {
TransactionPreValidationError(#[from] TransactionPreValidationError),
#[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 a9602c9

Please sign in to comment.