mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 22:50:59 +01:00
Implement TopUp in DescriptorScriptPubKeyMan
This commit is contained in:
@@ -219,6 +219,11 @@ struct CExtPubKey {
|
|||||||
a.pubkey == b.pubkey;
|
a.pubkey == b.pubkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const CExtPubKey &a, const CExtPubKey &b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
|
void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
|
||||||
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
|
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
|
||||||
bool Derive(CExtPubKey& out, unsigned int nChild) const;
|
bool Derive(CExtPubKey& out, unsigned int nChild) const;
|
||||||
|
|||||||
@@ -1533,9 +1533,99 @@ void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<CKeyID, CKey> DescriptorScriptPubKeyMan::GetKeys() const
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_desc_man);
|
||||||
|
if (m_storage.HasEncryptionKeys() && !m_storage.IsLocked()) {
|
||||||
|
KeyMap keys;
|
||||||
|
for (auto key_pair : m_map_crypted_keys) {
|
||||||
|
const CPubKey& pubkey = key_pair.second.first;
|
||||||
|
const std::vector<unsigned char>& crypted_secret = key_pair.second.second;
|
||||||
|
CKey key;
|
||||||
|
DecryptKey(m_storage.GetEncryptionKey(), crypted_secret, pubkey, key);
|
||||||
|
keys[pubkey.GetID()] = key;
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
return m_map_keys;
|
||||||
|
}
|
||||||
|
|
||||||
bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
|
bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
|
||||||
{
|
{
|
||||||
return false;
|
LOCK(cs_desc_man);
|
||||||
|
unsigned int target_size;
|
||||||
|
if (size > 0) {
|
||||||
|
target_size = size;
|
||||||
|
} else {
|
||||||
|
target_size = std::max(gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the new range_end
|
||||||
|
int32_t new_range_end = std::max(m_wallet_descriptor.next_index + (int32_t)target_size, m_wallet_descriptor.range_end);
|
||||||
|
|
||||||
|
// If the descriptor is not ranged, we actually just want to fill the first cache item
|
||||||
|
if (!m_wallet_descriptor.descriptor->IsRange()) {
|
||||||
|
new_range_end = 1;
|
||||||
|
m_wallet_descriptor.range_end = 1;
|
||||||
|
m_wallet_descriptor.range_start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlatSigningProvider provider;
|
||||||
|
provider.keys = GetKeys();
|
||||||
|
|
||||||
|
WalletBatch batch(m_storage.GetDatabase());
|
||||||
|
uint256 id = GetID();
|
||||||
|
for (int32_t i = m_max_cached_index + 1; i < new_range_end; ++i) {
|
||||||
|
FlatSigningProvider out_keys;
|
||||||
|
std::vector<CScript> scripts_temp;
|
||||||
|
DescriptorCache temp_cache;
|
||||||
|
// Maybe we have a cached xpub and we can expand from the cache first
|
||||||
|
if (!m_wallet_descriptor.descriptor->ExpandFromCache(i, m_wallet_descriptor.cache, scripts_temp, out_keys)) {
|
||||||
|
if (!m_wallet_descriptor.descriptor->Expand(i, provider, scripts_temp, out_keys, &temp_cache)) return false;
|
||||||
|
}
|
||||||
|
// Add all of the scriptPubKeys to the scriptPubKey set
|
||||||
|
for (const CScript& script : scripts_temp) {
|
||||||
|
m_map_script_pub_keys[script] = i;
|
||||||
|
}
|
||||||
|
// Write the cache
|
||||||
|
for (const auto& parent_xpub_pair : temp_cache.GetCachedParentExtPubKeys()) {
|
||||||
|
CExtPubKey xpub;
|
||||||
|
if (m_wallet_descriptor.cache.GetCachedParentExtPubKey(parent_xpub_pair.first, xpub)) {
|
||||||
|
if (xpub != parent_xpub_pair.second) {
|
||||||
|
throw std::runtime_error(std::string(__func__) + ": New cached parent xpub does not match already cached parent xpub");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!batch.WriteDescriptorParentCache(parent_xpub_pair.second, id, parent_xpub_pair.first)) {
|
||||||
|
throw std::runtime_error(std::string(__func__) + ": writing cache item failed");
|
||||||
|
}
|
||||||
|
m_wallet_descriptor.cache.CacheParentExtPubKey(parent_xpub_pair.first, parent_xpub_pair.second);
|
||||||
|
}
|
||||||
|
for (const auto& derived_xpub_map_pair : temp_cache.GetCachedDerivedExtPubKeys()) {
|
||||||
|
for (const auto& derived_xpub_pair : derived_xpub_map_pair.second) {
|
||||||
|
CExtPubKey xpub;
|
||||||
|
if (m_wallet_descriptor.cache.GetCachedDerivedExtPubKey(derived_xpub_map_pair.first, derived_xpub_pair.first, xpub)) {
|
||||||
|
if (xpub != derived_xpub_pair.second) {
|
||||||
|
throw std::runtime_error(std::string(__func__) + ": New cached derived xpub does not match already cached derived xpub");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!batch.WriteDescriptorDerivedCache(derived_xpub_pair.second, id, derived_xpub_map_pair.first, derived_xpub_pair.first)) {
|
||||||
|
throw std::runtime_error(std::string(__func__) + ": writing cache item failed");
|
||||||
|
}
|
||||||
|
m_wallet_descriptor.cache.CacheDerivedExtPubKey(derived_xpub_map_pair.first, derived_xpub_pair.first, derived_xpub_pair.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_max_cached_index++;
|
||||||
|
}
|
||||||
|
m_wallet_descriptor.range_end = new_range_end;
|
||||||
|
batch.WriteDescriptor(GetID(), m_wallet_descriptor);
|
||||||
|
|
||||||
|
// By this point, the cache size should be the size of the entire range
|
||||||
|
assert(m_wallet_descriptor.range_end - 1 == m_max_cached_index);
|
||||||
|
|
||||||
|
NotifyCanGetAddressesChanged();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
|
void DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
|
||||||
@@ -1753,6 +1843,7 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
|
|||||||
}
|
}
|
||||||
m_map_script_pub_keys[script] = i;
|
m_map_script_pub_keys[script] = i;
|
||||||
}
|
}
|
||||||
|
m_max_cached_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -492,6 +492,7 @@ private:
|
|||||||
using KeyMap = std::map<CKeyID, CKey>;
|
using KeyMap = std::map<CKeyID, CKey>;
|
||||||
|
|
||||||
ScriptPubKeyMap m_map_script_pub_keys GUARDED_BY(cs_desc_man);
|
ScriptPubKeyMap m_map_script_pub_keys GUARDED_BY(cs_desc_man);
|
||||||
|
int32_t m_max_cached_index = -1;
|
||||||
|
|
||||||
OutputType m_address_type;
|
OutputType m_address_type;
|
||||||
bool m_internal;
|
bool m_internal;
|
||||||
@@ -505,6 +506,8 @@ private:
|
|||||||
bool m_decryption_thoroughly_checked = false;
|
bool m_decryption_thoroughly_checked = false;
|
||||||
|
|
||||||
bool AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey);
|
bool AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey);
|
||||||
|
|
||||||
|
KeyMap GetKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
|
||||||
public:
|
public:
|
||||||
DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor)
|
DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor)
|
||||||
: ScriptPubKeyMan(storage),
|
: ScriptPubKeyMan(storage),
|
||||||
@@ -526,6 +529,10 @@ public:
|
|||||||
bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) override;
|
bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) override;
|
||||||
void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) override;
|
void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) override;
|
||||||
|
|
||||||
|
// Tops up the descriptor cache and m_map_script_pub_keys. The cache is stored in the wallet file
|
||||||
|
// and is used to expand the descriptor in GetNewDestination. DescriptorScriptPubKeyMan relies
|
||||||
|
// more on ephemeral data than LegacyScriptPubKeyMan. For wallets using unhardened derivation
|
||||||
|
// (with or without private keys), the "keypool" is a single xpub.
|
||||||
bool TopUp(unsigned int size = 0) override;
|
bool TopUp(unsigned int size = 0) override;
|
||||||
|
|
||||||
void MarkUnusedAddresses(const CScript& script) override;
|
void MarkUnusedAddresses(const CScript& script) override;
|
||||||
|
|||||||
@@ -216,6 +216,20 @@ bool WalletBatch::WriteDescriptor(const uint256& desc_id, const WalletDescriptor
|
|||||||
return WriteIC(make_pair(DBKeys::WALLETDESCRIPTOR, desc_id), descriptor);
|
return WriteIC(make_pair(DBKeys::WALLETDESCRIPTOR, desc_id), descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WalletBatch::WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index)
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
|
||||||
|
xpub.Encode(ser_xpub.data());
|
||||||
|
return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), std::make_pair(key_exp_index, der_index)), ser_xpub);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WalletBatch::WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
|
||||||
|
xpub.Encode(ser_xpub.data());
|
||||||
|
return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), key_exp_index), ser_xpub);
|
||||||
|
}
|
||||||
|
|
||||||
class CWalletScanState {
|
class CWalletScanState {
|
||||||
public:
|
public:
|
||||||
unsigned int nKeys{0};
|
unsigned int nKeys{0};
|
||||||
|
|||||||
@@ -249,6 +249,8 @@ public:
|
|||||||
bool WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey);
|
bool WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey);
|
||||||
bool WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret);
|
bool WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret);
|
||||||
bool WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor);
|
bool WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor);
|
||||||
|
bool WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index);
|
||||||
|
bool WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index);
|
||||||
|
|
||||||
/// Write destination data key,value tuple to database
|
/// Write destination data key,value tuple to database
|
||||||
bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);
|
bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);
|
||||||
|
|||||||
Reference in New Issue
Block a user