mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-05 10:42:13 +02:00
Merge #13723: PSBT key path cleanups
917353c8b0Make SignPSBTInput operate on a private SignatureData object (Pieter Wuille)cad5dd2368Pass HD path data through SignatureData (Pieter Wuille)03a99586a3Implement key origin lookup in CWallet (Pieter Wuille)3b01efa0d1[MOVEONLY] Move ParseHDKeypath to utilstrencodings (Pieter Wuille)81e1dd5ce1Generalize PublicOnlySigningProvider into HidingSigningProvider (Pieter Wuille)84f1f1bfdfMake SigningProvider expose key origin information (Pieter Wuille)611ab307fbIntroduce KeyOriginInfo for fingerprint + path (Pieter Wuille) Pull request description: This PR adds "key origin" (master fingeprint + key path) information to what is exposed from `SigningProvider`s, allowing this information to be used by the generic PSBT code instead of having the RPC pull it directly from the wallet. This is also a preparation to having PSBT interact with output descriptors, which can then directly expose key origin information for the scripts they generate. Tree-SHA512: c718382ba8ba2d6fc9a32c062bd4cff08b6f39b133838aa03115c39aeca0f654c7cc3ec72d87005bf8306e550824cd8eb9d60f0bd41784a3e22e17b2afcfe833
This commit is contained in:
@@ -3842,74 +3842,17 @@ UniValue sethdseed(const JSONRPCRequest& request)
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
bool ParseHDKeypath(std::string keypath_str, std::vector<uint32_t>& keypath)
|
||||
{
|
||||
std::stringstream ss(keypath_str);
|
||||
std::string item;
|
||||
bool first = true;
|
||||
while (std::getline(ss, item, '/')) {
|
||||
if (item.compare("m") == 0) {
|
||||
if (first) {
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Finds whether it is hardened
|
||||
uint32_t path = 0;
|
||||
size_t pos = item.find("'");
|
||||
if (pos != std::string::npos) {
|
||||
// The hardened tick can only be in the last index of the string
|
||||
if (pos != item.size() - 1) {
|
||||
return false;
|
||||
}
|
||||
path |= 0x80000000;
|
||||
item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick
|
||||
}
|
||||
|
||||
// Ensure this is only numbers
|
||||
if (item.find_first_not_of( "0123456789" ) != std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
uint32_t number;
|
||||
if (!ParseUInt32(item, &number)) {
|
||||
return false;
|
||||
}
|
||||
path |= number;
|
||||
|
||||
keypath.push_back(path);
|
||||
first = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths)
|
||||
void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
|
||||
{
|
||||
CPubKey vchPubKey;
|
||||
if (!pwallet->GetPubKey(keyID, vchPubKey)) {
|
||||
return;
|
||||
}
|
||||
CKeyMetadata meta;
|
||||
auto it = pwallet->mapKeyMetadata.find(keyID);
|
||||
if (it != pwallet->mapKeyMetadata.end()) {
|
||||
meta = it->second;
|
||||
KeyOriginInfo info;
|
||||
if (!pwallet->GetKeyOrigin(keyID, info)) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
|
||||
}
|
||||
std::vector<uint32_t> keypath;
|
||||
if (!meta.hdKeypath.empty()) {
|
||||
if (!ParseHDKeypath(meta.hdKeypath, keypath)) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
|
||||
}
|
||||
// Get the proper master key id
|
||||
CKey key;
|
||||
pwallet->GetKey(meta.hd_seed_id, key);
|
||||
CExtKey masterKey;
|
||||
masterKey.SetSeed(key.begin(), key.size());
|
||||
// Add to map
|
||||
keypath.insert(keypath.begin(), ReadLE32(masterKey.key.GetPubKey().GetID().begin()));
|
||||
} else { // Single pubkeys get the master fingerprint of themselves
|
||||
keypath.insert(keypath.begin(), ReadLE32(vchPubKey.GetID().begin()));
|
||||
}
|
||||
hd_keypaths.emplace(vchPubKey, keypath);
|
||||
hd_keypaths.emplace(vchPubKey, std::move(info));
|
||||
}
|
||||
|
||||
bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign, bool bip32derivs)
|
||||
@@ -3937,28 +3880,7 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Specified Sighash and sighash in PSBT do not match.");
|
||||
}
|
||||
|
||||
SignatureData sigdata;
|
||||
if (sign) {
|
||||
complete &= SignPSBTInput(*pwallet, *psbtx.tx, input, sigdata, i, sighash_type);
|
||||
} else {
|
||||
complete &= SignPSBTInput(PublicOnlySigningProvider(pwallet), *psbtx.tx, input, sigdata, i, sighash_type);
|
||||
}
|
||||
|
||||
if (it != pwallet->mapWallet.end()) {
|
||||
// Drop the unnecessary UTXO if we added both from the wallet.
|
||||
if (sigdata.witness) {
|
||||
input.non_witness_utxo = nullptr;
|
||||
} else {
|
||||
input.witness_utxo.SetNull();
|
||||
}
|
||||
}
|
||||
|
||||
// Get public key paths
|
||||
if (bip32derivs) {
|
||||
for (const auto& pubkey_it : sigdata.misc_pubkeys) {
|
||||
AddKeypathToMap(pwallet, pubkey_it.first, input.hd_keypaths);
|
||||
}
|
||||
}
|
||||
complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, i, sighash_type);
|
||||
}
|
||||
|
||||
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
|
||||
@@ -3971,15 +3893,8 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
|
||||
psbt_out.FillSignatureData(sigdata);
|
||||
|
||||
MutableTransactionSignatureCreator creator(psbtx.tx.get_ptr(), 0, out.nValue, 1);
|
||||
ProduceSignature(*pwallet, creator, out.scriptPubKey, sigdata);
|
||||
ProduceSignature(HidingSigningProvider(pwallet, true, !bip32derivs), creator, out.scriptPubKey, sigdata);
|
||||
psbt_out.FromSignatureData(sigdata);
|
||||
|
||||
// Get public key paths
|
||||
if (bip32derivs) {
|
||||
for (const auto& pubkey_it : sigdata.misc_pubkeys) {
|
||||
AddKeypathToMap(pwallet, pubkey_it.first, psbt_out.hd_keypaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
return complete;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user