Skip to content

Commit

Permalink
feat: adding block_builder object (starkware-libs#745)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yael-Starkware authored Oct 7, 2024
1 parent f48f5d4 commit 7df7a30
Show file tree
Hide file tree
Showing 13 changed files with 1,391 additions and 966 deletions.
1,865 changes: 960 additions & 905 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions crates/batcher/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ workspace = true

[dependencies]
async-trait.workspace = true
blockifier.workspace = true
chrono.workspace = true
indexmap.workspace = true
papyrus_config.workspace = true
papyrus_storage.workspace = true
serde.workspace = true
starknet-types-core.workspace = true
starknet_api.workspace = true
starknet_batcher_types.workspace = true
starknet_mempool_infra.workspace = true
Expand Down
29 changes: 26 additions & 3 deletions crates/batcher/src/batcher.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use std::sync::Arc;

use blockifier::blockifier::block::BlockNumberHashPair;
#[cfg(test)]
use mockall::automock;
use starknet_api::block::BlockNumber;
use starknet_batcher_types::batcher_types::BuildProposalInput;
use starknet_batcher_types::errors::BatcherError;
use starknet_mempool_infra::component_definitions::ComponentStarter;
use starknet_mempool_types::communication::SharedMempoolClient;

use crate::block_builder::{BlockBuilderFactoryTrait, BlockBuilderResult, BlockBuilderTrait};
use crate::config::BatcherConfig;
use crate::proposal_manager::{BlockBuilderFactory, ProposalManager, ProposalManagerError};
use crate::proposal_manager::{ProposalManager, ProposalManagerError};

pub struct Batcher {
pub config: BatcherConfig,
Expand All @@ -17,6 +20,19 @@ pub struct Batcher {
proposal_manager: ProposalManager,
}

// TODO(Yael 7/10/2024): remove DummyBlockBuilderFactory and pass the real BlockBuilderFactory
struct DummyBlockBuilderFactory {}

impl BlockBuilderFactoryTrait for DummyBlockBuilderFactory {
fn create_block_builder(
&self,
_height: BlockNumber,
_retrospective_block_hash: Option<BlockNumberHashPair>,
) -> BlockBuilderResult<Box<dyn BlockBuilderTrait>> {
todo!()
}
}

impl Batcher {
pub fn new(
config: BatcherConfig,
Expand All @@ -30,7 +46,8 @@ impl Batcher {
proposal_manager: ProposalManager::new(
config.proposal_manager.clone(),
mempool_client.clone(),
Arc::new(BlockBuilderFactory {}),
// TODO(Yael 7/10/2024) : Pass the real BlockBuilderFactory
Arc::new(DummyBlockBuilderFactory {}),
),
}
}
Expand All @@ -47,7 +64,12 @@ impl Batcher {
|_| BatcherError::TimeToDeadlineError { deadline: build_proposal_input.deadline },
)?);
self.proposal_manager
.build_block_proposal(build_proposal_input.proposal_id, deadline, content_sender)
.build_block_proposal(
build_proposal_input.proposal_id,
build_proposal_input.retrospective_block_hash,
deadline,
content_sender,
)
.await
.map_err(|err| match err {
ProposalManagerError::AlreadyGeneratingProposal {
Expand All @@ -57,6 +79,7 @@ impl Batcher {
active_proposal_id: current_generating_proposal_id,
new_proposal_id,
},
ProposalManagerError::BlockBuilderError(..) => BatcherError::InternalError,
ProposalManagerError::MempoolError(..) => BatcherError::InternalError,
ProposalManagerError::ProposalAlreadyExists { proposal_id } => {
BatcherError::ProposalAlreadyExists { proposal_id }
Expand Down
203 changes: 203 additions & 0 deletions crates/batcher/src/block_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
use std::num::NonZeroU128;

use async_trait::async_trait;
use blockifier::blockifier::block::{BlockInfo, BlockNumberHashPair, GasPrices};
use blockifier::blockifier::config::TransactionExecutorConfig;
use blockifier::blockifier::transaction_executor::{
TransactionExecutor,
TransactionExecutorResult,
VisitedSegmentsMapping,
};
use blockifier::bouncer::{BouncerConfig, BouncerWeights};
use blockifier::context::{BlockContext, ChainInfo};
use blockifier::state::cached_state::CommitmentStateDiff;
use blockifier::state::errors::StateError;
use blockifier::state::global_cache::GlobalContractCache;
use blockifier::state::state_api::StateReader;
use blockifier::transaction::objects::TransactionExecutionInfo;
use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction;
use blockifier::versioned_constants::{VersionedConstants, VersionedConstantsOverrides};
use indexmap::IndexMap;
#[cfg(test)]
use mockall::automock;
use papyrus_storage::StorageReader;
use starknet_api::block::{BlockNumber, BlockTimestamp};
use starknet_api::core::ContractAddress;
use starknet_api::executable_transaction::Transaction;
use starknet_api::transaction::TransactionHash;
use thiserror::Error;
use tokio::sync::Mutex;

use crate::papyrus_state::PapyrusReader;
use crate::proposal_manager::InputTxStream;

pub struct BlockBuilder {
_executor: Mutex<Box<dyn TransactionExecutorTrait>>,
_tx_chunk_size: usize,
}

#[derive(Debug, Error)]
pub enum BlockBuilderError {
#[error(transparent)]
BadTimestamp(#[from] std::num::TryFromIntError),
#[error(transparent)]
BlockifierStateError(#[from] StateError),
}

pub type BlockBuilderResult<T> = Result<T, BlockBuilderError>;

#[derive(Clone)]
pub struct ExecutionConfig {
// TODO(Yael 1/10/2024): add to config pointers
pub chain_info: ChainInfo,
pub execute_config: TransactionExecutorConfig,
pub bouncer_config: BouncerConfig,
pub sequencer_address: ContractAddress,
pub use_kzg_da: bool,
pub tx_chunk_size: usize,
pub versioned_constants_overrides: VersionedConstantsOverrides,
}

#[async_trait]
impl BlockBuilderTrait for BlockBuilder {
async fn build_block(
&mut self,
_deadline: tokio::time::Instant,
_mempool_tx_stream: InputTxStream,
_output_content_sender: tokio::sync::mpsc::Sender<Transaction>,
) -> BlockBuilderResult<BlockExecutionArtifacts> {
todo!();
}
}

#[derive(Default, Debug, PartialEq)]
pub struct BlockExecutionArtifacts {
pub execution_infos: IndexMap<TransactionHash, TransactionExecutionInfo>,
pub commitment_state_diff: CommitmentStateDiff,
pub visited_segments_mapping: VisitedSegmentsMapping,
pub bouncer_weights: BouncerWeights,
}

/// The BlockBuilderTrait is responsible for building a new block from transactions provided in
/// tx_stream. The block building will stop at time deadline.
/// The transactions that were added to the block will be streamed to the output_content_sender.
#[cfg_attr(test, automock)]
#[async_trait]
pub trait BlockBuilderTrait: Send {
async fn build_block(
&mut self,
deadline: tokio::time::Instant,
tx_stream: InputTxStream,
output_content_sender: tokio::sync::mpsc::Sender<Transaction>,
) -> BlockBuilderResult<BlockExecutionArtifacts>;
}

/// The BlockBuilderFactoryTrait is responsible for creating a new block builder.
#[cfg_attr(test, automock)]
pub trait BlockBuilderFactoryTrait {
fn create_block_builder(
&self,
height: BlockNumber,
retrospective_block_hash: Option<BlockNumberHashPair>,
) -> BlockBuilderResult<Box<dyn BlockBuilderTrait>>;
}

pub struct BlockBuilderFactory {
pub execution_config: ExecutionConfig,
pub storage_reader: StorageReader,
pub global_class_hash_to_class: GlobalContractCache,
}

impl BlockBuilderFactory {
fn preprocess_and_create_transaction_executor(
&self,
height: BlockNumber,
retrospective_block_hash: Option<BlockNumberHashPair>,
) -> BlockBuilderResult<TransactionExecutor<PapyrusReader>> {
let execution_config = self.execution_config.clone();
let next_block_info = BlockInfo {
block_number: height,
block_timestamp: BlockTimestamp(chrono::Utc::now().timestamp().try_into()?),
sequencer_address: execution_config.sequencer_address,
// TODO (yael 7/10/2024): add logic to compute gas prices
gas_prices: {
let tmp_val = NonZeroU128::new(1).unwrap();
GasPrices::new(tmp_val, tmp_val, tmp_val, tmp_val, tmp_val, tmp_val)
},
use_kzg_da: execution_config.use_kzg_da,
};
let block_context = BlockContext::new(
next_block_info,
execution_config.chain_info,
VersionedConstants::get_versioned_constants(
execution_config.versioned_constants_overrides,
),
execution_config.bouncer_config,
);

// TODO(Yael: 8/9/2024) Need to reconsider which StateReader to use. the papyrus execution
// state reader does not implement the Sync trait since it is using cell so I used
// the blockifier state reader instead. Also the blockifier reader is implementing a global
// cache.
let state_reader = PapyrusReader::new(
self.storage_reader.clone(),
height,
// TODO(Yael 18/9/2024): dont forget to flush the cached_state cache into the global
// cache on decision_reached.
self.global_class_hash_to_class.clone(),
);

let executor = TransactionExecutor::pre_process_and_create(
state_reader,
block_context,
retrospective_block_hash,
execution_config.execute_config,
)?;

Ok(executor)
}
}

impl BlockBuilderFactoryTrait for BlockBuilderFactory {
fn create_block_builder(
&self,
height: BlockNumber,
retrospective_block_hash: Option<BlockNumberHashPair>,
) -> BlockBuilderResult<Box<dyn BlockBuilderTrait>> {
let executor =
self.preprocess_and_create_transaction_executor(height, retrospective_block_hash)?;
Ok(Box::new(BlockBuilder {
_executor: Mutex::new(Box::new(executor)),
_tx_chunk_size: self.execution_config.tx_chunk_size,
}))
}
}

#[cfg_attr(test, automock)]
pub trait TransactionExecutorTrait: Send {
fn add_txs_to_block(
&mut self,
txs: &[BlockifierTransaction],
) -> Vec<TransactionExecutorResult<TransactionExecutionInfo>>;
fn close_block(
&mut self,
) -> TransactionExecutorResult<(CommitmentStateDiff, VisitedSegmentsMapping, BouncerWeights)>;
}

impl<S: StateReader + Send + Sync> TransactionExecutorTrait for TransactionExecutor<S> {
/// Adds the transactions to the generated block and returns the execution results.
fn add_txs_to_block(
&mut self,
txs: &[BlockifierTransaction],
) -> Vec<TransactionExecutorResult<TransactionExecutionInfo>> {
self.execute_txs(txs)
}
/// Finalizes the block creation and returns the commitment state diff, visited
/// segments mapping and bouncer.
fn close_block(
&mut self,
) -> TransactionExecutorResult<(CommitmentStateDiff, VisitedSegmentsMapping, BouncerWeights)>
{
self.finalize()
}
}
2 changes: 2 additions & 0 deletions crates/batcher/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub mod batcher;
pub mod block_builder;
pub mod communication;
pub mod config;
pub mod fee_market;
pub mod papyrus_state;
mod proposal_manager;
#[cfg(test)]
mod proposal_manager_test;
Loading

0 comments on commit 7df7a30

Please sign in to comment.