Merge #21200: test: Speed up rpc_blockchain.py by removing miniwallet.generate()

faa137eb9e test: Speed up rpc_blockchain.py by removing miniwallet.generate() (MarcoFalke)
fa1fe80c75 test: Change address type from P2PKH to P2WSH in rpc_blockchain (MarcoFalke)
fa4d8f3169 test: Cache 25 mature coins for ADDRESS_BCRT1_P2WSH_OP_TRUE (MarcoFalke)
fad25153f5 test: Remove unused bug workaround (MarcoFalke)
faabce7d07 test: Start only the number of nodes that are needed (MarcoFalke)

Pull request description:

  Speed up various tests:

  * Remove unused nodes, which only consume time on start/stop
  * Remove unused "bug workarounds"
  * Remove the need for `miniwallet.generate()` by adding `miniwallet.scan_blocks()`. (On my system, with valgrind, generating 105 blocks takes 3.31 seconds. Rescanning 5 blocks takes 0.11 seconds.)

ACKs for top commit:
  laanwj:
    Code review ACK faa137eb9e

Tree-SHA512: ead1988d5aaa748ef9f8520af1e0bf812cf1d72e281ad22fbd172b7306d850053040526f8adbcec0b9a971c697a0ee7ee8962684644d65b791663eedd505a025
This commit is contained in:
Wladimir J. van der Laan 2021-02-25 09:48:28 +01:00
commit 2059d32edb
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
5 changed files with 28 additions and 16 deletions

View file

@ -23,6 +23,7 @@ import http.client
import os import os
import subprocess import subprocess
from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
from test_framework.blocktools import ( from test_framework.blocktools import (
create_block, create_block,
create_coinbase, create_coinbase,
@ -71,11 +72,10 @@ class BlockchainTest(BitcoinTestFramework):
def mine_chain(self): def mine_chain(self):
self.log.info('Create some old blocks') self.log.info('Create some old blocks')
address = self.nodes[0].get_deterministic_priv_key().address
for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600): for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):
# ten-minute steps from genesis block time # ten-minute steps from genesis block time
self.nodes[0].setmocktime(t) self.nodes[0].setmocktime(t)
self.nodes[0].generatetoaddress(1, address) self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_P2WSH_OP_TRUE)
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200) assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
def _test_getblockchaininfo(self): def _test_getblockchaininfo(self):
@ -227,7 +227,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res['transactions'], 200) assert_equal(res['transactions'], 200)
assert_equal(res['height'], 200) assert_equal(res['height'], 200)
assert_equal(res['txouts'], 200) assert_equal(res['txouts'], 200)
assert_equal(res['bogosize'], 15000), assert_equal(res['bogosize'], 16800),
assert_equal(res['bestblock'], node.getblockhash(200)) assert_equal(res['bestblock'], node.getblockhash(200))
size = res['disk_size'] size = res['disk_size']
assert size > 6400 assert size > 6400
@ -332,12 +332,12 @@ class BlockchainTest(BitcoinTestFramework):
def _test_stopatheight(self): def _test_stopatheight(self):
assert_equal(self.nodes[0].getblockcount(), 200) assert_equal(self.nodes[0].getblockcount(), 200)
self.nodes[0].generatetoaddress(6, self.nodes[0].get_deterministic_priv_key().address) self.nodes[0].generatetoaddress(6, ADDRESS_BCRT1_P2WSH_OP_TRUE)
assert_equal(self.nodes[0].getblockcount(), 206) assert_equal(self.nodes[0].getblockcount(), 206)
self.log.debug('Node should not stop at this height') self.log.debug('Node should not stop at this height')
assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3)) assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))
try: try:
self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address) self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_P2WSH_OP_TRUE)
except (ConnectionError, http.client.BadStatusLine): except (ConnectionError, http.client.BadStatusLine):
pass # The node already shut down before response pass # The node already shut down before response
self.log.debug('Node should stop at this height...') self.log.debug('Node should stop at this height...')
@ -387,8 +387,7 @@ class BlockchainTest(BitcoinTestFramework):
node = self.nodes[0] node = self.nodes[0]
miniwallet = MiniWallet(node) miniwallet = MiniWallet(node)
miniwallet.generate(5) miniwallet.scan_blocks(num=5)
node.generate(100)
fee_per_byte = Decimal('0.00000010') fee_per_byte = Decimal('0.00000010')
fee_per_kb = 1000 * fee_per_byte fee_per_kb = 1000 * fee_per_byte

View file

