0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-10 10:52:31 -05:00

Merge bitcoin/bitcoin#24941: test: MiniWallet: support skipping mempool checks (feature_fee_estimation.py performance fix)

a498acce45 test: MiniWallet: skip mempool check if `mempool_valid=False` (Sebastian Falbesoner)
01552e8f67 test: MiniWallet: always rehash after signing (P2PK mode) (Sebastian Falbesoner)

Pull request description:

  MiniWallet's core method for creating txs (`create_self_transfer`) right now always executes the `testmempoolaccept` RPC to check for mempool validity or invalidity. In some test cases where we use MiniWallet to create a huge number of transactions this can lead to performance issues, in particular feature_fee_estimation.py where the execution time after MiniWallet usage (PR #24817) doubled, see https://github.com/bitcoin/bitcoin/issues/24828#issuecomment-1100058100, https://github.com/bitcoin/bitcoin/issues/24828#issuecomment-1100301980. This PR mitigates this by skipping the mempool check if the parameter `mempool_valid` is set to `False`.

  As a preparatory commit, the test feature_csv_activation.py has to be adapted w.r.t. to rehashing of transactions, as we now hash all transactions immediately in `create_self_transfer` in order to get the txid (before we relied on the result of `testmempoolaccept`).

  On my machine, this decreases the execution time quite noticably:

  master branch:
  ```
  $ time ./test/functional/feature_fee_estimation.py
  real    3m20.771s
  user    2m52.360s
  sys     0m39.340s
  ```

  PR branch:
  ```
  $ time ./test/functional/feature_fee_estimation.py
  real    2m1.386s
  user    1m42.510s
  sys     0m22.980s
  ```

  Partly fixes #24828 (hopefully).

ACKs for top commit:
  danielabrozzoni:
    tACK a498acce45

Tree-SHA512: f20c358ba42b2ded86175f46ff3ff9eaefb84175cbd1c2624f44904c8d8888e67ce64d6dcbb26aabbf07906e6f5bdea40353eba9ae668618cadcfc517ef7201b
This commit is contained in:
MacroFake 2022-05-03 09:59:42 +02:00
commit d24318a40c
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
2 changed files with 9 additions and 10 deletions

View file

@ -112,6 +112,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
tx.nVersion = txversion tx.nVersion = txversion
self.miniwallet.sign_tx(tx) self.miniwallet.sign_tx(tx)
tx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig))) tx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig)))
tx.rehash()
return tx return tx
def create_bip112emptystack(self, input, txversion): def create_bip112emptystack(self, input, txversion):
@ -119,6 +120,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
tx.nVersion = txversion tx.nVersion = txversion
self.miniwallet.sign_tx(tx) self.miniwallet.sign_tx(tx)
tx.vin[0].scriptSig = CScript([OP_CHECKSEQUENCEVERIFY] + list(CScript(tx.vin[0].scriptSig))) tx.vin[0].scriptSig = CScript([OP_CHECKSEQUENCEVERIFY] + list(CScript(tx.vin[0].scriptSig)))
tx.rehash()
return tx return tx
def send_generic_input_tx(self, coinbases): def send_generic_input_tx(self, coinbases):
@ -136,7 +138,6 @@ class BIP68_112_113Test(BitcoinTestFramework):
tx.nVersion = txversion tx.nVersion = txversion
tx.vin[0].nSequence = locktime + locktime_delta tx.vin[0].nSequence = locktime + locktime_delta
self.miniwallet.sign_tx(tx) self.miniwallet.sign_tx(tx)
tx.rehash()
txs.append({'tx': tx, 'sdf': sdf, 'stf': stf}) txs.append({'tx': tx, 'sdf': sdf, 'stf': stf})
return txs return txs
@ -339,20 +340,16 @@ class BIP68_112_113Test(BitcoinTestFramework):
# BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules # BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules
bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
self.miniwallet.sign_tx(bip113tx_v1) self.miniwallet.sign_tx(bip113tx_v1)
bip113tx_v1.rehash()
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
self.miniwallet.sign_tx(bip113tx_v2) self.miniwallet.sign_tx(bip113tx_v2)
bip113tx_v2.rehash()
for bip113tx in [bip113tx_v1, bip113tx_v2]: for bip113tx in [bip113tx_v1, bip113tx_v2]:
self.send_blocks([self.create_test_block([bip113tx])], success=False, reject_reason='bad-txns-nonfinal') self.send_blocks([self.create_test_block([bip113tx])], success=False, reject_reason='bad-txns-nonfinal')
# BIP 113 tests should now pass if the locktime is < MTP # BIP 113 tests should now pass if the locktime is < MTP
bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block
self.miniwallet.sign_tx(bip113tx_v1) self.miniwallet.sign_tx(bip113tx_v1)
bip113tx_v1.rehash()
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block
self.miniwallet.sign_tx(bip113tx_v2) self.miniwallet.sign_tx(bip113tx_v2)
bip113tx_v2.rehash()
for bip113tx in [bip113tx_v1, bip113tx_v2]: for bip113tx in [bip113tx_v1, bip113tx_v2]:
self.send_blocks([self.create_test_block([bip113tx])]) self.send_blocks([self.create_test_block([bip113tx])])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
@ -477,7 +474,6 @@ class BIP68_112_113Test(BitcoinTestFramework):
for tx in [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]: for tx in [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]:
tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME | SEQ_TYPE_FLAG tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME | SEQ_TYPE_FLAG
self.miniwallet.sign_tx(tx) self.miniwallet.sign_tx(tx)
tx.rehash()
time_txs.append(tx) time_txs.append(tx)
self.send_blocks([self.create_test_block(time_txs)]) self.send_blocks([self.create_test_block(time_txs)])

