Skip to content

feat(wallet): add support for bip-431 rules 4 and 5#493

Open
yan-pi wants to merge 4 commits into
bitcoindevkit:masterfrom
yan-pi:feat/truc-vsize-caps
Open

feat(wallet): add support for bip-431 rules 4 and 5#493
yan-pi wants to merge 4 commits into
bitcoindevkit:masterfrom
yan-pi:feat/truc-vsize-caps

Conversation

@yan-pi

@yan-pi yan-pi commented Jun 1, 2026

Copy link
Copy Markdown

partially addresses #477
depends of #478
solves #484
solves #485

Description

Enforces BIP-431 Rules 4 and 5 inside create_tx, before returning a PSBT:

  • Rule 4: rejects any TRUC (nVersion=3) transaction with sigop-adjusted vsize over 10,000 vB
  • Rule 5: tightens the cap to 1,000 vB when the transaction has an unconfirmed TRUC ancestor

Without this, build_tx().version(3).finish() hands back a valid PSBT that bitcoind rejects at broadcast.

The new CreateTxError::TrucSizeExceeded { cap_vb, actual_vb } tells callers which rule fired and by how much, so they can react (fewer inputs, split the payment, etc.).

It adds estimate_truc_vsize as a private helper, and reuses the is_truc helper and bdk_testenv dev-dependency introduced in #478.

This does not address Rules 1–3 (topology / package limits), that's a separate concern tracked in #477.

Notes to the reviewers

The check runs after coin_select and before complete_transaction. That's the only viable placement that I found.

CoinSelection::coin_select consumes Vec<WeightedUtxo> and returns Vec<Utxo>, so the per-input satisfaction_weight is gone by the time we'd want it.

We pre-collect a HashMap<OutPoint, Weight> from the WeightedUtxo list before handing it to the selector.
The map is only allocated when version == 3.

For the Rule 5 ancestor check, foreign UTXOs are conservatively treated as non-TRUC.
Same posture as the existing TRUC filter in filter_utxos.

We use plain weight / 4. Bitcoind's TRUC check uses sigop-adjusted vsize (max(weight, sigops * 20) / 4), which matches plain weight/4 for P2WPKH, P2TR and ordinary P2WSH.

#477 should have an followup to tracks proper sigop accounting.

Changelog notice

Added `CreateTxError::TrucSizeExceeded { cap_vb, actual_vb }`.
`create_tx` now enforces BIP-431 Rules 4 and 5 (vsize caps) for nVersion=3 transactions.

Checklists

All Submissions:

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@codecov

codecov Bot commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.52542% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.08%. Comparing base (58fe631) to head (1ae1a28).

Files with missing lines Patch % Lines
src/wallet/error.rs 0.00% 3 Missing ⚠️
src/wallet/mod.rs 96.42% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #493      +/-   ##
==========================================
+ Coverage   80.96%   81.08%   +0.12%     
==========================================
  Files          24       24              
  Lines        5489     5546      +57     
  Branches      247      254       +7     
==========================================
+ Hits         4444     4497      +53     
- Misses        968      971       +3     
- Partials       77       78       +1     
Flag Coverage Δ
rust 81.08% <91.52%> (+0.12%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/wallet/mod.rs Outdated
Comment thread src/wallet/mod.rs Outdated
Comment thread src/wallet/mod.rs Outdated
@oleonardolima oleonardolima added the bug Something isn't working label Jun 5, 2026
@oleonardolima oleonardolima moved this to In Progress in BDK Wallet Jun 5, 2026
@oleonardolima oleonardolima added this to the Wallet 3.2.0 milestone Jun 5, 2026
@yan-pi yan-pi force-pushed the feat/truc-vsize-caps branch 3 times, most recently from a8c7d37 to 634d476 Compare June 11, 2026 12:14
oleonardolima and others added 2 commits June 15, 2026 15:16
- introduces a private method `is_truc` to check if a given tx version
  is TRUC (e.g `transaction::Version(3)`).
- add new step in `filter_utxos` to validate BIP-431 rule 2, which
  validates the proper usage of unconfirmed TRUC/non-TRUC ancestor in a
  TRUC/non-TRUC tx.
- introduce `test_create_and_spend_from_tx` to exercise BIP-431 rule-2
  filtering in-memory, not relying on `bdk_testenv`/`bdk_electrum`.

NOTE: I asked Claude to remove the `bdk_testenv` dependency, keeping
the test behavior in-memory.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@oleonardolima

Copy link
Copy Markdown
Contributor

@yan-pi I updated my branch to remove the bdk_testenv dependency, you can rebase this one to get a green CI (though you might need to update your tests).

- adds `CreateTxError::TrucSizeExceeded { cap_vb, actual_vb }`.
- rejects v3 txs over 10,000 vB (Rule 4), or over 1,000 vB when the
  tx has an unconfirmed TRUC ancestor (Rule 5).
- adds private helper `estimate_truc_vsize` using plain weight/4.
@yan-pi yan-pi force-pushed the feat/truc-vsize-caps branch from 634d476 to 1e9f37e Compare June 19, 2026 13:50
@oleonardolima oleonardolima marked this pull request as ready for review June 19, 2026 14:09
@oleonardolima oleonardolima marked this pull request as draft June 19, 2026 14:10
@oleonardolima

Copy link
Copy Markdown
Contributor

@yan-pi the CI still failing

- covers rejection and acceptance for both rules, plus a v2 case to
  ensure non-TRUC builds aren't affected.
- end-to-end test funds via regtest electrum, broadcasts a v3 parent,
  and exercises both the Rule 5 rejection and the small-child acceptance
  paths through the mempool.
@yan-pi yan-pi force-pushed the feat/truc-vsize-caps branch from 1e9f37e to 1ae1a28 Compare June 19, 2026 17:52
@yan-pi

yan-pi commented Jun 19, 2026

Copy link
Copy Markdown
Author

Rebased this on top of the updated #478 branch.

I dropped the old bdk_testenv e2e test and kept the TRUC Rule 4/5 coverage in-memory.

@oleonardolima oleonardolima marked this pull request as ready for review June 20, 2026 15:49
@oleonardolima oleonardolima changed the title Add BIP-431 Rules 4 and 5 feat(wallet): add support for bip-431 rules 4 and 5 Jun 20, 2026
Comment thread src/wallet/error.rs
Comment on lines +218 to +227
/// TRUC (BIP-431) virtual size cap exceeded.
///
/// `cap_vb == 10_000` means Rule 4 (any TRUC tx).
/// `cap_vb == 1_000` means Rule 5 (TRUC tx with unconfirmed TRUC ancestor).
TrucSizeExceeded {
/// The cap that was exceeded, in virtual bytes.
cap_vb: u64,
/// The estimated virtual size of the candidate transaction.
actual_vb: u64,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@yan-pi did you manage to do it as a non-breaking change ? I agree that having the error would be the right approach, though it would only land in the next major release.

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

Labels

bug Something isn't working

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants