Skip to content

fix(bitcoin): Ensure non-negative amounts in transaction processing#4741

Open
sergei-boiko-trustwallet wants to merge 11 commits into
masterfrom
fix/bitcoin-signed-amount
Open

fix(bitcoin): Ensure non-negative amounts in transaction processing#4741
sergei-boiko-trustwallet wants to merge 11 commits into
masterfrom
fix/bitcoin-signed-amount

Conversation

@sergei-boiko-trustwallet

Copy link
Copy Markdown
Contributor

This pull request strengthens type safety and error handling for transaction value conversions across Bitcoin, Decred, and Zcash modules. The main goal is to ensure that all monetary values (inputs, outputs, fees, etc.) are properly checked and converted, preventing negative or out-of-range values from propagating through the codebase. This is achieved by consistently using try_into() with contextual error mapping and updating relevant method signatures to return SigningResult for better error propagation.

Key changes by theme:

Improved Type Safety and Error Handling for Value Conversions

  • Replaced direct assignments of transaction amounts (inputs, outputs, fees, etc.) with try_into() conversions and mapped errors using .tw_err(...) and .context(...) for detailed error reporting in Bitcoin and Decred modules. This affects planners, signers, protobuf builders, and transaction builders.

  • Updated method signatures in protobuf builders and related functions (e.g., tx_to_proto, tx_input_to_proto, tx_output_to_proto) to return SigningResult<T> instead of plain values, ensuring errors are properly propagated up the call stack.

Refactoring and Clean-up

  • Removed redundant or now-unnecessary manual negative value checks in favor of the new conversion and error handling approach, simplifying logic in transaction and UTXO builders.

Consistency Across Chains

  • Applied the same conversion and error handling logic to Decred and Zcash modules, ensuring uniformity and reducing the risk of inconsistencies or missed edge cases.

These changes make the codebase more robust, preventing invalid transaction values from causing subtle bugs or security issues, and provide clearer error messages for debugging and user feedback.

Copilot AI left a comment

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.

Pull request overview

This PR hardens UTXO-chain transaction processing by enforcing non-negative monetary amounts and propagating conversion failures as structured signing/planning errors across the C++ (Bitcoin/Zen/Decred) and Rust (tw_utxo, tw_bitcoin, tw_decred, tw_zcash) stacks.

Changes:

  • Added/centralized non-negative amount validation in C++ Bitcoin-derived modules (assertValidAmount) and applied it at key Proto parsing / output construction points.
  • Refactored Rust UTXO amount handling to use unsigned Amount (u64) and expanded try_into()-based error propagation for proto builders, planners, signers, and fee policy parsing.
  • Updated tests and constants to match the new error mapping and unsigned amount types.

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Zen/TransactionBuilder.h Validates output amounts as non-negative before script/output construction.
src/Decred/TransactionOutput.h Enforces non-negative output value at construction time.
src/Bitcoin/UTXO.h Validates protobuf UTXO amounts on construction.
src/Bitcoin/TransactionPlan.h Validates plan amounts/fee/change are non-negative when built from protobuf.
src/Bitcoin/SigningInput.cpp Validates protobuf-provided amounts (amount, byte fee, extra outputs) are non-negative.
src/Bitcoin/Amount.h Introduces assertValidAmount helper throwing on negative amounts.
rust/tw_tests/tests/chains/bitcoin/bitcoin_plan/plan_exact_error.rs Updates expected planner error for negative output amounts.
rust/frameworks/tw_utxo/tests/build_tx.rs Migrates fee-rate/expected fee types to u64 to match unsigned amounts.
rust/frameworks/tw_utxo/src/transaction/unsigned_transaction.rs Computes totals using u64 accumulation with checked arithmetic.
rust/frameworks/tw_utxo/src/transaction/transaction_sighash/legacy_sighash.rs Updates documentation around default output value sentinel under unsigned Amount.
rust/frameworks/tw_utxo/src/transaction/transaction_parts.rs Changes core Amount type to u64 and updates documentation.
rust/frameworks/tw_utxo/src/transaction/standard_transaction/mod.rs Replaces -1 default output value with u64::MAX and documents SIGHASH_SINGLE behavior.
rust/chains/tw_zcash/src/modules/signing_request.rs Rejects negative fee_per_vb via try_into() + contextual error.
rust/chains/tw_zcash/src/modules/protobuf_builder.rs Makes tx→proto conversion fallible; validates sapling value balance conversion.
rust/chains/tw_zcash/src/modules/pczt_request/utxo_pczt.rs Simplifies amount handling now that PCZT transparent values are u64.
rust/chains/tw_zcash/src/modules/pczt_request/output_pczt.rs Simplifies output value handling now that PCZT transparent values are u64.
rust/chains/tw_decred/src/modules/protobuf_builder.rs Makes input/output proto building fallible with amount conversions.
rust/chains/tw_bitcoin/src/modules/tx_builder/utxo_protobuf.rs Replaces manual negative checks with try_into() + contextual error mapping.
rust/chains/tw_bitcoin/src/modules/tx_builder/output_protobuf.rs Replaces manual negative checks with try_into() + contextual error mapping.
rust/chains/tw_bitcoin/src/modules/signing_request/standard_signing_request.rs Validates dust threshold and fee policy inputs via try_into() conversions.
rust/chains/tw_bitcoin/src/modules/signer.rs Propagates fallible tx→proto conversion and validates fee conversion.
rust/chains/tw_bitcoin/src/modules/psbt_request/utxo_psbt.rs Removes now-unneeded amount conversion for u64 PSBT amounts.
rust/chains/tw_bitcoin/src/modules/psbt_request/output_psbt.rs Removes now-unneeded amount conversion for u64 PSBT outputs.
rust/chains/tw_bitcoin/src/modules/protobuf_builder/standard_protobuf_builder.rs Makes tx→proto conversion fallible and validates output value conversion.
rust/chains/tw_bitcoin/src/modules/protobuf_builder/mod.rs Updates ProtobufBuilder trait to return SigningResult.
rust/chains/tw_bitcoin/src/modules/planner/psbt_planner.rs Validates plan numeric fields via try_into() conversions (non-negative/fit checks).
rust/chains/tw_bitcoin/src/modules/planner/mod.rs Validates planned output values and plan totals via try_into() conversions.
rust/chains/tw_bitcoin/src/modules/compiler.rs Propagates fallible tx→proto conversion and validates fee conversion.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rust/chains/tw_bitcoin/src/modules/protobuf_builder/standard_protobuf_builder.rs Outdated
Comment thread rust/chains/tw_decred/src/modules/protobuf_builder.rs
Comment thread rust/chains/tw_decred/src/modules/protobuf_builder.rs
@github-actions

github-actions Bot commented Apr 22, 2026

Copy link
Copy Markdown

Binary size comparison

➡️ aarch64-apple-ios:

- 14.36 MB
+ 14.38 MB 	 +19 KB

➡️ aarch64-apple-ios-sim:

- 14.37 MB
+ 14.39 MB 	 +20 KB

➡️ aarch64-linux-android:

- 18.81 MB
+ 18.83 MB 	 +30 KB

➡️ armv7-linux-androideabi:

- 16.23 MB
+ 16.26 MB 	 +32 KB

➡️ wasm32-unknown-emscripten:

- 13.72 MB
+ 13.75 MB 	 +30 KB

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 58 out of 58 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Bitcoin/Amount.h Outdated
Comment thread src/Bitcoin/Amount.h Outdated

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 60 out of 60 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Bitcoin/InputSelector.cpp
Comment thread src/Bitcoin/InputSelector.cpp
Comment thread src/Bitcoin/TransactionBuilder.cpp Outdated

@nikhil-gupta-tw nikhil-gupta-tw left a comment

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.

LGTM

Comment thread src/Bitcoin/SigningInput.cpp
@BSCSecChef BSCSecChef self-requested a review April 29, 2026 11:12
BSCSecChef
BSCSecChef previously approved these changes Apr 29, 2026

@BSCSecChef BSCSecChef left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@tw-davidkim tw-davidkim left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should we also wrap the fixed_dust_threshold ? I see it's in signed integer format (Bitcoin signing input).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants