aboutsummaryrefslogtreecommitdiff
path: root/src/key_io.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/key_io.cpp')
-rw-r--r--src/key_io.cpp44
1 files changed, 32 insertions, 12 deletions
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 615f4c9312..3559f3a03d 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -76,12 +76,16 @@ public:
std::string operator()(const CNoDestination& no) const { return {}; }
};
-CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
+CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str, std::vector<int>* error_locations)
{
std::vector<unsigned char> data;
uint160 hash;
error_str = "";
- if (DecodeBase58Check(str, data, 21)) {
+
+ // Note this will be false if it is a valid Bech32 address for a different network
+ bool is_bech32 = (ToLower(str.substr(0, params.Bech32HRP().size())) == params.Bech32HRP());
+
+ if (!is_bech32 && DecodeBase58Check(str, data, 21)) {
// base58-encoded Bitcoin addresses.
// Public-key-hash-addresses have version 0 (or 111 testnet).
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
@@ -98,15 +102,30 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return ScriptHash(hash);
}
- // Set potential error message.
- // This message may be changed if the address can also be interpreted as a Bech32 address.
- error_str = "Invalid prefix for Base58-encoded address";
+ // If the prefix of data matches either the script or pubkey prefix, the length must have been wrong
+ if ((data.size() >= script_prefix.size() &&
+ std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) ||
+ (data.size() >= pubkey_prefix.size() &&
+ std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin()))) {
+ error_str = "Invalid length for Base58 address";
+ } else {
+ error_str = "Invalid prefix for Base58-encoded address";
+ }
+ return CNoDestination();
+ } else if (!is_bech32) {
+ // Try Base58 decoding without the checksum, using a much larger max length
+ if (!DecodeBase58(str, data, 100)) {
+ error_str = "Not a valid Bech32 or Base58 encoding";
+ } else {
+ error_str = "Invalid checksum or length of Base58 address";
+ }
+ return CNoDestination();
}
+
data.clear();
const auto dec = bech32::Decode(str);
if ((dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) && dec.data.size() > 0) {
// Bech32 decoding
- error_str = "";
if (dec.hrp != params.Bech32HRP()) {
error_str = "Invalid prefix for Bech32 address";
return CNoDestination();
@@ -168,9 +187,10 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
}
}
- // Set error message if address can't be interpreted as Base58 or Bech32.
- if (error_str.empty()) error_str = "Invalid address format";
-
+ // Perform Bech32 error location
+ auto res = bech32::LocateErrors(str);
+ error_str = res.first;
+ if (error_locations) *error_locations = std::move(res.second);
return CNoDestination();
}
} // namespace
@@ -258,9 +278,9 @@ std::string EncodeDestination(const CTxDestination& dest)
return std::visit(DestinationEncoder(Params()), dest);
}
-CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg, std::vector<int>* error_locations)
{
- return DecodeDestination(str, Params(), error_msg);
+ return DecodeDestination(str, Params(), error_msg, error_locations);
}
CTxDestination DecodeDestination(const std::string& str)
@@ -272,7 +292,7 @@ CTxDestination DecodeDestination(const std::string& str)
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
std::string error_msg;
- return IsValidDestination(DecodeDestination(str, params, error_msg));
+ return IsValidDestination(DecodeDestination(str, params, error_msg, nullptr));
}
bool IsValidDestinationString(const std::string& str)