Skip to content

fix: seed sync checkpoints from birth_height in ManagedWalletInfo ctors#692

Open
xdustinface wants to merge 4 commits intov0.42-devfrom
refactor/birth-height-construction
Open

fix: seed sync checkpoints from birth_height in ManagedWalletInfo ctors#692
xdustinface wants to merge 4 commits intov0.42-devfrom
refactor/birth-height-construction

Conversation

@xdustinface
Copy link
Copy Markdown
Collaborator

@xdustinface xdustinface commented Apr 25, 2026

WalletInfoInterface::from_wallet and from_wallet_with_name (plus the inherent ManagedWalletInfo constructors) now take birth_height: CoreBlockHeight and seed both checkpoint heights (synced_height, last_processed_height) to birth_height.saturating_sub(1) so the next block to scan is always birth_height.

Without this, every wallet-add path had to remember set_birth_height after construction. Forgetting it left the checkpoints at 0, dragging WalletManager::synced_height (a min across wallets) back to genesis on every add. Moving the seed into construction makes the invariant a property of the type.

ManagedWalletInfo::with_birth_height is removed. It set only birth_height and had no callers.

Based on:

Summary by CodeRabbit

  • Bug Fixes
    • Wallet metadata now seeds synchronization checkpoints from each wallet's declared birth height, ensuring per-wallet synced and processed heights start correctly and manager aggregates reflect min/max across wallets.
  • Tests
    • Updated and expanded tests to validate independent per-wallet checkpoint initialization and correct manager-level aggregation behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fee835bc-f6a1-4c51-bbec-ca8bf35bfacc

📥 Commits

Reviewing files that changed from the base of the PR and between 0a49ef4 and 77abbbb.

📒 Files selected for processing (3)
  • key-wallet-manager/src/lib.rs
  • key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs
  • key-wallet/src/wallet/mod.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • key-wallet/src/wallet/mod.rs
  • key-wallet-manager/src/lib.rs
  • key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs

📝 Walkthrough

Walkthrough

This PR requires callers to supply a wallet birth height when constructing ManagedWalletInfo. It updates WalletInfoInterface signatures, ManagedWalletInfo implementations, WalletManager creation/import paths, FFI call sites, and numerous tests to pass an explicit birth_height, and seeds synced/last-processed heights to birth_height.saturating_sub(1).

Changes

Cohort / File(s) Summary
Core API & types
key-wallet/src/wallet/managed_wallet_info/mod.rs, key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs
Changed WalletInfoInterface and ManagedWalletInfo constructors to accept birth_height: CoreBlockHeight; initialize WalletMetadata with birth_height and seed synced_height/last_processed_height to birth_height.saturating_sub(1); removed set_birth_height.
WalletManager implementation
key-wallet-manager/src/lib.rs
Constructs ManagedWalletInfo with birth_height at wallet create/import time (uses provided birth height or fallback such as manager’s last_processed_height()); removed two-step set_birth_height flow.
FFI call sites
key-wallet-ffi/src/managed_wallet.rs, key-wallet-ffi/src/transaction.rs, key-wallet-ffi/src/transaction_checking.rs
Updated FFI usage to pass a birth_height argument (commonly 0 in these call sites) when creating ManagedWalletInfo.
Tests — manager & serialized wallets
key-wallet-manager/tests/integration_test.rs, key-wallet-manager/tests/test_serialized_wallets.rs, key-wallet-manager/src/accessors.rs
Updated tests to pass explicit birth heights (e.g., wallet2 at 5000); added assertions verifying checkpoint seeding to birth_height - 1 and adjusted aggregate height expectations.
Tests — wallet & transaction checking
key-wallet/src/test_utils/wallet.rs, key-wallet/src/transaction_checking/.../tests/*, key-wallet/src/transaction_checking/wallet_checker.rs, key-wallet/src/wallet/managed_wallet_info/asset_lock_builder.rs, key-wallet/src/wallet/mod.rs
Refactored many unit/integration test call sites to the new constructor signatures by adding the extra birth_height argument (typically 0 in tests) and updated related assertions where applicable.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Suggested labels

ready-for-review

Poem

🐰 I set the birth height at the start,
I seed the heights and do my part,
Wallets awake at their destined block,
Checkpoints ready—no more shock,
Hop, hop, the ledger keeps its heart.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately summarizes the main change: seeding sync checkpoints from birth_height in ManagedWalletInfo constructors, which is the core objective across all modified files.
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 refactor/birth-height-construction

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.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 25, 2026

Codecov Report

❌ Patch coverage is 84.21053% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.62%. Comparing base (ea33cbc) to head (77abbbb).

Files with missing lines Patch % Lines
key-wallet-manager/src/lib.rs 66.66% 2 Missing ⚠️
...allet/managed_wallet_info/wallet_info_interface.rs 50.00% 2 Missing ⚠️
key-wallet-ffi/src/transaction.rs 0.00% 1 Missing ⚠️
key-wallet-ffi/src/transaction_checking.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           v0.42-dev     #692      +/-   ##
=============================================
+ Coverage      70.59%   70.62%   +0.03%     
=============================================
  Files            320      320              
  Lines          68028    68023       -5     
=============================================
+ Hits           48021    48043      +22     
+ Misses         20007    19980      -27     
Flag Coverage Δ
core 75.81% <ø> (ø)
ffi 43.53% <60.00%> (+0.01%) ⬆️
rpc 20.00% <ø> (ø)
spv 87.37% <ø> (+0.07%) ⬆️
wallet 69.55% <87.87%> (+0.06%) ⬆️
Files with missing lines Coverage Δ
key-wallet-ffi/src/managed_wallet.rs 87.20% <100.00%> (ø)
key-wallet-manager/src/accessors.rs 55.90% <100.00%> (ø)
...-wallet/src/transaction_checking/wallet_checker.rs 99.34% <100.00%> (ø)
...c/wallet/managed_wallet_info/asset_lock_builder.rs 79.57% <100.00%> (ø)
key-wallet/src/wallet/managed_wallet_info/mod.rs 73.68% <100.00%> (+16.54%) ⬆️
key-wallet/src/wallet/mod.rs 88.21% <100.00%> (+0.11%) ⬆️
key-wallet-ffi/src/transaction.rs 0.00% <0.00%> (ø)
key-wallet-ffi/src/transaction_checking.rs 1.90% <0.00%> (ø)
key-wallet-manager/src/lib.rs 62.83% <66.66%> (-0.06%) ⬇️
...allet/managed_wallet_info/wallet_info_interface.rs 79.22% <50.00%> (+1.51%) ⬆️

... and 3 files with indirect coverage changes

@github-actions
Copy link
Copy Markdown
Contributor

This PR has merge conflicts with the base branch. Please rebase or merge the base branch into your branch to resolve them.

@github-actions github-actions Bot added the merge-conflict The PR conflicts with the target branch. label Apr 27, 2026
Base automatically changed from refactor/heights-per-wallet to v0.42-dev April 27, 2026 22:27
@xdustinface xdustinface force-pushed the refactor/birth-height-construction branch from 973115f to 5ee6537 Compare April 28, 2026 01:30
@github-actions github-actions Bot removed the merge-conflict The PR conflicts with the target branch. label Apr 28, 2026
@xdustinface xdustinface marked this pull request as ready for review April 28, 2026 01:30
@github-actions
Copy link
Copy Markdown
Contributor

This PR has merge conflicts with the base branch. Please rebase or merge the base branch into your branch to resolve them.

@github-actions github-actions Bot added the merge-conflict The PR conflicts with the target branch. label Apr 28, 2026
…dWalletInfo` ctors

`WalletInfoInterface::from_wallet` and `from_wallet_with_name` (plus the inherent `ManagedWalletInfo` constructors) now take `birth_height: CoreBlockHeight` and seed both checkpoint heights (`synced_height`, `last_processed_height`) to `birth_height.saturating_sub(1)` so the next block to scan is always `birth_height`.

Without this, every wallet-add path had to remember `set_birth_height` after construction, and even when called it only set `birth_height`, leaving the checkpoints at `0`. With the per-wallet sync introduced in #694, that dragged `WalletManager::synced_height` (a min across wallets) back to genesis on every add, forcing a re-scan from `0`. Moving the seed into construction makes the invariant a property of the type.

`ManagedWalletInfo::with_birth_height` is removed. It set only `birth_height` and had no callers.
@xdustinface xdustinface force-pushed the refactor/birth-height-construction branch from 5ee6537 to 0a49ef4 Compare April 28, 2026 13:14
@github-actions github-actions Bot removed the merge-conflict The PR conflicts with the target branch. label Apr 28, 2026
@xdustinface xdustinface changed the title refactor(key-wallet): seed checkpoints in ManagedWalletInfo ctors fix: seed sync checkpoints from birth_height in ManagedWalletInfo ctors Apr 28, 2026
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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
key-wallet-ffi/src/transaction_checking.rs (1)

77-83: ⚠️ Potential issue | 🟠 Major

FFI still hardcodes genesis as the wallet birth height.

Line 82 always constructs ManagedWalletInfo with 0, so restored wallets coming through this API still cannot preserve their actual birth height. That keeps the full-rescan behavior for FFI consumers even though the Rust API now makes birth_height explicit. This entry point needs a birth_height parameter, or it needs to build from persisted metadata instead of forcing genesis.

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

In `@key-wallet-ffi/src/transaction_checking.rs` around lines 77 - 83, The FFI
function wallet_create_managed_wallet currently forces genesis by calling
ManagedWalletInfo::from_wallet(wallet.inner(), 0); modify this entry point to
accept a birth_height parameter (or retrieve the wallet's persisted birth height
from its metadata) and pass that value into ManagedWalletInfo::from_wallet
instead of 0 so restored wallets preserve their actual birth_height; update the
extern "C" signature, any FFI callers, and the construction via
FFIManagedWalletInfo::new accordingly.
🧹 Nitpick comments (2)
key-wallet/src/wallet/mod.rs (1)

416-429: Please pin the new off-by-one checkpoint behavior in this test.

This now exercises the new constructor signature, but it still would not fail if birth_height stopped seeding synced_height / last_processed_height to birth_height - 1. A small non-zero birth-height assertion here would lock down the contract this PR is introducing.

Proposed test tweak
-        let mut managed_info = ManagedWalletInfo::from_wallet(&wallet, 0);
+        let mut managed_info = ManagedWalletInfo::from_wallet(&wallet, 100);
         managed_info.set_name("Test Wallet".to_string());
         managed_info.set_description(Some("A test wallet".to_string()));
 
         // Test initial managed info
         assert_eq!(managed_info.wallet_id, wallet.wallet_id);
         assert_eq!(managed_info.name.as_ref().unwrap(), "Test Wallet");
         assert_eq!(managed_info.description.as_ref().unwrap(), "A test wallet");
+        assert_eq!(managed_info.metadata.birth_height, 100);
+        assert_eq!(managed_info.metadata.synced_height, 99);
+        assert_eq!(managed_info.metadata.last_processed_height, 99);
         assert_eq!(managed_info.metadata.first_loaded_at, 0); // Default value
         assert!(managed_info.metadata.last_synced.is_none());

As per coding guidelines, "Write unit tests for new functionality".

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

In `@key-wallet/src/wallet/mod.rs` around lines 416 - 429, The test creates
ManagedWalletInfo via ManagedWalletInfo::from_wallet but doesn't assert the new
off-by-one contract for birth_height seeding
synced_height/last_processed_height; update the test after constructing
managed_info to (1) ensure the seed birth height is non-zero (e.g. assert
managed_info.metadata.birth_height > 0 or set wallet.birth_height to a small
non-zero value before calling ManagedWalletInfo::from_wallet) and (2) assert
that metadata.synced_height == Some(birth_height - 1) and
metadata.last_processed_height == Some(birth_height - 1) to lock down the new
behavior introduced by the constructor/signature change.
key-wallet-ffi/src/transaction.rs (1)

309-309: Avoid hardcoding birth_height = 0 in FFI transaction checks.

This works today, but it sidesteps the new constructor invariant and can reintroduce checkpoint drift if this path later persists managed state. Prefer threading an explicit birth/checkpoint height from caller or wallet context.

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

In `@key-wallet-ffi/src/transaction.rs` at line 309,
ManagedWalletInfo::from_wallet is being called with a hardcoded birth height of
0 (let mut managed_info = ManagedWalletInfo::from_wallet(wallet.inner(), 0)),
which violates the constructor invariant and risks checkpoint drift; instead
thread an explicit birth/checkpoint height into this code path by either (A)
obtaining the height from the wallet context (e.g., call a wallet method like
wallet.birth_height() or wallet.checkpoint_height() and pass that value to
ManagedWalletInfo::from_wallet) or (B) add a birth_height parameter to the
surrounding function and use that parameter when calling
ManagedWalletInfo::from_wallet(wallet.inner(), birth_height); update call sites
accordingly so no hardcoded 0 remains.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@key-wallet-manager/src/lib.rs`:
- Around line 440-442: The comment incorrectly states “current chain tip” though
the code passes self.last_processed_height() to T::from_wallet, which is
manager-derived and not necessarily the chain tip; update the comment above the
T::from_wallet(&wallet, self.last_processed_height()) call to describe that it
uses the manager's last processed height (or aggregate tip) as the birth height,
not the node's chain tip, so the wording accurately reflects
self.last_processed_height()’s semantics.

In `@key-wallet/src/wallet/managed_wallet_info/mod.rs`:
- Around line 85-100: The public API still allows creating inconsistent
checkpoints because ManagedWalletInfo::new, ManagedWalletInfo::with_name and
WalletInfoInterface::set_birth_height do not maintain the invariant that
WalletMetadata.{birth_height, synced_height, last_processed_height} are aligned;
update the API so either (A) all public constructors require a birth_height
argument and remove the mutable setter (delete
WalletInfoInterface::set_birth_height and change new/with_name to accept
birth_height) or (B) keep the setter but make
WalletInfoInterface::set_birth_height (and any constructors that accept a birth
height) update all three fields atomically (set synced_height =
last_processed_height = birth_height.saturating_sub(1)) to match
ManagedWalletInfo::from_wallet, referencing ManagedWalletInfo::from_wallet,
WalletMetadata::birth_height, WalletMetadata::synced_height and
WalletMetadata::last_processed_height when making the change.

---

Outside diff comments:
In `@key-wallet-ffi/src/transaction_checking.rs`:
- Around line 77-83: The FFI function wallet_create_managed_wallet currently
forces genesis by calling ManagedWalletInfo::from_wallet(wallet.inner(), 0);
modify this entry point to accept a birth_height parameter (or retrieve the
wallet's persisted birth height from its metadata) and pass that value into
ManagedWalletInfo::from_wallet instead of 0 so restored wallets preserve their
actual birth_height; update the extern "C" signature, any FFI callers, and the
construction via FFIManagedWalletInfo::new accordingly.

---

Nitpick comments:
In `@key-wallet-ffi/src/transaction.rs`:
- Line 309: ManagedWalletInfo::from_wallet is being called with a hardcoded
birth height of 0 (let mut managed_info =
ManagedWalletInfo::from_wallet(wallet.inner(), 0)), which violates the
constructor invariant and risks checkpoint drift; instead thread an explicit
birth/checkpoint height into this code path by either (A) obtaining the height
from the wallet context (e.g., call a wallet method like wallet.birth_height()
or wallet.checkpoint_height() and pass that value to
ManagedWalletInfo::from_wallet) or (B) add a birth_height parameter to the
surrounding function and use that parameter when calling
ManagedWalletInfo::from_wallet(wallet.inner(), birth_height); update call sites
accordingly so no hardcoded 0 remains.

In `@key-wallet/src/wallet/mod.rs`:
- Around line 416-429: The test creates ManagedWalletInfo via
ManagedWalletInfo::from_wallet but doesn't assert the new off-by-one contract
for birth_height seeding synced_height/last_processed_height; update the test
after constructing managed_info to (1) ensure the seed birth height is non-zero
(e.g. assert managed_info.metadata.birth_height > 0 or set wallet.birth_height
to a small non-zero value before calling ManagedWalletInfo::from_wallet) and (2)
assert that metadata.synced_height == Some(birth_height - 1) and
metadata.last_processed_height == Some(birth_height - 1) to lock down the new
behavior introduced by the constructor/signature change.
🪄 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: CHILL

Plan: Pro

Run ID: 885618de-3dc3-415f-a7d1-5b3b7d241b42

📥 Commits

Reviewing files that changed from the base of the PR and between ea33cbc and 0a49ef4.

📒 Files selected for processing (16)
  • key-wallet-ffi/src/managed_wallet.rs
  • key-wallet-ffi/src/transaction.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet-manager/src/accessors.rs
  • key-wallet-manager/src/lib.rs
  • key-wallet-manager/tests/integration_test.rs
  • key-wallet-manager/tests/test_serialized_wallets.rs
  • key-wallet/src/test_utils/wallet.rs
  • key-wallet/src/transaction_checking/transaction_router/tests/identity_transactions.rs
  • key-wallet/src/transaction_checking/transaction_router/tests/provider.rs
  • key-wallet/src/transaction_checking/transaction_router/tests/routing.rs
  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/wallet/managed_wallet_info/asset_lock_builder.rs
  • key-wallet/src/wallet/managed_wallet_info/mod.rs
  • key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs
  • key-wallet/src/wallet/mod.rs

Comment thread key-wallet-manager/src/lib.rs Outdated
Comment thread key-wallet/src/wallet/managed_wallet_info/mod.rs
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 28, 2026
…allet import

Addresses CodeRabbit review comment on PR #692
#692 (comment)
The setter only updated `birth_height`, leaving `synced_height` and `last_processed_height` at their previous values, so a caller using it after construction would silently bypass the seeding invariant established by `from_wallet`. With the per-wallet height tracking in #694 that aggregate to a min/max across wallets, this could drag the manager's `synced_height` back to genesis. After the constructor change, the setter has zero callers in-tree, so removing it is the cleanest way to enforce the invariant: `birth_height` is fixed at construction via `from_wallet`.

Addresses CodeRabbit review comment on PR #692
#692 (comment)
…anaged_info`

Use a non-zero `birth_height` and assert that `metadata.synced_height` and `metadata.last_processed_height` land at `birth_height - 1`, locking the seeding invariant in place.

Addresses CodeRabbit review comment on PR #692
#692 (review)
@github-actions github-actions Bot added the ready-for-review CodeRabbit has approved this PR label Apr 28, 2026
@xdustinface xdustinface requested a review from ZocoLini April 29, 2026 00:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-review CodeRabbit has approved this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant