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.
This commit is contained in:
Andrew Chow committed 2023-10-19 18:06:43 -04:00
1 parent 9af87cf348
commit 118f2d7d70
3 files changed
+31 -5

No files matched your search

+5
View File
@@ -24,4 +24,9 @@ int64_t CWalletTx::GetTxTime() const
int64_t n = nTimeSmart; int64_t n = nTimeSmart;
return n ? n : nTimeReceived; return n ? n : nTimeReceived;
} }
void CWalletTx::CopyFrom(const CWalletTx& _tx)
{
*this = _tx;
}
} // namespace wallet } // namespace wallet
+6 -2
View File
@@ -323,11 +323,15 @@ public:
const uint256& GetWitnessHash() const { return tx->GetWitnessHash(); } const uint256& GetWitnessHash() const { return tx->GetWitnessHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); } bool IsCoinBase() const { return tx->IsCoinBase(); }
private:
// Disable copying of CWalletTx objects to prevent bugs where instances get // 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 // copied in and out of the mapWallet map, and fields are updated in the
// wrong copy. // wrong copy.
CWalletTx(CWalletTx const &) = delete; CWalletTx(const CWalletTx&) = default;
void operator=(CWalletTx const &x) = delete; CWalletTx& operator=(const CWalletTx&) = default;
public:
// Instead have an explicit copy function
void CopyFrom(const CWalletTx&);
}; };
struct WalletTxOrderComparator { struct WalletTxOrderComparator {
+20 -3
View File
@@ -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. // 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. // We need to go through these in the tx insertion order so that lookups to spends works.
std::vector<uint256> txids_to_delete; 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) { for (const auto& [_pos, wtx] : wtxOrdered) {
if (!IsMine(*wtx->tx) && !IsFromMe(*wtx->tx)) { if (!IsMine(*wtx->tx) && !IsFromMe(*wtx->tx)) {
// Check it is the watchonly wallet's // 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); LOCK(data.watchonly_wallet->cs_wallet);
if (data.watchonly_wallet->IsMine(*wtx->tx) || data.watchonly_wallet->IsFromMe(*wtx->tx)) { if (data.watchonly_wallet->IsMine(*wtx->tx) || data.watchonly_wallet->IsFromMe(*wtx->tx)) {
// Add to watchonly wallet // Add to watchonly wallet
if (!data.watchonly_wallet->AddToWallet(wtx->tx, wtx->m_state)) { const uint256& hash = wtx->GetHash();
error = _("Error: Could not add watchonly tx to watchonly wallet"); 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; return false;
} }
watchonly_batch->WriteTx(data.watchonly_wallet->mapWallet.at(hash));
// Mark as to remove from this wallet // Mark as to remove from this wallet
txids_to_delete.push_back(wtx->GetHash()); txids_to_delete.push_back(hash);
continue; continue;
} }
} }
@@ -3930,6 +3946,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
return false; return false;
} }
} }
watchonly_batch.reset(); // Flush
// Do the removes // Do the removes
if (txids_to_delete.size() > 0) { if (txids_to_delete.size() > 0) {
std::vector<uint256> deleted_txids; std::vector<uint256> deleted_txids;