Skip to content

fix: enforce Core's std tx weight limit when building transactions - #361

Open
tvpeter wants to merge 2 commits into
bitcoindevkit:masterfrom
tvpeter:fix/std-tx-weight
Open

tvpeter wants to merge 2 commits into
bitcoindevkit:masterfrom
tvpeter:fix/std-tx-weight

Conversation

@tvpeter

@tvpeter tvpeter commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

Description

wallet create_tx could build transactions that are non-standard under Bitcoin Core's default policy, so they failed only at broadcast, after signing:

  • Nothing limited the transaction to MAX_STANDARD_TX_WEIGHT (400,000 wu / 100,000 vB). As shown in fix transaction creation input validation and fee rate calculation #326, a 99,994 byte --add_string payload produced a 100,150 vB tx that the node rejected with tx-size.
  • --add_data and --add_string documented "max 80 bytes" but was never enforced, and it stopped being Core's default in v30.

This PR rejects such transactions when they are built, with an error giving the weight and the limit. The check covers create_tx, create_dns_tx, bump_fee (where a fee bump can add inputs and push a tx over), and create_sp_tx.

It also parses --add_data/--add_string with clap value parsers, the same way as --fee_rate. That removes three copies of the same decoding block.

Fixes #339

Notes to the reviewers

  • Why there is no separate datacarrier check: in Core v30, IsStandardTx checks tx-size before datacarrier, and MAX_OP_RETURN_RELAY is defined as MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR. OP_RETURN bytes are non-witness, so at default settings any tx that passes the weight check also passes datacarrier. A separate check would be dead code.
  • Accounting for witnesses (from the fix transaction creation input validation and fee rate calculation #326 discussion): create_tx, create_dns_tx and bump_fee return unsigned PSBTs. Their weight is estimated with each wallet input's max_weight_to_satisfy(), the same worst case coin selection uses. The estimate is an upper bound: a tx under it can't go over once signed. In return, a segwit tx within about 1 wu per input of the limit may be rejected. create_sp_tx signs internally, so it checks the exact weight. Inputs are looked up through spk_index() rather than get_utxo(), because a fee bump's inputs are already spent.
  • Inputs the wallet doesn't own add no witness weight to the estimate.
  • Testing: the unit tests sign real transactions for tr, wpkh, sh(wpkh), pkh and a fee bump, and check that the estimate bounds the signed weight tightly.
  • Behaviour change: malformed --add_data base64 now exits 2 at argument parsing instead of 1, consistent with --fee_rate.

Changelog notice

  • Fixed create_tx, create_dns_tx, create_sp_tx and bump_fee building transactions over Bitcoin Core's 400,000 wu (100,000 vB) standard weight limit; they are now rejected when built, counting the witnesses still to be signed

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

Bugfixes:

  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

- `create_tx`, `create_sp_tx` and `create_dns_tx` each decoded
`--add_data`/`--add_string` into a `PushBytesBuf` in the handler, with
the same block. Parse both arguments with clap value parsers.

- Malformed `--add_data` base64 is now rejected at argument parsing
(exit 2) before a wallet is loaded, rather than when building (exit 1).
create_tx` could build transactions over Bitcoin Core's 400,000 wu
`MAX_STANDARD_TX_WEIGHT`, which no default node relays. The `--add_data`
and `--add_string` docs claimed an 80 byte limit that was never enforced
and is no longer Core's default. These changes:

- Enforce 400k WU limit across `create_tx`, `create_dns_tx`, `bump_fee`,
  and `create_sp_tx`.
- Estimate PSBT weight using `max_weight_to_satisfy` per input for
  unsigned flows (`create_tx`, `create_dns_tx`, `bump_fee`).
- Check exact weight post-signing in `create_sp_tx`.
- Update `--add_data` and `--add_string` docs to remove references to
  the deprecated 80-byte data limit. Bitcoin Core v30+ evaluates weight
  limits prior to data carrier limits.
@github-project-automation github-project-automation Bot moved this to Todo in BDK-CLI Oct 19, 2026
@tvpeter tvpeter changed the title fix: enforce Bitcoin Core's standard tx weight limit when building transactions fix: enforce Core's std tx weight limit when building transactions Oct 19, 2026
@tvpeter tvpeter self-assigned this Oct 19, 2026
@tvpeter tvpeter added this to the CLI 4.1.0 milestone Oct 19, 2026
@codecov

codecov Bot commented Oct 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.22642% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.42%. Comparing base (3f6b023) to head (70efe32).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/utils/common.rs 97.91% 2 Missing ⚠️
src/handlers/dns/mod.rs 66.66% 1 Missing ⚠️
src/handlers/offline.rs 85.71% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #361      +/-   ##
==========================================
+ Coverage   61.46%   62.42%   +0.95%     
==========================================
  Files          23       23              
  Lines        3989     4077      +88     
==========================================
+ Hits         2452     2545      +93     
+ Misses       1537     1532       -5     
Flag Coverage Δ
rust 62.42% <96.22%> (+0.95%) ⬆️

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.

@emma31-dev

Copy link
Copy Markdown

since you are already working on this i'll love you to address issue #360 in this same pr

This branch has not been deployed

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

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Enforce Core-compatible OP_RETURN / datacarrier and standard tx-size limits in create_tx

2 participants