Skip to content

Commit

Permalink
Merge bitcoin#27349: test: use address_to_scriptpubkey instead of RPC…
Browse files Browse the repository at this point in the history
… call

e47ce42 refactor: use address_to_scriptpubkey to retrieve addresses scriptpubkey (ismaelsadeeq)
4142d19 refactor: move address_to_scriptpubkey to address.py (ismaelsadeeq)

Pull request description:

  PR bitcoin#27269 enables the function address_to_scriptpubkey() to decode all address types and return their corresponding scriptpubkeys. As a result, there is no longer any need to call getaddressinfo or validateaddress RPCs in order to retrieve an address scriptpubkey, as explained in the comments on this pull request (see bitcoin#27269 (review) and bitcoin#27269 (comment)).

  Instead of using RPC calls, this update replaces the process of obtaining an address scriptPubkey with the address_to_scriptpubkey method, resulting in improved performance for functional tests.

ACKs for top commit:
  josibake:
    re-ACK bitcoin@e47ce42
  theStack:
    ACK e47ce42 🌱

Tree-SHA512: 05285349a7d5ce7097b8f2582e573a5135c6deef85ea9936f68f6ce94e9ebb1d84d94f7fc7e5ed833a698e01585addd80deb52e6338f8aee985bf14db45417d2
  • Loading branch information
