use serde::{Deserialize, Serialize};
#[cfg(feature = "production")]
use rustc_hash::FxHashMap;
#[cfg(feature = "production")]
use smallvec::SmallVec;
#[cfg(not(feature = "production"))]
use std::collections::HashMap;
#[cfg(feature = "production")]
pub use smallvec;
#[cfg(feature = "production")]
#[macro_export]
macro_rules! tx_inputs {
($($item:expr),* $(,)?) => {
{
$crate::smallvec::SmallVec::from_vec(vec![$($item),*])
}
};
}
#[cfg(not(feature = "production"))]
#[macro_export]
macro_rules! tx_inputs {
($($item:expr),* $(,)?) => {
vec![$($item),*]
};
}
#[cfg(feature = "production")]
#[macro_export]
macro_rules! tx_outputs {
($($item:expr),* $(,)?) => {
{
$crate::smallvec::SmallVec::from_vec(vec![$($item),*])
}
};
}
#[cfg(not(feature = "production"))]
#[macro_export]
macro_rules! tx_outputs {
($($item:expr),* $(,)?) => {
vec![$($item),*]
};
}
pub type Hash = [u8; 32];
pub type ByteString = Vec<u8>;
pub type Witness = Vec<ByteString>;
const SHARED_BYTE_INLINE_CAP: usize = 25;
#[derive(Clone)]
enum SharedRepr {
Inline {
len: u8,
data: [u8; SHARED_BYTE_INLINE_CAP],
},
Shared(std::sync::Arc<[u8]>),
}
#[derive(Clone)]
pub struct SharedByteString(SharedRepr);
impl std::fmt::Debug for SharedByteString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("SharedByteString")
.field(&self.as_slice())
.finish()
}
}
impl PartialEq for SharedByteString {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl Eq for SharedByteString {}
impl std::hash::Hash for SharedByteString {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_slice().hash(state);
}
}
impl SharedByteString {
#[inline]
fn as_slice(&self) -> &[u8] {
match &self.0 {
SharedRepr::Inline { len, data } => &data[..*len as usize],
SharedRepr::Shared(a) => a,
}
}
#[inline]
fn from_bytes(v: &[u8]) -> Self {
if v.len() <= SHARED_BYTE_INLINE_CAP {
let mut data = [0u8; SHARED_BYTE_INLINE_CAP];
data[..v.len()].copy_from_slice(v);
Self(SharedRepr::Inline {
len: v.len() as u8,
data,
})
} else {
Self(SharedRepr::Shared(std::sync::Arc::from(v)))
}
}
}
impl std::ops::Deref for SharedByteString {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.as_slice()
}
}
impl Serialize for SharedByteString {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.as_slice().serialize(s)
}
}
impl<'de> Deserialize<'de> for SharedByteString {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let v: Vec<u8> = Deserialize::deserialize(d)?;
Ok(Self::from_bytes(&v))
}
}
impl From<ByteString> for SharedByteString {
#[inline]
fn from(v: ByteString) -> Self {
Self::from_bytes(v.as_slice())
}
}
impl From<&[u8]> for SharedByteString {
#[inline]
fn from(v: &[u8]) -> Self {
Self::from_bytes(v)
}
}
impl Default for SharedByteString {
#[inline]
fn default() -> Self {
Self(SharedRepr::Inline {
len: 0,
data: [0u8; SHARED_BYTE_INLINE_CAP],
})
}
}
impl AsRef<[u8]> for SharedByteString {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl SharedByteString {
#[inline]
pub fn as_arc(&self) -> std::sync::Arc<[u8]> {
match &self.0 {
SharedRepr::Shared(a) => std::sync::Arc::clone(a),
SharedRepr::Inline { len, data } => {
std::sync::Arc::from(data[..*len as usize].to_vec().into_boxed_slice())
}
}
}
}
pub type Natural = u64;
pub type Integer = i64;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Network {
Mainnet,
Testnet,
Regtest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TimeContext {
pub network_time: u64,
pub median_time_past: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Bip54BoundaryTimestamps {
pub timestamp_n_minus_1: u64,
pub timestamp_n_minus_2015: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ForkId {
Bip30,
Bip16,
Bip34,
Bip66,
Bip65,
Bip112,
Bip147,
SegWit,
Taproot,
Ctv,
Csfs,
Bip54,
}
impl Network {
pub fn from_env() -> Self {
match std::env::var("BITCOIN_NETWORK").as_deref() {
Ok("testnet") => Network::Testnet,
Ok("regtest") => Network::Regtest,
_ => Network::Mainnet,
}
}
pub fn hrp(&self) -> &'static str {
match self {
Network::Mainnet => "bc",
Network::Testnet => "tb",
Network::Regtest => "bcrt",
}
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct BlockHeight(pub u64);
impl BlockHeight {
#[inline(always)]
pub fn new(height: u64) -> Self {
BlockHeight(height)
}
#[inline(always)]
pub fn as_u64(self) -> u64 {
self.0
}
}
impl From<u64> for BlockHeight {
#[inline(always)]
fn from(height: u64) -> Self {
BlockHeight(height)
}
}
impl From<BlockHeight> for u64 {
#[inline(always)]
fn from(height: BlockHeight) -> Self {
height.0
}
}
impl std::ops::Deref for BlockHeight {
type Target = u64;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BlockHash(pub Hash);
impl BlockHash {
#[inline(always)]
pub fn new(hash: Hash) -> Self {
BlockHash(hash)
}
#[inline(always)]
pub fn as_hash(self) -> Hash {
self.0
}
#[inline(always)]
pub fn as_hash_ref(&self) -> &Hash {
&self.0
}
}
impl From<Hash> for BlockHash {
#[inline(always)]
fn from(hash: Hash) -> Self {
BlockHash(hash)
}
}
impl From<BlockHash> for Hash {
#[inline(always)]
fn from(hash: BlockHash) -> Self {
hash.0
}
}
impl std::ops::Deref for BlockHash {
type Target = Hash;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct OutPoint {
pub hash: Hash,
pub index: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TransactionInput {
pub prevout: OutPoint, pub sequence: Natural, pub script_sig: ByteString, }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TransactionOutput {
pub value: Integer,
pub script_pubkey: ByteString,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Transaction {
pub version: Natural,
#[cfg(feature = "production")]
pub inputs: SmallVec<[TransactionInput; 2]>,
#[cfg(not(feature = "production"))]
pub inputs: Vec<TransactionInput>,
#[cfg(feature = "production")]
pub outputs: SmallVec<[TransactionOutput; 2]>,
#[cfg(not(feature = "production"))]
pub outputs: Vec<TransactionOutput>,
pub lock_time: Natural,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct BlockHeader {
pub version: Integer,
pub prev_block_hash: Hash,
pub merkle_root: Hash,
pub timestamp: Natural,
pub bits: Natural,
pub nonce: Natural,
}
impl std::convert::AsRef<BlockHeader> for BlockHeader {
#[inline]
fn as_ref(&self) -> &BlockHeader {
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Block {
pub header: BlockHeader,
pub transactions: Box<[Transaction]>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct UTXO {
pub value: Integer,
pub script_pubkey: SharedByteString,
pub height: Natural,
pub is_coinbase: bool,
}
#[cfg(feature = "production")]
pub type UtxoSet = FxHashMap<OutPoint, std::sync::Arc<UTXO>>;
#[cfg(not(feature = "production"))]
pub type UtxoSet = HashMap<OutPoint, std::sync::Arc<UTXO>>;
#[inline]
pub fn utxo_set_with_capacity(n: usize) -> UtxoSet {
#[cfg(feature = "production")]
{
FxHashMap::with_capacity_and_hasher(n, Default::default())
}
#[cfg(not(feature = "production"))]
{
HashMap::with_capacity(n)
}
}
#[inline]
pub fn utxo_set_insert(set: &mut UtxoSet, op: OutPoint, u: UTXO) {
use std::sync::Arc;
set.insert(op, Arc::new(u));
}
#[must_use = "Validation result must be checked - ignoring may cause consensus violations"]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValidationResult {
Valid,
Invalid(String),
}
#[derive(Debug, Clone)]
pub struct ScriptContext {
pub script_sig: ByteString,
pub script_pubkey: ByteString,
pub witness: Option<ByteString>,
pub flags: u32,
}
#[derive(Debug, Clone)]
pub struct BlockContext {
pub height: Natural,
pub prev_headers: Vec<BlockHeader>,
pub utxo_set: UtxoSet,
}