Skip to content

Commit 72a9540

Browse files
committed
Implement FillPSBT in DescriptorScriptPubKeyMan
FillPSBT will add our own scripts to the PSBT if those inputs are ours. If an input also lists pubkeys that we happen to know the private keys for, we will sign those inputs too.
1 parent 84b4978 commit 72a9540

File tree

2 files changed

+68
-48
lines changed

2 files changed

+68
-48
lines changed

src/wallet/scriptpubkeyman.cpp

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,9 +1974,71 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message,
19741974
return SigningResult::OK;
19751975
}
19761976

1977-
TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, int sighash_type, bool sign, bool bip32derivs) const
1977+
TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, int sighash_type, bool sign, bool bip32derivs) const
19781978
{
1979-
return TransactionError::INVALID_PSBT;
1979+
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
1980+
const CTxIn& txin = psbtx.tx->vin[i];
1981+
PSBTInput& input = psbtx.inputs.at(i);
1982+
1983+
if (PSBTInputSigned(input)) {
1984+
continue;
1985+
}
1986+
1987+
// Verify input looks sane. This will check that we have at most one uxto, witness or non-witness.
1988+
if (!input.IsSane()) {
1989+
return TransactionError::INVALID_PSBT;
1990+
}
1991+
1992+
// Get the Sighash type
1993+
if (sign && input.sighash_type > 0 && input.sighash_type != sighash_type) {
1994+
return TransactionError::SIGHASH_MISMATCH;
1995+
}
1996+
1997+
// Get the scriptPubKey to know which SigningProvider to use
1998+
CScript script;
1999+
if (!input.witness_utxo.IsNull()) {
2000+
script = input.witness_utxo.scriptPubKey;
2001+
} else if (input.non_witness_utxo) {
2002+
if (txin.prevout.n >= input.non_witness_utxo->vout.size()) {
2003+
return TransactionError::MISSING_INPUTS;
2004+
}
2005+
script = input.non_witness_utxo->vout[txin.prevout.n].scriptPubKey;
2006+
} else {
2007+
// There's no UTXO so we can just skip this now
2008+
continue;
2009+
}
2010+
SignatureData sigdata;
2011+
input.FillSignatureData(sigdata);
2012+
2013+
std::unique_ptr<FlatSigningProvider> keys = MakeUnique<FlatSigningProvider>();
2014+
std::unique_ptr<FlatSigningProvider> script_keys = GetSigningProvider(script, sign);
2015+
if (script_keys) {
2016+
*keys = Merge(*keys, *script_keys);
2017+
} else {
2018+
// Maybe there are pubkeys listed that we can sign for
2019+
script_keys = MakeUnique<FlatSigningProvider>();
2020+
for (const auto& pk_pair : input.hd_keypaths) {
2021+
const CPubKey& pubkey = pk_pair.first;
2022+
std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
2023+
if (pk_keys) {
2024+
*keys = Merge(*keys, *pk_keys);
2025+
}
2026+
}
2027+
}
2028+
2029+
SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, sighash_type);
2030+
}
2031+
2032+
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
2033+
for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
2034+
std::unique_ptr<SigningProvider> keys = GetSolvingProvider(psbtx.tx->vout.at(i).scriptPubKey);
2035+
if (!keys) {
2036+
continue;
2037+
}
2038+
UpdatePSBTOutput(HidingSigningProvider(keys.get(), true, !bip32derivs), psbtx, i);
2039+
}
2040+
2041+
return TransactionError::OK;
19802042
}
19812043

19822044
const CKeyMetadata* DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const

src/wallet/wallet.cpp

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2489,52 +2489,10 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
24892489
}
24902490

24912491
// Fill in information from ScriptPubKeyMans
2492-
// Because each ScriptPubKeyMan may be able to fill more than one input, we need to keep track of each ScriptPubKeyMan that has filled this psbt.
2493-
// Each iteration, we may fill more inputs than the input that is specified in that iteration.
2494-
// We assume that each input is filled by only one ScriptPubKeyMan
2495-
std::set<uint256> visited_spk_mans;
2496-
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
2497-
const CTxIn& txin = psbtx.tx->vin[i];
2498-
PSBTInput& input = psbtx.inputs.at(i);
2499-
2500-
if (PSBTInputSigned(input)) {
2501-
continue;
2502-
}
2503-
2504-
// Get the scriptPubKey to know which ScriptPubKeyMan to use
2505-
CScript script;
2506-
if (!input.witness_utxo.IsNull()) {
2507-
script = input.witness_utxo.scriptPubKey;
2508-
} else if (input.non_witness_utxo) {
2509-
if (txin.prevout.n >= input.non_witness_utxo->vout.size()) {
2510-
return TransactionError::MISSING_INPUTS;
2511-
}
2512-
script = input.non_witness_utxo->vout[txin.prevout.n].scriptPubKey;
2513-
} else {
2514-
// There's no UTXO so we can just skip this now
2515-
continue;
2516-
}
2517-
SignatureData sigdata;
2518-
input.FillSignatureData(sigdata);
2519-
std::set<ScriptPubKeyMan*> spk_mans = GetScriptPubKeyMans(script, sigdata);
2520-
if (spk_mans.size() == 0) {
2521-
continue;
2522-
}
2523-
2524-
for (auto& spk_man : spk_mans) {
2525-
// If we've already been signed by this spk_man, skip it
2526-
if (visited_spk_mans.count(spk_man->GetID()) > 0) {
2527-
continue;
2528-
}
2529-
2530-
// Fill in the information from the spk_man
2531-
TransactionError res = spk_man->FillPSBT(psbtx, sighash_type, sign, bip32derivs);
2532-
if (res != TransactionError::OK) {
2533-
return res;
2534-
}
2535-
2536-
// Add this spk_man to visited_spk_mans so we can skip it later
2537-
visited_spk_mans.insert(spk_man->GetID());
2492+
for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
2493+
TransactionError res = spk_man->FillPSBT(psbtx, sighash_type, sign, bip32derivs);
2494+
if (res != TransactionError::OK) {
2495+
return res;
25382496
}
25392497
}
25402498

0 commit comments

Comments
 (0)