0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-05 14:06:27 -05:00

Merge bitcoin/bitcoin#27035: test: simplify and speedup mempool_updatefromblock.py by using MiniWallet

dee8549be3 test: simplify and speedup mempool_updatefromblock.py by using MiniWallet (Sebastian Falbesoner)

Pull request description:

  This PR simplifies the functional test mempool_updatefromblock.py by using MiniWallet in order to avoid manual low-level tx creation (signing, outputs selection, fee calculation). Most of the tedious work is done by the method `MiniWallet.send_self_transfer_multi` (calling `create_self_transfer_multi` internally) which supports spending a given set of UTXOs and creating a certain number of outputs.

  As a nice side-effect, the test's performance increases significantly (~3.5x on my system):

  ```
  master
      1m56.80s real     1m50.10s user     0m06.36s system

  PR
      0m32.34s real     0m30.26s user     0m01.41s system
  ```

  The arguments `start_input_txid` and `end_address` have been removed from the `transaction_graph_test` method, as they are currently unused and I don't see them being needed for future tests.

ACKs for top commit:
  brunoerg:
    crACK dee8549be3
  MarcoFalke:
    lgtm ACK dee8549be3 🚏

Tree-SHA512: 9f6da634bdc8c272f9a2af1cddaa364ee371d4e95554463a066249eecebb668d8c6cb123ec8a5404c41b3291010c0c8806a8a01dd227733cec03e73aa93b0103
This commit is contained in:
merge-script 2023-02-15 16:26:00 +01:00
commit a65d2259f1
No known key found for this signature in database
GPG key ID: CE2B75697E69A548

View file

@ -7,14 +7,12 @@
Test mempool update of transaction descendants/ancestors information (count, size) Test mempool update of transaction descendants/ancestors information (count, size)
when transactions have been re-added from a disconnected block to the mempool. when transactions have been re-added from a disconnected block to the mempool.
""" """
from math import ceil
import time import time
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal from test_framework.util import assert_equal
from test_framework.address import key_to_p2pkh from test_framework.wallet import MiniWallet
from test_framework.wallet_util import bytes_to_wif
from test_framework.key import ECKey
class MempoolUpdateFromBlockTest(BitcoinTestFramework): class MempoolUpdateFromBlockTest(BitcoinTestFramework):
@ -22,15 +20,7 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
self.num_nodes = 1 self.num_nodes = 1
self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000', '-limitancestorcount=100']] self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000', '-limitancestorcount=100']]
def get_new_address(self): def transaction_graph_test(self, size, n_tx_to_mine=None, fee=100_000):
key = ECKey()
key.generate()
pubkey = key.get_pubkey().get_bytes()
address = key_to_p2pkh(pubkey)
self.priv_keys.append(bytes_to_wif(key.get_bytes()))
return address
def transaction_graph_test(self, size, n_tx_to_mine=None, start_input_txid='', end_address='', fee=Decimal(0.00100000)):
"""Create an acyclic tournament (a type of directed graph) of transactions and use it for testing. """Create an acyclic tournament (a type of directed graph) of transactions and use it for testing.
Keyword arguments: Keyword arguments:
@ -45,14 +35,7 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
More details: https://en.wikipedia.org/wiki/Tournament_(graph_theory) More details: https://en.wikipedia.org/wiki/Tournament_(graph_theory)
""" """
wallet = MiniWallet(self.nodes[0])
self.priv_keys = [self.nodes[0].get_deterministic_priv_key().key]
if not start_input_txid:
start_input_txid = self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0]
if not end_address:
end_address = self.get_new_address()
first_block_hash = '' first_block_hash = ''
tx_id = [] tx_id = []
tx_size = [] tx_size = []
@ -61,41 +44,31 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
self.log.debug('Preparing transaction #{}...'.format(i)) self.log.debug('Preparing transaction #{}...'.format(i))
# Prepare inputs. # Prepare inputs.
if i == 0: if i == 0:
inputs = [{'txid': start_input_txid, 'vout': 0}] inputs = [wallet.get_utxo()] # let MiniWallet provide a start UTXO
inputs_value = self.nodes[0].gettxout(start_input_txid, 0)['value']
else: else:
inputs = [] inputs = []
inputs_value = 0
for j, tx in enumerate(tx_id[0:i]): for j, tx in enumerate(tx_id[0:i]):
# Transaction tx[K] is a child of each of previous transactions tx[0]..tx[K-1] at their output K-1. # Transaction tx[K] is a child of each of previous transactions tx[0]..tx[K-1] at their output K-1.
vout = i - j - 1 vout = i - j - 1
inputs.append({'txid': tx_id[j], 'vout': vout}) inputs.append(wallet.get_utxo(txid=tx_id[j], vout=vout))
inputs_value += self.nodes[0].gettxout(tx, vout)['value']
self.log.debug('inputs={}'.format(inputs))
self.log.debug('inputs_value={}'.format(inputs_value))
# Prepare outputs. # Prepare outputs.
tx_count = i + 1 tx_count = i + 1
if tx_count < size: if tx_count < size:
# Transaction tx[K] is an ancestor of each of subsequent transactions tx[K+1]..tx[N-1]. # Transaction tx[K] is an ancestor of each of subsequent transactions tx[K+1]..tx[N-1].
n_outputs = size - tx_count n_outputs = size - tx_count
output_value = ((inputs_value - fee) / Decimal(n_outputs)).quantize(Decimal('0.00000001'))
outputs = {}
for _ in range(n_outputs):
outputs[self.get_new_address()] = output_value
else: else:
output_value = (inputs_value - fee).quantize(Decimal('0.00000001')) n_outputs = 1
outputs = {end_address: output_value}
self.log.debug('output_value={}'.format(output_value))
self.log.debug('outputs={}'.format(outputs))
# Create a new transaction. # Create a new transaction.
unsigned_raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) new_tx = wallet.send_self_transfer_multi(
signed_raw_tx = self.nodes[0].signrawtransactionwithkey(unsigned_raw_tx, self.priv_keys) from_node=self.nodes[0],
tx_id.append(self.nodes[0].sendrawtransaction(signed_raw_tx['hex'])) utxos_to_spend=inputs,
tx_size.append(self.nodes[0].getmempoolentry(tx_id[-1])['vsize']) num_outputs=n_outputs,
fee_per_output=ceil(fee / n_outputs)
)
tx_id.append(new_tx['txid'])
tx_size.append(new_tx['tx'].get_vsize())
if tx_count in n_tx_to_mine: if tx_count in n_tx_to_mine:
# The created transactions are mined into blocks by batches. # The created transactions are mined into blocks by batches.