Skip to content

interfaces: typed receive-request APIs#34838

Open
MkDev11 wants to merge 1 commit intobitcoin:masterfrom
MkDev11:feat/issue-34629-typed-receive-request-api
Open

interfaces: typed receive-request APIs#34838
MkDev11 wants to merge 1 commit intobitcoin:masterfrom
MkDev11:feat/issue-34629-typed-receive-request-api

Conversation

@MkDev11
Copy link

@MkDev11 MkDev11 commented Mar 17, 2026

Problem

The interfaces::Wallet receive-request API uses raw serialized strings, coupling GUI code to the wallet's internal storage format. The GUI serializes/deserializes RecentRequestEntry objects itself, and crashes if deserialization fails on malformed data. The GUI also owns ID assignment, which should be the wallet's responsibility.

Root Cause

getAddressReceiveRequests() returns vector<string> of opaque serialized blobs, and setAddressReceiveRequest() accepts the same — forcing the GUI to own the serialization format (RecentRequestEntry + SendCoinsRecipient SERIALIZE_METHODS in Qt code). The SpanReader deserialization in RecentRequestsTableModel::addNewRequest(const std::string&) throws on malformed data with no error handling.

Solution

Replace the two raw-string methods with three typed methods on interfaces::Wallet:

  • getReceiveRequests() → returns vector<WalletReceiveRequest> with typed fields
  • addReceiveRequest() → wallet assigns ID + timestamp, serializes internally, returns assigned ID
  • eraseReceiveRequest() → deletes by destination + ID

Serialization moves to wallet/interfaces.cpp using local RecipientData/RequestEntryData structs that are byte-identical to the Qt-side SendCoinsRecipient/RecentRequestEntry format, but have no Qt dependency. Malformed entries are logged and skipped instead of crashing. DB format is unchanged for full backward/forward compatibility.

Testing

  • Updated existing GUI test (src/qt/test/wallettests.cpp) to verify the new typed API:
    • Round-trip: add request via GUI → getReceiveRequests() returns correct typed fields
    • Erase: remove request → getReceiveRequests() returns empty
  • Existing wallet-layer test (LoadReceiveRequests in wallet_tests.cpp) unchanged — CWallet internals not modified
  • Verify: cmake --build build && build/bin/test_bitcoin-qt

Before / After

  • Before: GUI deserializes raw strings from wallet. SpanReader throws on malformed data → GUI crash. GUI owns ID assignment. Single method setAddressReceiveRequest overloaded for both save (non-empty value) and delete (empty value).
  • After: Wallet returns typed WalletReceiveRequest structs. Malformed entries are logged and skipped. Wallet assigns IDs and timestamps. Separate addReceiveRequest / eraseReceiveRequest methods.

Edge Cases Handled

  • Malformed/corrupted DB entries: caught with try/catch, logged via LogWarning, skipped
  • ID=0 entries: skipped on load (matches previous GUI behavior)
  • Invalid destination address on add: returns nullopt
  • ID collision with existing entries: scans all existing IDs to find max, assigns max+1
  • Empty label/message/zero amount: handled correctly (no special-casing needed)
  • Thread safety: all methods hold LOCK(m_wallet->cs_wallet)
  • Legacy BIP70 fields (sPaymentRequest, authenticatedMerchant): preserved in serialization format for DB compatibility

Closes #34629

Replace getAddressReceiveRequests() and setAddressReceiveRequest() with
three typed methods: getReceiveRequests(), addReceiveRequest(), and
eraseReceiveRequest(). This moves serialization responsibility from the
GUI to the wallet interface layer, decoupling Qt code from the wallet
storage format.

Add WalletReceiveRequest struct to interfaces/wallet.h carrying typed
fields (id, time, address, label, message, amount) instead of opaque
serialized blobs.

The wallet now:
- Assigns request IDs (previously done by GUI)
- Assigns timestamps
- Handles serialization/deserialization with graceful error recovery
  (malformed entries are logged and skipped instead of crashing the GUI)
- Uses separate add/erase methods instead of overloading a single setter

DB format is unchanged for full backward/forward compatibility. Local
serialization-compatible structs (RecipientData, RequestEntryData) in
wallet/interfaces.cpp mirror the Qt-side format without Qt dependencies.

Closes bitcoin#34629
@DrahtBot
Copy link
Contributor

DrahtBot commented Mar 17, 2026

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

Reviews

See the guideline for information on the review process.
A summary of reviews will appear here.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #34617 (fees: wallet: remove block policy fee estimator internals from wallet by ismaelsadeeq)
  • #33034 (wallet: Store transactions in a separate sqlite table by achow101)
  • #32763 (wallet: Replace CWalletTx::mapValue and vOrderForm with explicit class members by achow101)

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.

@MkDev11
Copy link
Author

MkDev11 commented Mar 17, 2026

@fanquake @hebasto Can you review the PR and let me know your feedback?

@hebasto
Copy link
Member

hebasto commented Mar 18, 2026

cc @achow101 @johnny9

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

interfaces/wallet: replace raw receive-request string APIs with typed methods

3 participants