Skip to content

Commit

Permalink
Merge #1569: Introduce bdk_core
Browse files Browse the repository at this point in the history
a5d076f chore(core)!: s/tx_graph::Update/TxUpdate/ (LLFourn)
dafb9aa feat(bitcoind_rpc)!: depend on `bdk_core` instead of `bdk_chain` (志宇)
fea8eed feat(esplora)!: depend on `bdk_core` instead of `bdk_chain` (志宇)
0d302f5 feat(electrum)!: depend on `bdk_core` instead of `bdk_chain` (志宇)
ab0315d feat!: move `spk_client`s to `bdk_core` (志宇)
bdea871 feat!: move `tx_graph::Update` to `bdk_core` (志宇)
77e31c7 feat!: move `CheckPoint` to `bdk_core` (志宇)
a86c878 refactor(chain): change `CheckPoint::apply_changeset` (志宇)
6f7626a feat!: introduce `bdk_core` (志宇)

Pull request description:

  Based on #1568
  Closes #1543

  ### Description

  Introduce `bdk_core` crate. Move types over from `bdk_chain`. Chain sources (`bdk_electrum`, `bdk_esplora` and `bdk_bitcoind_rpc`) now only depend on `bdk_core`.

  ### Notes to the reviewers

  Please review commit-by-commit. I've moved things over, but slight API changes were necessary (mentioned in the commit messages).

  ### Changelog notice

  * Add `bdk_core` crate which contains core types that were previously in `bdk_chain`. Including: `BlockId`, `ConfirmationBlockTime`, `CheckPoint`, `CheckPointIter`, `tx_graph::Update` and `spk_client`-types.
  * Change chain sources (`bdk_esplora`, `bdk_electrum` and `bdk_bitcoind_rpc`) to only depend on `bdk_core`.

  ### Checklists

  #### All Submissions:

  * [x] I've signed all my commits
  * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
  * [x] I ran `cargo fmt` and `cargo clippy` before committing

ACKs for top commit:
  LLFourn:
    Self-ACK: a5d076f
  evanlinjin:
    ACK a5d076f

Tree-SHA512: 13ecd0a2d2fc840b281977f07dc11fed27459f77c676af470134d2184db4a1fc352073ef82b1622e04fc60edb885e587ae8b9909c9bafb4ae63fcd51325d1cad
  • Loading branch information
evanlinjin committed Aug 25, 2024
2 parents dad9545 + a5d076f commit e9d0cd9
Show file tree
Hide file tree
Showing 39 changed files with 847 additions and 725 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"crates/wallet",
"crates/chain",
"crates/core",
"crates/file_store",
"crates/electrum",
"crates/esplora",
Expand Down
7 changes: 4 additions & 3 deletions crates/bitcoind_rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ readme = "README.md"
[dependencies]
bitcoin = { version = "0.32.0", default-features = false }
bitcoincore-rpc = { version = "0.19.0" }
bdk_chain = { path = "../chain", version = "0.17", default-features = false }
bdk_core = { path = "../core", version = "0.1", default-features = false }

[dev-dependencies]
bdk_testenv = { path = "../testenv", default-features = false }
bdk_chain = { path = "../chain", version = "0.17" }

[features]
default = ["std"]
std = ["bitcoin/std", "bdk_chain/std"]
serde = ["bitcoin/serde", "bdk_chain/serde"]
std = ["bitcoin/std", "bdk_core/std"]
serde = ["bitcoin/serde", "bdk_core/serde"]
2 changes: 1 addition & 1 deletion crates/bitcoind_rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! mempool.
#![warn(missing_docs)]

use bdk_chain::{local_chain::CheckPoint, BlockId};
use bdk_core::{BlockId, CheckPoint};
use bitcoin::{block::Header, Block, BlockHash, Transaction};
pub use bitcoincore_rpc;
use bitcoincore_rpc::bitcoincore_rpc_json;
Expand Down
9 changes: 4 additions & 5 deletions crates/chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ readme = "README.md"

[dependencies]
bitcoin = { version = "0.32.0", default-features = false }
bdk_core = { path = "../core", version = "0.1", default-features = false }
serde = { version = "1", optional = true, features = ["derive", "rc"] }

