rpc: Better error messages for invalid addresses #20832

pull eilx2 wants to merge 1 commits into bitcoin:master from eilx2:master changing 7 files +141 −14
  1. eilx2 commented at 1:12 am on January 3, 2021: none

    This PR addresses #20809.

    We add more detailed error messages in case an invalid address is provided inside the ‘validateaddress’ and ‘getaddressinfo’ RPC calls. This also covers the case when a user provides an address from a wrong network.

    We also add a functional test to test the new error messages.

  2. eilx2 commented at 1:14 am on January 3, 2021: none
    Tagging @instagibbs as requested.
  3. DrahtBot added the label RPC/REST/ZMQ on Jan 3, 2021
  4. DrahtBot added the label Utils/log/libs on Jan 3, 2021
  5. DrahtBot added the label Wallet on Jan 3, 2021
  6. MarcoFalke deleted a comment on Jan 3, 2021
  7. in src/key_io.cpp:153 in a913ee945c outdated
    149         }
    150     }
    151+
    152+    // Set error message if address can't be interpreted neither as Base58 nor Bech32.
    153+    if (error_str.empty())
    154+        error_str = "Invalid address format";
    


    jonatack commented at 11:27 am on January 3, 2021:

    See doc/developer-notes.md:

    If an `if` only has a single-statement `then`-clause, it can appear
    on the same line as the `if`, without braces. In every other case,
    braces are required, and the `then` and `else` clauses must appear
    correctly indented on a new line.
  8. in src/wallet/rpcwallet.cpp:3832 in a913ee945c outdated
    3830+
    3831     // Make sure the destination is valid
    3832     if (!IsValidDestination(dest)) {
    3833-        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
    3834+        if (error_msg.empty())
    3835+            error_msg = "Invalid address";
    


    jonatack commented at 11:28 am on January 3, 2021:
    Idem as previous comment about conditional formatting
  9. in src/rpc/misc.cpp:43 in a913ee945c outdated
    39@@ -40,6 +40,7 @@ static RPCHelpMan validateaddress()
    40                     RPCResult::Type::OBJ, "", "",
    41                     {
    42                         {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not. If not, this is the only property returned."},
    43+                        {RPCResult::Type::STR, "error_msg", "If the address is not valid this property contains a description of the error encountered while decoding the address."},
    


    jonatack commented at 11:33 am on January 3, 2021:

    suggestion

     0@@ -40,13 +40,13 @@ static RPCHelpMan validateaddress()
     1                     RPCResult::Type::OBJ, "", "",
     2                     {
     3                         {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not. If not, this is the only property returned."},
     4-                        {RPCResult::Type::STR, "error_msg", "If the address is not valid this property contains a description of the error encountered while decoding the address."},
     5                         {RPCResult::Type::STR, "address", "The bitcoin address validated"},
     6                         {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address"},
     7                         {RPCResult::Type::BOOL, "isscript", "If the key is a script"},
     8                         {RPCResult::Type::BOOL, "iswitness", "If the address is a witness address"},
     9                         {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"},
    10                         {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"},
    11+                        {RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"},
    12                     }
    
    • add optional indication and move after the other optional result field
    • simpler standard description
    • “error” seems to be the generally used error field name in this api (see src/wallet/rpcwallet.cpp::L4485
  10. in src/rpc/misc.cpp:42 in a913ee945c outdated
    39@@ -40,6 +40,7 @@ static RPCHelpMan validateaddress()
    40                     RPCResult::Type::OBJ, "", "",
    41                     {
    42                         {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not. If not, this is the only property returned."},
    


    jonatack commented at 11:38 am on January 3, 2021:

    this description needs to be updated (can remove trailing full stop too, like the other descriptions here)

    0                        {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
    
  11. in src/rpc/misc.cpp:74 in a913ee945c outdated
    69@@ -69,7 +70,10 @@ static RPCHelpMan validateaddress()
    70 
    71         UniValue detail = DescribeAddress(dest);
    72         ret.pushKVs(detail);
    73+    } else {
    74+        ret.pushKV("error_msg", error_msg);
    


    jonatack commented at 11:40 am on January 3, 2021:

    suggestion

    0-        ret.pushKV("error_msg", error_msg);
    1+        CHECK_NONFATAL(!error_msg.empty());
    2+        ret.pushKV("error", error_msg);
    
  12. in src/key_io.cpp:96 in a913ee945c outdated
    90@@ -89,10 +91,19 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
    91             std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
    92             return ScriptHash(hash);
    93         }
    94+
    95+        // Set potential error message.
    96+        // This message may be changed in case that the address can also be interpreted as a Bech32 address.
    


    jonatack commented at 11:50 am on January 3, 2021:
    0        // This message may be changed if the address can also be interpreted as a Bech32 address.
    
  13. in src/key_io.cpp:151 in a913ee945c outdated
    147             unk.length = data.size();
    148             return unk;
    149         }
    150     }
    151+
    152+    // Set error message if address can't be interpreted neither as Base58 nor Bech32.
    


    jonatack commented at 11:54 am on January 3, 2021:
    0    // Set error message if address can't be interpreted as Base58 or Bech32.
    
  14. in src/key_io.cpp:142 in a913ee945c outdated
    138+            if (data.size() < 2 || data.size() > 40) {
    139+                error_str = "Invalid Bech32 address data size";
    140                 return CNoDestination();
    141             }
    142+
    143+
    


    jonatack commented at 11:56 am on January 3, 2021:
    nit, remove extra line break here
  15. in src/key_io.cpp:254 in a913ee945c outdated
    250-    return DecodeDestination(str, Params());
    251+    std::string error_msg;
    252+    return DecodeDestination(str, error_msg);
    253 }
    254 
    255+
    


    jonatack commented at 11:57 am on January 3, 2021:
    nit, remove extra line break here
  16. in src/key_io.cpp:247 in a913ee945c outdated
    238@@ -212,14 +239,23 @@ std::string EncodeDestination(const CTxDestination& dest)
    239     return boost::apply_visitor(DestinationEncoder(Params()), dest);
    240 }
    241 
    242+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
    243+{
    244+    return DecodeDestination(str, Params(), error_msg);
    245+}
    246+
    247+
    


    jonatack commented at 11:57 am on January 3, 2021:
    nit, remove extra line break here
  17. jonatack commented at 12:06 pm on January 3, 2021: member
    Concept ACK, builds cleanly and works. A few suggestions follow.
  18. eilx2 force-pushed on Jan 3, 2021
  19. eilx2 force-pushed on Jan 3, 2021
  20. eilx2 force-pushed on Jan 3, 2021
  21. eilx2 force-pushed on Jan 3, 2021
  22. eilx2 commented at 11:11 pm on January 3, 2021: none

    Thanks a lot for the review! I’ve made the proposed changes.

    In addition, I’ve realized that DecodeDestination is used in other places too which return a generic ‘invalid address’ error message in case if fails. Should we also handle those places as part of this PR?

  23. in src/rpc/misc.cpp:74 in f1c7aea502 outdated
    69@@ -69,7 +70,11 @@ static RPCHelpMan validateaddress()
    70 
    71         UniValue detail = DescribeAddress(dest);
    72         ret.pushKVs(detail);
    73+    } else {
    74+        CHECK_NONFATAL(!error_msg.empty());
    


    jonatack commented at 11:54 pm on January 3, 2021:

    nit, might be better like this, just realized I’m doing the same here

     0@@ -57,7 +57,8 @@ static RPCHelpMan validateaddress()
     1 {
     2     std::string error_msg;
     3     CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
     4-    bool isValid = IsValidDestination(dest);
     5+    const bool isValid = IsValidDestination(dest);
     6+    CHECK_NONFATAL(isValid == error_msg.empty());
     7 
     8     UniValue ret(UniValue::VOBJ);
     9     ret.pushKV("isvalid", isValid);
    10@@ -71,7 +72,6 @@ static RPCHelpMan validateaddress()
    11         UniValue detail = DescribeAddress(dest);
    12         ret.pushKVs(detail);
    13     } else {
    14-        CHECK_NONFATAL(!error_msg.empty());
    15         ret.pushKV("error", error_msg);
    16     }
    
  24. fanquake requested review from instagibbs on Jan 4, 2021
  25. in test/functional/rpc_invalid_address_message.py:14 in f1c7aea502 outdated
     9+from test_framework.util import (
    10+    assert_equal,
    11+    assert_raises_rpc_error,
    12+)
    13+
    14+bech32_valid = 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
    


    instagibbs commented at 6:25 am on January 4, 2021:
    micro-nit: constants can be in ALL_CAPS
  26. in src/key_io.cpp:134 in f1c7aea502 outdated
    130                 return CNoDestination();
    131             }
    132-            if (version > 16 || data.size() < 2 || data.size() > 40) {
    133+
    134+            if (version > 16) {
    135+                error_str = "Invalid Bech32 address version";
    


    instagibbs commented at 6:32 am on January 4, 2021:
    suggested: “Invalid Bech32 address witness version” to clarify what thing’s version is wrong
  27. instagibbs approved
  28. instagibbs commented at 6:37 am on January 4, 2021: member

    ACK

    Take or leave the suggested changes, test coverage of various paths is nice.

  29. in src/key_io.cpp:138 in f1c7aea502 outdated
    134+            if (version > 16) {
    135+                error_str = "Invalid Bech32 address version";
    136                 return CNoDestination();
    137             }
    138+
    139+            if (data.size() < 2 || data.size() > 40) {
    


    jonasschnelli commented at 8:11 am on January 4, 2021:
    maybe use a constant (maybe WITHNESS_PROG_MAX_LEN) instead of a magic 40
  30. in src/wallet/rpcwallet.cpp:3829 in f1c7aea502 outdated
    3829+    CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
    3830+
    3831     // Make sure the destination is valid
    3832     if (!IsValidDestination(dest)) {
    3833-        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
    3834+        if (error_msg.empty()) error_msg = "Invalid address";
    


    jonasschnelli commented at 8:14 am on January 4, 2021:
    Maybe a comment why this can happen and why it’s not caught in DecodeDestination()?

    eilx2 commented at 12:07 pm on January 4, 2021:
    I added an additional check in case someone changes the DecodeDestination method in the future and forgets to set the error_msg. I’ve added a comment explaining this.
  31. jonasschnelli approved
  32. jonasschnelli commented at 8:15 am on January 4, 2021: contributor
    code review ACK f1c7aea502494055fd87b9335e786f151564a49c (modulo nitpicks).
  33. eilx2 force-pushed on Jan 4, 2021
  34. eilx2 force-pushed on Jan 4, 2021
  35. eilx2 commented at 2:56 pm on January 4, 2021: none

    Thanks again for the comments.

    I think for now I’ll let this PR cover only ‘getaddressinfo’ and ‘validateaddress’ just to keep it small enough. In the future I will work on the other code paths.

  36. in src/key_io.h:16 in 11de868a3d outdated
    12@@ -13,6 +13,8 @@
    13 
    14 #include <string>
    15 
    16+const std::size_t WITNESS_PROG_MAX_LEN = 40;
    


    jonatack commented at 3:41 pm on January 4, 2021:

    nit if you retouch (and maybe move to key_io.cpp if we only expect to use it there, I’m not sure what is preferred)

    0static constexpr std::size_t WITNESS_PROG_MAX_LEN = 40;
    

    eilx2 commented at 4:39 pm on January 4, 2021:
    Good point, I moved it inside key_io.cpp
  37. jonatack commented at 3:46 pm on January 4, 2021: member

    Almost-ACK 11de868a3d3e393e1fde4e5f45232ad5b8c94324

    The new test file test/functional/rpc_invalid_address_message.py has the wrong file permissions.

  38. eilx2 force-pushed on Jan 4, 2021
  39. jonatack commented at 5:43 pm on January 4, 2021: member
    ACK f58a4ed145f79ea3c62c3929647db6a4ee193a8c
  40. DrahtBot commented at 6:03 pm on January 4, 2021: member

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

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #20861 (Implement Bech32m and use it for v1+ segwit addresses by sipa)

    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.

  41. alizeyni approved
  42. fanquake deleted a comment on Jan 5, 2021
  43. in src/key_io.cpp:19 in f58a4ed145 outdated
    14@@ -15,6 +15,9 @@
    15 #include <string.h>
    16 #include <algorithm>
    17 
    18+/// Maximum witness length for Bech32 addresses.
    19+static constexpr std::size_t WITNESS_PROG_MAX_LEN = 40;
    


    luke-jr commented at 4:51 pm on January 6, 2021:
    Maybe this should have BECH32 in the var name?
  44. in src/rpc/misc.cpp:42 in f58a4ed145 outdated
    38@@ -39,13 +39,14 @@ static RPCHelpMan validateaddress()
    39                 RPCResult{
    40                     RPCResult::Type::OBJ, "", "",
    41                     {
    42-                        {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not. If not, this is the only property returned."},
    43+                        {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
    


    luke-jr commented at 4:58 pm on January 6, 2021:
    Maybe split up the two possible return cases like getrawmempool does?

    eilx2 commented at 1:51 am on January 24, 2021:
    Good idea, I will try to do this in a future commit where I address the other places where you need to return an error message for invalid address as they probably all require a similar change
  45. luke-jr approved
  46. luke-jr commented at 5:01 pm on January 6, 2021: member
    utACK, w/ a few nits
  47. felipsoarez commented at 2:08 pm on January 7, 2021: none
    ACK f58a4ed I have reviewed it and it looks OK
  48. instagibbs commented at 8:02 am on January 8, 2021: member
    4 ACKs, RFM imo
  49. kristapsk approved
  50. kristapsk commented at 5:00 pm on January 10, 2021: contributor
    ACK f58a4ed145f79ea3c62c3929647db6a4ee193a8c (I agree with @luke-jr comment about WITNESS_PROG_MAX_LEN constant name, but don’t think that’s too important). Apart from reviewing code and running test suite, made sure this does not break JoinMarket which uses getaddressinfo RPC.
  51. DrahtBot added the label Needs rebase on Jan 11, 2021
  52. Better error messages for invalid addresses
    This commit addresses #20809.
    
    We add an additional 'error' property in the result of 'validateaddress' in case the address is not valid that gives a short description of why the address in invalid. We also change the error message returned by 'getaddressinfo' in case the address is invalid.
    8f0b64fb51
  53. eilx2 force-pushed on Jan 24, 2021
  54. eilx2 commented at 1:52 am on January 24, 2021: none
    Thanks everyone for the review! I’ve rebased on the latest master so there are no more merge conflicts.
  55. DrahtBot removed the label Needs rebase on Jan 24, 2021
  56. kristapsk approved
  57. kristapsk commented at 9:41 am on January 24, 2021: contributor
    ACK 8f0b64fb513e8c6cdd1f115856100a4ef5afe23e
  58. meshcollider commented at 11:36 pm on January 25, 2021: contributor
    Code review ACK 8f0b64fb513e8c6cdd1f115856100a4ef5afe23e
  59. meshcollider merged this on Jan 26, 2021
  60. meshcollider closed this on Jan 26, 2021

  61. sidhujag referenced this in commit 1f9d20bd2a on Jan 26, 2021
  62. meshcollider added the label Needs release note on Jan 27, 2021
  63. MarcoFalke referenced this in commit c0b2ff7927 on May 22, 2021
  64. MarcoFalke referenced this in commit 46320ba72f on May 22, 2021
  65. luke-jr referenced this in commit 333927fa67 on Jun 27, 2021
  66. apoelstra referenced this in commit b42e7553ed on Aug 5, 2021
  67. apoelstra referenced this in commit c607835bad on Aug 18, 2021
  68. apoelstra referenced this in commit 64194498cf on Aug 30, 2021
  69. janus referenced this in commit 51dfbabb30 on Oct 24, 2021
  70. DrahtBot locked this on Aug 18, 2022
  71. fanquake removed the label Needs release note on Sep 15, 2022
  72. fanquake commented at 3:13 pm on September 15, 2022: member
    This change was part of 22.0, removing “Needs release note”.

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: 2024-12-18 15:12 UTC

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