Skip to content

feat(state): per-component fingerprint dump for cross-node drift diagnosis#790

Merged
github-actions[bot] merged 1 commit into
mainfrom
diag/state-component-fingerprint
Jun 4, 2026
Merged

feat(state): per-component fingerprint dump for cross-node drift diagnosis#790
github-actions[bot] merged 1 commit into
mainfrom
diag/state-component-fingerprint

Conversation

@satyakwok
Copy link
Copy Markdown
Member

@satyakwok satyakwok commented Jun 4, 2026

What

New read-only sentrix state fingerprint subcommand that splits the single state fingerprint into per-component hashes:
accounts_fp / contract_code_fp / contract_storage_fp / total_minted / total_burned / src20_fp / nft_fp (+ account_count).

Why

compute_state_fingerprint folds everything into one root — it tells you THAT two nodes diverged, not WHERE. This pinpoints the divergent subsystem to chase the post-#782 state-determinism drift (same block → multiple state_root clusters, suspected localized to mint/supply + account-level).

How to use

Run on each node with the node STOPPED, same height, then diff:

SENTRIX_DATA_DIR=/path/to/data sentrix state fingerprint

Safety

Pure diagnostic — state_components() is never called on the consensus/apply path; read-only over an opened chain.db. No version bump (not a consensus change).

Also gitignores the local docs-site/ docusaurus preview build (was untracked node_modules).

Summary by CodeRabbit

  • New Features
    • Added a new sentrix state fingerprint diagnostic command that computes and displays state fingerprints for all blockchain components, including accounts, EVM contract bytecode and storage, SRC-20 tokens, and NFTs. This enables operators to detect and diagnose potential state drift across the network.

…nosis

New read-only `sentrix state fingerprint` subcommand splits the single
state fingerprint into per-component hashes (accounts / EVM code / EVM
storage / total_minted / total_burned / SRC-20 / NFT). Run per node
(STOPPED) at the same height and diff the output to localize WHICH
component diverges — chasing the post-#782 determinism drift.

Pure diagnostic: state_components() is not on the consensus path.
Also gitignore the local docs-site/ docusaurus preview build.
@github-actions github-actions Bot enabled auto-merge (squash) June 4, 2026 15:17
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a new sentrix state fingerprint CLI command for diagnosing cross-node state drift. It adds a StateComponents struct and state_components() API in the core block executor that compute deterministic SHA-256 fingerprints for accounts, EVM contract code, EVM contract storage, and native module state (minted/burned totals, SRC-20 and NFT canonical hashes). The command handler reads the chain database, computes these fingerprints, and prints the current block height, account count, and hex-encoded component digests. The CLI wiring integrates the new subcommand into the sentrix state command group.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description provides clear context (What/Why/How), but the provided description template requires structured checkboxes for Scope, Checks, and Deploy impact that are missing or incomplete. Complete the template sections: mark all Scope checkboxes (appears to be repo tooling/test-only), all Checks (confirm build/test/format status), and Deploy impact (mark 'No on-chain change' as applicable).
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly summarizes the main change: adding a per-component fingerprint dump feature for diagnosing cross-node state drift.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 diag/state-component-fingerprint

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bin/sentrix/src/commands/state.rs`:
- Line 372: The printed output uses the wrong key name "contract_stor_fp" which
differs from the documented/canonical "contract_storage_fp"; update the println
in the state command (the println! call that references c.contract_storage_fp)
to print the key "contract_storage_fp" instead of "contract_stor_fp" so external
parsers see the documented field name.
- Around line 352-357: The docstring above the function cmd_state_fingerprint
incorrectly describes "state preflight"; update that comment to accurately
describe the "sentrix state fingerprint [--json]" command — a per-component
state fingerprint dump for the chain.db in SENTRIX_DATA_DIR (run against stopped
nodes to diff state components across nodes at the same height). Ensure the
first line, short description, and any following lines refer to "fingerprint"
rather than "preflight" so generated docs and code navigation reflect the
correct command.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0323ae97-67fb-4896-bc8a-457cd4b5c456

📥 Commits

Reviewing files that changed from the base of the PR and between f0e363f and f03ba54.

⛔ Files ignored due to path filters (1)
  • .gitignore is excluded by !**/.gitignore
📒 Files selected for processing (3)
  • bin/sentrix/src/commands/state.rs
  • bin/sentrix/src/main.rs
  • crates/sentrix-core/src/block_executor.rs

Comment on lines 352 to +357
/// `sentrix state preflight [--json]` — read-only activation readiness report.
/// Dump per-component state fingerprints for the chain.db at SENTRIX_DATA_DIR.
/// Run against each node's data dir (node STOPPED) and diff the output to find
/// WHICH state component diverges across nodes at the same height. Added
/// 2026-06-04 to chase the post-#782 determinism drift.
pub fn cmd_state_fingerprint() -> anyhow::Result<()> {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the stale docstring on this command.

Line 352 still describes state preflight, but this function is the fingerprint command. This is misleading in generated docs and code navigation.

Suggested patch
-/// `sentrix state preflight [--json]` — read-only activation readiness report.
+/// `sentrix state fingerprint` — dump per-component state fingerprints (read-only).
 /// Dump per-component state fingerprints for the chain.db at SENTRIX_DATA_DIR.
 /// Run against each node's data dir (node STOPPED) and diff the output to find
 /// WHICH state component diverges across nodes at the same height. Added
 /// 2026-06-04 to chase the post-#782 determinism drift.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// `sentrix state preflight [--json]` — read-only activation readiness report.
/// Dump per-component state fingerprints for the chain.db at SENTRIX_DATA_DIR.
/// Run against each node's data dir (node STOPPED) and diff the output to find
/// WHICH state component diverges across nodes at the same height. Added
/// 2026-06-04 to chase the post-#782 determinism drift.
pub fn cmd_state_fingerprint() -> anyhow::Result<()> {
/// `sentrix state fingerprint` — dump per-component state fingerprints (read-only).
/// Dump per-component state fingerprints for the chain.db at SENTRIX_DATA_DIR.
/// Run against each node's data dir (node STOPPED) and diff the output to find
/// WHICH state component diverges across nodes at the same height. Added
/// 2026-06-04 to chase the post-#782 determinism drift.
pub fn cmd_state_fingerprint() -> anyhow::Result<()> {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/sentrix/src/commands/state.rs` around lines 352 - 357, The docstring
above the function cmd_state_fingerprint incorrectly describes "state
preflight"; update that comment to accurately describe the "sentrix state
fingerprint [--json]" command — a per-component state fingerprint dump for the
chain.db in SENTRIX_DATA_DIR (run against stopped nodes to diff state components
across nodes at the same height). Ensure the first line, short description, and
any following lines refer to "fingerprint" rather than "preflight" so generated
docs and code navigation reflect the correct command.

println!("total_burned {}", c.total_burned);
println!("accounts_fp {}", hx(&c.accounts_fp));
println!("contract_code_fp {}", hx(&c.contract_code_fp));
println!("contract_stor_fp {}", hx(&c.contract_storage_fp));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the documented output key name for storage fingerprint.

Line 372 prints contract_stor_fp, but the API/docs use contract_storage_fp. This can break simple parser/diff scripts expecting the canonical field name.

Suggested patch
-    println!("contract_stor_fp  {}", hx(&c.contract_storage_fp));
+    println!("contract_storage_fp {}", hx(&c.contract_storage_fp));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
println!("contract_stor_fp {}", hx(&c.contract_storage_fp));
println!("contract_storage_fp {}", hx(&c.contract_storage_fp));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/sentrix/src/commands/state.rs` at line 372, The printed output uses the
wrong key name "contract_stor_fp" which differs from the documented/canonical
"contract_storage_fp"; update the println in the state command (the println!
call that references c.contract_storage_fp) to print the key
"contract_storage_fp" instead of "contract_stor_fp" so external parsers see the
documented field name.

@github-actions github-actions Bot merged commit 6416766 into main Jun 4, 2026
18 checks passed
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@satyakwok satyakwok self-assigned this Jun 4, 2026
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.

1 participant