Skip to content

refactor(cbf): drop latest_tip mirror, source chain tip from kyoto directly#12

Open
randomlogin wants to merge 3 commits intofebyeji:add-cbf-chain-sourcefrom
randomlogin:cbf-remove-latest-tip
Open

refactor(cbf): drop latest_tip mirror, source chain tip from kyoto directly#12
randomlogin wants to merge 3 commits intofebyeji:add-cbf-chain-sourcefrom
randomlogin:cbf-remove-latest-tip

Conversation

@randomlogin
Copy link
Copy Markdown

@randomlogin randomlogin commented Apr 21, 2026

Summary

Removes the latest_tip: Arc<Mutex<Option<BlockHash>>> field from CbfChainSource and CbfEventState. The only functional consumer was fee_rate_cache_from_cbf, which now calls Requester::chain_tip() per invocation instead of reading from a mirrored cache.

Motivation

latest_tip was cross-task shared mutable state maintained in three places:

  • Written on Event::FiltersSynced.
  • Cleared on BlockHeaderChanges::Reorganized.
  • Cleared on stale-tip get_block failures inside fee_rate_cache_from_cbf (the idx == 0 branches).

All three exist to keep the mirror consistent with kyoto's actual view of the chain. Asking kyoto directly removes the need for any of them.

Why this is safer than the mirror

  • Reorgs: kyoto already tracks the new tip, so chain_tip() returns the post-reorg value without us manually invalidating anything.
  • CBF node restart (auto-restart with exponential backoff): the new Requester is swapped into cbf_runtime_status, so chain_tip() calls through self.requester() pick up the fresh handle automatically. The old mirror could hold a stale hash from before the crash, which would then get handed to get_block and trigger the defensive "clear-cached-tip-and-return-None" fallback. That fallback is now gone.
  • Pre-sync window: instead of returning Ok(None) when latest_tip is None, we skip when tip.height < FEE_RATE_LOOKBACK_BLOCKS — more precise (the real requirement is "enough history to sample"), and no separate "have we synced yet?" signal needed.

Changes

  • Drop latest_tip from CbfChainSource (field, init, Arc clone in start()'s restart loop).
  • Drop latest_tip from CbfEventState (field + event-state construction inside the restart loop).
  • Remove the Event::FiltersSynced writer and the BlockHeaderChanges::Reorganized clearer.
  • Rewrite fee_rate_cache_from_cbf:
    • Fetch tip via tokio::time::timeout(timeout, requester.chain_tip()).
    • Skip fee estimation when the chain is shorter than the lookback window.
    • Drop the idx == 0 stale-tip defensive branches; any get_block failure is now a hard error.

Stacked on #11. Retargets to add-cbf-chain-source once that merges.

Disclosure: drafted with assistance from Claude Code.

randomlogin and others added 3 commits April 21, 2026 00:34
`push` only appends above the tip, so when `recent_history` contained
blocks at or below the wallet's current checkpoint height after a reorg,
the stale hashes on the wallet checkpoint were never replaced. Switch to
`CheckPoint::insert`, which detects conflicting hashes and purges stale
blocks, matching bdk-kyoto's `UpdateBuilder::apply_chain_event`.

Also clear `latest_tip` on `BlockHeaderChanges::Reorganized` so cached
tip state does not point at an abandoned chain.

Update the `checkpoint_building_handles_reorg` unit test (added in
c1844b3) to exercise the fixed behaviour: a reorg where the new tip
is at the same height as the wallet's checkpoint must still result
in the reorged hashes winning.

Disclosure: drafted with assistance from Claude Code.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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