Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Implement generics for CheckPoint, LocalChain, and spk_client types #1582

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

LagginTimes
Copy link
Contributor

@LagginTimes LagginTimes commented Aug 29, 2024

Implements #1757.

Description

This PR is a step towards header checkpointing for bdk_electrum. The goal is to be able to store whole headers in CheckPoint so they do not have to be re-downloaded. Storing headers this way would be a prerequisite for caching of merkle proofs and for median time passed.

TODO:

  • Change CheckPoint to take in a generic.
  • Change LocalChange to take in a generic.
  • Change spk_client types to take in generics.

Notes to the reviewers

Changelog notice

  • CheckPoint takes in a generic.
  • LocalChain and ChangeSet take in generics.
  • spk_client types can take in generics.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

@LagginTimes LagginTimes marked this pull request as draft August 29, 2024 09:59
@LagginTimes LagginTimes changed the title refactor(core): CheckPoint takes a generic refactor(core): Implement generics for CheckPoint and LocalChain Aug 29, 2024
@LagginTimes LagginTimes force-pushed the generic_checkpoint branch 3 times, most recently from a899049 to 7c13781 Compare September 2, 2024 02:53
@LagginTimes LagginTimes force-pushed the generic_checkpoint branch 2 times, most recently from ea1cf8b to bf90ea5 Compare September 3, 2024 06:15
@LagginTimes LagginTimes force-pushed the generic_checkpoint branch 5 times, most recently from c278804 to 6300d7c Compare September 5, 2024 03:43
@LagginTimes LagginTimes changed the title refactor(core): Implement generics for CheckPoint and LocalChain refactor(core): Implement generics for CheckPoint, LocalChain, and spk_client types Sep 5, 2024
Comment on lines +23 to +27
struct CPInner<B> {
/// Block data.
block_id: BlockId,
/// Data.
data: B,
Copy link
Contributor

Choose a reason for hiding this comment

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

When B is a blockhash, won't this be storing the same block hash twice? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 on this. Maybe data: Option<B> or just keep the height as part of CPInner?

struct CPInner<B> {
  height: u32,
  data: B,
  prev: Option<Arc<CPinner<B>>>,
}

Copy link
Member

Choose a reason for hiding this comment

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

Let's look at this from the API/performance perspective.

I think the "killer feature" of this PR is to be able to put Headers in Checkpoints.

Ideally, we want something like this: CheckPoint<Header>. However, with the proposed changes, it will mean we will be hashing the Header every time we want the block hash from the checkpoint (which will be extremely frequent).

To fix this, we can introduce another data type HeaderWithHash - which, as the name suggests, contains the Header and the BlockHash together. I'm honestly not a fan of this as it becomes clunky.

Since memory is cheap, I think it is okay to duplicate the BlockHash.

Copy link
Member

Choose a reason for hiding this comment

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

If we really don't want to duplicate the BlockHash, another solution would be to use an enum or option internally. It's honestly not pretty and we need to worry about unwraps and how to store the data. Not a fan.

Copy link
Contributor

@ValuedMammal ValuedMammal Jan 28, 2025

Choose a reason for hiding this comment

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

HeaderWithHash sounds reasonable. (or HashedHeader)

Comment on lines +23 to +27
struct CPInner<B> {
/// Block data.
block_id: BlockId,
/// Data.
data: B,
Copy link
Member

Choose a reason for hiding this comment

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

Let's look at this from the API/performance perspective.

I think the "killer feature" of this PR is to be able to put Headers in Checkpoints.

Ideally, we want something like this: CheckPoint<Header>. However, with the proposed changes, it will mean we will be hashing the Header every time we want the block hash from the checkpoint (which will be extremely frequent).

To fix this, we can introduce another data type HeaderWithHash - which, as the name suggests, contains the Header and the BlockHash together. I'm honestly not a fan of this as it becomes clunky.

Since memory is cheap, I think it is okay to duplicate the BlockHash.

@notmandatory
Copy link
Member

Since this one is still having design discussions can I move it out of the 1.1 milestone?

@notmandatory notmandatory removed this from the 1.1.0 milestone Feb 4, 2025
@notmandatory
Copy link
Member

Took this out of the bdk_wallet 1.1 milestone since tagging the release tomorrow.

@rustaceanrob
Copy link
Contributor

Dropping in to note that this would be incredible useful for bdk_kyoto. It is likely that a LocalChain generic over Header would allow the CBF system to simply use the LocalChain the chain backend, and the persistence may be shared between a Wallet and the node.

@LagginTimes LagginTimes force-pushed the generic_checkpoint branch 2 times, most recently from 6f2f42f to 45a7b56 Compare February 20, 2025 16:54
@notmandatory notmandatory added this to the 1.2.0 milestone Feb 24, 2025
@notmandatory notmandatory removed this from the 1.2.0 milestone Mar 4, 2025
@LagginTimes LagginTimes force-pushed the generic_checkpoint branch 3 times, most recently from 765d584 to 7488001 Compare March 10, 2025 20:16
@LagginTimes LagginTimes marked this pull request as draft March 11, 2025 18:12
@luisschwab
Copy link
Contributor

luisschwab commented Mar 17, 2025

Dropping in to note that this would be incredible useful for bdk_kyoto. It is likely that a LocalChain generic over Header would allow the CBF system to simply use the LocalChain the chain backend, and the persistence may be shared between a Wallet and the node.

+1 for this feature, bdk_floresta could share persistence with bdk_wallet as well.

@ValuedMammal
Copy link
Contributor

At a high level I think the API would be cleaner if the generic methods had the simpler names (new, push, extend, insert) and the old methods were renamed push_block_id, extend_block_ids, etc.

CheckPoint::data method can be two methods:

fn data_ref(&self) -> &B {}

fn data(&self) -> B where B: Clone {} // or Copy

LocalChain should have more of a unified interface. Most of the methods should be generic and the only methods under impl LocalChain<BlockHash> {} should be the ones that only make sense in the old design (from_genesis_hash, insert_block, etc). Having two versions of apply_changeset and _check_changeset_is_applied isn't very helpful.

I think the duplicate blockhash problem can be fixed using nymius' suggestion to change CheckPoint::block_id member to height.

Remaining questions:

  1. Will it be possible to migrate an existing sqlite database to one that persists a local chain of headers, or will it require adding a new SQL table?
  2. Are there plans to enable syncing a local chain of headers using bdk_electrum / esplora?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
module-blockchain new feature New feature or request
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

8 participants