View file

@ -127,6 +127,7 @@ class MiniWallet:
if not fixed_length: if not fixed_length:
break break
tx.vin[0].scriptSig = CScript([der_sig + bytes(bytearray([SIGHASH_ALL]))]) tx.vin[0].scriptSig = CScript([der_sig + bytes(bytearray([SIGHASH_ALL]))])
tx.rehash()
def generate(self, num_blocks, **kwargs): def generate(self, num_blocks, **kwargs):
"""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"""
@ -233,7 +234,8 @@ class MiniWallet:
return tx return tx
def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node=None, utxo_to_spend=None, mempool_valid=True, locktime=0, sequence=0): def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node=None, utxo_to_spend=None, mempool_valid=True, locktime=0, sequence=0):
"""Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.""" """Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.
Checking mempool validity via the testmempoolaccept RPC can be skipped by setting mempool_valid to False."""
from_node = from_node or self._test_node from_node = from_node or self._test_node
utxo_to_spend = utxo_to_spend or self.get_utxo() utxo_to_spend = utxo_to_spend or self.get_utxo()
if self._priv_key is None: if self._priv_key is None:
@ -260,12 +262,13 @@ class MiniWallet:
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key] tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key]
tx_hex = tx.serialize().hex() tx_hex = tx.serialize().hex()
tx_info = from_node.testmempoolaccept([tx_hex])[0]
assert_equal(mempool_valid, tx_info['allowed'])
if mempool_valid: if mempool_valid:
tx_info = from_node.testmempoolaccept([tx_hex])[0]
assert_equal(tx_info['allowed'], True)
assert_equal(tx_info['vsize'], vsize) assert_equal(tx_info['vsize'], vsize)
assert_equal(tx_info['fees']['base'], utxo_to_spend['value'] - Decimal(send_value) / COIN) assert_equal(tx_info['fees']['base'], utxo_to_spend['value'] - Decimal(send_value) / COIN)
return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex, 'tx': tx}
return {'txid': tx.rehash(), 'wtxid': tx.getwtxid(), 'hex': tx_hex, 'tx': tx}
def sendrawtransaction(self, *, from_node, tx_hex, **kwargs): def sendrawtransaction(self, *, from_node, tx_hex, **kwargs):
txid = from_node.sendrawtransaction(hexstring=tx_hex, **kwargs) txid = from_node.sendrawtransaction(hexstring=tx_hex, **kwargs)