pub(crate) async fn persist_block_with_transactions(
    pool: &ConnectionPool<Core>,
    txs: Vec<Transaction>,
) {
    let mut storage = pool.connection().await.unwrap();
    let prev_block = storage
        .blocks_dal()
        .get_last_sealed_l2_block_header()
        .await
        .unwrap()
        .expect("no blocks in storage");
    assert_eq!(prev_block.number, L2BlockNumber(0));
    let block_header = create_l2_block(1);
    let block_number = block_header.number;

    let system_env = default_system_env();
    let mut l1_batch_env = default_l1_batch_env(1, 1, Address::repeat_byte(1));
    l1_batch_env.first_l2_block.prev_block_hash = prev_block.hash;
    l1_batch_env.previous_batch_hash = Some(
        storage
            .blocks_dal()
            .get_l1_batch_state_root(L1BatchNumber(0))
            .await
            .unwrap()
            .expect("no root hash for genesis L1 batch"),
    );

    let executor_storage = PostgresStorage::new_async(
        tokio::runtime::Handle::current(),
        pool.connection().await.unwrap(),
        block_number - 1,
        false,
    )
    .await
    .unwrap();

    let mut batch_executor = MainBatchExecutorFactory::<()>::new(false).init_batch(
        executor_storage,
        l1_batch_env,
        system_env,
        PubdataParams::default(),
    );

    let mut all_events = vec![];
    let mut events_by_transaction = vec![];
    let mut all_logs = vec![];
    let mut all_tx_results = vec![];
    for (i, tx) in txs.into_iter().enumerate() {
        let tx_result = batch_executor
            .execute_tx(tx.clone())
            .await
            .unwrap()
            .tx_result;

        let start_idx = all_events.len();
        all_events.extend(tx_result.logs.events);
        let tx_location = IncludedTxLocation {
            tx_hash: tx.hash(),
            tx_index_in_l2_block: i as u32,
        };
        events_by_transaction.push((tx_location, start_idx..all_events.len()));
        all_logs.extend(tx_result.logs.storage_logs);
        all_tx_results.push(TransactionExecutionResult {
            execution_status: match tx_result.result {
                ExecutionResult::Success { .. } => TxExecutionStatus::Success,
                ExecutionResult::Revert { .. } => TxExecutionStatus::Failure,
                other => panic!("unexpected tx result: {other:?}"),
            },
            ..mock_execute_transaction(tx)
        });
    }

    let events_by_transaction: Vec<_> = events_by_transaction
        .into_iter()
        .map(|(location, range)| (location, all_events[range].iter().collect::<Vec<_>>()))
        .collect();

    storage
        .events_dal()
        .save_events(block_number, &events_by_transaction)
        .await
        .unwrap();
    let deduplicated_logs = StorageWritesDeduplicator::deduplicate_logs(all_logs.iter());
    storage
        .storage_logs_dal()
        .insert_storage_logs(block_number, &deduplicated_logs)
        .await
        .unwrap();
    store_custom_l2_block(&mut storage, &block_header, &all_tx_results)
        .await
        .unwrap();
}
Executes transactions and stores real events and storage logs.
core/node/api_server/src/testonly.rs