Skip to content

Commit 032a6c8

Browse files
committed
feat: Add Input for PSBT
This allows easier access to the inputs of our PSBT type
1 parent 66bc6c5 commit 032a6c8

File tree

2 files changed

+359
-2
lines changed

2 files changed

+359
-2
lines changed

bdk-ffi/src/bitcoin.rs

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::error::{
44
};
55
use crate::error::{ParseAmountError, PsbtFinalizeError};
66
use crate::{impl_from_core_type, impl_hash_like, impl_into_core_type};
7+
use std::collections::HashMap;
78

89
use bdk_wallet::bitcoin::address::NetworkChecked;
910
use bdk_wallet::bitcoin::address::NetworkUnchecked;
@@ -14,7 +15,9 @@ use bdk_wallet::bitcoin::consensus::encode::serialize;
1415
use bdk_wallet::bitcoin::consensus::Decodable;
1516
use bdk_wallet::bitcoin::hashes::sha256::Hash as BitcoinSha256Hash;
1617
use bdk_wallet::bitcoin::hashes::sha256d::Hash as BitcoinDoubleSha256Hash;
18+
use bdk_wallet::bitcoin::hex::DisplayHex;
1719
use bdk_wallet::bitcoin::io::Cursor;
20+
use bdk_wallet::bitcoin::psbt::Input as BdkInput;
1821
use bdk_wallet::bitcoin::secp256k1::Secp256k1;
1922
use bdk_wallet::bitcoin::Amount as BdkAmount;
2023
use bdk_wallet::bitcoin::BlockHash as BitcoinBlockHash;
@@ -500,6 +503,244 @@ impl Display for Transaction {
500503
}
501504
}
502505

