Skip to content

feat: tipset prechecks#6886

Merged
LesnyRumcajs merged 2 commits intomainfrom
tipset-prechecks
Apr 10, 2026
Merged

feat: tipset prechecks#6886
LesnyRumcajs merged 2 commits intomainfrom
tipset-prechecks

Conversation

@LesnyRumcajs
Copy link
Copy Markdown
Member

@LesnyRumcajs LesnyRumcajs commented Apr 9, 2026

Summary of changes

Changes introduced in this pull request:

  • adds prechecks (similar to what Lotus does, but more lightweight) before grabbing entire tipsets and putting them into DB. This doesn't 100% mitigate the issue but makes it more difficult to achieve. In our case, it should be good enough.

Reference issue to close (if applicable)

Closes #1914

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

Outside contributions

  • I have read and agree to the CONTRIBUTING document.
  • I have read and agree to the AI Policy document. I understand that failure to comply with the guidelines will lead to rejection of the pull request.

Summary by CodeRabbit

  • New Features
    • Pre-fetch validation for gossip blocks to reject duplicates, bad blocks, out-of-range epochs, and other invalid blocks before fetching.
    • New labeled metric to track rejection reasons for gossip blocks.
    • Reduced redundant processing of duplicate/seen blocks to improve network and persistence efficiency and logging.
  • Tests
    • Added unit tests covering validation paths and edge cases.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cb8f5bad-8c26-44ca-b9ff-dedc161f8437

📥 Commits

Reviewing files that changed from the base of the PR and between 930c9bc and 4a86802.

📒 Files selected for processing (2)
  • src/chain_sync/bad_block_cache.rs
  • src/chain_sync/chain_follower.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/chain_sync/bad_block_cache.rs

Walkthrough

Adds a pre-fetch gossip block validation path: a new SeenBlockCache, a GossipBlockValidator performing header-only checks (including bad/seen caches), metrics for rejected gossip blocks, and integration into the chain follower to skip fetching rejected blocks.

Changes

