mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-08 13:49:35 +02:00
Merge bitcoin/bitcoin#27224: refactor: Remove CAddressBookData::destdata
a5986e82ddrefactor: Remove CAddressBookData::destdata (Ryan Ofsky)5938ad0bdbwallet: Add DatabaseBatch::ErasePrefix method (Ryan Ofsky) Pull request description: This is cleanup that doesn't change external behavior. Benefits of the cleanup are: - Removes awkward `StringMap` intermediate representation for wallet address metadata. - Simplifies `CWallet`, deals with used address and received request serialization in `walletdb.cpp` instead of higher level wallet code - Adds test coverage and documentation This PR doesn't change externally observable behavior. Internally, the only change in behavior is that `EraseDestData` deletes rows directly from the database because they are no longer stored in memory. This is more direct and efficient because it uses a single lookup and scan instead of multiple lookups. Motivation for this cleanup is making changes like #18550, #18192, #13756 easier to reason about and less likely to result in unintended behavior and bugs --- This PR is a rebased copy of #18608. For some reason that PR is locked and couldn't be reopened or commented on. This PR is an alternative to #27215 with differences described in https://github.com/bitcoin/bitcoin/pull/27215#pullrequestreview-1329028143 ACKs for top commit: achow101: ACKa5986e82ddfurszy: Code ACKa5986e82Tree-SHA512: 6bd3e402f1f60263fbd433760bdc29d04175ddaf8307207c4a67d59f6cffa732e176ba57886e02926f7a1615dce0ed9cda36c8cbc6430aa8e5b56934c23f3fe7
This commit is contained in:
@@ -967,11 +967,11 @@ void CWallet::SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned
|
||||
CTxDestination dst;
|
||||
if (ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst)) {
|
||||
if (IsMine(dst)) {
|
||||
if (used != IsAddressUsed(dst)) {
|
||||
if (used != IsAddressPreviouslySpent(dst)) {
|
||||
if (used) {
|
||||
tx_destinations.insert(dst);
|
||||
}
|
||||
SetAddressUsed(batch, dst, used);
|
||||
SetAddressPreviouslySpent(batch, dst, used);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -984,7 +984,7 @@ bool CWallet::IsSpentKey(const CScript& scriptPubKey) const
|
||||
if (!ExtractDestination(scriptPubKey, dest)) {
|
||||
return false;
|
||||
}
|
||||
if (IsAddressUsed(dest)) {
|
||||
if (IsAddressPreviouslySpent(dest)) {
|
||||
return true;
|
||||
}
|
||||
if (IsLegacy()) {
|
||||
@@ -992,15 +992,15 @@ bool CWallet::IsSpentKey(const CScript& scriptPubKey) const
|
||||
assert(spk_man != nullptr);
|
||||
for (const auto& keyid : GetAffectedKeys(scriptPubKey, *spk_man)) {
|
||||
WitnessV0KeyHash wpkh_dest(keyid);
|
||||
if (IsAddressUsed(wpkh_dest)) {
|
||||
if (IsAddressPreviouslySpent(wpkh_dest)) {
|
||||
return true;
|
||||
}
|
||||
ScriptHash sh_wpkh_dest(GetScriptForDestination(wpkh_dest));
|
||||
if (IsAddressUsed(sh_wpkh_dest)) {
|
||||
if (IsAddressPreviouslySpent(sh_wpkh_dest)) {
|
||||
return true;
|
||||
}
|
||||
PKHash pkh_dest(keyid);
|
||||
if (IsAddressUsed(pkh_dest)) {
|
||||
if (IsAddressPreviouslySpent(pkh_dest)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2403,19 +2403,15 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||
WalletBatch batch(GetDatabase());
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
// If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
|
||||
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
|
||||
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
|
||||
// If we want to delete receiving addresses, we should avoid calling EraseAddressData because it will delete the previously_spent value. Could instead just erase the label so it becomes a change address, and keep the data.
|
||||
// NOTE: This isn't a problem for sending addresses because they don't have any data that needs to be kept.
|
||||
// When adding new address data, it should be considered here whether to retain or delete it.
|
||||
if (IsMine(address)) {
|
||||
WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
|
||||
return false;
|
||||
}
|
||||
// Delete destdata tuples associated with address
|
||||
std::string strAddress = EncodeDestination(address);
|
||||
for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
|
||||
{
|
||||
batch.EraseDestData(strAddress, item.first);
|
||||
}
|
||||
// Delete data rows associated with this address
|
||||
batch.EraseAddressData(address);
|
||||
m_address_book.erase(address);
|
||||
}
|
||||
|
||||
@@ -2790,51 +2786,42 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old
|
||||
return nTimeSmart;
|
||||
}
|
||||
|
||||
bool CWallet::SetAddressUsed(WalletBatch& batch, const CTxDestination& dest, bool used)
|
||||
bool CWallet::SetAddressPreviouslySpent(WalletBatch& batch, const CTxDestination& dest, bool used)
|
||||
{
|
||||
const std::string key{"used"};
|
||||
if (std::get_if<CNoDestination>(&dest))
|
||||
return false;
|
||||
|
||||
if (!used) {
|
||||
if (auto* data = util::FindKey(m_address_book, dest)) data->destdata.erase(key);
|
||||
return batch.EraseDestData(EncodeDestination(dest), key);
|
||||
if (auto* data{util::FindKey(m_address_book, dest)}) data->previously_spent = false;
|
||||
return batch.WriteAddressPreviouslySpent(dest, false);
|
||||
}
|
||||
|
||||
const std::string value{"1"};
|
||||
m_address_book[dest].destdata.insert(std::make_pair(key, value));
|
||||
return batch.WriteDestData(EncodeDestination(dest), key, value);
|
||||
LoadAddressPreviouslySpent(dest);
|
||||
return batch.WriteAddressPreviouslySpent(dest, true);
|
||||
}
|
||||
|
||||
void CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
|
||||
void CWallet::LoadAddressPreviouslySpent(const CTxDestination& dest)
|
||||
{
|
||||
m_address_book[dest].destdata.insert(std::make_pair(key, value));
|
||||
m_address_book[dest].previously_spent = true;
|
||||
}
|
||||
|
||||
bool CWallet::IsAddressUsed(const CTxDestination& dest) const
|
||||
void CWallet::LoadAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& request)
|
||||
{
|
||||
const std::string key{"used"};
|
||||
std::map<CTxDestination, CAddressBookData>::const_iterator i = m_address_book.find(dest);
|
||||
if(i != m_address_book.end())
|
||||
{
|
||||
CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
|
||||
if(j != i->second.destdata.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
m_address_book[dest].receive_requests[id] = request;
|
||||
}
|
||||
|
||||
bool CWallet::IsAddressPreviouslySpent(const CTxDestination& dest) const
|
||||
{
|
||||
if (auto* data{util::FindKey(m_address_book, dest)}) return data->previously_spent;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> CWallet::GetAddressReceiveRequests() const
|
||||
{
|
||||
const std::string prefix{"rr"};
|
||||
std::vector<std::string> values;
|
||||
for (const auto& address : m_address_book) {
|
||||
for (const auto& data : address.second.destdata) {
|
||||
if (!data.first.compare(0, prefix.size(), prefix)) {
|
||||
values.emplace_back(data.second);
|
||||
}
|
||||
for (const auto& [dest, entry] : m_address_book) {
|
||||
for (const auto& [id, request] : entry.receive_requests) {
|
||||
values.emplace_back(request);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
@@ -2842,15 +2829,15 @@ std::vector<std::string> CWallet::GetAddressReceiveRequests() const
|
||||
|
||||
bool CWallet::SetAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id, const std::string& value)
|
||||
{
|
||||
const std::string key{"rr" + id}; // "rr" prefix = "receive request" in destdata
|
||||
CAddressBookData& data = m_address_book.at(dest);
|
||||
if (value.empty()) {
|
||||
if (!batch.EraseDestData(EncodeDestination(dest), key)) return false;
|
||||
data.destdata.erase(key);
|
||||
} else {
|
||||
if (!batch.WriteDestData(EncodeDestination(dest), key, value)) return false;
|
||||
data.destdata[key] = value;
|
||||
}
|
||||
if (!batch.WriteAddressReceiveRequest(dest, id, value)) return false;
|
||||
m_address_book[dest].receive_requests[id] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::EraseAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id)
|
||||
{
|
||||
if (!batch.EraseAddressReceiveRequest(dest, id)) return false;
|
||||
m_address_book[dest].receive_requests.erase(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user