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

Add bitcoind_rpc chain source module. #1041

Merged
merged 14 commits into from Oct 9, 2023

Conversation

evanlinjin
Copy link
Member

@evanlinjin evanlinjin commented Jul 20, 2023

Description

This PR builds on top of #1034 and adds the bitcoind_rpc chain-src module and example.

Notes to the reviewers

Don't merge this until #1034 is in!

Changelog notice

  • Add bitcoind_rpc chain-source module.
  • Add example_bitcoind_rpc example module.
  • Add AnchorFromBlockPosition trait which are for anchors that can be constructed from a given block, height and position in block.
  • Add helper methods to IndexedTxGraph and TxGraph for batch operations and applying blocks directly.
  • Add helper methods to CheckPoint for easier construction from a block Header.

Checklists

  • Add test: we should detect when an initially-confirmed transaction is "unconfirmed" during a reorg.
  • Improve example_bitcoind_rpc: add live command.
  • Improve docs.
  • Reintroduce CheckPoint.

All Submissions:

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

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

@evanlinjin evanlinjin added this to the 1.0.0-alpha.2 milestone Jul 20, 2023
@evanlinjin evanlinjin self-assigned this Jul 20, 2023
@evanlinjin evanlinjin force-pushed the bitcoind_rpc_chain_src branch 3 times, most recently from a0cb7f8 to ae3ee39 Compare July 28, 2023 11:15
@evanlinjin evanlinjin force-pushed the bitcoind_rpc_chain_src branch 8 times, most recently from 658259c to b5b2367 Compare August 1, 2023 07:44
@evanlinjin evanlinjin marked this pull request as ready for review August 1, 2023 07:45
@evanlinjin evanlinjin force-pushed the bitcoind_rpc_chain_src branch 2 times, most recently from 019f9f1 to 19e51d4 Compare August 5, 2023 04:29
@evanlinjin evanlinjin mentioned this pull request Aug 7, 2023
5 tasks
Copy link
Contributor

@LLFourn LLFourn left a comment

Choose a reason for hiding this comment

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

I've made some comments. It looks awesome. I think this will be a "flagship" example on how to use bdk so I think we should spend the time to get it right. The block data processing pipeline is too complicated for what the problem is. I think IndexedTxGraph needs to be able to process block data and filter out what's relevant itself. This is needed for CBF block processing as well so calling out to weird helper methods in the bitcoind_rpc crate seems counter productive.

crates/bitcoind_rpc/src/lib.rs Outdated Show resolved Hide resolved
example-crates/example_rpc/src/main.rs Outdated Show resolved Hide resolved
crates/bitcoind_rpc/src/lib.rs Outdated Show resolved Hide resolved
crates/bitcoind_rpc/src/lib.rs Outdated Show resolved Hide resolved
crates/bitcoind_rpc/src/lib.rs Outdated Show resolved Hide resolved
example-crates/example_rpc/src/main.rs Outdated Show resolved Hide resolved
example-crates/example_rpc/src/main.rs Outdated Show resolved Hide resolved
@notmandatory
Copy link
Member

@evanlinjin this looks like a really powerful way to sync with a core node. I read through the code and I think I understand the state-model approach within the Emitter::emit_block. Have you and @LLFourn chatted yet about his ideas to simplify it somehow? From an outside user the APIs look easy enough to use but if there are opportunities to simplify the internals it's worth discussing.

You look to be covering the main test scenarios, 1. sync blocks before and after reorg, 2. sync txs in mempool and after being included in a block. Is it worth adding a test to verify confirmed tx are unconfirmed after a reorg?

@evanlinjin evanlinjin force-pushed the bitcoind_rpc_chain_src branch 3 times, most recently from 9e873b5 to e1a9124 Compare August 26, 2023 14:23
@evanlinjin evanlinjin force-pushed the bitcoind_rpc_chain_src branch 2 times, most recently from 68ed908 to 074ba6a Compare October 9, 2023 13:48
@evanlinjin
Copy link
Member Author

evanlinjin commented Oct 9, 2023

@LLFourn the file is 104MB, with a start height of 778,000

UPDATE: Okay I accidentally called batch_insert_unconfirmed instead of batch_insert_relevant_confirmed. So most of the content is mempool txs.

