-
Notifications
You must be signed in to change notification settings - Fork 162
fix(l1): only rebuild payload when mempool receives new transactions #6165
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
base: main
Are you sure you want to change the base?
Conversation
new transactions instead of rebuilding continuously. Each rebuild is CPU-intensive (EVM execution, trie operations) and contends with RPC handlers over the shared trie_cache mutex, starving the RPC server. Mempool::add_transaction() now calls notify_one() after inserting a tx. build_payload_loop uses tokio::select! to wait for either a mempool notification or cancel_token cancellation before each rebuild. The first build_payload call remains unconditional.
🤖 Kimi Code ReviewSecurity & Correctness IssuesFile:
Performance & Correctness IssuesFile:
File:
Suggested Fixes
// Before the while loop, check if we should wait
if res.transactions.is_empty() {
tokio::select! {
_ = self.mempool.tx_added().notified() => {}
_ = cancel_token.cancelled() => return Ok(res),
}
}
while start.elapsed() < SECONDS_PER_SLOT && !cancel_token.is_cancelled() {
// Check for new transactions or cancellation
tokio::select! {
_ = self.mempool.tx_added().notified() => {}
_ = cancel_token.cancelled() => return Ok(res),
}
if cancel_token.is_cancelled() {
return Ok(res);
}
// ... rest of the logic
}
Automated review by Kimi (Moonshot AI) · custom prompt |
🤖 Codex Code ReviewFindings
Notes
If you want, I can sketch a minimal patch for the timeout/remaining-slot handling in Automated review by OpenAI Codex · custom prompt |
🤖 Claude Code ReviewPerfect! Now I have a complete understanding of the PR. Let me compile my review: Code Review - PR #6165: perf(l1): only rebuild payload when mempool receives new transactionsSummaryThis PR adds a ✅ Strengths
🔍 Observations & Potential Issues1. Race condition potential (Low severity)Location: mempool.rs:129-134 and payload.rs:394-395 There's a subtle timing window: if However, 2. Missing notification on transaction removal (Low severity)Location: mempool.rs:178-182 The Recommendation: No action needed unless there's a use case for rebuilding when transactions are removed. 3. Cargo.toml feature additionsLocation: crates/blockchain/Cargo.toml:25 -tokio = { workspace = true, features = ["time", "rt"] }
+tokio = { workspace = true, features = ["time", "rt", "sync", "macros"] }
Action: Verify that 4. Potential starvation scenario (Low-Medium severity)Location: payload.rs:392-415 If transactions arrive continuously at a high rate, the build loop might rebuild frequently, potentially never reaching the optimal state. Each Scenario:
The current implementation handles this correctly: No action needed, but the PR description correctly notes this: "if multiple txs arrive during a build, the next 5. Error path analysisLocation: mempool.rs:109-137 If ✅ Correct as-is 🔒 Security & Consensus Implications
🎯 Rust Best Practices
📋 Minor SuggestionsDocumentation EnhancementAdd a brief comment explaining the notification behavior: // Drop the write lock before notifying to avoid holding it while waking waiters
drop(inner);
// notify_one() stores a permit; if multiple txs arrive during a build,
// the next notified().await resolves immediately to batch them
self.tx_added.notify_one();Testing ConsiderationConsider adding an integration test that verifies:
✅ VerdictAPPROVE - This is a well-implemented performance optimization that addresses a real issue. The code is correct, follows Rust best practices, and doesn't introduce security concerns. Minor action items:
The implementation correctly handles the tricky aspects of Automated review by Claude (Anthropic) · custom prompt |
Lines of code reportTotal lines added: Detailed view |
Mempool, polled by the payload build loop with a 100ms sleep interval. This avoids adding new tokio features (sync, macros) while still skipping rebuilds when no new transactions have arrived.
iteration always triggers a rebuild without sleeping, picking up any transactions that arrived during the initial build_payload call.
Benchmark Block Execution Results Comparison Against Main
|
Motivation
The block building loop (
build_payload_loop) continuously rebuilds the block for 12 seconds (one slot), even when no new transactions have arrived. Each rebuild is CPU-intensive (EVM execution, trie operations) and contends with RPC handlers over the sharedtrie_cachemutex, starving the RPC server.Description
Add an
AtomicU64generation counter toMempoolthat increments on every transaction insertion. The payload build loop polls this counter with a 100ms sleep interval and only rebuilds when it detects a change, instead of looping as fast as possible.Mempool::add_transaction()increments the generation counter after inserting a txbuild_payload_loopcompares the current generation to the one from the last build; if unchanged, sleeps 100ms and rechecksbuild_payloadcall remains unconditional — we always build one payload immediately when FCU arrivesstd::sync::atomicand the already-enabledtokio::timeChecklist
STORE_SCHEMA_VERSION(crates/storage/lib.rs) if the PR includes breaking changes to theStorerequiring a re-sync.