Skip to content

Commit d50c8dd

Browse files
committed
Implement GetSolvingProvider for DescriptorScriptPubKeyMan
Internally, a GetSigningProvider function is introduced which allows for some private keys to be optionally included. This can be called with a script as the argument (i.e. a scriptPubKey from our wallet when we are signing) or with a pubkey. In order to know what index to expand the private keys for that pubkey, we need to also cache all of the pubkeys involved when we expand the descriptor. So SetCache and TopUp are updated to do this too.
1 parent f1ca5fe commit d50c8dd

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

src/wallet/scriptpubkeyman.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1680,6 +1680,15 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
16801680
for (const CScript& script : scripts_temp) {
16811681
m_map_script_pub_keys[script] = i;
16821682
}
1683+
for (const auto& pk_pair : out_keys.pubkeys) {
1684+
const CPubKey& pubkey = pk_pair.second;
1685+
if (m_map_pubkeys.count(pubkey) != 0) {
1686+
// We don't need to give an error here.
1687+
// It doesn't matter which of many valid indexes the pubkey has, we just need an index where we can derive it and it's private key
1688+
continue;
1689+
}
1690+
m_map_pubkeys[pubkey] = i;
1691+
}
16831692
// Write the cache
16841693
for (const auto& parent_xpub_pair : temp_cache.GetCachedParentExtPubKeys()) {
16851694
CExtPubKey xpub;
@@ -1876,9 +1885,55 @@ int64_t DescriptorScriptPubKeyMan::GetTimeFirstKey() const
18761885
return m_wallet_descriptor.creation_time;
18771886
}
18781887

1888+
std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvider(const CScript& script, bool include_private) const
1889+
{
1890+
LOCK(cs_desc_man);
1891+
1892+
// Find the index of the script
1893+
auto it = m_map_script_pub_keys.find(script);
1894+
if (it == m_map_script_pub_keys.end()) {
1895+
return nullptr;
1896+
}
1897+
int32_t index = it->second;
1898+
1899+
return GetSigningProvider(index, include_private);
1900+
}
1901+
1902+
std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvider(const CPubKey& pubkey) const
1903+
{
1904+
LOCK(cs_desc_man);
1905+
1906+
// Find index of the pubkey
1907+
auto it = m_map_pubkeys.find(pubkey);
1908+
if (it == m_map_pubkeys.end()) {
1909+
return nullptr;
1910+
}
1911+
int32_t index = it->second;
1912+
1913+
// Always try to get the signing provider with private keys. This function should only be called during signing anyways
1914+
return GetSigningProvider(index, true);
1915+
}
1916+
1917+
std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvider(int32_t index, bool include_private) const
1918+
{
1919+
AssertLockHeld(cs_desc_man);
1920+
// Get the scripts, keys, and key origins for this script
1921+
std::unique_ptr<FlatSigningProvider> out_keys = MakeUnique<FlatSigningProvider>();
1922+
std::vector<CScript> scripts_temp;
1923+
if (!m_wallet_descriptor.descriptor->ExpandFromCache(index, m_wallet_descriptor.cache, scripts_temp, *out_keys)) return nullptr;
1924+
1925+
if (HavePrivateKeys() && include_private) {
1926+
FlatSigningProvider master_provider;
1927+
master_provider.keys = GetKeys();
1928+
m_wallet_descriptor.descriptor->ExpandPrivate(index, master_provider, *out_keys);
1929+
}
1930+
1931+
return out_keys;
1932+
}
1933+
18791934
std::unique_ptr<SigningProvider> DescriptorScriptPubKeyMan::GetSolvingProvider(const CScript& script) const
18801935
{
1881-
return nullptr;
1936+
return GetSigningProvider(script, false);
18821937
}
18831938

18841939
bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sigdata)
@@ -1938,6 +1993,15 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
19381993
}
19391994
m_map_script_pub_keys[script] = i;
19401995
}
1996+
for (const auto& pk_pair : out_keys.pubkeys) {
1997+
const CPubKey& pubkey = pk_pair.second;
1998+
if (m_map_pubkeys.count(pubkey) != 0) {
1999+
// We don't need to give an error here.
2000+
// It doesn't matter which of many valid indexes the pubkey has, we just need an index where we can derive it and it's private key
2001+
continue;
2002+
}
2003+
m_map_pubkeys[pubkey] = i;
2004+
}
19412005
m_max_cached_index++;
19422006
}
19432007
}

src/wallet/scriptpubkeyman.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,10 +488,12 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
488488
WalletDescriptor m_wallet_descriptor GUARDED_BY(cs_desc_man);
489489

490490
using ScriptPubKeyMap = std::map<CScript, int32_t>; // Map of scripts to descriptor range index
491+
using PubKeyMap = std::map<CPubKey, int32_t>; // Map of pubkeys involved in scripts to descriptor range index
491492
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
492493
using KeyMap = std::map<CKeyID, CKey>;
493494

494495
ScriptPubKeyMap m_map_script_pub_keys GUARDED_BY(cs_desc_man);
496+
PubKeyMap m_map_pubkeys GUARDED_BY(cs_desc_man);
495497
int32_t m_max_cached_index = -1;
496498

497499
OutputType m_address_type;
@@ -508,6 +510,14 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
508510
bool AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey);
509511

510512
KeyMap GetKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
513+
514+
// Fetch the SigningProvider for the given script and optionally include private keys
515+
std::unique_ptr<FlatSigningProvider> GetSigningProvider(const CScript& script, bool include_private = false) const;
516+
// Fetch the SigningProvider for the given pubkey and always include private keys. This should only be called by signing code.
517+
std::unique_ptr<FlatSigningProvider> GetSigningProvider(const CPubKey& pubkey) const;
518+
// Fetch the SigningProvider for a given index and optionally include private keys. Called by the above functions.
519+
std::unique_ptr<FlatSigningProvider> GetSigningProvider(int32_t index, bool include_private = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
520+
511521
public:
512522
DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor)
513523
: ScriptPubKeyMan(storage),

0 commit comments

Comments
 (0)