-
Notifications
You must be signed in to change notification settings - Fork 1.2k
backport: bitcoin/bitcoin#23201, bitcoin/bitcoin#25551 (external signer, user provided size of tx) #7055
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
✅ No Merge Conflicts DetectedThis PR currently has no conflicts with other open PRs. |
WalkthroughThis change adds per-input weight support: CCoinControl gains SetInputWeight/HasInputWeight/GetInputWeight and an internal map for weights. RPCs (fundrawtransaction, send, walletcreatefundedpsbt) accept an inputs->input_sizes parameter; a helper extracts per-input sizes into options and applies them to coin control. Coin selection uses provided input weights when estimating input bytes. A FillInputToWeight helper and integration in DummySignTx pre-fills inputs to target serialized weight. New unit and functional tests exercise sizing, boundaries, and fee effects. Sequence DiagramsequenceDiagram
participant User
participant RPC as RPC Layer (spend.cpp)
participant CC as CCoinControl
participant CS as Coin Selection (spend.cpp)
participant Sign as Signing (wallet.cpp)
User->>RPC: Call fund/send/walletcreatefundedpsbt with input_sizes
RPC->>RPC: SetOptionsInputWeights(inputs, options)
RPC->>CC: SetInputWeight(outpoint, weight) for each input
RPC->>CS: FundTransaction(..., coin_control)
CS->>CC: HasInputWeight(outpoint)?
alt weight present
CC-->>CS: true
CS->>CC: GetInputWeight(outpoint)
CS->>CS: Use provided weight for input_bytes
else no weight
CC-->>CS: false
CS->>CS: Use estimated input size
end
CS-->>RPC: Built transaction/psbt
RPC->>Sign: DummySignTx(tx, coin_control)
Sign->>CC: HasInputWeight(outpoint)?
alt weight present
CC-->>Sign: true
Sign->>Sign: FillInputToWeight(txin, target_weight)
Sign->>Sign: Skip normal signing for that input
else no weight
CC-->>Sign: false
Sign->>Sign: Normal signing
end
Sign-->>RPC: Signed/funded tx or PSBT
RPC-->>User: Result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
test/functional/wallet_send.py (1)
542-542: Use string literal for Decimal to avoid float precision issues."Unfortunately, most decimal fractions cannot be represented exactly as binary fractions." Using
Decimal(0.0001)with a float literal may introduce precision errors.- assert_fee_amount(testres["fees"]["base"], testres["vsize"], Decimal(0.0001)) + assert_fee_amount(testres["fees"]["base"], testres["vsize"], Decimal("0.0001"))test/functional/rpc_fundrawtransaction.py (2)
10-10: Remove unused import.Static analysis correctly identifies that
ceilfrommathis imported but never used in this file.-from math import ceil
1028-1028: Use string literal for Decimal to avoid float precision issues.Same as in
wallet_send.py, usingDecimal(0.0001)with a float literal may introduce precision errors.- assert_fee_amount(funded_tx4["fee"], tx4_size, Decimal(0.0001)) + assert_fee_amount(funded_tx4["fee"], tx4_size, Decimal("0.0001"))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/wallet/coincontrol.h(2 hunks)src/wallet/rpc/spend.cpp(9 hunks)src/wallet/spend.cpp(1 hunks)src/wallet/test/spend_tests.cpp(1 hunks)src/wallet/wallet.cpp(2 hunks)src/wallet/wallet.h(1 hunks)test/functional/rpc_fundrawtransaction.py(3 hunks)test/functional/rpc_psbt.py(3 hunks)test/functional/wallet_send.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
src/**/*.{cpp,h,hpp,cc}
📄 CodeRabbit inference engine (CLAUDE.md)
Dash Core implementation must be written in C++20, requiring at least Clang 16 or GCC 11.1
Files:
src/wallet/wallet.hsrc/wallet/test/spend_tests.cppsrc/wallet/spend.cppsrc/wallet/coincontrol.hsrc/wallet/rpc/spend.cppsrc/wallet/wallet.cpp
src/wallet/**/*.{cpp,h}
📄 CodeRabbit inference engine (CLAUDE.md)
Wallet implementation must use Berkeley DB and SQLite
Files:
src/wallet/wallet.hsrc/wallet/test/spend_tests.cppsrc/wallet/spend.cppsrc/wallet/coincontrol.hsrc/wallet/rpc/spend.cppsrc/wallet/wallet.cpp
src/{test,wallet/test}/**/*.{cpp,h}
📄 CodeRabbit inference engine (CLAUDE.md)
Unit tests in src/test/ and src/wallet/test/ must use Boost::Test framework
Files:
src/wallet/test/spend_tests.cpp
test/functional/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Functional tests in test/functional/ must be written in Python (minimum version specified in .python-version) and depend on dashd and dash-node
Files:
test/functional/wallet_send.pytest/functional/rpc_fundrawtransaction.pytest/functional/rpc_psbt.py
🧠 Learnings (7)
📓 Common learnings
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: knst
Repo: dashpay/dash PR: 6916
File: src/univalue/include/univalue.h:81-88
Timestamp: 2025-10-25T07:08:51.918Z
Learning: For backport PRs from bitcoin/bitcoin, bitcoin-core/gui, etc., backported changes should match the original upstream PRs even if they appear strange, modify vendored code, or seem to violate coding guidelines. Still flag genuine issues like bugs, undefined behavior, crashes, compilation errors, or linter failures.
Learnt from: knst
Repo: dashpay/dash PR: 6883
File: src/rpc/rawtransaction.cpp:1088-1125
Timestamp: 2025-10-13T12:37:12.357Z
Learning: In backport pull requests (especially from Bitcoin Core), treat "moved" or refactored code as out-of-scope for content-level review. Focus validation on verifying that code is moved correctly: no fields added, no fields removed, no fields reordered, and no unexpected changes beyond whitespace adjustments. Pre-existing issues in the upstream code should be preserved to maintain fidelity to the original implementation.
Learnt from: knst
Repo: dashpay/dash PR: 6871
File: contrib/guix/libexec/build.sh:358-360
Timestamp: 2025-10-05T20:38:28.457Z
Learning: In the Dash repository, when backporting code from Bitcoin Core, typos and minor issues in comments should be kept as-is to reduce merge conflicts in future backports, even if they remain unfixed in Bitcoin Core's master branch.
Learnt from: PastaPastaPasta
Repo: dashpay/dash PR: 6804
File: src/qt/proposalwizard.cpp:40-42
Timestamp: 2025-08-11T17:16:36.654Z
Learning: In the Dash repository, when a PR adds new files that are not from Bitcoin backports, these files must be added to the list in test/util/data/non-backported.txt. This applies to newly created files like qt/proposalwizard.{h,cpp} and forms/proposalwizard.ui. Limited exemptions may exist for subtrees and similar cases.
📚 Learning: 2025-08-08T07:01:47.332Z
Learnt from: knst
Repo: dashpay/dash PR: 6805
File: src/wallet/rpc/wallet.cpp:357-357
Timestamp: 2025-08-08T07:01:47.332Z
Learning: In src/wallet/rpc/wallet.cpp, the upgradetohd RPC now returns a UniValue string message (RPCResult::Type::STR) instead of a boolean, including guidance about mnemonic backup and null-character passphrase handling; functional tests have been updated to assert returned strings in several cases.
Applied to files:
src/wallet/test/spend_tests.cppsrc/wallet/rpc/spend.cpptest/functional/rpc_fundrawtransaction.pytest/functional/rpc_psbt.py
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,txmempool}/**/*.{cpp,h} : Block validation and mempool handling must use extensions to Bitcoin Core mechanisms for special transaction validation and enhanced transaction relay
Applied to files:
src/wallet/test/spend_tests.cppsrc/wallet/rpc/spend.cppsrc/wallet/wallet.cpp
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/coinjoin/**/*.{cpp,h} : CoinJoin implementation must use masternode-coordinated mixing sessions with uniform denomination outputs
Applied to files:
src/wallet/spend.cppsrc/wallet/coincontrol.h
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,consensus,net_processing}/**/*.{cpp,h} : ValidationInterface callbacks must be used for event-driven architecture to coordinate subsystems during block/transaction processing
Applied to files:
src/wallet/rpc/spend.cpp
📚 Learning: 2025-01-14T08:37:16.955Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6530
File: src/validation.cpp:360-362
Timestamp: 2025-01-14T08:37:16.955Z
Learning: The UpdateTransactionsFromBlock() method in txmempool.cpp takes parameters in the order: vHashUpdate, ancestor_size_limit, ancestor_count_limit. The size limit comes before the count limit.
Applied to files:
src/wallet/rpc/spend.cpp
📚 Learning: 2025-06-09T16:43:20.996Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Applied to files:
test/functional/rpc_fundrawtransaction.pytest/functional/rpc_psbt.py
🧬 Code graph analysis (9)
src/wallet/wallet.h (1)
src/wallet/wallet.cpp (2)
FillInputToWeight(1661-1694)FillInputToWeight(1661-1661)
src/wallet/test/spend_tests.cpp (1)
src/wallet/wallet.cpp (2)
FillInputToWeight(1661-1694)FillInputToWeight(1661-1661)
test/functional/wallet_send.py (2)
test/functional/test_framework/util.py (3)
assert_raises_rpc_error(132-148)assert_equal(69-74)assert_fee_amount(44-52)src/wallet/rpc/spend.cpp (3)
send(797-994)send(797-797)tx(981-981)
src/wallet/spend.cpp (1)
src/policy/policy.h (1)
GetVirtualTransactionSize(118-121)
src/wallet/coincontrol.h (4)
src/wallet/spend.cpp (1)
outpoint(150-150)src/wallet/wallet.cpp (1)
outpoint(1093-1093)src/wallet/interfaces.cpp (4)
outpoint(399-399)outpoint(399-399)outpoint(400-400)outpoint(400-400)src/wallet/coinjoin.cpp (2)
outpoint(510-510)outpoint(560-560)
src/wallet/rpc/spend.cpp (2)
src/rpc/util.cpp (2)
ParseHashO(106-109)ParseHashO(106-106)src/rpc/rawtransaction_util.cpp (2)
ConstructTransaction(24-132)ConstructTransaction(24-24)
test/functional/rpc_fundrawtransaction.py (2)
test/functional/test_framework/util.py (4)
assert_raises_rpc_error(132-148)assert_equal(69-74)assert_greater_than(77-79)assert_fee_amount(44-52)src/wallet/rpc/spend.cpp (4)
fundrawtransaction(603-704)fundrawtransaction(603-603)signrawtransactionwithwallet(706-795)signrawtransactionwithwallet(706-706)
src/wallet/wallet.cpp (1)
src/serialize.h (1)
GetSizeOfCompactSize(245-251)
test/functional/rpc_psbt.py (3)
test/functional/test_framework/util.py (2)
assert_greater_than(77-79)assert_raises_rpc_error(132-148)test/functional/test_framework/test_node.py (1)
get_wallet_rpc(363-369)src/wallet/rpc/spend.cpp (2)
walletcreatefundedpsbt(1075-1208)walletcreatefundedpsbt(1075-1075)
🪛 Flake8 (7.3.0)
test/functional/rpc_fundrawtransaction.py
[error] 10-10: 'math.ceil' imported but unused
(F401)
🪛 Ruff (0.14.7)
test/functional/wallet_send.py
542-542: Decimal() called with float literal argument
Replace with string literal
(RUF032)
test/functional/rpc_fundrawtransaction.py
1028-1028: Decimal() called with float literal argument
Replace with string literal
(RUF032)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: arm-linux-build / Build source
- GitHub Check: linux64_nowallet-build / Build source
- GitHub Check: mac-build / Build source
- GitHub Check: linux64_ubsan-build / Build source
- GitHub Check: linux64_sqlite-build / Build source
- GitHub Check: linux64-build / Build source
- GitHub Check: linux64_fuzz-build / Build source
- GitHub Check: linux64_tsan-build / Build source
- GitHub Check: win64-build / Build source
- GitHub Check: Lint / Run linters
🔇 Additional comments (17)
src/wallet/spend.cpp (1)
553-556: Preset-input size override via CCoinControl weight is consistent and correctUsing
HasInputWeight/GetInputWeighthere to overrideinput_byteswithGetVirtualTransactionSize(...)cleanly integrates caller‑supplied weights into coin selection and solvability checks, and preserves the existing-1error path for inputs without a weight. This matches the intended behavior for external/nonstandard inputs.src/wallet/wallet.h (1)
1134-1134: New FillInputToWeight API declaration is well-placed and consistentThe
FillInputToWeightdeclaration in the wallet namespace matches its implementation and test usage, and sits logically next toDummySignInputas another input‑sizing helper.src/wallet/wallet.cpp (2)
1661-1694: FillInputToWeight correctly pads inputs to a bounded target sizeThe helper cleanly enforces its preconditions (empty
scriptSig, nondecreasing size) and uses compact‑size accounting so that the final serialized input size is guaranteed within[target_weight-2, target_weight]. This matches the documented 2‑byte tolerance and is exercised by the new unit tests.
1704-1712: DummySignTx integration with per-input weights behaves as intendedShort‑circuiting to
FillInputToWeightwhenHasInputWeight(txin.prevout)is true lets callers fully control fee estimation for those inputs, and intentionally skips producing dummy signatures afterward. On failure, the function exits early, allowing higher‑level code to surface “missing solving data / bad weight” conditions as before.src/wallet/coincontrol.h (1)
132-147: Per-input weight tracking in CCoinControl is coherent and minimally scopedThe new
m_input_weightsmap and itsSetInputWeight/HasInputWeight/GetInputWeightaccessors integrate cleanly with existingCOutPoint-keyed state, and match how the weights are consumed in coin selection and dummy signing. The assert inGetInputWeightis appropriate given current usage patterns.Also applies to: 162-163
src/wallet/test/spend_tests.cpp (1)
61-106: FillInputToWeight tests thoroughly exercise edge cases and compact-size boundariesThe new helper and
FillInputToWeightTestcover negative/too‑small targets, the exact empty‑input size, and multiple compact‑size transitions, verifying both overall serialized size andscriptSiglength. This gives good confidence thatFillInputToWeightbehaves correctly across its range of expected inputs.src/wallet/rpc/spend.cpp (4)
531-560: LGTM - Input size parsing and validation is thorough.The validation logic correctly enforces:
voutmust be present and non-negativesizemust be present, at least 41 bytes (minimum input size), and at mostMAX_STANDARD_TX_SIZE- The
CHECK_NONFATAL(min_input_size == 41)assertion documents the expected minimumThe use of
sizein the RPC API (vs.weightin the internal API) is appropriate for Dash's non-SegWit transaction format where size and weight are equivalent.
586-601: Prevent options conflict for input sizes specified in inputs.The helper correctly:
- Rejects
input_sizesin options when inputs specify sizes (preventing ambiguity)- Early-returns if no inputs
- Extracts only inputs that have a
sizefieldOne consideration: When
inputshas elements but none containsize, this still pushes an emptyinput_sizesarray to options. This is harmless but slightly redundant.
946-947: LGTM - Input weights correctly propagated insendRPC.The call to
SetOptionsInputWeightsproperly extracts size hints fromoptions["inputs"]before passing toFundTransaction.
1174-1184: LGTM - Input weights correctly propagated inwalletcreatefundedpsbt.The options object is properly made mutable,
SetOptionsInputWeightsextracts size hints from inputs, and the modified options are passed toFundTransaction.test/functional/wallet_send.py (1)
506-542: LGTM - Comprehensive test coverage for input weight functionality.The test correctly:
- Computes input weight from the finalized PSBT
- Tests error condition when
input_sizesis in options instead of inputs- Validates funding works with explicit input weights
- Verifies mempool acceptance and fee calculation
test/functional/rpc_fundrawtransaction.py (2)
981-986: LGTM - Comprehensive error condition coverage forinput_sizesvalidation.Tests correctly verify all validation paths:
- Missing
voutkey- Negative
voutvalue- Missing
sizekey- Size below minimum (40 bytes, which is less than 41)
- Negative size
- Size exceeding maximum standard tx size
1010-1033: LGTM - Weight-based funding tests are thorough.The tests correctly verify:
- Funding with explicit input weights works and passes mempool acceptance
- Lower weight results in lower fee
- Higher weight results in higher fee
- Explicit weight overrides calculated weight when solving data is provided
- Fee rate calculation is correct with explicit weight
- Boundary values at csuint thresholds (255, 65539) don't cause issues
test/functional/rpc_psbt.py (4)
467-475: LGTM - Test setup for external input funding with PSBT.The test correctly:
- Logs the test section
- Creates a new wallet "extfund" on node 1
- Sets up the necessary infrastructure for external input testing
507-521: Input weight calculation includes buffer for potential scriptwitness variation.The formula
input_weight = ((41 + len_scriptsig + 2) * 4) + len_scriptwitnessincludes a 2-byte buffer. This is appropriate for weight calculation in a SegWit-aware context, though Dash doesn't use SegWit. The calculation appears adapted from Bitcoin Core's approach.For Dash's non-SegWit context, the simpler formula might be
41 + len_scriptsig, but the current approach is conservative and aligns with the backported code's comments about allowing up to 2-byte differences.Please verify that this weight calculation formula aligns with the
FillInputToWeightimplementation mentioned in the PR notes, which permits up to 2-byte differences due to missing segregated-data stack handling.
523-563: LGTM - Comprehensive input weight testing via walletcreatefundedpsbt.The tests correctly verify:
- Error when
input_sizesis specified in options instead of inputs- Funding with explicit input weight succeeds and passes mempool acceptance
- Lower weight produces lower fee
- Higher weight produces higher fee
- Explicit weight overrides calculated weight when solving data is provided
565-577: LGTM - Tests weight override for wallet inputs after descriptor import.After importing the descriptor into the wallet, the test verifies that explicitly provided weights still override the wallet's calculated weight for inputs it can solve. This ensures the weight override behavior is consistent for both external and wallet inputs.
| {"input_sizes", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Inputs and their corresponding sizes", | ||
| { | ||
| {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, | ||
| {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"}, | ||
| {"size", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum size for this input, " | ||
| "including the size of the outpoint and sequence number. " | ||
| "Note that serialized signature sizes are not guaranteed to be consistent, " | ||
| "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures." | ||
| "Remember to convert serialized sizes to weight units when necessary."}, | ||
| }, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RPC documentation structure issue: input_sizes elements are not properly nested.
The input_sizes array documentation declares txid, vout, and size as direct children, but they should be wrapped in an object. The current structure doesn't match the expected input format [{"txid": ..., "vout": ..., "size": ...}, ...].
The input_sizes array should document its elements as objects. Consider applying this fix:
{"input_sizes", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Inputs and their corresponding sizes",
{
- {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
- {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"},
- {"size", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum size for this input, "
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+ {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"},
+ {"size", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum size for this input, "
"including the size of the outpoint and sequence number. "
"Note that serialized signature sizes are not guaranteed to be consistent, "
"so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures."
"Remember to convert serialized sizes to weight units when necessary."},
+ },
+ },
},
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {"input_sizes", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Inputs and their corresponding sizes", | |
| { | |
| {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, | |
| {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"}, | |
| {"size", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum size for this input, " | |
| "including the size of the outpoint and sequence number. " | |
| "Note that serialized signature sizes are not guaranteed to be consistent, " | |
| "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures." | |
| "Remember to convert serialized sizes to weight units when necessary."}, | |
| }, | |
| }, | |
| {"input_sizes", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Inputs and their corresponding sizes", | |
| { | |
| {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", | |
| { | |
| {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, | |
| {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"}, | |
| {"size", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum size for this input, " | |
| "including the size of the outpoint and sequence number. " | |
| "Note that serialized signature sizes are not guaranteed to be consistent, " | |
| "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures." | |
| "Remember to convert serialized sizes to weight units when necessary."}, | |
| }, | |
| }, | |
| }, | |
| }, |
🤖 Prompt for AI Agents
In src/wallet/rpc/spend.cpp around lines 643 to 653, the RPCArg for
"input_sizes" currently lists "txid", "vout" and "size" as direct children of
the array but they must be defined as members of an object because the expected
input is an array of objects like [{"txid":...,"vout":...,"size":...},...].
Change the array element spec to be an object (RPCArg::Type::OBJ) and move
"txid", "vout" and "size" into that object's children with their current types
and descriptions, keeping the same optional/required flags and text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@coderabbitai, compare this code as backported - minimal improvisation. Is there indeed bug or you propose an improvement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for the upstream Bitcoin Core PR #23201 and #25551 to check the input_sizes documentation structure
# Let's search in the repository's git history for the relevant commits
# First, let's check if there are any references to these Bitcoin PRs in the commit messages
git log --all --grep="23201\|25551" --oneline | head -20
# Let's also search for the input_sizes RPC argument in the codebase to see how it's structured
rg -n "input_sizes.*RPCArg::Type::ARR" --type=cpp -A 15
Length of output: 3620
🌐 Web query:
Bitcoin Core PR 23201 input_sizes RPC documentation structure
💡 Result:
I can look that up — can you share a link to PR bitcoin#23201 (or tell me which repository/org it's in)? I couldn't find a matching GitHub PR or an "input_sizes" RPC with the information given.
🌐 Web query:
site:github.com bitcoin/bitcoin pull 23201 input_sizes
💡 Result:
Found Pull Request bitcoin#23201 on the bitcoin/bitcoin repo:
- Title: "wallet: Allow users to specify input weights when funding a transaction" — author achow101. [1][2]
Sources:
[1] bitcoin-irc log referencing the PR. [2] Bitcoin Core PR Review Club notes for bitcoin#23201.
🏁 Script executed:
#!/bin/bash
# Let's fetch the Bitcoin Core repository to compare the exact structure
# First, check if we can find the upstream commit that added input_sizes
# Look for the commit that added input_sizes in the Dash repository
git log --all --grep="23201" --format="%H %s" | head -5
# Get one of the commits that mentions this PR
COMMIT_HASH=$(git log --all --grep="23201" --oneline | grep "Allow users to specify input weights" | head -1 | cut -d' ' -f1)
echo "Examining commit: $COMMIT_HASH"
# Show the diff for the fundrawtransaction RPC documentation in that commit
git show $COMMIT_HASH -- src/wallet/rpc/spend.cpp | grep -A 20 "input_sizes.*RPCArg::Type::ARR" || echo "Not found in this commit"
# Let's also check the current Bitcoin Core master branch structure
# We'll use curl to fetch the file from GitHub
curl -s "https://raw.githubusercontent.com/bitcoin/bitcoin/master/src/wallet/rpc/spend.cpp" | grep -A 20 "input_weights.*RPCArg::Type::ARR" || echo "Checking input_weights pattern"
Length of output: 4316
🏁 Script executed:
#!/bin/bash
# Let's check the actual upstream Bitcoin Core PR #23201 to see the original structure
# Fetch the specific file from the merge commit or the PR branch
# Let's get the Bitcoin Core commit from their repo
curl -s "https://raw.githubusercontent.com/bitcoin/bitcoin/b544010a712c3fa92ad73bf0bf785e1a6b53a15d/src/wallet/rpc/spend.cpp" | grep -B 2 -A 20 "input_weights.*RPCArg::Type::ARR" | head -30
echo "---"
echo "Now checking if Dash has input_weights anywhere:"
rg -n "input_weights" src/wallet/rpc/spend.cpp || echo "Not found - this is the dashification part (input_weights renamed to input_sizes)"
Length of output: 134
🏁 Script executed:
#!/bin/bash
# Let's check Bitcoin Core's current master for fundrawtransaction to see the input_weights structure
curl -s "https://raw.githubusercontent.com/bitcoin/bitcoin/master/src/wallet/rpc/spend.cpp" > /tmp/bitcoin_spend.cpp
# Search for fundrawtransaction and input_weights in the Bitcoin Core file
grep -A 100 "RPCHelpMan fundrawtransaction" /tmp/bitcoin_spend.cpp | grep -B 5 -A 15 "input_weights" | head -40
echo "========================================"
echo "Now let's check the walletcreatefundedpsbt for comparison:"
grep -A 150 "RPCHelpMan walletcreatefundedpsbt" /tmp/bitcoin_spend.cpp | grep -B 5 -A 15 "inputs.*RPCArg::Type::ARR" | head -50
Length of output: 3776
@knst, I've compared with the upstream Bitcoin Core code and this is indeed a bug in the backport, not just an improvement suggestion.In the upstream Bitcoin Core PR bitcoin#23201, the wallet RPCs send, walletcreatefundedpsbt, and fundrawtransaction add support for specifying the weights of external inputs. When I checked the actual Bitcoin Core code structure:
In Bitcoin Core's fundrawtransaction:
{"input_weights", RPCArg::Type::ARR, ...,
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", // ← OBJ wrapper present
{
{"txid", RPCArg::Type::STR_HEX, ...},
{"vout", RPCArg::Type::NUM, ...},
{"weight", RPCArg::Type::NUM, ...},
},
},
},
}In Dash's current code (this PR):
{"input_sizes", RPCArg::Type::ARR, ...,
{
{"txid", RPCArg::Type::STR_HEX, ...}, // ← Missing OBJ wrapper
{"vout", RPCArg::Type::NUM, ...},
{"size", RPCArg::Type::NUM, ...},
},
}The Dash backport renamed input_weights → input_sizes and weight → size, but failed to preserve the intermediate OBJ structure from the upstream code. This is a structural bug in the backport, not just a style improvement.
The correct structure should have the empty-string OBJ element wrapping the fields, as CodeRabbit suggested. This matches how Bitcoin Core structures similar array-of-objects parameters (like inputs in walletcreatefundedpsbt).
Recommendation: Apply the CodeRabbit suggestion to fix the backport bug and match the upstream structure.
🐰✨
🧬 Code Graph Analysis Results
[src/wallet/spend.cpp] lines 1093-1140
- Summary: CreateTransaction
- Parameters:
- CWallet& wallet: wallet instance.
- const std::vector& vecSend: recipients to send to.
- int change_pos: preferred change output position.
- const CCoinControl& coin_control: coin selection and spending constraints.
- bool sign: whether to sign the transaction.
- int nExtraPayloadSize: extra payload space for signing data.
- Returns: util::Result
- Behavior:
- Validates inputs (must have at least one recipient; amounts non-negative).
- Locks the wallet and invokes internal transaction creation.
- Logs tracing information about fee and change position.
- If creation fails, returns an error via util::Error or propagates the failure.
- On success, returns the created transaction and associated metadata.
- Errors/Edge cases:
- If the result is empty (creation failed), returns that failure.
- Uses internal fee/change_pos, and may choose different internal flows (e.g., APS) depending on results.
- Parameters:
[src/wallet/spend.cpp] lines 1142-1218
- Summary: FundTransaction
- Parameters:
- CWallet& wallet: wallet instance.
- CMutableTransaction& tx: the mutable transaction being funded (inputs/outputs may be updated).
- CAmount& fee_out: output parameter for the fee estimated.
- int& change_position: output parameter for the chosen change output position.
- const UniValue& options: options for funding (inputs, change, fee rate, etc.).
- CCoinControl& coinControl: coin control to be configured for funding.
- bool override_min_fee: whether to override minimum fee requirements.
- Returns: bool
- Behavior:
- If options are provided, validates keys and compatibility (e.g., feeRate vs fee_rate, conf_target vs fee_rate, etc.).
- Parses options such as change address, change position, include_watching, inputs, etc.
- Applies fee estimation mode via SetFeeEstimateMode.
- Calls into internal funding logic to select inputs/outputs and adjust the transaction.
- If funding succeeds, modifies tx accordingly and sets fee_out/change_position.
- Errors/Edge cases:
- Returns false and sets error via bilingual_str if funding fails (in caller context).
- Ensures compatibility between various fee-related options to avoid conflicts.
- Parameters:
[src/wallet/rpc/spend.cpp] lines ~SetFeeEstimateMode function (in same file)
- Summary: SetFeeEstimateMode
- Parameters:
- const CWallet& wallet: wallet instance.
- CCoinControl& cc: coin control to update with fee estimation settings.
- const UniValue& conf_target: optional confirmation target (blocks).
- const UniValue& estimate_mode: optional string mode ("unset", "economical", "conservative").
- const UniValue& fee_rate: optional explicit fee rate (sat/vB or a rate value depending on context).
- bool override_min_fee: whether to set fOverrideFeeRate to true to bypass minimum fee checks.
- Returns: void
- Behavior:
- If fee_rate is provided:
- Rejects if conf_target or estimate_mode are also provided (mutually exclusive).
- Sets cc.m_feerate from fee_rate (3 significant digits) and enables fOverrideFeeRate if requested.
- Returns early.
- Otherwise, validates estimate_mode via FeeModeFromString and updates cc.m_fee_mode.
- If conf_target is provided, parses it into cc.m_confirm_target with proper bounds.
- If fee_rate is provided:
- Errors/Edge cases:
- Throws JSONRPCError(RPC_INVALID_PARAMETER, ...) for invalid combinations or invalid values.
- Parameters:
🧠 Learnings used
Learnt from: kwvg
Repo: dashpay/dash PR: 6530
File: src/validation.cpp:360-362
Timestamp: 2025-01-14T08:37:16.955Z
Learning: The UpdateTransactionsFromBlock() method in txmempool.cpp takes parameters in the order: vHashUpdate, ancestor_size_limit, ancestor_count_limit. The size limit comes before the count limit.
Learnt from: knst
Repo: dashpay/dash PR: 6916
File: src/univalue/include/univalue.h:81-88
Timestamp: 2025-10-25T07:08:51.918Z
Learning: For backport PRs from bitcoin/bitcoin, bitcoin-core/gui, etc., backported changes should match the original upstream PRs even if they appear strange, modify vendored code, or seem to violate coding guidelines. Still flag genuine issues like bugs, undefined behavior, crashes, compilation errors, or linter failures.
Learnt from: knst
Repo: dashpay/dash PR: 6805
File: src/wallet/rpc/wallet.cpp:357-357
Timestamp: 2025-08-08T07:01:47.332Z
Learning: In src/wallet/rpc/wallet.cpp, the upgradetohd RPC now returns a UniValue string message (RPCResult::Type::STR) instead of a boolean, including guidance about mnemonic backup and null-character passphrase handling; functional tests have been updated to assert returned strings in several cases.
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: knst
Repo: dashpay/dash PR: 6883
File: src/rpc/rawtransaction.cpp:1088-1125
Timestamp: 2025-10-13T12:37:12.357Z
Learning: In backport pull requests (especially from Bitcoin Core), treat "moved" or refactored code as out-of-scope for content-level review. Focus validation on verifying that code is moved correctly: no fields added, no fields removed, no fields reordered, and no unexpected changes beyond whitespace adjustments. Pre-existing issues in the upstream code should be preserved to maintain fidelity to the original implementation.
Learnt from: knst
Repo: dashpay/dash PR: 6871
File: contrib/guix/libexec/build.sh:358-360
Timestamp: 2025-10-05T20:38:28.457Z
Learning: In the Dash repository, when backporting code from Bitcoin Core, typos and minor issues in comments should be kept as-is to reduce merge conflicts in future backports, even if they remain unfixed in Bitcoin Core's master branch.
Learnt from: PastaPastaPasta
Repo: dashpay/dash PR: 6804
File: src/qt/proposalwizard.cpp:40-42
Timestamp: 2025-08-11T17:16:36.654Z
Learning: In the Dash repository, when a PR adds new files that are not from Bitcoin backports, these files must be added to the list in test/util/data/non-backported.txt. This applies to newly created files like qt/proposalwizard.{h,cpp} and forms/proposalwizard.ui. Limited exemptions may exist for subtrees and similar cases.
…n funding a transaction 3866272 tests: Test specifying input weights (Andrew Chow) 6fa762a rpc, wallet: Allow users to specify input weights (Andrew Chow) 808068e wallet: Allow user specified input size to override (Andrew Chow) 4060c50 wallet: add input weights to CCoinControl (Andrew Chow) Pull request description: When funding a transaction with external inputs, instead of providing solving data, a user may want to just provide the maximum signed size of that input. This is particularly useful in cases where the input is nonstandard as our dummy signer is unable to handle those inputs. The input weight can be provided to any input regardless of whether it belongs to the wallet and the provided weight will always be used regardless of any calculated input weight. This allows the user to override the calculated input weight which may overestimate in some circumstances due to missing information (e.g. if the private key is not known, a maximum size signature will be used, but the actual signer may be doing additional work which reduces the size of the signature). For `send` and `walletcreatefundedpsbt`, the input weight is specified in a `weight` field in an input object. For `fundrawtransaction`, a new `input_weights` field is added to the `options` object. This is an array of objects consisting of a txid, vout, and weight. Closes bitcoin#23187 ACKs for top commit: instagibbs: reACK bitcoin@3866272 glozow: reACK 3866272 via range-diff t-bast: ACK bitcoin@3866272 Tree-SHA512: 2c8b471ee537c62a51389b7c4e86b5ac1c3a223b444195042be8117b3c83e29c0619463610b950cbbd1648d3ed01ecc5bb0b3c4f39640680da9157763b9b9f9f
…shes over silent ignore fa277cd univalue: Throw exception on invalid pushes over silent ignore (MacroFake) ccccc17 refactor: Default options in walletcreatefundedpsbt to VOBJ instead of VNULL (MacroFake) Pull request description: The return value of the `push*` helpers is never used, but important to determine if the operation was successful. One way to fix this would be to add the "nodiscard" attribute. However, this would make the code (and this diff) overly verbose for no reason. So fix it by removing the never used return value. Also, fail verbosely in case of a programming mistake. ACKs for top commit: furszy: code ACK fa277cd Tree-SHA512: ef212a5bf5ae6bbad20acc4dafa3715521e81544185988d1eab724f440e4864a27e686aff51d5bc51b3017892c2eb8e577bcb8f37e8ddbaa0d8833bb622f2f9c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/wallet/rpc/spend.cpp (1)
643-653: RPC documentation structure matches backport pattern.Per the past review discussion and retrieved learnings, backported changes should match the original upstream PRs. This RPC argument structure for
input_sizesfollows the same pattern used in Bitcoin Core's implementation. Based on learnings, backported code should be preserved as-is unless there are genuine bugs.
🧹 Nitpick comments (2)
test/functional/wallet_send.py (1)
542-542: Use string literal for Decimal to avoid floating-point precision issues.Per static analysis hint (RUF032),
Decimal()should be called with a string literal instead of a float literal to avoid potential floating-point representation issues.- assert_fee_amount(testres["fees"]["base"], testres["vsize"], Decimal(0.0001)) + assert_fee_amount(testres["fees"]["base"], testres["vsize"], Decimal("0.0001"))test/functional/rpc_fundrawtransaction.py (1)
1027-1027: Use string literal for Decimal to avoid floating-point precision issues.Per static analysis hint (RUF032),
Decimal()should be called with a string literal instead of a float literal.- assert_fee_amount(funded_tx4["fee"], tx4_size, Decimal(0.0001)) + assert_fee_amount(funded_tx4["fee"], tx4_size, Decimal("0.0001"))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/wallet/coincontrol.h(2 hunks)src/wallet/rpc/spend.cpp(9 hunks)src/wallet/spend.cpp(1 hunks)src/wallet/test/spend_tests.cpp(1 hunks)src/wallet/wallet.cpp(2 hunks)src/wallet/wallet.h(1 hunks)test/functional/rpc_fundrawtransaction.py(3 hunks)test/functional/rpc_psbt.py(3 hunks)test/functional/wallet_send.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- src/wallet/wallet.h
- src/wallet/wallet.cpp
- src/wallet/spend.cpp
- src/wallet/test/spend_tests.cpp
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{cpp,h,hpp,cc}
📄 CodeRabbit inference engine (CLAUDE.md)
Dash Core implementation must be written in C++20, requiring at least Clang 16 or GCC 11.1
Files:
src/wallet/rpc/spend.cppsrc/wallet/coincontrol.h
src/wallet/**/*.{cpp,h}
📄 CodeRabbit inference engine (CLAUDE.md)
Wallet implementation must use Berkeley DB and SQLite
Files:
src/wallet/rpc/spend.cppsrc/wallet/coincontrol.h
test/functional/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Functional tests in test/functional/ must be written in Python (minimum version specified in .python-version) and depend on dashd and dash-node
Files:
test/functional/rpc_fundrawtransaction.pytest/functional/rpc_psbt.pytest/functional/wallet_send.py
🧠 Learnings (8)
📓 Common learnings
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: knst
Repo: dashpay/dash PR: 6916
File: src/univalue/include/univalue.h:81-88
Timestamp: 2025-10-25T07:08:51.918Z
Learning: For backport PRs from bitcoin/bitcoin, bitcoin-core/gui, etc., backported changes should match the original upstream PRs even if they appear strange, modify vendored code, or seem to violate coding guidelines. Still flag genuine issues like bugs, undefined behavior, crashes, compilation errors, or linter failures.
Learnt from: knst
Repo: dashpay/dash PR: 6883
File: src/rpc/rawtransaction.cpp:1088-1125
Timestamp: 2025-10-13T12:37:12.357Z
Learning: In backport pull requests (especially from Bitcoin Core), treat "moved" or refactored code as out-of-scope for content-level review. Focus validation on verifying that code is moved correctly: no fields added, no fields removed, no fields reordered, and no unexpected changes beyond whitespace adjustments. Pre-existing issues in the upstream code should be preserved to maintain fidelity to the original implementation.
📚 Learning: 2025-08-08T07:01:47.332Z
Learnt from: knst
Repo: dashpay/dash PR: 6805
File: src/wallet/rpc/wallet.cpp:357-357
Timestamp: 2025-08-08T07:01:47.332Z
Learning: In src/wallet/rpc/wallet.cpp, the upgradetohd RPC now returns a UniValue string message (RPCResult::Type::STR) instead of a boolean, including guidance about mnemonic backup and null-character passphrase handling; functional tests have been updated to assert returned strings in several cases.
Applied to files:
src/wallet/rpc/spend.cpptest/functional/rpc_psbt.py
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,txmempool}/**/*.{cpp,h} : Block validation and mempool handling must use extensions to Bitcoin Core mechanisms for special transaction validation and enhanced transaction relay
Applied to files:
src/wallet/rpc/spend.cpp
📚 Learning: 2025-10-25T07:08:51.918Z
Learnt from: knst
Repo: dashpay/dash PR: 6916
File: src/univalue/include/univalue.h:81-88
Timestamp: 2025-10-25T07:08:51.918Z
Learning: For backport PRs from bitcoin/bitcoin, bitcoin-core/gui, etc., backported changes should match the original upstream PRs even if they appear strange, modify vendored code, or seem to violate coding guidelines. Still flag genuine issues like bugs, undefined behavior, crashes, compilation errors, or linter failures.
Applied to files:
src/wallet/rpc/spend.cpp
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,consensus,net_processing}/**/*.{cpp,h} : ValidationInterface callbacks must be used for event-driven architecture to coordinate subsystems during block/transaction processing
Applied to files:
src/wallet/rpc/spend.cpp
📚 Learning: 2025-01-14T08:37:16.955Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6530
File: src/validation.cpp:360-362
Timestamp: 2025-01-14T08:37:16.955Z
Learning: The UpdateTransactionsFromBlock() method in txmempool.cpp takes parameters in the order: vHashUpdate, ancestor_size_limit, ancestor_count_limit. The size limit comes before the count limit.
Applied to files:
src/wallet/rpc/spend.cpp
📚 Learning: 2025-06-09T16:43:20.996Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Applied to files:
test/functional/rpc_fundrawtransaction.pytest/functional/rpc_psbt.py
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/coinjoin/**/*.{cpp,h} : CoinJoin implementation must use masternode-coordinated mixing sessions with uniform denomination outputs
Applied to files:
src/wallet/coincontrol.h
🧬 Code graph analysis (3)
test/functional/rpc_fundrawtransaction.py (2)
test/functional/test_framework/util.py (4)
assert_raises_rpc_error(132-148)assert_equal(69-74)assert_greater_than(77-79)assert_fee_amount(44-52)src/wallet/rpc/spend.cpp (4)
fundrawtransaction(603-704)fundrawtransaction(603-603)signrawtransactionwithwallet(706-795)signrawtransactionwithwallet(706-706)
test/functional/rpc_psbt.py (2)
test/functional/test_framework/util.py (2)
assert_greater_than(77-79)assert_raises_rpc_error(132-148)test/functional/test_framework/test_node.py (1)
get_wallet_rpc(363-369)
src/wallet/coincontrol.h (4)
src/wallet/spend.cpp (1)
outpoint(150-150)src/wallet/wallet.cpp (1)
outpoint(1093-1093)src/wallet/interfaces.cpp (4)
outpoint(399-399)outpoint(399-399)outpoint(400-400)outpoint(400-400)src/wallet/coinjoin.cpp (2)
outpoint(510-510)outpoint(560-560)
🪛 Ruff (0.14.7)
test/functional/rpc_fundrawtransaction.py
1027-1027: Decimal() called with float literal argument
Replace with string literal
(RUF032)
test/functional/wallet_send.py
542-542: Decimal() called with float literal argument
Replace with string literal
(RUF032)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: linux64_multiprocess-build / Build source
- GitHub Check: linux64_tsan-build / Build source
- GitHub Check: win64-build / Build source
- GitHub Check: linux64_sqlite-build / Build source
- GitHub Check: linux64_ubsan-build / Build source
- GitHub Check: linux64_fuzz-build / Build source
- GitHub Check: linux64-build / Build source
- GitHub Check: mac-build / Build source
- GitHub Check: linux64_nowallet-build / Build source
- GitHub Check: arm-linux-build / Build source
🔇 Additional comments (15)
src/wallet/coincontrol.h (2)
132-147: LGTM! Clean API for per-input weight tracking.The three new methods follow a consistent pattern:
SetInputWeightto store,HasInputWeightto check existence, andGetInputWeightwith an assert precondition requiring callers to verify existence first. This matches the usage pattern insrc/wallet/spend.cppwhereHasInputWeightis always checked beforeGetInputWeight.
162-163: Comment accurately reflects Dash context.The comment notes "weight (equals to size)" which is correct for Dash since there's no segregated witness data, making weight equivalent to serialized size. This aligns with the PR description noting the backport differs from Bitcoin Core due to missing segregated-data stack handling.
src/wallet/rpc/spend.cpp (4)
5-5: New include is appropriate.The
consensus/validation.hinclude is needed forMAX_STANDARD_TX_SIZEused in the size validation at line 554.
531-560: Robust input_sizes validation logic.The parsing correctly validates:
txidviaParseHashOvoutpresence, type, and non-negativitysizepresence, minimum bound (41 bytes for outpoint + sequence + empty scriptSig), and maximum bound (MAX_STANDARD_TX_SIZE)The
CHECK_NONFATAL(min_input_size == 41)is a good compile-time sanity check ensuring the constant matches expectations.
586-601: SetOptionsInputWeights correctly enforces input specification location.The guard at line 588-590 prevents users from specifying
input_sizesin options when usingsendorwalletcreatefundedpsbt, enforcing that sizes must be specified inline with inputs. The function then extracts and consolidates size specifications from inputs into the options for downstream processing.
1174-1184: Correct integration in walletcreatefundedpsbt.The code properly:
- Creates a mutable copy of options if provided, or an empty object
- Calls
SetOptionsInputWeightsto extract per-input sizes from the inputs array- Passes the enriched options to
FundTransactiontest/functional/wallet_send.py (2)
506-514: Input weight calculation logic looks correct.The code correctly:
- Decodes the PSBT to find the external input
- Locates the matching input by txid/vout
- Calculates
input_weight = 41 + len_scriptsig - 1where 41 is the base input size (outpoint + sequence + 1-byte scriptSig length), and the -1 compensates for the length byte already included in the base.
517-523: Good coverage for error path.The test correctly verifies that specifying
input_sizesin the options object (rather than inline with inputs) raises the expected RPC error with code -8.test/functional/rpc_fundrawtransaction.py (3)
980-985: Comprehensive error path coverage for input_sizes validation.The tests cover all validation scenarios:
- Missing vout key
- Negative vout
- Missing size key
- Size below minimum (40, -1)
- Size above maximum (400001)
1000-1006: Input weight calculation is well-documented.The calculation
input_weight = signed_weight - unsigned_weight + 41correctly derives the input's signing overhead by comparing signed vs unsigned transaction sizes, then adding back the base input components (prevout, sequence, 1-byte scriptSig length).
1030-1031: Good boundary testing for CompactSize encoding.Testing at sizes 255 and 65539 validates correct handling at CompactSize encoding boundaries (1-byte to 3-byte, and 3-byte to 5-byte transitions), ensuring the weight serialization doesn't have off-by-one issues at these thresholds.
test/functional/rpc_psbt.py (4)
17-17: Import added for new assertion.The
assert_greater_thanimport is needed for the fee comparison assertions in the new weight-based tests.
515-521: Input weight formula includes witness handling (safely degenerates for Dash).The formula
input_weight = ((41 + len_scriptsig + 2) * 4) + len_scriptwitnessis designed for Bitcoin's witness weight calculation. For Dash (no SegWit),len_scriptwitnesswill always be 0, and the formula correctly computes the input weight as(41 + len_scriptsig + 2) * 4. The +2 buffer provides margin for signature size variance.
523-531: Error path test for options-based input_sizes.Consistent with wallet_send.py, this test verifies that specifying
input_sizesin the options object raises RPC error -8 with the expected message.
533-577: Comprehensive PSBT weight-based funding tests.The tests cover:
- Funding with exact input weight → mempool acceptance
- Lower weight → lower fee (line 549)
- Higher weight → higher fee (line 556)
- Provided weight overrides solving_data calculated weight (line 563)
- Wallet inputs also respect provided weights after descriptor import (lines 566-577)
This provides excellent coverage of the new input weight functionality.
Issue being fixed or feature implemented
When funding a transaction with external inputs, instead of providing solving data, a user may want to just provide the maximum signed size of that input. This is particularly useful in cases where the input is nonstandard as our dummy signer is unable to handle those inputs.
The input size can be provided to any input regardless of whether it belongs to the wallet and the provided size will always be used regardless of any calculated input size. This allows the user to override the calculated input size which may overestimate in some circumstances due to missing information (e.g. if the private key is not known, a maximum size signature will be used, but the actual signer may be doing additional work which reduces the size of the signature).
For
sendandwalletcreatefundedpsbt, the input size is specified in asizefield in an input object. Forfundrawtransaction, a newinput_sizesfield is added to theoptionsobject. This is an array of objects consisting of a txid, vout, and size.What was done?
Bitcoin backport bitcoin#23201 and related fixes.
This backport is not trivial to do, not trivial to dashify, and not trivial to review, so, it has own PR.
Please note, that implementation of
FillInputToWeightis different with Bitcoin Core. Due missing stack of "segregated data" we can't get exactly the same size, it maybe different up to 2 bytes.How Has This Been Tested?
Run unit & functional tests
Breaking Changes
N/A
Checklist: