Improve Address Decoding Error Messages
Issue
DecodeDestination does not properly handle errors when a user inputs a valid address for the wrong network (e.g., a testnet address while running the client on mainnet).
The previous error messages were misleading. For example, "Invalid or unsupported Segwit (Bech32) or Base58 encoding" was displayed for a valid Bech32 address on a different network. This occurred because the is_bech32 variable only checked if the prefix matched the current network's HRP. If it didn't match, the code would fall through to Base58 decoding logic regardless of whether the string was actually a valid Bech32 address.
Solution
Implementation Approach
Decode first, then validate: Instead of checking the prefix before decoding, we now decode the string using
bech32::Decode(str)upfront. This takes minimal CPU cycles and is acceptable since address validation is not a frequent operation.Gather decoding information: After Bech32 decoding, we also attempt
DecodeBase58(with a length of 100) andDecodeBase58Check. This provides enough information to properly diagnose errors.Provide network-aware error messages: When an address has an invalid prefix, the error message now includes the expected network values.
Changes Made
1. Add Base58 Encoded Prefixes to ChainParams (src/kernel/chainparams.cpp, src/kernel/chainparams.h)
2. Refactor Address Decoding Logic (src/key_io.cpp)
- Decode Bech32 upfront using
bech32::Decode(str)instead of checking prefix first - Use structured bindings for cleaner code:
auto [bech32_encoding, bech32_hrp, bech32_chars] = bech32::Decode(str) - Improved error handling flow with clearer branching
3. Improved Error Messages
| Scenario | Previous Error | New Error |
|---|---|---|
| Base58 address with wrong prefix | "Invalid or unsupported Base58-encoded address." | "Invalid Base58 address. Expected prefix 3, or 1" |
| Bech32 address with wrong HRP | "Invalid or unsupported Segwit (Bech32) or Base58 encoding." | "Invalid or unsupported prefix for Segwit (Bech32) address (expected bc, got tb)" |
| Invalid Base58 checksum | "Invalid or unsupported Segwit (Bech32) or Base58 encoding." | "Invalid checksum or length of Base58 address (P2PKH or P2SH)" |
| Ambiguous invalid address | "Invalid or unsupported Segwit (Bech32) or Base58 encoding." | "Address is not valid Base58 or Bech32" |
| Bech32 with checksum error | N/A | "Bech32 address decoded with error: Invalid Bech32 checksum" |
4. Test Updates
- Added
test/functional/data/rpc_validateaddress.jsonwith comprehensive test vectors for both mainnet and signet - Updated
test/functional/rpc_validateaddress.pyto use data-driven testing across multiple networks - Updated
test/functional/rpc_invalid_address_message.pywith new error message expectations
Consistency Improvements
- Removed inconsistent periods at the end of some error messages
- Changed "Bech32 v0" to "SegWit v0" for clarity
Reference
- Issue: #26290