506+
#[derive(Clone, Debug, uniffi::Record)]
507+
pub struct PartialSig {
508+
pub pubkey: String,
509+
pub signature: Vec<u8>,
510+
}
511+
512+
#[derive(Clone, Debug, uniffi::Record)]
513+
pub struct TapScriptSig {
514+
/// x-only pubkey as hex
515+
pub xonly_pubkey: String,
516+
/// tap leaf hash as hex
517+
pub leaf_hash: String,
518+
/// signature bytes
519+
pub signature: Vec<u8>,
520+
}
521+
522+
#[derive(Clone, Debug, uniffi::Record)]
523+
pub struct TapScriptEntry {
524+
/// control block bytes
525+
pub control_block: String,
526+
/// script (reuse existing `Script` FFI type)
527+
pub script: Arc<Script>,
528+
/// leaf version
529+
pub leaf_version: u8,
530+
}
531+
532+
#[derive(Clone, Debug, uniffi::Record)]
533+
pub struct TapKeyOrigin {
534+
/// x-only pubkey as hex
535+
pub xonly_pubkey: String,
536+
/// leaf hashes as hex strings
537+
pub leaf_hashes: Vec<String>,
538+
/// master key fingerprint
539+
pub fingerprint: String,
540+
/// derivation path segments
541+
pub path: String,
542+
}
543+
544+
#[derive(Clone, Debug, uniffi::Record)]
545+
pub struct KeyValuePair {
546+
/// raw key bytes (for proprietary / unknown keys)
547+
pub key: Vec<u8>,
548+
/// raw value bytes
549+
pub value: Vec<u8>,
550+
/// The type of this PSBT key.
551+
pub type_value: u8,
552+
}
553+
554+
#[derive(Clone, Debug, uniffi::Record)]
555+
pub struct ProprietaryKeyValuePair {
556+
/// Proprietary type prefix used for grouping together keys under some application and avoid namespace collision
557+
pub prefix: Vec<u8>,
558+
/// Custom proprietary subtype
559+
pub subtype: u8,
560+
/// Additional key bytes (like serialized public key data etc)
561+
pub key: Vec<u8>,
562+
/// raw value bytes
563+
pub value: Vec<u8>,
564+
}
565+
566+
#[derive(Clone, Debug, uniffi::Record)]
567+
pub struct KeySource {
568+
pub fingerprint: String,
569+
pub path: String,
570+
}
571+
572+
/// A key-value map for an input of the corresponding index in the unsigned transaction.
573+
#[derive(Clone, Debug, uniffi::Record)]
574+
pub struct Input {
575+
/// The non-witness transaction this input spends from. Should only be
576+
/// `Option::Some` for inputs which spend non-segwit outputs or
577+
/// if it is unknown whether an input spends a segwit output.
578+
pub non_witness_utxo: Option<Arc<Transaction>>,
579+
/// The transaction output this input spends from. Should only be
580+
/// `Option::Some` for inputs which spend segwit outputs,
581+
/// including P2SH embedded ones.
582+
pub witness_utxo: Option<TxOut>,
583+
/// A map from public keys to their corresponding signature as would be
584+
/// pushed to the stack from a scriptSig or witness for a non-taproot inputs.
585+
pub partial_sigs: HashMap<String, Vec<u8>>,
586+
/// The sighash type to be used for this input. Signatures for this input
587+
/// must use the sighash type.
588+
pub sighash_type: Option<String>,
589+
/// The redeem script for this input.
590+
pub redeem_script: Option<Arc<Script>>,
591+
/// The witness script for this input.
592+
pub witness_script: Option<Arc<Script>>,
593+
/// A map from public keys needed to sign this input to their corresponding
594+
/// master key fingerprints and derivation paths.
595+
pub bip32_derivation: HashMap<String, KeySource>,
596+
597+
/// The finalized, fully-constructed scriptSig with signatures and any other
598+
/// scripts necessary for this input to pass validation.
599+
pub final_script_sig: Option<Arc<Script>>,
600+
601+
/// The finalized, fully-constructed scriptWitness with signatures and any
602+
/// other scripts necessary for this input to pass validation.
603+
pub final_script_witness: Option<Vec<Vec<u8>>>,
604+
/// RIPEMD160 hash to preimage map.
605+
pub ripemd160_preimages: HashMap<String, Vec<u8>>,
606+
/// SHA256 hash to preimage map.
607+
pub sha256_preimages: HashMap<String, Vec<u8>>,
608+
/// HASH160 hash to preimage map.
609+
pub hash160_preimages: HashMap<String, Vec<u8>>,
610+
/// HASH256 hash to preimage map.
611+
pub hash256_preimages: HashMap<String, Vec<u8>>,
612+
/// Serialized taproot signature with sighash type for key spend.
613+
pub tap_key_sig: Option<Vec<u8>>,
614+
/// Map of `<xonlypubkey>|<leafhash>` with signature.
615+
pub tap_script_sigs: Vec<TapScriptSig>,
616+
/// Map of Control blocks to Script version pair.
617+
pub tap_scripts: Vec<TapScriptEntry>,
618+
/// Map of tap root x only keys to origin info and leaf hashes contained in it.
619+
pub tap_key_origins: Vec<TapKeyOrigin>,
620+
/// Taproot Internal key.
621+
pub tap_internal_key: Option<String>,
622+
/// Taproot Merkle root.
623+
pub tap_merkle_root: Option<String>,
624+
/// Proprietary key-value pairs for this input.
625+
pub proprietary: Vec<ProprietaryKeyValuePair>,
626+
/// Unknown key-value pairs for this input.
627+
pub unknown: Vec<KeyValuePair>,
628+
}
629+
630+
impl From<&BdkInput> for Input {
631+
fn from(input: &BdkInput) -> Self {
632+
Input {
633+
non_witness_utxo: input
634+
.non_witness_utxo
635+
.as_ref()
636+
.map(|tx| Arc::new(Transaction(tx.clone()))),
637+
witness_utxo: input.witness_utxo.as_ref().map(TxOut::from),
638+
partial_sigs: input
639+
.partial_sigs
640+
.iter()
641+
.map(|(k, v)| (k.to_string(), v.to_vec()))
642+
.collect(),
643+
sighash_type: input.sighash_type.as_ref().map(|s| s.to_string()),
644+
redeem_script: input
645+
.redeem_script
646+
.as_ref()
647+
.map(|s| Arc::new(Script(s.clone()))),
648+
witness_script: input
649+
.witness_script
650+
.as_ref()
651+
.map(|s| Arc::new(Script(s.clone()))),
652+
bip32_derivation: input
653+
.bip32_derivation
654+
.iter()
655+
.map(|(pk, (fingerprint, deriv_path))| {
656+
(
657+
pk.to_string(),
658+
KeySource {
659+
fingerprint: fingerprint.to_string(),
660+
path: deriv_path.to_string(),
661+
},
662+
)
663+
})
664+
.collect(),
665+
final_script_sig: input
666+
.final_script_sig
667+
.as_ref()
668+
.map(|s| Arc::new(Script(s.clone()))),
669+
final_script_witness: input.final_script_witness.as_ref().map(|w| w.to_vec()),
670+
ripemd160_preimages: input
671+
.ripemd160_preimages
672+
.iter()
673+
.map(|(k, v)| (k.to_string(), v.clone()))
674+
.collect(),
675+
sha256_preimages: input
676+
.sha256_preimages
677+
.iter()
678+
.map(|(k, v)| (k.to_string(), v.clone()))
679+
.collect(),
680+
hash160_preimages: input
681+
.hash160_preimages
682+
.iter()
683+
.map(|(k, v)| (k.to_string(), v.clone()))
684+
.collect(),
685+
hash256_preimages: input
686+
.hash256_preimages
687+
.iter()
688+
.map(|(k, v)| (k.to_string(), v.clone()))
689+
.collect(),
690+
tap_key_sig: input.tap_key_sig.as_ref().map(|s| s.serialize().to_vec()),
691+
tap_script_sigs: input
692+
.tap_script_sigs
693+
.iter()
694+
.map(|(k, v)| TapScriptSig {
695+
xonly_pubkey: k.0.to_string(),
696+
leaf_hash: k.1.to_string(),
697+
signature: v.to_vec(),
698+
})
699+
.collect::<Vec<TapScriptSig>>(),
700+
tap_scripts: input
701+
.tap_scripts
702+
.iter()
703+
.map(|(k, v)| TapScriptEntry {
704+
control_block: DisplayHex::to_lower_hex_string(&k.serialize()),
705+
script: Arc::new(v.0.clone().into()),
706+
leaf_version: v.1.to_consensus(),
707+
})
708+
.collect::<Vec<TapScriptEntry>>(),
709+
tap_key_origins: input
710+
.tap_key_origins
711+
.iter()
712+
.map(|(k, v)| TapKeyOrigin {
713+
xonly_pubkey: k.to_string(),
714+
leaf_hashes: v.0.iter().map(|h| h.to_string()).collect(),
715+
fingerprint: v.1 .0.to_string(),
716+
path: v.1 .1.to_string(),
717+
})
718+
.collect::<Vec<TapKeyOrigin>>(),
719+
tap_internal_key: input.tap_internal_key.as_ref().map(|k| k.to_string()),
720+
tap_merkle_root: input.tap_merkle_root.as_ref().map(|k| k.to_string()),
721+
proprietary: input
722+
.proprietary
723+
.iter()
724+
.map(|(k, v)| ProprietaryKeyValuePair {
725+
key: k.to_key().key.clone(),
726+
subtype: k.subtype,
727+
prefix: k.prefix.to_vec(),
728+
value: v.to_vec(),
729+
})
730+
.collect(),
731+
unknown: input
732+
.unknown
733+
.iter()
734+
.map(|(k, v)| KeyValuePair {
735+
key: k.key.clone(),
736+
value: v.to_vec(),
737+
type_value: k.type_value,
738+
})
739+
.collect(),
740+
}
741+
}
742+
}
743+
503744
/// A Partially Signed Transaction.
504745
#[derive(uniffi::Object)]
505746
pub struct Psbt(pub(crate) Mutex<BdkPsbt>);
@@ -625,6 +866,12 @@ impl Psbt {
625866
let utxo = psbt.spend_utxo(input_index as usize).unwrap();
626867
serde_json::to_string(&utxo).unwrap()
627868
}
869+
870+
/// The corresponding key-value map for each input in the unsigned transaction.
871+
pub fn input(&self) -> Vec<Input> {
872+
let psbt = self.0.lock().unwrap();
873+
psbt.inputs.iter().map(|input| input.into()).collect()
874+
}
628875
}
629876

630877
impl From<BdkPsbt> for Psbt {

0 commit comments

Comments
 (0)