aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2023-10-06 16:57:42 -0400
committerAndrew Chow <github@achow101.com>2023-10-19 18:06:43 -0400
commit118f2d7d70b584eee7b89e58b5cd2d61c59a9bbf (patch)
tree6245f3440412bf8efad81c033a9512585d9b3bab /src
parent9af87cf3485ce3fac553a284cde37a35d1085c25 (diff)
downloadbitcoin-118f2d7d70b584eee7b89e58b5cd2d61c59a9bbf.tar.xz
wallet: Copy all tx metadata to watchonly wallet
When moving a tx to the watchonly wallet during migration, make sure that all of the CWalletTx data follows it.
Diffstat (limited to 'src')
-rw-r--r--src/wallet/transaction.cpp5
-rw-r--r--src/wallet/transaction.h8
-rw-r--r--src/wallet/wallet.cpp23
3 files changed, 31 insertions, 5 deletions
diff --git a/src/wallet/transaction.cpp b/src/wallet/transaction.cpp
index a46846c1d4..4f78fe7520 100644
--- a/src/wallet/transaction.cpp
+++ b/src/wallet/transaction.cpp
@@ -24,4 +24,9 @@ int64_t CWalletTx::GetTxTime() const
int64_t n = nTimeSmart;
return n ? n : nTimeReceived;
}
+
+void CWalletTx::CopyFrom(const CWalletTx& _tx)
+{
+ *this = _tx;
+}
} // namespace wallet
diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h
index 1a79d7db4e..fa6c8d6f3b 100644
--- a/src/wallet/transaction.h
+++ b/src/wallet/transaction.h
@@ -323,11 +323,15 @@ public:
const uint256& GetWitnessHash() const { return tx->GetWitnessHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
+private:
// Disable copying of CWalletTx objects to prevent bugs where instances get
// copied in and out of the mapWallet map, and fields are updated in the
// wrong copy.
- CWalletTx(CWalletTx const &) = delete;
- void operator=(CWalletTx const &x) = delete;
+ CWalletTx(const CWalletTx&) = default;
+ CWalletTx& operator=(const CWalletTx&) = default;
+public:
+ // Instead have an explicit copy function
+ void CopyFrom(const CWalletTx&);
};
struct WalletTxOrderComparator {
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 5d2f9e2fb6..5caa43edb4 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3908,6 +3908,14 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
// Check if the transactions in the wallet are still ours. Either they belong here, or they belong in the watchonly wallet.
// We need to go through these in the tx insertion order so that lookups to spends works.
std::vector<uint256> txids_to_delete;
+ std::unique_ptr<WalletBatch> watchonly_batch;
+ if (data.watchonly_wallet) {
+ watchonly_batch = std::make_unique<WalletBatch>(data.watchonly_wallet->GetDatabase());
+ // Copy the next tx order pos to the watchonly wallet
+ LOCK(data.watchonly_wallet->cs_wallet);
+ data.watchonly_wallet->nOrderPosNext = nOrderPosNext;
+ watchonly_batch->WriteOrderPosNext(data.watchonly_wallet->nOrderPosNext);
+ }
for (const auto& [_pos, wtx] : wtxOrdered) {
if (!IsMine(*wtx->tx) && !IsFromMe(*wtx->tx)) {
// Check it is the watchonly wallet's
@@ -3916,12 +3924,20 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
LOCK(data.watchonly_wallet->cs_wallet);
if (data.watchonly_wallet->IsMine(*wtx->tx) || data.watchonly_wallet->IsFromMe(*wtx->tx)) {
// Add to watchonly wallet
- if (!data.watchonly_wallet->AddToWallet(wtx->tx, wtx->m_state)) {
- error = _("Error: Could not add watchonly tx to watchonly wallet");
+ const uint256& hash = wtx->GetHash();
+ const CWalletTx& to_copy_wtx = *wtx;
+ if (!data.watchonly_wallet->LoadToWallet(hash, [&](CWalletTx& ins_wtx, bool new_tx) EXCLUSIVE_LOCKS_REQUIRED(data.watchonly_wallet->cs_wallet) {
+ if (!new_tx) return false;
+ ins_wtx.SetTx(to_copy_wtx.tx);
+ ins_wtx.CopyFrom(to_copy_wtx);
+ return true;
+ })) {
+ error = strprintf(_("Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex());
return false;
}
+ watchonly_batch->WriteTx(data.watchonly_wallet->mapWallet.at(hash));
// Mark as to remove from this wallet
- txids_to_delete.push_back(wtx->GetHash());
+ txids_to_delete.push_back(hash);
continue;
}
}
@@ -3930,6 +3946,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
return false;
}
}
+ watchonly_batch.reset(); // Flush
// Do the removes
if (txids_to_delete.size() > 0) {
std::vector<uint256> deleted_txids;