wallet: accept uppercase addresses without amount in sendall #36375

pull FlashWayne wants to merge 1 commits into bitcoin:master from FlashWayne:fix-sendall-uppercase-address changing 2 files +22 −5
  1. FlashWayne commented at 5:47 PM on September 28, 2026: contributor

    sendall keeps the recipients that were given without an amount as the strings the user passed (spend.cpp:1399). Later it finds their outputs by comparing against EncodeDestination of each output script (spend.cpp:1564), which for bech32 is the canonical lowercase form.

    An address given in uppercase is valid bech32, and validateaddress and sendtoaddress accept it. In sendall it never matches, so its output keeps the placeholder amount of 0 and the call fails:

    sendall '["BCRT1Q..."]'
    error code: -8
    Specified output amount to bcrt1q... is below dust threshold.
    

    This stores the decoded destinations of those addresses instead and compares them with the destinations of the outputs, so the match doesn't depend on how the address was written. Invalid addresses are still rejected later when the transaction is constructed.

    The new sendall_uppercase_address in wallet_sendall.py sweeps the wallet to the uppercase form of an address. It fails on master with the dust error above and passes with the fix. wallet_send.py still passes.

  2. DrahtBot added the label Wallet on Sep 28, 2026
  3. DrahtBot commented at 5:47 PM on September 28, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/36375.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

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

    Type Reviewers
    ACK polespinasa, maflcko, 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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. furszy commented at 6:32 PM on September 28, 2026: member

    you are fast

  5. polespinasa commented at 7:05 PM on September 28, 2026: member

    Concept~0

    If we are doing this, maybe a better way would be to store CTxDestinations directly in the std::set so you can avoid Encode - Decode multiple times:

    $ git diff
    diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
    index 1e85412c58..8a34b97b3d 100644
    --- a/src/wallet/rpc/spend.cpp
    +++ b/src/wallet/rpc/spend.cpp
    @@ -1387,7 +1387,7 @@ RPCMethod sendall()
                 PreventOutdatedOptions(options);
     
     
    -            std::set<std::string> addresses_without_amount;
    +            std::set<CTxDestination> addresses_without_amount;
                 UniValue recipient_key_value_pairs(UniValue::VARR);
                 const UniValue& recipients{request.params[0]};
                 for (unsigned int i = 0; i < recipients.size(); ++i) {
    @@ -1396,9 +1396,9 @@ RPCMethod sendall()
                         UniValue rkvp(UniValue::VOBJ);
                         rkvp.pushKV(recipient.get_str(), 0);
                         recipient_key_value_pairs.push_back(std::move(rkvp));
    -                    // Store the canonical encoding, so it matches the outputs below
    +                    // Store the decoded destination, so it matches the outputs below
                         // also when the address was given in another case (e.g. uppercase bech32)
    -                    addresses_without_amount.insert(EncodeDestination(DecodeDestination(recipient.get_str())));
    +                    addresses_without_amount.insert(DecodeDestination(recipient.get_str()));
                     } else {
                         recipient_key_value_pairs.push_back(recipient);
                     }
    @@ -1562,8 +1562,7 @@ RPCMethod sendall()
                 for (CTxOut& out : rawTx.vout) {
                     CTxDestination dest;
                     ExtractDestination(out.scriptPubKey, dest);
    -                std::string addr{EncodeDestination(dest)};
    -                if (addresses_without_amount.contains(addr)) {
    +                if (addresses_without_amount.contains(dest)) {
                         out.nValue = per_output_without_amount;
                         if (!gave_remaining_to_first) {
                             out.nValue += remainder % addresses_without_amount.size();
    @@ -1576,7 +1575,7 @@ RPCMethod sendall()
                     } else {
                         if (IsDust(out, pwallet->chain().relayDustFee())) {
                             // Specified output amount is dust
    -                        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Specified output amount to %s is below dust threshold.", addr));
    +                        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Specified output amount to %s is below dust threshold.", EncodeDestination(dest)));
                         }
                     }
                 }
    
    
  6. FlashWayne commented at 7:18 PM on September 28, 2026: contributor

    you are fast

    Cause I am flash ⚡😁

  7. wallet: accept uppercase addresses without amount in sendall
    sendall remembers the recipients given without an amount as the strings
    the user passed, and later finds their outputs by comparing against
    EncodeDestination of each output script, which is the canonical
    lowercase form for bech32. An address given in uppercase, which is
    valid bech32 and accepted by the rest of the wallet, never matches. Its
    output then keeps the placeholder amount of 0 and sendall fails with
    "Specified output amount to bcrt1q... is below dust threshold."
    
    Store the decoded destinations of those addresses instead and compare
    them with the destinations of the outputs, so the match no longer
    depends on how the address was written.
    df2994b14a
  8. FlashWayne force-pushed on Sep 28, 2026
  9. FlashWayne commented at 7:48 PM on September 28, 2026: contributor

    Thanks, that's cleaner. Taken as suggested in df2994b14a.

  10. polespinasa commented at 7:50 PM on September 28, 2026: member

    ACK df2994b14a4ba26c4ccebd6df4c24d8aaf22d851

  11. maflcko commented at 5:49 AM on September 29, 2026: member

    lgtm ACK df2994b14a4ba26c4ccebd6df4c24d8aaf22d851

  12. achow101 commented at 9:37 PM on September 29, 2026: member

    ACK df2994b14a4ba26c4ccebd6df4c24d8aaf22d851

  13. in src/wallet/rpc/spend.cpp:1400 in df2994b14a
    1395 | @@ -1396,7 +1396,9 @@ RPCMethod sendall()
    1396 |                      UniValue rkvp(UniValue::VOBJ);
    1397 |                      rkvp.pushKV(recipient.get_str(), 0);
    1398 |                      recipient_key_value_pairs.push_back(std::move(rkvp));
    1399 | -                    addresses_without_amount.insert(recipient.get_str());
    1400 | +                    // Store the decoded destination, so it matches the outputs below
    1401 | +                    // also when the address was given in another case (e.g. uppercase bech32)
    


    achow101 commented at 9:38 PM on September 29, 2026:

    This comment is unnecessary.

  14. achow101 merged this on Sep 29, 2026
  15. achow101 closed this on Sep 29, 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-18 10:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me