Merge rust-bitcoin/rust-bitcoin#3437: Move `block::Version` to primitives
70264bfcec
Move block::Version to primitives (Tobin C. Harding)819d8d72e8
Stop using private Version constructor (Tobin C. Harding) Pull request description: This is a straight up move of the whole type because there are only three methods, a getter, a setter, and `is_signalling_soft_fork`. If we use an extension trait for `is_signalling_soft_fork` then we have to make the two private associated consts public which is in my opinion worse. Patch 1 is preparation, use getter/setter, patch 2 does the move. ACKs for top commit: apoelstra: ACK70264bfcec
successfully ran local tests Tree-SHA512: b61e853b4b96cb1cc56c7bfb67cc6c3ba7c631cb9e540393eb780dcf63bd2d934058794f2ac0145b4b5404a6a68887c3a1d225b2d87b57415474c05d3ef2811f
This commit is contained in:
commit
d5ebb19543
|
@ -118,85 +118,15 @@ impl fmt::Debug for Header {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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 }
|
||||
}
|
||||
|
||||
impl Encodable for Version {
|
||||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
self.0.consensus_encode(w)
|
||||
self.to_consensus().consensus_encode(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Version {
|
||||
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
||||
Decodable::consensus_decode(r).map(Version)
|
||||
Decodable::consensus_decode(r).map(Version::from_consensus)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,7 +445,7 @@ mod tests {
|
|||
assert!(decode.is_ok());
|
||||
assert!(bad_decode.is_err());
|
||||
let real_decode = decode.unwrap();
|
||||
assert_eq!(real_decode.header.version, Version(1));
|
||||
assert_eq!(real_decode.header.version, Version::from_consensus(1));
|
||||
assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash);
|
||||
assert_eq!(real_decode.header.merkle_root, real_decode.compute_merkle_root().unwrap());
|
||||
assert_eq!(serialize(&real_decode.header.merkle_root), merkle);
|
||||
|
@ -557,7 +487,7 @@ mod tests {
|
|||
|
||||
assert!(decode.is_ok());
|
||||
let real_decode = decode.unwrap();
|
||||
assert_eq!(real_decode.header.version, Version(Version::USE_VERSION_BITS as i32)); // VERSIONBITS but no bits set
|
||||
assert_eq!(real_decode.header.version, Version::from_consensus(0x2000_0000)); // VERSIONBITS but no bits set
|
||||
assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash);
|
||||
assert_eq!(serialize(&real_decode.header.merkle_root), merkle);
|
||||
assert_eq!(real_decode.header.merkle_root, real_decode.compute_merkle_root().unwrap());
|
||||
|
@ -587,13 +517,13 @@ mod tests {
|
|||
let decode: Result<Block, _> = deserialize(&block);
|
||||
assert!(decode.is_ok());
|
||||
let real_decode = decode.unwrap();
|
||||
assert_eq!(real_decode.header.version, Version(2147483647));
|
||||
assert_eq!(real_decode.header.version, Version::from_consensus(2147483647));
|
||||
|
||||
let block2 = hex!("000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||
let decode2: Result<Block, _> = deserialize(&block2);
|
||||
assert!(decode2.is_ok());
|
||||
let real_decode2 = decode2.unwrap();
|
||||
assert_eq!(real_decode2.header.version, Version(-2147483648));
|
||||
assert_eq!(real_decode2.header.version, Version::from_consensus(-2147483648));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -614,7 +544,7 @@ mod tests {
|
|||
|
||||
// test with modified header
|
||||
let mut invalid_header: Header = some_header;
|
||||
invalid_header.version.0 += 1;
|
||||
invalid_header.version = Version::from_consensus(invalid_header.version.to_consensus() + 1);
|
||||
match invalid_header.validate_pow(invalid_header.target()) {
|
||||
Err(ValidationError::BadProofOfWork) => (),
|
||||
_ => panic!("unexpected result from validate_pow"),
|
||||
|
@ -635,7 +565,7 @@ mod tests {
|
|||
fn soft_fork_signalling() {
|
||||
for i in 0..31 {
|
||||
let version_int = (0x20000000u32 ^ 1 << i) as i32;
|
||||
let version = Version(version_int);
|
||||
let version = Version::from_consensus(version_int);
|
||||
if i < 29 {
|
||||
assert!(version.is_signalling_soft_fork(i));
|
||||
} else {
|
||||
|
@ -643,7 +573,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let segwit_signal = Version(0x20000000 ^ 1 << 1);
|
||||
let segwit_signal = Version::from_consensus(0x20000000 ^ 1 << 1);
|
||||
assert!(!segwit_signal.is_signalling_soft_fork(0));
|
||||
assert!(segwit_signal.is_signalling_soft_fork(1));
|
||||
assert!(!segwit_signal.is_signalling_soft_fork(2));
|
||||
|
|
|
@ -9,6 +9,76 @@
|
|||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue