mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-16 09:39:52 +02:00
Merge bitcoin/bitcoin#35458: qa: Avoid extra tracebacks when exception is raised
472b950b7fqa: Use custom assert_greater_than() over naked assert (Hodlinator)f42226d526qa: Silence socket.timeout exception when substituting it for a JSONRPCException (Hodlinator)659671ac3dqa: Avoid cleanup when exception is raised (Hodlinator) Pull request description: Clean up some cases in which we would trigger multiple tracebacks, which makes it unclear what issue is occuring (https://github.com/bitcoin/bitcoin/issues/31894#issuecomment-4616130031). CI log of this occurring: https://github.com/bitcoin/bitcoin/actions/runs/26907239657/job/79375388058?pr=35179 <details><summary>Relevant log excerpt</summary> ``` test 2026-06-03T19:28:28.119804Z TestFramework.node0 (DEBUG): TestNode.generate() dispatches `generate` call to `generatetoaddress` test 2026-06-03T19:28:28.120483Z TestFramework (ERROR): Unexpected exception: Traceback (most recent call last): File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/authproxy.py", line 165, in _get_response http_response = self.__conn.getresponse() ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/http/client.py", line 1448, in getresponse response.begin() File "/usr/lib/python3.12/http/client.py", line 336, in begin version, status, reason = self._read_status() ^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/http/client.py", line 297, in _read_status line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/socket.py", line 707, in readinto return self._sock.recv_into(b) ^^^^^^^^^^^^^^^^^^^^^^^ TimeoutError: timed out During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/runner/work/bitcoin/bitcoin/ci_build/test/functional/p2p_orphan_handling.py", line 54, in wrapper func(self) File "/home/runner/work/bitcoin/bitcoin/ci_build/test/functional/p2p_orphan_handling.py", line 633, in test_maximal_package_protected testres = node.testmempoolaccept([large_orphan.serialize().hex()]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/coverage.py", line 50, in __call__ return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/authproxy.py", line 128, in __call__ response, status = self._request('POST', self.__url.path, postdata.encode('utf-8')) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/authproxy.py", line 102, in _request return self._get_response() ^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/authproxy.py", line 167, in _get_response raise JSONRPCException({ test_framework.util.JSONRPCException: 'testmempoolaccept' RPC took longer than 30.000000 seconds. Consider using larger timeout for calls that take longer to return. (-344) [http_status=None] During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/test_framework.py", line 143, in main self.run_test() File "/home/runner/work/bitcoin/bitcoin/ci_build/test/functional/p2p_orphan_handling.py", line 837, in run_test self.test_maximal_package_protected() File "/home/runner/work/bitcoin/bitcoin/ci_build/test/functional/p2p_orphan_handling.py", line 57, in wrapper self.generate(self.nodes[0], 1) File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/test_framework.py", line 666, in generate blocks = generator.generate(*args, called_by_framework=True, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/test_node.py", line 445, in generate return self.generatetoaddress(nblocks=nblocks, address=self.get_deterministic_priv_key().address, maxtries=maxtries, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/test_node.py", line 453, in generatetoaddress return self.__getattr__('generatetoaddress')(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/coverage.py", line 50, in __call__ return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/authproxy.py", line 128, in __call__ response, status = self._request('POST', self.__url.path, postdata.encode('utf-8')) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/runner/work/bitcoin/bitcoin/test/functional/test_framework/authproxy.py", line 101, in _request self.__conn.request(method, path, postdata, headers) File "/usr/lib/python3.12/http/client.py", line 1356, in request self._send_request(method, url, body, headers, encode_chunked) File "/usr/lib/python3.12/http/client.py", line 1367, in _send_request self.putrequest(method, url, **skips) File "/usr/lib/python3.12/http/client.py", line 1193, in putrequest raise CannotSendRequest(self.__state) http.client.CannotSendRequest: Request-sent test 2026-06-03T19:28:28.124908Z TestFramework (DEBUG): Closing down network thread ``` </details> Fix in authproxy.py can be verified through applying the below diff with/without PR changes and running `./build/test/functional/p2p_orphan_handling.py`: ```diff --- a/test/functional/test_framework/authproxy.py +++ b/test/functional/test_framework/authproxy.py @@ -162,6 +162,8 @@ class AuthServiceProxy(): def _get_response(self): req_start_time = time.time() try: + if AuthServiceProxy.__id_count > 55: + raise socket.timeout() http_response = self.__conn.getresponse() except socket.timeout: raise JSONRPCException({ ``` ACKs for top commit: maflcko: review ACK472b950b7f🔼 polespinasa: reACK472b950b7fTree-SHA512: ec1ede0340da9d1338643980e7f2e4646f0aed2e64f339f8b41a447cbbfb4da8158c1cbcb22f2d0cc383c2dd945075602d02b07a47b33b44cc6215f3292c1d46
This commit is contained in:
@@ -30,13 +30,12 @@ def weight_to_vsize(weight):
|
||||
|
||||
def cleanup(func):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
func(self, *args, **kwargs)
|
||||
finally:
|
||||
# Mine blocks to clear the mempool and replenish the wallet's confirmed UTXOs.
|
||||
while (len(self.nodes[0].getrawmempool()) > 0):
|
||||
self.generate(self.nodes[0], 1)
|
||||
self.wallet.rescan_utxos(include_mempool=True)
|
||||
func(self, *args, **kwargs)
|
||||
|
||||
# Mine blocks to clear the mempool and replenish the wallet's confirmed UTXOs.
|
||||
while (len(self.nodes[0].getrawmempool()) > 0):
|
||||
self.generate(self.nodes[0], 1)
|
||||
self.wallet.rescan_utxos(include_mempool=True)
|
||||
return wrapper
|
||||
|
||||
class MempoolClusterTest(BitcoinTestFramework):
|
||||
|
||||
@@ -29,15 +29,14 @@ TRUC_CHILD_MAX_VSIZE = 1000
|
||||
def cleanup(extra_args=None):
|
||||
def decorator(func):
|
||||
def wrapper(self):
|
||||
try:
|
||||
if extra_args is not None:
|
||||
self.restart_node(0, extra_args=extra_args)
|
||||
func(self)
|
||||
finally:
|
||||
# Clear mempool again after test
|
||||
self.generate(self.nodes[0], 1)
|
||||
if extra_args is not None:
|
||||
self.restart_node(0)
|
||||
if extra_args is not None:
|
||||
self.restart_node(0, extra_args=extra_args)
|
||||
func(self)
|
||||
|
||||
# Clear mempool again after test
|
||||
self.generate(self.nodes[0], 1)
|
||||
if extra_args is not None:
|
||||
self.restart_node(0)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
@@ -58,18 +58,17 @@ GETDATA_WAIT = 60
|
||||
|
||||
def cleanup(func):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
func(self, *args, **kwargs)
|
||||
finally:
|
||||
self.nodes[0].disconnect_p2ps()
|
||||
# Do not clear the node's mempool, as each test requires mempool min feerate > min
|
||||
# relay feerate. However, do check that this is the case.
|
||||
assert self.nodes[0].getmempoolinfo()["mempoolminfee"] > self.nodes[0].getnetworkinfo()["relayfee"]
|
||||
# Ensure we do not try to spend the same UTXOs in subsequent tests, as they will look like RBF attempts.
|
||||
self.wallet.rescan_utxos(include_mempool=True)
|
||||
func(self, *args, **kwargs)
|
||||
|
||||
# Resets if mocktime was used
|
||||
self.nodes[0].setmocktime(0)
|
||||
self.nodes[0].disconnect_p2ps()
|
||||
# Do not clear the node's mempool, as each test requires mempool min feerate > min
|
||||
# relay feerate. However, do check that this is the case.
|
||||
assert_greater_than(self.nodes[0].getmempoolinfo()["mempoolminfee"], self.nodes[0].getnetworkinfo()["relayfee"])
|
||||
# Ensure we do not try to spend the same UTXOs in subsequent tests, as they will look like RBF attempts.
|
||||
self.wallet.rescan_utxos(include_mempool=True)
|
||||
|
||||
# Resets if mocktime was used
|
||||
self.nodes[0].setmocktime(0)
|
||||
return wrapper
|
||||
|
||||
class PackageRelayTest(BitcoinTestFramework):
|
||||
|
||||
@@ -50,20 +50,19 @@ TXREQUEST_TIME_SKIP = NONPREF_PEER_TX_DELAY + TXID_RELAY_DELAY + OVERLOADED_PEER
|
||||
|
||||
def cleanup(func):
|
||||
def wrapper(self):
|
||||
try:
|
||||
func(self)
|
||||
finally:
|
||||
# Clear mempool
|
||||
self.generate(self.nodes[0], 1)
|
||||
self.nodes[0].disconnect_p2ps()
|
||||
# Check that mempool and orphanage have been cleared
|
||||
self.wait_until(lambda: len(self.nodes[0].getorphantxs()) == 0)
|
||||
assert_equal(0, len(self.nodes[0].getrawmempool()))
|
||||
func(self)
|
||||
|
||||
self.restart_node(0, extra_args=["-persistmempool=0"])
|
||||
# Allow use of bumpmocktime again
|
||||
self.nodes[0].setmocktime(int(time.time()))
|
||||
self.wallet.rescan_utxos(include_mempool=True)
|
||||
# Clear mempool
|
||||
self.generate(self.nodes[0], 1)
|
||||
self.nodes[0].disconnect_p2ps()
|
||||
# Check that mempool and orphanage have been cleared
|
||||
self.wait_until(lambda: len(self.nodes[0].getorphantxs()) == 0)
|
||||
assert_equal(0, len(self.nodes[0].getrawmempool()))
|
||||
|
||||
self.restart_node(0, extra_args=["-persistmempool=0"])
|
||||
# Allow use of bumpmocktime again
|
||||
self.nodes[0].setmocktime(int(time.time()))
|
||||
self.wallet.rescan_utxos(include_mempool=True)
|
||||
return wrapper
|
||||
|
||||
class PeerTxRelayer(P2PTxInvStore):
|
||||
|
||||
@@ -169,7 +169,7 @@ class AuthServiceProxy():
|
||||
'message': '%r RPC took longer than %f seconds. Consider '
|
||||
'using larger timeout for calls that take '
|
||||
'longer to return.' % (self._service_name,
|
||||
self.__conn.timeout)})
|
||||
self.__conn.timeout)}) from None
|
||||
if http_response is None:
|
||||
raise JSONRPCException({
|
||||
'code': -342, 'message': 'missing HTTP response from server'})
|
||||
|
||||
@@ -18,12 +18,11 @@ from test_framework.util import (
|
||||
# Decorator to reset activewallet to zero utxos
|
||||
def cleanup(func):
|
||||
def wrapper(self):
|
||||
try:
|
||||
func(self)
|
||||
finally:
|
||||
if 0 < self.wallet.getbalances()["mine"]["trusted"]:
|
||||
self.wallet.sendall([self.remainder_target])
|
||||
assert_equal(0, self.wallet.getbalances()["mine"]["trusted"]) # wallet is empty
|
||||
func(self)
|
||||
|
||||
if 0 < self.wallet.getbalances()["mine"]["trusted"]:
|
||||
self.wallet.sendall([self.remainder_target])
|
||||
assert_equal(0, self.wallet.getbalances()["mine"]["trusted"]) # wallet is empty
|
||||
return wrapper
|
||||
|
||||
class SendallTest(BitcoinTestFramework):
|
||||
|
||||
@@ -38,28 +38,27 @@ from test_framework.mempool_util import (
|
||||
# sweep alice and bob's wallets and clear the mempool
|
||||
def cleanup(func):
|
||||
def wrapper(self, *args):
|
||||
try:
|
||||
self.generate(self.nodes[0], 1)
|
||||
func(self, *args)
|
||||
finally:
|
||||
self.generate(self.nodes[0], 1)
|
||||
for wallet in [self.alice, self.bob]:
|
||||
txs = set(tx["txid"] for tx in wallet.listtransactions("*", 1000) if tx["confirmations"] == 0 and not tx["abandoned"])
|
||||
for tx in txs:
|
||||
wallet.abandontransaction(tx)
|
||||
try:
|
||||
wallet.sendall([self.charlie.getnewaddress()])
|
||||
except JSONRPCException as e:
|
||||
assert "Total value of UTXO pool too low to pay for transaction" in e.error['message']
|
||||
self.generate(self.nodes[0], 1)
|
||||
self.generate(self.nodes[0], 1)
|
||||
func(self, *args)
|
||||
|
||||
for wallet in [self.alice, self.bob]:
|
||||
balance = wallet.getbalances()["mine"]
|
||||
for balance_type in ["untrusted_pending", "trusted", "immature", "nonmempool"]:
|
||||
assert_equal(balance[balance_type], 0)
|
||||
self.generate(self.nodes[0], 1)
|
||||
for wallet in [self.alice, self.bob]:
|
||||
txs = set(tx["txid"] for tx in wallet.listtransactions("*", 1000) if tx["confirmations"] == 0 and not tx["abandoned"])
|
||||
for tx in txs:
|
||||
wallet.abandontransaction(tx)
|
||||
try:
|
||||
wallet.sendall([self.charlie.getnewaddress()])
|
||||
except JSONRPCException as e:
|
||||
assert "Total value of UTXO pool too low to pay for transaction" in e.error['message']
|
||||
self.generate(self.nodes[0], 1)
|
||||
|
||||
assert_equal(self.alice.getrawmempool(), [])
|
||||
assert_equal(self.bob.getrawmempool(), [])
|
||||
for wallet in [self.alice, self.bob]:
|
||||
balance = wallet.getbalances()["mine"]
|
||||
for balance_type in ["untrusted_pending", "trusted", "immature", "nonmempool"]:
|
||||
assert_equal(balance[balance_type], 0)
|
||||
|
||||
assert_equal(self.alice.getrawmempool(), [])
|
||||
assert_equal(self.bob.getrawmempool(), [])
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
Reference in New Issue
Block a user