This commit is contained in:
Portland.HODL 2025-03-13 02:09:20 +01:00 committed by GitHub
commit 63ce1e0201
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 153 additions and 91 deletions

View file

@ -160,6 +160,12 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E}; base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
base58EncodedPrefixes[PUBKEY_ADDRESS] = {"1"};
base58EncodedPrefixes[SCRIPT_ADDRESS] = {"3"};
base58EncodedPrefixes[SECRET_KEY] = {"5","K","L"};
base58EncodedPrefixes[EXT_PUBLIC_KEY] = {"xpub"};
base58EncodedPrefixes[EXT_SECRET_KEY] = {"xpriv"};
bech32_hrp = "bc"; bech32_hrp = "bc";
vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_main), std::end(chainparams_seed_main)); vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_main), std::end(chainparams_seed_main));
@ -279,6 +285,12 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
base58EncodedPrefixes[PUBKEY_ADDRESS] = {"m","n"};
base58EncodedPrefixes[SCRIPT_ADDRESS] = {"2"};
base58EncodedPrefixes[SECRET_KEY] = {"9","c"};
base58EncodedPrefixes[EXT_PUBLIC_KEY] = {"tpub"};
base58EncodedPrefixes[EXT_SECRET_KEY] = {"tpriv"};
bech32_hrp = "tb"; bech32_hrp = "tb";
vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_test), std::end(chainparams_seed_test)); vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_test), std::end(chainparams_seed_test));
@ -383,6 +395,12 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
base58EncodedPrefixes[PUBKEY_ADDRESS] = {"m","n"};
base58EncodedPrefixes[SCRIPT_ADDRESS] = {"2"};
base58EncodedPrefixes[SECRET_KEY] = {"9","c"};
base58EncodedPrefixes[EXT_PUBLIC_KEY] = {"tpub"};
base58EncodedPrefixes[EXT_SECRET_KEY] = {"tpriv"};
bech32_hrp = "tb"; bech32_hrp = "tb";
vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_testnet4), std::end(chainparams_seed_testnet4)); vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_testnet4), std::end(chainparams_seed_testnet4));
@ -513,6 +531,12 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
base58EncodedPrefixes[PUBKEY_ADDRESS] = {"m","n"};
base58EncodedPrefixes[SCRIPT_ADDRESS] = {"2"};
base58EncodedPrefixes[SECRET_KEY] = {"9","c"};
base58EncodedPrefixes[EXT_PUBLIC_KEY] = {"tpub"};
base58EncodedPrefixes[EXT_SECRET_KEY] = {"tpriv"};
bech32_hrp = "tb"; bech32_hrp = "tb";
fDefaultConsistencyChecks = false; fDefaultConsistencyChecks = false;
@ -650,6 +674,12 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
base58EncodedPrefixes[PUBKEY_ADDRESS] = {"m","n"};
base58EncodedPrefixes[SCRIPT_ADDRESS] = {"2"};
base58EncodedPrefixes[SECRET_KEY] = {"9","c"};
base58EncodedPrefixes[EXT_PUBLIC_KEY] = {"tpub"};
base58EncodedPrefixes[EXT_SECRET_KEY] = {"tpriv"};
bech32_hrp = "bcrt"; bech32_hrp = "bcrt";
} }
}; };

View file

