Merge rust-bitcoin/rust-bitcoin#1357: Do some rustdoc cleanups

26be9ddd27 Make RBF rustdoc more scrary (Tobin C. Harding)
c9a49d5be7 blockdata: Improve content of rustdocs (Tobin C. Harding)
e1e5974065 consensus: Improve rustdocs (Tobin C. Harding)
c553299ace Remove uninformative code comments (Tobin C. Harding)
bbd39e5ecc Use longer column width (Tobin C. Harding)
31740710ee blockdata: Improve rustdocs (Tobin C. Harding)
fb708ca74b Add newline after brief description (Tobin C. Harding)

Pull request description:

  Put some effort into our documentation, this is all pretty non-controversial. Patches separated to ease review.

ACKs for top commit:
  Kixunil:
    ACK 26be9ddd27
  apoelstra:
    ACK 26be9ddd27

Tree-SHA512: 8990ed812b3bb55f722ac7e85a8655b65744eb21ad3b16dae77e05d9273f86e248f1ef4945a35d7767241038986bc23e0a8024347e600f0c1e53f8de992208e2
This commit is contained in:
Andrew Poelstra 2022-12-07 13:40:05 +00:00
commit fd5c5e43d2
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
7 changed files with 166 additions and 153 deletions

View File

@ -96,7 +96,7 @@ impl Header {
} }
} }
/// Bitcoin block version number /// Bitcoin block version number.
/// ///
/// Originally used as a protocol version, but repurposed for soft-fork signaling. /// Originally used as a protocol version, but repurposed for soft-fork signaling.
/// ///
@ -146,7 +146,7 @@ impl Version {
self.0 self.0
} }
/// Check whether the version number is signalling a soft fork at the given bit. /// 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 /// 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. /// the version bit for the specific soft fork is toggled on.
@ -213,7 +213,7 @@ impl Block {
self.header.block_hash() self.header.block_hash()
} }
/// check if merkle root of header matches merkle root of the transaction list /// Checks if merkle root of header matches merkle root of the transaction list.
pub fn check_merkle_root(&self) -> bool { pub fn check_merkle_root(&self) -> bool {
match self.compute_merkle_root() { match self.compute_merkle_root() {
Some(merkle_root) => self.header.merkle_root == merkle_root, Some(merkle_root) => self.header.merkle_root == merkle_root,

View File

@ -26,21 +26,21 @@ use crate::network::constants::Network;
use crate::pow::CompactTarget; use crate::pow::CompactTarget;
use crate::internal_macros::impl_bytes_newtype; use crate::internal_macros::impl_bytes_newtype;
/// How many satoshis are in "one bitcoin" /// How many satoshis are in "one bitcoin".
pub const COIN_VALUE: u64 = 100_000_000; pub const COIN_VALUE: u64 = 100_000_000;
/// How many seconds between blocks we expect on average /// How many seconds between blocks we expect on average.
pub const TARGET_BLOCK_SPACING: u32 = 600; pub const TARGET_BLOCK_SPACING: u32 = 600;
/// How many blocks between diffchanges /// How many blocks between diffchanges.
pub const DIFFCHANGE_INTERVAL: u32 = 2016; pub const DIFFCHANGE_INTERVAL: u32 = 2016;
/// How much time on average should occur between diffchanges /// How much time on average should occur between diffchanges.
pub const DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600; pub const DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600;
/// The maximum allowed weight for a block, see BIP 141 (network rule) /// The maximum allowed weight for a block, see BIP 141 (network rule).
pub const MAX_BLOCK_WEIGHT: u32 = 4_000_000; pub const MAX_BLOCK_WEIGHT: u32 = 4_000_000;
/// The minimum transaction weight for a valid serialized transaction /// The minimum transaction weight for a valid serialized transaction.
pub const MIN_TRANSACTION_WEIGHT: u32 = 4 * 60; pub const MIN_TRANSACTION_WEIGHT: u32 = 4 * 60;
/// The factor that non-witness serialization data is multiplied by during weight calculation /// The factor that non-witness serialization data is multiplied by during weight calculation.
pub const WITNESS_SCALE_FACTOR: usize = 4; pub const WITNESS_SCALE_FACTOR: usize = 4;
/// The maximum allowed number of signature check operations in a block /// The maximum allowed number of signature check operations in a block.
pub const MAX_BLOCK_SIGOPS_COST: i64 = 80_000; pub const MAX_BLOCK_SIGOPS_COST: i64 = 80_000;
/// Mainnet (bitcoin) pubkey address prefix. /// Mainnet (bitcoin) pubkey address prefix.
pub const PUBKEY_ADDRESS_PREFIX_MAIN: u8 = 0; // 0x00 pub const PUBKEY_ADDRESS_PREFIX_MAIN: u8 = 0; // 0x00
@ -62,7 +62,7 @@ pub const MAX_SCRIPTNUM_VALUE: u32 = 0x80000000; // 2^31
/// if you are doing anything remotely sane with monetary values). /// if you are doing anything remotely sane with monetary values).
pub const MAX_MONEY: u64 = 21_000_000 * COIN_VALUE; pub const MAX_MONEY: u64 = 21_000_000 * COIN_VALUE;
/// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block /// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block.
fn bitcoin_genesis_tx() -> Transaction { fn bitcoin_genesis_tx() -> Transaction {
// Base // Base
let mut ret = Transaction { let mut ret = Transaction {
@ -101,7 +101,7 @@ fn bitcoin_genesis_tx() -> Transaction {
ret ret
} }
/// Constructs and returns the genesis block /// Constructs and returns the genesis block.
pub fn genesis_block(network: Network) -> Block { pub fn genesis_block(network: Network) -> Block {
let txdata = vec![bitcoin_genesis_tx()]; let txdata = vec![bitcoin_genesis_tx()];
let hash: sha256d::Hash = txdata[0].txid().into(); let hash: sha256d::Hash = txdata[0].txid().into();

View File

@ -156,17 +156,17 @@ pub enum Error {
/// Something did a non-minimal push; for more information see /// Something did a non-minimal push; for more information see
/// `https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Push_operators` /// `https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Push_operators`
NonMinimalPush, NonMinimalPush,
/// Some opcode expected a parameter, but it was missing or truncated /// Some opcode expected a parameter but it was missing or truncated.
EarlyEndOfScript, EarlyEndOfScript,
/// Tried to read an array off the stack as a number when it was more than 4 bytes /// Tried to read an array off the stack as a number when it was more than 4 bytes.
NumericOverflow, NumericOverflow,
/// Error validating the script with bitcoinconsensus library /// Error validating the script with bitcoinconsensus library.
#[cfg(feature = "bitcoinconsensus")] #[cfg(feature = "bitcoinconsensus")]
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))] #[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
BitcoinConsensus(bitcoinconsensus::Error), BitcoinConsensus(bitcoinconsensus::Error),
/// Can not find the spent output /// Can not find the spent output.
UnknownSpentOutput(OutPoint), UnknownSpentOutput(OutPoint),
/// Can not serialize the spending transaction /// Can not serialize the spending transaction.
Serialization Serialization
} }
@ -266,7 +266,8 @@ impl From<bitcoinconsensus::Error> for Error {
} }
} }
/// Helper to encode an integer in script(minimal CScriptNum) format. /// Encodes an integer in script(minimal CScriptNum) format.
///
/// Writes bytes into the buffer and returns the number of bytes written. /// Writes bytes into the buffer and returns the number of bytes written.
pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize { pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
let mut len = 0; let mut len = 0;
@ -297,7 +298,8 @@ pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
len len
} }
/// Helper to decode an integer in script(minimal CScriptNum) format /// Decodes an integer in script(minimal CScriptNum) format.
///
/// Notice that this fails on overflow: the result is the same as in /// Notice that this fails on overflow: the result is the same as in
/// bitcoind, that only 4-byte signed-magnitude values may be read as /// bitcoind, that only 4-byte signed-magnitude values may be read as
/// numbers. They can be added or subtracted (and a long time ago, /// numbers. They can be added or subtracted (and a long time ago,
@ -343,6 +345,8 @@ pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
Ok(ret) Ok(ret)
} }
/// Decodes a boolean.
///
/// This is like "`read_scriptint` then map 0 to false and everything /// This is like "`read_scriptint` then map 0 to false and everything
/// else as true", except that the overflow rules don't apply. /// else as true", except that the overflow rules don't apply.
#[inline] #[inline]
@ -353,7 +357,7 @@ pub fn read_scriptbool(v: &[u8]) -> bool {
} }
} }
/// Read a script-encoded unsigned integer /// Decodes a script-encoded unsigned integer.
/// ///
/// ## Errors /// ## Errors
/// ///
@ -395,7 +399,7 @@ impl Script {
/// Creates a new empty script. /// Creates a new empty script.
pub fn new() -> Script { Script(vec![].into_boxed_slice()) } pub fn new() -> Script { Script(vec![].into_boxed_slice()) }
/// Creates a new script builder /// Creates a new script builder.
pub fn builder() -> Builder { pub fn builder() -> Builder {
Builder::new() Builder::new()
} }
@ -863,15 +867,16 @@ pub struct Instructions<'a> {
} }
impl<'a> Instructions<'a> { impl<'a> Instructions<'a> {
/// Set the iterator to end so that it won't iterate any longer /// Sets the iterator to end so that it won't iterate any longer.
fn kill(&mut self) { fn kill(&mut self) {
let len = self.data.len(); let len = self.data.len();
self.data.nth(len.max(1) - 1); self.data.nth(len.max(1) - 1);
} }
/// takes `len` bytes long slice from iterator and returns it advancing iterator /// Takes a `len` bytes long slice from iterator and returns it, advancing the iterator.
/// if the iterator is not long enough [`Error::EarlyEndOfScript`] is returned and the iterator is killed ///
/// to avoid returning an infinite stream of errors. /// If the iterator is not long enough [`Error::EarlyEndOfScript`] is returned and the iterator
/// is killed to avoid returning an infinite stream of errors.
fn take_slice_or_kill(&mut self, len: usize) -> Result<&'a [u8], Error> { fn take_slice_or_kill(&mut self, len: usize) -> Result<&'a [u8], Error> {
if self.data.len() >= len { if self.data.len() >= len {
let slice = &self.data.as_slice()[..len]; let slice = &self.data.as_slice()[..len];
@ -968,9 +973,10 @@ impl Builder {
/// Checks whether the script is the empty script. /// Checks whether the script is the empty script.
pub fn is_empty(&self) -> bool { self.0.is_empty() } pub fn is_empty(&self) -> bool { self.0.is_empty() }
/// Adds instructions to push an integer onto the stack. Integers are /// Adds instructions to push an integer onto the stack.
/// encoded as little-endian signed-magnitude numbers, but there are ///
/// dedicated opcodes to push some small integers. /// Integers are encoded as little-endian signed-magnitude numbers, but there are dedicated
/// opcodes to push some small integers.
pub fn push_int(self, data: i64) -> Builder { pub fn push_int(self, data: i64) -> Builder {
// We can special-case -1, 1-16 // We can special-case -1, 1-16
if data == -1 || (1..=16).contains(&data) { if data == -1 || (1..=16).contains(&data) {

View File

@ -146,6 +146,7 @@ impl std::error::Error for ParseOutPointError {
} }
/// Parses a string-encoded transaction index (vout). /// Parses a string-encoded transaction index (vout).
///
/// Does not permit leading zeroes or non-digit characters. /// Does not permit leading zeroes or non-digit characters.
fn parse_vout(s: &str) -> Result<u32, ParseOutPointError> { fn parse_vout(s: &str) -> Result<u32, ParseOutPointError> {
if s.len() > 1 { if s.len() > 1 {
@ -319,13 +320,13 @@ impl Sequence {
self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK > 0) self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK > 0)
} }
/// Create a relative lock-time using block height. /// Creates a relative lock-time using block height.
#[inline] #[inline]
pub fn from_height(height: u16) -> Self { pub fn from_height(height: u16) -> Self {
Sequence(u32::from(height)) Sequence(u32::from(height))
} }
/// Create a relative lock-time using time intervals where each interval is equivalent /// Creates a relative lock-time using time intervals where each interval is equivalent
/// to 512 seconds. /// to 512 seconds.
/// ///
/// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin /// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin
@ -334,7 +335,7 @@ impl Sequence {
Sequence(u32::from(intervals) | Sequence::LOCK_TYPE_MASK) Sequence(u32::from(intervals) | Sequence::LOCK_TYPE_MASK)
} }
/// Create a relative lock-time from seconds, converting the seconds into 512 second /// Creates a relative lock-time from seconds, converting the seconds into 512 second
/// interval with floor division. /// interval with floor division.
/// ///
/// Will return an error if the input cannot be encoded in 16 bits. /// Will return an error if the input cannot be encoded in 16 bits.
@ -347,7 +348,7 @@ impl Sequence {
} }
} }
/// Create a relative lock-time from seconds, converting the seconds into 512 second /// Creates a relative lock-time from seconds, converting the seconds into 512 second
/// interval with ceiling division. /// interval with ceiling division.
/// ///
/// Will return an error if the input cannot be encoded in 16 bits. /// Will return an error if the input cannot be encoded in 16 bits.
@ -366,7 +367,7 @@ impl Sequence {
!self.is_final() !self.is_final()
} }
/// Create a sequence from a u32 value. /// Creates a sequence from a u32 value.
#[inline] #[inline]
pub fn from_consensus(n: u32) -> Self { pub fn from_consensus(n: u32) -> Self {
Sequence(n) Sequence(n)
@ -590,6 +591,7 @@ pub struct Transaction {
impl Transaction { impl Transaction {
/// Computes a "normalized TXID" which does not include any signatures. /// Computes a "normalized TXID" which does not include any signatures.
///
/// This gives a way to identify a transaction that is "the same" as /// This gives a way to identify a transaction that is "the same" as
/// another in the sense of having same inputs and outputs. /// another in the sense of having same inputs and outputs.
pub fn ntxid(&self) -> sha256d::Hash { pub fn ntxid(&self) -> sha256d::Hash {
@ -602,10 +604,11 @@ impl Transaction {
cloned_tx.txid().into() cloned_tx.txid().into()
} }
/// Computes the txid. For non-segwit transactions this will be identical /// Computes the [`Txid`].
/// to the output of `wtxid()`, but for segwit transactions, ///
/// this will give the correct txid (not including witnesses) while `wtxid` /// Hashes the transaction **excluding** the segwit data (i.e. the marker, flag bytes, and the
/// will also hash witnesses. /// witness fields themselves). For non-segwit transactions which do not have any segwit data,
/// this will be equal to [`Transaction::wtxid()`].
pub fn txid(&self) -> Txid { pub fn txid(&self) -> Txid {
let mut enc = Txid::engine(); let mut enc = Txid::engine();
self.version.consensus_encode(&mut enc).expect("engines don't error"); self.version.consensus_encode(&mut enc).expect("engines don't error");
@ -615,9 +618,11 @@ impl Transaction {
Txid::from_engine(enc) Txid::from_engine(enc)
} }
/// Computes SegWit-version of the transaction id (wtxid). For transaction with the witness /// Computes the segwit version of the transaction id.
/// data this hash includes witness, for pre-witness transaction it is equal to the normal ///
/// value returned by txid() function. /// Hashes the transaction **including** all segwit data (i.e. the marker, flag bytes, and the
/// witness fields themselves). For non-segwit transactions which do not have any segwit data,
/// this will be equal to [`Transaction::txid()`].
pub fn wtxid(&self) -> Wtxid { pub fn wtxid(&self) -> Wtxid {
let mut enc = Wtxid::engine(); let mut enc = Wtxid::engine();
self.consensus_encode(&mut enc).expect("engines don't error"); self.consensus_encode(&mut enc).expect("engines don't error");
@ -640,9 +645,9 @@ impl Transaction {
/// - Does NOT attempt to support OP_CODESEPARATOR. In general this would require evaluating /// - Does NOT attempt to support OP_CODESEPARATOR. In general this would require evaluating
/// `script_pubkey` to determine which separators get evaluated and which don't, which we don't /// `script_pubkey` to determine which separators get evaluated and which don't, which we don't
/// have the information to determine. /// have the information to determine.
/// - Does NOT handle the sighash single bug (see "Return type" section) /// - Does NOT handle the sighash single bug (see "Returns" section)
/// ///
/// # Return type /// # Returns
/// ///
/// This function can't handle the SIGHASH_SINGLE bug internally, so it returns [`EncodeSigningDataResult`] /// This function can't handle the SIGHASH_SINGLE bug internally, so it returns [`EncodeSigningDataResult`]
/// that must be handled by the caller (see [`EncodeSigningDataResult::is_sighash_single_bug`]). /// that must be handled by the caller (see [`EncodeSigningDataResult::is_sighash_single_bug`]).
@ -826,6 +831,7 @@ impl Transaction {
} }
/// Verify that this transaction is able to spend its inputs. /// Verify that this transaction is able to spend its inputs.
///
/// The `spent` closure should not return the same [`TxOut`] twice! /// The `spent` closure should not return the same [`TxOut`] twice!
#[cfg(feature="bitcoinconsensus")] #[cfg(feature="bitcoinconsensus")]
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))] #[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
@ -846,14 +852,25 @@ impl Transaction {
Ok(()) Ok(())
} }
/// Is this a coin base transaction? /// Checks if this is a coinbase transaction.
///
/// The first transaction in the block distributes the mining reward and is called the coinbase
/// transaction. It is impossible to check if the transaction is first in the block, so this
/// function checks the structure of the transaction instead - the previous output must be
/// all-zeros (creates satoshis "out of thin air").
pub fn is_coin_base(&self) -> bool { pub fn is_coin_base(&self) -> bool {
self.input.len() == 1 && self.input[0].previous_output.is_null() self.input.len() == 1 && self.input[0].previous_output.is_null()
} }
/// Returns `true` if the transaction itself opted in to be BIP-125-replaceable (RBF). This /// Returns `true` if the transaction itself opted in to be BIP-125-replaceable (RBF).
/// **does not** cover the case where a transaction becomes replaceable due to ancestors being ///
/// RBF. /// # Warning
///
/// **Incorrectly relying on RBF may lead to monetary loss!**
///
/// This **does not** cover the case where a transaction becomes replaceable due to ancestors
/// being RBF. Please note that transactions **may be replaced** even if they **do not** include
/// the RBF signal: <https://bitcoinops.org/en/newsletters/2022/10/19/#transaction-replacement-option>.
pub fn is_explicitly_rbf(&self) -> bool { pub fn is_explicitly_rbf(&self) -> bool {
self.input.iter().any(|input| input.sequence.is_rbf()) self.input.iter().any(|input| input.sequence.is_rbf())
} }

View File

@ -18,7 +18,7 @@ use crate::prelude::*;
use crate::VarInt; use crate::VarInt;
use crate::taproot::TAPROOT_ANNEX_PREFIX; use crate::taproot::TAPROOT_ANNEX_PREFIX;
/// The Witness is the data used to unlock bitcoins since the [segwit upgrade](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki) /// The Witness is the data used to unlock bitcoin since the [segwit upgrade].
/// ///
/// Can be logically seen as an array of bytestrings, i.e. `Vec<Vec<u8>>`, and it is serialized on the wire /// Can be logically seen as an array of bytestrings, i.e. `Vec<Vec<u8>>`, and it is serialized on the wire
/// in that format. You can convert between this type and `Vec<Vec<u8>>` by using [`Witness::from_slice`] /// in that format. You can convert between this type and `Vec<Vec<u8>>` by using [`Witness::from_slice`]
@ -27,23 +27,25 @@ use crate::taproot::TAPROOT_ANNEX_PREFIX;
/// For serialization and deserialization performance it is stored internally as a single `Vec`, /// For serialization and deserialization performance it is stored internally as a single `Vec`,
/// saving some allocations. /// saving some allocations.
/// ///
/// [segwit upgrade]: <https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki>
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Witness { pub struct Witness {
/// Contains the witness `Vec<Vec<u8>>` serialization without the initial varint indicating the /// Contains the witness `Vec<Vec<u8>>` serialization without the initial varint indicating the
/// number of elements (which is stored in `witness_elements`) /// number of elements (which is stored in `witness_elements`).
content: Vec<u8>, content: Vec<u8>,
/// Number of elements in the witness. /// The number of elements in the witness.
/// It is stored separately (instead of as VarInt in the initial part of content) so that method ///
/// like [`Witness::push`] doesn't have case requiring to shift the entire array /// Stored separately (instead of as a VarInt in the initial part of content) so that methods
/// like [`Witness::push`] don't have to shift the entire array.
witness_elements: usize, witness_elements: usize,
/// This is the valid index pointing to the beginning of the index area. This area is 4 * stack_size bytes /// This is the valid index pointing to the beginning of the index area. This area is 4 *
/// at the end of the content vector which stores the indices of each item. /// stack_size bytes at the end of the content vector which stores the indices of each item.
indices_start: usize, indices_start: usize,
} }
/// Support structure to allow efficient and convenient iteration over the Witness elements /// An iterator returning individual witness elements.
pub struct Iter<'a> { pub struct Iter<'a> {
inner: &'a [u8], inner: &'a [u8],
indices_start: usize, indices_start: usize,
@ -162,7 +164,7 @@ impl Encodable for Witness {
} }
impl Witness { impl Witness {
/// Create a new empty [`Witness`] /// Creates a new empty [`Witness`].
pub fn new() -> Self { pub fn new() -> Self {
Witness::default() Witness::default()
} }
@ -202,17 +204,17 @@ impl Witness {
} }
} }
/// Convenience method to create an array of byte-arrays from this witness /// Convenience method to create an array of byte-arrays from this witness.
pub fn to_vec(&self) -> Vec<Vec<u8>> { pub fn to_vec(&self) -> Vec<Vec<u8>> {
self.iter().map(|s| s.to_vec()).collect() self.iter().map(|s| s.to_vec()).collect()
} }
/// Returns `true` if the witness contains no element /// Returns `true` if the witness contains no element.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.witness_elements == 0 self.witness_elements == 0
} }
/// Returns a struct implementing [`Iterator`] /// Returns a struct implementing [`Iterator`].
pub fn iter(&self) -> Iter { pub fn iter(&self) -> Iter {
Iter { Iter {
inner: self.content.as_slice(), inner: self.content.as_slice(),
@ -221,12 +223,12 @@ impl Witness {
} }
} }
/// Returns the number of elements this witness holds /// Returns the number of elements this witness holds.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.witness_elements self.witness_elements
} }
/// Returns the bytes required when this Witness is consensus encoded /// Returns the bytes required when this Witness is consensus encoded.
pub fn serialized_len(&self) -> usize { pub fn serialized_len(&self) -> usize {
self.iter() self.iter()
.map(|el| VarInt(el.len() as u64).len() + el.len()) .map(|el| VarInt(el.len() as u64).len() + el.len())
@ -234,14 +236,14 @@ impl Witness {
+ VarInt(self.witness_elements as u64).len() + VarInt(self.witness_elements as u64).len()
} }
/// Clear the witness /// Clear the witness.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.content.clear(); self.content.clear();
self.witness_elements = 0; self.witness_elements = 0;
self.indices_start = 0; self.indices_start = 0;
} }
/// Push a new element on the witness, requires an allocation /// Push a new element on the witness, requires an allocation.
pub fn push<T: AsRef<[u8]>>(&mut self, new_element: T) { pub fn push<T: AsRef<[u8]>>(&mut self, new_element: T) {
self.push_slice(new_element.as_ref()); self.push_slice(new_element.as_ref());
} }
@ -284,7 +286,7 @@ impl Witness {
Some(&self.content[start..start + varint.0 as usize]) Some(&self.content[start..start + varint.0 as usize])
} }
/// Return the last element in the witness, if any /// Returns the last element in the witness, if any.
pub fn last(&self) -> Option<&[u8]> { pub fn last(&self) -> Option<&[u8]> {
if self.witness_elements == 0 { if self.witness_elements == 0 {
None None
@ -293,7 +295,7 @@ impl Witness {
} }
} }
/// Return the second-to-last element in the witness, if any /// Returns the second-to-last element in the witness, if any.
pub fn second_to_last(&self) -> Option<&[u8]> { pub fn second_to_last(&self) -> Option<&[u8]> {
if self.witness_elements <= 1 { if self.witness_elements <= 1 {
None None

View File

@ -35,33 +35,33 @@ use crate::blockdata::transaction::{TxOut, Transaction, TxIn};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::network::{message_blockdata::Inventory, address::{Address, AddrV2Message}}; use crate::network::{message_blockdata::Inventory, address::{Address, AddrV2Message}};
/// Encoding error /// Encoding error.
#[derive(Debug)] #[derive(Debug)]
#[non_exhaustive] #[non_exhaustive]
pub enum Error { pub enum Error {
/// And I/O error /// And I/O error.
Io(io::Error), Io(io::Error),
/// PSBT-related error /// PSBT-related error.
Psbt(psbt::Error), Psbt(psbt::Error),
/// Tried to allocate an oversized vector /// Tried to allocate an oversized vector.
OversizedVectorAllocation { OversizedVectorAllocation {
/// The capacity requested /// The capacity requested.
requested: usize, requested: usize,
/// The maximum capacity /// The maximum capacity.
max: usize, max: usize,
}, },
/// Checksum was invalid /// Checksum was invalid.
InvalidChecksum { InvalidChecksum {
/// The expected checksum /// The expected checksum.
expected: [u8; 4], expected: [u8; 4],
/// The invalid checksum /// The invalid checksum.
actual: [u8; 4], actual: [u8; 4],
}, },
/// VarInt was encoded in a non-minimal way /// VarInt was encoded in a non-minimal way.
NonMinimalVarInt, NonMinimalVarInt,
/// Parsing error /// Parsing error.
ParseFailed(&'static str), ParseFailed(&'static str),
/// Unsupported Segwit flag /// Unsupported Segwit flag.
UnsupportedSegwitFlag(u8), UnsupportedSegwitFlag(u8),
} }
@ -114,7 +114,7 @@ impl From<psbt::Error> for Error {
} }
} }
/// Encode an object into a vector /// Encodes an object into a vector.
pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> { pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> {
let mut encoder = Vec::new(); let mut encoder = Vec::new();
let len = data.consensus_encode(&mut encoder).expect("in-memory writers don't error"); let len = data.consensus_encode(&mut encoder).expect("in-memory writers don't error");
@ -122,12 +122,12 @@ pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> {
encoder encoder
} }
/// Encode an object into a hex-encoded string /// Encodes an object into a hex-encoded string.
pub fn serialize_hex<T: Encodable + ?Sized>(data: &T) -> String { pub fn serialize_hex<T: Encodable + ?Sized>(data: &T) -> String {
serialize(data)[..].to_hex() serialize(data)[..].to_hex()
} }
/// Deserialize an object from a vector, will error if said deserialization /// Deserializes an object from a vector, will error if said deserialization
/// doesn't consume the entire vector. /// doesn't consume the entire vector.
pub fn deserialize<T: Decodable>(data: &[u8]) -> Result<T, Error> { pub fn deserialize<T: Decodable>(data: &[u8]) -> Result<T, Error> {
let (rv, consumed) = deserialize_partial(data)?; let (rv, consumed) = deserialize_partial(data)?;
@ -140,7 +140,7 @@ pub fn deserialize<T: Decodable>(data: &[u8]) -> Result<T, Error> {
} }
} }
/// Deserialize an object from a vector, but will not report an error if said deserialization /// Deserializes an object from a vector, but will not report an error if said deserialization
/// doesn't consume the entire vector. /// doesn't consume the entire vector.
pub fn deserialize_partial<T: Decodable>(data: &[u8]) -> Result<(T, usize), Error> { pub fn deserialize_partial<T: Decodable>(data: &[u8]) -> Result<(T, usize), Error> {
let mut decoder = Cursor::new(data); let mut decoder = Cursor::new(data);
@ -151,57 +151,57 @@ pub fn deserialize_partial<T: Decodable>(data: &[u8]) -> Result<(T, usize), Erro
} }
/// Extensions of `Write` to encode data as per Bitcoin consensus /// Extensions of `Write` to encode data as per Bitcoin consensus.
pub trait WriteExt : io::Write { pub trait WriteExt : io::Write {
/// Output a 64-bit uint /// Outputs a 64-bit unsigned integer.
fn emit_u64(&mut self, v: u64) -> Result<(), io::Error>; fn emit_u64(&mut self, v: u64) -> Result<(), io::Error>;
/// Output a 32-bit uint /// Outputs a 32-bit unsigned integer.
fn emit_u32(&mut self, v: u32) -> Result<(), io::Error>; fn emit_u32(&mut self, v: u32) -> Result<(), io::Error>;
/// Output a 16-bit uint /// Outputs a 16-bit unsigned integer.
fn emit_u16(&mut self, v: u16) -> Result<(), io::Error>; fn emit_u16(&mut self, v: u16) -> Result<(), io::Error>;
/// Output a 8-bit uint /// Outputs a 8-bit unsigned integer.
fn emit_u8(&mut self, v: u8) -> Result<(), io::Error>; fn emit_u8(&mut self, v: u8) -> Result<(), io::Error>;
/// Output a 64-bit int /// Outputs a 64-bit signed integer.
fn emit_i64(&mut self, v: i64) -> Result<(), io::Error>; fn emit_i64(&mut self, v: i64) -> Result<(), io::Error>;
/// Output a 32-bit int /// Outputs a 32-bit signed integer.
fn emit_i32(&mut self, v: i32) -> Result<(), io::Error>; fn emit_i32(&mut self, v: i32) -> Result<(), io::Error>;
/// Output a 16-bit int /// Outputs a 16-bit signed integer.
fn emit_i16(&mut self, v: i16) -> Result<(), io::Error>; fn emit_i16(&mut self, v: i16) -> Result<(), io::Error>;
/// Output a 8-bit int /// Outputs a 8-bit signed integer.
fn emit_i8(&mut self, v: i8) -> Result<(), io::Error>; fn emit_i8(&mut self, v: i8) -> Result<(), io::Error>;
/// Output a boolean /// Outputs a boolean.
fn emit_bool(&mut self, v: bool) -> Result<(), io::Error>; fn emit_bool(&mut self, v: bool) -> Result<(), io::Error>;
/// Output a byte slice /// Outputs a byte slice.
fn emit_slice(&mut self, v: &[u8]) -> Result<(), io::Error>; fn emit_slice(&mut self, v: &[u8]) -> Result<(), io::Error>;
} }
/// Extensions of `Read` to decode data as per Bitcoin consensus /// Extensions of `Read` to decode data as per Bitcoin consensus.
pub trait ReadExt : io::Read { pub trait ReadExt : io::Read {
/// Read a 64-bit uint /// Reads a 64-bit unsigned integer.
fn read_u64(&mut self) -> Result<u64, Error>; fn read_u64(&mut self) -> Result<u64, Error>;
/// Read a 32-bit uint /// Reads a 32-bit unsigned integer.
fn read_u32(&mut self) -> Result<u32, Error>; fn read_u32(&mut self) -> Result<u32, Error>;
/// Read a 16-bit uint /// Reads a 16-bit unsigned integer.
fn read_u16(&mut self) -> Result<u16, Error>; fn read_u16(&mut self) -> Result<u16, Error>;
/// Read a 8-bit uint /// Reads a 8-bit unsigned integer.
fn read_u8(&mut self) -> Result<u8, Error>; fn read_u8(&mut self) -> Result<u8, Error>;
/// Read a 64-bit int /// Reads a 64-bit signed integer.
fn read_i64(&mut self) -> Result<i64, Error>; fn read_i64(&mut self) -> Result<i64, Error>;
/// Read a 32-bit int /// Reads a 32-bit signed integer.
fn read_i32(&mut self) -> Result<i32, Error>; fn read_i32(&mut self) -> Result<i32, Error>;
/// Read a 16-bit int /// Reads a 16-bit signed integer.
fn read_i16(&mut self) -> Result<i16, Error>; fn read_i16(&mut self) -> Result<i16, Error>;
/// Read a 8-bit int /// Reads a 8-bit signed integer.
fn read_i8(&mut self) -> Result<i8, Error>; fn read_i8(&mut self) -> Result<i8, Error>;
/// Read a boolean /// Reads a boolean.
fn read_bool(&mut self) -> Result<bool, Error>; fn read_bool(&mut self) -> Result<bool, Error>;
/// Read a byte slice /// Reads a byte slice.
fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error>; fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error>;
} }
@ -281,59 +281,55 @@ impl<R: Read + ?Sized> ReadExt for R {
} }
} }
/// Maximum size, in bytes, of a vector we are allowed to decode /// Maximum size, in bytes, of a vector we are allowed to decode.
pub const MAX_VEC_SIZE: usize = 4_000_000; pub const MAX_VEC_SIZE: usize = 4_000_000;
/// Data which can be encoded in a consensus-consistent way /// Data which can be encoded in a consensus-consistent way.
pub trait Encodable { pub trait Encodable {
/// Encode an object with a well-defined format. /// Encodes an object with a well-defined format.
/// Returns the number of bytes written on success.
/// ///
/// The only errors returned are errors propagated from the writer. /// # Returns
///
/// The number of bytes written on success. The only errors returned are errors propagated from
/// the writer.
fn consensus_encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error>; fn consensus_encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error>;
} }
/// Data which can be encoded in a consensus-consistent way /// Data which can be encoded in a consensus-consistent way.
pub trait Decodable: Sized { pub trait Decodable: Sized {
/// Decode `Self` from a size-limited reader. /// Decode `Self` from a size-limited reader.
/// ///
/// Like `consensus_decode` but relies on the reader being /// Like `consensus_decode` but relies on the reader being limited in the amount of data it
/// limited in the amount of data it returns, e.g. by /// returns, e.g. by being wrapped in [`std::io::Take`].
/// being wrapped in [`std::io::Take`].
/// ///
/// Failling to obide to this requirement might lead to /// Failling to obide to this requirement might lead to memory exhaustion caused by malicious
/// memory exhaustion caused by malicious inputs. /// inputs.
/// ///
/// Users should default to `consensus_decode`, but /// Users should default to `consensus_decode`, but when data to be decoded is already in a byte
/// when data to be decoded is already in a byte vector /// vector of a limited size, calling this function directly might be marginally faster (due to
/// of a limited size, calling this function directly /// avoiding extra checks).
/// might be marginally faster (due to avoiding
/// extra checks).
/// ///
/// ### Rules for trait implementations /// ### Rules for trait implementations
/// ///
/// * Simple types that that have a fixed size (own and member fields), /// * Simple types that that have a fixed size (own and member fields), don't have to overwrite
/// don't have to overwrite this method, or be concern with it. /// this method, or be concern with it.
/// * Types that deserialize using externally provided length /// * Types that deserialize using externally provided length should implement it:
/// should implement it: /// * Make `consensus_decode` forward to `consensus_decode_bytes_from_finite_reader` with the
/// * Make `consensus_decode` forward to `consensus_decode_bytes_from_finite_reader` /// reader wrapped by `Take`. Failure to do so, without other forms of memory exhaustion
/// with the reader wrapped by `Take`. Failure to do so, without other /// protection might lead to resource exhaustion vulnerability.
/// forms of memory exhaustion protection might lead to resource exhaustion /// * Put a max cap on things like `Vec::with_capacity` to avoid oversized allocations, and
/// vulnerability. /// rely on the reader running out of data, and collections reallocating on a legitimately
/// * Put a max cap on things like `Vec::with_capacity` to avoid oversized /// oversized input data, instead of trying to enforce arbitrary length limits.
/// allocations, and rely on the reader running out of data, and collections /// * Types that contain other types that implement custom
/// reallocating on a legitimately oversized input data, instead of trying /// `consensus_decode_from_finite_reader`, should also implement it applying same rules, and
/// to enforce arbitrary length limits. /// in addition make sure to call `consensus_decode_from_finite_reader` on all members, to
/// * Types that contain other types that implement custom `consensus_decode_from_finite_reader`, /// avoid creating redundant `Take` wrappers. Failure to do so might result only in a tiny
/// should also implement it applying same rules, and in addition make sure to call /// performance hit.
/// `consensus_decode_from_finite_reader` on all members, to avoid creating redundant
/// `Take` wrappers. Failure to do so might result only in a tiny performance hit.
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> { fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
// This method is always strictly less general than, `consensus_decode`, // This method is always strictly less general than, `consensus_decode`, so it's safe and
// so it's safe and make sense to default to just calling it. // make sense to default to just calling it. This way most types, that don't care about
// This way most types, that don't care about protecting against // protecting against resource exhaustion due to malicious input, can just ignore it.
// resource exhaustion due to malicious input, can just ignore it.
Self::consensus_decode(reader) Self::consensus_decode(reader)
} }
@ -351,11 +347,11 @@ pub trait Decodable: Sized {
} }
} }
/// A variable-length unsigned integer /// A variable-length unsigned integer.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
pub struct VarInt(pub u64); pub struct VarInt(pub u64);
/// Data which must be preceded by a 4-byte checksum /// Data which must be preceded by a 4-byte checksum.
#[derive(PartialEq, Eq, Clone, Debug)] #[derive(PartialEq, Eq, Clone, Debug)]
pub struct CheckedData(pub Vec<u8>); pub struct CheckedData(pub Vec<u8>);
@ -390,6 +386,7 @@ impl_int_encodable!(i64, read_i64, emit_i64);
#[allow(clippy::len_without_is_empty)] // VarInt has on concept of 'is_empty'. #[allow(clippy::len_without_is_empty)] // VarInt has on concept of 'is_empty'.
impl VarInt { impl VarInt {
/// Gets the length of this VarInt when encoded. /// Gets the length of this VarInt when encoded.
///
/// Returns 1 for 0..=0xFC, 3 for 0xFD..=(2^16-1), 5 for 0x10000..=(2^32-1), /// Returns 1 for 0..=0xFC, 3 for 0xFD..=(2^16-1), 5 for 0x10000..=(2^32-1),
/// and 9 otherwise. /// and 9 otherwise.
#[inline] #[inline]
@ -464,7 +461,6 @@ impl Decodable for VarInt {
} }
} }
// Booleans
impl Encodable for bool { impl Encodable for bool {
#[inline] #[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> { fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
@ -480,7 +476,6 @@ impl Decodable for bool {
} }
} }
// Strings
impl Encodable for String { impl Encodable for String {
#[inline] #[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> { fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
@ -499,7 +494,6 @@ impl Decodable for String {
} }
} }
// Cow<'static, str>
impl Encodable for Cow<'static, str> { impl Encodable for Cow<'static, str> {
#[inline] #[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> { fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
@ -519,8 +513,6 @@ impl Decodable for Cow<'static, str> {
} }
} }
// Arrays
macro_rules! impl_array { macro_rules! impl_array {
( $size:literal ) => { ( $size:literal ) => {
impl Encodable for [u8; $size] { impl Encodable for [u8; $size] {
@ -571,7 +563,6 @@ impl Encodable for [u16; 8] {
} }
} }
// Vectors
macro_rules! impl_vec { macro_rules! impl_vec {
($type: ty) => { ($type: ty) => {
impl Encodable for Vec<$type> { impl Encodable for Vec<$type> {
@ -636,7 +627,7 @@ struct ReadBytesFromFiniteReaderOpts {
chunk_size: usize, chunk_size: usize,
} }
/// Read `opts.len` bytes from reader, where `opts.len` could potentially be malicious /// Read `opts.len` bytes from reader, where `opts.len` could potentially be malicious.
/// ///
/// This function relies on reader being bound in amount of data /// This function relies on reader being bound in amount of data
/// it returns for OOM protection. See [`Decodable::consensus_decode_from_finite_reader`]. /// it returns for OOM protection. See [`Decodable::consensus_decode_from_finite_reader`].
@ -689,13 +680,12 @@ impl Decodable for Box<[u8]> {
} }
/// Do a double-SHA256 on some data and return the first 4 bytes /// Does a double-SHA256 on `data` and returns the first 4 bytes.
fn sha2_checksum(data: &[u8]) -> [u8; 4] { fn sha2_checksum(data: &[u8]) -> [u8; 4] {
let checksum = <sha256d::Hash as Hash>::hash(data); let checksum = <sha256d::Hash as Hash>::hash(data);
[checksum[0], checksum[1], checksum[2], checksum[3]] [checksum[0], checksum[1], checksum[2], checksum[3]]
} }
// Checked data
impl Encodable for CheckedData { impl Encodable for CheckedData {
#[inline] #[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> { fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
@ -725,7 +715,6 @@ impl Decodable for CheckedData {
} }
} }
// References
impl<'a, T: Encodable> Encodable for &'a T { impl<'a, T: Encodable> Encodable for &'a T {
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> { fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
(**self).consensus_encode(w) (**self).consensus_encode(w)
@ -750,7 +739,6 @@ impl<T: Encodable> Encodable for sync::Arc<T> {
} }
} }
// Tuples
macro_rules! tuple_encode { macro_rules! tuple_encode {
($($x:ident),*) => { ($($x:ident),*) => {
impl <$($x: Encodable),*> Encodable for ($($x),*) { impl <$($x: Encodable),*> Encodable for ($($x),*) {
@ -821,7 +809,6 @@ impl Decodable for TapLeafHash {
} }
} }
// Tests
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -11,6 +11,7 @@ use super::Case;
use crate::prelude::*; use crate::prelude::*;
/// Extension trait for types that can be displayed as hex. /// Extension trait for types that can be displayed as hex.
///
/// Types that have a single, obvious text representation being hex should **not** implement this /// Types that have a single, obvious text representation being hex should **not** implement this
/// trait and simply implement `Display` instead. /// trait and simply implement `Display` instead.
/// ///