Cohort / File(s) Summary
Seen Block Cache
src/chain_sync/bad_block_cache.rs
Added DEFAULT_CID_CACHE_CAPACITY: NonZeroUsize; new pub struct SeenBlockCache wrapping SizeTrackingLruCache<get_size::CidWrapper, ()> with new() and test_and_insert(); updated BadBlockCache::default() to use the shared constant.
Validation Logic & Tests
src/chain_sync/validation.rs
Added GossipBlockValidator, GossipBlockRejectReason enum (with label()), max_allowed_epoch() helper, and pre-fetch checks (epoch/finality/timestamp/election proof/signature, win count, message limits, bad/seen cache checks). Expanded unit tests for these paths.
Chain Follower Integration
src/chain_sync/chain_follower.rs
Instantiate and share SeenBlockCache (Arc) alongside BadBlockCache; call GossipBlockValidator::validate_pre_fetch() for incoming PubsubMessage::Block messages; increment labeled GOSSIP_BLOCK_REJECTED_TOTAL, log rejection, and skip fetch/persist when validation fails.
Metrics Addition
src/chain_sync/metrics.rs
Added pub static GOSSIP_BLOCK_REJECTED_TOTAL: LazyLock<Family<GossipRejectReasonLabel, Counter>> and pub struct GossipRejectReasonLabel { pub reason: &'static str } for labeled rejection counters.

Sequence Diagram

sequenceDiagram
    participant Gossipsub as Gossipsub Network
    participant ChainFollower as Chain Follower
    participant Validator as GossipBlockValidator
    participant Caches as SeenBlockCache + BadBlockCache
    participant Metrics as Metrics Counter

    Gossipsub->>ChainFollower: PubsubMessage::Block(header)
    ChainFollower->>Validator: validate_pre_fetch(header, ...)
    Validator->>Caches: SeenBlockCache.test_and_insert(cid)
    Caches-->>Validator: seen? (bool)
    alt duplicate
        Validator-->>ChainFollower: Err(DuplicateCID)
    else not duplicate
        Validator->>Caches: BadBlockCache.get(cid)
        Caches-->>Validator: is_bad? (bool)
        alt bad block
            Validator-->>ChainFollower: Err(BadBlock)
        else
            Validator->>Validator: epoch/finality/timestamp/election/message checks
            alt validation fails
                Validator-->>ChainFollower: Err(reason)
            else validation succeeds
                Validator-->>ChainFollower: Ok
            end
        end
    end
    alt Err(reason)
        ChainFollower->>Metrics: Increment GOSSIP_BLOCK_REJECTED_TOTAL{reason}
        ChainFollower->>ChainFollower: Skip fetch/persist
    else Ok
        ChainFollower->>ChainFollower: Fetch full tipset and persist
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Suggested reviewers

  • akaladarshi
  • sudo-shashank
  • elmattic
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: tipset prechecks' accurately describes the main change—adding lightweight prechecks before retrieving tipsets—and is clear and specific.
Linked Issues check ✅ Passed The PR directly addresses issue #1914 by implementing gossip block prechecks to mitigate database flooding; all code changes align with the mitigation objective.
Out of Scope Changes check ✅ Passed All changes—SeenBlockCache, pre-fetch validation, rejection metrics, and epoch validation—are directly scoped to implementing gossip block prechecks as required by the linked issue.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tipset-prechecks
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch tipset-prechecks

Comment @coderabbitai help to get the list of available commands and usage tips.

@LesnyRumcajs LesnyRumcajs marked this pull request as ready for review April 9, 2026 17:31
@LesnyRumcajs LesnyRumcajs requested a review from a team as a code owner April 9, 2026 17:31
@LesnyRumcajs LesnyRumcajs requested review from akaladarshi and sudo-shashank and removed request for a team April 9, 2026 17:32
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/chain_sync/validation.rs (1)

196-223: Document the new public helpers.

GossipBlockRejectReason::label and GossipBlockValidator::new are public entry points now, so they should have rustdoc while this API surface is still small.

As per coding guidelines, "Document public functions and structs with doc comments".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/chain_sync/validation.rs` around lines 196 - 223, Add doc comments for
the newly public helpers: document the purpose and behavior of
GossipBlockRejectReason::label (what each returned &'static str represents and
when to use it) and GossipBlockValidator::new (what a GossipBlockValidator
validates and that it only uses header+CIDs for pre-validation). Place ///
rustdoc comments immediately above the impl or method signatures so these public
entry points are discoverable in generated docs; mention any important
invariants or expected inputs for GossipBlockValidator.
src/chain_sync/bad_block_cache.rs (1)

62-67: Add rustdoc to SeenBlockCache::new.

The type itself is documented, but its public constructor is not.

As per coding guidelines, "Document public functions and structs with doc comments".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/chain_sync/bad_block_cache.rs` around lines 62 - 67, Add a rustdoc
comment to the public constructor SeenBlockCache::new describing what kind of
cache it creates and its purpose (a size-tracking LRU used for seen gossip
blocks), document the parameter `cap: NonZeroUsize` as the maximum number of
entries, and document the return value as a new SeenBlockCache wrapping a
SizeTrackingLruCache initialized with the metric name "seen_gossip_block"; keep
the comment concise and follow existing doc style for public APIs.
src/chain_sync/metrics.rs (1)

61-64: Document GossipRejectReasonLabel.

This is a new public type, so it should carry a short rustdoc comment describing which metric it labels.

As per coding guidelines, "Document public functions and structs with doc comments".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/chain_sync/metrics.rs` around lines 61 - 64, Add a short Rust doc comment
above the public struct GossipRejectReasonLabel that explains this type is used
to label the metric which tracks gossip message rejections (i.e., it carries the
rejection reason string for the gossip rejection metric), so consumers know what
metric it labels and what the &'static str field represents; update the doc to
mention the field `reason` and its purpose.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/chain_sync/validation.rs`:
- Around line 236-255: The code currently inserts the block CID into
SeenBlockCache via check_duplicate before running transient validations
(validate_epoch_range, validate_timestamp, etc.), causing
early-rejected-but-later-valid blocks to be marked duplicate; fix by deferring
the check_duplicate call (and any test_and_insert) until after transient checks
succeed — i.e., move the call to check_duplicate(cid, seen_block_cache) to after
validate_epoch_range, validate_timestamp, validate_election_proof,
validate_signature_present, and validate_message_count so only fully-passed
blocks are cached; also add a regression test that submits a block once yielding
EpochTooFarAhead and then again later that is accepted, asserting it was not
suppressed as DuplicateBlock.

---

Nitpick comments:
In `@src/chain_sync/bad_block_cache.rs`:
- Around line 62-67: Add a rustdoc comment to the public constructor
SeenBlockCache::new describing what kind of cache it creates and its purpose (a
size-tracking LRU used for seen gossip blocks), document the parameter `cap:
NonZeroUsize` as the maximum number of entries, and document the return value as
a new SeenBlockCache wrapping a SizeTrackingLruCache initialized with the metric
name "seen_gossip_block"; keep the comment concise and follow existing doc style
for public APIs.

In `@src/chain_sync/metrics.rs`:
- Around line 61-64: Add a short Rust doc comment above the public struct
GossipRejectReasonLabel that explains this type is used to label the metric
which tracks gossip message rejections (i.e., it carries the rejection reason
string for the gossip rejection metric), so consumers know what metric it labels
and what the &'static str field represents; update the doc to mention the field
`reason` and its purpose.

In `@src/chain_sync/validation.rs`:
- Around line 196-223: Add doc comments for the newly public helpers: document
the purpose and behavior of GossipBlockRejectReason::label (what each returned
&'static str represents and when to use it) and GossipBlockValidator::new (what
a GossipBlockValidator validates and that it only uses header+CIDs for
pre-validation). Place /// rustdoc comments immediately above the impl or method
signatures so these public entry points are discoverable in generated docs;
mention any important invariants or expected inputs for GossipBlockValidator.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f8fc99aa-e340-45dd-b594-e6769237cada

📥 Commits

Reviewing files that changed from the base of the PR and between c77d176 and 58fc490.

📒 Files selected for processing (4)
  • src/chain_sync/bad_block_cache.rs
  • src/chain_sync/chain_follower.rs
  • src/chain_sync/metrics.rs
  • src/chain_sync/validation.rs

Comment thread src/chain_sync/validation.rs
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/chain_sync/validation.rs (1)

196-223: Document the new public helpers or narrow their visibility.

GossipBlockRejectReason::label() and GossipBlockValidator::new() are now public API surface but still undocumented. If they are internal-only, pub(crate) would also keep the surface smaller.

As per coding guidelines "Document public functions and structs with doc comments".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/chain_sync/validation.rs` around lines 196 - 223,
GossipBlockRejectReason::label() and GossipBlockValidator::new() were made
public without docs; either add concise doc-comments describing their purpose
and usage (e.g., doc on GossipBlockRejectReason::label explaining it returns a
stable metric label for rejection reasons, and doc on GossipBlockValidator::new
describing it constructs a validator for a gossip block) or, if they are
intended to be internal, reduce their visibility to pub(crate) to avoid
expanding the public API; update the signatures accordingly and ensure the
chosen approach is applied to both symbols consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/chain_sync/validation.rs`:
- Around line 243-245: The code currently marks a CID seen inside
Self::check_duplicate (using seen_block_cache) before the subsequent
get_full_tipset() + persist path runs, causing transient fetch failures to cause
later rebroadcasts to be rejected as DuplicateBlock; change the behavior so
check_duplicate only checks membership (do not insert), and perform the insert
into seen_block_cache only after get_full_tipset() returns successfully (the
caller in chain_follower that invokes get_full_tipset should add the insert), or
alternatively add an explicit rollback removal of the CID from seen_block_cache
if get_full_tipset()/persist fails; update/check the functions check_duplicate
and the chain_follower code path that calls get_full_tipset to implement this
move-or-rollback change.

---

Nitpick comments:
In `@src/chain_sync/validation.rs`:
- Around line 196-223: GossipBlockRejectReason::label() and
GossipBlockValidator::new() were made public without docs; either add concise
doc-comments describing their purpose and usage (e.g., doc on
GossipBlockRejectReason::label explaining it returns a stable metric label for
rejection reasons, and doc on GossipBlockValidator::new describing it constructs
a validator for a gossip block) or, if they are intended to be internal, reduce
their visibility to pub(crate) to avoid expanding the public API; update the
signatures accordingly and ensure the chosen approach is applied to both symbols
consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bd29c923-2196-4776-b8e1-93d0709ad7bd

📥 Commits

Reviewing files that changed from the base of the PR and between 58fc490 and 930c9bc.

📒 Files selected for processing (4)
  • src/chain_sync/bad_block_cache.rs
  • src/chain_sync/chain_follower.rs
  • src/chain_sync/metrics.rs
  • src/chain_sync/validation.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/chain_sync/metrics.rs

Comment thread src/chain_sync/validation.rs
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 9, 2026

Codecov Report

❌ Patch coverage is 84.04558% with 56 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.09%. Comparing base (c77d176) to head (4a86802).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/chain_sync/validation.rs 91.88% 13 Missing and 12 partials ⚠️
src/chain_sync/chain_follower.rs 0.00% 22 Missing ⚠️
src/chain_sync/metrics.rs 0.00% 9 Missing ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/chain_sync/bad_block_cache.rs 100.00% <100.00%> (ø)
src/chain_sync/metrics.rs 33.96% <0.00%> (-6.95%) ⬇️
src/chain_sync/chain_follower.rs 38.06% <0.00%> (-1.21%) ⬇️
src/chain_sync/validation.rs 88.57% <91.88%> (+9.85%) ⬆️

... and 12 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c77d176...4a86802. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread src/chain_sync/bad_block_cache.rs Outdated
Comment thread src/chain_sync/chain_follower.rs Outdated
hanabi1224
hanabi1224 previously approved these changes Apr 10, 2026
@LesnyRumcajs LesnyRumcajs added this pull request to the merge queue Apr 10, 2026
Merged via the queue into main with commit 715d34f Apr 10, 2026
46 checks passed
@LesnyRumcajs LesnyRumcajs deleted the tipset-prechecks branch April 10, 2026 08:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Investigate potential vulnerability in ChainMuxer (database flood)

2 participants