Merge pull request #68 from TheBlueMatt/master

Move witness inside of TxIn.
This commit is contained in:
Andrew Poelstra 2018-04-02 16:21:54 +00:00 committed by GitHub
commit 050fd8ccd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 22 deletions

View File

@ -61,7 +61,6 @@ fn bitcoin_genesis_tx() -> Transaction {
lock_time: 0, lock_time: 0,
input: vec![], input: vec![],
output: vec![], output: vec![],
witness: vec![]
}; };
// Inputs // Inputs
@ -73,7 +72,8 @@ fn bitcoin_genesis_tx() -> Transaction {
prev_hash: Default::default(), prev_hash: Default::default(),
prev_index: 0xFFFFFFFF, prev_index: 0xFFFFFFFF,
script_sig: in_script, script_sig: in_script,
sequence: MAX_SEQUENCE sequence: MAX_SEQUENCE,
witness: vec![],
}); });
// Outputs // Outputs

View File

@ -66,8 +66,14 @@ pub struct TxIn {
/// to ignore this feature. This is generally never used since /// to ignore this feature. This is generally never used since
/// the miner behaviour cannot be enforced. /// the miner behaviour cannot be enforced.
pub sequence: u32, pub sequence: u32,
/// Witness data: an array of byte-arrays.
/// Note that this field is *not* (de)serialized with the rest of the TxIn in
/// ConsensusEncodable/ConsennsusDecodable, as it is (de)serialized at the end of the full
/// Transaction. It *is* (de)serialized with the rest of the TxIn in other (de)serializationn
/// routines.
pub witness: Vec<Vec<u8>>
} }
serde_struct_impl!(TxIn, prev_hash, prev_index, script_sig, sequence); serde_struct_impl!(TxIn, prev_hash, prev_index, script_sig, sequence, witness);
/// A transaction output, which defines new coins to be created from old ones. /// A transaction output, which defines new coins to be created from old ones.
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
@ -98,10 +104,8 @@ pub struct Transaction {
pub input: Vec<TxIn>, pub input: Vec<TxIn>,
/// List of outputs /// List of outputs
pub output: Vec<TxOut>, pub output: Vec<TxOut>,
/// Witness data: for each txin, an array of byte-arrays
pub witness: Vec<Vec<Vec<u8>>>
} }
serde_struct_impl!(Transaction, version, lock_time, input, output, witness); serde_struct_impl!(Transaction, version, lock_time, input, output);
impl Transaction { impl Transaction {
/// Computes a "normalized TXID" which does not include any signatures. /// Computes a "normalized TXID" which does not include any signatures.
@ -111,9 +115,8 @@ impl Transaction {
let cloned_tx = Transaction { let cloned_tx = Transaction {
version: self.version, version: self.version,
lock_time: self.lock_time, lock_time: self.lock_time,
input: self.input.iter().map(|txin| TxIn { script_sig: Script::new(), .. *txin }).collect(), input: self.input.iter().map(|txin| TxIn { script_sig: Script::new(), witness: vec![], .. *txin }).collect(),
output: self.output.clone(), output: self.output.clone(),
witness: vec![]
}; };
cloned_tx.bitcoin_hash() cloned_tx.bitcoin_hash()
} }
@ -165,7 +168,6 @@ impl Transaction {
lock_time: self.lock_time, lock_time: self.lock_time,
input: vec![], input: vec![],
output: vec![], output: vec![],
witness: vec![]
}; };
// Add all inputs necessary.. // Add all inputs necessary..
if anyone_can_pay { if anyone_can_pay {
@ -173,7 +175,8 @@ impl Transaction {
prev_hash: self.input[input_index].prev_hash, prev_hash: self.input[input_index].prev_hash,
script_sig: script_pubkey.clone(), script_sig: script_pubkey.clone(),
prev_index: self.input[input_index].prev_index, prev_index: self.input[input_index].prev_index,
sequence: self.input[input_index].sequence sequence: self.input[input_index].sequence,
witness: vec![],
}]; }];
} else { } else {
tx.input = Vec::with_capacity(self.input.len()); tx.input = Vec::with_capacity(self.input.len());
@ -182,7 +185,8 @@ impl Transaction {
prev_hash: input.prev_hash, prev_hash: input.prev_hash,
prev_index: input.prev_index, prev_index: input.prev_index,
script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() }, 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 } sequence: if n != input_index && (sighash == SigHashType::Single || sighash == SigHashType::None) { 0 } else { input.sequence },
witness: vec![],
}); });
} }
} }
@ -238,13 +242,39 @@ impl BitcoinHash for Transaction {
} }
} }
impl_consensus_encoding!(TxIn, prev_hash, prev_index, script_sig, sequence);
impl_consensus_encoding!(TxOut, value, script_pubkey); impl_consensus_encoding!(TxOut, value, script_pubkey);
impl<S: SimpleEncoder> ConsensusEncodable<S> for TxIn {
fn consensus_encode(&self, s: &mut S) -> Result <(), S::Error> {
try!(self.prev_hash.consensus_encode(s));
try!(self.prev_index.consensus_encode(s));
try!(self.script_sig.consensus_encode(s));
self.sequence.consensus_encode(s)
}
}
impl<D: SimpleDecoder> ConsensusDecodable<D> for TxIn {
fn consensus_decode(d: &mut D) -> Result<TxIn, D::Error> {
Ok(TxIn {
prev_hash: try!(ConsensusDecodable::consensus_decode(d)),
prev_index: try!(ConsensusDecodable::consensus_decode(d)),
script_sig: try!(ConsensusDecodable::consensus_decode(d)),
sequence: try!(ConsensusDecodable::consensus_decode(d)),
witness: vec![],
})
}
}
impl<S: SimpleEncoder> ConsensusEncodable<S> for Transaction { impl<S: SimpleEncoder> ConsensusEncodable<S> for Transaction {
fn consensus_encode(&self, s: &mut S) -> Result <(), S::Error> { fn consensus_encode(&self, s: &mut S) -> Result <(), S::Error> {
try!(self.version.consensus_encode(s)); try!(self.version.consensus_encode(s));
if self.witness.is_empty() { let mut have_witness = false;
for input in &self.input {
if !input.witness.is_empty() {
have_witness = true;
break;
}
}
if !have_witness {
try!(self.input.consensus_encode(s)); try!(self.input.consensus_encode(s));
try!(self.output.consensus_encode(s)); try!(self.output.consensus_encode(s));
} else { } else {
@ -252,8 +282,8 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for Transaction {
try!(1u8.consensus_encode(s)); try!(1u8.consensus_encode(s));
try!(self.input.consensus_encode(s)); try!(self.input.consensus_encode(s));
try!(self.output.consensus_encode(s)); try!(self.output.consensus_encode(s));
for witness in &self.witness { for input in &self.input {
try!(witness.consensus_encode(s)); try!(input.witness.consensus_encode(s));
} }
} }
self.lock_time.consensus_encode(s) self.lock_time.consensus_encode(s)
@ -275,22 +305,19 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Transaction {
input: input, input: input,
output: vec![], output: vec![],
lock_time: try!(ConsensusDecodable::consensus_decode(d)), lock_time: try!(ConsensusDecodable::consensus_decode(d)),
witness: vec![]
}) })
} }
// BIP144 input witnesses // BIP144 input witnesses
1 => { 1 => {
let input: Vec<TxIn> = try!(ConsensusDecodable::consensus_decode(d)); let mut input: Vec<TxIn> = try!(ConsensusDecodable::consensus_decode(d));
let output: Vec<TxOut> = try!(ConsensusDecodable::consensus_decode(d)); let output: Vec<TxOut> = try!(ConsensusDecodable::consensus_decode(d));
let mut witness: Vec<Vec<Vec<u8>>> = Vec::with_capacity(input.len()); for txin in input.iter_mut() {
for _ in 0..input.len() { txin.witness = try!(ConsensusDecodable::consensus_decode(d));
witness.push(try!(ConsensusDecodable::consensus_decode(d)));
} }
Ok(Transaction { Ok(Transaction {
version: version, version: version,
input: input, input: input,
output: output, output: output,
witness: witness,
lock_time: try!(ConsensusDecodable::consensus_decode(d)) lock_time: try!(ConsensusDecodable::consensus_decode(d))
}) })
} }
@ -306,7 +333,6 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Transaction {
input: input, input: input,
output: try!(ConsensusDecodable::consensus_decode(d)), output: try!(ConsensusDecodable::consensus_decode(d)),
lock_time: try!(ConsensusDecodable::consensus_decode(d)), lock_time: try!(ConsensusDecodable::consensus_decode(d)),
witness: vec![]
}) })
} }
} }