1use serde::{Deserialize, Serialize};
4use std::sync::atomic::{AtomicI64, AtomicU64, Ordering};
5
6#[cfg(feature = "production")]
7use rustc_hash::FxHashMap;
8#[cfg(feature = "production")]
9use smallvec::SmallVec;
10#[cfg(not(feature = "production"))]
11use std::collections::HashMap;
12
13#[cfg(feature = "production")]
15pub use smallvec;
16
17#[cfg(feature = "production")]
19#[macro_export]
20macro_rules! tx_inputs {
21 ($($item:expr),* $(,)?) => {
22 {
23 $crate::smallvec::SmallVec::from_vec(vec![$($item),*])
24 }
25 };
26}
27
28#[cfg(not(feature = "production"))]
29#[macro_export]
30macro_rules! tx_inputs {
31 ($($item:expr),* $(,)?) => {
32 vec![$($item),*]
33 };
34}
35
36#[cfg(feature = "production")]
37#[macro_export]
38macro_rules! tx_outputs {
39 ($($item:expr),* $(,)?) => {
40 {
41 $crate::smallvec::SmallVec::from_vec(vec![$($item),*])
42 }
43 };
44}
45
46#[cfg(not(feature = "production"))]
47#[macro_export]
48macro_rules! tx_outputs {
49 ($($item:expr),* $(,)?) => {
50 vec![$($item),*]
51 };
52}
53
54pub type Hash = [u8; 32];
56
57pub type ByteString = Vec<u8>;
59
60pub type Witness = Vec<ByteString>;
65
66const SHARED_BYTE_INLINE_CAP: usize = 25;
74
75pub static SBS_SHARED_LIVE: std::sync::atomic::AtomicI64 = std::sync::atomic::AtomicI64::new(0);
79pub static SBS_SHARED_TOTAL: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
81
82enum SharedRepr {
83 Inline {
84 len: u8,
85 data: [u8; SHARED_BYTE_INLINE_CAP],
86 },
87 Shared(std::sync::Arc<[u8]>),
88}
89
90#[derive(Clone)]
93pub struct SharedByteString(SharedRepr);
94
95impl std::fmt::Debug for SharedByteString {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.debug_tuple("SharedByteString")
98 .field(&self.as_slice())
99 .finish()
100 }
101}
102
103impl PartialEq for SharedByteString {
104 #[inline]
105 fn eq(&self, other: &Self) -> bool {
106 self.as_slice() == other.as_slice()
107 }
108}
109
110impl Eq for SharedByteString {}
111
112impl std::hash::Hash for SharedByteString {
113 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
114 self.as_slice().hash(state);
115 }
116}
117
118impl SharedByteString {
119 #[inline]
120 fn as_slice(&self) -> &[u8] {
121 match &self.0 {
122 SharedRepr::Inline { len, data } => &data[..*len as usize],
123 SharedRepr::Shared(a) => a,
124 }
125 }
126
127 #[inline]
128 fn from_bytes(v: &[u8]) -> Self {
129 if v.len() <= SHARED_BYTE_INLINE_CAP {
130 let mut data = [0u8; SHARED_BYTE_INLINE_CAP];
131 data[..v.len()].copy_from_slice(v);
132 Self(SharedRepr::Inline {
133 len: v.len() as u8,
134 data,
135 })
136 } else {
137 SBS_SHARED_LIVE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
138 SBS_SHARED_TOTAL.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
139 Self(SharedRepr::Shared(std::sync::Arc::from(v)))
140 }
141 }
142}
143
144impl Clone for SharedRepr {
149 fn clone(&self) -> Self {
150 match self {
151 SharedRepr::Inline { len, data } => SharedRepr::Inline {
152 len: *len,
153 data: *data,
154 },
155 SharedRepr::Shared(a) => {
156 SBS_SHARED_LIVE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
157 SharedRepr::Shared(std::sync::Arc::clone(a))
158 }
159 }
160 }
161}
162
163impl Drop for SharedRepr {
164 fn drop(&mut self) {
165 if matches!(self, SharedRepr::Shared(_)) {
166 SBS_SHARED_LIVE.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
167 }
168 }
169}
170
171impl std::ops::Deref for SharedByteString {
172 type Target = [u8];
173 #[inline]
174 fn deref(&self) -> &[u8] {
175 self.as_slice()
176 }
177}
178
179impl Serialize for SharedByteString {
180 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
181 self.as_slice().serialize(s)
182 }
183}
184
185impl<'de> Deserialize<'de> for SharedByteString {
186 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
187 let v: Vec<u8> = Deserialize::deserialize(d)?;
188 Ok(Self::from_bytes(&v))
189 }
190}
191
192impl From<ByteString> for SharedByteString {
193 #[inline]
194 fn from(v: ByteString) -> Self {
195 Self::from_bytes(v.as_slice())
196 }
197}
198
199impl From<&[u8]> for SharedByteString {
200 #[inline]
201 fn from(v: &[u8]) -> Self {
202 Self::from_bytes(v)
203 }
204}
205
206impl Default for SharedByteString {
207 #[inline]
208 fn default() -> Self {
209 Self(SharedRepr::Inline {
210 len: 0,
211 data: [0u8; SHARED_BYTE_INLINE_CAP],
212 })
213 }
214}
215
216impl AsRef<[u8]> for SharedByteString {
217 #[inline]
218 fn as_ref(&self) -> &[u8] {
219 self.as_slice()
220 }
221}
222
223impl SharedByteString {
224 #[inline]
226 pub fn as_arc(&self) -> std::sync::Arc<[u8]> {
227 match &self.0 {
228 SharedRepr::Shared(a) => std::sync::Arc::clone(a),
229 SharedRepr::Inline { len, data } => {
230 std::sync::Arc::from(data[..*len as usize].to_vec().into_boxed_slice())
231 }
232 }
233 }
234}
235
236pub type Natural = u64;
238
239pub type Integer = i64;
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
246pub enum Network {
247 Mainnet,
249 Testnet,
251 Regtest,
253 Signet,
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
262pub struct TimeContext {
263 pub network_time: u64,
266 pub median_time_past: u64,
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq)]
278pub struct Bip54BoundaryTimestamps {
279 pub timestamp_n_minus_1: u64,
281 pub timestamp_n_minus_2015: u64,
283}
284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
290pub enum ForkId {
291 Bip30,
293 Bip16,
295 Bip34,
297 Bip66,
299 Bip65,
301 Bip112,
303 Bip147,
305 SegWit,
307 Taproot,
309 Ctv,
311 Csfs,
313 Bip54,
315}
316
317impl Network {
318 pub fn from_env() -> Self {
326 match std::env::var("BITCOIN_NETWORK").as_deref() {
327 Ok("testnet") => Network::Testnet,
328 Ok("regtest") => Network::Regtest,
329 Ok("signet") => Network::Signet,
330 _ => Network::Mainnet,
331 }
332 }
333
334 pub fn hrp(&self) -> &'static str {
338 match self {
339 Network::Mainnet => "bc",
340 Network::Testnet => "tb",
341 Network::Regtest => "bcrt",
342 Network::Signet => "tb",
343 }
344 }
345}
346
347#[repr(transparent)]
352#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
353pub struct BlockHeight(pub u64);
354
355impl BlockHeight {
356 #[inline(always)]
358 pub fn new(height: u64) -> Self {
359 BlockHeight(height)
360 }
361
362 #[inline(always)]
364 pub fn as_u64(self) -> u64 {
365 self.0
366 }
367}
368
369impl From<u64> for BlockHeight {
370 #[inline(always)]
371 fn from(height: u64) -> Self {
372 BlockHeight(height)
373 }
374}
375
376impl From<BlockHeight> for u64 {
377 #[inline(always)]
378 fn from(height: BlockHeight) -> Self {
379 height.0
380 }
381}
382
383impl std::ops::Deref for BlockHeight {
384 type Target = u64;
385
386 #[inline(always)]
387 fn deref(&self) -> &Self::Target {
388 &self.0
389 }
390}
391
392#[repr(transparent)]
397#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
398pub struct BlockHash(pub Hash);
399
400impl BlockHash {
401 #[inline(always)]
403 pub fn new(hash: Hash) -> Self {
404 BlockHash(hash)
405 }
406
407 #[inline(always)]
409 pub fn as_hash(self) -> Hash {
410 self.0
411 }
412
413 #[inline(always)]
415 pub fn as_hash_ref(&self) -> &Hash {
416 &self.0
417 }
418}
419
420impl From<Hash> for BlockHash {
421 #[inline(always)]
422 fn from(hash: Hash) -> Self {
423 BlockHash(hash)
424 }
425}
426
427impl From<BlockHash> for Hash {
428 #[inline(always)]
429 fn from(hash: BlockHash) -> Self {
430 hash.0
431 }
432}
433
434impl std::ops::Deref for BlockHash {
435 type Target = Hash;
436
437 #[inline(always)]
438 fn deref(&self) -> &Self::Target {
439 &self.0
440 }
441}
442
443#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
447pub struct OutPoint {
448 pub hash: Hash,
449 pub index: u32,
450}
451
452#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
457pub struct TransactionInput {
458 pub prevout: OutPoint, pub sequence: Natural, pub script_sig: ByteString, }
462
463#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
465pub struct TransactionOutput {
466 pub value: Integer,
467 pub script_pubkey: ByteString,
468}
469
470#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
475pub struct Transaction {
476 pub version: Natural,
477 #[cfg(feature = "production")]
478 pub inputs: SmallVec<[TransactionInput; 2]>,
479 #[cfg(not(feature = "production"))]
480 pub inputs: Vec<TransactionInput>,
481 #[cfg(feature = "production")]
482 pub outputs: SmallVec<[TransactionOutput; 2]>,
483 #[cfg(not(feature = "production"))]
484 pub outputs: Vec<TransactionOutput>,
485 pub lock_time: Natural,
486}
487
488#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
493pub struct BlockHeader {
494 pub version: Integer,
495 pub prev_block_hash: Hash,
496 pub merkle_root: Hash,
497 pub timestamp: Natural,
498 pub bits: Natural,
499 pub nonce: Natural,
500}
501
502impl std::convert::AsRef<BlockHeader> for BlockHeader {
503 #[inline]
504 fn as_ref(&self) -> &BlockHeader {
505 self
506 }
507}
508
509pub static ARC_BLOCK_CREATED: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
513
514pub static ARC_BLOCKHEADER_CREATED: std::sync::atomic::AtomicU64 =
517 std::sync::atomic::AtomicU64::new(0);
518
519pub static BLOCK_LIVE: AtomicI64 = AtomicI64::new(0);
524
525pub static LARGE_TX_SLICE_LIVE: AtomicI64 = AtomicI64::new(0);
529
530pub static LARGE_TX_SLICE_BYTES: AtomicU64 = AtomicU64::new(0);
532
533pub const TX_SLICE_LARGE_MIN: usize = 786_432;
535pub const TX_SLICE_LARGE_MAX: usize = 1_572_864;
536
537#[inline]
538pub fn tx_slice_heap_bytes(n_tx: usize) -> usize {
539 n_tx.saturating_mul(std::mem::size_of::<Transaction>())
540}
541
542#[inline]
543fn note_block_new(n_tx: usize) {
544 BLOCK_LIVE.fetch_add(1, Ordering::Relaxed);
545 let b = tx_slice_heap_bytes(n_tx);
546 if (TX_SLICE_LARGE_MIN..=TX_SLICE_LARGE_MAX).contains(&b) {
547 LARGE_TX_SLICE_LIVE.fetch_add(1, Ordering::Relaxed);
548 LARGE_TX_SLICE_BYTES.fetch_add(b as u64, Ordering::Relaxed);
549 }
550}
551
552#[inline]
553fn note_block_drop(n_tx: usize) {
554 BLOCK_LIVE
558 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
559 Some(if v > 0 { v - 1 } else { 0 })
560 })
561 .ok();
562 let b = tx_slice_heap_bytes(n_tx);
563 if (TX_SLICE_LARGE_MIN..=TX_SLICE_LARGE_MAX).contains(&b) {
564 LARGE_TX_SLICE_LIVE
565 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
566 Some(if v > 0 { v - 1 } else { 0 })
567 })
568 .ok();
569 LARGE_TX_SLICE_BYTES
570 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
571 Some(v.saturating_sub(b as u64))
572 })
573 .ok();
574 }
575}
576
577#[derive(Debug, PartialEq, Eq, Serialize)]
583pub struct Block {
584 pub header: BlockHeader,
585 pub transactions: Box<[Transaction]>,
586}
587
588impl Block {
589 pub fn from_parts(header: BlockHeader, transactions: Box<[Transaction]>) -> Self {
592 note_block_new(transactions.len());
593 Self {
594 header,
595 transactions,
596 }
597 }
598}
599
600impl Clone for Block {
601 fn clone(&self) -> Self {
602 Self::from_parts(self.header.clone(), self.transactions.clone())
603 }
604}
605
606impl<'de> Deserialize<'de> for Block {
607 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
608 #[derive(Deserialize)]
609 struct BlockDe {
610 header: BlockHeader,
611 transactions: Box<[Transaction]>,
612 }
613 let raw = BlockDe::deserialize(deserializer)?;
614 note_block_new(raw.transactions.len());
615 Ok(Self {
616 header: raw.header,
617 transactions: raw.transactions,
618 })
619 }
620}
621
622impl Drop for Block {
623 fn drop(&mut self) {
624 note_block_drop(self.transactions.len());
625 }
626}
627
628#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
630pub struct UTXO {
631 pub value: Integer,
632 pub script_pubkey: SharedByteString,
633 pub height: Natural,
634 pub is_coinbase: bool,
637}
638
639#[cfg(feature = "production")]
644pub type UtxoSet = FxHashMap<OutPoint, std::sync::Arc<UTXO>>;
645
646#[cfg(not(feature = "production"))]
647pub type UtxoSet = HashMap<OutPoint, std::sync::Arc<UTXO>>;
648
649#[inline]
653pub fn utxo_set_with_capacity(n: usize) -> UtxoSet {
654 #[cfg(feature = "production")]
655 {
656 FxHashMap::with_capacity_and_hasher(n, Default::default())
657 }
658 #[cfg(not(feature = "production"))]
659 {
660 HashMap::with_capacity(n)
661 }
662}
663
664#[inline]
666pub fn utxo_set_insert(set: &mut UtxoSet, op: OutPoint, u: UTXO) {
667 use std::sync::Arc;
668 set.insert(op, Arc::new(u));
669}
670
671#[must_use = "Validation result must be checked - ignoring may cause consensus violations"]
676#[derive(Debug, Clone, PartialEq, Eq)]
677pub enum ValidationResult {
678 Valid,
679 Invalid(String),
680}
681
682#[derive(Debug, Clone)]
684pub struct ScriptContext {
685 pub script_sig: ByteString,
686 pub script_pubkey: ByteString,
687 pub witness: Option<ByteString>,
688 pub flags: u32,
689}
690
691#[derive(Debug, Clone)]
693pub struct BlockContext {
694 pub height: Natural,
695 pub prev_headers: Vec<BlockHeader>,
696 pub utxo_set: UtxoSet,
697}
698
699#[cfg(test)]
700mod m1_block_live_tests {
701 use super::*;
702
703 #[test]
704 fn dest_ba_1mib_classes_are_tx_slice_widths() {
705 let tsz = std::mem::size_of::<Transaction>();
706 assert_eq!(tx_slice_heap_bytes(4096), 4096 * tsz);
707 assert_eq!(tx_slice_heap_bytes(5120), 5120 * tsz);
708 if tsz == 256 {
710 assert_eq!(tx_slice_heap_bytes(3072), 786_432);
711 assert_eq!(tx_slice_heap_bytes(4096), 1_048_576);
712 assert_eq!(tx_slice_heap_bytes(5120), 1_310_720);
713 assert_eq!(tx_slice_heap_bytes(6144), 1_572_864);
714 assert!((TX_SLICE_LARGE_MIN..=TX_SLICE_LARGE_MAX).contains(&tx_slice_heap_bytes(4096)));
715 assert!((TX_SLICE_LARGE_MIN..=TX_SLICE_LARGE_MAX).contains(&tx_slice_heap_bytes(5120)));
716 }
717 }
718
719 #[test]
720 fn serde_notes_block_live() {
721 let literal = Block {
722 header: BlockHeader::default(),
723 transactions: Vec::new().into_boxed_slice(),
724 };
725 let json = serde_json::to_string(&literal).expect("ser");
726 drop(literal);
727 let before = BLOCK_LIVE.load(Ordering::Relaxed);
728 let decoded: Block = serde_json::from_str(&json).expect("de");
729 assert_eq!(BLOCK_LIVE.load(Ordering::Relaxed), before + 1);
730 drop(decoded);
731 assert_eq!(BLOCK_LIVE.load(Ordering::Relaxed), before);
732 }
733
734 #[test]
735 fn wire_decode_notes_block_live() {
736 use crate::serialization::block::{deserialize_block_with_witnesses, serialize_block};
737 let tx = Transaction {
738 version: 1,
739 inputs: crate::tx_inputs![TransactionInput {
740 prevout: OutPoint {
741 hash: [1; 32],
742 index: 0
743 },
744 script_sig: vec![0x51],
745 sequence: 0xffffffff,
746 }],
747 outputs: crate::tx_outputs![TransactionOutput {
748 value: 50_0000_0000,
749 script_pubkey: vec![0x51],
750 }],
751 lock_time: 0,
752 };
753 let built = Block::from_parts(BlockHeader::default(), vec![tx].into_boxed_slice());
754 let wire = serialize_block(&built);
755 drop(built);
756 let before = BLOCK_LIVE.load(Ordering::Relaxed);
757 let (decoded, _) = deserialize_block_with_witnesses(&wire).expect("wire decode");
758 assert_eq!(BLOCK_LIVE.load(Ordering::Relaxed), before + 1);
759 drop(decoded);
760 assert_eq!(BLOCK_LIVE.load(Ordering::Relaxed), before);
761 }
762
763 #[test]
764 fn drop_floors_live_at_zero() {
765 let before = BLOCK_LIVE.load(Ordering::Relaxed);
766 {
767 let _literal = Block {
768 header: BlockHeader::default(),
769 transactions: Vec::new().into_boxed_slice(),
770 };
771 }
772 assert_eq!(BLOCK_LIVE.load(Ordering::Relaxed), before);
773 }
774}