Skip to content

Commit 118f2d7

Browse files
committed
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.
1 parent 9af87cf commit 118f2d7

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed

src/wallet/transaction.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ int64_t CWalletTx::GetTxTime() const
2424
int64_t n = nTimeSmart;
2525
return n ? n : nTimeReceived;
2626
}
27+
28+
void CWalletTx::CopyFrom(const CWalletTx& _tx)
29+
{
30+
*this = _tx;
31+
}
2732
} // namespace wallet

src/wallet/transaction.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,15 @@ class CWalletTx
323323
const uint256& GetWitnessHash() const { return tx->GetWitnessHash(); }
324324
bool IsCoinBase() const { return tx->IsCoinBase(); }
325325

326+
private:
326327
// Disable copying of CWalletTx objects to prevent bugs where instances get
327328
// copied in and out of the mapWallet map, and fields are updated in the
328329
// wrong copy.
329-
CWalletTx(CWalletTx const &) = delete;
330-
void operator=(CWalletTx const &x) = delete;
330+
CWalletTx(const CWalletTx&) = default;
331+
CWalletTx& operator=(const CWalletTx&) = default;
332+
public:
333+
// Instead have an explicit copy function
334+
void CopyFrom(const CWalletTx&);
331335
};
332336

333337
struct WalletTxOrderComparator {

src/wallet/wallet.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3908,6 +3908,14 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
39083908
// Check if the transactions in the wallet are still ours. Either they belong here, or they belong in the watchonly wallet.
39093909
// We need to go through these in the tx insertion order so that lookups to spends works.
39103910
std::vector<uint256> txids_to_delete;
3911+
std::unique_ptr<WalletBatch> watchonly_batch;
3912+
if (data.watchonly_wallet) {
3913+
watchonly_batch = std::make_unique<WalletBatch>(data.watchonly_wallet->GetDatabase());
3914+
// Copy the next tx order pos to the watchonly wallet
3915+
LOCK(data.watchonly_wallet->cs_wallet);
3916+
data.watchonly_wallet->nOrderPosNext = nOrderPosNext;
3917+
watchonly_batch->WriteOrderPosNext(data.watchonly_wallet->nOrderPosNext);
3918+
}
39113919
for (const auto& [_pos, wtx] : wtxOrdered) {
39123920
if (!IsMine(*wtx->tx) && !IsFromMe(*wtx->tx)) {
39133921
// Check it is the watchonly wallet's
@@ -3916,12 +3924,20 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
39163924
LOCK(data.watchonly_wallet->cs_wallet);
39173925
if (data.watchonly_wallet->IsMine(*wtx->tx) || data.watchonly_wallet->IsFromMe(*wtx->tx)) {
39183926
// Add to watchonly wallet
3919-
if (!data.watchonly_wallet->AddToWallet(wtx->tx, wtx->m_state)) {
3920-
error = _("Error: Could not add watchonly tx to watchonly wallet");
3927+
const uint256& hash = wtx->GetHash();
3928+
const CWalletTx& to_copy_wtx = *wtx;
3929+
if (!data.watchonly_wallet->LoadToWallet(hash, [&](CWalletTx& ins_wtx, bool new_tx) EXCLUSIVE_LOCKS_REQUIRED(data.watchonly_wallet->cs_wallet) {
3930+
if (!new_tx) return false;
3931+
ins_wtx.SetTx(to_copy_wtx.tx);
3932+
ins_wtx.CopyFrom(to_copy_wtx);
3933+
return true;
3934+
})) {
3935+
error = strprintf(_("Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex());
39213936
return false;
39223937
}
3938+
watchonly_batch->WriteTx(data.watchonly_wallet->mapWallet.at(hash));
39233939
// Mark as to remove from this wallet
3924-
txids_to_delete.push_back(wtx->GetHash());
3940+
txids_to_delete.push_back(hash);
39253941
continue;
39263942
}
39273943
}
@@ -3930,6 +3946,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
39303946
return false;
39313947
}
39323948
}
3949+
watchonly_batch.reset(); // Flush
39333950
// Do the removes
39343951
if (txids_to_delete.size() > 0) {
39353952
std::vector<uint256> deleted_txids;

0 commit comments

Comments
 (0)