1use serde::{Deserialize, Serialize};
4
5#[cfg(feature = "production")]
6use rustc_hash::FxHashMap;
7#[cfg(feature = "production")]
8use smallvec::SmallVec;
9#[cfg(not(feature = "production"))]
10use std::collections::HashMap;
11
12#[cfg(feature = "production")]
14pub use smallvec;
15
16#[cfg(feature = "production")]
18#[macro_export]
19macro_rules! tx_inputs {
20 ($($item:expr),* $(,)?) => {
21 {
22 $crate::smallvec::SmallVec::from_vec(vec![$($item),*])
23 }
24 };
25}
26
27#[cfg(not(feature = "production"))]
28#[macro_export]
29macro_rules! tx_inputs {
30 ($($item:expr),* $(,)?) => {
31 vec![$($item),*]
32 };
33}
34
35#[cfg(feature = "production")]
36#[macro_export]
37macro_rules! tx_outputs {
38 ($($item:expr),* $(,)?) => {
39 {
40 $crate::smallvec::SmallVec::from_vec(vec![$($item),*])
41 }
42 };
43}
44
45#[cfg(not(feature = "production"))]
46#[macro_export]
47macro_rules! tx_outputs {
48 ($($item:expr),* $(,)?) => {
49 vec![$($item),*]
50 };
51}
52
53pub type Hash = [u8; 32];
55
56pub type ByteString = Vec<u8>;
58
59pub type Witness = Vec<ByteString>;
64
65const SHARED_BYTE_INLINE_CAP: usize = 25;
73
74pub static SBS_SHARED_LIVE: std::sync::atomic::AtomicI64 = std::sync::atomic::AtomicI64::new(0);
78pub static SBS_SHARED_TOTAL: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
80
81enum SharedRepr {
82 Inline {
83 len: u8,
84 data: [u8; SHARED_BYTE_INLINE_CAP],
85 },
86 Shared(std::sync::Arc<[u8]>),
87}
88
89#[derive(Clone)]
92pub struct SharedByteString(SharedRepr);
93
94impl std::fmt::Debug for SharedByteString {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 f.debug_tuple("SharedByteString")
97 .field(&self.as_slice())
98 .finish()
99 }
100}
101
102impl PartialEq for SharedByteString {
103 #[inline]
104 fn eq(&self, other: &Self) -> bool {
105 self.as_slice() == other.as_slice()
106 }
107}
108
109impl Eq for SharedByteString {}
110
111impl std::hash::Hash for SharedByteString {
112 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
113 self.as_slice().hash(state);
114 }
115}
116
117impl SharedByteString {
118 #[inline]
119 fn as_slice(&self) -> &[u8] {
120 match &self.0 {
121 SharedRepr::Inline { len, data } => &data[..*len as usize],
122 SharedRepr::Shared(a) => a,
123 }
124 }
125
126 #[inline]
127 fn from_bytes(v: &[u8]) -> Self {
128 if v.len() <= SHARED_BYTE_INLINE_CAP {
129 let mut data = [0u8; SHARED_BYTE_INLINE_CAP];
130 data[..v.len()].copy_from_slice(v);
131 Self(SharedRepr::Inline {
132 len: v.len() as u8,
133 data,
134 })
135 } else {
136 SBS_SHARED_LIVE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
137 SBS_SHARED_TOTAL.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
138 Self(SharedRepr::Shared(std::sync::Arc::from(v)))
139 }
140 }
141}
142
143impl Clone for SharedRepr {
148 fn clone(&self) -> Self {
149 match self {
150 SharedRepr::Inline { len, data } => SharedRepr::Inline {
151 len: *len,
152 data: *data,
153 },
154 SharedRepr::Shared(a) => {
155 SBS_SHARED_LIVE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
156 SharedRepr::Shared(std::sync::Arc::clone(a))
157 }
158 }
159 }
160}
161
162impl Drop for SharedRepr {
163 fn drop(&mut self) {
164 if matches!(self, SharedRepr::Shared(_)) {
165 SBS_SHARED_LIVE.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
166 }
167 }
168}
169
170impl std::ops::Deref for SharedByteString {
171 type Target = [u8];
172 #[inline]
173 fn deref(&self) -> &[u8] {
174 self.as_slice()
175 }
176}
177
178impl Serialize for SharedByteString {
179 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
180 self.as_slice().serialize(s)
181 }
182}
183
184impl<'de> Deserialize<'de> for SharedByteString {
185 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
186 let v: Vec<u8> = Deserialize::deserialize(d)?;
187 Ok(Self::from_bytes(&v))
188 }
189}
190
191impl From<ByteString> for SharedByteString {
192 #[inline]
193 fn from(v: ByteString) -> Self {
194 Self::from_bytes(v.as_slice())
195 }
196}
197
198impl From<&[u8]> for SharedByteString {
199 #[inline]
200 fn from(v: &[u8]) -> Self {
201 Self::from_bytes(v)
202 }
203}
204
205impl Default for SharedByteString {
206 #[inline]
207 fn default() -> Self {
208 Self(SharedRepr::Inline {
209 len: 0,
210 data: [0u8; SHARED_BYTE_INLINE_CAP],
211 })
212 }
213}
214
215impl AsRef<[u8]> for SharedByteString {
216 #[inline]
217 fn as_ref(&self) -> &[u8] {
218 self.as_slice()
219 }
220}
221
222impl SharedByteString {
223 #[inline]
225 pub fn as_arc(&self) -> std::sync::Arc<[u8]> {
226 match &self.0 {
227 SharedRepr::Shared(a) => std::sync::Arc::clone(a),
228 SharedRepr::Inline { len, data } => {
229 std::sync::Arc::from(data[..*len as usize].to_vec().into_boxed_slice())
230 }
231 }
232 }
233}
234
235pub type Natural = u64;
237
238pub type Integer = i64;
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
245pub enum Network {
246 Mainnet,
248 Testnet,
250 Regtest,
252 Signet,
254}
255
256#[derive(Debug, Clone, Copy, PartialEq, Eq)]
261pub struct TimeContext {
262 pub network_time: u64,
265 pub median_time_past: u64,
268}
269
270#[derive(Debug, Clone, Copy, PartialEq, Eq)]
277pub struct Bip54BoundaryTimestamps {
278 pub timestamp_n_minus_1: u64,
280 pub timestamp_n_minus_2015: u64,
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
289pub enum ForkId {
290 Bip30,
292 Bip16,
294 Bip34,
296 Bip66,
298 Bip65,
300 Bip112,
302 Bip147,
304 SegWit,
306 Taproot,
308 Ctv,
310 Csfs,
312 Bip54,
314}
315
316impl Network {
317 pub fn from_env() -> Self {
325 match std::env::var("BITCOIN_NETWORK").as_deref() {
326 Ok("testnet") => Network::Testnet,
327 Ok("regtest") => Network::Regtest,
328 Ok("signet") => Network::Signet,
329 _ => Network::Mainnet,
330 }
331 }
332
333 pub fn hrp(&self) -> &'static str {
337 match self {
338 Network::Mainnet => "bc",
339 Network::Testnet => "tb",
340 Network::Regtest => "bcrt",
341 Network::Signet => "tb",
342 }
343 }
344}
345
346#[repr(transparent)]
351#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
352pub struct BlockHeight(pub u64);
353
354impl BlockHeight {
355 #[inline(always)]
357 pub fn new(height: u64) -> Self {
358 BlockHeight(height)
359 }
360
361 #[inline(always)]
363 pub fn as_u64(self) -> u64 {
364 self.0
365 }
366}
367
368impl From<u64> for BlockHeight {
369 #[inline(always)]
370 fn from(height: u64) -> Self {
371 BlockHeight(height)
372 }
373}
374
375impl From<BlockHeight> for u64 {
376 #[inline(always)]
377 fn from(height: BlockHeight) -> Self {
378 height.0
379 }
380}
381
382impl std::ops::Deref for BlockHeight {
383 type Target = u64;
384
385 #[inline(always)]
386 fn deref(&self) -> &Self::Target {
387 &self.0
388 }
389}
390
391#[repr(transparent)]
396#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
397pub struct BlockHash(pub Hash);
398
399impl BlockHash {
400 #[inline(always)]
402 pub fn new(hash: Hash) -> Self {
403 BlockHash(hash)
404 }
405
406 #[inline(always)]
408 pub fn as_hash(self) -> Hash {
409 self.0
410 }
411
412 #[inline(always)]
414 pub fn as_hash_ref(&self) -> &Hash {
415 &self.0
416 }
417}
418
419impl From<Hash> for BlockHash {
420 #[inline(always)]
421 fn from(hash: Hash) -> Self {
422 BlockHash(hash)
423 }
424}
425
426impl From<BlockHash> for Hash {
427 #[inline(always)]
428 fn from(hash: BlockHash) -> Self {
429 hash.0
430 }
431}
432
433impl std::ops::Deref for BlockHash {
434 type Target = Hash;
435
436 #[inline(always)]
437 fn deref(&self) -> &Self::Target {
438 &self.0
439 }
440}
441
442#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
446pub struct OutPoint {
447 pub hash: Hash,
448 pub index: u32,
449}
450
451#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
456pub struct TransactionInput {
457 pub prevout: OutPoint, pub sequence: Natural, pub script_sig: ByteString, }
461
462#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
464pub struct TransactionOutput {
465 pub value: Integer,
466 pub script_pubkey: ByteString,
467}
468
469#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
474pub struct Transaction {
475 pub version: Natural,
476 #[cfg(feature = "production")]
477 pub inputs: SmallVec<[TransactionInput; 2]>,
478 #[cfg(not(feature = "production"))]
479 pub inputs: Vec<TransactionInput>,
480 #[cfg(feature = "production")]
481 pub outputs: SmallVec<[TransactionOutput; 2]>,
482 #[cfg(not(feature = "production"))]
483 pub outputs: Vec<TransactionOutput>,
484 pub lock_time: Natural,
485}
486
487#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
492pub struct BlockHeader {
493 pub version: Integer,
494 pub prev_block_hash: Hash,
495 pub merkle_root: Hash,
496 pub timestamp: Natural,
497 pub bits: Natural,
498 pub nonce: Natural,
499}
500
501impl std::convert::AsRef<BlockHeader> for BlockHeader {
502 #[inline]
503 fn as_ref(&self) -> &BlockHeader {
504 self
505 }
506}
507
508pub static ARC_BLOCK_CREATED: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
512
513pub static ARC_BLOCKHEADER_CREATED: std::sync::atomic::AtomicU64 =
516 std::sync::atomic::AtomicU64::new(0);
517
518#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
524pub struct Block {
525 pub header: BlockHeader,
526 pub transactions: Box<[Transaction]>,
527}
528
529#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
531pub struct UTXO {
532 pub value: Integer,
533 pub script_pubkey: SharedByteString,
534 pub height: Natural,
535 pub is_coinbase: bool,
538}
539
540#[cfg(feature = "production")]
545pub type UtxoSet = FxHashMap<OutPoint, std::sync::Arc<UTXO>>;
546
547#[cfg(not(feature = "production"))]
548pub type UtxoSet = HashMap<OutPoint, std::sync::Arc<UTXO>>;
549
550#[inline]
554pub fn utxo_set_with_capacity(n: usize) -> UtxoSet {
555 #[cfg(feature = "production")]
556 {
557 FxHashMap::with_capacity_and_hasher(n, Default::default())
558 }
559 #[cfg(not(feature = "production"))]
560 {
561 HashMap::with_capacity(n)
562 }
563}
564
565#[inline]
567pub fn utxo_set_insert(set: &mut UtxoSet, op: OutPoint, u: UTXO) {
568 use std::sync::Arc;
569 set.insert(op, Arc::new(u));
570}
571
572#[must_use = "Validation result must be checked - ignoring may cause consensus violations"]
577#[derive(Debug, Clone, PartialEq, Eq)]
578pub enum ValidationResult {
579 Valid,
580 Invalid(String),
581}
582
583#[derive(Debug, Clone)]
585pub struct ScriptContext {
586 pub script_sig: ByteString,
587 pub script_pubkey: ByteString,
588 pub witness: Option<ByteString>,
589 pub flags: u32,
590}
591
592#[derive(Debug, Clone)]
594pub struct BlockContext {
595 pub height: Natural,
596 pub prev_headers: Vec<BlockHeader>,
597 pub utxo_set: UtxoSet,
598}