use std::fmt;
use std::{
cmp,
collections::btree_map::{BTreeMap, Entry},
io,
str::FromStr,
};
use crate::taproot::{ControlBlock, LeafVersion, TapNodeHash, TapLeafHash};
use crate::{schnorr, AssetId, ContractHash};
use crate::{confidential, locktime};
use crate::encode::{self, Decodable};
use crate::hashes::{self, hash160, ripemd160, sha256, sha256d, Hash};
use crate::pset::map::Map;
use crate::pset::raw;
use crate::pset::serialize;
use crate::pset::{self, error, Error};
use crate::{transaction::SighashTypeParseError, SchnorrSighashType};
use crate::{AssetIssuance, BlockHash, EcdsaSighashType, Script, Transaction, TxIn, TxOut, Txid};
use bitcoin::bip32::KeySource;
use bitcoin::{PublicKey, key::XOnlyPublicKey};
use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak, ZERO_TWEAK};
use crate::{OutPoint, Sequence};
const PSET_IN_NON_WITNESS_UTXO: u8 = 0x00;
const PSET_IN_WITNESS_UTXO: u8 = 0x01;
const PSET_IN_PARTIAL_SIG: u8 = 0x02;
const PSET_IN_SIGHASH_TYPE: u8 = 0x03;
const PSET_IN_REDEEM_SCRIPT: u8 = 0x04;
const PSET_IN_WITNESS_SCRIPT: u8 = 0x05;
const PSET_IN_BIP32_DERIVATION: u8 = 0x06;
const PSET_IN_FINAL_SCRIPTSIG: u8 = 0x07;
const PSET_IN_FINAL_SCRIPTWITNESS: u8 = 0x08;
const PSET_IN_RIPEMD160: u8 = 0x0a;
const PSET_IN_SHA256: u8 = 0x0b;
const PSET_IN_HASH160: u8 = 0x0c;
const PSET_IN_HASH256: u8 = 0x0d;
const PSET_IN_PREVIOUS_TXID: u8 = 0x0e;
const PSET_IN_OUTPUT_INDEX: u8 = 0x0f;
const PSET_IN_SEQUENCE: u8 = 0x10;
const PSET_IN_REQUIRED_TIME_LOCKTIME: u8 = 0x11;
const PSET_IN_REQUIRED_HEIGHT_LOCKTIME: u8 = 0x12;
const PSBT_IN_TAP_KEY_SIG: u8 = 0x13;
const PSBT_IN_TAP_SCRIPT_SIG: u8 = 0x14;
const PSBT_IN_TAP_LEAF_SCRIPT: u8 = 0x15;
const PSBT_IN_TAP_BIP32_DERIVATION: u8 = 0x16;
const PSBT_IN_TAP_INTERNAL_KEY: u8 = 0x17;
const PSBT_IN_TAP_MERKLE_ROOT: u8 = 0x18;
const PSET_IN_PROPRIETARY: u8 = 0xFC;
const PSBT_ELEMENTS_IN_ISSUANCE_VALUE: u8 = 0x00;
const PSBT_ELEMENTS_IN_ISSUANCE_VALUE_COMMITMENT: u8 = 0x01;
const PSBT_ELEMENTS_IN_ISSUANCE_VALUE_RANGEPROOF: u8 = 0x02;
const PSBT_ELEMENTS_IN_ISSUANCE_KEYS_RANGEPROOF: u8 = 0x03;
const PSBT_ELEMENTS_IN_PEG_IN_TX: u8 = 0x04;
const PSBT_ELEMENTS_IN_PEG_IN_TXOUT_PROOF: u8 = 0x05;
const PSBT_ELEMENTS_IN_PEG_IN_GENESIS: u8 = 0x06;
const PSBT_ELEMENTS_IN_PEG_IN_CLAIM_SCRIPT: u8 = 0x07;
const PSBT_ELEMENTS_IN_PEG_IN_VALUE: u8 = 0x08;
const PSBT_ELEMENTS_IN_PEG_IN_WITNESS: u8 = 0x09;
const PSBT_ELEMENTS_IN_ISSUANCE_INFLATION_KEYS: u8 = 0x0a;
const PSBT_ELEMENTS_IN_ISSUANCE_INFLATION_KEYS_COMMITMENT: u8 = 0x0b;
const PSBT_ELEMENTS_IN_ISSUANCE_BLINDING_NONCE: u8 = 0x0c;
const PSBT_ELEMENTS_IN_ISSUANCE_ASSET_ENTROPY: u8 = 0x0d;
const PSBT_ELEMENTS_IN_UTXO_RANGEPROOF: u8 = 0x0e;
const PSBT_ELEMENTS_IN_ISSUANCE_BLIND_VALUE_PROOF: u8 = 0x0f;
const PSBT_ELEMENTS_IN_ISSUANCE_BLIND_INFLATION_KEYS_PROOF: u8 = 0x10;
const PSBT_ELEMENTS_IN_EXPLICIT_VALUE: u8 = 0x11;
const PSBT_ELEMENTS_IN_VALUE_PROOF: u8 = 0x12;
const PSBT_ELEMENTS_IN_EXPLICIT_ASSET: u8 = 0x13;
const PSBT_ELEMENTS_IN_ASSET_PROOF: u8 = 0x14;
const PSBT_ELEMENTS_IN_BLINDED_ISSUANCE: u8 = 0x15;
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "actual_serde"))]
pub struct Input {
pub non_witness_utxo: Option<Transaction>,
pub witness_utxo: Option<TxOut>,
#[cfg_attr(
feature = "serde",
serde(with = "crate::serde_utils::btreemap_byte_values")
)]
pub partial_sigs: BTreeMap<PublicKey, Vec<u8>>,
pub sighash_type: Option<PsbtSighashType>,
pub redeem_script: Option<Script>,
pub witness_script: Option<Script>,
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
pub bip32_derivation: BTreeMap<PublicKey, KeySource>,
pub final_script_sig: Option<Script>,
pub final_script_witness: Option<Vec<Vec<u8>>>,
#[cfg_attr(
feature = "serde",
serde(with = "crate::serde_utils::btreemap_byte_values")
)]
pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
#[cfg_attr(
feature = "serde",
serde(with = "crate::serde_utils::btreemap_byte_values")
)]
pub sha256_preimages: BTreeMap<sha256::Hash, Vec<u8>>,
#[cfg_attr(
feature = "serde",
serde(with = "crate::serde_utils::btreemap_byte_values")
)]
pub hash160_preimages: BTreeMap<hash160::Hash, Vec<u8>>,
#[cfg_attr(
feature = "serde",
serde(with = "crate::serde_utils::btreemap_byte_values")
)]
pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>,
pub previous_txid: Txid,
pub previous_output_index: u32,
pub sequence: Option<Sequence>,
pub required_time_locktime: Option<locktime::Time>,
pub required_height_locktime: Option<locktime::Height>,
pub tap_key_sig: Option<schnorr::SchnorrSig>,
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), schnorr::SchnorrSig>,
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
pub tap_scripts: BTreeMap<ControlBlock, (Script, LeafVersion)>,
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
pub tap_internal_key: Option<XOnlyPublicKey>,
pub tap_merkle_root: Option<TapNodeHash>,
pub issuance_value_amount: Option<u64>,
pub issuance_value_comm: Option<secp256k1_zkp::PedersenCommitment>,
pub issuance_value_rangeproof: Option<Box<RangeProof>>,
pub issuance_keys_rangeproof: Option<Box<RangeProof>>,
pub pegin_tx: Option<bitcoin::Transaction>,
pub pegin_txout_proof: Option<Vec<u8>>,
pub pegin_genesis_hash: Option<BlockHash>,
pub pegin_claim_script: Option<Script>,
pub pegin_value: Option<u64>,
pub pegin_witness: Option<Vec<Vec<u8>>>,
pub issuance_inflation_keys: Option<u64>,
pub issuance_inflation_keys_comm: Option<secp256k1_zkp::PedersenCommitment>,
pub issuance_blinding_nonce: Option<Tweak>,
pub issuance_asset_entropy: Option<[u8; 32]>,
pub in_utxo_rangeproof: Option<Box<RangeProof>>,
pub in_issuance_blind_value_proof: Option<Box<RangeProof>>,
pub in_issuance_blind_inflation_keys_proof: Option<Box<RangeProof>>,
pub amount: Option<u64>,
pub blind_value_proof: Option<Box<RangeProof>>,
pub asset: Option<AssetId>,
pub blind_asset_proof: Option<Box<SurjectionProof>>,
pub blinded_issuance: Option<u8>,
#[cfg_attr(
feature = "serde",
serde(with = "crate::serde_utils::btreemap_as_seq_byte_values")
)]
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
#[cfg_attr(
feature = "serde",
serde(with = "crate::serde_utils::btreemap_as_seq_byte_values")
)]
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
}
impl Default for Input {
fn default() -> Self {
Self {
non_witness_utxo: None,
witness_utxo: None,
partial_sigs: BTreeMap::new(),
sighash_type: None,
redeem_script: None,
witness_script: None,
bip32_derivation: BTreeMap::new(),
final_script_sig: None,
final_script_witness: None,
ripemd160_preimages: BTreeMap::new(),
sha256_preimages: BTreeMap::new(),
hash160_preimages: BTreeMap::new(),
hash256_preimages: BTreeMap::new(),
previous_txid: Txid::all_zeros(),
previous_output_index: 0,
sequence: None,
required_time_locktime: None,
required_height_locktime: None,
tap_key_sig: None,
tap_script_sigs: BTreeMap::new(),
tap_scripts: BTreeMap::new(),
tap_key_origins: BTreeMap::new(),
tap_internal_key: None,
tap_merkle_root: None,
issuance_value_amount: None,
issuance_value_comm: None,
issuance_value_rangeproof: None,
issuance_keys_rangeproof: None,
pegin_tx: None,
pegin_txout_proof: None,
pegin_genesis_hash: None,
pegin_claim_script: None,
pegin_value: None,
pegin_witness: None,
issuance_inflation_keys: None,
issuance_inflation_keys_comm: None,
issuance_blinding_nonce: None,
issuance_asset_entropy: None,
in_utxo_rangeproof: None,
in_issuance_blind_value_proof: None,
in_issuance_blind_inflation_keys_proof: None,
amount: None,
blind_value_proof: None,
asset: None,
blind_asset_proof: None,
blinded_issuance: None,
proprietary: BTreeMap::new(),
unknown: BTreeMap::new(),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PsbtSighashType {
pub(crate) inner: u32,
}
serde_string_impl!(PsbtSighashType, "a PsbtSighashType data");
impl fmt::Display for PsbtSighashType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.schnorr_hash_ty() {
Some(SchnorrSighashType::Reserved) | None => write!(f, "{:#x}", self.inner),
Some(schnorr_hash_ty) => fmt::Display::fmt(&schnorr_hash_ty, f),
}
}
}
impl FromStr for PsbtSighashType {
type Err = SighashTypeParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
match SchnorrSighashType::from_str(s) {
Ok(SchnorrSighashType::Reserved) => {
return Err(SighashTypeParseError {
unrecognized: s.to_owned(),
})
}
Ok(ty) => return Ok(ty.into()),
Err(_) => {}
}
if let Ok(inner) = u32::from_str_radix(s.trim_start_matches("0x"), 16) {
return Ok(PsbtSighashType { inner });
}
Err(SighashTypeParseError {
unrecognized: s.to_owned(),
})
}
}
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 {
pub fn ecdsa_hash_ty(self) -> Option<EcdsaSighashType> {
EcdsaSighashType::from_standard(self.inner).ok()
}
pub fn schnorr_hash_ty(self) -> Option<SchnorrSighashType> {
if self.inner > 0xffu32 {
None
} else {
SchnorrSighashType::from_u8(self.inner as u8)
}
}
pub fn from_u32(n: u32) -> PsbtSighashType {
PsbtSighashType { inner: n }
}
pub fn to_u32(self) -> u32 {
self.inner
}
}
impl Input {
pub fn ecdsa_hash_ty(&self) -> Option<EcdsaSighashType> {
self.sighash_type
.map_or(
Some(EcdsaSighashType::All),
PsbtSighashType::ecdsa_hash_ty,
)
}
pub fn schnorr_hash_ty(&self) -> Option<SchnorrSighashType> {
self.sighash_type
.map_or(
Some(SchnorrSighashType::Default),
PsbtSighashType::schnorr_hash_ty,
)
}
pub fn from_prevout(outpoint: OutPoint) -> Self {
Input {
previous_output_index: outpoint.vout,
previous_txid: outpoint.txid,
..Default::default()
}
}
pub fn from_txin(txin: TxIn) -> Self {
let mut ret = Self::from_prevout(txin.previous_output);
let has_issuance = txin.has_issuance();
ret.sequence = Some(txin.sequence);
ret.final_script_sig = Some(txin.script_sig);
ret.final_script_witness = Some(txin.witness.script_witness);
if txin.is_pegin {
ret.previous_output_index |= 1 << 30;
ret.pegin_witness = Some(txin.witness.pegin_witness);
}
if has_issuance {
ret.previous_output_index |= 1 << 31;
ret.issuance_blinding_nonce = Some(txin.asset_issuance.asset_blinding_nonce);
ret.issuance_asset_entropy = Some(txin.asset_issuance.asset_entropy);
match txin.asset_issuance.amount {
confidential::Value::Null => {}
confidential::Value::Explicit(x) => ret.issuance_value_amount = Some(x),
confidential::Value::Confidential(comm) => ret.issuance_value_comm = Some(comm),
}
match txin.asset_issuance.inflation_keys {
confidential::Value::Null => {}
confidential::Value::Explicit(x) => ret.issuance_inflation_keys = Some(x),
confidential::Value::Confidential(comm) => {
ret.issuance_inflation_keys_comm = Some(comm);
}
}
ret.issuance_keys_rangeproof = txin.witness.inflation_keys_rangeproof;
ret.issuance_value_rangeproof = txin.witness.amount_rangeproof;
}
ret
}
pub fn issuance_ids(&self) -> (AssetId, AssetId) {
let issue_nonce = self.issuance_blinding_nonce.unwrap_or(ZERO_TWEAK);
let entropy = if issue_nonce == ZERO_TWEAK {
let prevout = OutPoint {
txid: self.previous_txid,
vout: self.previous_output_index,
};
let contract_hash =
ContractHash::from_byte_array(self.issuance_asset_entropy.unwrap_or_default());
AssetId::generate_asset_entropy(prevout, contract_hash)
} else {
sha256::Midstate::from_byte_array(self.issuance_asset_entropy.unwrap_or_default())
};
let asset_id = AssetId::from_entropy(entropy);
let token_id =
AssetId::reissuance_token_from_entropy(entropy, self.issuance_value_comm.is_some());
(asset_id, token_id)
}
pub fn has_issuance(&self) -> bool {
!self.asset_issuance().is_null()
}
pub fn is_pegin(&self) -> bool {
self.previous_output_index & (1 << 30) != 0
}
pub fn asset_issuance(&self) -> AssetIssuance {
AssetIssuance {
asset_blinding_nonce: *self.issuance_blinding_nonce.as_ref().unwrap_or(&ZERO_TWEAK),
asset_entropy: self.issuance_asset_entropy.unwrap_or_default(),
amount: match (self.issuance_value_amount, self.issuance_value_comm) {
(None, None) => confidential::Value::Null,
(_, Some(comm)) => confidential::Value::Confidential(comm),
(Some(x), None) => confidential::Value::Explicit(x),
},
inflation_keys: match (
self.issuance_inflation_keys,
self.issuance_inflation_keys_comm,
) {
(None, None) => confidential::Value::Null,
(_, Some(comm)) => confidential::Value::Confidential(comm),
(Some(x), None) => confidential::Value::Explicit(x),
},
}
}
}
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 {
PSET_IN_NON_WITNESS_UTXO => {
impl_pset_insert_pair! {
self.non_witness_utxo <= <raw_key: _>|<raw_value: Transaction>
}
}
PSET_IN_WITNESS_UTXO => {
impl_pset_insert_pair! {
self.witness_utxo <= <raw_key: _>|<raw_value: TxOut>
}
}
PSET_IN_PARTIAL_SIG => {
impl_pset_insert_pair! {
self.partial_sigs <= <raw_key: PublicKey>|<raw_value: Vec<u8>>
}
}
PSET_IN_SIGHASH_TYPE => {
impl_pset_insert_pair! {
self.sighash_type <= <raw_key: _>|<raw_value: PsbtSighashType>
}
}
PSET_IN_REDEEM_SCRIPT => {
impl_pset_insert_pair! {
self.redeem_script <= <raw_key: _>|<raw_value: Script>
}
}
PSET_IN_WITNESS_SCRIPT => {
impl_pset_insert_pair! {
self.witness_script <= <raw_key: _>|<raw_value: Script>
}
}
PSET_IN_BIP32_DERIVATION => {
impl_pset_insert_pair! {
self.bip32_derivation <= <raw_key: PublicKey>|<raw_value: KeySource>
}
}
PSET_IN_FINAL_SCRIPTSIG => {
impl_pset_insert_pair! {
self.final_script_sig <= <raw_key: _>|<raw_value: Script>
}
}
PSET_IN_FINAL_SCRIPTWITNESS => {
impl_pset_insert_pair! {
self.final_script_witness <= <raw_key: _>|<raw_value: Vec<Vec<u8>>>
}
}
PSET_IN_RIPEMD160 => {
pset_insert_hash_pair(
&mut self.ripemd160_preimages,
raw_key,
&raw_value,
error::PsetHash::Ripemd,
)?;
}
PSET_IN_SHA256 => {
pset_insert_hash_pair(
&mut self.sha256_preimages,
raw_key,
&raw_value,
error::PsetHash::Sha256,
)?;
}
PSET_IN_HASH160 => {
pset_insert_hash_pair(
&mut self.hash160_preimages,
raw_key,
&raw_value,
error::PsetHash::Hash160,
)?;
}
PSET_IN_HASH256 => {
pset_insert_hash_pair(
&mut self.hash256_preimages,
raw_key,
&raw_value,
error::PsetHash::Hash256,
)?;
}
PSET_IN_PREVIOUS_TXID | PSET_IN_OUTPUT_INDEX => {
return Err(Error::DuplicateKey(raw_key))?;
}
PSET_IN_SEQUENCE => {
impl_pset_insert_pair! {
self.sequence <= <raw_key: _>|<raw_value: Sequence>
}
}
PSET_IN_REQUIRED_TIME_LOCKTIME => {
impl_pset_insert_pair! {
self.required_time_locktime <= <raw_key: _>|<raw_value: locktime::Time>
}
}
PSET_IN_REQUIRED_HEIGHT_LOCKTIME => {
impl_pset_insert_pair! {
self.required_height_locktime <= <raw_key: _>|<raw_value: locktime::Height>
}
}
PSBT_IN_TAP_KEY_SIG => {
impl_pset_insert_pair! {
self.tap_key_sig <= <raw_key: _>|<raw_value: schnorr::SchnorrSig>
}
}
PSBT_IN_TAP_SCRIPT_SIG => {
impl_pset_insert_pair! {
self.tap_script_sigs <= <raw_key: (XOnlyPublicKey, TapLeafHash)>|<raw_value: schnorr::SchnorrSig>
}
}
PSBT_IN_TAP_LEAF_SCRIPT => {
impl_pset_insert_pair! {
self.tap_scripts <= <raw_key: ControlBlock>|< raw_value: (Script, LeafVersion)>
}
}
PSBT_IN_TAP_BIP32_DERIVATION => {
impl_pset_insert_pair! {
self.tap_key_origins <= <raw_key: XOnlyPublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
}
}
PSBT_IN_TAP_INTERNAL_KEY => {
impl_pset_insert_pair! {
self.tap_internal_key <= <raw_key: _>|< raw_value: XOnlyPublicKey>
}
}
PSBT_IN_TAP_MERKLE_ROOT => {
impl_pset_insert_pair! {
self.tap_merkle_root <= <raw_key: _>|< raw_value: TapNodeHash>
}
}
PSET_IN_PROPRIETARY => {
let prop_key = raw::ProprietaryKey::from_key(&raw_key)?;
if prop_key.is_pset_key() {
match prop_key.subtype {
PSBT_ELEMENTS_IN_ISSUANCE_VALUE => {
impl_pset_prop_insert_pair!(self.issuance_value_amount <= <raw_key: _> | <raw_value : u64>);
}
PSBT_ELEMENTS_IN_ISSUANCE_VALUE_COMMITMENT => {
impl_pset_prop_insert_pair!(self.issuance_value_comm <= <raw_key: _> | <raw_value : secp256k1_zkp::PedersenCommitment>);
}
PSBT_ELEMENTS_IN_ISSUANCE_VALUE_RANGEPROOF => {
impl_pset_prop_insert_pair!(self.issuance_value_rangeproof <= <raw_key: _> | <raw_value : Box<RangeProof>>);
}
PSBT_ELEMENTS_IN_ISSUANCE_KEYS_RANGEPROOF => {
impl_pset_prop_insert_pair!(self.issuance_keys_rangeproof <= <raw_key: _> | <raw_value : Box<RangeProof>>);
}
PSBT_ELEMENTS_IN_PEG_IN_TX => {
impl_pset_prop_insert_pair!(self.pegin_tx <= <raw_key: _> | <raw_value : bitcoin::Transaction>);
}
PSBT_ELEMENTS_IN_PEG_IN_TXOUT_PROOF => {
impl_pset_prop_insert_pair!(self.pegin_txout_proof <= <raw_key: _> | <raw_value : Vec<u8>>);
}
PSBT_ELEMENTS_IN_PEG_IN_GENESIS => {
impl_pset_prop_insert_pair!(self.pegin_genesis_hash <= <raw_key: _> | <raw_value : BlockHash>);
}
PSBT_ELEMENTS_IN_PEG_IN_CLAIM_SCRIPT => {
impl_pset_prop_insert_pair!(self.pegin_claim_script <= <raw_key: _> | <raw_value : Script>);
}
PSBT_ELEMENTS_IN_PEG_IN_VALUE => {
impl_pset_prop_insert_pair!(self.pegin_value <= <raw_key: _> | <raw_value : u64>);
}
PSBT_ELEMENTS_IN_PEG_IN_WITNESS => {
impl_pset_prop_insert_pair!(self.pegin_witness <= <raw_key: _> | <raw_value : Vec<Vec<u8>>>);
}
PSBT_ELEMENTS_IN_ISSUANCE_INFLATION_KEYS => {
impl_pset_prop_insert_pair!(self.issuance_inflation_keys <= <raw_key: _> | <raw_value : u64>);
}
PSBT_ELEMENTS_IN_ISSUANCE_INFLATION_KEYS_COMMITMENT => {
impl_pset_prop_insert_pair!(self.issuance_inflation_keys_comm <= <raw_key: _> | <raw_value : secp256k1_zkp::PedersenCommitment>);
}
PSBT_ELEMENTS_IN_ISSUANCE_BLINDING_NONCE => {
impl_pset_prop_insert_pair!(self.issuance_blinding_nonce <= <raw_key: _> | <raw_value : Tweak>);
}
PSBT_ELEMENTS_IN_ISSUANCE_ASSET_ENTROPY => {
impl_pset_prop_insert_pair!(self.issuance_asset_entropy <= <raw_key: _> | <raw_value : [u8;32]>);
}
PSBT_ELEMENTS_IN_UTXO_RANGEPROOF => {
impl_pset_prop_insert_pair!(self.in_utxo_rangeproof <= <raw_key: _> | <raw_value : Box<RangeProof>>);
}
PSBT_ELEMENTS_IN_ISSUANCE_BLIND_VALUE_PROOF => {
impl_pset_prop_insert_pair!(self.in_issuance_blind_value_proof <= <raw_key: _> | <raw_value : Box<RangeProof>>);
}
PSBT_ELEMENTS_IN_ISSUANCE_BLIND_INFLATION_KEYS_PROOF => {
impl_pset_prop_insert_pair!(self.in_issuance_blind_inflation_keys_proof <= <raw_key: _> | <raw_value : Box<RangeProof>>);
}
PSBT_ELEMENTS_IN_EXPLICIT_VALUE => {
impl_pset_prop_insert_pair!(self.amount <= <raw_key: _> | <raw_value : u64>);
}
PSBT_ELEMENTS_IN_VALUE_PROOF => {
impl_pset_prop_insert_pair!(self.blind_value_proof <= <raw_key: _> | <raw_value : Box<RangeProof>>);
}
PSBT_ELEMENTS_IN_EXPLICIT_ASSET => {
impl_pset_prop_insert_pair!(self.asset <= <raw_key: _> | <raw_value : AssetId>);
}
PSBT_ELEMENTS_IN_ASSET_PROOF => {
impl_pset_prop_insert_pair!(self.blind_asset_proof <= <raw_key: _> | <raw_value : Box<SurjectionProof>>);
}
PSBT_ELEMENTS_IN_BLINDED_ISSUANCE => {
impl_pset_prop_insert_pair!(self.blinded_issuance <= <raw_key: _> | <raw_value : u8>);
}
_ => match self.proprietary.entry(prop_key) {
Entry::Vacant(empty_key) => {
empty_key.insert(raw_value);
}
Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()),
},
}
} else {
match self.proprietary.entry(prop_key) {
Entry::Vacant(empty_key) => {
empty_key.insert(raw_value);
}
Entry::Occupied(_) => {
return Err(Error::DuplicateKey(raw_key).into())
}
}
}
}
_ => match self.unknown.entry(raw_key) {
Entry::Vacant(empty_key) => {
empty_key.insert(raw_value);
}
Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()),
},
}
Ok(())
}
fn get_pairs(&self) -> Result<Vec<raw::Pair>, encode::Error> {
let mut rv: Vec<raw::Pair> = Vec::default();
impl_pset_get_pair! {
rv.push(self.non_witness_utxo as <PSET_IN_NON_WITNESS_UTXO, _>)
}
impl_pset_get_pair! {
rv.push(self.witness_utxo as <PSET_IN_WITNESS_UTXO, _>)
}
impl_pset_get_pair! {
rv.push(self.partial_sigs as <PSET_IN_PARTIAL_SIG, PublicKey>)
}
impl_pset_get_pair! {
rv.push(self.sighash_type as <PSET_IN_SIGHASH_TYPE, _>)
}
impl_pset_get_pair! {
rv.push(self.redeem_script as <PSET_IN_REDEEM_SCRIPT, _>)
}
impl_pset_get_pair! {
rv.push(self.witness_script as <PSET_IN_WITNESS_SCRIPT, _>)
}
impl_pset_get_pair! {
rv.push(self.bip32_derivation as <PSET_IN_BIP32_DERIVATION, PublicKey>)
}
impl_pset_get_pair! {
rv.push(self.final_script_sig as <PSET_IN_FINAL_SCRIPTSIG, _>)
}
impl_pset_get_pair! {
rv.push(self.final_script_witness as <PSET_IN_FINAL_SCRIPTWITNESS, _>)
}
impl_pset_get_pair! {
rv.push(self.ripemd160_preimages as <PSET_IN_RIPEMD160, ripemd160::Hash>)
}
impl_pset_get_pair! {
rv.push(self.sha256_preimages as <PSET_IN_SHA256, sha256::Hash>)
}
impl_pset_get_pair! {
rv.push(self.hash160_preimages as <PSET_IN_HASH160, hash160::Hash>)
}
impl_pset_get_pair! {
rv.push(self.hash256_preimages as <PSET_IN_HASH256, sha256d::Hash>)
}
rv.push(raw::Pair {
key: raw::Key {
type_value: PSET_IN_PREVIOUS_TXID,
key: vec![],
},
value: serialize::Serialize::serialize(&self.previous_txid),
});
rv.push(raw::Pair {
key: raw::Key {
type_value: PSET_IN_OUTPUT_INDEX,
key: vec![],
},
value: serialize::Serialize::serialize(&self.previous_output_index),
});
impl_pset_get_pair! {
rv.push(self.sequence as <PSET_IN_SEQUENCE, _>)
}
impl_pset_get_pair! {
rv.push(self.required_time_locktime as <PSET_IN_REQUIRED_TIME_LOCKTIME, _>)
}
impl_pset_get_pair! {
rv.push(self.required_height_locktime as <PSET_IN_REQUIRED_HEIGHT_LOCKTIME, _>)
}
impl_pset_get_pair! {
rv.push(self.tap_key_sig as <PSBT_IN_TAP_KEY_SIG, _>)
}
impl_pset_get_pair! {
rv.push(self.tap_script_sigs as <PSBT_IN_TAP_SCRIPT_SIG, (schnorr::PublicKey, TapLeafHash)>)
}
impl_pset_get_pair! {
rv.push(self.tap_scripts as <PSBT_IN_TAP_LEAF_SCRIPT, ControlBlock>)
}
impl_pset_get_pair! {
rv.push(self.tap_key_origins as <PSBT_IN_TAP_BIP32_DERIVATION,
schnorr::PublicKey>)
}
impl_pset_get_pair! {
rv.push(self.tap_internal_key as <PSBT_IN_TAP_INTERNAL_KEY, _>)
}
impl_pset_get_pair! {
rv.push(self.tap_merkle_root as <PSBT_IN_TAP_MERKLE_ROOT, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.issuance_value_amount as <PSBT_ELEMENTS_IN_ISSUANCE_VALUE, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.issuance_value_comm as <PSBT_ELEMENTS_IN_ISSUANCE_VALUE_COMMITMENT, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.issuance_value_rangeproof as <PSBT_ELEMENTS_IN_ISSUANCE_VALUE_RANGEPROOF, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.issuance_keys_rangeproof as <PSBT_ELEMENTS_IN_ISSUANCE_KEYS_RANGEPROOF, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.pegin_tx as <PSBT_ELEMENTS_IN_PEG_IN_TX, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.pegin_txout_proof as <PSBT_ELEMENTS_IN_PEG_IN_TXOUT_PROOF, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.pegin_genesis_hash as <PSBT_ELEMENTS_IN_PEG_IN_GENESIS, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.pegin_claim_script as <PSBT_ELEMENTS_IN_PEG_IN_CLAIM_SCRIPT, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.pegin_value as <PSBT_ELEMENTS_IN_PEG_IN_VALUE, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.pegin_witness as <PSBT_ELEMENTS_IN_PEG_IN_WITNESS, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.issuance_inflation_keys as <PSBT_ELEMENTS_IN_ISSUANCE_INFLATION_KEYS, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.issuance_inflation_keys_comm as <PSBT_ELEMENTS_IN_ISSUANCE_INFLATION_KEYS_COMMITMENT, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.issuance_blinding_nonce as <PSBT_ELEMENTS_IN_ISSUANCE_BLINDING_NONCE, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.issuance_asset_entropy as <PSBT_ELEMENTS_IN_ISSUANCE_ASSET_ENTROPY, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.in_utxo_rangeproof as <PSBT_ELEMENTS_IN_UTXO_RANGEPROOF, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.in_issuance_blind_value_proof as <PSBT_ELEMENTS_IN_ISSUANCE_BLIND_VALUE_PROOF, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.in_issuance_blind_inflation_keys_proof as <PSBT_ELEMENTS_IN_ISSUANCE_BLIND_INFLATION_KEYS_PROOF, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.amount as <PSBT_ELEMENTS_IN_EXPLICIT_VALUE, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.blind_value_proof as <PSBT_ELEMENTS_IN_VALUE_PROOF, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.asset as <PSBT_ELEMENTS_IN_EXPLICIT_ASSET, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.blind_asset_proof as <PSBT_ELEMENTS_IN_ASSET_PROOF, _>)
}
impl_pset_get_pair! {
rv.push_prop(self.blinded_issuance as <PSBT_ELEMENTS_IN_BLINDED_ISSUANCE, _>)
}
for (key, value) in &self.proprietary {
rv.push(raw::Pair {
key: key.to_key(),
value: value.clone(),
});
}
for (key, value) in &self.unknown {
rv.push(raw::Pair {
key: key.clone(),
value: value.clone(),
});
}
Ok(rv)
}
fn merge(&mut self, other: Self) -> Result<(), pset::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; }
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);
self.required_time_locktime =
cmp::max(self.required_time_locktime, other.required_time_locktime);
self.required_height_locktime = cmp::max(
self.required_height_locktime,
other.required_height_locktime,
);
merge!(issuance_value_amount, self, other);
merge!(issuance_value_comm, self, other);
merge!(issuance_value_rangeproof, self, other);
merge!(issuance_keys_rangeproof, self, other);
merge!(pegin_tx, self, other);
merge!(pegin_txout_proof, self, other);
merge!(pegin_genesis_hash, self, other);
merge!(pegin_claim_script, self, other);
merge!(pegin_value, self, other);
merge!(pegin_witness, self, other);
merge!(issuance_inflation_keys, self, other);
merge!(issuance_inflation_keys_comm, self, other);
merge!(issuance_blinding_nonce, self, other);
merge!(issuance_asset_entropy, self, other);
merge!(in_utxo_rangeproof, self, other);
merge!(in_issuance_blind_value_proof, self, other);
merge!(in_issuance_blind_inflation_keys_proof, self, other);
merge!(amount, self, other);
merge!(blind_value_proof, self, other);
merge!(asset, self, other);
merge!(blind_asset_proof, self, other);
merge!(blinded_issuance, self, other);
Ok(())
}
}
impl_psetmap_consensus_encoding!(Input);
impl Decodable for Input {
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
let mut rv = Self::default();
let mut prev_vout: Option<u32> = None;
let mut prev_txid: Option<Txid> = None;
loop {
match raw::Pair::consensus_decode(&mut d) {
Ok(pair) => {
let raw::Pair {
key: raw_key,
value: raw_value,
} = pair;
match raw_key.type_value {
PSET_IN_PREVIOUS_TXID => {
impl_pset_insert_pair! {
prev_txid <= <raw_key: _>|<raw_value: Txid>
}
}
PSET_IN_OUTPUT_INDEX => {
impl_pset_insert_pair! {
prev_vout <= <raw_key: _>|<raw_value: u32>
}
}
_ => rv.insert_pair(raw::Pair {
key: raw_key,
value: raw_value,
})?,
}
}
Err(crate::encode::Error::PsetError(crate::pset::Error::NoMorePairs)) => break,
Err(e) => return Err(e),
}
}
let prev_txid = prev_txid.ok_or(Error::MissingInputPrevTxId)?;
let prev_vout = prev_vout.ok_or(Error::MissingInputPrevVout)?;
rv.previous_txid = prev_txid;
rv.previous_output_index = prev_vout;
Ok(rv)
}
}
fn pset_insert_hash_pair<H>(
map: &mut BTreeMap<H, Vec<u8>>,
raw_key: raw::Key,
raw_value: &[u8],
hash_type: error::PsetHash,
) -> Result<(), encode::Error>
where
H: hashes::Hash + serialize::Deserialize,
{
if raw_key.key.is_empty() {
return Err(pset::Error::InvalidKey(raw_key).into());
}
let key_val: H = serialize::Deserialize::deserialize(&raw_key.key)?;
match map.entry(key_val) {
Entry::Vacant(empty_key) => {
let val: Vec<u8> = serialize::Deserialize::deserialize(raw_value)?;
if <H as hashes::Hash>::hash(&val) != key_val {
return Err(pset::Error::InvalidPreimageHashPair {
preimage: val,
hash: Vec::from(key_val.borrow()),
hash_type,
}
.into());
}
empty_key.insert(val);
Ok(())
}
Entry::Occupied(_) => Err(pset::Error::DuplicateKey(raw_key).into()),
}
}