fanquake committed Mar 29, 2023
2 parents 6882828 + e47ce42 commit c0311b1
Show file tree
Hide file tree
Showing 10 changed files with 38 additions and 29 deletions.
3 changes: 2 additions & 1 deletion test/functional/feature_nulldummy.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"""
import time

from test_framework.address import address_to_scriptpubkey
from test_framework.blocktools import (
COINBASE_MATURITY,
NORMAL_GBT_REQUEST_PARAMS,
Expand Down Expand Up @@ -77,7 +78,7 @@ def run_test(self):
cms = self.nodes[0].createmultisig(1, [self.pubkey])
wms = self.nodes[0].createmultisig(1, [self.pubkey], 'p2sh-segwit')
self.ms_address = cms["address"]
ms_unlock_details = {"scriptPubKey": self.nodes[0].validateaddress(self.ms_address)["scriptPubKey"],
ms_unlock_details = {"scriptPubKey": address_to_scriptpubkey(self.ms_address).hex(),
"redeemScript": cms["redeemScript"]}
self.wit_ms_address = wms['address']

Expand Down
3 changes: 2 additions & 1 deletion test/functional/rpc_createmultisig.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import json
import os

from test_framework.address import address_to_scriptpubkey
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.authproxy import JSONRPCException
from test_framework.descriptors import descsum_create, drop_origins
Expand Down Expand Up @@ -193,7 +194,7 @@ def do_multisig(self):
assert mredeemw == mredeem
wmulti.unloadwallet()

spk = bytes.fromhex(node0.validateaddress(madd)["scriptPubKey"])
spk = address_to_scriptpubkey(madd)
txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=spk, amount=1300)
tx = node0.getrawtransaction(txid, True)
vout = [v["n"] for v in tx["vout"] if madd == v["scriptPubKey"]["address"]]
Expand Down
3 changes: 2 additions & 1 deletion test/functional/rpc_scanblocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the scanblocks RPC call."""
from test_framework.address import address_to_scriptpubkey
from test_framework.blockfilter import (
bip158_basic_element_hash,
bip158_relevant_scriptpubkeys,
Expand Down Expand Up @@ -36,7 +37,7 @@ def run_test(self):
# send 1.0, mempool only
# childkey 5 of `parent_key`
wallet.send_to(from_node=node,
scriptPubKey=bytes.fromhex(node.validateaddress("mkS4HXoTYWRTescLGaUTGbtTTYX5EjJyEE")['scriptPubKey']),
scriptPubKey=address_to_scriptpubkey("mkS4HXoTYWRTescLGaUTGbtTTYX5EjJyEE"),
amount=1 * COIN)

# mine a block and assure that the mined blockhash is in the filterresult
Expand Down
2 changes: 1 addition & 1 deletion test/functional/rpc_scantxoutset.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the scantxoutset rpc call."""
from test_framework.address import address_to_scriptpubkey
from test_framework.messages import COIN
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
from test_framework.wallet import (
MiniWallet,
address_to_scriptpubkey,
getnewdestination,
)

Expand Down
3 changes: 2 additions & 1 deletion test/functional/rpc_signrawtransactionwithkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
COINBASE_MATURITY,
)
from test_framework.address import (
address_to_scriptpubkey,
script_to_p2sh,
)
from test_framework.key import ECKey
Expand Down Expand Up @@ -118,7 +119,7 @@ def verify_txn_with_witness_script(self, tx_type):
}.get(tx_type, "Invalid tx_type")
redeem_script = script_to_p2wsh_script(witness_script).hex()
addr = script_to_p2sh(redeem_script)
script_pub_key = self.nodes[1].validateaddress(addr)['scriptPubKey']
script_pub_key = address_to_scriptpubkey(addr).hex()
# Fund that address
txid = self.send_to_address(addr, 10)
vout = find_vout_for_address(self.nodes[0], txid, addr)
Expand Down
21 changes: 21 additions & 0 deletions test/functional/test_framework/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@
taproot_construct,
)
from .util import assert_equal
from test_framework.script_util import (
keyhash_to_p2pkh_script,
program_to_witness_script,
scripthash_to_p2sh_script,
)
from test_framework.segwit_addr import (
decode_segwit_address,
encode_segwit_address,
)


ADDRESS_BCRT1_UNSPENDABLE = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj'
ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR = 'addr(bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj)#juyq9d97'
# Coins sent to this address can be spent with a witness stack of just OP_TRUE
Expand Down Expand Up @@ -172,6 +178,21 @@ def bech32_to_bytes(address):
return version, bytearray(payload)


def address_to_scriptpubkey(address):
"""Converts a given address to the corresponding output script (scriptPubKey)."""
version, payload = bech32_to_bytes(address)
if version is not None:
return program_to_witness_script(version, payload) # testnet segwit scriptpubkey
payload, version = base58_to_byte(address)
if version == 111: # testnet pubkey hash
return keyhash_to_p2pkh_script(payload)
elif version == 196: # testnet script hash
return scripthash_to_p2sh_script(payload)
# TODO: also support other address formats
else:
assert False


class TestFrameworkScript(unittest.TestCase):
def test_base58encodedecode(self):
def check_base58(data, version):
Expand Down
3 changes: 2 additions & 1 deletion test/functional/test_framework/blocktools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import unittest

from .address import (
address_to_scriptpubkey,
key_to_p2sh_p2wpkh,
key_to_p2wpkh,
script_to_p2sh_p2wsh,
Expand Down Expand Up @@ -205,7 +206,7 @@ def create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):
else:
addr = key_to_p2sh_p2wpkh(pubkey) if encode_p2sh else key_to_p2wpkh(pubkey)
if not encode_p2sh:
assert_equal(node.getaddressinfo(addr)['scriptPubKey'], witness_script(use_p2wsh, pubkey))
assert_equal(address_to_scriptpubkey(addr).hex(), witness_script(use_p2wsh, pubkey))
return node.createrawtransaction([utxo], {addr: amount})

def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
Expand Down
23 changes: 2 additions & 21 deletions test/functional/test_framework/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
Optional,
)
from test_framework.address import (
base58_to_byte,
bech32_to_bytes,
address_to_scriptpubkey,
create_deterministic_address_bcrt1_p2tr_op_true,
key_to_p2pkh,
key_to_p2sh_p2wpkh,
Expand Down Expand Up @@ -49,9 +48,6 @@
key_to_p2pkh_script,
key_to_p2sh_p2wpkh_script,
key_to_p2wpkh_script,
keyhash_to_p2pkh_script,
program_to_witness_script,
scripthash_to_p2sh_script,
)
from test_framework.util import (
assert_equal,
Expand Down Expand Up @@ -101,7 +97,7 @@ def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE):
self._scriptPubKey = key_to_p2pk_script(pub_key.get_bytes())
elif mode == MiniWalletMode.ADDRESS_OP_TRUE:
self._address, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true()
self._scriptPubKey = bytes.fromhex(self._test_node.validateaddress(self._address)['scriptPubKey'])
self._scriptPubKey = address_to_scriptpubkey(self._address)

# When the pre-mined test framework chain is used, it contains coinbase
# outputs to the MiniWallet's default address in blocks 76-100
Expand Down Expand Up @@ -412,18 +408,3 @@ def getnewdestination(address_type='bech32m'):
else:
assert False
return pubkey, scriptpubkey, address


def address_to_scriptpubkey(address):
"""Converts a given address to the corresponding output script (scriptPubKey)."""
version, payload = bech32_to_bytes(address)
if version is not None:
return program_to_witness_script(version, payload) # testnet segwit scriptpubkey
payload, version = base58_to_byte(address)
if version == 111: # testnet pubkey hash
return keyhash_to_p2pkh_script(payload)
elif version == 196: # testnet script hash
return scripthash_to_p2sh_script(payload)
# TODO: also support other address formats
else:
assert False
3 changes: 2 additions & 1 deletion test/functional/wallet_avoidreuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the avoid_reuse and setwalletflag features."""

from test_framework.address import address_to_scriptpubkey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_approx,
Expand Down Expand Up @@ -257,7 +258,7 @@ def test_sending_from_reused_address_fails(self, second_addr_type):
if not self.options.descriptors:
# For the second send, we transmute it to a related single-key address
# to make sure it's also detected as re-use
fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
fund_spk = address_to_scriptpubkey(fundaddr).hex()
fund_decoded = self.nodes[0].decodescript(fund_spk)
if second_addr_type == "p2sh-segwit":
new_fundaddr = fund_decoded["segwit"]["p2sh-segwit"]
Expand Down
3 changes: 2 additions & 1 deletion test/functional/wallet_fast_rescan.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import os
from typing import List

from test_framework.address import address_to_scriptpubkey
from test_framework.descriptors import descsum_create
from test_framework.test_framework import BitcoinTestFramework
from test_framework.test_node import TestNode
Expand Down Expand Up @@ -58,7 +59,7 @@ def run_test(self):
if 'range' in desc_info:
start_range, end_range = desc_info['range']
addr = w.deriveaddresses(desc_info['desc'], [end_range, end_range])[0]
spk = bytes.fromhex(w.getaddressinfo(addr)['scriptPubKey'])
spk = address_to_scriptpubkey(addr)
self.log.info(f"-> range [{start_range},{end_range}], last address {addr}")
else:
spk = bytes.fromhex(fixed_key.p2wpkh_script)
Expand Down

0 comments on commit c0311b1

Please sign in to comment.