464 lines
18 KiB
Rust
464 lines
18 KiB
Rust
// Rust Bitcoin Library
|
|
// Written by
|
|
// The Rust Bitcoin developers
|
|
//
|
|
// To the extent possible under law, the author(s) have dedicated all
|
|
// copyright and related and neighboring rights to this software to
|
|
// the public domain worldwide. This software is distributed without
|
|
// any warranty.
|
|
//
|
|
// You should have received a copy of the CC0 Public Domain Dedication
|
|
// along with this software.
|
|
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
//
|
|
|
|
use prelude::*;
|
|
use io;
|
|
|
|
use secp256k1;
|
|
use blockdata::script::Script;
|
|
use blockdata::witness::Witness;
|
|
use blockdata::transaction::{Transaction, TxOut, NonStandardSigHashType};
|
|
use consensus::encode;
|
|
use hashes::{self, hash160, ripemd160, sha256, sha256d};
|
|
use secp256k1::XOnlyPublicKey;
|
|
use util::bip32::KeySource;
|
|
use util::psbt;
|
|
use util::psbt::map::Map;
|
|
use util::psbt::raw;
|
|
use util::psbt::serialize::Deserialize;
|
|
use util::psbt::{Error, error};
|
|
|
|
use util::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash};
|
|
use util::sighash;
|
|
use {EcdsaSigHashType, SchnorrSigHashType, EcdsaSig, SchnorrSig};
|
|
|
|
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
|
|
const PSBT_IN_NON_WITNESS_UTXO: u8 = 0x00;
|
|
/// Type: Witness UTXO PSBT_IN_WITNESS_UTXO = 0x01
|
|
const PSBT_IN_WITNESS_UTXO: u8 = 0x01;
|
|
/// Type: Partial Signature PSBT_IN_PARTIAL_SIG = 0x02
|
|
const PSBT_IN_PARTIAL_SIG: u8 = 0x02;
|
|
/// Type: Sighash Type PSBT_IN_SIGHASH_TYPE = 0x03
|
|
const PSBT_IN_SIGHASH_TYPE: u8 = 0x03;
|
|
/// Type: Redeem Script PSBT_IN_REDEEM_SCRIPT = 0x04
|
|
const PSBT_IN_REDEEM_SCRIPT: u8 = 0x04;
|
|
/// Type: Witness Script PSBT_IN_WITNESS_SCRIPT = 0x05
|
|
const PSBT_IN_WITNESS_SCRIPT: u8 = 0x05;
|
|
/// Type: BIP 32 Derivation Path PSBT_IN_BIP32_DERIVATION = 0x06
|
|
const PSBT_IN_BIP32_DERIVATION: u8 = 0x06;
|
|
/// Type: Finalized scriptSig PSBT_IN_FINAL_SCRIPTSIG = 0x07
|
|
const PSBT_IN_FINAL_SCRIPTSIG: u8 = 0x07;
|
|
/// Type: Finalized scriptWitness PSBT_IN_FINAL_SCRIPTWITNESS = 0x08
|
|
const PSBT_IN_FINAL_SCRIPTWITNESS: u8 = 0x08;
|
|
/// Type: RIPEMD160 preimage PSBT_IN_RIPEMD160 = 0x0a
|
|
const PSBT_IN_RIPEMD160: u8 = 0x0a;
|
|
/// Type: SHA256 preimage PSBT_IN_SHA256 = 0x0b
|
|
const PSBT_IN_SHA256: u8 = 0x0b;
|
|
/// Type: HASH160 preimage PSBT_IN_HASH160 = 0x0c
|
|
const PSBT_IN_HASH160: u8 = 0x0c;
|
|
/// Type: HASH256 preimage PSBT_IN_HASH256 = 0x0d
|
|
const PSBT_IN_HASH256: u8 = 0x0d;
|
|
/// Type: Schnorr Signature in Key Spend PSBT_IN_TAP_KEY_SIG = 0x13
|
|
const PSBT_IN_TAP_KEY_SIG: u8 = 0x13;
|
|
/// Type: Schnorr Signature in Script Spend PSBT_IN_TAP_SCRIPT_SIG = 0x14
|
|
const PSBT_IN_TAP_SCRIPT_SIG: u8 = 0x14;
|
|
/// Type: Taproot Leaf Script PSBT_IN_TAP_LEAF_SCRIPT = 0x14
|
|
const PSBT_IN_TAP_LEAF_SCRIPT: u8 = 0x15;
|
|
/// Type: Taproot Key BIP 32 Derivation Path PSBT_IN_TAP_BIP32_DERIVATION = 0x16
|
|
const PSBT_IN_TAP_BIP32_DERIVATION : u8 = 0x16;
|
|
/// Type: Taproot Internal Key PSBT_IN_TAP_INTERNAL_KEY = 0x17
|
|
const PSBT_IN_TAP_INTERNAL_KEY : u8 = 0x17;
|
|
/// Type: Taproot Merkle Root PSBT_IN_TAP_MERKLE_ROOT = 0x18
|
|
const PSBT_IN_TAP_MERKLE_ROOT : u8 = 0x18;
|
|
/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC
|
|
const PSBT_IN_PROPRIETARY: u8 = 0xFC;
|
|
|
|
/// A key-value map for an input of the corresponding index in the unsigned
|
|
/// transaction.
|
|
#[derive(Clone, Default, Debug, PartialEq)]
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
pub struct Input {
|
|
/// The non-witness transaction this input spends from. Should only be
|
|
/// [std::option::Option::Some] for inputs which spend non-segwit outputs or
|
|
/// if it is unknown whether an input spends a segwit output.
|
|
pub non_witness_utxo: Option<Transaction>,
|
|
/// The transaction output this input spends from. Should only be
|
|
/// [std::option::Option::Some] for inputs which spend segwit outputs,
|
|
/// including P2SH embedded ones.
|
|
pub witness_utxo: Option<TxOut>,
|
|
/// A map from public keys to their corresponding signature as would be
|
|
/// pushed to the stack from a scriptSig or witness for a non-taproot inputs.
|
|
pub partial_sigs: BTreeMap<secp256k1::PublicKey, EcdsaSig>,
|
|
/// The sighash type to be used for this input. Signatures for this input
|
|
/// must use the sighash type.
|
|
pub sighash_type: Option<PsbtSigHashType>,
|
|
/// The redeem script for this input.
|
|
pub redeem_script: Option<Script>,
|
|
/// The witness script for this input.
|
|
pub witness_script: Option<Script>,
|
|
/// A map from public keys needed to sign this input to their corresponding
|
|
/// master key fingerprints and derivation paths.
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
|
pub bip32_derivation: BTreeMap<secp256k1::PublicKey, KeySource>,
|
|
/// The finalized, fully-constructed scriptSig with signatures and any other
|
|
/// scripts necessary for this input to pass validation.
|
|
pub final_script_sig: Option<Script>,
|
|
/// The finalized, fully-constructed scriptWitness with signatures and any
|
|
/// other scripts necessary for this input to pass validation.
|
|
pub final_script_witness: Option<Witness>,
|
|
/// TODO: Proof of reserves commitment
|
|
/// RIPEMD160 hash to preimage map
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
|
|
pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
|
|
/// SHA256 hash to preimage map
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
|
|
pub sha256_preimages: BTreeMap<sha256::Hash, Vec<u8>>,
|
|
/// HSAH160 hash to preimage map
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
|
|
pub hash160_preimages: BTreeMap<hash160::Hash, Vec<u8>>,
|
|
/// HAS256 hash to preimage map
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
|
|
pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>,
|
|
/// Serialized schnorr signature with sighash type for key spend
|
|
pub tap_key_sig: Option<SchnorrSig>,
|
|
/// Map of <xonlypubkey>|<leafhash> with signature
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
|
pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), SchnorrSig>,
|
|
/// Map of Control blocks to Script version pair
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
|
pub tap_scripts: BTreeMap<ControlBlock, (Script, LeafVersion)>,
|
|
/// Map of tap root x only keys to origin info and leaf hashes contained in it
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
|
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
|
|
/// Taproot Internal key
|
|
pub tap_internal_key : Option<XOnlyPublicKey>,
|
|
/// Taproot Merkle root
|
|
pub tap_merkle_root : Option<TapBranchHash>,
|
|
/// Proprietary key-value pairs for this input.
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))]
|
|
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
|
|
/// Unknown key-value pairs for this input.
|
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))]
|
|
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
|
|
}
|
|
|
|
|
|
/// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash
|
|
/// type can be either [`EcdsaSigHashType`] or [`SchnorrSigHashType`] but it is not possible to know
|
|
/// directly which signature hash type the user is dealing with. Therefore, the user is responsible
|
|
/// for converting to/from [`PsbtSigHashType`] from/to the desired signature hash type they need.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
pub struct PsbtSigHashType {
|
|
pub (in ::util::psbt) inner: u32,
|
|
}
|
|
|
|
impl From<EcdsaSigHashType> for PsbtSigHashType {
|
|
fn from(ecdsa_hash_ty: EcdsaSigHashType) -> Self {
|
|
PsbtSigHashType {inner: ecdsa_hash_ty as u32}
|
|
}
|
|
}
|
|
|
|
impl From<SchnorrSigHashType> for PsbtSigHashType {
|
|
fn from(schnorr_hash_ty: SchnorrSigHashType) -> Self {
|
|
PsbtSigHashType {inner: schnorr_hash_ty as u32}
|
|
}
|
|
}
|
|
|
|
impl PsbtSigHashType {
|
|
/// Returns the [`EcdsaSigHashType`] if the [`PsbtSigHashType`] can be
|
|
/// converted to one.
|
|
pub fn ecdsa_hash_ty(self) -> Result<EcdsaSigHashType, NonStandardSigHashType> {
|
|
EcdsaSigHashType::from_u32_standard(self.inner)
|
|
}
|
|
|
|
/// Returns the [`SchnorrSigHashType`] if the [`PsbtSigHashType`] can be
|
|
/// converted to one.
|
|
pub fn schnorr_hash_ty(self) -> Result<SchnorrSigHashType, sighash::Error> {
|
|
if self.inner > 0xffu32 {
|
|
Err(sighash::Error::InvalidSigHashType(self.inner))
|
|
} else {
|
|
SchnorrSigHashType::from_u8(self.inner as u8)
|
|
}
|
|
}
|
|
|
|
/// Obtains the inner sighash byte from this [`PsbtSigHashType`].
|
|
pub fn inner(self) -> u32 {
|
|
self.inner
|
|
}
|
|
}
|
|
|
|
impl Map for Input {
|
|
fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> {
|
|
let raw::Pair {
|
|
key: raw_key,
|
|
value: raw_value,
|
|
} = pair;
|
|
|
|
match raw_key.type_value {
|
|
PSBT_IN_NON_WITNESS_UTXO => {
|
|
impl_psbt_insert_pair! {
|
|
self.non_witness_utxo <= <raw_key: _>|<raw_value: Transaction>
|
|
}
|
|
}
|
|
PSBT_IN_WITNESS_UTXO => {
|
|
impl_psbt_insert_pair! {
|
|
self.witness_utxo <= <raw_key: _>|<raw_value: TxOut>
|
|
}
|
|
}
|
|
PSBT_IN_PARTIAL_SIG => {
|
|
impl_psbt_insert_pair! {
|
|
self.partial_sigs <= <raw_key: secp256k1::PublicKey>|<raw_value: EcdsaSig>
|
|
}
|
|
}
|
|
PSBT_IN_SIGHASH_TYPE => {
|
|
impl_psbt_insert_pair! {
|
|
self.sighash_type <= <raw_key: _>|<raw_value: PsbtSigHashType>
|
|
}
|
|
}
|
|
PSBT_IN_REDEEM_SCRIPT => {
|
|
impl_psbt_insert_pair! {
|
|
self.redeem_script <= <raw_key: _>|<raw_value: Script>
|
|
}
|
|
}
|
|
PSBT_IN_WITNESS_SCRIPT => {
|
|
impl_psbt_insert_pair! {
|
|
self.witness_script <= <raw_key: _>|<raw_value: Script>
|
|
}
|
|
}
|
|
PSBT_IN_BIP32_DERIVATION => {
|
|
impl_psbt_insert_pair! {
|
|
self.bip32_derivation <= <raw_key: secp256k1::PublicKey>|<raw_value: KeySource>
|
|
}
|
|
}
|
|
PSBT_IN_FINAL_SCRIPTSIG => {
|
|
impl_psbt_insert_pair! {
|
|
self.final_script_sig <= <raw_key: _>|<raw_value: Script>
|
|
}
|
|
}
|
|
PSBT_IN_FINAL_SCRIPTWITNESS => {
|
|
impl_psbt_insert_pair! {
|
|
self.final_script_witness <= <raw_key: _>|<raw_value: Witness>
|
|
}
|
|
}
|
|
PSBT_IN_RIPEMD160 => {
|
|
psbt_insert_hash_pair(&mut self.ripemd160_preimages, raw_key, raw_value, error::PsbtHash::Ripemd)?;
|
|
}
|
|
PSBT_IN_SHA256 => {
|
|
psbt_insert_hash_pair(&mut self.sha256_preimages, raw_key, raw_value, error::PsbtHash::Sha256)?;
|
|
}
|
|
PSBT_IN_HASH160 => {
|
|
psbt_insert_hash_pair(&mut self.hash160_preimages, raw_key, raw_value, error::PsbtHash::Hash160)?;
|
|
}
|
|
PSBT_IN_HASH256 => {
|
|
psbt_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsbtHash::Hash256)?;
|
|
}
|
|
PSBT_IN_TAP_KEY_SIG => {
|
|
impl_psbt_insert_pair! {
|
|
self.tap_key_sig <= <raw_key: _>|<raw_value: SchnorrSig>
|
|
}
|
|
}
|
|
PSBT_IN_TAP_SCRIPT_SIG => {
|
|
impl_psbt_insert_pair! {
|
|
self.tap_script_sigs <= <raw_key: (XOnlyPublicKey, TapLeafHash)>|<raw_value: SchnorrSig>
|
|
}
|
|
}
|
|
PSBT_IN_TAP_LEAF_SCRIPT=> {
|
|
impl_psbt_insert_pair! {
|
|
self.tap_scripts <= <raw_key: ControlBlock>|< raw_value: (Script, LeafVersion)>
|
|
}
|
|
}
|
|
PSBT_IN_TAP_BIP32_DERIVATION => {
|
|
impl_psbt_insert_pair! {
|
|
self.tap_key_origins <= <raw_key: XOnlyPublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
|
|
}
|
|
}
|
|
PSBT_IN_TAP_INTERNAL_KEY => {
|
|
impl_psbt_insert_pair! {
|
|
self.tap_internal_key <= <raw_key: _>|< raw_value: XOnlyPublicKey>
|
|
}
|
|
}
|
|
PSBT_IN_TAP_MERKLE_ROOT => {
|
|
impl_psbt_insert_pair! {
|
|
self.tap_merkle_root <= <raw_key: _>|< raw_value: TapBranchHash>
|
|
}
|
|
}
|
|
PSBT_IN_PROPRIETARY => match self.proprietary.entry(raw::ProprietaryKey::from_key(raw_key.clone())?) {
|
|
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);},
|
|
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()),
|
|
}
|
|
_ => match self.unknown.entry(raw_key) {
|
|
btree_map::Entry::Vacant(empty_key) => {
|
|
empty_key.insert(raw_value);
|
|
}
|
|
btree_map::Entry::Occupied(k) => {
|
|
return Err(Error::DuplicateKey(k.key().clone()).into())
|
|
}
|
|
},
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error> {
|
|
let mut rv: Vec<raw::Pair> = Default::default();
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.non_witness_utxo as <PSBT_IN_NON_WITNESS_UTXO, _>|<Transaction>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.witness_utxo as <PSBT_IN_WITNESS_UTXO, _>|<TxOut>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.partial_sigs as <PSBT_IN_PARTIAL_SIG, PublicKey>|<EcdsaSig>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.sighash_type as <PSBT_IN_SIGHASH_TYPE, _>|<SigHashType>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.redeem_script as <PSBT_IN_REDEEM_SCRIPT, _>|<Script>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.witness_script as <PSBT_IN_WITNESS_SCRIPT, _>|<Script>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.bip32_derivation as <PSBT_IN_BIP32_DERIVATION, secp256k1::PublicKey>|<KeySource>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.final_script_sig as <PSBT_IN_FINAL_SCRIPTSIG, _>|<Script>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.final_script_witness as <PSBT_IN_FINAL_SCRIPTWITNESS, _>|<Witness>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.ripemd160_preimages as <PSBT_IN_RIPEMD160, ripemd160::Hash>|<Vec<u8>>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.sha256_preimages as <PSBT_IN_SHA256, sha256::Hash>|<Vec<u8>>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.hash160_preimages as <PSBT_IN_HASH160, hash160::Hash>|<Vec<u8>>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.hash256_preimages as <PSBT_IN_HASH256, sha256d::Hash>|<Vec<u8>>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.tap_key_sig as <PSBT_IN_TAP_KEY_SIG, _>|<SchnorrSig>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.tap_script_sigs as <PSBT_IN_TAP_SCRIPT_SIG, (XOnlyPublicKey, TapLeafHash)>|<SchnorrSig>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.tap_scripts as <PSBT_IN_TAP_LEAF_SCRIPT, ControlBlock>|<(Script, LeafVersion)>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.tap_key_origins as <PSBT_IN_TAP_BIP32_DERIVATION,
|
|
XOnlyPublicKey>|<(Vec<TapLeafHash>, KeySource)>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.tap_internal_key as <PSBT_IN_TAP_INTERNAL_KEY, _>|<XOnlyPublicKey>)
|
|
}
|
|
|
|
impl_psbt_get_pair! {
|
|
rv.push(self.tap_merkle_root as <PSBT_IN_TAP_MERKLE_ROOT, _>|<TapBranchHash>)
|
|
}
|
|
for (key, value) in self.proprietary.iter() {
|
|
rv.push(raw::Pair {
|
|
key: key.to_key(),
|
|
value: value.clone(),
|
|
});
|
|
}
|
|
|
|
for (key, value) in self.unknown.iter() {
|
|
rv.push(raw::Pair {
|
|
key: key.clone(),
|
|
value: value.clone(),
|
|
});
|
|
}
|
|
|
|
Ok(rv)
|
|
}
|
|
|
|
fn merge(&mut self, other: Self) -> Result<(), psbt::Error> {
|
|
merge!(non_witness_utxo, self, other);
|
|
|
|
if let (&None, Some(witness_utxo)) = (&self.witness_utxo, other.witness_utxo) {
|
|
self.witness_utxo = Some(witness_utxo);
|
|
self.non_witness_utxo = None; // Clear out any non-witness UTXO when we set a witness one
|
|
}
|
|
|
|
self.partial_sigs.extend(other.partial_sigs);
|
|
self.bip32_derivation.extend(other.bip32_derivation);
|
|
self.ripemd160_preimages.extend(other.ripemd160_preimages);
|
|
self.sha256_preimages.extend(other.sha256_preimages);
|
|
self.hash160_preimages.extend(other.hash160_preimages);
|
|
self.hash256_preimages.extend(other.hash256_preimages);
|
|
self.tap_script_sigs.extend(other.tap_script_sigs);
|
|
self.tap_scripts.extend(other.tap_scripts);
|
|
self.tap_key_origins.extend(other.tap_key_origins);
|
|
self.proprietary.extend(other.proprietary);
|
|
self.unknown.extend(other.unknown);
|
|
|
|
merge!(redeem_script, self, other);
|
|
merge!(witness_script, self, other);
|
|
merge!(final_script_sig, self, other);
|
|
merge!(final_script_witness, self, other);
|
|
merge!(tap_key_sig, self, other);
|
|
merge!(tap_internal_key, self, other);
|
|
merge!(tap_merkle_root, self, other);
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl_psbtmap_consensus_enc_dec_oding!(Input);
|
|
|
|
fn psbt_insert_hash_pair<H>(
|
|
map: &mut BTreeMap<H, Vec<u8>>,
|
|
raw_key: raw::Key,
|
|
raw_value: Vec<u8>,
|
|
hash_type: error::PsbtHash,
|
|
) -> Result<(), encode::Error>
|
|
where
|
|
H: hashes::Hash + Deserialize,
|
|
{
|
|
if raw_key.key.is_empty() {
|
|
return Err(psbt::Error::InvalidKey(raw_key).into());
|
|
}
|
|
let key_val: H = Deserialize::deserialize(&raw_key.key)?;
|
|
match map.entry(key_val) {
|
|
btree_map::Entry::Vacant(empty_key) => {
|
|
let val: Vec<u8> = Deserialize::deserialize(&raw_value)?;
|
|
if <H as hashes::Hash>::hash(&val) != key_val {
|
|
return Err(psbt::Error::InvalidPreimageHashPair {
|
|
preimage: val.into_boxed_slice(),
|
|
hash: Box::from(key_val.borrow()),
|
|
hash_type,
|
|
}
|
|
.into());
|
|
}
|
|
empty_key.insert(val);
|
|
Ok(())
|
|
}
|
|
btree_map::Entry::Occupied(_) => Err(psbt::Error::DuplicateKey(raw_key).into()),
|
|
}
|
|
}
|