Skip to main content

cast/cmd/
da_estimate.rs

1//! Estimates the data availability size of a block for opstack.
2
3use alloy_consensus::BlockHeader;
4use alloy_network::{AnyNetwork, BlockResponse, Ethereum, Network, eip2718::Encodable2718};
5use alloy_provider::Provider;
6use alloy_rpc_types::BlockId;
7use clap::Parser;
8use eyre::Result;
9use foundry_cli::{opts::RpcOpts, utils::LoadConfig};
10use foundry_common::provider::ProviderBuilder;
11use foundry_config::Config;
12use foundry_evm_networks::NetworkVariant;
13use op_alloy_network::Optimism;
14
15/// CLI arguments for `cast da-estimate`.
16#[derive(Debug, Parser)]
17pub struct DAEstimateArgs {
18    /// The block to estimate the data availability size for.
19    pub block: BlockId,
20    #[command(flatten)]
21    pub rpc: RpcOpts,
22    /// Specify the Network for correct encoding.
23    #[arg(long, short, num_args = 1, value_name = "NETWORK")]
24    network: Option<NetworkVariant>,
25}
26
27impl DAEstimateArgs {
28    /// Load the RPC URL from the config file.
29    pub async fn run(self) -> Result<()> {
30        let Self { block, rpc, network } = self;
31        let config = rpc.load_config()?;
32        let network = match network {
33            Some(n) => n,
34            None => {
35                let provider = ProviderBuilder::<AnyNetwork>::from_config(&config)?.build()?;
36                provider.get_chain_id().await?.into()
37            }
38        };
39        match network {
40            NetworkVariant::Optimism => da_estimate::<Optimism>(&config, block).await,
41            NetworkVariant::Ethereum => da_estimate::<Ethereum>(&config, block).await,
42            #[cfg(feature = "monad")]
43            NetworkVariant::Monad => unsupported_da_estimation("Monad"),
44            NetworkVariant::Tempo => unsupported_da_estimation("Tempo"),
45        }
46    }
47}
48
49fn unsupported_da_estimation(network: &str) -> Result<()> {
50    Err(eyre::eyre!(
51        "DA estimation is not supported for {network}: EIP-4844 blob transactions are not available on this network"
52    ))
53}
54
55pub async fn da_estimate<N: Network>(config: &Config, block_id: BlockId) -> Result<()> {
56    let provider = ProviderBuilder::<N>::from_config(config)?.build()?;
57    let block =
58        provider.get_block(block_id).full().await?.ok_or_else(|| eyre::eyre!("Block not found"))?;
59
60    let block_number = block.header().number();
61    let tx_count = block.transactions().len();
62    let mut da_estimate = 0;
63    for tx in block.transactions().txns() {
64        da_estimate += op_alloy_flz::tx_estimated_size_fjord(&tx.as_ref().encoded_2718());
65    }
66    sh_status!(
67        "Estimated data availability size for block {block_number} with {tx_count} transactions:"
68    )?;
69    sh_println!("{da_estimate}")?;
70    Ok(())
71}
72
73#[cfg(all(test, feature = "monad"))]
74mod tests {
75    use super::*;
76
77    #[tokio::test]
78    #[cfg(feature = "monad")]
79    async fn monad_da_estimate_is_unsupported() {
80        let args = DAEstimateArgs {
81            block: BlockId::latest(),
82            rpc: RpcOpts::default(),
83            network: Some(NetworkVariant::Monad),
84        };
85
86        let err = args.run().await.unwrap_err().to_string();
87        assert!(err.contains("Monad"), "{err}");
88        assert!(err.contains("EIP-4844"), "{err}");
89    }
90}