# Use hashbrown as a feature flag to have HashSet and HashMap from it.
hashbrown = { version = "0.9.1", optional = true, features = ["serde"] }
miniscript = { version = "12.0.0", optional = true, default-features = false }

# Feature dependencies
Expand All @@ -30,6 +28,7 @@ proptest = "1.2.0"

[features]
default = ["std", "miniscript"]
std = ["bitcoin/std", "miniscript?/std"]
serde = ["dep:serde", "bitcoin/serde", "miniscript?/serde"]
std = ["bitcoin/std", "miniscript?/std", "bdk_core/std"]
serde = ["dep:serde", "bitcoin/serde", "miniscript?/serde", "bdk_core/serde"]
hashbrown = ["bdk_core/hashbrown"]
rusqlite = ["std", "dep:rusqlite", "serde", "serde_json"]
93 changes: 5 additions & 88 deletions crates/chain/src/chain_data.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bitcoin::{hashes::Hash, BlockHash, OutPoint, TxOut, Txid};
use crate::ConfirmationBlockTime;
use bitcoin::{OutPoint, TxOut, Txid};

use crate::{Anchor, AnchorFromBlockPosition, COINBASE_MATURITY};
use crate::{Anchor, COINBASE_MATURITY};

/// Represents the observed position of some chain data.
///
Expand Down Expand Up @@ -82,92 +83,6 @@ impl From<ChainPosition<ConfirmationBlockTime>> for ConfirmationTime {
}
}

/// A reference to a block in the canonical chain.
///
/// `BlockId` implements [`Anchor`]. When a transaction is anchored to `BlockId`, the confirmation
/// block and anchor block are the same block.
#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct BlockId {
/// The height of the block.
pub height: u32,
/// The hash of the block.
pub hash: BlockHash,
}

impl Anchor for BlockId {
fn anchor_block(&self) -> Self {
*self
}
}

