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: ACK26be9ddd27
apoelstra: ACK26be9ddd27
Tree-SHA512: 8990ed812b3bb55f722ac7e85a8655b65744eb21ad3b16dae77e05d9273f86e248f1ef4945a35d7767241038986bc23e0a8024347e600f0c1e53f8de992208e2
This commit is contained in:
commit
fd5c5e43d2
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue