This is an initial version with `chain_data` types ported over.
Types ported over include `BlockId`, `ConfirmationBlockTime`. The impls
for `Anchor` and `AnchorFromBlockPosition` of these types are moved to
where the traits are defined.
members = [
"crates/wallet",
"crates/chain",
+ "crates/core",
"crates/file_store",
"crates/electrum",
"crates/esplora",
[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
[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"]
-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.
///
}
}
-/// 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> {
#[cfg(test)]
mod test {
+ use crate::BlockId;
+
use super::*;
#[test]
#![allow(unused)]
+use crate::BlockId;
use alloc::vec::Vec;
use bitcoin::{
consensus,
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";
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::*;
pub mod rusqlite_impl;
pub mod spk_client;
+pub extern crate bdk_core;
+pub use bdk_core::*;
+
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;
#[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;
&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
+ }
+}
}
}
-impl<A: Anchor + serde::de::DeserializeOwned> FromSql for Impl<A> {
+impl<A: Anchor + serde::de::DeserializeOwned> FromSql for AnchorImpl<A> {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
serde_json::from_str(value.as_str()?)
- .map(Impl)
+ .map(AnchorImpl)
.map_err(from_sql_error)
}
}
-impl<A: Anchor + serde::Serialize> ToSql for Impl<A> {
+impl<A: Anchor + serde::Serialize> ToSql for AnchorImpl<A> {
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
serde_json::to_string(&self.0)
.map(Into::into)
))?;
let row_iter = statement.query_map([], |row| {
Ok((
- row.get::<_, Impl<A>>("json(anchor)")?,
+ row.get::<_, AnchorImpl<A>>("json(anchor)")?,
row.get::<_, Impl<bitcoin::Txid>>("txid")?,
))
})?;
for row in row_iter {
- let (Impl(anchor), Impl(txid)) = row?;
+ let (AnchorImpl(anchor), Impl(txid)) = row?;
changeset.anchors.insert((anchor, txid));
}
":txid": Impl(*txid),
":block_height": anchor_block.height,
":block_hash": Impl(anchor_block.hash),
- ":anchor": Impl(anchor.clone()),
+ ":anchor": AnchorImpl(anchor.clone()),
})?;
}
alloc::{boxed::Box, collections::VecDeque, vec::Vec},
collections::BTreeMap,
local_chain::CheckPoint,
- ConfirmationBlockTime, Indexed,
+ Indexed,
};
+use bdk_core::ConfirmationBlockTime;
use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
type InspectSync<I> = dyn FnMut(SyncItem<I>, SyncProgress) + Send + 'static;
-use crate::collections::BTreeMap;
-use crate::collections::BTreeSet;
-use crate::BlockId;
+use crate::collections::{BTreeMap, BTreeSet};
+use crate::{BlockId, ConfirmationBlockTime};
use alloc::vec::Vec;
/// Trait that "anchors" blockchain data to a specific block of height and hash.
}
}
+impl Anchor for BlockId {
+ fn anchor_block(&self) -> Self {
+ *self
+ }
+}
+
+impl Anchor for ConfirmationBlockTime {
+ fn anchor_block(&self) -> BlockId {
+ self.block_id
+ }
+
+ fn confirmation_height_upper_bound(&self) -> u32 {
+ self.block_id.height
+ }
+}
+
/// An [`Anchor`] that can be constructed from a given block, block height and transaction position
/// within the block.
pub trait AnchorFromBlockPosition: Anchor {
fn from_block_position(block: &bitcoin::Block, block_id: BlockId, tx_pos: usize) -> Self;
}
+impl AnchorFromBlockPosition for BlockId {
+ fn from_block_position(_block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self {
+ block_id
+ }
+}
+
+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 _,
+ }
+ }
+}
+
/// Trait that makes an object mergeable.
pub trait Merge: Default {
/// Merge another object of the same type onto `self`.
//! [`try_get_chain_position`]: TxGraph::try_get_chain_position
//! [`insert_txout`]: TxGraph::insert_txout
-use crate::{
- collections::*, Anchor, Balance, BlockId, ChainOracle, ChainPosition, FullTxOut, Merge,
-};
+use crate::collections::*;
+use crate::BlockId;
+use crate::{Anchor, Balance, ChainOracle, ChainPosition, FullTxOut, Merge};
use alloc::collections::vec_deque::VecDeque;
use alloc::sync::Arc;
use alloc::vec::Vec;
#[macro_use]
mod common;
-use bdk_chain::tx_graph::{self, CalculateFeeError};
+use bdk_chain::{collections::*, BlockId, ConfirmationBlockTime};
use bdk_chain::{
- collections::*,
local_chain::LocalChain,
+ tx_graph::{self, CalculateFeeError},
tx_graph::{ChangeSet, TxGraph},
- Anchor, BlockId, ChainOracle, ChainPosition, ConfirmationBlockTime, Merge,
+ Anchor, ChainOracle, ChainPosition, Merge,
};
use bitcoin::{
absolute, hashes::Hash, transaction, Amount, BlockHash, OutPoint, ScriptBuf, SignedAmount,
--- /dev/null
+[package]
+name = "bdk_core"
+version = "0.1.0"
+edition = "2021"
+rust-version = "1.63"
+homepage = "https://bitcoindevkit.org"
+repository = "https://github.com/bitcoindevkit/bdk"
+documentation = "https://docs.rs/bdk_core"
+description = "Collection of core structures for Bitcoin Dev Kit."
+license = "MIT OR Apache-2.0"
+readme = "README.md"
+
+[dependencies]
+bitcoin = { version = "0.32", default-features = false }
+serde = { version = "1", optional = true, features = ["derive", "rc"] }
+hashbrown = { version = "0.9.1", optional = true }
+
+[features]
+default = ["std"]
+std = ["bitcoin/std"]
+serde = ["dep:serde", "bitcoin/serde", "hashbrown?/serde"]
--- /dev/null
+use bitcoin::{hashes::Hash, BlockHash};
+
+/// A reference to a block in the canonical chain.
+#[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 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,
+ }
+ }
+}
+
+/// Represents the confirmation block and time of a transaction.
+#[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,
+}
--- /dev/null
+//! This crate is a collection of core structures for [Bitcoin Dev Kit].
+
+// only enables the `doc_cfg` feature when the `docsrs` configuration attribute is defined
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![cfg_attr(
+ docsrs,
+ doc(html_logo_url = "https://github.com/bitcoindevkit/bdk/raw/master/static/bdk.png")
+)]
+#![no_std]
+#![warn(missing_docs)]
+
+pub use bitcoin;
+
+#[allow(unused_imports)]
+#[macro_use]
+extern crate alloc;
+
+#[allow(unused_imports)]
+#[cfg(feature = "std")]
+#[macro_use]
+extern crate std;
+
+#[cfg(feature = "serde")]
+pub extern crate serde;
+
+#[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;
+}
+
+mod chain_data;
+pub use chain_data::*;
-use bdk_chain::ConfirmationBlockTime;
use serde_json::json;
use std::cmp;
use std::collections::HashMap;
psbt::PsbtExt,
Descriptor, DescriptorPublicKey,
};
+use bdk_chain::ConfirmationBlockTime;
use bdk_chain::{
indexed_tx_graph,
indexer::keychain_txout::{self, KeychainTxOutIndex},