impl AnchorFromBlockPosition for BlockId {
fn from_block_position(_block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self {
block_id
}
}

impl Default for BlockId {
fn default() -> Self {
Self {
height: Default::default(),
hash: BlockHash::all_zeros(),
}
}
}

impl From<(u32, BlockHash)> for BlockId {
fn from((height, hash): (u32, BlockHash)) -> Self {
Self { height, hash }
}
}

impl From<BlockId> for (u32, BlockHash) {
fn from(block_id: BlockId) -> Self {
(block_id.height, block_id.hash)
}
}

impl From<(&u32, &BlockHash)> for BlockId {
fn from((height, hash): (&u32, &BlockHash)) -> Self {
Self {
height: *height,
hash: *hash,
}
}
}

/// An [`Anchor`] implementation that also records the exact confirmation time of the transaction.
///
/// Refer to [`Anchor`] for more details.
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ConfirmationBlockTime {
/// The anchor block.
pub block_id: BlockId,
/// The confirmation time of the transaction being anchored.
pub confirmation_time: u64,
}

impl Anchor for ConfirmationBlockTime {
fn anchor_block(&self) -> BlockId {
self.block_id
}

fn confirmation_height_upper_bound(&self) -> u32 {
self.block_id.height
}
}

impl AnchorFromBlockPosition for ConfirmationBlockTime {
fn from_block_position(block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self {
Self {
block_id,
confirmation_time: block.header.time as _,
}
}
}

/// A `TxOut` with as much data as we can retrieve about it
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FullTxOut<A> {
Expand Down Expand Up @@ -244,6 +159,8 @@ impl<A: Anchor> FullTxOut<A> {

#[cfg(test)]
mod test {
use crate::BlockId;

use super::*;

#[test]
Expand Down
3 changes: 1 addition & 2 deletions crates/chain/src/example_utils.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#![allow(unused)]
use crate::BlockId;
use alloc::vec::Vec;
use bitcoin::{
consensus,
hashes::{hex::FromHex, Hash},
Transaction,
};

use crate::BlockId;

pub const RAW_TX_1: &str = "0200000000010116d6174da7183d70d0a7d4dc314d517a7d135db79ad63515028b293a76f4f9d10000000000feffffff023a21fc8350060000160014531c405e1881ef192294b8813631e258bf98ea7a1027000000000000225120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c024730440220591b1a172a122da49ba79a3e79f98aaa03fd7a372f9760da18890b6a327e6010022013e82319231da6c99abf8123d7c07e13cf9bd8d76e113e18dc452e5024db156d012102318a2d558b2936c52e320decd6d92a88d7f530be91b6fe0af5caf41661e77da3ef2e0100";
pub const RAW_TX_2: &str = "02000000000101a688607020cfae91a61e7c516b5ef1264d5d77f17200c3866826c6c808ebf1620000000000feffffff021027000000000000225120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c20fd48ff530600001600146886c525e41d4522042bd0b159dfbade2504a6bb024730440220740ff7e665cd20565d4296b549df8d26b941be3f1e3af89a0b60e50c0dbeb69a02206213ab7030cf6edc6c90d4ccf33010644261e029950a688dc0b1a9ebe6ddcc5a012102f2ac6b396a97853cb6cd62242c8ae4842024742074475023532a51e9c53194253e760100";
pub const RAW_TX_3: &str = "0200000000010135d67ee47b557e68b8c6223958f597381965ed719f1207ee2b9e20432a24a5dc0100000000feffffff021027000000000000225120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb62215a5055060000160014070df7671dea67a50c4799a744b5c9be8f4bac690247304402207ebf8d29f71fd03e7e6977b3ea78ca5fcc5c49a42ae822348fc401862fdd766c02201d7e4ff0684ecb008b6142f36ead1b0b4d615524c4f58c261113d361f4427e25012103e6a75e2fab85e5ecad641afc4ffba7222f998649d9f18cac92f0fcc8618883b3ee760100";
Expand Down
6 changes: 3 additions & 3 deletions crates/chain/src/indexed_tx_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ where

/// Apply an `update` directly.
///
/// `update` is a [`tx_graph::Update<A>`] and the resultant changes is returned as [`ChangeSet`].
/// `update` is a [`tx_graph::TxUpdate<A>`] and the resultant changes is returned as [`ChangeSet`].
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn apply_update(&mut self, update: tx_graph::Update<A>) -> ChangeSet<A, I::ChangeSet> {
pub fn apply_update(&mut self, update: tx_graph::TxUpdate<A>) -> ChangeSet<A, I::ChangeSet> {
let tx_graph = self.graph.apply_update(update);
let indexer = self.index_tx_graph_changeset(&tx_graph);
ChangeSet { tx_graph, indexer }
Expand All @@ -114,7 +114,7 @@ where
/// set to the current time.
pub fn apply_update_at(
&mut self,
update: tx_graph::Update<A>,
update: tx_graph::TxUpdate<A>,
seen_at: Option<u64>,
) -> ChangeSet<A, I::ChangeSet> {
let tx_graph = self.graph.apply_update_at(update, seen_at);
Expand Down
41 changes: 41 additions & 0 deletions crates/chain/src/indexer/keychain_txout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use crate::{
collections::*,
miniscript::{Descriptor, DescriptorPublicKey},
spk_client::{FullScanRequestBuilder, SyncRequestBuilder},
spk_iter::BIP32_MAX_INDEX,
spk_txout::SpkTxOutIndex,
DescriptorExt, DescriptorId, Indexed, Indexer, KeychainIndexed, SpkIterator,
Expand Down Expand Up @@ -875,3 +876,43 @@ impl Merge for ChangeSet {
self.last_revealed.is_empty()
}
}

/// Trait to extend [`SyncRequestBuilder`].
pub trait SyncRequestBuilderExt<K> {
/// Add [`Script`](bitcoin::Script)s that are revealed by the `indexer` of the given `spk_range`
/// that will be synced against.
fn revealed_spks_from_indexer<R>(self, indexer: &KeychainTxOutIndex<K>, spk_range: R) -> Self
where
R: core::ops::RangeBounds<K>;

/// Add [`Script`](bitcoin::Script)s that are revealed by the `indexer` but currently unused.
fn unused_spks_from_indexer(self, indexer: &KeychainTxOutIndex<K>) -> Self;
}

impl<K: Clone + Ord + core::fmt::Debug> SyncRequestBuilderExt<K> for SyncRequestBuilder<(K, u32)> {
fn revealed_spks_from_indexer<R>(self, indexer: &KeychainTxOutIndex<K>, spk_range: R) -> Self
where
R: core::ops::RangeBounds<K>,
{
self.spks_with_indexes(indexer.revealed_spks(spk_range))
}

fn unused_spks_from_indexer(self, indexer: &KeychainTxOutIndex<K>) -> Self {
self.spks_with_indexes(indexer.unused_spks())
}
}

/// Trait to extend [`FullScanRequestBuilder`].
pub trait FullScanRequestBuilderExt<K> {
/// Add spk iterators for each keychain tracked in `indexer`.
fn spks_from_indexer(self, indexer: &KeychainTxOutIndex<K>) -> Self;
}

impl<K: Clone + Ord + core::fmt::Debug> FullScanRequestBuilderExt<K> for FullScanRequestBuilder<K> {
fn spks_from_indexer(mut self, indexer: &KeychainTxOutIndex<K>) -> Self {
for (keychain, spks) in indexer.all_unbounded_spk_iters() {
self = self.spks_for_keychain(keychain, spks);
}
self
}
}
66 changes: 28 additions & 38 deletions crates/chain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ pub use indexer::spk_txout;
pub use indexer::Indexer;
pub mod local_chain;
mod tx_data_traits;
pub mod tx_graph;
pub use tx_data_traits::*;
pub mod tx_graph;
pub use tx_graph::TxGraph;
mod chain_oracle;
pub use chain_oracle::*;
Expand All @@ -61,7 +61,9 @@ pub use indexer::keychain_txout;
pub use spk_iter::*;
#[cfg(feature = "rusqlite")]
pub mod rusqlite_impl;
pub mod spk_client;

pub extern crate bdk_core;
pub use bdk_core::*;

#[allow(unused_imports)]
#[macro_use]
Expand All @@ -75,45 +77,9 @@ pub extern crate serde;
#[macro_use]
extern crate std;

#[cfg(all(not(feature = "std"), feature = "hashbrown"))]
extern crate hashbrown;

// When no-std use `alloc`'s Hash collections. This is activated by default
#[cfg(all(not(feature = "std"), not(feature = "hashbrown")))]
#[doc(hidden)]
pub mod collections {
#![allow(dead_code)]
pub type HashSet<K> = alloc::collections::BTreeSet<K>;
pub type HashMap<K, V> = alloc::collections::BTreeMap<K, V>;
pub use alloc::collections::{btree_map as hash_map, *};
}

// When we have std, use `std`'s all collections
#[cfg(all(feature = "std", not(feature = "hashbrown")))]
#[doc(hidden)]
pub mod collections {
pub use std::collections::{hash_map, *};
}

// With this special feature `hashbrown`, use `hashbrown`'s hash collections, and else from `alloc`.
#[cfg(feature = "hashbrown")]
#[doc(hidden)]
pub mod collections {
#![allow(dead_code)]
pub type HashSet<K> = hashbrown::HashSet<K>;
pub type HashMap<K, V> = hashbrown::HashMap<K, V>;
pub use alloc::collections::*;
pub use hashbrown::hash_map;
}

/// How many confirmations are needed f or a coinbase output to be spent.
pub const COINBASE_MATURITY: u32 = 100;

/// A tuple of keychain index and `T` representing the indexed value.
pub type Indexed<T> = (u32, T);
/// A tuple of keychain `K`, derivation index (`u32`) and a `T` associated with them.
pub type KeychainIndexed<K, T> = ((K, u32), T);

/// A wrapper that we use to impl remote traits for types in our crate or dependency crates.
pub struct Impl<T>(pub T);

Expand All @@ -137,3 +103,27 @@ impl<T> core::ops::Deref for Impl<T> {
&self.0
}
}

/// A wrapper that we use to impl remote traits for types in our crate or dependency crates that impl [`Anchor`].
pub struct AnchorImpl<T>(pub T);

impl<T> AnchorImpl<T> {
/// Returns the inner `T`.
pub fn into_inner(self) -> T {
self.0
}
}

impl<T> From<T> for AnchorImpl<T> {
fn from(value: T) -> Self {
Self(value)
}
}

impl<T> core::ops::Deref for AnchorImpl<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.0
}
}
Loading

0 comments on commit e9d0cd9

Please sign in to comment.