mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-11 12:22:39 -03:00
95d19f8c1a
88cc481092
Modify copyright header on Bech32 code (Samuel Dobson)5599813b80
Add lots of comments to Bech32 (Samuel Dobson)2eb5792ec7
Add release notes for validateaddress Bech32 error detection (MeshCollider)42d6a029e5
Refactor and add more tests for validateaddress (Samuel Dobson)c4979f77c1
Add boost tests for bech32 error detection (MeshCollider)02a7bdee42
Add error_locations to validateaddress RPC (Samuel Dobson)b62b67e06c
Add Bech32 error location function (Samuel Dobson)0b06e720c0
More detailed error checking for base58 addresses (Samuel Dobson) Pull request description: Addresses (partially) #16779 - no GUI change in this PR Adds a LocateError function the bech32 library, which is then called by `validateaddress` RPC, (and then eventually from a GUI tool too, future work). I think modifying validateaddress is nicer than adding a separate RPC for this. Includes tests. Based on https://github.com/sipa/bech32/blob/master/ecc/javascript/bech32_ecc.js Credit to sipa for that code ACKs for top commit: laanwj: Code review and manually tested ACK88cc481092
ryanofsky: Code review ACK88cc481092
with caveat that I only checked the new `LocateErrors` code to try to verify it didn't have unsafe or unexpected operations or loop forever or crash. Did not try to verify behavior corresponds to the spec. In the worst case bugs here should just affect error messages not actual decoding of addresses so this seemed ok. w0xlt: tACK88cc481
Tree-SHA512: 9c7fe9745bc7527f80a30bd4c1e3034e16b96a02cc7f6c268f91bfad08a6965a8064fe44230aa3f87e4fa3c938f662ff4446bc682c83cb48c1a3f95cf4186688
115 lines
5.7 KiB
Python
Executable file
115 lines
5.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Copyright (c) 2020-2021 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
"""Test error messages for 'getaddressinfo' and 'validateaddress' RPC commands."""
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
|
|
from test_framework.util import (
|
|
assert_equal,
|
|
assert_raises_rpc_error,
|
|
)
|
|
|
|
BECH32_VALID = 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
|
|
BECH32_VALID_CAPITALS = 'BCRT1QPLMTZKC2XHARPPZDLNPAQL78RSHJ68U33RAH7R'
|
|
BECH32_VALID_MULTISIG = 'bcrt1qdg3myrgvzw7ml9q0ejxhlkyxm7vl9r56yzkfgvzclrf4hkpx9yfqhpsuks'
|
|
|
|
BECH32_INVALID_BECH32 = 'bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqdmchcc'
|
|
BECH32_INVALID_BECH32M = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7k35mrzd'
|
|
BECH32_INVALID_VERSION = 'bcrt130xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqynjegk'
|
|
BECH32_INVALID_SIZE = 'bcrt1s0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav25430mtr'
|
|
BECH32_INVALID_V0_SIZE = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kqqq5k3my'
|
|
BECH32_INVALID_PREFIX = 'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx'
|
|
BECH32_TOO_LONG = 'bcrt1q049edschfnwystcqnsvyfpj23mpsg3jcedq9xv049edschfnwystcqnsvyfpj23mpsg3jcedq9xv049edschfnwystcqnsvyfpj23m'
|
|
BECH32_ONE_ERROR = 'bcrt1q049edschfnwystcqnsvyfpj23mpsg3jcedq9xv'
|
|
BECH32_ONE_ERROR_CAPITALS = 'BCRT1QPLMTZKC2XHARPPZDLNPAQL78RSHJ68U32RAH7R'
|
|
BECH32_TWO_ERRORS = 'bcrt1qax9suht3qv95sw33xavx8crpxduefdrsvgsklu' # should be bcrt1qax9suht3qv95sw33wavx8crpxduefdrsvgsklx
|
|
BECH32_NO_SEPARATOR = 'bcrtq049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
|
|
BECH32_INVALID_CHAR = 'bcrt1q04oldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
|
|
BECH32_MULTISIG_TWO_ERRORS = 'bcrt1qdg3myrgvzw7ml8q0ejxhlkyxn7vl9r56yzkfgvzclrf4hkpx9yfqhpsuks'
|
|
BECH32_WRONG_VERSION = 'bcrt1ptmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
|
|
|
|
BASE58_VALID = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn'
|
|
BASE58_INVALID_PREFIX = '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem'
|
|
BASE58_INVALID_CHECKSUM = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJJfn'
|
|
BASE58_INVALID_LENGTH = '2VKf7XKMrp4bVNVmuRbyCewkP8FhGLP2E54LHDPakr9Sq5mtU2'
|
|
|
|
INVALID_ADDRESS = 'asfah14i8fajz0123f'
|
|
INVALID_ADDRESS_2 = '1q049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
|
|
|
|
class InvalidAddressErrorMessageTest(BitcoinTestFramework):
|
|
def set_test_params(self):
|
|
self.setup_clean_chain = True
|
|
self.num_nodes = 1
|
|
|
|
def check_valid(self, addr):
|
|
info = self.nodes[0].validateaddress(addr)
|
|
assert info['isvalid']
|
|
assert 'error' not in info
|
|
assert 'error_locations' not in info
|
|
|
|
def check_invalid(self, addr, error_str, error_locations=None):
|
|
res = self.nodes[0].validateaddress(addr)
|
|
assert not res['isvalid']
|
|
assert_equal(res['error'], error_str)
|
|
if error_locations:
|
|
assert_equal(res['error_locations'], error_locations)
|
|
else:
|
|
assert_equal(res['error_locations'], [])
|
|
|
|
def test_validateaddress(self):
|
|
# Invalid Bech32
|
|
self.check_invalid(BECH32_INVALID_SIZE, 'Invalid Bech32 address data size')
|
|
self.check_invalid(BECH32_INVALID_PREFIX, 'Invalid HRP or Base58 character in address')
|
|
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_VERSION, 'Invalid Bech32 address witness version')
|
|
self.check_invalid(BECH32_INVALID_V0_SIZE, 'Invalid Bech32 v0 address data size')
|
|
self.check_invalid(BECH32_TOO_LONG, 'Bech32 string too long', list(range(90, 108)))
|
|
self.check_invalid(BECH32_ONE_ERROR, 'Invalid checksum', [9])
|
|
self.check_invalid(BECH32_TWO_ERRORS, 'Invalid checksum', [22, 43])
|
|
self.check_invalid(BECH32_ONE_ERROR_CAPITALS, 'Invalid checksum', [38])
|
|
self.check_invalid(BECH32_NO_SEPARATOR, 'Missing separator')
|
|
self.check_invalid(BECH32_INVALID_CHAR, 'Invalid Base 32 character', [8])
|
|
self.check_invalid(BECH32_MULTISIG_TWO_ERRORS, 'Invalid checksum', [19, 30])
|
|
self.check_invalid(BECH32_WRONG_VERSION, 'Invalid checksum', [5])
|
|
|
|
# Valid Bech32
|
|
self.check_valid(BECH32_VALID)
|
|
self.check_valid(BECH32_VALID_CAPITALS)
|
|
self.check_valid(BECH32_VALID_MULTISIG)
|
|
|
|
# Invalid Base58
|
|
self.check_invalid(BASE58_INVALID_PREFIX, 'Invalid prefix for Base58-encoded address')
|
|
self.check_invalid(BASE58_INVALID_CHECKSUM, 'Invalid checksum or length of Base58 address')
|
|
self.check_invalid(BASE58_INVALID_LENGTH, 'Invalid checksum or length of Base58 address')
|
|
|
|
# Valid Base58
|
|
self.check_valid(BASE58_VALID)
|
|
|
|
# Invalid address format
|
|
self.check_invalid(INVALID_ADDRESS, 'Invalid HRP or Base58 character in address')
|
|
self.check_invalid(INVALID_ADDRESS_2, 'Invalid HRP or Base58 character in address')
|
|
|
|
def test_getaddressinfo(self):
|
|
node = self.nodes[0]
|
|
|
|
assert_raises_rpc_error(-5, "Invalid Bech32 address data size", node.getaddressinfo, BECH32_INVALID_SIZE)
|
|
|
|
assert_raises_rpc_error(-5, "Invalid HRP or Base58 character in address", node.getaddressinfo, BECH32_INVALID_PREFIX)
|
|
|
|
assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", node.getaddressinfo, BASE58_INVALID_PREFIX)
|
|
|
|
assert_raises_rpc_error(-5, "Invalid HRP or Base58 character in address", node.getaddressinfo, INVALID_ADDRESS)
|
|
|
|
def run_test(self):
|
|
self.test_validateaddress()
|
|
|
|
if self.is_wallet_compiled():
|
|
self.init_wallet(node=0)
|
|
self.test_getaddressinfo()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
InvalidAddressErrorMessageTest().main()
|