bitcoin_ext/
lib.rs

1
2#[macro_use] extern crate lazy_static;
3#[macro_use] extern crate serde as serde_crate;
4
5pub extern crate bitcoin;
6
7pub mod cpfp;
8pub mod fee;
9
10#[cfg(feature = "bdk")]
11pub mod bdk;
12#[cfg(feature = "esplora")]
13pub mod esplora;
14#[cfg(feature = "rpc")]
15pub mod rpc;
16pub mod serde;
17
18pub use mbitcoin::{
19	AmountExt, FeeRateExt, TaprootSpendInfoExt, KeypairExt, TransactionExt, TxOutExt,
20};
21
22#[path = "bitcoin.rs"]
23mod mbitcoin;
24
25use std::{fmt, str::FromStr};
26
27use bitcoin::{Amount, BlockHash};
28
29/// The number of confirmations after which we don't expect a
30/// re-org to ever happen.
31pub const DEEPLY_CONFIRMED: BlockHeight = 100;
32
33pub const P2TR_DUST_VB: u64 = 110;
34/// 330 satoshis
35pub const P2TR_DUST_SAT: u64 = P2TR_DUST_VB * 3;
36pub const P2TR_DUST: Amount = Amount::from_sat(P2TR_DUST_SAT);
37
38pub const P2WPKH_DUST_VB: u64 = 90;
39/// 294 satoshis
40pub const P2WPKH_DUST_SAT: u64 = P2WPKH_DUST_VB * 3;
41pub const P2WPKH_DUST: Amount = Amount::from_sat(P2WPKH_DUST_SAT);
42
43pub const P2PKH_DUST_VB: u64 = 182;
44/// 546 satoshis
45pub const P2PKH_DUST_SAT: u64 = P2PKH_DUST_VB * 3;
46pub const P2PKH_DUST: Amount = Amount::from_sat(P2PKH_DUST_SAT);
47
48pub const P2SH_DUST_VB: u64 = 180;
49/// 540 satoshis
50pub const P2SH_DUST_SAT: u64 = P2SH_DUST_VB * 3;
51pub const P2SH_DUST: Amount = Amount::from_sat(P2SH_DUST_SAT);
52
53pub const P2WSH_DUST_VB: u64 = 110;
54/// 330 satoshis
55pub const P2WSH_DUST_SAT: u64 = P2WSH_DUST_VB * 3;
56pub const P2WSH_DUST: Amount = Amount::from_sat(P2WSH_DUST_SAT);
57
58/// Witness weight of a taproot keyspend.
59pub const TAPROOT_KEYSPEND_WEIGHT: usize = 66;
60
61/// Type representing a block height in the bitcoin blockchain.
62pub type BlockHeight = u32;
63/// Type representing a block height delta
64pub type BlockDelta = u16;
65/// Reference to a block in the chain
66///
67/// String representation is "<height>:<hash>".
68#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
69pub struct BlockRef {
70	pub height: BlockHeight,
71	pub hash: BlockHash,
72}
73
74impl fmt::Display for BlockRef {
75	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76		write!(f, "{}:{}", self.height, self.hash)
77	}
78}
79
80impl fmt::Debug for BlockRef {
81	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82		fmt::Display::fmt(self, f)
83	}
84}
85
86impl FromStr for BlockRef {
87	type Err = &'static str;
88
89	fn from_str(s: &str) -> Result<Self, Self::Err> {
90		let mut parts = s.splitn(2, ':');
91		Ok(BlockRef {
92			height: parts.next().expect("always one part")
93				.parse().map_err(|_| "invalid height")?,
94			hash: parts.next().ok_or("should be <height>:<hash> string")?
95				.parse().map_err(|_| "invalid hash")?,
96		})
97	}
98}
99
100impl serde_crate::Serialize for BlockRef {
101	fn serialize<S: serde_crate::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
102		s.collect_str(self)
103	}
104}
105
106impl<'de> serde_crate::Deserialize<'de> for BlockRef {
107	fn deserialize<D: serde_crate::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
108		struct Visitor;
109		impl<'de> serde_crate::de::Visitor<'de> for Visitor {
110			type Value = BlockRef;
111			fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112				write!(f, "a BlockRef")
113			}
114			fn visit_str<E: serde_crate::de::Error>(self, v: &str) -> Result<Self::Value, E> {
115				BlockRef::from_str(v).map_err(serde_crate::de::Error::custom)
116			}
117		}
118		d.deserialize_str(Visitor)
119	}
120}
121
122#[cfg(feature = "bdk")]
123impl From<bdk_wallet::chain::BlockId> for BlockRef {
124	fn from(id: bdk_wallet::chain::BlockId) -> Self {
125		Self {
126			height: id.height,
127			hash: id.hash,
128		}
129	}
130}
131
132#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
133pub enum TxStatus {
134	Confirmed(BlockRef),
135	Mempool,
136	NotFound,
137}
138
139impl TxStatus {
140	pub fn confirmed_height(&self) -> Option<BlockHeight> {
141		match self {
142			TxStatus::Confirmed(block_ref) => Some(block_ref.height),
143			_ => None,
144		}
145	}
146
147	pub fn confirmed_in(&self) -> Option<BlockRef> {
148		match self {
149			TxStatus::Confirmed(block_ref) => Some(*block_ref),
150			_ => None,
151		}
152	}
153}
154