@ -19,6 +19,7 @@ import tempfile
import time import time
from typing import List from typing import List
from .address import ADDRESS_BCRT1_P2WSH_OP_TRUE
from .authproxy import JSONRPCException from .authproxy import JSONRPCException
from . import coverage from . import coverage
from .p2p import NetworkThread from .p2p import NetworkThread
@ -732,16 +733,17 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Set a time in the past, so that blocks don't end up in the future # Set a time in the past, so that blocks don't end up in the future
cache_node.setmocktime(cache_node.getblockheader(cache_node.getbestblockhash())['time']) cache_node.setmocktime(cache_node.getblockheader(cache_node.getbestblockhash())['time'])
# Create a 199-block-long chain; each of the 4 first nodes # Create a 199-block-long chain; each of the 3 first nodes
# gets 25 mature blocks and 25 immature. # gets 25 mature blocks and 25 immature.
# The 4th node gets only 24 immature blocks so that the very last # The 4th address gets 25 mature and only 24 immature blocks so that the very last
# block in the cache does not age too much (have an old tip age). # block in the cache does not age too much (have an old tip age).
# This is needed so that we are out of IBD when the test starts, # This is needed so that we are out of IBD when the test starts,
# see the tip age check in IsInitialBlockDownload(). # see the tip age check in IsInitialBlockDownload().
gen_addresses = [k.address for k in TestNode.PRIV_KEYS] + [ADDRESS_BCRT1_P2WSH_OP_TRUE]
for i in range(8): for i in range(8):
cache_node.generatetoaddress( cache_node.generatetoaddress(
nblocks=25 if i != 7 else 24, nblocks=25 if i != 7 else 24,
address=TestNode.PRIV_KEYS[i % 4].address, address=gen_addresses[i % 4],
) )
assert_equal(cache_node.getblockchaininfo()["blocks"], 199) assert_equal(cache_node.getblockchaininfo()["blocks"], 199)

View file

@ -32,6 +32,15 @@ class MiniWallet:
self._address = ADDRESS_BCRT1_P2WSH_OP_TRUE self._address = ADDRESS_BCRT1_P2WSH_OP_TRUE
self._scriptPubKey = hex_str_to_bytes(self._test_node.validateaddress(self._address)['scriptPubKey']) self._scriptPubKey = hex_str_to_bytes(self._test_node.validateaddress(self._address)['scriptPubKey'])
def scan_blocks(self, *, start=1, num):
"""Scan the blocks for self._address outputs and add them to self._utxos"""
for i in range(start, start + num):
block = self._test_node.getblock(blockhash=self._test_node.getblockhash(i), verbosity=2)
for tx in block['tx']:
for out in tx['vout']:
if out['scriptPubKey']['hex'] == self._scriptPubKey.hex():
self._utxos.append({'txid': tx['txid'], 'vout': out['n'], 'value': out['value']})
def generate(self, num_blocks): def generate(self, num_blocks):
"""Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list""" """Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list"""
blocks = self._test_node.generatetoaddress(num_blocks, self._address) blocks = self._test_node.generatetoaddress(num_blocks, self._address)

View file

@ -11,9 +11,10 @@ from test_framework.util import (
) )
from test_framework.messages import CTransaction, COIN from test_framework.messages import CTransaction, COIN
class TxnMallTest(BitcoinTestFramework): class TxnMallTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
self.num_nodes = 4 self.num_nodes = 3
self.supports_cli = False self.supports_cli = False
def skip_test_if_missing_module(self): def skip_test_if_missing_module(self):
@ -38,9 +39,8 @@ class TxnMallTest(BitcoinTestFramework):
# All nodes should start with 1,250 BTC: # All nodes should start with 1,250 BTC:
starting_balance = 1250 starting_balance = 1250
for i in range(4): for i in range(3):
assert_equal(self.nodes[i].getbalance(), starting_balance) assert_equal(self.nodes[i].getbalance(), starting_balance)
self.nodes[i].getnewaddress() # bug workaround, coins generated assigned to first getnewaddress!
self.nodes[0].settxfee(.001) self.nodes[0].settxfee(.001)
@ -139,5 +139,6 @@ class TxnMallTest(BitcoinTestFramework):
expected -= 50 expected -= 50
assert_equal(self.nodes[0].getbalance(), expected) assert_equal(self.nodes[0].getbalance(), expected)
if __name__ == '__main__': if __name__ == '__main__':
TxnMallTest().main() TxnMallTest().main()

View file

@ -11,9 +11,10 @@ from test_framework.util import (
find_output, find_output,
) )
class TxnMallTest(BitcoinTestFramework): class TxnMallTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
self.num_nodes = 4 self.num_nodes = 3
self.supports_cli = False self.supports_cli = False
def skip_test_if_missing_module(self): def skip_test_if_missing_module(self):
@ -39,9 +40,8 @@ class TxnMallTest(BitcoinTestFramework):
for n in self.nodes: for n in self.nodes:
assert n.getblockchaininfo()["initialblockdownload"] == False assert n.getblockchaininfo()["initialblockdownload"] == False
for i in range(4): for i in range(3):
assert_equal(self.nodes[i].getbalance(), starting_balance) assert_equal(self.nodes[i].getbalance(), starting_balance)
self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress!
# Assign coins to foo and bar addresses: # Assign coins to foo and bar addresses:
node0_address_foo = self.nodes[0].getnewaddress() node0_address_foo = self.nodes[0].getnewaddress()
@ -136,5 +136,6 @@ class TxnMallTest(BitcoinTestFramework):
# Node1's balance should be its initial balance (1250 for 25 block rewards) plus the doublespend: # Node1's balance should be its initial balance (1250 for 25 block rewards) plus the doublespend:
assert_equal(self.nodes[1].getbalance(), 1250 + 1240) assert_equal(self.nodes[1].getbalance(), 1250 + 1240)
if __name__ == '__main__': if __name__ == '__main__':
TxnMallTest().main() TxnMallTest().main()