@ -109,6 +109,8 @@ public:
uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; } uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
/** Whether it is possible to mine blocks on demand (no retargeting) */ /** Whether it is possible to mine blocks on demand (no retargeting) */
bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; } bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
/** Return the chain type as a user-facing string */
std::string GetChainTypeDisplayString() const { return ChainTypeToDisplayString(m_chain_type); }
/** Return the chain type string */ /** Return the chain type string */
std::string GetChainTypeString() const { return ChainTypeToString(m_chain_type); } std::string GetChainTypeString() const { return ChainTypeToString(m_chain_type); }
/** Return the chain type */ /** Return the chain type */
@ -116,6 +118,7 @@ public:
/** Return the list of hostnames to look up for DNS seeds */ /** Return the list of hostnames to look up for DNS seeds */
const std::vector<std::string>& DNSSeeds() const { return vSeeds; } const std::vector<std::string>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::vector<std::string_view>& Base58EncodedPrefix(Base58Type type) const { return base58EncodedPrefixes[type]; }
const std::string& Bech32HRP() const { return bech32_hrp; } const std::string& Bech32HRP() const { return bech32_hrp; }
const std::vector<uint8_t>& FixedSeeds() const { return vFixedSeeds; } const std::vector<uint8_t>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; } const CCheckpointData& Checkpoints() const { return checkpointData; }
@ -175,6 +178,7 @@ protected:
uint64_t m_assumed_chain_state_size; uint64_t m_assumed_chain_state_size;
std::vector<std::string> vSeeds; std::vector<std::string> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES]; std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
std::vector<std::string_view> base58EncodedPrefixes[MAX_BASE58_TYPES];
std::string bech32_hrp; std::string bech32_hrp;
ChainType m_chain_type; ChainType m_chain_type;
CBlock genesis; CBlock genesis;

View file

