Skip to content

wallet: Avoid unnecessary wtxvariant rewrites - #35935

Open
achow101 wants to merge 3 commits into
bitcoin:masterfrom
achow101:optimize-multiple-wtx
Open

wallet: Avoid unnecessary wtxvariant rewrites#35935
achow101 wants to merge 3 commits into
bitcoin:masterfrom
achow101:optimize-multiple-wtx

Conversation

@achow101

@achow101 achow101 commented Aug 7, 2026

Copy link
Copy Markdown
Member

wtxvariant records should never change, so it is unnecessary for us to be rewriting all wtxvariants in a CWalletTx every time the CWalletTx's state changes. Likewise, every time there is a new variant, CWalletTx states may not change so do not need to always be unconditionally written.

This PR adds a WalletBatch::WriteTxMetadata to write just the tx record (the former behavior of WriteTx) and renames WriteTx to WriteFullTx to indicate that it will write all relevant records for a CWalletTx. Most uses of WriteTx become WriteTxMetadata, except in migration and watch only export.

AddToWallet is changed to use WriteFullTx only for new transactions, and to do so immediately after the transaction is inserted to the wallet. CWalletTx::Update takes the WalletBatch now and will write the correct records according to what is actually being updated.

When writing a tx to the wallet, we don't always need to rewrite all of
the wtx variants. Most writes can write the single tx record since they
are only updating metadata stored in that record.
@DrahtBot DrahtBot added the Wallet label Aug 7, 2026
@DrahtBot

DrahtBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35935.

Reviews

See the guideline and AI policy for information on the review process.

Type Reviewers
Concept ACK pablomartin4btc

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

When a CWalletTx is updated, we should immediately write the changes to
the database. The update may be writing a new wtx variant, updating the
metadata, or both. There is no need to rewrite all wtx variants or
update the metadata if it did not change.
Clarify in the name that this function writes the entire metadata and
all of the witness tx variants.

@pablomartin4btc pablomartin4btc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

WriteFullTx (previously WriteTx) was a single all-or-nothing write regardless of what actually changed. This PR correctly separates the two independent concerns: variant records (write-once, immutable) and metadata (mutable, state-driven), and writes only what the specific operation requires.

Left a few comments...

Comment thread src/wallet/transaction.h
// The canonical wtxid is also updated. The tx that is confirmed becomes canonical. For unconfirmed txs,
// those with witnesses are preferred, followed by least weight.
bool Update(CTransactionRef tx, const TxState& arg_state);
bool Update(CTransactionRef tx, const TxState& arg_state, WalletBatch& batch);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: as per a41607f in #35930...

Suggested change
bool Update(CTransactionRef tx, const TxState& arg_state, WalletBatch& batch);
bool Update(CTransactionRef tx, const TxState& new_state, WalletBatch& batch);

Comment thread src/wallet/walletdb.h
bool EraseTx(Txid hash);
// Write a single witness variant of CWalletTx (single wtxvariant record)
bool WriteWtxVariant(const Txid& txid, const CTransactionRef& tx);
// Write only the canonical witness tx and all of the tx metadata (single tx record)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this is a bit confusing I think — it seems to say "canonical witness tx" and "all metadata" but this function only writes ONE record (the DBKeys::TX record). Perhaps something like "// Write only the tx record (state, timestamps, canonical wtxid) — no wtxvariant records" would be clearer.

Comment thread src/wallet/wallet.cpp
// Break caches since we have changed the state
desc_tx->MarkDirty();
batch.WriteTx(*desc_tx);
batch.WriteTxMetadata(*desc_tx);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: return value discarded here — pre-existing from WriteTx, but since we're touching this area could be worth addressing (?).

Comment thread src/wallet/wallet.cpp
}
// Rewrite the transaction so that anything that may have changed about it in memory also persists to disk
local_wallet_batch.WriteTx(*wtx);
local_wallet_batch.WriteTxMetadata(*wtx);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: same return value discarded here...

const auto& [tx_pair, new_variant] = m_txs.emplace(new_tx->GetWitnessHash(), std::move(new_tx));
if (new_variant) {
if (!batch.WriteWtxVariant(GetHash(), tx_pair->second)) {
throw std::ios_base::failure("Unable to write wtxvariant record");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All other write methods in this area return bool on failure. Update() throwing std::ios_base::failure works, but it means callers need an unexpected try-catch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants