aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/scriptpubkeyman.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/scriptpubkeyman.cpp')
-rw-r--r--src/wallet/scriptpubkeyman.cpp128
1 files changed, 63 insertions, 65 deletions
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 8f0b72c2b0..b42275fe4b 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -11,6 +11,7 @@
#include <script/sign.h>
#include <script/solver.h>
#include <util/bip32.h>
+#include <util/check.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
@@ -96,6 +97,7 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const LegacyScriptPubKeyMan&
//! @param recurse_scripthash whether to recurse into nested p2sh and p2wsh
//! scripts or simply treat any script that has been
//! stored in the keystore as spendable
+// NOLINTNEXTLINE(misc-no-recursion)
IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true)
{
IsMineResult ret = IsMineResult::NO;
@@ -225,7 +227,7 @@ isminetype LegacyScriptPubKeyMan::IsMine(const CScript& script) const
assert(false);
}
-bool LegacyScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys)
+bool LegacyScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key)
{
{
LOCK(cs_KeyStore);
@@ -258,7 +260,7 @@ bool LegacyScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key
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))
+ if (keyFail || !keyPass)
return false;
fDecryptionThoroughlyChecked = true;
}
@@ -280,7 +282,7 @@ bool LegacyScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, WalletBat
{
const CKey &key = mKey.second;
CPubKey vchPubKey = key.GetPubKey();
- CKeyingMaterial vchSecret(key.begin(), key.end());
+ CKeyingMaterial vchSecret{UCharCast(key.begin()), UCharCast(key.end())};
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(master_key, vchSecret, vchPubKey.GetHash(), vchCryptedSecret)) {
encrypted_batch = nullptr;
@@ -652,8 +654,6 @@ TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psb
// There's no UTXO so we can just skip this now
continue;
}
- SignatureData sigdata;
- input.FillSignatureData(sigdata);
SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
bool signed_one = PSBTInputSigned(input);
@@ -810,8 +810,10 @@ bool LegacyScriptPubKeyMan::AddKeyPubKeyInner(const CKey& key, const CPubKey &pu
}
std::vector<unsigned char> vchCryptedSecret;
- CKeyingMaterial vchSecret(key.begin(), key.end());
- if (!EncryptSecret(m_storage.GetEncryptionKey(), vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
+ CKeyingMaterial vchSecret{UCharCast(key.begin()), UCharCast(key.end())};
+ if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
+ return EncryptSecret(encryption_key, vchSecret, pubkey.GetHash(), vchCryptedSecret);
+ })) {
return false;
}
@@ -997,7 +999,9 @@ bool LegacyScriptPubKeyMan::GetKey(const CKeyID &address, CKey& keyOut) const
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- return DecryptKey(m_storage.GetEncryptionKey(), vchCryptedSecret, vchPubKey, keyOut);
+ return m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
+ return DecryptKey(encryption_key, vchCryptedSecret, vchPubKey, keyOut);
+ });
}
return false;
}
@@ -1286,6 +1290,9 @@ bool LegacyScriptPubKeyMan::TopUp(unsigned int kpSize)
}
if (!batch.TxnCommit()) throw std::runtime_error(strprintf("Error during keypool top up. Cannot commit changes for wallet %s", m_storage.GetDisplayName()));
NotifyCanGetAddressesChanged();
+ // Note: Unlike with DescriptorSPKM, LegacySPKM does not need to call
+ // m_storage.TopUpCallback() as we do not know what new scripts the LegacySPKM is
+ // watching for. CWallet's scriptPubKey cache is not used for LegacySPKMs.
return true;
}
@@ -2045,7 +2052,7 @@ isminetype DescriptorScriptPubKeyMan::IsMine(const CScript& script) const
return ISMINE_NO;
}
-bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys)
+bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key)
{
LOCK(cs_desc_man);
if (!m_map_keys.empty()) {
@@ -2070,7 +2077,7 @@ bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master
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)) {
+ if (keyFail || !keyPass) {
return false;
}
m_decryption_thoroughly_checked = true;
@@ -2088,7 +2095,7 @@ bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, Walle
{
const CKey &key = key_in.second;
CPubKey pubkey = key.GetPubKey();
- CKeyingMaterial secret(key.begin(), key.end());
+ CKeyingMaterial secret{UCharCast(key.begin()), UCharCast(key.end())};
std::vector<unsigned char> crypted_secret;
if (!EncryptSecret(master_key, secret, pubkey.GetHash(), crypted_secret)) {
return false;
@@ -2128,7 +2135,9 @@ std::map<CKeyID, CKey> DescriptorScriptPubKeyMan::GetKeys() const
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);
+ m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
+ return DecryptKey(encryption_key, crypted_secret, pubkey, key);
+ });
keys[pubkey.GetID()] = key;
}
return keys;
@@ -2136,6 +2145,36 @@ std::map<CKeyID, CKey> DescriptorScriptPubKeyMan::GetKeys() const
return m_map_keys;
}
+bool DescriptorScriptPubKeyMan::HasPrivKey(const CKeyID& keyid) const
+{
+ AssertLockHeld(cs_desc_man);
+ return m_map_keys.contains(keyid) || m_map_crypted_keys.contains(keyid);
+}
+
+std::optional<CKey> DescriptorScriptPubKeyMan::GetKey(const CKeyID& keyid) const
+{
+ AssertLockHeld(cs_desc_man);
+ if (m_storage.HasEncryptionKeys() && !m_storage.IsLocked()) {
+ const auto& it = m_map_crypted_keys.find(keyid);
+ if (it == m_map_crypted_keys.end()) {
+ return std::nullopt;
+ }
+ const std::vector<unsigned char>& crypted_secret = it->second.second;
+ CKey key;
+ if (!Assume(m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
+ return DecryptKey(encryption_key, crypted_secret, it->second.first, key);
+ }))) {
+ return std::nullopt;
+ }
+ return key;
+ }
+ const auto& it = m_map_keys.find(keyid);
+ if (it == m_map_keys.end()) {
+ return std::nullopt;
+ }
+ return it->second;
+}
+
bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
{
WalletBatch batch(m_storage.GetDatabase());
@@ -2148,6 +2187,7 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int size)
{
LOCK(cs_desc_man);
+ std::set<CScript> new_spks;
unsigned int target_size;
if (size > 0) {
target_size = size;
@@ -2178,6 +2218,7 @@ bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int siz
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
+ new_spks.insert(scripts_temp.begin(), scripts_temp.end());
for (const CScript& script : scripts_temp) {
m_map_script_pub_keys[script] = i;
}
@@ -2203,6 +2244,7 @@ bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int siz
// 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);
+ m_storage.TopUpCallback(new_spks, this);
NotifyCanGetAddressesChanged();
return true;
}
@@ -2261,8 +2303,10 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
}
std::vector<unsigned char> crypted_secret;
- CKeyingMaterial secret(key.begin(), key.end());
- if (!EncryptSecret(m_storage.GetEncryptionKey(), secret, pubkey.GetHash(), crypted_secret)) {
+ CKeyingMaterial secret{UCharCast(key.begin()), UCharCast(key.end())};
+ if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
+ return EncryptSecret(encryption_key, secret, pubkey.GetHash(), crypted_secret);
+ })) {
return false;
}
@@ -2284,55 +2328,7 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(WalletBatch& batch, co
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 (addr_type) {
- case OutputType::LEGACY: {
- desc_prefix = "pkh(" + xpub + "/44h";
- break;
- }
- case OutputType::P2SH_SEGWIT: {
- desc_prefix = "sh(wpkh(" + xpub + "/49h";
- desc_suffix += ")";
- break;
- }
- case OutputType::BECH32: {
- desc_prefix = "wpkh(" + xpub + "/84h";
- break;
- }
- case OutputType::BECH32M: {
- desc_prefix = "tr(" + xpub + "/86h";
- break;
- }
- case OutputType::UNKNOWN: {
- // We should never have a DescriptorScriptPubKeyMan for an UNKNOWN OutputType,
- // so if we get to this point something is wrong
- assert(false);
- }
- } // no default case, so the compiler can warn about missing cases
- assert(!desc_prefix.empty());
-
- // Mainnet derives at 0', testnet and regtest derive at 1'
- if (Params().IsTestChain()) {
- desc_prefix += "/1h";
- } else {
- desc_prefix += "/0h";
- }
-
- std::string internal_path = internal ? "/1" : "/0";
- std::string desc_str = desc_prefix + "/0h" + internal_path + desc_suffix;
-
- // Make the descriptor
- FlatSigningProvider keys;
- std::string error;
- std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
- WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
- m_wallet_descriptor = w_desc;
+ m_wallet_descriptor = GenerateWalletDescriptor(master_key.Neuter(), addr_type, internal);
// Store the master private key, and descriptor
if (!AddDescriptorKeyWithDB(batch, master_key.key, master_key.key.GetPubKey())) {
@@ -2520,8 +2516,6 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
// There's no UTXO so we can just skip this now
continue;
}
- SignatureData sigdata;
- input.FillSignatureData(sigdata);
std::unique_ptr<FlatSigningProvider> keys = std::make_unique<FlatSigningProvider>();
std::unique_ptr<FlatSigningProvider> script_keys = GetSigningProvider(script, /*include_private=*/sign);
@@ -2616,6 +2610,7 @@ uint256 DescriptorScriptPubKeyMan::GetID() const
void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
{
LOCK(cs_desc_man);
+ std::set<CScript> new_spks;
m_wallet_descriptor.cache = cache;
for (int32_t i = m_wallet_descriptor.range_start; i < m_wallet_descriptor.range_end; ++i) {
FlatSigningProvider out_keys;
@@ -2624,6 +2619,7 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
throw std::runtime_error("Error: Unable to expand wallet descriptor from cache");
}
// Add all of the scriptPubKeys to the scriptPubKey set
+ new_spks.insert(scripts_temp.begin(), scripts_temp.end());
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]));
@@ -2641,6 +2637,8 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
}
m_max_cached_index++;
}
+ // Make sure the wallet knows about our new spks
+ m_storage.TopUpCallback(new_spks, this);
}
bool DescriptorScriptPubKeyMan::AddKey(const CKeyID& key_id, const CKey& key)