Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pending): pending block sealed instead of re-added to mempool #468

Merged
merged 8 commits into from
Jan 22, 2025
Merged
1,070 changes: 1,045 additions & 25 deletions crates/madara/client/block_production/src/lib.rs

Large diffs are not rendered by default.

This file was deleted.

6 changes: 6 additions & 0 deletions crates/madara/client/db/src/block_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ impl MadaraBackend {
Ok(res)
}

#[tracing::instrument(skip(self), fields(module = "BlockDB"))]
pub fn has_pending_block(&self) -> Result<bool> {
let col = self.db.get_column(Column::BlockStorageMeta);
Ok(self.db.get_cf(&col, ROW_PENDING_STATE_UPDATE)?.is_some())
}

#[tracing::instrument(skip(self), fields(module = "BlockDB"))]
pub fn get_pending_block_state_update(&self) -> Result<StateDiff> {
let col = self.db.get_column(Column::BlockStorageMeta);
Expand Down
4 changes: 0 additions & 4 deletions crates/madara/client/db/src/storage_updates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,9 @@ impl MadaraBackend {
};

let task_contract_db = || {
// let nonces_from_deployed =
// state_diff.deployed_contracts.iter().map(|&DeployedContractItem { address, .. }| (address, Felt::ZERO));

let nonces_from_updates =
state_diff.nonces.into_iter().map(|NonceUpdate { contract_address, nonce }| (contract_address, nonce));

// let nonce_map: HashMap<Felt, Felt> = nonces_from_deployed.chain(nonces_from_updates).collect(); // set nonce to zero when contract deployed
let nonce_map: HashMap<Felt, Felt> = nonces_from_updates.collect();

let contract_class_updates_replaced = state_diff
Expand Down
22 changes: 12 additions & 10 deletions crates/madara/client/devnet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,9 @@ mod tests {
let importer = Arc::new(BlockImporter::new(Arc::clone(&backend), None).unwrap());

tracing::debug!("{:?}", block.state_diff);
tokio::runtime::Runtime::new()
.unwrap()
let runtime = tokio::runtime::Runtime::new().unwrap();

runtime
.block_on(
importer.add_block(
block,
Expand All @@ -335,14 +336,15 @@ mod tests {
let mempool = Arc::new(Mempool::new(Arc::clone(&backend), Arc::clone(&l1_data_provider), mempool_limits));
let metrics = BlockProductionMetrics::register();

let block_production = BlockProductionTask::new(
Arc::clone(&backend),
Arc::clone(&importer),
Arc::clone(&mempool),
Arc::new(metrics),
Arc::clone(&l1_data_provider),
)
.unwrap();
let block_production = runtime
.block_on(BlockProductionTask::new(
Arc::clone(&backend),
Arc::clone(&importer),
Arc::clone(&mempool),
Arc::new(metrics),
Arc::clone(&l1_data_provider),
))
.unwrap();

DevnetForTesting { backend, contracts, block_production, mempool }
}
Expand Down
17 changes: 0 additions & 17 deletions crates/madara/client/mempool/src/inner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,23 +767,6 @@ impl MempoolInner {
}
}

// This is called by the block production when loading the pending block
// from db
pub fn insert_txs(
&mut self,
txs: impl IntoIterator<Item = MempoolTransaction>,
force: bool,
) -> Result<(), TxInsertionError> {
for tx in txs {
// Transactions are marked as ready as they were already included
// into the pending block
let nonce = tx.nonce;
let nonce_next = tx.nonce_next;
self.insert_tx(tx, force, true, NonceInfo::ready(nonce, nonce_next))?;
}
Ok(())
}

/// Returns true if [MempoolInner] has the transaction at a contract address
/// and [Nonce] in the ready queue.
pub fn nonce_is_ready(&self, sender_address: Felt, nonce: Nonce) -> bool {
Expand Down
37 changes: 2 additions & 35 deletions crates/madara/client/mempool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ pub trait MempoolProvider: Send + Sync {
txs: VecDeque<MempoolTransaction>,
consumed_txs: Vec<MempoolTransaction>,
) -> Result<(), MempoolError>;
fn txs_insert_no_validation(&self, txs: Vec<MempoolTransaction>, force: bool) -> Result<(), MempoolError>
where
Self: Sized;
fn chain_id(&self) -> Felt;
}

Expand Down Expand Up @@ -154,7 +151,8 @@ impl Mempool {
let pending_block_info = if let Some(block) = self.backend.get_block_info(&DbBlockId::Pending)? {
block
} else {
// No current pending block, we'll make an unsaved empty one for the sake of validating this tx.
// No current pending block, we'll make an unsaved empty one for
// the sake of validating this tx.
let parent_block_hash = self
.backend
.get_block_hash(&BlockId::Tag(BlockTag::Latest))?
Expand Down Expand Up @@ -486,37 +484,6 @@ impl MempoolProvider for Mempool {
Ok(())
}

/// This is called by the block production task to re-add transaction from
/// the pending block back into the mempool
#[tracing::instrument(skip(self, txs), fields(module = "Mempool"))]
fn txs_insert_no_validation(&self, txs: Vec<MempoolTransaction>, force: bool) -> Result<(), MempoolError> {
let mut nonce_cache = self.nonce_cache.write().expect("Poisoned lock");

for tx in &txs {
// Theoretically we should not have to invalidate the nonce cache
// here as this function should ONLY be called when adding the
// pending block back into the mempool from the db. However I am
// afraid someone will end up using this incorrectly so I am adding
// this here.
nonce_cache.remove(&tx.contract_address());

// Save to db. Transactions are marked as ready since they were
// already previously included into the pending block
let nonce_info = NonceInfo::ready(tx.nonce, tx.nonce_next);
let saved_tx = blockifier_to_saved_tx(&tx.tx, tx.arrived_at);
self.backend.save_mempool_transaction(
&saved_tx,
tx.tx_hash().to_felt(),
&tx.converted_class,
&nonce_info,
)?;
}

let mut inner = self.inner.write().expect("Poisoned lock");
inner.insert_txs(txs, force)?;

Ok(())
}
fn chain_id(&self) -> Felt {
Felt::from_bytes_be_slice(format!("{}", self.backend.chain_config().chain_id).as_bytes())
}
Expand Down
3 changes: 2 additions & 1 deletion crates/madara/node/src/service/block_production.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ impl Service for BlockProductionService {
Arc::clone(mempool),
Arc::clone(metrics),
Arc::clone(l1_data_provider),
)?;
)
.await?;

runner.service_loop(move |ctx| block_production_task.block_production_task(ctx));

Expand Down
2 changes: 1 addition & 1 deletion crates/madara/primitives/block/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ impl From<MadaraBlock> for MadaraMaybePendingBlock {

/// Visited segments are the class segments that are visited during the execution of the block.
/// This info is an input of SNOS and used for proving.
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Default, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct VisitedSegments(pub Vec<VisitedSegmentEntry>);

#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
Expand Down
78 changes: 0 additions & 78 deletions crates/madara/tests/src/devnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,81 +159,3 @@ async fn madara_devnet_mempool_saving() {
)
.await;
}

#[rstest]
#[tokio::test]
async fn madara_devnet_continue_pending() {
let _ = tracing_subscriber::fmt().with_test_writer().try_init();

let cmd_builder = MadaraCmdBuilder::new().args([
"--devnet",
"--no-l1-sync",
"--gas-price",
"0",
// never produce blocks but produce pending txs
"--chain-config-path",
"test_devnet.yaml",
"--chain-config-override",
"block_time=5min,pending_block_update_time=500ms",
]);
let mut node = cmd_builder.clone().run();
node.wait_for_ready().await;

let chain_id = node.json_rpc().chain_id().await.unwrap();

let signer = LocalWallet::from_signing_key(SigningKey::from_secret_scalar(ACCOUNT_SECRET));
let mut account =
SingleOwnerAccount::new(node.json_rpc(), signer, ACCOUNT_ADDRESS, chain_id, ExecutionEncoding::New);
account.set_block_id(BlockId::Tag(BlockTag::Pending));

let res = account
.execute_v3(vec![Call {
to: ERC20_STRK_CONTRACT_ADDRESS,
selector: starknet_keccak(b"transfer"),
calldata: vec![ACCOUNT_ADDRESS, 15.into(), Felt::ZERO],
}])
.send()
.await
.unwrap();

wait_for_cond(
|| async {
let receipt = node.json_rpc().get_transaction_receipt(res.transaction_hash).await?;
assert_eq!(receipt.block, ReceiptBlock::Pending);
Ok(())
},
Duration::from_millis(500),
60,
)
.await;

drop(node);

// tx should appear in saved pending block

let cmd_builder = cmd_builder.args([
"--devnet",
"--no-l1-sync",
"--gas-price",
"0",
// never produce blocks but produce pending txs
"--chain-config-path",
"test_devnet.yaml",
"--chain-config-override",
"block_time=5min,pending_block_update_time=500ms",
]);
let mut node = cmd_builder.clone().run();
node.wait_for_ready().await;

// should find receipt
wait_for_cond(
|| async {
let receipt = node.json_rpc().get_transaction_receipt(res.transaction_hash).await?;
assert_eq!(receipt.block, ReceiptBlock::Pending);
Ok(())
},
Duration::from_millis(500),
60,
)
.await;
}
Loading