Rename `TxOutRef` to `OutPoint` and use it in `TxIn`.
Previously this structure was unused, it's now being used by the `TxIn` structure to simplify the code a little bit and avoid confusions. Also the rust-lightning source code has an `OutPoint` similar to this one but with the `vout` index as an `u16` to avoid unsafe conversions. I've added to new methods to `OutPoint`: - `null`: Creates a new "null" `OutPoint`. - `is_null`: Checks if the given `OutPoint` is null. Signed-off-by: Jean Pierre Dudey <jeandudey@hotmail.com>
This commit is contained in:
parent
85ddb66be0
commit
32631e44ad
|
@ -23,7 +23,7 @@ use std::default::Default;
|
|||
|
||||
use blockdata::opcodes;
|
||||
use blockdata::script;
|
||||
use blockdata::transaction::{Transaction, TxOut, TxIn};
|
||||
use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
|
||||
use blockdata::block::{Block, BlockHeader};
|
||||
use network::constants::Network;
|
||||
use util::misc::hex_bytes;
|
||||
|
@ -69,8 +69,7 @@ fn bitcoin_genesis_tx() -> Transaction {
|
|||
.push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks")
|
||||
.into_script();
|
||||
ret.input.push(TxIn {
|
||||
prev_hash: Default::default(),
|
||||
prev_index: 0xFFFFFFFF,
|
||||
previous_output: OutPoint::null(),
|
||||
script_sig: in_script,
|
||||
sequence: MAX_SEQUENCE,
|
||||
witness: vec![],
|
||||
|
@ -154,8 +153,8 @@ mod test {
|
|||
|
||||
assert_eq!(gen.version, 1);
|
||||
assert_eq!(gen.input.len(), 1);
|
||||
assert_eq!(gen.input[0].prev_hash, Default::default());
|
||||
assert_eq!(gen.input[0].prev_index, 0xFFFFFFFF);
|
||||
assert_eq!(gen.input[0].previous_output.txid, Default::default());
|
||||
assert_eq!(gen.input[0].previous_output.vout, 0xFFFFFFFF);
|
||||
assert_eq!(serialize(&gen.input[0].script_sig).ok(),
|
||||
Some(hex_decode("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73").unwrap()));
|
||||
|
||||
|
|
|
@ -36,28 +36,65 @@ use network::serialize::{serialize, BitcoinHash, SimpleEncoder, SimpleDecoder};
|
|||
use network::encodable::{ConsensusEncodable, ConsensusDecodable, VarInt};
|
||||
|
||||
/// A reference to a transaction output
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct TxOutRef {
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct OutPoint {
|
||||
/// The referenced transaction's txid
|
||||
pub txid: Sha256dHash,
|
||||
/// The index of the referenced output in its transaction's vout
|
||||
pub index: usize
|
||||
pub vout: u32,
|
||||
}
|
||||
serde_struct_impl!(TxOutRef, txid, index);
|
||||
serde_struct_impl!(OutPoint, txid, vout);
|
||||
|
||||
impl fmt::Display for TxOutRef {
|
||||
impl OutPoint {
|
||||
/// Creates a "null" `OutPoint`.
|
||||
///
|
||||
/// This value is used for coinbase transactions because they don't have
|
||||
/// any previous outputs.
|
||||
#[inline]
|
||||
pub fn null() -> OutPoint {
|
||||
OutPoint {
|
||||
txid: Default::default(),
|
||||
vout: u32::max_value(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if an `OutPoint` is "null".
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bitcoin::blockdata::constants::genesis_block;
|
||||
/// use bitcoin::network::constants::Network;
|
||||
///
|
||||
/// let block = genesis_block(Network::Bitcoin);
|
||||
/// let tx = &block.txdata[0];
|
||||
///
|
||||
/// // Coinbase transactions don't have any previous output.
|
||||
/// assert_eq!(tx.input[0].previous_output.is_null(), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
*self == OutPoint::null()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OutPoint {
|
||||
fn default() -> Self {
|
||||
OutPoint::null()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OutPoint {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}:{}", self.txid, self.index)
|
||||
write!(f, "{}:{}", self.txid, self.vout)
|
||||
}
|
||||
}
|
||||
|
||||
/// A transaction input, which defines old coins to be consumed
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct TxIn {
|
||||
/// The hash of the transaction whose output is being used an an input
|
||||
pub prev_hash: Sha256dHash,
|
||||
/// The index of the output in the previous transaction, which may have several
|
||||
pub prev_index: u32,
|
||||
/// The reference to the previous output that is being used an an input
|
||||
pub previous_output: OutPoint,
|
||||
/// The script which pushes values on the stack which will cause
|
||||
/// the referenced output's script to accept
|
||||
pub script_sig: Script,
|
||||
|
@ -73,7 +110,7 @@ pub struct TxIn {
|
|||
/// routines.
|
||||
pub witness: Vec<Vec<u8>>
|
||||
}
|
||||
serde_struct_impl!(TxIn, prev_hash, prev_index, script_sig, sequence, witness);
|
||||
serde_struct_impl!(TxIn, previous_output, script_sig, sequence, witness);
|
||||
|
||||
/// A transaction output, which defines new coins to be created from old ones.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
|
@ -172,9 +209,8 @@ impl Transaction {
|
|||
// Add all inputs necessary..
|
||||
if anyone_can_pay {
|
||||
tx.input = vec![TxIn {
|
||||
prev_hash: self.input[input_index].prev_hash,
|
||||
previous_output: self.input[input_index].previous_output,
|
||||
script_sig: script_pubkey.clone(),
|
||||
prev_index: self.input[input_index].prev_index,
|
||||
sequence: self.input[input_index].sequence,
|
||||
witness: vec![],
|
||||
}];
|
||||
|
@ -182,8 +218,7 @@ impl Transaction {
|
|||
tx.input = Vec::with_capacity(self.input.len());
|
||||
for (n, input) in self.input.iter().enumerate() {
|
||||
tx.input.push(TxIn {
|
||||
prev_hash: input.prev_hash,
|
||||
prev_index: input.prev_index,
|
||||
previous_output: input.previous_output,
|
||||
script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() },
|
||||
sequence: if n != input_index && (sighash == SigHashType::Single || sighash == SigHashType::None) { 0 } else { input.sequence },
|
||||
witness: vec![],
|
||||
|
@ -253,17 +288,17 @@ impl Transaction {
|
|||
|
||||
#[cfg(feature="bitcoinconsensus")]
|
||||
/// Verify that this transaction is able to spend some outputs of spent transactions
|
||||
pub fn verify (&self, spent : &HashMap<Sha256dHash, Transaction>) -> Result<(), script::Error> {
|
||||
pub fn verify(&self, spent: &HashMap<Sha256dHash, Transaction>) -> Result<(), script::Error> {
|
||||
if let Ok(tx) = serialize(&*self) {
|
||||
for (idx, input) in self.input.iter().enumerate() {
|
||||
if let Some(ref s) = spent.get(&input.prev_hash) {
|
||||
if let Some(ref output) = s.output.get(input.prev_index as usize) {
|
||||
if let Some(ref s) = spent.get(&input.previous_output.txid) {
|
||||
if let Some(ref output) = s.output.get(input.previous_output.vout as usize) {
|
||||
output.script_pubkey.verify(idx, output.value, tx.as_slice())?;
|
||||
} else {
|
||||
return Err(script::Error::WrongSpentOutputIndex(input.prev_index as usize));
|
||||
return Err(script::Error::WrongSpentOutputIndex(input.previous_output.vout as usize));
|
||||
}
|
||||
} else {
|
||||
return Err(script::Error::UnknownSpentTransaction(input.prev_hash));
|
||||
return Err(script::Error::UnknownSpentTransaction(input.previous_output.txid));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -273,9 +308,9 @@ impl Transaction {
|
|||
}
|
||||
}
|
||||
|
||||
/// is this a coin base transaction?
|
||||
pub fn is_coin_base (&self) -> bool {
|
||||
self.input.len() == 1 && self.input[0].prev_index == 0xFFFFFFFF && self.input [0].prev_hash == Sha256dHash::default()
|
||||
/// Is this a coin base transaction?
|
||||
pub fn is_coin_base(&self) -> bool {
|
||||
self.input.len() == 1 && self.input[0].previous_output.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,10 +326,24 @@ impl BitcoinHash for Transaction {
|
|||
|
||||
impl_consensus_encoding!(TxOut, value, script_pubkey);
|
||||
|
||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for OutPoint {
|
||||
fn consensus_encode(&self, s: &mut S) -> Result <(), S::Error> {
|
||||
self.txid.consensus_encode(s)?;
|
||||
self.vout.consensus_encode(s)
|
||||
}
|
||||
}
|
||||
impl<D: SimpleDecoder> ConsensusDecodable<D> for OutPoint {
|
||||
fn consensus_decode(d: &mut D) -> Result<OutPoint, D::Error> {
|
||||
Ok(OutPoint {
|
||||
txid: ConsensusDecodable::consensus_decode(d)?,
|
||||
vout: ConsensusDecodable::consensus_decode(d)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: SimpleEncoder> ConsensusEncodable<S> for TxIn {
|
||||
fn consensus_encode(&self, s: &mut S) -> Result <(), S::Error> {
|
||||
self.prev_hash.consensus_encode(s)?;
|
||||
self.prev_index.consensus_encode(s)?;
|
||||
self.previous_output.consensus_encode(s)?;
|
||||
self.script_sig.consensus_encode(s)?;
|
||||
self.sequence.consensus_encode(s)
|
||||
}
|
||||
|
@ -302,8 +351,7 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for TxIn {
|
|||
impl<D: SimpleDecoder> ConsensusDecodable<D> for TxIn {
|
||||
fn consensus_decode(d: &mut D) -> Result<TxIn, D::Error> {
|
||||
Ok(TxIn {
|
||||
prev_hash: ConsensusDecodable::consensus_decode(d)?,
|
||||
prev_index: ConsensusDecodable::consensus_decode(d)?,
|
||||
previous_output: ConsensusDecodable::consensus_decode(d)?,
|
||||
script_sig: ConsensusDecodable::consensus_decode(d)?,
|
||||
sequence: ConsensusDecodable::consensus_decode(d)?,
|
||||
witness: vec![],
|
||||
|
@ -482,9 +530,9 @@ mod tests {
|
|||
assert_eq!(realtx.input.len(), 1);
|
||||
// In particular this one is easy to get backward -- in bitcoin hashes are encoded
|
||||
// as little-endian 256-bit numbers rather than as data strings.
|
||||
assert_eq!(realtx.input[0].prev_hash.be_hex_string(),
|
||||
assert_eq!(realtx.input[0].previous_output.txid.be_hex_string(),
|
||||
"ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string());
|
||||
assert_eq!(realtx.input[0].prev_index, 1);
|
||||
assert_eq!(realtx.input[0].previous_output.vout, 1);
|
||||
assert_eq!(realtx.output.len(), 1);
|
||||
assert_eq!(realtx.lock_time, 0);
|
||||
|
||||
|
|
|
@ -47,8 +47,7 @@ impl SighashComponents {
|
|||
let hash_prevouts = {
|
||||
let mut enc = Sha256dEncoder::new();
|
||||
for txin in &tx.input {
|
||||
txin.prev_hash.consensus_encode(&mut enc).unwrap();
|
||||
txin.prev_index.consensus_encode(&mut enc).unwrap();
|
||||
txin.previous_output.consensus_encode(&mut enc).unwrap();
|
||||
}
|
||||
enc.into_hash()
|
||||
};
|
||||
|
@ -86,11 +85,7 @@ impl SighashComponents {
|
|||
self.hash_prevouts.consensus_encode(&mut enc).unwrap();
|
||||
self.hash_sequence.consensus_encode(&mut enc).unwrap();
|
||||
txin
|
||||
.prev_hash
|
||||
.consensus_encode(&mut enc)
|
||||
.unwrap();
|
||||
txin
|
||||
.prev_index
|
||||
.previous_output
|
||||
.consensus_encode(&mut enc)
|
||||
.unwrap();
|
||||
witness_script.consensus_encode(&mut enc).unwrap();
|
||||
|
|
Loading…
Reference in New Issue