@ -83,14 +83,21 @@ public:
CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str, std::vector<int>* error_locations) 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 = ""; error_str = "";
// Note this will be false if it is a valid Bech32 address for a different network static const uint8_t MAX_BASE58_CHARS = 100;
bool is_bech32 = (ToLower(str.substr(0, params.Bech32HRP().size())) == params.Bech32HRP()); static const uint8_t MAX_BASE58_CHECK_CHARS = 21;
if (!is_bech32 && DecodeBase58Check(str, data, 21)) { std::vector<unsigned char> data, bech32_data;
auto [bech32_encoding, bech32_hrp, bech32_chars] = bech32::Decode(str);
auto [bech32_error, bech32_error_loc] = bech32::LocateErrors(str);
bool is_bech32 = bech32_encoding != bech32::Encoding::INVALID;
auto check_base58 = [&]() { return DecodeBase58Check(str, data, MAX_BASE58_CHECK_CHARS); };
if (!is_bech32 && check_base58()) {
uint160 hash;
// base58-encoded Bitcoin addresses. // base58-encoded Bitcoin addresses.
// Public-key-hash-addresses have version 0 (or 111 testnet). // Public-key-hash-addresses have version 0 (or 111 testnet).
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
@ -114,74 +121,97 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin()))) { std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin()))) {
error_str = "Invalid length for Base58 address (P2PKH or P2SH)"; error_str = "Invalid length for Base58 address (P2PKH or P2SH)";
} else { } else {
error_str = "Invalid or unsupported Base58-encoded address."; std::vector<std::string_view> encoded_prefixes;
const std::vector<std::string_view>& pubkey_prefixes = params.Base58EncodedPrefix(CChainParams::PUBKEY_ADDRESS);
const std::vector<std::string_view>& script_prefixes = params.Base58EncodedPrefix(CChainParams::SCRIPT_ADDRESS);
encoded_prefixes.insert(encoded_prefixes.end(), script_prefixes.begin(), script_prefixes.end());
encoded_prefixes.insert(encoded_prefixes.end(), pubkey_prefixes.begin(), pubkey_prefixes.end());
std::string base58_address_prefixes;
for (size_t i = 0; i < encoded_prefixes.size(); ++i) {
if (i > 0) {
base58_address_prefixes += (i == encoded_prefixes.size() - 1) ? ", or " : ", ";
}
base58_address_prefixes += std::string(encoded_prefixes[i]);
}
error_str = strprintf("Invalid Base58 %s address. Expected prefix %s", params.GetChainTypeDisplayString(), base58_address_prefixes);
} }
return CNoDestination(); return CNoDestination();
} else if (!is_bech32) { } else if (!is_bech32) {
bool is_base58 = DecodeBase58(str, data, MAX_BASE58_CHARS);
// Try Base58 decoding without the checksum, using a much larger max length // Try Base58 decoding without the checksum, using a much larger max length
if (!DecodeBase58(str, data, 100)) { if (!is_base58) {
error_str = "Invalid or unsupported Segwit (Bech32) or Base58 encoding."; // If bech32 decoding failed due to invalid base32 chars, address format is ambiguous; otherwise, report bech32 error
bool is_validBech32Chars = (bech32_error != "Invalid Base 32 character");
error_str = is_validBech32Chars ? "Bech32(m) address decoded with error: " + bech32_error : "Address is not valid Base58 or Bech32";
} else { } else {
if (bech32_error == "Invalid character or mixed case") {
error_str = "Invalid checksum or length of Base58 address (P2PKH or P2SH)"; error_str = "Invalid checksum or length of Base58 address (P2PKH or P2SH)";
} }
// This covers the case where an address is encoded as valid base58 and invalid bech32(m) due to a non base32 error
error_str = "Invalid checksum or length of Base58 address (P2PKH or P2SH)";
}
if (error_locations) {
*error_locations = std::move(bech32_error_loc);
}
return CNoDestination(); return CNoDestination();
} }
data.clear(); if (bech32_encoding == bech32::Encoding::BECH32 || bech32_encoding == bech32::Encoding::BECH32M) {
const auto dec = bech32::Decode(str); if (bech32_chars.empty()) {
if (dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) {
if (dec.data.empty()) {
error_str = "Empty Bech32 data section"; error_str = "Empty Bech32 data section";
return CNoDestination(); return CNoDestination();
} }
// Bech32 decoding // Bech32 decoding
if (dec.hrp != params.Bech32HRP()) { if (bech32_hrp != params.Bech32HRP()) {
error_str = strprintf("Invalid or unsupported prefix for Segwit (Bech32) address (expected %s, got %s).", params.Bech32HRP(), dec.hrp); error_str = strprintf("Invalid or unsupported prefix for Segwit (Bech32) %s address (expected %s, got %s)", params.GetChainTypeDisplayString(), params.Bech32HRP(), bech32_hrp);
return CNoDestination(); return CNoDestination();
} }
int version = dec.data[0]; // The first 5 bit symbol is the witness version (0-16) int version = bech32_chars[0]; // The first 5 bit symbol is the witness version (0-16)
if (version == 0 && dec.encoding != bech32::Encoding::BECH32) { if (version == 0 && bech32_encoding != bech32::Encoding::BECH32) {
error_str = "Version 0 witness address must use Bech32 checksum"; error_str = "Version 0 witness address must use Bech32 checksum";
return CNoDestination(); return CNoDestination();
} }
if (version != 0 && dec.encoding != bech32::Encoding::BECH32M) { if (version != 0 && bech32_encoding != bech32::Encoding::BECH32M) {
error_str = "Version 1+ witness address must use Bech32m checksum"; error_str = "Version 1+ witness address must use Bech32m checksum";
return CNoDestination(); return CNoDestination();
} }
// The rest of the symbols are converted witness program bytes. // The rest of the symbols are converted witness program bytes.
data.reserve(((dec.data.size() - 1) * 5) / 8); bech32_data.reserve(((bech32_chars.size() - 1) * 5) / 8);
if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, dec.data.begin() + 1, dec.data.end())) { if (ConvertBits<5, 8, false>([&](unsigned char c) { bech32_data.push_back(c); }, bech32_chars.begin() + 1, bech32_chars.end())) {
std::string_view byte_str{data.size() == 1 ? "byte" : "bytes"}; std::string_view byte_str{bech32_data.size() == 1 ? "byte" : "bytes"};
if (version == 0) { if (version == 0) {
{ {
WitnessV0KeyHash keyid; WitnessV0KeyHash keyid;
if (data.size() == keyid.size()) { if (bech32_data.size() == keyid.size()) {
std::copy(data.begin(), data.end(), keyid.begin()); std::copy(bech32_data.begin(), bech32_data.end(), keyid.begin());
return keyid; return keyid;
} }
} }
{ {
WitnessV0ScriptHash scriptid; WitnessV0ScriptHash scriptid;
if (data.size() == scriptid.size()) { if (bech32_data.size() == scriptid.size()) {
std::copy(data.begin(), data.end(), scriptid.begin()); std::copy(bech32_data.begin(), bech32_data.end(), scriptid.begin());
return scriptid; return scriptid;
} }
} }
error_str = strprintf("Invalid Bech32 v0 address program size (%d %s), per BIP141", data.size(), byte_str); error_str = strprintf("Invalid SegWit v0 address program size (%d %s), per BIP141", bech32_data.size(), byte_str);
return CNoDestination(); return CNoDestination();
} }
if (version == 1 && data.size() == WITNESS_V1_TAPROOT_SIZE) { if (version == 1 && bech32_data.size() == WITNESS_V1_TAPROOT_SIZE) {
static_assert(WITNESS_V1_TAPROOT_SIZE == WitnessV1Taproot::size()); static_assert(WITNESS_V1_TAPROOT_SIZE == WitnessV1Taproot::size());
WitnessV1Taproot tap; WitnessV1Taproot tap;
std::copy(data.begin(), data.end(), tap.begin()); std::copy(bech32_data.begin(), bech32_data.end(), tap.begin());
return tap; return tap;
} }
if (CScript::IsPayToAnchor(version, data)) { if (CScript::IsPayToAnchor(version, bech32_data)) {
return PayToAnchor(); return PayToAnchor();
} }
@ -190,12 +220,12 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return CNoDestination(); return CNoDestination();
} }
if (data.size() < 2 || data.size() > BECH32_WITNESS_PROG_MAX_LEN) { if (bech32_data.size() < 2 || bech32_data.size() > BECH32_WITNESS_PROG_MAX_LEN) {
error_str = strprintf("Invalid Bech32 address program size (%d %s)", data.size(), byte_str); error_str = strprintf("Invalid Bech32 address program size (%d %s)", bech32_data.size(), byte_str);
return CNoDestination(); return CNoDestination();
} }
return WitnessUnknown{version, data}; return WitnessUnknown{version, bech32_data};
} else { } else {
error_str = strprintf("Invalid padding in Bech32 data section"); error_str = strprintf("Invalid padding in Bech32 data section");
return CNoDestination(); return CNoDestination();
@ -203,9 +233,8 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
} }
// Perform Bech32 error location // Perform Bech32 error location
auto res = bech32::LocateErrors(str); error_str = bech32_error;
error_str = res.first; if (error_locations) *error_locations = std::move(bech32_error_loc);
if (error_locations) *error_locations = std::move(res.second);
return CNoDestination(); return CNoDestination();
} }
} // namespace } // namespace