UPDATE 2: Yeah with these settings, when a wallet is fully synced, loading from db takes less than 100ms.

evanlinjin and others added 12 commits October 9, 2023 22:14
So you can pass in the esplora/electrum/bitcoind_rpc server details in
the example.

Co-authored-by: LLFourn <lloyd.fourn@gmail.com>
This is useful for block-by-block chain sources. We can determine the
tx's anchor based on the block, block height and tx position in the
block.
* `CheckPoint::from_header` allows us to construct a checkpoint from
  block header.
* `CheckPoint::into_update` transforms the cp into a
  `local_chain::Update`.
Co-authored-by: Steve Myers <steve@notmandatory.org>
For `IndexedTxGraph`:
- Remove `InsertTxItem` type (this is too complex).
    - `batch_insert_relevant` now uses a simple tuple `(&tx, anchors)`.
    - `batch_insert` is now also removed, as the same functionality can be
      done elsewhere.
- Add internal helper method `index_tx_graph_changeset` so we don't need
  to create a seprate `TxGraph` update in each method.
- `batch_insert_<relevant>_unconfirmed` no longer takes in an option of
  last_seen.
- `batch_insert_unconfirmed` no longer takes a reference of a
  transaction (since we apply all transactions anyway, so there is no
  need to clone).

For `TxGraph`:
- Add `batch_insert_unconfirmed` method.
Instead of inserting anchors and seen_at timestamp in the same method,
we have three separate methods. This makes the API easier to understand
and makes `IndexedTxGraph` more consistent with the `TxGraph` API.
Instead of comparing the blockhash against the emitted_blocks map
to see whether the block is part of the emitter's best chain, we
reduce the `last_mempool_tip` height to the last agreement height
during the polling logic.

The benefits of this is we have tighter bounds for avoiding re-
emission. Also, it will be easier to replace `emitted_blocks` to
a `CheckPoint` (since we no longer rely on map lookup).
* `bdk_chain` dependency is added. In the future, we will introduce a
  separate `bdk_core` crate to contain shared types.
* replace `Emitter::new` with `from_height` and `from_checkpoint`
  * `from_height` emits from the given start height
  * `from_checkpoint` uses the provided cp to find agreement point
* introduce logic that ensures emitted blocks can connect with
  receiver's `LocalChain`
* in our rpc example, we can now `expect()` chain updates to always
  since we are using checkpoints and receiving blocks in order
Copy link
Contributor

@vladimirfomene vladimirfomene left a comment

Choose a reason for hiding this comment

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

Great work @evanlinjin ! Just a couple of questions and nits.


/// The latest first-seen epoch of emitted mempool transactions. This is used to determine
/// whether a mempool transaction is already emitted.
last_mempool_time: usize,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why define this as usize? Can we have it as u64 to avoid conversion later?

/// that the block is no longer in the best chain, it will be popped off from here.
last_cp: Option<CheckPoint>,

/// The block result returned from rpc of the last-emitted block. As this result contains the
Copy link
Contributor

Choose a reason for hiding this comment

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

I think using GetBlockResult will make this sentence clearer.

/// To filter out irrelevant transactions, use [`batch_insert_relevant_unconfirmed`] instead.
///
/// [`batch_insert_relevant_unconfirmed`]: IndexedTxGraph::batch_insert_relevant_unconfirmed
pub fn batch_insert_unconfirmed(
Copy link
Contributor

Choose a reason for hiding this comment

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

When will this be useful? Can we add docs around when a user will want to use this API?

Copy link
Member Author

@evanlinjin evanlinjin Oct 9, 2023

Choose a reason for hiding this comment

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

When we want to track transactions, but don't want to filter them out.

example-crates/example_bitcoind_rpc_polling/src/main.rs Outdated Show resolved Hide resolved
example-crates/example_bitcoind_rpc_polling/src/main.rs Outdated Show resolved Hide resolved
* avoid holding mutex lock over io
* document `CHANNEL_BOUND` const
* use the `relevant` variant of `batch_insert_unconfirmed`
* print elapsed time in stdout for various updates
Also better docs for `Emitter` fields.
Copy link
Member

@notmandatory notmandatory left a comment

Choose a reason for hiding this comment

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

Re ACK 85c6253

I don't see any critical issues remaining and any final nits can be fixed in follow-up PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

6 participants