[consensus/marshal] Expand Digest Fetching#3722
Conversation
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
commonware-mcp | 1a93809 | May 15 2026, 07:06 AM |
| } | ||
|
|
||
| /// Enqueue a resolver fetch for a block commitment. | ||
| async fn enqueue_block_fetch( |
There was a problem hiding this comment.
remove this thin wrapper
| .fetch(ResolverKey::request(Request::Notarized { round })) | ||
| .await; | ||
| } else if let (Some(height), BlockSubscriptionKey::Commitment(commitment)) = (height, key) { | ||
| if height <= self.last_processed_height { |
There was a problem hiding this comment.
May need this to verify block (read parent)?
| metadata: Metadata<R, u8, (Epoch, Epoch)>, | ||
|
|
||
| /// Blocks fetched by digest during ancestry verification, indexed by height. | ||
| digest_blocks: prunable::Archive<TwoCap, R, <V::Block as Digestible>::Digest, V::StoredBlock>, |
There was a problem hiding this comment.
put in caches
Benchmark resultsTip ✅ PASSED: No benchmark exceeded the regression threshold. Benchmark comparison table
Baseline commit(s): |
| subscription.await.ok().map(V::into_inner) | ||
| } | ||
|
|
||
| async fn fetch_parent(self, block: Self::Block) -> Option<Self::Block> { |
There was a problem hiding this comment.
make it clearer what actually fetches when subscribing.
Deploying monorepo with
|
| Latest commit: |
1a93809
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://752626d6.monorepo-eu0.pages.dev |
| Branch Preview URL: | https://expand-digest-fetching.monorepo-eu0.pages.dev |
| let block_rx = self.marshal.subscribe_by_digest(Some(round), digest).await; | ||
| let block_rx = self | ||
| .marshal | ||
| .subscribe_by_commitment(digest, CommitmentRequest::FetchByRound { round }) |
There was a problem hiding this comment.
the one big downside of this approach is that we can fetch the same object twice (won't dedup because of hint)
There was a problem hiding this comment.
If we refactor resolver to allow a multiple "retain keys" to a single "fetch key", we could minimize duplicate work.
| @@ -510,7 +515,10 @@ where | |||
| } | |||
|
|
|||
There was a problem hiding this comment.
For data on the pending tip, we actually want to specify not to fetch the block (and just wait for it).
This would make it possible for us to starve the resolver capacity (because we won't prune that pending request until finalization).
| Finalization<S, V::Commitment>, | ||
| >, | ||
| /// Verified blocks stored by height. | ||
| verified_blocks_by_height: |
There was a problem hiding this comment.
we should be able to get rid of the verified by view (if we can track digest by height we don't need that)
There was a problem hiding this comment.
maybe call this "certified_blocks_by_height"?
| /// Verified blocks stored by height. | ||
| verified_blocks_by_height: | ||
| prunable::Archive<TwoCap, R, <V::Block as Digestible>::Digest, V::StoredBlock>, | ||
| } |
There was a problem hiding this comment.
We should ensure we don't fetch beyond the finalized floor here? if so, we should at least be sure we dedup requests?
| verified_blocks_by_height: | ||
| prunable::Archive<TwoCap, R, <V::Block as Digestible>::Digest, V::StoredBlock>, | ||
| } | ||
|
|
There was a problem hiding this comment.
I'm not sure we ever need to fetch by notarized anymore?
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## main #3722 +/- ##
==========================================
- Coverage 95.82% 95.79% -0.04%
==========================================
Files 466 467 +1
Lines 185569 187086 +1517
Branches 4427 4467 +40
==========================================
+ Hits 177825 179214 +1389
- Misses 6324 6430 +106
- Partials 1420 1442 +22
... and 14 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
# Conflicts: # consensus/src/marshal/coding/marshaled.rs # consensus/src/marshal/coding/mod.rs # consensus/src/marshal/core/actor.rs # consensus/src/marshal/core/mailbox.rs # consensus/src/marshal/mocks/harness.rs # consensus/src/marshal/resolver/handler.rs # consensus/src/marshal/resolver/p2p.rs # consensus/src/marshal/standard/deferred.rs # consensus/src/marshal/standard/inline.rs # consensus/src/marshal/standard/mod.rs # consensus/src/marshal/standard/validation.rs # consensus/src/simplex/actors/resolver/ingress.rs # consensus/src/simplex/actors/resolver/state.rs # examples/reshare/src/engine.rs # resolver/src/lib.rs # resolver/src/p2p/engine.rs # resolver/src/p2p/inflight.rs # resolver/src/p2p/ingress.rs # resolver/src/p2p/mocks/consumer.rs # resolver/src/p2p/mod.rs
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d0cd9d737f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if height > self.last_processed_height { | ||
| if let Some(bounds) = self.epocher.containing(height) { | ||
| self.cache | ||
| .put_certified_block_by_height( | ||
| bounds.epoch(), | ||
| height, | ||
| digest, | ||
| block.clone().into(), | ||
| ) | ||
| .await; | ||
| } | ||
| self.notify_subscribers(&block); | ||
| } |
There was a problem hiding this comment.
Deliver fetched ancestry blocks to waiting subscribers
When a Request::Block response is valid but the Ancestry subscriber metadata does not match (for example, a proposal carries an incorrect child height so expected_height != block.height()), this branch skips notify_subscribers entirely. The fetch_parent caller is waiting on subscribe_by_commitment, so dropping the context without notifying leaves that verification/certification task hanging until external cancellation instead of promptly receiving the parent and rejecting the block. This is a liveness regression on malformed proposals and can stall verification work.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d0cd9d7. Configure here.
| } | ||
| self.notify_subscribers(&block); | ||
| } | ||
| false |
There was a problem hiding this comment.
Ancestry block delivery skips subscriber notification below floor
Medium Severity
In handle_deliver for Request::Block, the ancestry path only calls notify_subscribers when height > self.last_processed_height. If last_processed_height advances between the time a subscriber is registered (in handle_subscribe, where height > last_processed_height was true) and the time the resolver delivers the block, the block is silently dropped without notifying the still-registered block subscription waiter. The retain call in update_processed_height may cancel the resolver fetch, but if the response was already in-flight, the delivery arrives with valid subscribers while notify_subscribers is skipped. This can leave an AncestorStream's subscribe_parent call waiting indefinitely on a oneshot::Receiver that is never fulfilled nor closed.
Reviewed by Cursor Bugbot for commit d0cd9d7. Configure here.
|
Replaced by #3796 |


Related: #3718