View file

@ -41,3 +41,20 @@ std::optional<ChainType> ChainTypeFromString(std::string_view chain)
return std::nullopt; return std::nullopt;
} }
} }
std::string ChainTypeToDisplayString(ChainType chain)
{
switch (chain) {
case ChainType::MAIN:
return "Bitcoin";
case ChainType::TESTNET:
return "testnet";
case ChainType::TESTNET4:
return "testnet4";
case ChainType::SIGNET:
return "signet";
case ChainType::REGTEST:
return "regtest";
}
assert(false);
}

View file

@ -16,6 +16,8 @@ enum class ChainType {
TESTNET4, TESTNET4,
}; };
std::string ChainTypeToDisplayString(ChainType chain);
std::string ChainTypeToString(ChainType chain); std::string ChainTypeToString(ChainType chain);
std::optional<ChainType> ChainTypeFromString(std::string_view chain); std::optional<ChainType> ChainTypeFromString(std::string_view chain);

View file

@ -64,20 +64,20 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
def test_validateaddress(self): def test_validateaddress(self):
# Invalid Bech32 # Invalid Bech32
self.check_invalid(BECH32_INVALID_SIZE, "Invalid Bech32 address program size (41 bytes)") self.check_invalid(BECH32_INVALID_SIZE, 'Invalid Bech32 address program size (41 bytes)')
self.check_invalid(BECH32_INVALID_PREFIX, 'Invalid or unsupported Segwit (Bech32) or Base58 encoding.') self.check_invalid(BECH32_INVALID_PREFIX, 'Invalid or unsupported prefix for Segwit (Bech32) regtest address (expected bcrt, got bc)')
self.check_invalid(BECH32_INVALID_BECH32, 'Version 1+ witness address must use Bech32m checksum') self.check_invalid(BECH32_INVALID_BECH32, 'Version 1+ witness address must use Bech32m checksum')
self.check_invalid(BECH32_INVALID_BECH32M, 'Version 0 witness address must use Bech32 checksum') self.check_invalid(BECH32_INVALID_BECH32M, 'Version 0 witness address must use Bech32 checksum')
self.check_invalid(BECH32_INVALID_VERSION, 'Invalid Bech32 address witness version') self.check_invalid(BECH32_INVALID_VERSION, 'Invalid Bech32 address witness version')
self.check_invalid(BECH32_INVALID_V0_SIZE, "Invalid Bech32 v0 address program size (21 bytes), per BIP141") self.check_invalid(BECH32_INVALID_V0_SIZE, 'Invalid SegWit v0 address program size (21 bytes), per BIP141')
self.check_invalid(BECH32_TOO_LONG, 'Bech32 string too long', list(range(90, 108))) self.check_invalid(BECH32_TOO_LONG, 'Bech32(m) address decoded with error: Bech32 string too long', list(range(90, 108)))
self.check_invalid(BECH32_ONE_ERROR, 'Invalid Bech32 checksum', [9]) self.check_invalid(BECH32_ONE_ERROR, 'Bech32(m) address decoded with error: Invalid Bech32 checksum', [9])
self.check_invalid(BECH32_TWO_ERRORS, 'Invalid Bech32 checksum', [22, 43]) self.check_invalid(BECH32_TWO_ERRORS, 'Bech32(m) address decoded with error: Invalid Bech32 checksum', [22, 43])
self.check_invalid(BECH32_ONE_ERROR_CAPITALS, 'Invalid Bech32 checksum', [38]) self.check_invalid(BECH32_ONE_ERROR_CAPITALS, 'Invalid checksum or length of Base58 address (P2PKH or P2SH)', [38])
self.check_invalid(BECH32_NO_SEPARATOR, 'Missing separator') self.check_invalid(BECH32_NO_SEPARATOR, 'Bech32(m) address decoded with error: Missing separator')
self.check_invalid(BECH32_INVALID_CHAR, 'Invalid Base 32 character', [8]) self.check_invalid(BECH32_INVALID_CHAR, 'Address is not valid Base58 or Bech32', [8])
self.check_invalid(BECH32_MULTISIG_TWO_ERRORS, 'Invalid Bech32 checksum', [19, 30]) self.check_invalid(BECH32_MULTISIG_TWO_ERRORS, 'Bech32(m) address decoded with error: Invalid Bech32 checksum', [19, 30])
self.check_invalid(BECH32_WRONG_VERSION, 'Invalid Bech32 checksum', [5]) self.check_invalid(BECH32_WRONG_VERSION, 'Bech32(m) address decoded with error: Invalid Bech32 checksum', [5])
# Valid Bech32 # Valid Bech32
self.check_valid(BECH32_VALID) self.check_valid(BECH32_VALID)
@ -86,16 +86,16 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
self.check_valid(BECH32_VALID_MULTISIG) self.check_valid(BECH32_VALID_MULTISIG)
# Invalid Base58 # Invalid Base58
self.check_invalid(BASE58_INVALID_PREFIX, 'Invalid or unsupported Base58-encoded address.') self.check_invalid(BASE58_INVALID_PREFIX, 'Invalid Base58 regtest address. Expected prefix 2, m, or n')
self.check_invalid(BASE58_INVALID_CHECKSUM, 'Invalid checksum or length of Base58 address (P2PKH or P2SH)') self.check_invalid(BASE58_INVALID_CHECKSUM, 'Invalid checksum or length of Base58 address (P2PKH or P2SH)', [4, 6, 10, 12, 16, 25, 29, 30, 31])
self.check_invalid(BASE58_INVALID_LENGTH, 'Invalid checksum or length of Base58 address (P2PKH or P2SH)') self.check_invalid(BASE58_INVALID_LENGTH, 'Invalid checksum or length of Base58 address (P2PKH or P2SH)', [3, 8, 9, 11, 15, 16, 18, 19, 21, 22, 23, 27, 39, 40, 41, 44, 46, 47])
# Valid Base58 # Valid Base58
self.check_valid(BASE58_VALID) self.check_valid(BASE58_VALID)
# Invalid address format # Invalid address format
self.check_invalid(INVALID_ADDRESS, 'Invalid or unsupported Segwit (Bech32) or Base58 encoding.') self.check_invalid(INVALID_ADDRESS, 'Bech32(m) address decoded with error: Invalid separator position' , [14])
self.check_invalid(INVALID_ADDRESS_2, 'Invalid or unsupported Segwit (Bech32) or Base58 encoding.') self.check_invalid(INVALID_ADDRESS_2, 'Bech32(m) address decoded with error: Invalid separator position', [0])
node = self.nodes[0] node = self.nodes[0]
@ -107,10 +107,10 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
def test_getaddressinfo(self): def test_getaddressinfo(self):
node = self.nodes[0] node = self.nodes[0]
assert_raises_rpc_error(-5, "Invalid Bech32 address program size (41 bytes)", node.getaddressinfo, BECH32_INVALID_SIZE) assert_raises_rpc_error(-5, 'Invalid Bech32 address program size (41 bytes)', node.getaddressinfo, BECH32_INVALID_SIZE)
assert_raises_rpc_error(-5, "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", node.getaddressinfo, BECH32_INVALID_PREFIX) assert_raises_rpc_error(-5, 'Invalid or unsupported prefix for Segwit (Bech32) regtest address (expected bcrt, got bc)', node.getaddressinfo, BECH32_INVALID_PREFIX)
assert_raises_rpc_error(-5, "Invalid or unsupported Base58-encoded address.", node.getaddressinfo, BASE58_INVALID_PREFIX) assert_raises_rpc_error(-5, 'Invalid Base58 regtest address. Expected prefix 2, m, or n', node.getaddressinfo, BASE58_INVALID_PREFIX)
assert_raises_rpc_error(-5, "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", node.getaddressinfo, INVALID_ADDRESS) assert_raises_rpc_error(-5, 'Bech32(m) address decoded with error: Invalid separator position', node.getaddressinfo, INVALID_ADDRESS)
assert "isscript" not in node.getaddressinfo(BECH32_VALID_UNKNOWN_WITNESS) assert "isscript" not in node.getaddressinfo(BECH32_VALID_UNKNOWN_WITNESS)
def run_test(self): def run_test(self):

