From 06620302c713cae65ee8e4ff9302e4c88e2a1285 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 16 Jul 2019 13:34:35 -0400 Subject: Introduce SetType function to tell ScriptPubKeyMans the type and internal-ness of it --- src/wallet/scriptpubkeyman.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index ec75f06e5..f8f5740b3 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1497,3 +1497,5 @@ std::set LegacyScriptPubKeyMan::GetKeys() const } return set_address; } + +void LegacyScriptPubKeyMan::SetType(OutputType type, bool internal) {} -- cgit v1.2.3 From 6b8119af53ee2fdb4c4b5b24b4e650c0dc3bd27c Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 5 Jul 2019 18:16:48 -0400 Subject: Introduce DescriptorScriptPubKeyMan as a dummy class --- src/wallet/scriptpubkeyman.cpp | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index f8f5740b3..ea61ab793 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1499,3 +1499,113 @@ std::set LegacyScriptPubKeyMan::GetKeys() const } void LegacyScriptPubKeyMan::SetType(OutputType type, bool internal) {} + +bool DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDestination& dest, std::string& error) +{ + return false; +} + +isminetype DescriptorScriptPubKeyMan::IsMine(const CScript& script) const +{ + return ISMINE_NO; +} + +bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys) +{ + return false; +} + +bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) +{ + return false; +} + +bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) +{ + return false; +} + +void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) +{ +} + +bool DescriptorScriptPubKeyMan::TopUp(unsigned int size) +{ + return false; +} + +void DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script) +{ +} + +bool DescriptorScriptPubKeyMan::IsHDEnabled() const +{ + return false; +} + +bool DescriptorScriptPubKeyMan::CanGetAddresses(bool internal) const +{ + return false; +} + +bool DescriptorScriptPubKeyMan::HavePrivateKeys() const +{ + return false; +} + +int64_t DescriptorScriptPubKeyMan::GetOldestKeyPoolTime() const +{ + return GetTime(); +} + +size_t DescriptorScriptPubKeyMan::KeypoolCountExternalKeys() const +{ + return 0; +} + +unsigned int DescriptorScriptPubKeyMan::GetKeyPoolSize() const +{ + return 0; +} + +int64_t DescriptorScriptPubKeyMan::GetTimeFirstKey() const +{ + return 0; +} + +std::unique_ptr DescriptorScriptPubKeyMan::GetSolvingProvider(const CScript& script) const +{ + return nullptr; +} + +bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sigdata) +{ + return false; +} + +bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map& coins, int sighash, std::map& input_errors) const +{ + return false; +} + +SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const +{ + return SigningResult::SIGNING_FAILED; +} + +TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, int sighash_type, bool sign, bool bip32derivs) const +{ + return TransactionError::INVALID_PSBT; +} + +const CKeyMetadata* DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const +{ + return nullptr; +} + +uint256 DescriptorScriptPubKeyMan::GetID() const +{ + return uint256(); +} + +void DescriptorScriptPubKeyMan::SetType(OutputType type, bool internal) {} -- cgit v1.2.3 From 78f8a92910d34247fa5d04368338c598d9908267 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 16 Jul 2019 13:50:32 -0400 Subject: Implement SetType in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index ea61ab793..c825438f9 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1608,4 +1608,8 @@ uint256 DescriptorScriptPubKeyMan::GetID() const return uint256(); } -void DescriptorScriptPubKeyMan::SetType(OutputType type, bool internal) {} +void DescriptorScriptPubKeyMan::SetType(OutputType type, bool internal) +{ + this->m_address_type = type; + this->m_internal = internal; +} -- cgit v1.2.3 From 2db7ca765c8fb2c71dd6f7c4f29ad70e68ff1720 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 5 Jul 2019 18:33:55 -0400 Subject: Implement IsMine for DescriptorScriptPubKeyMan Adds a set of scriptPubKeys that DescriptorScriptPubKeyMan tracks. If the given script is in that set, it is considered ISMINE_SPENDABLE --- src/wallet/scriptpubkeyman.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index c825438f9..88563459b 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1507,6 +1507,10 @@ bool DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDest isminetype DescriptorScriptPubKeyMan::IsMine(const CScript& script) const { + LOCK(cs_desc_man); + if (m_map_script_pub_keys.count(script) > 0) { + return ISMINE_SPENDABLE; + } return ISMINE_NO; } @@ -1580,7 +1584,7 @@ std::unique_ptr DescriptorScriptPubKeyMan::GetSolvingProvider(c bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sigdata) { - return false; + return IsMine(script); } bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map& coins, int sighash, std::map& input_errors) const -- cgit v1.2.3 From 741122d4c1a62ced3e96d16d67f4eeb3a6522d99 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 8 Jul 2019 16:25:10 -0400 Subject: Implement MarkUnusedAddresses in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 88563459b..31a87a53f 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1540,6 +1540,17 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size) void DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script) { + LOCK(cs_desc_man); + if (IsMine(script)) { + int32_t index = m_map_script_pub_keys[script]; + if (index >= m_wallet_descriptor.next_index) { + WalletLogPrintf("%s: Detected a used keypool item at index %d, mark all keypool items up to this item as used\n", __func__, index); + m_wallet_descriptor.next_index = index + 1; + } + if (!TopUp()) { + WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__); + } + } } bool DescriptorScriptPubKeyMan::IsHDEnabled() const -- cgit v1.2.3 From ec2f9e1178c8e38c0a5ca063fe81adac8f916348 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 8 Jul 2019 17:05:05 -0400 Subject: Implement IsHDEnabled in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 31a87a53f..c28b7fcfa 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1555,7 +1555,8 @@ void DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script) bool DescriptorScriptPubKeyMan::IsHDEnabled() const { - return false; + LOCK(cs_desc_man); + return m_wallet_descriptor.descriptor->IsRange(); } bool DescriptorScriptPubKeyMan::CanGetAddresses(bool internal) const -- cgit v1.2.3 From 46c46aebb7943e1e2e96755e94dc6c197920bf75 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 8 Jul 2019 17:28:17 -0400 Subject: Implement GetID for DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index c28b7fcfa..a6978d4aa 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1621,7 +1621,11 @@ const CKeyMetadata* DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& uint256 DescriptorScriptPubKeyMan::GetID() const { - return uint256(); + LOCK(cs_desc_man); + std::string desc_str = m_wallet_descriptor.descriptor->ToString(); + uint256 id; + CSHA256().Write((unsigned char*)desc_str.data(), desc_str.size()).Finalize(id.begin()); + return id; } void DescriptorScriptPubKeyMan::SetType(OutputType type, bool internal) -- cgit v1.2.3 From 2363e9fcaa41b68bf11153f591b95f2d41ff9a1a Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 9 Jul 2019 13:40:34 -0400 Subject: Load the descriptor cache from the wallet file --- src/wallet/scriptpubkeyman.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index a6978d4aa..714286708 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1633,3 +1633,23 @@ void DescriptorScriptPubKeyMan::SetType(OutputType type, bool internal) this->m_address_type = type; this->m_internal = internal; } + +void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache) +{ + LOCK(cs_desc_man); + m_wallet_descriptor.cache = cache; + for (int32_t i = m_wallet_descriptor.range_start; i < m_wallet_descriptor.range_end; ++i) { + FlatSigningProvider out_keys; + std::vector scripts_temp; + if (!m_wallet_descriptor.descriptor->ExpandFromCache(i, m_wallet_descriptor.cache, scripts_temp, out_keys)) { + throw std::runtime_error("Error: Unable to expand wallet descriptor from cache"); + } + // Add all of the scriptPubKeys to the scriptPubKey set + for (const CScript& script : scripts_temp) { + if (m_map_script_pub_keys.count(script) != 0) { + throw std::runtime_error(strprintf("Error: Already loaded script at index %d as being at index %d", i, m_map_script_pub_keys[script])); + } + m_map_script_pub_keys[script] = i; + } + } +} -- cgit v1.2.3 From 953feb3d2724f5398dd48990c4957a19313d2c8c Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 9 Jul 2019 18:23:51 -0400 Subject: Implement loading of keys for DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 714286708..d651816e5 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1653,3 +1653,21 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache) } } } + +bool DescriptorScriptPubKeyMan::AddKey(const CKeyID& key_id, const CKey& key) +{ + LOCK(cs_desc_man); + m_map_keys[key_id] = key; + return true; +} + +bool DescriptorScriptPubKeyMan::AddCryptedKey(const CKeyID& key_id, const CPubKey& pubkey, const std::vector& crypted_key) +{ + LOCK(cs_desc_man); + if (!m_map_keys.empty()) { + return false; + } + + m_map_crypted_keys[key_id] = make_pair(pubkey, crypted_key); + return true; +} -- cgit v1.2.3 From 4cb9b69be031e1dc65d8964794781b347fd948f5 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 9 Jul 2019 19:34:39 -0400 Subject: Implement several simple functions in DescriptorScriptPubKeyMan Implements a bunch of one liners: UpgradeKeyMetadata, IsFirstRun, HavePrivateKeys, KeypoolCountExternalKeys, GetKeypoolSize, GetTimeFirstKey, CanGetAddresses, RewriteDB --- src/wallet/scriptpubkeyman.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index d651816e5..fbba42f50 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1561,12 +1561,18 @@ bool DescriptorScriptPubKeyMan::IsHDEnabled() const bool DescriptorScriptPubKeyMan::CanGetAddresses(bool internal) const { - return false; + // We can only give out addresses from descriptors that are single type (not combo), ranged, + // and either have cached keys or can generate more keys (ignoring encryption) + LOCK(cs_desc_man); + return m_wallet_descriptor.descriptor->IsSingleType() && + m_wallet_descriptor.descriptor->IsRange() && + (HavePrivateKeys() || m_wallet_descriptor.next_index < m_wallet_descriptor.range_end); } bool DescriptorScriptPubKeyMan::HavePrivateKeys() const { - return false; + LOCK(cs_desc_man); + return m_map_keys.size() > 0 || m_map_crypted_keys.size() > 0; } int64_t DescriptorScriptPubKeyMan::GetOldestKeyPoolTime() const @@ -1576,17 +1582,22 @@ int64_t DescriptorScriptPubKeyMan::GetOldestKeyPoolTime() const size_t DescriptorScriptPubKeyMan::KeypoolCountExternalKeys() const { - return 0; + if (m_internal) { + return 0; + } + return GetKeyPoolSize(); } unsigned int DescriptorScriptPubKeyMan::GetKeyPoolSize() const { - return 0; + LOCK(cs_desc_man); + return m_wallet_descriptor.range_end - m_wallet_descriptor.next_index; } int64_t DescriptorScriptPubKeyMan::GetTimeFirstKey() const { - return 0; + LOCK(cs_desc_man); + return m_wallet_descriptor.creation_time; } std::unique_ptr DescriptorScriptPubKeyMan::GetSolvingProvider(const CScript& script) const -- cgit v1.2.3 From 46dfb99768e7d03a3cf552812d5b41ceaebc06be Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 10 Jul 2019 16:02:43 -0400 Subject: Implement writing descriptorkeys, descriptorckeys, and descriptors to wallet file --- src/wallet/scriptpubkeyman.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index fbba42f50..76beafa7e 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1553,6 +1553,30 @@ void DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script) } } +bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey) +{ + AssertLockHeld(cs_desc_man); + assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); + + if (m_storage.HasEncryptionKeys()) { + if (m_storage.IsLocked()) { + return false; + } + + std::vector crypted_secret; + CKeyingMaterial secret(key.begin(), key.end()); + if (!EncryptSecret(m_storage.GetEncryptionKey(), secret, pubkey.GetHash(), crypted_secret)) { + return false; + } + + m_map_crypted_keys[pubkey.GetID()] = make_pair(pubkey, crypted_secret); + return batch.WriteCryptedDescriptorKey(GetID(), pubkey, crypted_secret); + } else { + m_map_keys[pubkey.GetID()] = key; + return batch.WriteDescriptorKey(GetID(), pubkey, key.GetPrivKey()); + } +} + bool DescriptorScriptPubKeyMan::IsHDEnabled() const { LOCK(cs_desc_man); -- cgit v1.2.3 From e014886a342508f7c8d80323eee9a5f314eaf94c Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 10 Jul 2019 16:03:17 -0400 Subject: Implement SetupGeneration for DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 76beafa7e..91637803e 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1577,6 +1577,73 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const } } +bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key) +{ + LOCK(cs_desc_man); + assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); + + // Ignore when there is already a descriptor + if (m_wallet_descriptor.descriptor) { + return false; + } + + int64_t creation_time = GetTime(); + + std::string xpub = EncodeExtPubKey(master_key.Neuter()); + + // Build descriptor string + std::string desc_prefix; + std::string desc_suffix = "/*)"; + switch (m_address_type) { + case OutputType::LEGACY: { + desc_prefix = "pkh(" + xpub + "/44'"; + break; + } + case OutputType::P2SH_SEGWIT: { + desc_prefix = "sh(wpkh(" + xpub + "/49'"; + desc_suffix += ")"; + break; + } + case OutputType::BECH32: { + desc_prefix = "wpkh(" + xpub + "/84'"; + break; + } + default: assert(false); + } + + // Mainnet derives at 0', testnet and regtest derive at 1' + if (Params().IsTestChain()) { + desc_prefix += "/1'"; + } else { + desc_prefix += "/0'"; + } + + std::string internal_path = m_internal ? "/1" : "/0"; + std::string desc_str = desc_prefix + "/0'" + internal_path + desc_suffix; + + // Make the descriptor + FlatSigningProvider keys; + std::string error; + std::unique_ptr desc = Parse(desc_str, keys, error, false); + WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); + m_wallet_descriptor = w_desc; + + // Store the master private key, and descriptor + WalletBatch batch(m_storage.GetDatabase()); + if (!AddDescriptorKeyWithDB(batch, master_key.key, master_key.key.GetPubKey())) { + throw std::runtime_error(std::string(__func__) + ": writing descriptor master private key failed"); + } + if (!batch.WriteDescriptor(GetID(), m_wallet_descriptor)) { + throw std::runtime_error(std::string(__func__) + ": writing descriptor failed"); + } + + // TopUp + TopUp(); + + m_storage.UnsetBlankWalletFlag(batch); + return true; +} + bool DescriptorScriptPubKeyMan::IsHDEnabled() const { LOCK(cs_desc_man); -- cgit v1.2.3 From 58c7651821b0eeff0a99dc61d78d2e9e07986580 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 10 Jul 2019 16:38:12 -0400 Subject: Implement TopUp in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 93 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 91637803e..dea4d072f 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1533,9 +1533,99 @@ void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, { } +std::map 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& 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) { - 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 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) @@ -1753,6 +1843,7 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache) } m_map_script_pub_keys[script] = i; } + m_max_cached_index++; } } -- cgit v1.2.3 From bfdd0734869a22217c15858d7a76d0dacc2ebc86 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 10 Jul 2019 18:01:40 -0400 Subject: Implement GetNewDestination for DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index dea4d072f..564fff2f6 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1502,7 +1502,44 @@ void LegacyScriptPubKeyMan::SetType(OutputType type, bool internal) {} bool DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDestination& dest, std::string& error) { - return false; + // Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later + if (!CanGetAddresses(m_internal)) { + error = "No addresses available"; + return false; + } + { + LOCK(cs_desc_man); + assert(m_wallet_descriptor.descriptor->IsSingleType()); // This is a combo descriptor which should not be an active descriptor + if (type != m_address_type) { + throw std::runtime_error(std::string(__func__) + ": Types are inconsistent"); + } + + TopUp(); + + // Get the scriptPubKey from the descriptor + FlatSigningProvider out_keys; + std::vector scripts_temp; + if (m_wallet_descriptor.range_end <= m_max_cached_index && !TopUp(1)) { + // We can't generate anymore keys + error = "Error: Keypool ran out, please call keypoolrefill first"; + return false; + } + if (!m_wallet_descriptor.descriptor->ExpandFromCache(m_wallet_descriptor.next_index, m_wallet_descriptor.cache, scripts_temp, out_keys)) { + // We can't generate anymore keys + error = "Error: Keypool ran out, please call keypoolrefill first"; + return false; + } + + Optional out_script_type = m_wallet_descriptor.descriptor->GetOutputType(); + if (out_script_type && out_script_type == type) { + ExtractDestination(scripts_temp[0], dest); + } else { + throw std::runtime_error(std::string(__func__) + ": Types are inconsistent. Stored type does not match type of newly generated address"); + } + m_wallet_descriptor.next_index++; + WalletBatch(m_storage.GetDatabase()).WriteDescriptor(GetID(), m_wallet_descriptor); + return true; + } } isminetype DescriptorScriptPubKeyMan::IsMine(const CScript& script) const -- cgit v1.2.3 From a775f7c7fd0b9094fcbeee6ba92206d5bbb19164 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 11 Jul 2019 14:32:05 -0400 Subject: Implement Unlock and Encrypt in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 49 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 564fff2f6..8effb67ab 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1553,12 +1553,57 @@ isminetype DescriptorScriptPubKeyMan::IsMine(const CScript& script) const bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys) { - return false; + LOCK(cs_desc_man); + if (!m_map_keys.empty()) { + return false; + } + + bool keyPass = m_map_crypted_keys.empty(); // Always pass when there are no encrypted keys + bool keyFail = false; + for (const auto& mi : m_map_crypted_keys) { + const CPubKey &pubkey = mi.second.first; + const std::vector &crypted_secret = mi.second.second; + CKey key; + if (!DecryptKey(master_key, crypted_secret, pubkey, key)) { + keyFail = true; + break; + } + keyPass = true; + if (m_decryption_thoroughly_checked) + break; + } + if (keyPass && keyFail) { + LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n"); + throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt."); + } + if (keyFail || (!keyPass && !accept_no_keys)) { + return false; + } + m_decryption_thoroughly_checked = true; + return true; } bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) { - return false; + LOCK(cs_desc_man); + if (!m_map_crypted_keys.empty()) { + return false; + } + + for (const KeyMap::value_type& key_in : m_map_keys) + { + const CKey &key = key_in.second; + CPubKey pubkey = key.GetPubKey(); + CKeyingMaterial secret(key.begin(), key.end()); + std::vector crypted_secret; + if (!EncryptSecret(master_key, secret, pubkey.GetHash(), crypted_secret)) { + return false; + } + m_map_crypted_keys[pubkey.GetID()] = make_pair(pubkey, crypted_secret); + batch->WriteCryptedDescriptorKey(GetID(), pubkey, crypted_secret); + } + m_map_keys.clear(); + return true; } bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) -- cgit v1.2.3 From f866957979c23cefd41efa9dae9e53b9177818dc Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 11 Jul 2019 15:54:07 -0400 Subject: Implement GetReservedDestination in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 8effb67ab..c9f2e38ae 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1608,7 +1608,11 @@ bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, Walle bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) { - return false; + LOCK(cs_desc_man); + std::string error; + bool result = GetNewDestination(type, address, error); + index = m_wallet_descriptor.next_index - 1; + return result; } void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) -- cgit v1.2.3 From 586b57a9a6b4b12a78f792785b63a5a1743bce0c Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 11 Jul 2019 14:44:53 -0400 Subject: Implement ReturnDestination in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index c9f2e38ae..c0d48c224 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1617,6 +1617,13 @@ bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bo void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) { + LOCK(cs_desc_man); + // Only return when the index was the most recent + if (m_wallet_descriptor.next_index - 1 == index) { + m_wallet_descriptor.next_index--; + } + WalletBatch(m_storage.GetDatabase()).WriteDescriptor(GetID(), m_wallet_descriptor); + NotifyCanGetAddressesChanged(); } std::map DescriptorScriptPubKeyMan::GetKeys() const -- cgit v1.2.3 From f1ca5feb4ad668a3e1ae543d0addd5f483f1a88f Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 11 Jul 2019 16:14:17 -0400 Subject: Implement GetKeypoolOldestTime and only display it if greater than 0 --- src/wallet/scriptpubkeyman.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index c0d48c224..cf2882ed6 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1851,7 +1851,9 @@ bool DescriptorScriptPubKeyMan::HavePrivateKeys() const int64_t DescriptorScriptPubKeyMan::GetOldestKeyPoolTime() const { - return GetTime(); + // This is only used for getwalletinfo output and isn't relevant to descriptor wallets. + // The magic number 0 indicates that it shouldn't be displayed so that's what we return. + return 0; } size_t DescriptorScriptPubKeyMan::KeypoolCountExternalKeys() const -- cgit v1.2.3 From d50c8ddd4190f20bf0debd410348b73408ec3143 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 11 Jul 2019 16:41:25 -0400 Subject: 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. --- src/wallet/scriptpubkeyman.cpp | 66 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index cf2882ed6..67063ad23 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1680,6 +1680,15 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size) for (const CScript& script : scripts_temp) { m_map_script_pub_keys[script] = i; } + for (const auto& pk_pair : out_keys.pubkeys) { + const CPubKey& pubkey = pk_pair.second; + if (m_map_pubkeys.count(pubkey) != 0) { + // We don't need to give an error here. + // 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 + continue; + } + m_map_pubkeys[pubkey] = i; + } // Write the cache for (const auto& parent_xpub_pair : temp_cache.GetCachedParentExtPubKeys()) { CExtPubKey xpub; @@ -1876,9 +1885,55 @@ int64_t DescriptorScriptPubKeyMan::GetTimeFirstKey() const return m_wallet_descriptor.creation_time; } +std::unique_ptr DescriptorScriptPubKeyMan::GetSigningProvider(const CScript& script, bool include_private) const +{ + LOCK(cs_desc_man); + + // Find the index of the script + auto it = m_map_script_pub_keys.find(script); + if (it == m_map_script_pub_keys.end()) { + return nullptr; + } + int32_t index = it->second; + + return GetSigningProvider(index, include_private); +} + +std::unique_ptr DescriptorScriptPubKeyMan::GetSigningProvider(const CPubKey& pubkey) const +{ + LOCK(cs_desc_man); + + // Find index of the pubkey + auto it = m_map_pubkeys.find(pubkey); + if (it == m_map_pubkeys.end()) { + return nullptr; + } + int32_t index = it->second; + + // Always try to get the signing provider with private keys. This function should only be called during signing anyways + return GetSigningProvider(index, true); +} + +std::unique_ptr DescriptorScriptPubKeyMan::GetSigningProvider(int32_t index, bool include_private) const +{ + AssertLockHeld(cs_desc_man); + // Get the scripts, keys, and key origins for this script + std::unique_ptr out_keys = MakeUnique(); + std::vector scripts_temp; + if (!m_wallet_descriptor.descriptor->ExpandFromCache(index, m_wallet_descriptor.cache, scripts_temp, *out_keys)) return nullptr; + + if (HavePrivateKeys() && include_private) { + FlatSigningProvider master_provider; + master_provider.keys = GetKeys(); + m_wallet_descriptor.descriptor->ExpandPrivate(index, master_provider, *out_keys); + } + + return out_keys; +} + std::unique_ptr DescriptorScriptPubKeyMan::GetSolvingProvider(const CScript& script) const { - return nullptr; + return GetSigningProvider(script, false); } bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sigdata) @@ -1938,6 +1993,15 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache) } m_map_script_pub_keys[script] = i; } + for (const auto& pk_pair : out_keys.pubkeys) { + const CPubKey& pubkey = pk_pair.second; + if (m_map_pubkeys.count(pubkey) != 0) { + // We don't need to give an error here. + // 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 + continue; + } + m_map_pubkeys[pubkey] = i; + } m_max_cached_index++; } } -- cgit v1.2.3 From bde7c9fa38775a81d53ac0484fa9c98076a0c7d1 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 11 Feb 2020 17:10:25 -0500 Subject: Implement SignTransaction in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 67063ad23..1eb9dc4d7 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1943,7 +1943,16 @@ bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map& coins, int sighash, std::map& input_errors) const { - return false; + std::unique_ptr keys = MakeUnique(); + for (const auto& coin_pair : coins) { + std::unique_ptr coin_keys = GetSigningProvider(coin_pair.second.out.scriptPubKey, true); + if (!coin_keys) { + continue; + } + *keys = Merge(*keys, *coin_keys); + } + + return ::SignTransaction(tx, keys.get(), coins, sighash, input_errors); } SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const -- cgit v1.2.3 From 84b4978c02102171775c77a45f6ec198930f0a88 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 11 Feb 2020 17:36:44 -0500 Subject: Implement SignMessage for descriptor wallets --- src/wallet/scriptpubkeyman.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 1eb9dc4d7..b5272be83 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1957,7 +1957,21 @@ bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const s SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { - return SigningResult::SIGNING_FAILED; + std::unique_ptr keys = GetSigningProvider(GetScriptForDestination(pkhash), true); + if (!keys) { + return SigningResult::PRIVATE_KEY_NOT_AVAILABLE; + } + + CKeyID key_id(pkhash); + CKey key; + if (!keys->GetKey(key_id, key)) { + return SigningResult::PRIVATE_KEY_NOT_AVAILABLE; + } + + if (!MessageSign(key, message, str_sig)) { + return SigningResult::SIGNING_FAILED; + } + return SigningResult::OK; } TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, int sighash_type, bool sign, bool bip32derivs) const -- cgit v1.2.3 From 72a9540df96ffdb94f039b9c14eaacdc7d961196 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 11 Feb 2020 17:39:43 -0500 Subject: 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. --- src/wallet/scriptpubkeyman.cpp | 66 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index b5272be83..0c1da43b4 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1974,9 +1974,71 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, return SigningResult::OK; } -TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, int sighash_type, bool sign, bool bip32derivs) const +TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, int sighash_type, bool sign, bool bip32derivs) const { - return TransactionError::INVALID_PSBT; + for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { + const CTxIn& txin = psbtx.tx->vin[i]; + PSBTInput& input = psbtx.inputs.at(i); + + if (PSBTInputSigned(input)) { + continue; + } + + // Verify input looks sane. This will check that we have at most one uxto, witness or non-witness. + if (!input.IsSane()) { + return TransactionError::INVALID_PSBT; + } + + // Get the Sighash type + if (sign && input.sighash_type > 0 && input.sighash_type != sighash_type) { + return TransactionError::SIGHASH_MISMATCH; + } + + // Get the scriptPubKey to know which SigningProvider to use + CScript script; + if (!input.witness_utxo.IsNull()) { + script = input.witness_utxo.scriptPubKey; + } else if (input.non_witness_utxo) { + if (txin.prevout.n >= input.non_witness_utxo->vout.size()) { + return TransactionError::MISSING_INPUTS; + } + script = input.non_witness_utxo->vout[txin.prevout.n].scriptPubKey; + } else { + // There's no UTXO so we can just skip this now + continue; + } + SignatureData sigdata; + input.FillSignatureData(sigdata); + + std::unique_ptr keys = MakeUnique(); + std::unique_ptr script_keys = GetSigningProvider(script, sign); + if (script_keys) { + *keys = Merge(*keys, *script_keys); + } else { + // Maybe there are pubkeys listed that we can sign for + script_keys = MakeUnique(); + for (const auto& pk_pair : input.hd_keypaths) { + const CPubKey& pubkey = pk_pair.first; + std::unique_ptr pk_keys = GetSigningProvider(pubkey); + if (pk_keys) { + *keys = Merge(*keys, *pk_keys); + } + } + } + + SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, sighash_type); + } + + // Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change + for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) { + std::unique_ptr keys = GetSolvingProvider(psbtx.tx->vout.at(i).scriptPubKey); + if (!keys) { + continue; + } + UpdatePSBTOutput(HidingSigningProvider(keys.get(), true, !bip32derivs), psbtx, i); + } + + return TransactionError::OK; } const CKeyMetadata* DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const -- cgit v1.2.3 From 8b9603bd0b443e2f7984eb72bf2e21cf02af0bcb Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 6 Nov 2019 20:55:34 -0500 Subject: Change GetMetadata to use unique_ptr --- src/wallet/scriptpubkeyman.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 0c1da43b4..e10c248c6 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -568,7 +568,7 @@ TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psb return TransactionError::OK; } -const CKeyMetadata* LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const +std::unique_ptr LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const { LOCK(cs_KeyStore); @@ -576,14 +576,14 @@ const CKeyMetadata* LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& des if (!key_id.IsNull()) { auto it = mapKeyMetadata.find(key_id); if (it != mapKeyMetadata.end()) { - return &it->second; + return MakeUnique(it->second); } } CScript scriptPubKey = GetScriptForDestination(dest); auto it = m_script_metadata.find(CScriptID(scriptPubKey)); if (it != m_script_metadata.end()) { - return &it->second; + return MakeUnique(it->second); } return nullptr; @@ -2041,7 +2041,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& return TransactionError::OK; } -const CKeyMetadata* DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const +std::unique_ptr DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const { return nullptr; } -- cgit v1.2.3 From b713baa75a62335ab9c0eed9ef76a95bfec30668 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 6 Nov 2019 21:20:39 -0500 Subject: Implement GetMetadata in DescriptorScriptPubKeyMan --- src/wallet/scriptpubkeyman.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index e10c248c6..6aeea700b 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -2043,6 +2043,19 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& std::unique_ptr DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const { + std::unique_ptr provider = GetSigningProvider(GetScriptForDestination(dest)); + if (provider) { + KeyOriginInfo orig; + CKeyID key_id = GetKeyForDestination(*provider, dest); + if (provider->GetKeyOrigin(key_id, orig)) { + LOCK(cs_desc_man); + std::unique_ptr meta = MakeUnique(); + meta->key_origin = orig; + meta->has_key_origin = true; + meta->nCreateTime = m_wallet_descriptor.creation_time; + return meta; + } + } return nullptr; } -- cgit v1.2.3 From f193ea889ddb53d9a5c47647966681d525e38368 Mon Sep 17 00:00:00 2001 From: Hugo Nguyen Date: Thu, 1 Aug 2019 15:08:47 -0700 Subject: add importdescriptors RPC and tests for native descriptor wallets Co-authored-by: Andrew Chow --- src/wallet/scriptpubkeyman.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'src/wallet/scriptpubkeyman.cpp') diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 6aeea700b..ecb95d599 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1745,6 +1745,15 @@ void DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script) } } +void DescriptorScriptPubKeyMan::AddDescriptorKey(const CKey& key, const CPubKey &pubkey) +{ + LOCK(cs_desc_man); + WalletBatch batch(m_storage.GetDatabase()); + if (!AddDescriptorKeyWithDB(batch, key, pubkey)) { + throw std::runtime_error(std::string(__func__) + ": writing descriptor private key failed"); + } +} + bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey) { AssertLockHeld(cs_desc_man); @@ -2121,3 +2130,35 @@ bool DescriptorScriptPubKeyMan::AddCryptedKey(const CKeyID& key_id, const CPubKe m_map_crypted_keys[key_id] = make_pair(pubkey, crypted_key); return true; } + +bool DescriptorScriptPubKeyMan::HasWalletDescriptor(const WalletDescriptor& desc) const +{ + LOCK(cs_desc_man); + return m_wallet_descriptor.descriptor != nullptr && desc.descriptor != nullptr && m_wallet_descriptor.descriptor->ToString() == desc.descriptor->ToString(); +} + +void DescriptorScriptPubKeyMan::WriteDescriptor() +{ + LOCK(cs_desc_man); + WalletBatch batch(m_storage.GetDatabase()); + if (!batch.WriteDescriptor(GetID(), m_wallet_descriptor)) { + throw std::runtime_error(std::string(__func__) + ": writing descriptor failed"); + } +} + +const WalletDescriptor DescriptorScriptPubKeyMan::GetWalletDescriptor() const +{ + return m_wallet_descriptor; +} + +const std::vector DescriptorScriptPubKeyMan::GetScriptPubKeys() const +{ + LOCK(cs_desc_man); + std::vector script_pub_keys; + script_pub_keys.reserve(m_map_script_pub_keys.size()); + + for (auto const& script_pub_key: m_map_script_pub_keys) { + script_pub_keys.push_back(script_pub_key.first); + } + return script_pub_keys; +} -- cgit v1.2.3