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
74#[derive(Clone)]
75enum SharedRepr {
76 Inline {
77 len: u8,
78 data: [u8; SHARED_BYTE_INLINE_CAP],
79 },
80 Shared(std::sync::Arc<[u8]>),
81}
82
83#[derive(Clone)]
86pub struct SharedByteString(SharedRepr);
87
88impl std::fmt::Debug for SharedByteString {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 f.debug_tuple("SharedByteString")
91 .field(&self.as_slice())
92 .finish()
93 }
94}
95
96impl PartialEq for SharedByteString {
97 #[inline]
98 fn eq(&self, other: &Self) -> bool {
99 self.as_slice() == other.as_slice()
100 }
101}
102
103impl Eq for SharedByteString {}
104
105impl std::hash::Hash for SharedByteString {
106 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
107 self.as_slice().hash(state);
108 }
109}
110
111impl SharedByteString {
112 #[inline]
113 fn as_slice(&self) -> &[u8] {
114 match &self.0 {
115 SharedRepr::Inline { len, data } => &data[..*len as usize],
116 SharedRepr::Shared(a) => a,
117 }
118 }
119
120 #[inline]
121 fn from_bytes(v: &[u8]) -> Self {
122 if v.len() <= SHARED_BYTE_INLINE_CAP {
123 let mut data = [0u8; SHARED_BYTE_INLINE_CAP];
124 data[..v.len()].copy_from_slice(v);
125 Self(SharedRepr::Inline {
126 len: v.len() as u8,
127 data,
128 })
129 } else {
130 Self(SharedRepr::Shared(std::sync::Arc::from(v)))
131 }
132 }
133}
134
135impl std::ops::Deref for SharedByteString {
136 type Target = [u8];
137 #[inline]
138 fn deref(&self) -> &[u8] {
139 self.as_slice()
140 }
141}
142
143impl Serialize for SharedByteString {
144 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
145 self.as_slice().serialize(s)
146 }
147}
148
149impl<'de> Deserialize<'de> for SharedByteString {
150 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
151 let v: Vec<u8> = Deserialize::deserialize(d)?;
152 Ok(Self::from_bytes(&v))
153 }
154}
155
156impl From<ByteString> for SharedByteString {
157 #[inline]
158 fn from(v: ByteString) -> Self {
159 Self::from_bytes(v.as_slice())
160 }
161}
162
163impl From<&[u8]> for SharedByteString {
164 #[inline]
165 fn from(v: &[u8]) -> Self {
166 Self::from_bytes(v)
167 }
168}
169
170impl Default for SharedByteString {
171 #[inline]
172 fn default() -> Self {
173 Self(SharedRepr::Inline {
174 len: 0,
175 data: [0u8; SHARED_BYTE_INLINE_CAP],
176 })
177 }
178}
179
180impl AsRef<[u8]> for SharedByteString {
181 #[inline]
182 fn as_ref(&self) -> &[u8] {
183 self.as_slice()
184 }
185}
186
187impl SharedByteString {
188 #[inline]
190 pub fn as_arc(&self) -> std::sync::Arc<[u8]> {
191 match &self.0 {
192 SharedRepr::Shared(a) => std::sync::Arc::clone(a),
193 SharedRepr::Inline { len, data } => {
194 std::sync::Arc::from(data[..*len as usize].to_vec().into_boxed_slice())
195 }
196 }
197 }
198}
199
200pub type Natural = u64;
202
203pub type Integer = i64;
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
210pub enum Network {
211 Mainnet,
213 Testnet,
215 Regtest,
217 Signet,
219}
220
221#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226pub struct TimeContext {
227 pub network_time: u64,
230 pub median_time_past: u64,
233}
234
235#[derive(Debug, Clone, Copy, PartialEq, Eq)]
242pub struct Bip54BoundaryTimestamps {
243 pub timestamp_n_minus_1: u64,
245 pub timestamp_n_minus_2015: u64,
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
254pub enum ForkId {
255 Bip30,
257 Bip16,
259 Bip34,
261 Bip66,
263 Bip65,
265 Bip112,
267 Bip147,
269 SegWit,
271 Taproot,
273 Ctv,
275 Csfs,
277 Bip54,
279}
280
281impl Network {
282 pub fn from_env() -> Self {
290 match std::env::var("BITCOIN_NETWORK").as_deref() {
291 Ok("testnet") => Network::Testnet,
292 Ok("regtest") => Network::Regtest,
293 Ok("signet") => Network::Signet,
294 _ => Network::Mainnet,
295 }
296 }
297
298 pub fn hrp(&self) -> &'static str {
302 match self {
303 Network::Mainnet => "bc",
304 Network::Testnet => "tb",
305 Network::Regtest => "bcrt",
306 Network::Signet => "tb",
307 }
308 }
309}
310
311#[repr(transparent)]
316#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
317pub struct BlockHeight(pub u64);
318
319impl BlockHeight {
320 #[inline(always)]
322 pub fn new(height: u64) -> Self {
323 BlockHeight(height)
324 }
325
326 #[inline(always)]
328 pub fn as_u64(self) -> u64 {
329 self.0
330 }
331}
332
333impl From<u64> for BlockHeight {
334 #[inline(always)]
335 fn from(height: u64) -> Self {
336 BlockHeight(height)
337 }
338}
339
340impl From<BlockHeight> for u64 {
341 #[inline(always)]
342 fn from(height: BlockHeight) -> Self {
343 height.0
344 }
345}
346
347impl std::ops::Deref for BlockHeight {
348 type Target = u64;
349
350 #[inline(always)]
351 fn deref(&self) -> &Self::Target {
352 &self.0
353 }
354}
355
356#[repr(transparent)]
361#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
362pub struct BlockHash(pub Hash);
363
364impl BlockHash {
365 #[inline(always)]
367 pub fn new(hash: Hash) -> Self {
368 BlockHash(hash)
369 }
370
371 #[inline(always)]
373 pub fn as_hash(self) -> Hash {
374 self.0
375 }
376
377 #[inline(always)]
379 pub fn as_hash_ref(&self) -> &Hash {
380 &self.0
381 }
382}
383
384impl From<Hash> for BlockHash {
385 #[inline(always)]
386 fn from(hash: Hash) -> Self {
387 BlockHash(hash)
388 }
389}
390
391impl From<BlockHash> for Hash {
392 #[inline(always)]
393 fn from(hash: BlockHash) -> Self {
394 hash.0
395 }
396}
397
398impl std::ops::Deref for BlockHash {
399 type Target = Hash;
400
401 #[inline(always)]
402 fn deref(&self) -> &Self::Target {
403 &self.0
404 }
405}
406
407#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
411pub struct OutPoint {
412 pub hash: Hash,
413 pub index: u32,
414}
415
416#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
421pub struct TransactionInput {
422 pub prevout: OutPoint, pub sequence: Natural, pub script_sig: ByteString, }
426
427#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
429pub struct TransactionOutput {
430 pub value: Integer,
431 pub script_pubkey: ByteString,
432}
433
434#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
439pub struct Transaction {
440 pub version: Natural,
441 #[cfg(feature = "production")]
442 pub inputs: SmallVec<[TransactionInput; 2]>,
443 #[cfg(not(feature = "production"))]
444 pub inputs: Vec<TransactionInput>,
445 #[cfg(feature = "production")]
446 pub outputs: SmallVec<[TransactionOutput; 2]>,
447 #[cfg(not(feature = "production"))]
448 pub outputs: Vec<TransactionOutput>,
449 pub lock_time: Natural,
450}
451
452#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
457pub struct BlockHeader {
458 pub version: Integer,
459 pub prev_block_hash: Hash,
460 pub merkle_root: Hash,
461 pub timestamp: Natural,
462 pub bits: Natural,
463 pub nonce: Natural,
464}
465
466impl std::convert::AsRef<BlockHeader> for BlockHeader {
467 #[inline]
468 fn as_ref(&self) -> &BlockHeader {
469 self
470 }
471}
472
473#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
479pub struct Block {
480 pub header: BlockHeader,
481 pub transactions: Box<[Transaction]>,
482}
483
484#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
486pub struct UTXO {
487 pub value: Integer,
488 pub script_pubkey: SharedByteString,
489 pub height: Natural,
490 pub is_coinbase: bool,
493}
494
495#[cfg(feature = "production")]
500pub type UtxoSet = FxHashMap<OutPoint, std::sync::Arc<UTXO>>;
501
502#[cfg(not(feature = "production"))]
503pub type UtxoSet = HashMap<OutPoint, std::sync::Arc<UTXO>>;
504
505#[inline]
509pub fn utxo_set_with_capacity(n: usize) -> UtxoSet {
510 #[cfg(feature = "production")]
511 {
512 FxHashMap::with_capacity_and_hasher(n, Default::default())
513 }
514 #[cfg(not(feature = "production"))]
515 {
516 HashMap::with_capacity(n)
517 }
518}
519
520#[inline]
522pub fn utxo_set_insert(set: &mut UtxoSet, op: OutPoint, u: UTXO) {
523 use std::sync::Arc;
524 set.insert(op, Arc::new(u));
525}
526
527#[must_use = "Validation result must be checked - ignoring may cause consensus violations"]
532#[derive(Debug, Clone, PartialEq, Eq)]
533pub enum ValidationResult {
534 Valid,
535 Invalid(String),
536}
537
538#[derive(Debug, Clone)]
540pub struct ScriptContext {
541 pub script_sig: ByteString,
542 pub script_pubkey: ByteString,
543 pub witness: Option<ByteString>,
544 pub flags: u32,
545}
546
547#[derive(Debug, Clone)]
549pub struct BlockContext {
550 pub height: Natural,
551 pub prev_headers: Vec<BlockHeader>,
552 pub utxo_set: UtxoSet,
553}