View file

@ -12,10 +12,10 @@ INVALID_DATA = [
# BIP 173 # BIP 173
( (
"tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
"Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # Invalid hrp "Invalid or unsupported prefix for Segwit (Bech32) Bitcoin address (expected bc, got tc)", # Invalid hrp
[], [],
), ),
("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", "Invalid Bech32 checksum", [41]), ("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", "Bech32(m) address decoded with error: Invalid Bech32 checksum", [41]),
( (
"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
"Version 1+ witness address must use Bech32m checksum", "Version 1+ witness address must use Bech32m checksum",
@ -33,17 +33,17 @@ INVALID_DATA = [
), ),
( (
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
"Invalid Bech32 v0 address program size (16 bytes), per BIP141", "Invalid SegWit v0 address program size (16 bytes), per BIP141",
[], [],
), ),
( (
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
"Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Mixed case "Bech32(m) address decoded with error: Invalid character or mixed case", # tb1, Mixed case
[], [58],
), ),
( (
"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3t4", "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3t4",
"Invalid character or mixed case", # bc1, Mixed case, not in BIP 173 test vectors "Bech32(m) address decoded with error: Invalid character or mixed case", # bc1, Mixed case, not in BIP 173 test vectors
[40], [40],
), ),
( (
@ -52,15 +52,15 @@ INVALID_DATA = [
[], [],
), ),
( (
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", "bc1qfysxzmfq2phhyarvv9hxgtjgdajxcw3fpkpph893lw",
"Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Non-zero padding in 8-to-5 conversion "Invalid padding in Bech32 data section", # tb1, Non-zero padding in 8-to-5 conversion
[], [],
), ),
("bc1gmk9yu", "Empty Bech32 data section", []), ("bc1gmk9yu", "Empty Bech32 data section", []),
# BIP 350 # BIP 350
( (
"tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut", "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut",
"Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # Invalid human-readable part "Invalid or unsupported prefix for Segwit (Bech32) Bitcoin address (expected bc, got tc)", # Invalid human-readable part
[], [],
), ),
( (
@ -69,29 +69,19 @@ INVALID_DATA = [
[], [],
), ),
( (
"tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf", "BC1PFYSXZMFQ2PHHYARVV9HXGTJGFAZYCWJYPQQQF9ZLQ6",
"Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Invalid checksum (Bech32 instead of Bech32m)
[],
),
(
"BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL",
"Version 1+ witness address must use Bech32m checksum", # Invalid checksum (Bech32 instead of Bech32m) "Version 1+ witness address must use Bech32m checksum", # Invalid checksum (Bech32 instead of Bech32m)
[], [],
), ),
( (
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh", "bc1qfysxzmfq2phhyarvv9hxgtjgfazycwjypqqqfm706a",
"Version 0 witness address must use Bech32 checksum", # Invalid checksum (Bech32m instead of Bech32) "Version 0 witness address must use Bech32 checksum", # Invalid checksum (Bech32m instead of Bech32)
[], [],
), ),
( (
"tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47", "Address is not valid Base58 or Bech32 ",
"Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Invalid checksum (Bech32m instead of Bech32) "Bech32(m) address decoded with error: Invalid character or mixed case", # Invalid character in checksum
[], [x for x in range(1, 21)] + [22, 23, 24] + [27, 28, 29, 30] + [32, 33, 34] + [37],
),
(
"bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4",
"Invalid Base 32 character", # Invalid character in checksum
[59],
), ),
( (
"BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R", "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R",
@ -106,12 +96,7 @@ INVALID_DATA = [
), ),
( (
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
"Invalid Bech32 v0 address program size (16 bytes), per BIP141", "Invalid SegWit v0 address program size (16 bytes), per BIP141",
[],
),
(
"tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq",
"Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Mixed case
[], [],
), ),
( (
@ -119,11 +104,6 @@ INVALID_DATA = [
"Invalid padding in Bech32 data section", # zero padding of more than 4 bits "Invalid padding in Bech32 data section", # zero padding of more than 4 bits
[], [],
), ),
(
"tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j",
"Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Non-zero padding in 8-to-5 conversion
[],
),
("bc1gmk9yu", "Empty Bech32 data section", []), ("bc1gmk9yu", "Empty Bech32 data section", []),
] ]
VALID_DATA = [ VALID_DATA = [

View file

@ -650,7 +650,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999))) assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))
# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
assert_raises_rpc_error(-5, "Invalid or unsupported Base58-encoded address.", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") assert_raises_rpc_error(-5, "Invalid Base58 regtest address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac") assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")