diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 0b1392fd6e..8a486efb57 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -32,7 +32,7 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.31.0" +version = "0.31.1" dependencies = [ "base64", "bech32", diff --git a/Cargo-recent.lock b/Cargo-recent.lock index 307e739e45..355a16fb13 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -31,7 +31,7 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.31.0" +version = "0.31.1" dependencies = [ "base64", "bech32", diff --git a/bitcoin/CHANGELOG.md b/bitcoin/CHANGELOG.md index ebc8f9fba8..254a941ab8 100644 --- a/bitcoin/CHANGELOG.md +++ b/bitcoin/CHANGELOG.md @@ -1,4 +1,13 @@ -# 0.31.1 - 2023-10-18 +# 0.31.2 - 2024-04-01 + +- Fix parsing bug in `merkle_block::deserialize` [#2614](https://github.com/rust-bitcoin/rust-bitcoin/pull/2614) + +# 0.31.1 - 2024-01-09 + +- Fix bug in `FeeRate::checked_mul_by_weight` [#2128](https://github.com/rust-bitcoin/rust-bitcoin/pull/2182) +- Add BIP-32 types remove in 0.31 back in and mark as deprecated [#2258](https://github.com/rust-bitcoin/rust-bitcoin/pull/2258) + +# 0.31.0 - 2023-10-18 - Bump MSRV to Rust 1.48.0 [#1729](https://github.com/rust-bitcoin/rust-bitcoin/pull/1729) - Add new example code for signature verification [#1776](https://github.com/rust-bitcoin/rust-bitcoin/pull/1776) diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index 1f1926a48a..568bc791c8 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitcoin" -version = "0.31.0" +version = "0.31.2" authors = ["Andrew Poelstra "] license = "CC0-1.0" repository = "https://github.com/rust-bitcoin/rust-bitcoin/" @@ -13,7 +13,7 @@ edition = "2018" exclude = ["tests", "contrib"] [features] -default = [ "std", "secp-recovery" ] +default = [ "std", "secp-recovery", "serde" ] rand-std = ["secp256k1/rand-std", "std"] rand = ["secp256k1/rand"] serde = ["actual-serde", "hashes/serde", "secp256k1/serde", "internals/serde"] @@ -55,6 +55,7 @@ serde_json = "1.0.0" serde_test = "1.0.19" serde_derive = "1.0.103" bincode = "1.3.1" +anyhow = "=1.0.86" [target.'cfg(mutate)'.dev-dependencies] mutagen = { git = "https://github.com/llogiq/mutagen" } diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs index 2ba70d73aa..18e7306639 100644 --- a/bitcoin/src/bip152.rs +++ b/bitcoin/src/bip152.rs @@ -232,7 +232,7 @@ impl HeaderAndShortIds { } Ok(HeaderAndShortIds { - header: block.header, + header: block.header.clone(), nonce, // Provide coinbase prefilled. prefilled_txs: prefilled, @@ -405,6 +405,7 @@ mod test { time: 2, bits: CompactTarget::from_consensus(3), nonce: 4, + aux_data: None, }, txdata: vec![dummy_tx(&[2]), dummy_tx(&[3]), dummy_tx(&[4])], } diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 7a2c4be9f4..319e796c87 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -28,14 +28,22 @@ use crate::network::Network; use crate::prelude::*; /// Version bytes for extended public keys on the Bitcoin network. -const VERSION_BYTES_MAINNET_PUBLIC: [u8; 4] = [0x04, 0x88, 0xB2, 0x1E]; +const VERSION_BYTES_MAINNET_PUBLIC: [u8; 4] = [0x02, 0xfa, 0xca, 0xfd]; /// Version bytes for extended private keys on the Bitcoin network. -const VERSION_BYTES_MAINNET_PRIVATE: [u8; 4] = [0x04, 0x88, 0xAD, 0xE4]; +const VERSION_BYTES_MAINNET_PRIVATE: [u8; 4] = [0x02, 0xfa, 0xc3, 0x98]; /// Version bytes for extended public keys on any of the testnet networks. const VERSION_BYTES_TESTNETS_PUBLIC: [u8; 4] = [0x04, 0x35, 0x87, 0xCF]; /// Version bytes for extended private keys on any of the testnet networks. const VERSION_BYTES_TESTNETS_PRIVATE: [u8; 4] = [0x04, 0x35, 0x83, 0x94]; +/// The old name for xpub, extended public key. +#[deprecated(since = "0.31.0", note = "use xpub instead")] +pub type ExtendendPubKey = Xpub; + +/// The old name for xpriv, extended public key. +#[deprecated(since = "0.31.0", note = "use xpriv instead")] +pub type ExtendendPrivKey = Xpriv; + /// A chain code #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ChainCode([u8; 32]); diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index b08bc5c771..de1d978205 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -33,7 +33,7 @@ use crate::{io, merkle_tree, VarInt}; /// ### Bitcoin Core References /// /// * [CBlockHeader definition](https://github.com/bitcoin/bitcoin/blob/345457b542b6a980ccfbc868af0970a6f91d1b82/src/primitives/block.h#L20) -#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] +#[derive(PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] pub struct Header { @@ -49,30 +49,137 @@ pub struct Header { pub bits: CompactTarget, /// The nonce, selected to obtain a low enough blockhash. pub nonce: u32, + + pub aux_data: Option, +} + +//impl_consensus_encoding!(Header, version, prev_blockhash, merkle_root, time, bits, nonce); +impl Decodable for Header { + fn consensus_decode_from_finite_reader( + reader: &mut R, + ) -> Result { + let base = SimpleHeader::consensus_decode_from_finite_reader(reader)?; + if (base.version.0 & 0x100) == 0 { + return Ok(Header { + version: base.version, + prev_blockhash: base.prev_blockhash, + merkle_root: base.merkle_root, + time: base.time, + bits: base.bits, + nonce: base.nonce, + aux_data: None, + }); + } else { + let aux_data = AuxPow::consensus_decode_from_finite_reader(reader)?; + Ok(Header { + version: base.version, + prev_blockhash: base.prev_blockhash, + merkle_root: base.merkle_root, + time: base.time, + bits: base.bits, + nonce: base.nonce, + aux_data: Some(aux_data), + }) + } + } + + fn consensus_decode(reader: &mut R) -> Result { + use crate::io::Read as _; + let mut r = reader.take(encode::MAX_VEC_SIZE as u64); + let thing = SimpleHeader::consensus_decode(r.by_ref())?; + if (thing.version.0 & 0x100) == 0 { + return Ok(Header { + version: thing.version, + prev_blockhash: thing.prev_blockhash, + merkle_root: thing.merkle_root, + time: thing.time, + bits: thing.bits, + nonce: thing.nonce, + aux_data: None, + }); + } else { + let aux_data = AuxPow::consensus_decode(r.by_ref())?; + Ok(Header { + version: thing.version, + prev_blockhash: thing.prev_blockhash, + merkle_root: thing.merkle_root, + time: thing.time, + bits: thing.bits, + nonce: thing.nonce, + aux_data: Some(aux_data), + }) + } + } +} +impl Encodable for Header { + fn consensus_encode(&self, writer: &mut W) -> Result { + let mut len = self.version.consensus_encode(writer)?; + len += self.prev_blockhash.consensus_encode(writer)?; + len += self.merkle_root.consensus_encode(writer)?; + len += self.time.consensus_encode(writer)?; + len += self.bits.consensus_encode(writer)?; + len += self.nonce.consensus_encode(writer)?; + if (self.version.0 & 0x100) != 0 { + len += self.aux_data.as_ref().unwrap().consensus_encode(writer)?; + } + Ok(len) + } +} + +#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] +pub struct SimpleHeader { + /// Block version, now repurposed for soft fork signalling. + pub version: Version, + /// Reference to the previous block in the chain. + pub prev_blockhash: BlockHash, + /// The root hash of the merkle tree of transactions in the block. + pub merkle_root: TxMerkleNode, + /// The timestamp of the block, as claimed by the miner. + pub time: u32, + /// The target value below which the blockhash must lie. + pub bits: CompactTarget, + /// The nonce, selected to obtain a low enough blockhash. + pub nonce: u32, } -impl_consensus_encoding!(Header, version, prev_blockhash, merkle_root, time, bits, nonce); +impl_consensus_encoding!(SimpleHeader, version, prev_blockhash, merkle_root, time, bits, nonce); impl Header { /// The number of bytes that the block header contributes to the size of a block. // Serialized length of fields (version, prev_blockhash, merkle_root, time, bits, nonce) - pub const SIZE: usize = 4 + 32 + 32 + 4 + 4 + 4; // 80 - + pub fn to_simple_header(&self) -> SimpleHeader { + SimpleHeader { + version: self.version, + prev_blockhash: self.prev_blockhash, + merkle_root: self.merkle_root, + time: self.time, + bits: self.bits, + nonce: self.nonce, + } + } /// Returns the block hash. pub fn block_hash(&self) -> BlockHash { let mut engine = BlockHash::engine(); - self.consensus_encode(&mut engine).expect("engines don't error"); + self.to_simple_header().consensus_encode(&mut engine).expect("engines don't error"); BlockHash::from_engine(engine) } /// Computes the target (range [0, T] inclusive) that a blockhash must land in to be valid. - pub fn target(&self) -> Target { self.bits.into() } + pub fn target(&self) -> Target { + self.bits.into() + } /// Computes the popular "difficulty" measure for mining. - pub fn difficulty(&self) -> u128 { self.target().difficulty() } + pub fn difficulty(&self) -> u128 { + self.target().difficulty() + } /// Computes the popular "difficulty" measure for mining and returns a float value of f64. - pub fn difficulty_float(&self) -> f64 { self.target().difficulty_float() } + pub fn difficulty_float(&self) -> f64 { + self.target().difficulty_float() + } /// Checks that the proof-of-work for the block is valid, returning the block hash. pub fn validate_pow(&self, required_target: Target) -> Result { @@ -89,7 +196,17 @@ impl Header { } /// Returns the total work of the block. - pub fn work(&self) -> Work { self.target().to_work() } + pub fn work(&self) -> Work { + self.target().to_work() + } + pub fn get_size(&self) -> usize { + /*if self.aux_data.is_none() { + return 80 + }else{ + 80 + self.aux_data.unwrap().get_size() + }*/ + 80 + } } impl fmt::Debug for Header { @@ -106,6 +223,62 @@ impl fmt::Debug for Header { } } +impl fmt::Debug for SimpleHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Header") + //.field("block_hash", &self.block_hash()) + .field("version", &self.version) + .field("prev_blockhash", &self.prev_blockhash) + .field("merkle_root", &self.merkle_root) + .field("time", &self.time) + .field("bits", &self.bits) + .field("nonce", &self.nonce) + .finish() + } +} + +#[derive(PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] +pub struct MerkleBranch { + pub hashes: Vec, + // Bitmask of which side of the merkle hash function the branch_hash element should go on. + // Zero means it goes on the right, One means on the left. + // It is equal to the index of the starting hash within the widest level + // of the merkle tree for this merkle branch. + pub side_mask: u32, +} +impl_consensus_encoding!(MerkleBranch, hashes, side_mask); + +#[derive(PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] + +pub struct AuxPow { + pub coinbase_tx: Transaction, + pub block_hash: BlockHash, + pub coinbase_branch: MerkleBranch, + pub blockchain_branch: MerkleBranch, + pub parent_block: SimpleHeader, +} + +impl_consensus_encoding!( + AuxPow, + coinbase_tx, + block_hash, + coinbase_branch, + blockchain_branch, + parent_block +); +impl AuxPow { + pub fn get_size(&self) -> usize { + self.coinbase_tx.total_size() + + 32 + + self.coinbase_branch.hashes.len() * 32 + + self.blockchain_branch.hashes.len() * 32 + + 80 + } +} /// Bitcoin block version number. /// /// Originally used as a protocol version, but repurposed for soft-fork signaling. @@ -122,7 +295,7 @@ impl fmt::Debug for Header { #[derive(Copy, PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] -pub struct Version(i32); +pub struct Version(pub i32); impl Version { /// The original Bitcoin Block v1. @@ -145,12 +318,16 @@ impl Version { /// Creates a [`Version`] from a signed 32 bit integer value. /// /// This is the data type used in consensus code in Bitcoin Core. - pub fn from_consensus(v: i32) -> Self { Version(v) } + pub 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 } + pub fn to_consensus(self) -> i32 { + self.0 + } /// Checks whether the version number is signalling a soft fork at the given bit. /// @@ -173,7 +350,9 @@ impl Version { } impl Default for Version { - fn default() -> Version { Self::NO_SOFT_FORK_SIGNALLING } + fn default() -> Version { + Self::NO_SOFT_FORK_SIGNALLING + } } impl Encodable for Version { @@ -213,7 +392,9 @@ impl_consensus_encoding!(Block, header, txdata); impl Block { /// Returns the block hash. - pub fn block_hash(&self) -> BlockHash { self.header.block_hash() } + pub fn block_hash(&self) -> BlockHash { + self.header.block_hash() + } /// Checks if merkle root of header matches merkle root of the transaction list. pub fn check_merkle_root(&self) -> bool { @@ -307,7 +488,7 @@ impl Block { /// > Base size is the block size in bytes with the original transaction serialization without /// > any witness-related data, as seen by a non-upgraded node. fn base_size(&self) -> usize { - let mut size = Header::SIZE; + let mut size = self.header.get_size(); size += VarInt::from(self.txdata.len()).size(); size += self.txdata.iter().map(|tx| tx.base_size()).sum::(); @@ -320,7 +501,7 @@ impl Block { /// > Total size is the block size in bytes with transactions serialized as described in BIP144, /// > including base data and witness data. pub fn total_size(&self) -> usize { - let mut size = Header::SIZE; + let mut size = self.header.get_size(); size += VarInt::from(self.txdata.len()).size(); size += self.txdata.iter().map(|tx| tx.total_size()).sum::(); @@ -330,10 +511,14 @@ impl Block { /// Returns the stripped size of the block. #[deprecated(since = "0.31.0", note = "use Block::base_size() instead")] - pub fn strippedsize(&self) -> usize { self.base_size() } + pub fn strippedsize(&self) -> usize { + self.base_size() + } /// Returns the coinbase transaction, if one is present. - pub fn coinbase(&self) -> Option<&Transaction> { self.txdata.first() } + pub fn coinbase(&self) -> Option<&Transaction> { + self.txdata.first() + } /// Returns the block height, as encoded in the coinbase transaction according to BIP34. pub fn bip34_block_height(&self) -> Result { @@ -370,19 +555,27 @@ impl Block { } impl From
for BlockHash { - fn from(header: Header) -> BlockHash { header.block_hash() } + fn from(header: Header) -> BlockHash { + header.block_hash() + } } impl From<&Header> for BlockHash { - fn from(header: &Header) -> BlockHash { header.block_hash() } + fn from(header: &Header) -> BlockHash { + header.block_hash() + } } impl From for BlockHash { - fn from(block: Block) -> BlockHash { block.block_hash() } + fn from(block: Block) -> BlockHash { + block.block_hash() + } } impl From<&Block> for BlockHash { - fn from(block: &Block) -> BlockHash { block.block_hash() } + fn from(block: &Block) -> BlockHash { + block.block_hash() + } } /// An error when looking up a BIP34 block height. @@ -482,7 +675,12 @@ mod tests { let push = Vec::::from_hex("a08601112233445566").unwrap(); assert_eq!(bad.bip34_block_height(), Err(super::Bip34Error::UnexpectedPush(push))); } - + #[test] + fn block2() { + let dd = hex!("010000009156352c1818b32e90c9e792efd6a11a82fe7956a630f03bbee236cedae3911a1c525f1049e519256961f407e96e22aef391581de98686524ef500769f777e5fafeda352f0ff0f1e001083540101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e04afeda3520102062f503253482fffffffff01004023ef3806000023210338bf57d51a50184cf5ef0dc42ecd519fb19e24574c057620262cc1df94da2ae5ac00000000"); + let block: Block = deserialize(&dd).unwrap(); + println!("{:?}", block); + } #[test] fn block_test() { // Mainnet block 00000000b0c5a240b2a61d2e75692224efd4cbecdf6eaf4cc2cf477ca7c270e7 diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs index 87bca277ec..159555caf0 100644 --- a/bitcoin/src/blockdata/constants.rs +++ b/bitcoin/src/blockdata/constants.rs @@ -44,11 +44,11 @@ pub const WITNESS_SCALE_FACTOR: usize = 4; /// The maximum allowed number of signature check operations in a block. pub const MAX_BLOCK_SIGOPS_COST: i64 = 80_000; /// Mainnet (bitcoin) pubkey address prefix. -pub const PUBKEY_ADDRESS_PREFIX_MAIN: u8 = 0; // 0x00 +pub const PUBKEY_ADDRESS_PREFIX_MAIN: u8 = 30; /// Mainnet (bitcoin) script address prefix. -pub const SCRIPT_ADDRESS_PREFIX_MAIN: u8 = 5; // 0x05 +pub const SCRIPT_ADDRESS_PREFIX_MAIN: u8 = 22; /// Test (tesnet, signet, regtest) pubkey address prefix. -pub const PUBKEY_ADDRESS_PREFIX_TEST: u8 = 111; // 0x6f +pub const PUBKEY_ADDRESS_PREFIX_TEST: u8 = 113; // 0x71 /// Test (tesnet, signet, regtest) script address prefix. pub const SCRIPT_ADDRESS_PREFIX_TEST: u8 = 196; // 0xc4 /// The maximum allowed script size. @@ -96,7 +96,7 @@ fn bitcoin_genesis_tx() -> Transaction { /// Constructs and returns the genesis block. pub fn genesis_block(network: Network) -> Block { let txdata = vec![bitcoin_genesis_tx()]; - let hash: sha256d::Hash = txdata[0].txid().into(); + let hash: sha256d::Hash = sha256d::Hash::from_slice(&hex!("696ad20e2dd4365c7459b4a4a5af743d5e92c6da3229e6532cd605f6533f2a5b")).unwrap(); let merkle_root = hash.into(); match network { Network::Bitcoin => Block { @@ -104,9 +104,10 @@ pub fn genesis_block(network: Network) -> Block { version: block::Version::ONE, prev_blockhash: Hash::all_zeros(), merkle_root, - time: 1231006505, - bits: CompactTarget::from_consensus(0x1d00ffff), - nonce: 2083236893, + time: 1386325540, + bits: CompactTarget::from_consensus(0x1e0ffff0), + nonce: 99943, + aux_data: None, }, txdata, }, @@ -116,8 +117,9 @@ pub fn genesis_block(network: Network) -> Block { prev_blockhash: Hash::all_zeros(), merkle_root, time: 1296688602, - bits: CompactTarget::from_consensus(0x1d00ffff), - nonce: 414098458, + bits: CompactTarget::from_consensus(0x1e0ffff0), + nonce: 997879, + aux_data: None, }, txdata, }, @@ -129,6 +131,7 @@ pub fn genesis_block(network: Network) -> Block { time: 1598918400, bits: CompactTarget::from_consensus(0x1e0377ae), nonce: 52613770, + aux_data: None, }, txdata, }, @@ -140,6 +143,7 @@ pub fn genesis_block(network: Network) -> Block { time: 1296688602, bits: CompactTarget::from_consensus(0x207fffff), nonce: 2, + aux_data: None, }, txdata, }, @@ -156,13 +160,11 @@ impl ChainHash { // Mainnet value can be verified at https://github.com/lightning/bolts/blob/master/00-introduction.md /// `ChainHash` for mainnet bitcoin. pub const BITCOIN: Self = Self([ - 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131, - 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, + 145, 86, 53, 44, 24, 24, 179, 46, 144, 201, 231, 146, 239, 214, 161, 26, 130, 254, 121, 86, 166, 48, 240, 59, 190, 226, 54, 206, 218, 227, 145, 26 ]); /// `ChainHash` for testnet bitcoin. pub const TESTNET: Self = Self([ - 67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151, - 32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0, + 158, 85, 80, 115, 208, 196, 243, 100, 86, 219, 137, 81, 244, 73, 112, 77, 84, 77, 40, 38, 217, 170, 96, 99, 107, 64, 55, 70, 38, 120, 10, 187 ]); /// `ChainHash` for signet bitcoin. pub const SIGNET: Self = Self([ @@ -171,8 +173,7 @@ impl ChainHash { ]); /// `ChainHash` for regtest bitcoin. pub const REGTEST: Self = Self([ - 6, 34, 110, 70, 17, 26, 11, 89, 202, 175, 18, 96, 67, 235, 91, 191, 40, 195, 79, 58, 94, - 51, 42, 31, 199, 178, 183, 60, 241, 136, 145, 15, + 165, 115, 233, 28, 23, 114, 7, 108, 13, 64, 247, 14, 68, 8, 200, 58, 49, 112, 95, 41, 106, 230, 231, 98, 157, 74, 220, 181, 163, 96, 33, 61 ]); /// Returns the hash of the `network` genesis block for use as a chain hash. diff --git a/bitcoin/src/blockdata/fee_rate.rs b/bitcoin/src/blockdata/fee_rate.rs index 1c3b8a9e2c..aa8d3c441a 100644 --- a/bitcoin/src/blockdata/fee_rate.rs +++ b/bitcoin/src/blockdata/fee_rate.rs @@ -82,10 +82,12 @@ impl FeeRate { /// Checked weight multiplication. /// - /// Computes `self * rhs` where rhs is of type Weight. `None` is returned if an overflow - /// occurred. + /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. + /// + /// `None` is returned if an overflow occurred. pub fn checked_mul_by_weight(self, rhs: Weight) -> Option { - self.0.checked_mul(rhs.to_wu()).map(Amount::from_sat) + let sats = self.0.checked_mul(rhs.to_wu())?.checked_add(999)? / 1000; + Some(Amount::from_sat(sats)) } /// Calculates fee by multiplying this fee rate by weight, in weight units, returning `None` @@ -95,13 +97,14 @@ impl FeeRate { /// /// # Examples /// - /// ```no_run + /// ``` /// # use bitcoin::{absolute, transaction, FeeRate, Transaction}; /// # // Dummy transaction. /// # let tx = Transaction { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![] }; /// /// let rate = FeeRate::from_sat_per_vb(1).expect("1 sat/vbyte is valid"); - /// let fee = rate.fee_wu(tx.weight()); + /// let fee = rate.fee_wu(tx.weight()).unwrap(); + /// assert_eq!(fee.to_sat(), tx.vsize() as u64); /// ``` pub fn fee_wu(self, weight: Weight) -> Option { self.checked_mul_by_weight(weight) } @@ -209,12 +212,20 @@ mod tests { #[test] fn checked_weight_mul_test() { - let weight = Weight::from_wu(10); - let fee: Amount = FeeRate(10).checked_mul_by_weight(weight).expect("expected Amount"); + let weight = Weight::from_vb(10).unwrap(); + let fee: Amount = FeeRate::from_sat_per_vb(10) + .unwrap() + .checked_mul_by_weight(weight) + .expect("expected Amount"); assert_eq!(Amount::from_sat(100), fee); let fee = FeeRate(10).checked_mul_by_weight(Weight::MAX); assert!(fee.is_none()); + + let weight = Weight::from_vb(3).unwrap(); + let fee_rate = FeeRate::from_sat_per_vb(3).unwrap(); + let fee = fee_rate.checked_mul_by_weight(weight).unwrap(); + assert_eq!(Amount::from_sat(9), fee); } #[test] diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 6e38d25021..50ffc28d24 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1101,39 +1101,13 @@ impl Decodable for Transaction { let version = Version::consensus_decode_from_finite_reader(r)?; let input = Vec::::consensus_decode_from_finite_reader(r)?; // segwit - if input.is_empty() { - let segwit_flag = u8::consensus_decode_from_finite_reader(r)?; - match segwit_flag { - // BIP144 input witnesses - 1 => { - let mut input = Vec::::consensus_decode_from_finite_reader(r)?; - let output = Vec::::consensus_decode_from_finite_reader(r)?; - for txin in input.iter_mut() { - txin.witness = Decodable::consensus_decode_from_finite_reader(r)?; - } - if !input.is_empty() && input.iter().all(|input| input.witness.is_empty()) { - Err(encode::Error::ParseFailed("witness flag set but no witnesses present")) - } else { - Ok(Transaction { - version, - input, - output, - lock_time: Decodable::consensus_decode_from_finite_reader(r)?, - }) - } - } - // We don't support anything else - x => Err(encode::Error::UnsupportedSegwitFlag(x)), - } - // non-segwit - } else { - Ok(Transaction { - version, - input, - output: Decodable::consensus_decode_from_finite_reader(r)?, - lock_time: Decodable::consensus_decode_from_finite_reader(r)?, - }) - } + + Ok(Transaction { + version, + input, + output: Decodable::consensus_decode_from_finite_reader(r)?, + lock_time: Decodable::consensus_decode_from_finite_reader(r)?, + }) } } diff --git a/bitcoin/src/consensus/encode.rs b/bitcoin/src/consensus/encode.rs index 78fa7a19d6..4f38314515 100644 --- a/bitcoin/src/consensus/encode.rs +++ b/bitcoin/src/consensus/encode.rs @@ -119,6 +119,7 @@ pub fn deserialize(data: &[u8]) -> Result { let (rv, consumed) = deserialize_partial(data)?; // Fail if data are not consumed entirely. + if consumed == data.len() { Ok(rv) } else { diff --git a/bitcoin/src/consensus/params.rs b/bitcoin/src/consensus/params.rs index e2d747f867..936f35c5fa 100644 --- a/bitcoin/src/consensus/params.rs +++ b/bitcoin/src/consensus/params.rs @@ -55,28 +55,28 @@ impl Params { Network::Bitcoin => Params { network: Network::Bitcoin, bip16_time: 1333238400, // Apr 1 2012 - bip34_height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8 - bip65_height: 388381, // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0 - bip66_height: 363725, // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931 - rule_change_activation_threshold: 1916, // 95% - miner_confirmation_window: 2016, + bip34_height: 1034383, // + bip65_height: 3464751, // + bip66_height: 1034383, // + rule_change_activation_threshold: 9576, // 95% + miner_confirmation_window: 10080, pow_limit: Target::MAX_ATTAINABLE_MAINNET, - pow_target_spacing: 10 * 60, // 10 minutes. - pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks. + pow_target_spacing: 60, // 1 minutes. + pow_target_timespan: 4 * 60 * 60, // 4 hours. allow_min_difficulty_blocks: false, no_pow_retargeting: false, }, Network::Testnet => Params { network: Network::Testnet, bip16_time: 1333238400, // Apr 1 2012 - bip34_height: 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8 - bip65_height: 581885, // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 - bip66_height: 330776, // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182 - rule_change_activation_threshold: 1512, // 75% + bip34_height: 708658, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8 + bip65_height: 1854705, // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 + bip66_height: 708658, // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182 + rule_change_activation_threshold: 2880, // 75% miner_confirmation_window: 2016, pow_limit: Target::MAX_ATTAINABLE_TESTNET, - pow_target_spacing: 10 * 60, // 10 minutes. - pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks. + pow_target_spacing: 60, // 1 minutes. + pow_target_timespan: 4 * 60 * 60, // 4 hours. allow_min_difficulty_blocks: true, no_pow_retargeting: false, }, @@ -103,8 +103,8 @@ impl Params { rule_change_activation_threshold: 108, // 75% miner_confirmation_window: 144, pow_limit: Target::MAX_ATTAINABLE_REGTEST, - pow_target_spacing: 10 * 60, // 10 minutes. - pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks. + pow_target_spacing: 1, // 1 second. + pow_target_timespan: 4 * 60 * 60, // 4 hours allow_min_difficulty_blocks: true, no_pow_retargeting: true, }, diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index b6321abe3c..facffb5ee9 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -311,8 +311,9 @@ impl PrivateKey { pub fn fmt_wif(&self, fmt: &mut dyn fmt::Write) -> fmt::Result { let mut ret = [0; 34]; ret[0] = match self.network { - Network::Bitcoin => 128, - Network::Testnet | Network::Signet | Network::Regtest => 239, + Network::Bitcoin => 158, + Network::Testnet => 241, + Network::Signet | Network::Regtest => 239, }; ret[1..33].copy_from_slice(&self.inner[..]); let privkey = if self.compressed { @@ -345,8 +346,9 @@ impl PrivateKey { }; let network = match data[0] { - 128 => Network::Bitcoin, - 239 => Network::Testnet, + 158 => Network::Bitcoin, + 239 => Network::Regtest, + 241 => Network::Testnet, x => { return Err(Error::Base58(base58::Error::InvalidAddressVersion(x))); } diff --git a/bitcoin/src/merkle_tree/block.rs b/bitcoin/src/merkle_tree/block.rs index ae8806607c..8ae3030c4a 100644 --- a/bitcoin/src/merkle_tree/block.rs +++ b/bitcoin/src/merkle_tree/block.rs @@ -46,7 +46,7 @@ use self::MerkleBlockError::*; use crate::blockdata::block::{self, Block}; use crate::blockdata::transaction::Transaction; use crate::blockdata::weight::Weight; -use crate::consensus::encode::{self, Decodable, Encodable}; +use crate::consensus::encode::{self, Decodable, Encodable, MAX_VEC_SIZE}; use crate::hash_types::{TxMerkleNode, Txid}; use crate::io; use crate::prelude::*; @@ -123,7 +123,7 @@ impl MerkleBlock { let matches: Vec = block_txids.iter().map(match_txids).collect(); let pmt = PartialMerkleTree::from_txids(block_txids, &matches); - MerkleBlock { header: *header, txn: pmt } + MerkleBlock { header: header.clone(), txn: pmt } } /// Extract the matching txid's represented by this partial merkle tree @@ -460,6 +460,12 @@ impl Decodable for PartialMerkleTree { let hashes: Vec = Decodable::consensus_decode(r)?; let nb_bytes_for_bits = encode::VarInt::consensus_decode(r)?.0 as usize; + if nb_bytes_for_bits > MAX_VEC_SIZE { + return Err(encode::Error::OversizedVectorAllocation { + requested: nb_bytes_for_bits, + max: MAX_VEC_SIZE, + }); + } let mut bits = vec![false; nb_bytes_for_bits * 8]; for chunk in bits.chunks_mut(8) { let byte = u8::consensus_decode(r)?; @@ -821,4 +827,18 @@ mod tests { tree_width_20, 7, 2, 2; tree_width_21, 7, 3, 1; } + + #[test] + fn regression_2606() { + // Attempt + let bytes = hex!( + "000006000000000000000004ee00000004c7f1ccb1000000ffff000000010000\ + 0000ffffffffff1f000000000400000000000002000000000500000000000000\ + 000000000300000000000003000000000200000000ff00000000c7f1ccb10407\ + 00000000000000ccb100c76538b100000004bfa9c251681b1b00040000000025\ + 00000004bfaac251681b1b25\ + "); + let deser = crate::consensus::deserialize::(&bytes); + assert!(deser.is_err()); + } } diff --git a/bitcoin/src/p2p/mod.rs b/bitcoin/src/p2p/mod.rs index c7f67570ff..9fc596ad9a 100644 --- a/bitcoin/src/p2p/mod.rs +++ b/bitcoin/src/p2p/mod.rs @@ -201,13 +201,13 @@ impl Decodable for ServiceFlags { } /// Network magic bytes to identify the cryptocurrency network the message was intended for. #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] -pub struct Magic([u8; 4]); +pub struct Magic(pub [u8; 4]); impl Magic { /// Bitcoin mainnet network magic bytes. - pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]); + pub const BITCOIN: Self = Self([0xc0, 0xc0, 0xc0, 0xc0]); /// Bitcoin testnet network magic bytes. - pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]); + pub const TESTNET: Self = Self([0xfc, 0xc1, 0xb7, 0xdc]); /// Bitcoin signet network magic bytes. pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]); /// Bitcoin regtest network magic bytes. @@ -408,8 +408,8 @@ mod tests { #[test] fn magic_from_str() { let known_network_magic_strs = [ - ("f9beb4d9", Network::Bitcoin), - ("0b110907", Network::Testnet), + ("c0c0c0c0", Network::Bitcoin), + ("fcc1b7dc", Network::Testnet), ("fabfb5da", Network::Regtest), ("0a03cf40", Network::Signet), ]; diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index c40270cc49..d41ac97169 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -10,7 +10,7 @@ cargo-fuzz = true [dependencies] honggfuzz = { version = "0.5.55", default-features = false } -bitcoin = { version = "0.31.0", features = [ "serde" ] } +bitcoin = { version = "0.31.1", features = [ "serde" ] } serde = { version = "1.0.103", features = [ "derive" ] } serde_json = "1.0" diff --git a/fuzz/generate-files.sh b/fuzz/generate-files.sh index 25af89894e..e04516a4e2 100755 --- a/fuzz/generate-files.sh +++ b/fuzz/generate-files.sh @@ -21,7 +21,7 @@ cargo-fuzz = true [dependencies] honggfuzz = { version = "0.5.55", default-features = false } -bitcoin = { version = "0.31.0", features = [ "serde" ] } +bitcoin = { version = "0.31.1", features = [ "serde" ] } serde = { version = "1.0.103", features = [ "derive" ] } serde_json = "1.0" diff --git a/hashes/Cargo.toml b/hashes/Cargo.toml index 6f91a0206a..2b301405d8 100644 --- a/hashes/Cargo.toml +++ b/hashes/Cargo.toml @@ -38,4 +38,4 @@ actual-core2 = { package = "core2", version = "0.3.2", default-features = false, [dev-dependencies] serde_test = "1.0" -serde_json = "1.0" +serde_json = "1.0" \ No newline at end of file diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 32a52dbf75..83e18aa25e 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -202,7 +202,7 @@ macro_rules! hash_type { #[cfg_attr(feature = "schemars", derive(crate::schemars::JsonSchema))] #[repr(transparent)] pub struct Hash( - #[cfg_attr(feature = "schemars", schemars(schema_with = $schemars))] [u8; $bits / 8], + #[cfg_attr(feature = "schemars", schemars(schema_with = $schemars))] pub [u8; $bits / 8], ); impl Hash {