140 lines
4.9 KiB
Rust
140 lines
4.9 KiB
Rust
// SPDX-License-Identifier: CC0-1.0
|
|
|
|
//! Bitcoin blocks.
|
|
//!
|
|
//! A block is a bundle of transactions with a proof-of-work attached,
|
|
//! which commits to an earlier block to form the blockchain. This
|
|
//! module describes structures and functions needed to describe
|
|
//! these blocks and the blockchain.
|
|
|
|
#[cfg(feature = "arbitrary")]
|
|
use arbitrary::{Arbitrary, Unstructured};
|
|
use hashes::sha256d;
|
|
|
|
/// Bitcoin block version number.
|
|
///
|
|
/// Originally used as a protocol version, but repurposed for soft-fork signaling.
|
|
///
|
|
/// The inner value is a signed integer in Bitcoin Core for historical reasons, if version bits is
|
|
/// being used the top three bits must be 001, this gives us a useful range of [0x20000000...0x3FFFFFFF].
|
|
///
|
|
/// > When a block nVersion does not have top bits 001, it is treated as if all bits are 0 for the purposes of deployments.
|
|
///
|
|
/// ### Relevant BIPs
|
|
///
|
|
/// * [BIP9 - Version bits with timeout and delay](https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki) (current usage)
|
|
/// * [BIP34 - Block v2, Height in Coinbase](https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki)
|
|
#[derive(Copy, PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)]
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
pub struct Version(i32);
|
|
|
|
impl Version {
|
|
/// The original Bitcoin Block v1.
|
|
pub const ONE: Self = Self(1);
|
|
|
|
/// BIP-34 Block v2.
|
|
pub const TWO: Self = Self(2);
|
|
|
|
/// BIP-9 compatible version number that does not signal for any softforks.
|
|
pub const NO_SOFT_FORK_SIGNALLING: Self = Self(Self::USE_VERSION_BITS as i32);
|
|
|
|
/// BIP-9 soft fork signal bits mask.
|
|
const VERSION_BITS_MASK: u32 = 0x1FFF_FFFF;
|
|
|
|
/// 32bit value starting with `001` to use version bits.
|
|
///
|
|
/// The value has the top three bits `001` which enables the use of version bits to signal for soft forks.
|
|
const USE_VERSION_BITS: u32 = 0x2000_0000;
|
|
|
|
/// Creates a [`Version`] from a signed 32 bit integer value.
|
|
///
|
|
/// This is the data type used in consensus code in Bitcoin Core.
|
|
#[inline]
|
|
pub const fn from_consensus(v: i32) -> Self { Version(v) }
|
|
|
|
/// Returns the inner `i32` value.
|
|
///
|
|
/// This is the data type used in consensus code in Bitcoin Core.
|
|
pub fn to_consensus(self) -> i32 { self.0 }
|
|
|
|
/// Checks whether the version number is signalling a soft fork at the given bit.
|
|
///
|
|
/// A block is signalling for a soft fork under BIP-9 if the first 3 bits are `001` and
|
|
/// the version bit for the specific soft fork is toggled on.
|
|
pub fn is_signalling_soft_fork(&self, bit: u8) -> bool {
|
|
// Only bits [0, 28] inclusive are used for signalling.
|
|
if bit > 28 {
|
|
return false;
|
|
}
|
|
|
|
// To signal using version bits, the first three bits must be `001`.
|
|
if (self.0 as u32) & !Self::VERSION_BITS_MASK != Self::USE_VERSION_BITS {
|
|
return false;
|
|
}
|
|
|
|
// The bit is set if signalling a soft fork.
|
|
(self.0 as u32 & Self::VERSION_BITS_MASK) & (1 << bit) > 0
|
|
}
|
|
}
|
|
|
|
impl Default for Version {
|
|
fn default() -> Version { Self::NO_SOFT_FORK_SIGNALLING }
|
|
}
|
|
|
|
hashes::hash_newtype! {
|
|
/// A bitcoin block hash.
|
|
pub struct BlockHash(sha256d::Hash);
|
|
/// A hash corresponding to the witness structure commitment in the coinbase transaction.
|
|
pub struct WitnessCommitment(sha256d::Hash);
|
|
}
|
|
|
|
impl BlockHash {
|
|
/// Dummy hash used as the previous blockhash of the genesis block.
|
|
pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]);
|
|
}
|
|
|
|
#[cfg(feature = "arbitrary")]
|
|
impl<'a> Arbitrary<'a> for Version {
|
|
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
|
// Equally weight known versions and arbitrary versions
|
|
let choice = u.int_in_range(0..=3)?;
|
|
match choice {
|
|
0 => Ok(Version::ONE),
|
|
1 => Ok(Version::TWO),
|
|
2 => Ok(Version::NO_SOFT_FORK_SIGNALLING),
|
|
_ => Ok(Version::from_consensus(u.arbitrary()?)),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_version_is_not_signalling_with_invalid_bit() {
|
|
let arbitrary_version = Version::from_consensus(1234567890);
|
|
// The max bit number to signal is 28.
|
|
assert!(!Version::is_signalling_soft_fork(&arbitrary_version, 29));
|
|
}
|
|
|
|
#[test]
|
|
fn test_version_is_not_signalling_when_use_version_bit_not_set() {
|
|
let version = Version::from_consensus(0b01000000000000000000000000000000);
|
|
// Top three bits must be 001 to signal.
|
|
assert!(!Version::is_signalling_soft_fork(&version, 1));
|
|
}
|
|
|
|
#[test]
|
|
fn test_version_is_signalling() {
|
|
let version = Version::from_consensus(0b00100000000000000000000000000010);
|
|
assert!(Version::is_signalling_soft_fork(&version, 1));
|
|
}
|
|
|
|
#[test]
|
|
fn test_version_is_not_signalling() {
|
|
let version = Version::from_consensus(0b00100000000000000000000000000010);
|
|
assert!(!Version::is_signalling_soft_fork(&version, 0));
|
|
}
|
|
}
|