Merge rust-bitcoin/rust-bitcoin#865: Cleanup transaction docs
e503f14331
Improve docs: blockdata::transaction (Tobin Harding)f02b3a8472
Add code comment for emtpy input (Tobin Harding)6a0ec1ac47
Remove redundant _eq (Tobin Harding)3bcc146a44
Improve docs: encode_signing_data_to/signature_hash (Tobin Harding) Pull request description: Do some cleanups to the docs in `blockdata::transaction`. Patch 1 needs the most careful review please. The rest should not be too controversial. ACKs for top commit: apoelstra: ACKe503f14331
dr-orlovsky: ACKe503f14331
Tree-SHA512: 3953226e1b7f0db0371b1902888407a48531688bf8ed08539a0090f369b491b130d70b2fae859878ef178a397cefe0ee2a15f3358afc990a2776194cc2b3882b
This commit is contained in:
commit
501cf63f0d
|
@ -42,18 +42,21 @@ use consensus::encode::MAX_VEC_SIZE;
|
||||||
use hash_types::{SigHash, Txid, Wtxid};
|
use hash_types::{SigHash, Txid, Wtxid};
|
||||||
use VarInt;
|
use VarInt;
|
||||||
|
|
||||||
/// A reference to a transaction output
|
#[cfg(doc)]
|
||||||
|
use util::sighash::SchnorrSigHashType;
|
||||||
|
|
||||||
|
/// A reference to a transaction output.
|
||||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct OutPoint {
|
pub struct OutPoint {
|
||||||
/// The referenced transaction's txid
|
/// The referenced transaction's txid.
|
||||||
pub txid: Txid,
|
pub txid: Txid,
|
||||||
/// The index of the referenced output in its transaction's vout
|
/// The index of the referenced output in its transaction's vout.
|
||||||
pub vout: u32,
|
pub vout: u32,
|
||||||
}
|
}
|
||||||
serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout);
|
serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout);
|
||||||
|
|
||||||
impl OutPoint {
|
impl OutPoint {
|
||||||
/// Create a new [OutPoint].
|
/// Creates a new [`OutPoint`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(txid: Txid, vout: u32) -> OutPoint {
|
pub fn new(txid: Txid, vout: u32) -> OutPoint {
|
||||||
OutPoint {
|
OutPoint {
|
||||||
|
@ -64,8 +67,7 @@ impl OutPoint {
|
||||||
|
|
||||||
/// Creates a "null" `OutPoint`.
|
/// Creates a "null" `OutPoint`.
|
||||||
///
|
///
|
||||||
/// This value is used for coinbase transactions because they don't have
|
/// This value is used for coinbase transactions because they don't have any previous outputs.
|
||||||
/// any previous outputs.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn null() -> OutPoint {
|
pub fn null() -> OutPoint {
|
||||||
OutPoint {
|
OutPoint {
|
||||||
|
@ -86,7 +88,7 @@ impl OutPoint {
|
||||||
/// let tx = &block.txdata[0];
|
/// let tx = &block.txdata[0];
|
||||||
///
|
///
|
||||||
/// // Coinbase transactions don't have any previous output.
|
/// // Coinbase transactions don't have any previous output.
|
||||||
/// assert_eq!(tx.input[0].previous_output.is_null(), true);
|
/// assert!(tx.input[0].previous_output.is_null());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_null(&self) -> bool {
|
pub fn is_null(&self) -> bool {
|
||||||
|
@ -146,7 +148,7 @@ impl error::Error for ParseOutPointError {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a string-encoded transaction index (vout).
|
/// Parses a string-encoded transaction index (vout).
|
||||||
/// It 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 {
|
||||||
let first = s.chars().next().unwrap();
|
let first = s.chars().next().unwrap();
|
||||||
|
@ -183,10 +185,10 @@ impl ::core::str::FromStr for OutPoint {
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct TxIn {
|
pub struct TxIn {
|
||||||
/// The reference to the previous output that is being used an an input
|
/// The reference to the previous output that is being used an an input.
|
||||||
pub previous_output: OutPoint,
|
pub previous_output: OutPoint,
|
||||||
/// The script which pushes values on the stack which will cause
|
/// The script which pushes values on the stack which will cause
|
||||||
/// the referenced output's script to accept
|
/// the referenced output's script to be accepted.
|
||||||
pub script_sig: Script,
|
pub script_sig: Script,
|
||||||
/// The sequence number, which suggests to miners which of two
|
/// The sequence number, which suggests to miners which of two
|
||||||
/// conflicting transactions should be preferred, or 0xFFFFFFFF
|
/// conflicting transactions should be preferred, or 0xFFFFFFFF
|
||||||
|
@ -216,13 +218,13 @@ impl Default for TxIn {
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct TxOut {
|
pub struct TxOut {
|
||||||
/// The value of the output, in satoshis
|
/// The value of the output, in satoshis.
|
||||||
pub value: u64,
|
pub value: u64,
|
||||||
/// The script which must satisfy for the output to be spent
|
/// The script which must be satisfied for the output to be spent.
|
||||||
pub script_pubkey: Script
|
pub script_pubkey: Script
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used as a "null txout" in consensus signing code
|
// This is used as a "null txout" in consensus signing code.
|
||||||
impl Default for TxOut {
|
impl Default for TxOut {
|
||||||
fn default() -> TxOut {
|
fn default() -> TxOut {
|
||||||
TxOut { value: 0xffffffffffffffff, script_pubkey: Script::new() }
|
TxOut { value: 0xffffffffffffffff, script_pubkey: Script::new() }
|
||||||
|
@ -264,12 +266,11 @@ impl Default for TxOut {
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
/// The protocol version, is currently expected to be 1 or 2 (BIP 68).
|
/// The protocol version, is currently expected to be 1 or 2 (BIP 68).
|
||||||
pub version: i32,
|
pub version: i32,
|
||||||
/// Block number before which this transaction is valid, or 0 for
|
/// Block number before which this transaction is valid, or 0 for valid immediately.
|
||||||
/// valid immediately.
|
|
||||||
pub lock_time: u32,
|
pub lock_time: u32,
|
||||||
/// List of inputs
|
/// List of transaction inputs.
|
||||||
pub input: Vec<TxIn>,
|
pub input: Vec<TxIn>,
|
||||||
/// List of outputs
|
/// List of transaction outputs.
|
||||||
pub output: Vec<TxOut>,
|
pub output: Vec<TxOut>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,20 +311,23 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encodes the signing data from which a signature hash for a given input index with a given
|
/// Encodes the signing data from which a signature hash for a given input index with a given
|
||||||
/// sighash flag can be computed. To actually produce a scriptSig, this hash needs to be run
|
/// sighash flag can be computed.
|
||||||
/// through an ECDSA signer, the SigHashType appended to the resulting sig, and a script
|
|
||||||
/// written around this, but this is the general (and hard) part.
|
|
||||||
///
|
///
|
||||||
/// The `sighash_type` supports arbitrary `u32` value, instead of just [`SigHashType`],
|
/// To actually produce a scriptSig, this hash needs to be run through an ECDSA signer, the
|
||||||
/// because internally 4 bytes are being hashed, even though only lowest byte
|
/// [`EcdsaSigHashType`] appended to the resulting sig, and a script written around this, but
|
||||||
/// is appended to signature in a transaction.
|
/// this is the general (and hard) part.
|
||||||
///
|
///
|
||||||
/// *Warning* This does NOT attempt to support OP_CODESEPARATOR. In general this would require
|
/// The `sighash_type` supports an arbitrary `u32` value, instead of just [`EcdsaSigHashType`],
|
||||||
/// evaluating `script_pubkey` to determine which separators get evaluated and which don't,
|
/// because internally 4 bytes are being hashed, even though only lowest byte is appended to
|
||||||
/// which we don't have the information to determine.
|
/// signature in a transaction.
|
||||||
|
///
|
||||||
|
/// **Warning**: This 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 have the information to determine.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if `input_index` is greater than or equal to `self.input.len()`
|
///
|
||||||
|
/// If `input_index` is out of bounds (greater than or equal to `self.input.len()`).
|
||||||
pub fn encode_signing_data_to<Write: io::Write, U: Into<u32>>(
|
pub fn encode_signing_data_to<Write: io::Write, U: Into<u32>>(
|
||||||
&self,
|
&self,
|
||||||
mut writer: Write,
|
mut writer: Write,
|
||||||
|
@ -392,18 +396,8 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a signature hash for a given input index with a given sighash flag.
|
/// Computes a signature hash for a given input index with a given sighash flag.
|
||||||
/// To actually produce a scriptSig, this hash needs to be run through an
|
|
||||||
/// ECDSA signer, the SigHashType appended to the resulting sig, and a
|
|
||||||
/// script written around this, but this is the general (and hard) part.
|
|
||||||
///
|
|
||||||
/// *Warning* This 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 have the information to
|
|
||||||
/// determine.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// Panics if `input_index` is greater than or equal to `self.input.len()`
|
|
||||||
///
|
///
|
||||||
|
/// Please refer [`Self::encode_signing_data_to`] for full documentation of this method.
|
||||||
pub fn signature_hash(
|
pub fn signature_hash(
|
||||||
&self,
|
&self,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
|
@ -506,7 +500,7 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shorthand for [Self::verify_with_flags] with flag [bitcoinconsensus::VERIFY_ALL]
|
/// Shorthand for [`Self::verify_with_flags`] with flag [`bitcoinconsensus::VERIFY_ALL`].
|
||||||
#[cfg(feature="bitcoinconsensus")]
|
#[cfg(feature="bitcoinconsensus")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
|
||||||
pub fn verify<S>(&self, spent: S) -> Result<(), script::Error>
|
pub fn verify<S>(&self, spent: S) -> Result<(), script::Error>
|
||||||
|
@ -514,8 +508,8 @@ impl Transaction {
|
||||||
self.verify_with_flags(spent, ::bitcoinconsensus::VERIFY_ALL)
|
self.verify_with_flags(spent, ::bitcoinconsensus::VERIFY_ALL)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify that this transaction is able to spend its inputs
|
/// Verify that this transaction is able to spend its inputs.
|
||||||
/// The lambda spent 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")))]
|
||||||
pub fn verify_with_flags<S, F>(&self, mut spent: S, flags: F) -> Result<(), script::Error>
|
pub fn verify_with_flags<S, F>(&self, mut spent: S, flags: F) -> Result<(), script::Error>
|
||||||
|
@ -595,6 +589,8 @@ impl Encodable for Transaction {
|
||||||
) -> Result<usize, io::Error> {
|
) -> Result<usize, io::Error> {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
len += self.version.consensus_encode(&mut s)?;
|
len += self.version.consensus_encode(&mut s)?;
|
||||||
|
// To avoid serialization ambiguity, no inputs means we use BIP141 serialization (see
|
||||||
|
// `Transaction` docs for full explanation).
|
||||||
let mut have_witness = self.input.is_empty();
|
let mut have_witness = self.input.is_empty();
|
||||||
for input in &self.input {
|
for input in &self.input {
|
||||||
if !input.witness.is_empty() {
|
if !input.witness.is_empty() {
|
||||||
|
@ -678,29 +674,30 @@ impl fmt::Display for NonStandardSigHashType {
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl error::Error for NonStandardSigHashType {}
|
impl error::Error for NonStandardSigHashType {}
|
||||||
|
|
||||||
/// Legacy Hashtype of an input's signature
|
/// Legacy Hashtype of an input's signature.
|
||||||
#[deprecated(since="0.28.0", note="Please use [`EcdsaSigHashType`] instead")]
|
#[deprecated(since="0.28.0", note="Please use [`EcdsaSigHashType`] instead")]
|
||||||
pub type SigHashType = EcdsaSigHashType;
|
pub type SigHashType = EcdsaSigHashType;
|
||||||
|
|
||||||
/// Hashtype of an input's signature, encoded in the last byte of the signature
|
/// Hashtype of an input's signature, encoded in the last byte of the signature.
|
||||||
/// Fixed values so they can be casted as integer types for encoding
|
///
|
||||||
/// See also [`crate::SchnorrSigHashType`]
|
/// Fixed values so they can be cast as integer types for encoding (see also
|
||||||
|
/// [`SchnorrSigHashType`]).
|
||||||
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
||||||
pub enum EcdsaSigHashType {
|
pub enum EcdsaSigHashType {
|
||||||
/// 0x1: Sign all outputs
|
/// 0x1: Sign all outputs.
|
||||||
All = 0x01,
|
All = 0x01,
|
||||||
/// 0x2: Sign no outputs --- anyone can choose the destination
|
/// 0x2: Sign no outputs --- anyone can choose the destination.
|
||||||
None = 0x02,
|
None = 0x02,
|
||||||
/// 0x3: Sign the output whose index matches this input's index. If none exists,
|
/// 0x3: Sign the output whose index matches this input's index. If none exists,
|
||||||
/// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`.
|
/// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`.
|
||||||
/// (This rule is probably an unintentional C++ism, but it's consensus so we have
|
/// (This rule is probably an unintentional C++ism, but it's consensus so we have
|
||||||
/// to follow it.)
|
/// to follow it.)
|
||||||
Single = 0x03,
|
Single = 0x03,
|
||||||
/// 0x81: Sign all outputs but only this input
|
/// 0x81: Sign all outputs but only this input.
|
||||||
AllPlusAnyoneCanPay = 0x81,
|
AllPlusAnyoneCanPay = 0x81,
|
||||||
/// 0x82: Sign no outputs and only this input
|
/// 0x82: Sign no outputs and only this input.
|
||||||
NonePlusAnyoneCanPay = 0x82,
|
NonePlusAnyoneCanPay = 0x82,
|
||||||
/// 0x83: Sign one output and only this input (see `Single` for what "one output" means)
|
/// 0x83: Sign one output and only this input (see `Single` for what "one output" means).
|
||||||
SinglePlusAnyoneCanPay = 0x83
|
SinglePlusAnyoneCanPay = 0x83
|
||||||
}
|
}
|
||||||
serde_string_impl!(EcdsaSigHashType, "a EcdsaSigHashType data");
|
serde_string_impl!(EcdsaSigHashType, "a EcdsaSigHashType data");
|
||||||
|
@ -736,7 +733,7 @@ impl str::FromStr for EcdsaSigHashType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EcdsaSigHashType {
|
impl EcdsaSigHashType {
|
||||||
/// Break the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean
|
/// Splits the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean.
|
||||||
pub(crate) fn split_anyonecanpay_flag(self) -> (EcdsaSigHashType, bool) {
|
pub(crate) fn split_anyonecanpay_flag(self) -> (EcdsaSigHashType, bool) {
|
||||||
match self {
|
match self {
|
||||||
EcdsaSigHashType::All => (EcdsaSigHashType::All, false),
|
EcdsaSigHashType::All => (EcdsaSigHashType::All, false),
|
||||||
|
|
Loading…
Reference in New Issue