wallet: reject duplicate inputs in sendall #36344

pull Bruce039 wants to merge 1 commits into bitcoin:master from Bruce039:fix-sendall-duplicate-inputs changing 2 files +23 −0
  1. Bruce039 commented at 9:57 AM on September 26, 2026: contributor

    sendall with the inputs option doesn't check for duplicates. Each listed input is added to total_input_value in the loop at spend.cpp:1472, so passing the same UTXO twice counts its value twice.

    On regtest, with a wallet that has a single 1 BTC UTXO:

    sendall '["<addr>"]' '{"inputs": [<utxo>, <utxo>]}'
    
    • the RPC returns complete: true
    • the committed tx has 2 inputs (the same outpoint twice) and one output of 1.99998230 BTC
    • it isn't in the mempool, and testmempoolaccept rejects it with bad-txns-inputs-duplicate
    • after that, listunspent is empty and getbalances shows nonmempool: -1.0 until the tx is abandoned

    send and walletcreatefundedpsbt aren't affected, because CCoinControl::Select removes duplicates.

    This rejects a duplicated input with Invalid parameter, duplicated input: <txid>:<vout> (RPC_INVALID_PARAMETER). The message matches what createrawtransaction says for duplicated addresses. The new sendall_fails_on_duplicate_input test fails on master ("No exception raised") and passes with the fix. wallet_send.py still passes.

  2. DrahtBot added the label Wallet on Sep 26, 2026
  3. DrahtBot commented at 9:57 AM on September 26, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    External sites

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    Concept ACK l0rinc
    Stale ACK achow101

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35302 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35302.svg"></sub> (Silent Payments: Sending (take 2) by Eunovo)

    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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. Bruce039 force-pushed on Sep 26, 2026
  5. DrahtBot added the label CI failed on Sep 26, 2026
  6. DrahtBot removed the label CI failed on Sep 26, 2026
  7. achow101 commented at 11:21 PM on September 29, 2026: member

    ACK c46a0b34fd06c874191cf880ba7082790b96c194

  8. in test/functional/wallet_sendall.py:257 in c46a0b34fd
     252 | +        utxo = self.wallet.listunspent()[0]
     253 | +
     254 | +        assert_raises_rpc_error(-8,
     255 | +                "Invalid parameter, duplicated input: {}:{}".format(utxo["txid"], utxo["vout"]),
     256 | +                self.wallet.sendall, recipients=[self.remainder_target], inputs=[utxo, utxo])
     257 | +        assert_equal(self.wallet.getbalances()["mine"]["untrusted_pending"], 0)
    


    l0rinc commented at 6:06 AM on October 18, 2026:

    The previous line correctly fails without the fix, but this assertion would pass before and after because the invalid transaction never enters the mempool - we should assert the affected wallet state instead.

    See my suggested alternative in https://github.com/l0rinc/bitcoin/pull/308/commits which demonstrates the full state transition by first characterizing the old behavior and then updating the expectations with the fix.


    Bruce039 commented at 10:50 AM on October 27, 2026:

    Thanks, you're right that the pending-balance check passed either way. 1beefce checks the wallet state instead: txcount and the nonmempool balance stay the same and the outpoint is still listed in listunspent. Without the fix the first two change (txcount +1, nonmempool -17) and the outpoint disappears.

  9. l0rinc changes_requested
  10. l0rinc commented at 6:08 AM on October 18, 2026: contributor

    Concept ACK

    The RPC-error assertion catches the missing rejection, but we should cover the reported wallet-state correction also - see inline suggestion.

  11. wallet: reject duplicate inputs in sendall
    sendall with the inputs option adds up the value of each listed input
    without checking for duplicates. When the same UTXO is given twice, the
    input value is counted twice, and the wallet builds, signs and commits
    a transaction that spends one outpoint twice and pays out twice its
    value. The RPC reports success, but the transaction is consensus-invalid
    (bad-txns-inputs-duplicate), and the coin disappears from listunspent
    until the transaction is abandoned.
    
    Reject duplicated inputs with an error, like createrawtransaction does
    for duplicated addresses.
    1beefce351
  12. Bruce039 force-pushed on Oct 27, 2026
  13. DrahtBot added the label CI failed on Oct 27, 2026
  14. DrahtBot removed the label CI failed on Oct 27, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-10-30 09:40 UTC