wallet: Delete LegacySPKM

Deletes LegacyScriptPubKeyMan and related tests

Best reviewed with `git diff --patience` or `git diff --histogram`
This commit is contained in:
Ava Chow 2024-01-05 18:42:23 -05:00
parent 8ede6dea0c
commit 83af1a3cca
22 changed files with 25 additions and 2427 deletions

View File

@ -107,9 +107,6 @@ public:
//! Return whether wallet has private key.
virtual bool isSpendable(const CTxDestination& dest) = 0;
//! Return whether wallet has watch only keys.
virtual bool haveWatchOnly() = 0;
//! Add or update address.
virtual bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<wallet::AddressPurpose>& purpose) = 0;
@ -282,9 +279,6 @@ public:
// Remove wallet.
virtual void remove() = 0;
//! Return whether is a legacy wallet
virtual bool isLegacy() = 0;
//! Register handler for unload message.
using UnloadFn = std::function<void()>;
virtual std::unique_ptr<Handler> handleUnload(UnloadFn fn) = 0;

View File

@ -195,28 +195,10 @@ OverviewPage::~OverviewPage()
void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
{
BitcoinUnit unit = walletModel->getOptionsModel()->getDisplayUnit();
if (walletModel->wallet().isLegacy()) {
if (walletModel->wallet().privateKeysDisabled()) {
ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
} else {
ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelWatchAvailable->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelWatchPending->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelWatchImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelWatchTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
}
} else {
ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
}
ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
// for the non-mining users
bool showImmature = balances.immature_balance != 0;
@ -281,11 +263,7 @@ void OverviewPage::setWalletModel(WalletModel *model)
connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &OverviewPage::updateDisplayUnit);
interfaces::Wallet& wallet = model->wallet();
updateWatchOnlyLabels(wallet.haveWatchOnly() && !wallet.privateKeysDisabled());
connect(model, &WalletModel::notifyWatchonlyChanged, [this](bool showWatchOnly) {
updateWatchOnlyLabels(showWatchOnly && !walletModel->wallet().privateKeysDisabled());
});
updateWatchOnlyLabels(false);
}
// update the display unit, to not use the default ("BTC")

View File

@ -711,9 +711,6 @@ void SendCoinsDialog::setBalance(const interfaces::WalletBalances& balances)
CAmount balance = balances.balance;
if (model->wallet().hasExternalSigner()) {
ui->labelBalanceName->setText(tr("External balance:"));
} else if (model->wallet().isLegacy() && model->wallet().privateKeysDisabled()) {
balance = balances.watch_only_balance;
ui->labelBalanceName->setText(tr("Watch-only balance:"));
}
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), balance));
}

View File

@ -241,8 +241,8 @@ void TransactionView::setModel(WalletModel *_model)
}
}
// show/hide column Watch-only
updateWatchOnlyColumn(_model->wallet().haveWatchOnly());
// hide column Watch-only
updateWatchOnlyColumn(false);
// Watch-only signal
connect(_model, &WalletModel::notifyWatchonlyChanged, this, &TransactionView::updateWatchOnlyColumn);
@ -368,8 +368,6 @@ void TransactionView::exportClicked()
// name, column, role
writer.setModel(transactionProxyModel);
writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
if (model->wallet().haveWatchOnly())
writer.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly);
writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);

View File

@ -45,7 +45,7 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel
optionsModel(client_model.getOptionsModel()),
timer(new QTimer(this))
{
fHaveWatchOnly = m_wallet->haveWatchOnly();
fHaveWatchOnly = false;
addressTableModel = new AddressTableModel(this);
transactionTableModel = new TransactionTableModel(platformStyle, this);
recentRequestsTableModel = new RecentRequestsTableModel(this);

View File

@ -48,7 +48,7 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
if (require_mine) {
// check that original tx consists entirely of our inputs
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
isminefilter filter = ISMINE_SPENDABLE;
if (!AllInputsMine(wallet, *wtx.tx, filter)) {
errors.emplace_back(Untranslated("Transaction contains inputs that don't belong to this wallet"));
return feebumper::Result::WALLET_ERROR;

View File

@ -175,14 +175,6 @@ public:
LOCK(m_wallet->cs_wallet);
return m_wallet->IsMine(dest) & ISMINE_SPENDABLE;
}
bool haveWatchOnly() override
{
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
if (spk_man) {
return spk_man->HaveWatchOnly();
}
return false;
};
bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<AddressPurpose>& purpose) override
{
return m_wallet->SetAddressBook(dest, name, purpose);
@ -407,12 +399,7 @@ public:
result.balance = bal.m_mine_trusted;
result.unconfirmed_balance = bal.m_mine_untrusted_pending;
result.immature_balance = bal.m_mine_immature;
result.have_watch_only = haveWatchOnly();
if (result.have_watch_only) {
result.watch_only_balance = bal.m_watchonly_trusted;
result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending;
result.immature_watch_only_balance = bal.m_watchonly_immature;
}
result.have_watch_only = false;
return result;
}
bool tryGetBalances(WalletBalances& balances, uint256& block_hash) override
@ -516,7 +503,6 @@ public:
bool hasExternalSigner() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER); }
bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); }
bool taprootEnabled() override {
if (m_wallet->IsLegacy()) return false;
auto spk_man = m_wallet->GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/false);
return spk_man != nullptr;
}
@ -526,7 +512,6 @@ public:
{
RemoveWallet(m_context, m_wallet, /*load_on_start=*/false);
}
bool isLegacy() override { return m_wallet->IsLegacy(); }
std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
{
return MakeSignalHandler(m_wallet->NotifyUnload.connect(fn));

View File

@ -54,8 +54,6 @@ RPCHelpMan getnewaddress()
std::optional<OutputType> parsed = ParseOutputType(request.params[1].get_str());
if (!parsed) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
} else if (parsed.value() == OutputType::BECH32M && pwallet->GetLegacyScriptPubKeyMan()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy wallets cannot provide bech32m addresses");
}
output_type = parsed.value();
}
@ -101,8 +99,6 @@ RPCHelpMan getrawchangeaddress()
std::optional<OutputType> parsed = ParseOutputType(request.params[0].get_str());
if (!parsed) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
} else if (parsed.value() == OutputType::BECH32M && pwallet->GetLegacyScriptPubKeyMan()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy wallets cannot provide bech32m addresses");
}
output_type = parsed.value();
}
@ -233,10 +229,6 @@ RPCHelpMan keypoolrefill()
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
if (pwallet->IsLegacy() && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
LOCK(pwallet->cs_wallet);
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool

View File

@ -440,12 +440,6 @@ RPCHelpMan getbalances()
{RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
{RPCResult::Type::STR_AMOUNT, "used", /*optional=*/true, "(only present if avoid_reuse is set) balance from coins sent to addresses that were previously spent from (potentially privacy violating)"},
}},
{RPCResult::Type::OBJ, "watchonly", /*optional=*/true, "watchonly balances (not present if wallet does not watch anything)",
{
{RPCResult::Type::STR_AMOUNT, "trusted", "trusted balance (outputs created by the wallet or confirmed outputs)"},
{RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"},
{RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
}},
RESULT_LAST_PROCESSED_BLOCK,
}
},
@ -479,15 +473,6 @@ RPCHelpMan getbalances()
}
balances.pushKV("mine", std::move(balances_mine));
}
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
if (spk_man && spk_man->HaveWatchOnly()) {
UniValue balances_watchonly{UniValue::VOBJ};
balances_watchonly.pushKV("trusted", ValueFromAmount(bal.m_watchonly_trusted));
balances_watchonly.pushKV("untrusted_pending", ValueFromAmount(bal.m_watchonly_untrusted_pending));
balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
balances.pushKV("watchonly", std::move(balances_watchonly));
}
AppendLastProcessedBlock(balances, wallet);
return balances;
},

View File

@ -60,7 +60,6 @@ static RPCHelpMan getwalletinfo()
{RPCResult::Type::NUM, "keypoolsize_hd_internal", /*optional=*/true, "how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"},
{RPCResult::Type::NUM_TIME, "unlocked_until", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},
{RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kvB"},
{RPCResult::Type::STR_HEX, "hdseedid", /*optional=*/true, "the Hash160 of the HD seed (only present when HD is enabled)"},
{RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
{RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
{RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
@ -107,14 +106,6 @@ static RPCHelpMan getwalletinfo()
}
obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
if (spk_man) {
CKeyID seed_id = spk_man->GetHDChain().seed_id;
if (!seed_id.IsNull()) {
obj.pushKV("hdseedid", seed_id.GetHex());
}
}
if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
}

File diff suppressed because it is too large Load Diff

View File

@ -65,99 +65,6 @@ static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
std::vector<CKeyID> GetAffectedKeys(const CScript& spk, const SigningProvider& provider);
/** A key from a CWallet's keypool
*
* The wallet holds one (for pre HD-split wallets) or several keypools. These
* are sets of keys that have not yet been used to provide addresses or receive
* change.
*
* The Bitcoin Core wallet was originally a collection of unrelated private
* keys with their associated addresses. If a non-HD wallet generated a
* key/address, gave that address out and then restored a backup from before
* that key's generation, then any funds sent to that address would be
* lost definitively.
*
* The keypool was implemented to avoid this scenario (commit: 10384941). The
* wallet would generate a set of keys (100 by default). When a new public key
* was required, either to give out as an address or to use in a change output,
* it would be drawn from the keypool. The keypool would then be topped up to
* maintain 100 keys. This ensured that as long as the wallet hadn't used more
* than 100 keys since the previous backup, all funds would be safe, since a
* restored wallet would be able to scan for all owned addresses.
*
* A keypool also allowed encrypted wallets to give out addresses without
* having to be decrypted to generate a new private key.
*
* With the introduction of HD wallets (commit: f1902510), the keypool
* essentially became an address look-ahead pool. Restoring old backups can no
* longer definitively lose funds as long as the addresses used were from the
* wallet's HD seed (since all private keys can be rederived from the seed).
* However, if many addresses were used since the backup, then the wallet may
* not know how far ahead in the HD chain to look for its addresses. The
* keypool is used to implement a 'gap limit'. The keypool maintains a set of
* keys (by default 1000) ahead of the last used key and scans for the
* addresses of those keys. This avoids the risk of not seeing transactions
* involving the wallet's addresses, or of re-using the same address.
* In the unlikely case where none of the addresses in the `gap limit` are
* used on-chain, the look-ahead will not be incremented to keep
* a constant size and addresses beyond this range will not be detected by an
* old backup. For this reason, it is not recommended to decrease keypool size
* lower than default value.
*
* The HD-split wallet feature added a second keypool (commit: 02592f4c). There
* is an external keypool (for addresses to hand out) and an internal keypool
* (for change addresses).
*
* Keypool keys are stored in the wallet/keystore's keymap. The keypool data is
* stored as sets of indexes in the wallet (setInternalKeyPool,
* setExternalKeyPool and set_pre_split_keypool), and a map from the key to the
* index (m_pool_key_to_index). The CKeyPool object is used to
* serialize/deserialize the pool data to/from the database.
*/
class CKeyPool
{
public:
//! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB
int64_t nTime;
//! The public key
CPubKey vchPubKey;
//! Whether this keypool entry is in the internal keypool (for change outputs)
bool fInternal;
//! Whether this key was generated for a keypool before the wallet was upgraded to HD-split
bool m_pre_split;
CKeyPool();
CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
template<typename Stream>
void Serialize(Stream& s) const
{
s << int{259900}; // Unused field, writes the highest client version ever written
s << nTime << vchPubKey << fInternal << m_pre_split;
}
template<typename Stream>
void Unserialize(Stream& s)
{
s >> int{}; // Discard unused field
s >> nTime >> vchPubKey;
try {
s >> fInternal;
} catch (std::ios_base::failure&) {
/* flag as external address if we can't read the internal boolean
(this will be the case for any wallet before the HD chain split version) */
fInternal = false;
}
try {
s >> m_pre_split;
} catch (std::ios_base::failure&) {
/* flag as postsplit address if we can't read the m_pre_split boolean
(this will be the case for any wallet that upgrades to HD chain split) */
m_pre_split = false;
}
}
};
struct WalletDestination
{
CTxDestination dest;
@ -186,7 +93,7 @@ public:
virtual bool CheckDecryptionKey(const CKeyingMaterial& master_key) { return false; }
virtual bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) { return false; }
virtual util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) { return util::Error{Untranslated("Not supported")}; }
virtual util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index) { return util::Error{Untranslated("Not supported")}; }
virtual void KeepDestination(int64_t index, const OutputType& type) {}
virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) {}
@ -277,8 +184,6 @@ static const std::unordered_set<OutputType> LEGACY_OUTPUT_TYPES {
OutputType::BECH32,
};
class DescriptorScriptPubKeyMan;
// Manages the data for a LegacyScriptPubKeyMan.
// This is the minimum necessary to load a legacy wallet so that it can be migrated.
class LegacyDataSPKM : public ScriptPubKeyMan, public FillableSigningProvider
@ -331,12 +236,6 @@ public:
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_KeyStore);
std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_KeyStore);
std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_KeyStore);
int64_t m_max_keypool_index GUARDED_BY(cs_KeyStore) = 0;
std::map<CKeyID, int64_t> m_pool_key_to_index;
//! Load metadata (used by LoadWallet)
virtual void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata);
virtual void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata);
@ -357,8 +256,6 @@ public:
void LoadHDChain(const CHDChain& chain);
void AddInactiveHDChain(const CHDChain& chain);
const CHDChain& GetHDChain() const { return m_hd_chain; }
//! Load a keypool entry
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool);
//! Fetches a pubkey from mapWatchKeys if it exists there
bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const;
@ -377,199 +274,6 @@ public:
bool DeleteRecordsWithDB(WalletBatch& batch);
};
// Implements the full legacy wallet behavior
class LegacyScriptPubKeyMan : public LegacyDataSPKM
{
private:
WalletBatch *encrypted_batch GUARDED_BY(cs_KeyStore) = nullptr;
// By default, do not scan any block until keys/scripts are generated/imported
int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = UNKNOWN_TIME;
//! Number of pre-generated keys/scripts (part of the look-ahead process, used to detect payments)
int64_t m_keypool_size GUARDED_BY(cs_KeyStore){DEFAULT_KEYPOOL_SIZE};
bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey) override;
/**
* Private version of AddWatchOnly method which does not accept a
* timestamp, and which will reset the wallet's nTimeFirstKey value to 1 if
* the watch key did not previously have a timestamp associated with it.
* Because this is an inherited virtual method, it is accessible despite
* being marked private, but it is marked private anyway to encourage use
* of the other AddWatchOnly which accepts a timestamp and sets
* nTimeFirstKey more intelligently for more efficient rescans.
*/
bool AddWatchOnly(const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
//! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
//! Adds a key to the store, and saves it to disk.
bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
//! Adds a script to the store and saves it to disk
bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
/** Add a KeyOriginInfo to the wallet */
bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
/* HD derive new child key (on internal or external chain) */
void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
// Tracks keypool indexes to CKeyIDs of keys that have been taken out of the keypool but may be returned to it
std::map<int64_t, CKeyID> m_index_to_reserved_key;
//! Fetches a key from the keypool
bool GetKeyFromPool(CPubKey &key, const OutputType type);
/**
* Reserves a key from the keypool and sets nIndex to its index
*
* @param[out] nIndex the index of the key in keypool
* @param[out] keypool the keypool the key was drawn from, which could be the
* the pre-split pool if present, or the internal or external pool
* @param fRequestedInternal true if the caller would like the key drawn
* from the internal keypool, false if external is preferred
*
* @return true if succeeded, false if failed due to empty keypool
* @throws std::runtime_error if keypool read failed, key was invalid,
* was not found in the wallet, or was misclassified in the internal
* or external keypool
*/
bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
/**
* Like TopUp() but adds keys for inactive HD chains.
* Ensures that there are at least -keypool number of keys derived after the given index.
*
* @param seed_id the CKeyID for the HD seed.
* @param index the index to start generating keys from
* @param internal whether the internal chain should be used. true for internal chain, false for external chain.
*
* @return true if seed was found and keys were derived. false if unable to derive seeds
*/
bool TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal);
bool TopUpChain(WalletBatch& batch, CHDChain& chain, unsigned int size);
public:
LegacyScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size) : LegacyDataSPKM(storage), m_keypool_size(keypool_size) {}
util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override;
void KeepDestination(int64_t index, const OutputType& type) override;
void ReturnDestination(int64_t index, bool internal, const CTxDestination&) override;
bool TopUp(unsigned int size = 0) override;
std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) override;
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
void UpgradeKeyMetadata();
bool IsHDEnabled() const override;
bool SetupGeneration(bool force = false) override;
bool Upgrade(int prev_version, int new_version, bilingual_str& error) override;
bool HavePrivateKeys() const override;
bool HaveCryptedKeys() const override;
void RewriteDB() override;
std::optional<int64_t> GetOldestKeyPoolTime() const override;
size_t KeypoolCountExternalKeys() const;
unsigned int GetKeyPoolSize() const override;
int64_t GetTimeFirstKey() const override;
std::unique_ptr<CKeyMetadata> GetMetadata(const CTxDestination& dest) const override;
bool CanGetAddresses(bool internal = false) const override;
bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override;
SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override;
std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
uint256 GetID() const override;
//! Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
//! Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
//! Load metadata (used by LoadWallet)
void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) override;
void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) override;
//! Generate a new key
CPubKey GenerateNewKey(WalletBatch& batch, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
/* Set the HD chain model (chain child index counters) and writes it to the database */
void AddHDChain(const CHDChain& chain);
//! Remove a watch only script from the keystore
bool RemoveWatchOnly(const CScript &dest);
bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
/* SigningProvider overrides */
bool AddCScript(const CScript& redeemScript) override;
bool NewKeyPool();
void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
bool ImportPubKeys(const std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
bool ImportScriptPubKeys(const std::set<CScript>& script_pub_keys, const bool have_solving_data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
/* Returns true if the wallet can generate new keys */
bool CanGenerateKeys() const;
/* Generates a new HD seed (will not be activated) */
CPubKey GenerateNewSeed();
/* Derives a new HD seed (will not be activated) */
CPubKey DeriveNewSeed(const CKey& key);
/* Set the current HD seed (will reset the chain child index counters)
Sets the seed's version based on the current wallet version (so the
caller must ensure the current wallet version is correct before calling
this function). */
void SetHDSeed(const CPubKey& key);
/**
* Explicitly make the wallet learn the related scripts for outputs to the
* given key. This is purely to make the wallet file compatible with older
* software, as FillableSigningProvider automatically does this implicitly for all
* keys now.
*/
void LearnRelatedScripts(const CPubKey& key, OutputType);
/**
* Same as LearnRelatedScripts, but when the OutputType is not known (and could
* be anything).
*/
void LearnAllRelatedScripts(const CPubKey& key);
/**
* Marks all keys in the keypool up to and including the provided key as used.
*
* @param keypool_id determines the last key to mark as used
*
* @return All affected keys
*/
std::vector<CKeyPool> MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
std::set<CKeyID> GetKeys() const override;
};
/** Wraps a LegacyScriptPubKeyMan so that it can be returned in a new unique_ptr. Does not provide privkeys */
class LegacySigningProvider : public SigningProvider
{
@ -644,7 +348,7 @@ public:
bool CheckDecryptionKey(const CKeyingMaterial& master_key) override;
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override;
util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index) 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

View File

@ -508,8 +508,6 @@ std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet)
std::map<CTxDestination, std::vector<COutput>> result;
CCoinControl coin_control;
// Include watch-only for LegacyScriptPubKeyMan wallets without private keys
coin_control.fAllowWatchOnly = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
CoinFilterParams coins_params;
coins_params.only_spendable = false;
coins_params.skip_locked = false;

View File

@ -36,25 +36,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
CScript scriptPubKey;
isminetype result;
// P2PK compressed - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
// Keystore does not have key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2PK compressed - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -67,25 +48,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PK uncompressed - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
// Keystore does not have key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2PK uncompressed - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -98,25 +60,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PKH compressed - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
// Keystore does not have key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2PKH compressed - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -129,25 +72,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PKH uncompressed - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
// Keystore does not have key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2PKH uncompressed - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -160,33 +84,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2SH - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore does not have redeemScript or key
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has redeemScript but no key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has redeemScript and key
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2SH - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -200,25 +97,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// (P2PKH inside) P2SH inside P2SH (invalid) - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript_inner));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// (P2PKH inside) P2SH inside P2SH (invalid) - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -228,25 +106,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(spk_manager, nullptr);
}
// (P2PKH inside) P2SH inside P2WSH (invalid) - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// (P2PKH inside) P2SH inside P2WSH (invalid) - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -256,23 +115,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(spk_manager, nullptr);
}
// P2WPKH inside P2WSH (invalid) - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// P2WPKH inside P2WSH (invalid) - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -282,25 +124,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(spk_manager, nullptr);
}
// (P2PKH inside) P2WSH inside P2WSH (invalid) - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript_inner));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// (P2PKH inside) P2WSH inside P2WSH (invalid) - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -310,22 +133,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(spk_manager, nullptr);
}
// P2WPKH compressed - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
// Keystore implicitly has key and P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2WPKH compressed - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -338,27 +145,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WPKH uncompressed - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey));
// Keystore has key, but no P2SH redeemScript
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has key and P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// P2WPKH uncompressed (invalid) - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -368,41 +154,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(spk_manager, nullptr);
}
// scriptPubKey multisig - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
// Keystore does not have any keys
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has 1/2 keys
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has 2/2 keys
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has 2/2 keys and the script
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// scriptPubKey multisig - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -415,29 +166,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2SH multisig - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore has no redeemScript
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2SH multisig - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -452,35 +180,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WSH multisig with compressed keys - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys and witnessScript, but no P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2WSH multisig with compressed keys - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -495,35 +194,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WSH multisig with uncompressed key - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys and witnessScript, but no P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// P2WSH multisig with uncompressed key (invalid) - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -534,36 +204,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK_EQUAL(spk_manager, nullptr);
}
// P2WSH multisig wrapped in P2SH - Legacy
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
// Keystore has no witnessScript, P2SH redeemScript, or keys
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has witnessScript and P2SH redeemScript, but no keys
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
// Keystore has keys, witnessScript, P2SH redeemScript
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
// P2WSH multisig wrapped in P2SH - Descriptor
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
@ -640,66 +280,6 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// OP_RETURN
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// witness unspendable
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_0 << "aabb"_hex;
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// witness unknown
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_16 << "aabb"_hex;
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
// Nonstandard
{
CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
scriptPubKey.clear();
scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -15,32 +15,6 @@
namespace wallet {
BOOST_FIXTURE_TEST_SUITE(scriptpubkeyman_tests, BasicTestingSetup)
// Test LegacyScriptPubKeyMan::CanProvide behavior, making sure it returns true
// for recognized scripts even when keys may not be available for signing.
BOOST_AUTO_TEST_CASE(CanProvide)
{
// Set up wallet and keyman variables.
CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
LegacyScriptPubKeyMan& keyman = *wallet.GetOrCreateLegacyScriptPubKeyMan();
// Make a 1 of 2 multisig script
std::vector<CKey> keys(2);
std::vector<CPubKey> pubkeys;
for (CKey& key : keys) {
key.MakeNewKey(true);
pubkeys.emplace_back(key.GetPubKey());
}
CScript multisig_script = GetScriptForMultisig(1, pubkeys);
CScript p2sh_script = GetScriptForDestination(ScriptHash(multisig_script));
SignatureData data;
// Verify the p2sh(multisig) script is not recognized until the multisig
// script is added to the keystore to make it solvable
BOOST_CHECK(!keyman.CanProvide(p2sh_script, data));
keyman.AddCScript(multisig_script);
BOOST_CHECK(keyman.CanProvide(p2sh_script, data));
}
BOOST_AUTO_TEST_CASE(DescriptorScriptPubKeyManTests)
{
std::unique_ptr<interfaces::Chain>& chain = m_node.chain;

View File

@ -29,34 +29,5 @@ BOOST_AUTO_TEST_CASE(walletdb_readkeyvalue)
BOOST_CHECK_THROW(ssValue >> dummy, std::ios_base::failure);
}
BOOST_AUTO_TEST_CASE(walletdb_read_write_deadlock)
{
// Exercises a db read write operation that shouldn't deadlock.
for (const DatabaseFormat& db_format : DATABASE_FORMATS) {
// Context setup
DatabaseOptions options;
options.require_format = db_format;
DatabaseStatus status;
bilingual_str error_string;
std::unique_ptr<WalletDatabase> db = MakeDatabase(m_path_root / strprintf("wallet_%d_.dat", db_format).c_str(), options, status, error_string);
BOOST_CHECK_EQUAL(status, DatabaseStatus::SUCCESS);
std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(db)));
wallet->m_keypool_size = 4;
// Create legacy spkm
LOCK(wallet->cs_wallet);
auto legacy_spkm = wallet->GetOrCreateLegacyScriptPubKeyMan();
BOOST_CHECK(!HasLegacyRecords(*wallet));
BOOST_CHECK(legacy_spkm->SetupGeneration(true));
BOOST_CHECK(HasLegacyRecords(*wallet));
wallet->Flush();
// Now delete all records, which performs a read write operation.
BOOST_CHECK(wallet->GetLegacyScriptPubKeyMan()->DeleteRecords());
BOOST_CHECK(!HasLegacyRecords(*wallet));
}
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet

View File

@ -313,9 +313,6 @@ class FastWalletRescanFilter
public:
FastWalletRescanFilter(const CWallet& wallet) : m_wallet(wallet)
{
// fast rescanning via block filters is only supported by descriptor wallets right now
assert(!m_wallet.IsLegacy());
// create initial filter with scripts from all ScriptPubKeyMans
for (auto spkm : m_wallet.GetAllScriptPubKeyMans()) {
auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
@ -548,21 +545,6 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
return &(it->second);
}
void CWallet::UpgradeKeyMetadata()
{
if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
return;
}
auto spk_man = GetLegacyScriptPubKeyMan();
if (!spk_man) {
return;
}
spk_man->UpgradeKeyMetadata();
SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA);
}
void CWallet::UpgradeDescriptorCache()
{
if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) || IsLocked() || IsWalletFlagSet(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED)) {
@ -630,8 +612,6 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
continue; // try another master key
}
if (Unlock(plain_master_key)) {
// Now that we've unlocked, upgrade the key metadata
UpgradeKeyMetadata();
// Now that we've unlocked, upgrade the descriptor cache
UpgradeDescriptorCache();
return true;
@ -895,13 +875,6 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
// If we are using descriptors, make new descriptors with a new seed
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)) {
SetupDescriptorScriptPubKeyMans();
} else if (auto spk_man = GetLegacyScriptPubKeyMan()) {
// if we are using HD, replace the HD seed with a new one
if (spk_man->IsHDEnabled()) {
if (!spk_man->SetupGeneration(true)) {
return false;
}
}
}
Lock();
@ -1059,23 +1032,6 @@ bool CWallet::IsSpentKey(const CScript& scriptPubKey) const
if (IsAddressPreviouslySpent(dest)) {
return true;
}
if (LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan()) {
for (const auto& keyid : GetAffectedKeys(scriptPubKey, *spk_man)) {
WitnessV0KeyHash wpkh_dest(keyid);
if (IsAddressPreviouslySpent(wpkh_dest)) {
return true;
}
ScriptHash sh_wpkh_dest(GetScriptForDestination(wpkh_dest));
if (IsAddressPreviouslySpent(sh_wpkh_dest)) {
return true;
}
PKHash pkh_dest(keyid);
if (IsAddressPreviouslySpent(pkh_dest)) {
return true;
}
}
}
return false;
}
@ -1651,11 +1607,6 @@ isminetype CWallet::IsMine(const CScript& script) const
return res;
}
// Legacy wallet
if (LegacyScriptPubKeyMan* spkm = GetLegacyScriptPubKeyMan()) {
return spkm->IsMine(script);
}
return ISMINE_NO;
}
@ -1788,59 +1739,6 @@ void CWallet::InitWalletFlags(uint64_t flags)
if (!LoadWalletFlags(flags)) assert(false);
}
bool CWallet::ImportScripts(const std::set<CScript> scripts, int64_t timestamp)
{
auto spk_man = GetLegacyScriptPubKeyMan();
if (!spk_man) {
return false;
}
LOCK(spk_man->cs_KeyStore);
return spk_man->ImportScripts(scripts, timestamp);
}
bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp)
{
auto spk_man = GetLegacyScriptPubKeyMan();
if (!spk_man) {
return false;
}
LOCK(spk_man->cs_KeyStore);
return spk_man->ImportPrivKeys(privkey_map, timestamp);
}
bool CWallet::ImportPubKeys(const std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const int64_t timestamp)
{
auto spk_man = GetLegacyScriptPubKeyMan();
if (!spk_man) {
return false;
}
LOCK(spk_man->cs_KeyStore);
return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins, add_keypool, timestamp);
}
bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp)
{
auto spk_man = GetLegacyScriptPubKeyMan();
if (!spk_man) {
return false;
}
LOCK(spk_man->cs_KeyStore);
if (!spk_man->ImportScriptPubKeys(script_pub_keys, have_solving_data, timestamp)) {
return false;
}
if (apply_label) {
WalletBatch batch(GetDatabase());
for (const CScript& script : script_pub_keys) {
CTxDestination dest;
ExtractDestination(script, dest);
if (IsValidDestination(dest)) {
SetAddressBookWithDB(batch, dest, label, AddressPurpose::RECEIVE);
}
}
}
return true;
}
void CWallet::MaybeUpdateBirthTime(int64_t time)
{
int64_t birthtime = m_birth_time.load();
@ -1913,7 +1811,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
ScanResult result;
std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
if (!IsLegacy() && chain().hasBlockFilterIndex(BlockFilterType::BASIC)) fast_rescan_filter = std::make_unique<FastWalletRescanFilter>(*this);
if (chain().hasBlockFilterIndex(BlockFilterType::BASIC)) fast_rescan_filter = std::make_unique<FastWalletRescanFilter>(*this);
WalletLogPrintf("Rescan started from block %s... (%s)\n", start_block.ToString(),
fast_rescan_filter ? "fast variant using block filters" : "slow variant inspecting all blocks");
@ -2182,11 +2080,6 @@ void MaybeResendWalletTxs(WalletContext& context)
}
/** @defgroup Actions
*
* @{
*/
bool CWallet::SignTransaction(CMutableTransaction& tx) const
{
AssertLockHeld(cs_wallet);
@ -2559,11 +2452,6 @@ size_t CWallet::KeypoolCountExternalKeys() const
{
AssertLockHeld(cs_wallet);
auto legacy_spk_man = GetLegacyScriptPubKeyMan();
if (legacy_spk_man) {
return legacy_spk_man->KeypoolCountExternalKeys();
}
unsigned int count = 0;
for (auto spk_man : m_external_spk_managers) {
count += spk_man.second->GetKeyPoolSize();
@ -2695,13 +2583,11 @@ util::Result<CTxDestination> ReserveDestination::GetReservedDestination(bool int
}
if (nIndex == -1) {
CKeyPool keypool;
int64_t index;
auto op_address = m_spk_man->GetReservedDestination(type, internal, index, keypool);
auto op_address = m_spk_man->GetReservedDestination(type, internal, index);
if (!op_address) return op_address;
nIndex = index;
address = *op_address;
fInternal = keypool.fInternal;
}
return address;
}
@ -2786,68 +2672,6 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
}
}
/** @} */ // end of Actions
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
AssertLockHeld(cs_wallet);
mapKeyBirth.clear();
// map in which we'll infer heights of other keys
std::map<CKeyID, const TxStateConfirmed*> mapKeyFirstBlock;
TxStateConfirmed max_confirm{uint256{}, /*height=*/-1, /*index=*/-1};
max_confirm.confirmed_block_height = GetLastBlockHeight() > 144 ? GetLastBlockHeight() - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
CHECK_NONFATAL(chain().findAncestorByHeight(GetLastBlockHash(), max_confirm.confirmed_block_height, FoundBlock().hash(max_confirm.confirmed_block_hash)));
{
LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan();
assert(spk_man != nullptr);
LOCK(spk_man->cs_KeyStore);
// get birth times for keys with metadata
for (const auto& entry : spk_man->mapKeyMetadata) {
if (entry.second.nCreateTime) {
mapKeyBirth[entry.first] = entry.second.nCreateTime;
}
}
// Prepare to infer birth heights for keys without metadata
for (const CKeyID &keyid : spk_man->GetKeys()) {
if (mapKeyBirth.count(keyid) == 0)
mapKeyFirstBlock[keyid] = &max_confirm;
}
// if there are no such keys, we're done
if (mapKeyFirstBlock.empty())
return;
// find first block that affects those keys, if there are any left
for (const auto& entry : mapWallet) {
// iterate over all wallet transactions...
const CWalletTx &wtx = entry.second;
if (auto* conf = wtx.state<TxStateConfirmed>()) {
// ... which are already in a block
for (const CTxOut &txout : wtx.tx->vout) {
// iterate over all their outputs
for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *spk_man)) {
// ... and all their affected keys
auto rit = mapKeyFirstBlock.find(keyid);
if (rit != mapKeyFirstBlock.end() && conf->confirmed_block_height < rit->second->confirmed_block_height) {
rit->second = conf;
}
}
}
}
}
}
// Extract block timestamps for those keys
for (const auto& entry : mapKeyFirstBlock) {
int64_t block_time;
CHECK_NONFATAL(chain().findBlock(entry.second->confirmed_block_hash, FoundBlock().time(block_time)));
mapKeyBirth[entry.first] = block_time - TIMESTAMP_WINDOW; // block times can be 2h off
}
}
/**
* Compute smart timestamp for a transaction being added to the wallet.
*
@ -3465,21 +3289,6 @@ bool CWallet::BackupWallet(const std::string& strDest) const
return GetDatabase().Backup(strDest);
}
CKeyPool::CKeyPool()
{
nTime = GetTime();
fInternal = false;
m_pre_split = false;
}
CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
{
nTime = GetTime();
vchPubKey = vchPubKeyIn;
fInternal = internalIn;
m_pre_split = false;
}
int CWallet::GetTxDepthInMainChain(const CWalletTx& wtx) const
{
AssertLockHeld(cs_wallet);
@ -3616,10 +3425,6 @@ std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script) c
SignatureData sigdata;
Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&script, &sigdata](ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); }));
// Legacy wallet
LegacyScriptPubKeyMan* spkm = GetLegacyScriptPubKeyMan();
if (spkm && spkm->CanProvide(script, sigdata)) spk_mans.insert(spkm);
return spk_mans;
}
@ -3647,10 +3452,6 @@ std::unique_ptr<SigningProvider> CWallet::GetSolvingProvider(const CScript& scri
return it->second.at(0)->GetSolvingProvider(script);
}
// Legacy wallet
LegacyScriptPubKeyMan* spkm = GetLegacyScriptPubKeyMan();
if (spkm && spkm->CanProvide(script, sigdata)) return spkm->GetSolvingProvider(script);
return nullptr;
}
@ -3666,18 +3467,6 @@ std::vector<WalletDescriptor> CWallet::GetWalletDescriptors(const CScript& scrip
return descs;
}
LegacyScriptPubKeyMan* CWallet::GetLegacyScriptPubKeyMan() const
{
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
return nullptr;
}
// Legacy wallets only have one ScriptPubKeyMan which is a LegacyScriptPubKeyMan.
// Everything in m_internal_spk_managers and m_external_spk_managers point to the same legacyScriptPubKeyMan.
auto it = m_internal_spk_managers.find(OutputType::LEGACY);
if (it == m_internal_spk_managers.end()) return nullptr;
return dynamic_cast<LegacyScriptPubKeyMan*>(it->second);
}
LegacyDataSPKM* CWallet::GetLegacyDataSPKM() const
{
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
@ -3688,12 +3477,6 @@ LegacyDataSPKM* CWallet::GetLegacyDataSPKM() const
return dynamic_cast<LegacyDataSPKM*>(it->second);
}
LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
{
SetupLegacyScriptPubKeyMan();
return GetLegacyScriptPubKeyMan();
}
void CWallet::AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man)
{
// Add spkm_man to m_spk_managers before calling any method
@ -3716,9 +3499,8 @@ void CWallet::SetupLegacyScriptPubKeyMan()
return;
}
std::unique_ptr<ScriptPubKeyMan> spk_manager = m_database->Format() == "bdb_ro" ?
std::make_unique<LegacyDataSPKM>(*this) :
std::make_unique<LegacyScriptPubKeyMan>(*this, m_keypool_size);
Assert(m_database->Format() == "bdb_ro" || m_database->Format() == "mock");
std::unique_ptr<ScriptPubKeyMan> spk_manager = std::make_unique<LegacyDataSPKM>(*this);
for (const auto& type : LEGACY_OUTPUT_TYPES) {
m_internal_spk_managers[type] = spk_manager.get();
@ -3915,11 +3697,6 @@ void CWallet::DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool intern
NotifyCanGetAddressesChanged();
}
bool CWallet::IsLegacy() const
{
return !IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS);
}
DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const
{
auto spk_man_pair = m_spk_managers.find(desc.id);
@ -3937,11 +3714,6 @@ DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDes
std::optional<bool> CWallet::IsInternalScriptPubKeyMan(ScriptPubKeyMan* spk_man) const
{
// Legacy script pubkey man can't be either external or internal
if (IsLegacy()) {
return std::nullopt;
}
// only active ScriptPubKeyMan can be internal
if (!GetActiveScriptPubKeyMans().count(spk_man)) {
return std::nullopt;

View File

@ -558,9 +558,6 @@ public:
SteadyClock::duration ScanningDuration() const { return fScanningWallet ? SteadyClock::now() - m_scanning_start.load() : SteadyClock::duration{}; }
double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Upgrade DescriptorCaches
void UpgradeDescriptorCache() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@ -583,7 +580,6 @@ public:
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
unsigned int ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old_block) const;
/**
@ -920,9 +916,6 @@ public:
/** Loads the flags into the wallet. (used by LoadWallet) */
bool LoadWalletFlags(uint64_t flags);
/** Determine if we are a legacy wallet */
bool IsLegacy() const;
/** Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet has no name */
std::string GetDisplayName() const override
{
@ -963,8 +956,6 @@ public:
std::vector<WalletDescriptor> GetWalletDescriptors(const CScript& script) const;
//! Get the LegacyScriptPubKeyMan which is used for all types, internal, and external.
LegacyScriptPubKeyMan* GetLegacyScriptPubKeyMan() const;
LegacyScriptPubKeyMan* GetOrCreateLegacyScriptPubKeyMan();
LegacyDataSPKM* GetLegacyDataSPKM() const;
LegacyDataSPKM* GetOrCreateLegacyDataSPKM();

View File

@ -154,11 +154,6 @@ bool WalletBatch::EraseMasterKey(unsigned int id)
return EraseIC(std::make_pair(DBKeys::MASTER_KEY, id));
}
bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript)
{
return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false);
}
bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
{
if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) {
@ -203,21 +198,6 @@ bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext);
}
bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
{
return m_batch->Read(std::make_pair(DBKeys::POOL, nPool), keypool);
}
bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
{
return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool);
}
bool WalletBatch::ErasePool(int64_t nPool)
{
return EraseIC(std::make_pair(DBKeys::POOL, nPool));
}
bool WalletBatch::WriteMinVersion(int nVersion)
{
return WriteIC(DBKeys::MINVERSION, nVersion);
@ -744,18 +724,6 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch,
});
result = std::max(result, watch_meta_res.m_result);
// Load keypool
LoadResult pool_res = LoadRecords(pwallet, batch, DBKeys::POOL,
[] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
int64_t nIndex;
key >> nIndex;
CKeyPool keypool;
value >> keypool;
pwallet->GetOrCreateLegacyDataSPKM()->LoadKeyPool(nIndex, keypool);
return DBErrors::LOAD_OK;
});
result = std::max(result, pool_res.m_result);
// Deal with old "wkey" and "defaultkey" records.
// These are not actually loaded, but we need to check for them
@ -791,15 +759,6 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch,
// Only do logging and time first key update if there were no critical errors
pwallet->WalletLogPrintf("Legacy Wallet Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total.\n",
key_res.m_records, ckey_res.m_records, keymeta_res.m_records, key_res.m_records + ckey_res.m_records);
// nTimeFirstKey is only reliable if all keys have metadata
if (pwallet->IsLegacy() && (key_res.m_records + ckey_res.m_records + watch_script_res.m_records) != (keymeta_res.m_records + watch_meta_res.m_records)) {
auto spk_man = pwallet->GetLegacyScriptPubKeyMan();
if (spk_man) {
LOCK(spk_man->cs_KeyStore);
spk_man->UpdateTimeFirstKey(1);
}
}
}
return result;
@ -1253,14 +1212,6 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
if (any_unordered)
result = pwallet->ReorderTransactions();
// Upgrade all of the wallet keymetadata to have the hd master key id
// This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software
try {
pwallet->UpgradeKeyMetadata();
} catch (...) {
result = DBErrors::CORRUPT;
}
// Upgrade all of the descriptor caches to cache the last hardened xpub
// This operation is not atomic, but if it fails, only new entries are added so it is backwards compatible
try {
@ -1366,11 +1317,6 @@ bool WalletBatch::EraseAddressData(const CTxDestination& dest)
return m_batch->ErasePrefix(prefix);
}
bool WalletBatch::WriteHDChain(const CHDChain& chain)
{
return WriteIC(DBKeys::HDCHAIN, chain);
}
bool WalletBatch::WriteWalletFlags(const uint64_t flags)
{
return WriteIC(DBKeys::FLAGS, flags);

View File

@ -21,7 +21,6 @@ class uint256;
struct CBlockLocator;
namespace wallet {
class CKeyPool;
class CMasterKey;
class CWallet;
class CWalletTx;
@ -239,8 +238,6 @@ public:
bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey);
bool EraseMasterKey(unsigned int id);
bool WriteCScript(const uint160& hash, const CScript& redeemScript);
bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta);
bool EraseWatchOnly(const CScript &script);
@ -252,10 +249,6 @@ public:
bool WriteOrderPosNext(int64_t nOrderPosNext);
bool ReadPool(int64_t nPool, CKeyPool& keypool);
bool WritePool(int64_t nPool, const CKeyPool& keypool);
bool ErasePool(int64_t nPool);
bool WriteMinVersion(int nVersion);
bool WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey);
@ -279,9 +272,6 @@ public:
DBErrors LoadWallet(CWallet* pwallet);
//! write the hdchain model (external chain child index counter)
bool WriteHDChain(const CHDChain& chain);
//! Delete records of the given types
bool EraseRecords(const std::unordered_set<std::string>& types);

View File

@ -7,6 +7,7 @@
#include <wallet/wallettool.h>
#include <common/args.h>
#include <util/check.h>
#include <util/fs.h>
#include <util/translation.h>
#include <wallet/dump.h>
@ -33,12 +34,8 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag
wallet_instance->SetMinVersion(FEATURE_LATEST);
wallet_instance->InitWalletFlags(wallet_creation_flags);
if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
spk_man->SetupGeneration(false);
} else {
wallet_instance->SetupDescriptorScriptPubKeyMans();
}
Assert(wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
wallet_instance->SetupDescriptorScriptPubKeyMans();
tfm::format(std::cout, "Topping up keypool...\n");
wallet_instance->TopUpKeyPool();

View File

@ -5,8 +5,6 @@
# race (TODO fix)
race:LoadWallet
race:WalletBatch::WriteHDChain
race:BerkeleyBatch
race:DatabaseBatch
race:zmq::*
race:bitcoin-qt