Merge pull request #477 from rust-bitcoin/revert-465-psbt_updates
Revert "Added hash Preimages to psbt"
This commit is contained in:
commit
c1ae3b7955
|
@ -8,6 +8,3 @@ fuzz/hfuzz_workspace
|
||||||
#IntelliJ project files
|
#IntelliJ project files
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
#Vscode project files
|
|
||||||
.vscode
|
|
||||||
|
|
|
@ -18,17 +18,6 @@ use std::fmt;
|
||||||
use blockdata::transaction::Transaction;
|
use blockdata::transaction::Transaction;
|
||||||
use util::psbt::raw;
|
use util::psbt::raw;
|
||||||
|
|
||||||
use hashes::{self, sha256, hash160, sha256d, ripemd160};
|
|
||||||
use hash_types::Txid;
|
|
||||||
|
|
||||||
/// Support hash-preimages in psbt
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PsbtHash{
|
|
||||||
Ripemd160(ripemd160::Hash),
|
|
||||||
Sha256(sha256::Hash),
|
|
||||||
Hash256(sha256d::Hash),
|
|
||||||
Hash160(hash160::Hash),
|
|
||||||
}
|
|
||||||
/// Ways that a Partially Signed Transaction might fail.
|
/// Ways that a Partially Signed Transaction might fail.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -59,37 +48,6 @@ pub enum Error {
|
||||||
},
|
},
|
||||||
/// Unable to parse as a standard SigHash type.
|
/// Unable to parse as a standard SigHash type.
|
||||||
NonStandardSigHashType(u32),
|
NonStandardSigHashType(u32),
|
||||||
/// Parsing errors from bitcoin_hashes
|
|
||||||
HashParseError(hashes::Error),
|
|
||||||
/// The pre-image must hash to the correponding psbt hash
|
|
||||||
InvalidPreimageHashPair{
|
|
||||||
/// Pre-image
|
|
||||||
preimage: Vec<u8>,
|
|
||||||
/// Hash value
|
|
||||||
hash: PsbtHash,
|
|
||||||
},
|
|
||||||
/// If NonWitnessUtxo is used, the nonWitnessUtxo txid must
|
|
||||||
/// be the same of prevout txid
|
|
||||||
InvalidNonWitnessUtxo{
|
|
||||||
/// Pre-image
|
|
||||||
prevout_txid: Txid,
|
|
||||||
/// Hash value
|
|
||||||
non_witness_utxo_txid: Txid,
|
|
||||||
},
|
|
||||||
/// Incorrect P2sh/p2wsh script hash for the witness/redeem
|
|
||||||
/// script
|
|
||||||
InvalidWitnessScript{
|
|
||||||
/// Expected Witness/Redeem Script Hash
|
|
||||||
// returns a vec to unify the p2wsh(sha2) and p2sh(hash160)
|
|
||||||
expected: Vec<u8>,
|
|
||||||
/// Actual Witness script Hash
|
|
||||||
actual: Vec<u8>,
|
|
||||||
},
|
|
||||||
/// Currently only p2wpkh and p2wsh scripts are possible in segwit
|
|
||||||
UnrecognizedWitnessProgram,
|
|
||||||
/// The psbt input must either have an associated nonWitnessUtxo or
|
|
||||||
/// a WitnessUtxo
|
|
||||||
MustHaveSpendingUtxo,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
@ -107,23 +65,6 @@ impl fmt::Display for Error {
|
||||||
f.write_str("partially signed transactions must have an unsigned transaction")
|
f.write_str("partially signed transactions must have an unsigned transaction")
|
||||||
}
|
}
|
||||||
Error::NoMorePairs => f.write_str("no more key-value pairs for this psbt map"),
|
Error::NoMorePairs => f.write_str("no more key-value pairs for this psbt map"),
|
||||||
Error::HashParseError(e) => write!(f, "Hash Parse Error: {}", e),
|
|
||||||
Error::InvalidPreimageHashPair{ref preimage, ref hash} => {
|
|
||||||
// directly using debug forms of psbthash enums
|
|
||||||
write!(f, "Preimage {:?} does not match hash {:?}", preimage, hash )
|
|
||||||
},
|
|
||||||
Error::InvalidNonWitnessUtxo{ref prevout_txid, ref non_witness_utxo_txid} => {
|
|
||||||
write!(f, "NonWitnessUtxo txid {} must be the same as prevout txid {}", non_witness_utxo_txid, prevout_txid)
|
|
||||||
},
|
|
||||||
Error::InvalidWitnessScript{ref expected, ref actual} => {
|
|
||||||
write!(f, "Invalid Witness/Redeem script: Expected {:?}, got {:?}", expected, actual)
|
|
||||||
}
|
|
||||||
Error::UnrecognizedWitnessProgram => {
|
|
||||||
f.write_str("Witness program must be p2wpkh/p2wsh")
|
|
||||||
}
|
|
||||||
Error::MustHaveSpendingUtxo => {
|
|
||||||
f.write_str("Input must either WitnessUtxo/ NonWitnessUtxo")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,10 +75,3 @@ impl error::Error for Error {
|
||||||
"description() is deprecated; use Display"
|
"description() is deprecated; use Display"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
impl From<hashes::Error> for Error {
|
|
||||||
fn from(e: hashes::Error) -> Error {
|
|
||||||
Error::HashParseError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -130,30 +130,6 @@ macro_rules! impl_psbt_insert_pair {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
|
||||||
macro_rules! impl_psbt_insert_hash_pair {
|
|
||||||
($slf:ident.$keyed_name:ident <= <$raw_key:ident: $keyed_key_type:ty>|<$raw_value:ident: $keyed_value_type:ty>; $err_name: ident ) => {
|
|
||||||
if !$raw_key.key.is_empty() {
|
|
||||||
let key_val: $keyed_key_type = $crate::util::psbt::serialize::Deserialize::deserialize(&$raw_key.key)?;
|
|
||||||
match $slf.$keyed_name.entry(key_val) {
|
|
||||||
::std::collections::btree_map::Entry::Vacant(empty_key) => {
|
|
||||||
let val: $keyed_value_type = $crate::util::psbt::serialize::Deserialize::deserialize(&$raw_value)?;
|
|
||||||
if <$keyed_key_type>::hash(&val) != key_val{
|
|
||||||
return Err($crate::util::psbt::Error::InvalidPreimageHashPair{
|
|
||||||
preimage: val,
|
|
||||||
hash: $crate::util::psbt::error::PsbtHash::$err_name(key_val),
|
|
||||||
}.into());
|
|
||||||
}
|
|
||||||
empty_key.insert(val);
|
|
||||||
}
|
|
||||||
::std::collections::btree_map::Entry::Occupied(_) => return Err($crate::util::psbt::Error::DuplicateKey($raw_key).into()),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err($crate::util::psbt::Error::InvalidKey($raw_key).into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
macro_rules! impl_psbt_get_pair {
|
macro_rules! impl_psbt_get_pair {
|
||||||
($rv:ident.push($slf:ident.$unkeyed_name:ident as <$unkeyed_typeval:expr, _>|<$unkeyed_value_type:ty>)) => {
|
($rv:ident.push($slf:ident.$unkeyed_name:ident as <$unkeyed_typeval:expr, _>|<$unkeyed_value_type:ty>)) => {
|
||||||
|
@ -179,33 +155,3 @@ macro_rules! impl_psbt_get_pair {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// macros for serde of hashes
|
|
||||||
macro_rules! impl_psbt_hash_de_serialize {
|
|
||||||
($thing:ty) => {
|
|
||||||
impl_psbt_hash_serialize!($thing);
|
|
||||||
impl_psbt_hash_deserialize!($thing);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_psbt_hash_deserialize {
|
|
||||||
($thing:ty) => {
|
|
||||||
impl $crate::util::psbt::serialize::Deserialize for $thing {
|
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, $crate::consensus::encode::Error> {
|
|
||||||
<$thing>::from_slice(&bytes[..]).map_err(|e| {
|
|
||||||
$crate::util::psbt::Error::from(e).into()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_psbt_hash_serialize {
|
|
||||||
($thing:ty) => {
|
|
||||||
impl $crate::util::psbt::serialize::Serialize for $thing {
|
|
||||||
fn serialize(&self) -> Vec<u8> {
|
|
||||||
self.into_inner().to_vec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,13 +17,13 @@ use std::collections::BTreeMap;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{SigHashType, Transaction, TxOut};
|
use blockdata::transaction::{SigHashType, Transaction, TxOut};
|
||||||
use consensus::encode;
|
use consensus::encode;
|
||||||
use hashes::{Hash, hash160, ripemd160, sha256, sha256d};
|
|
||||||
use util::bip32::{DerivationPath, Fingerprint};
|
use util::bip32::{DerivationPath, Fingerprint};
|
||||||
use util::key::PublicKey;
|
use util::key::PublicKey;
|
||||||
use util::psbt;
|
use util::psbt;
|
||||||
use util::psbt::map::Map;
|
use util::psbt::map::Map;
|
||||||
use util::psbt::raw;
|
use util::psbt::raw;
|
||||||
use util::psbt::Error;
|
use util::psbt::Error;
|
||||||
|
|
||||||
/// A key-value map for an input of the corresponding index in the unsigned
|
/// A key-value map for an input of the corresponding index in the unsigned
|
||||||
/// transaction.
|
/// transaction.
|
||||||
#[derive(Clone, Default, Debug, PartialEq)]
|
#[derive(Clone, Default, Debug, PartialEq)]
|
||||||
|
@ -55,15 +55,6 @@ pub struct Input {
|
||||||
/// The finalized, fully-constructed scriptWitness with signatures and any
|
/// The finalized, fully-constructed scriptWitness with signatures and any
|
||||||
/// other scripts necessary for this input to pass validation.
|
/// other scripts necessary for this input to pass validation.
|
||||||
pub final_script_witness: Option<Vec<Vec<u8>>>,
|
pub final_script_witness: Option<Vec<Vec<u8>>>,
|
||||||
/// TODO: Proof of reserves commitment
|
|
||||||
/// RIPEMD hash to preimage map
|
|
||||||
pub ripemd_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
|
|
||||||
/// SHA256 hash to preimage map
|
|
||||||
pub sha256_preimages: BTreeMap<sha256::Hash, Vec<u8>>,
|
|
||||||
/// HSAH160 hash to preimage map
|
|
||||||
pub hash160_preimages: BTreeMap<hash160::Hash, Vec<u8>>,
|
|
||||||
/// HAS256 hash to preimage map
|
|
||||||
pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>,
|
|
||||||
/// Unknown key-value pairs for this input.
|
/// Unknown key-value pairs for this input.
|
||||||
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
|
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
@ -121,34 +112,10 @@ impl Map for Input {
|
||||||
self.hd_keypaths <= <raw_key: PublicKey>|<raw_value: (Fingerprint, DerivationPath)>
|
self.hd_keypaths <= <raw_key: PublicKey>|<raw_value: (Fingerprint, DerivationPath)>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
10u8 => {
|
|
||||||
impl_psbt_insert_hash_pair! {
|
|
||||||
self.ripemd_preimages <= <raw_key: ripemd160::Hash>|<raw_value: Vec<u8>>; Ripemd160
|
|
||||||
}
|
|
||||||
}
|
|
||||||
11u8 => {
|
|
||||||
impl_psbt_insert_hash_pair! {
|
|
||||||
self.sha256_preimages <= <raw_key: sha256::Hash>|<raw_value: Vec<u8>>; Sha256
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12u8 => {
|
|
||||||
impl_psbt_insert_hash_pair! {
|
|
||||||
self.hash160_preimages <= <raw_key: hash160::Hash>|<raw_value: Vec<u8>>; Hash160
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13u8 => {
|
|
||||||
impl_psbt_insert_hash_pair! {
|
|
||||||
self.hash256_preimages <= <raw_key: sha256d::Hash>|<raw_value: Vec<u8>>; Hash256
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => match self.unknown.entry(raw_key) {
|
_ => match self.unknown.entry(raw_key) {
|
||||||
::std::collections::btree_map::Entry::Vacant(empty_key) => {
|
::std::collections::btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);},
|
||||||
empty_key.insert(raw_value);
|
::std::collections::btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()),
|
||||||
}
|
}
|
||||||
::std::collections::btree_map::Entry::Occupied(k) => {
|
|
||||||
return Err(Error::DuplicateKey(k.key().clone()).into())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -193,22 +160,6 @@ impl Map for Input {
|
||||||
rv.push(self.final_script_witness as <8u8, _>|<Script>)
|
rv.push(self.final_script_witness as <8u8, _>|<Script>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
|
||||||
rv.push(self.ripemd_preimages as <10u8, ripemd160::Hash>|<Vec<u8>>)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
|
||||||
rv.push(self.sha256_preimages as <11u8, sha256::Hash>|<Vec<u8>>)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
|
||||||
rv.push(self.hash160_preimages as <12u8, hash160::Hash>|<Vec<u8>>)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
|
||||||
rv.push(self.hash256_preimages as <13u8, sha256d::Hash>|<Vec<u8>>)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (key, value) in self.unknown.iter() {
|
for (key, value) in self.unknown.iter() {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair {
|
||||||
key: key.clone(),
|
key: key.clone(),
|
||||||
|
@ -229,10 +180,6 @@ impl Map for Input {
|
||||||
|
|
||||||
self.partial_sigs.extend(other.partial_sigs);
|
self.partial_sigs.extend(other.partial_sigs);
|
||||||
self.hd_keypaths.extend(other.hd_keypaths);
|
self.hd_keypaths.extend(other.hd_keypaths);
|
||||||
self.ripemd_preimages.extend(other.ripemd_preimages);
|
|
||||||
self.sha256_preimages.extend(other.sha256_preimages);
|
|
||||||
self.hash160_preimages.extend(other.hash160_preimages);
|
|
||||||
self.hash256_preimages.extend(other.hash256_preimages);
|
|
||||||
self.unknown.extend(other.unknown);
|
self.unknown.extend(other.unknown);
|
||||||
|
|
||||||
merge!(redeem_script, self, other);
|
merge!(redeem_script, self, other);
|
||||||
|
|
|
@ -18,12 +18,9 @@
|
||||||
//! defined at https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
|
//! defined at https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
|
||||||
//! except we define PSBTs containing non-standard SigHash types as invalid.
|
//! except we define PSBTs containing non-standard SigHash types as invalid.
|
||||||
|
|
||||||
use blockdata::transaction::{SigHashType, Transaction};
|
use blockdata::script::Script;
|
||||||
use hash_types::SigHash;
|
use blockdata::transaction::Transaction;
|
||||||
use consensus::{encode, Encodable, Decodable};
|
use consensus::{encode, Encodable, Decodable};
|
||||||
use util::bip143::SigHashCache;
|
|
||||||
use blockdata::script::{Builder, Script};
|
|
||||||
use blockdata::opcodes;
|
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
@ -91,83 +88,6 @@ impl PartiallySignedTransaction {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the Sighash for the Psbt Input at idx depending on whether input spends
|
|
||||||
/// spends a segwit or not
|
|
||||||
/// #Panics:
|
|
||||||
/// Panics if the index >= number of inputs in psbt
|
|
||||||
pub fn signature_hash(&self, idx: usize) -> Result<SigHash, self::Error> {
|
|
||||||
let inp = &self.inputs[idx];
|
|
||||||
let sighash_type = inp.sighash_type.unwrap_or_else(|| SigHashType::All);
|
|
||||||
// Compute Script code for the Script. When this script is used as scriptPubkey,
|
|
||||||
// the Script Code determines what goes into sighash.
|
|
||||||
// For non-p2sh non-segwit outputs and non-p2sh wrapped segwit-outputs
|
|
||||||
// script code is the public key.
|
|
||||||
let sighash = if let Some(ref non_witness_utxo) = inp.non_witness_utxo {
|
|
||||||
let spent_outpoint = self.global.unsigned_tx.input[idx].previous_output;
|
|
||||||
if spent_outpoint.txid != non_witness_utxo.txid() {
|
|
||||||
return Err(Error::InvalidNonWitnessUtxo {
|
|
||||||
prevout_txid: spent_outpoint.txid,
|
|
||||||
non_witness_utxo_txid: non_witness_utxo.txid()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let script_pubkey = &non_witness_utxo.output[spent_outpoint.vout as usize].script_pubkey;
|
|
||||||
if let Some(ref redeem_script) = inp.redeem_script {
|
|
||||||
if redeem_script.to_p2sh() != *script_pubkey {
|
|
||||||
return Err(Error::InvalidWitnessScript{
|
|
||||||
expected: script_pubkey.to_bytes(),
|
|
||||||
actual: redeem_script.to_p2sh().into_bytes(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
self.global.unsigned_tx.signature_hash(
|
|
||||||
idx, &redeem_script, sighash_type.as_u32()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
self.global.unsigned_tx.signature_hash(
|
|
||||||
idx, &script_pubkey, sighash_type.as_u32()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if let Some(ref witness_utxo) = inp.witness_utxo {
|
|
||||||
let script_pubkey = if let Some(ref redeem_script) = inp.redeem_script {
|
|
||||||
if redeem_script.to_p2sh() != witness_utxo.script_pubkey {
|
|
||||||
return Err(Error::InvalidWitnessScript{
|
|
||||||
expected: witness_utxo.script_pubkey.to_bytes(),
|
|
||||||
actual: redeem_script.to_p2sh().into_bytes(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
redeem_script
|
|
||||||
} else {
|
|
||||||
&witness_utxo.script_pubkey
|
|
||||||
};
|
|
||||||
|
|
||||||
let amt = witness_utxo.value;
|
|
||||||
let mut sighash_cache = SigHashCache::new(&self.global.unsigned_tx);
|
|
||||||
if let Some(ref witness_script) = inp.witness_script {
|
|
||||||
if witness_script.to_v0_p2wsh() != *script_pubkey {
|
|
||||||
return Err(Error::InvalidWitnessScript{
|
|
||||||
expected: script_pubkey.clone().into_bytes(),
|
|
||||||
actual: witness_script.to_p2sh().into_bytes(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
sighash_cache.signature_hash(idx, &witness_script, amt, sighash_type)
|
|
||||||
} else if script_pubkey.is_v0_p2wpkh() {
|
|
||||||
// Indirect way to get script code
|
|
||||||
let builder = Builder::new();
|
|
||||||
let script_code = builder
|
|
||||||
.push_opcode(opcodes::all::OP_DUP)
|
|
||||||
.push_opcode(opcodes::all::OP_HASH160)
|
|
||||||
.push_slice(&script_pubkey[2..22])
|
|
||||||
.push_opcode(opcodes::all::OP_EQUALVERIFY)
|
|
||||||
.into_script();
|
|
||||||
sighash_cache.signature_hash(idx, &script_code, amt, sighash_type)
|
|
||||||
} else {
|
|
||||||
return Err(Error::UnrecognizedWitnessProgram);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::MustHaveSpendingUtxo);
|
|
||||||
};
|
|
||||||
Ok(sighash)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for PartiallySignedTransaction {
|
impl Encodable for PartiallySignedTransaction {
|
||||||
|
@ -243,7 +163,6 @@ impl Decodable for PartiallySignedTransaction {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use hashes::hex::FromHex;
|
use hashes::hex::FromHex;
|
||||||
use hashes::{sha256, hash160, Hash, ripemd160};
|
|
||||||
use hash_types::Txid;
|
use hash_types::Txid;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
@ -256,7 +175,7 @@ mod tests {
|
||||||
use consensus::encode::{deserialize, serialize, serialize_hex};
|
use consensus::encode::{deserialize, serialize, serialize_hex};
|
||||||
use util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint};
|
use util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint};
|
||||||
use util::key::PublicKey;
|
use util::key::PublicKey;
|
||||||
use util::psbt::map::{Global, Output, Input};
|
use util::psbt::map::{Global, Output};
|
||||||
use util::psbt::raw;
|
use util::psbt::raw;
|
||||||
|
|
||||||
use super::PartiallySignedTransaction;
|
use super::PartiallySignedTransaction;
|
||||||
|
@ -642,116 +561,4 @@ mod tests {
|
||||||
assert_eq!(psbt.inputs[0].unknown, unknown)
|
assert_eq!(psbt.inputs[0].unknown, unknown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_and_deserialize_preimage_psbt(){
|
|
||||||
// create a sha preimage map
|
|
||||||
let mut sha256_preimages = BTreeMap::new();
|
|
||||||
sha256_preimages.insert(sha256::Hash::hash(&[1u8, 2u8]), vec![1u8, 2u8]);
|
|
||||||
sha256_preimages.insert(sha256::Hash::hash(&[1u8]), vec![1u8]);
|
|
||||||
|
|
||||||
// same for hash160
|
|
||||||
let mut hash160_preimages = BTreeMap::new();
|
|
||||||
hash160_preimages.insert(hash160::Hash::hash(&[1u8, 2u8]), vec![1u8, 2u8]);
|
|
||||||
hash160_preimages.insert(hash160::Hash::hash(&[1u8]), vec![1u8]);
|
|
||||||
|
|
||||||
// same vector as valid_vector_1 from BIPs with added
|
|
||||||
let mut unserialized = PartiallySignedTransaction {
|
|
||||||
global: Global {
|
|
||||||
unsigned_tx: Transaction {
|
|
||||||
version: 2,
|
|
||||||
lock_time: 1257139,
|
|
||||||
input: vec![TxIn {
|
|
||||||
previous_output: OutPoint {
|
|
||||||
txid: Txid::from_hex(
|
|
||||||
"f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126",
|
|
||||||
).unwrap(),
|
|
||||||
vout: 0,
|
|
||||||
},
|
|
||||||
script_sig: Script::new(),
|
|
||||||
sequence: 4294967294,
|
|
||||||
witness: vec![],
|
|
||||||
}],
|
|
||||||
output: vec![
|
|
||||||
TxOut {
|
|
||||||
value: 99999699,
|
|
||||||
script_pubkey: hex_script!("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac"),
|
|
||||||
},
|
|
||||||
TxOut {
|
|
||||||
value: 100000000,
|
|
||||||
script_pubkey: hex_script!("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
unknown: BTreeMap::new(),
|
|
||||||
},
|
|
||||||
inputs: vec![Input {
|
|
||||||
non_witness_utxo: Some(Transaction {
|
|
||||||
version: 1,
|
|
||||||
lock_time: 0,
|
|
||||||
input: vec![TxIn {
|
|
||||||
previous_output: OutPoint {
|
|
||||||
txid: Txid::from_hex(
|
|
||||||
"e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389",
|
|
||||||
).unwrap(),
|
|
||||||
vout: 1,
|
|
||||||
},
|
|
||||||
script_sig: hex_script!("160014be18d152a9b012039daf3da7de4f53349eecb985"),
|
|
||||||
sequence: 4294967295,
|
|
||||||
witness: vec![
|
|
||||||
Vec::from_hex("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").unwrap(),
|
|
||||||
Vec::from_hex("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105").unwrap(),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
TxIn {
|
|
||||||
previous_output: OutPoint {
|
|
||||||
txid: Txid::from_hex(
|
|
||||||
"b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886",
|
|
||||||
).unwrap(),
|
|
||||||
vout: 1,
|
|
||||||
},
|
|
||||||
script_sig: hex_script!("160014fe3e9ef1a745e974d902c4355943abcb34bd5353"),
|
|
||||||
sequence: 4294967295,
|
|
||||||
witness: vec![
|
|
||||||
Vec::from_hex("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").unwrap(),
|
|
||||||
Vec::from_hex("0223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab3").unwrap(),
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
output: vec![
|
|
||||||
TxOut {
|
|
||||||
value: 200000000,
|
|
||||||
script_pubkey: hex_script!("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac"),
|
|
||||||
},
|
|
||||||
TxOut {
|
|
||||||
value: 190303501938,
|
|
||||||
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
},],
|
|
||||||
outputs: vec![
|
|
||||||
Output {
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
Output {
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
unserialized.inputs[0].hash160_preimages = hash160_preimages;
|
|
||||||
unserialized.inputs[0].sha256_preimages = sha256_preimages;
|
|
||||||
|
|
||||||
let rtt : PartiallySignedTransaction = hex_psbt!(&serialize_hex(&unserialized)).unwrap();
|
|
||||||
assert_eq!(rtt, unserialized);
|
|
||||||
|
|
||||||
// Now add an ripemd160 with incorrect preimage
|
|
||||||
let mut ripemd160_preimages = BTreeMap::new();
|
|
||||||
ripemd160_preimages.insert(ripemd160::Hash::hash(&[17u8]), vec![18u8]);
|
|
||||||
unserialized.inputs[0].ripemd_preimages = ripemd160_preimages;
|
|
||||||
|
|
||||||
// Now the roundtrip should fail as the preimage is incorrect.
|
|
||||||
let rtt : Result<PartiallySignedTransaction, _> = hex_psbt!(&serialize_hex(&unserialized));
|
|
||||||
assert!(rtt.is_err());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ use std::io;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{SigHashType, Transaction, TxOut};
|
use blockdata::transaction::{SigHashType, Transaction, TxOut};
|
||||||
use consensus::encode::{self, serialize, Decodable};
|
use consensus::encode::{self, serialize, Decodable};
|
||||||
use hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
|
||||||
use util::bip32::{ChildNumber, DerivationPath, Fingerprint};
|
use util::bip32::{ChildNumber, DerivationPath, Fingerprint};
|
||||||
use util::key::PublicKey;
|
use util::key::PublicKey;
|
||||||
use util::psbt;
|
use util::psbt;
|
||||||
|
@ -43,10 +42,6 @@ pub trait Deserialize: Sized {
|
||||||
impl_psbt_de_serialize!(Transaction);
|
impl_psbt_de_serialize!(Transaction);
|
||||||
impl_psbt_de_serialize!(TxOut);
|
impl_psbt_de_serialize!(TxOut);
|
||||||
impl_psbt_de_serialize!(Vec<Vec<u8>>); // scriptWitness
|
impl_psbt_de_serialize!(Vec<Vec<u8>>); // scriptWitness
|
||||||
impl_psbt_hash_de_serialize!(ripemd160::Hash);
|
|
||||||
impl_psbt_hash_de_serialize!(sha256::Hash);
|
|
||||||
impl_psbt_hash_de_serialize!(hash160::Hash);
|
|
||||||
impl_psbt_hash_de_serialize!(sha256d::Hash);
|
|
||||||
|
|
||||||
impl Serialize for Script {
|
impl Serialize for Script {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
|
|
Loading…
Reference in New Issue