Repository: bitcoin/bitcoin
File: test/functional/test_framework/test_node.py (Python)

Code before:
            except JSONRPCException as e:  # Initialization phase
                # -28 RPC in warmup
                # -342 Service unavailable, RPC server started but is shutting down due to error
                if e.error['code'] != -28 and e.error['code'] != -342:
                    raise  # unknown JSON RPC exception
            except ConnectionResetError:
                # This might happen when the RPC server is in warmup, but shut down before the call to getblockcount
                # succeeds. Try again to properly raise the FailedToStartError
                pass
            except OSError as e:
                if e.errno == errno.ETIMEDOUT:
                    pass  # Treat identical to ConnectionResetError
                elif e.errno == errno.ECONNREFUSED:
                    pass  # Port not yet open?
                else:
                    raise  # unknown OS error
            except ValueError as e:  # cookie file not found and no rpcuser or rpcpassword; bitcoind is still starting
                if "No RPC credentials" not in str(e):
                    raise
            time.sleep(1.0 / poll_per_s)
        self._raise_assertion_error("Unable to connect to bitcoind after {}s".format(self.rpc_timeout))

    def wait_for_cookie_credentials(self):
        """Ensures auth cookie credentials can be read, e.g. for testing CLI with -rpcwait before RPC connection is up."""
        self.log.debug("Waiting for cookie credentials")
        # Poll at a rate of four times per second.
        poll_per_s = 4
        for _ in range(poll_per_s * self.rpc_timeout):
            try:
                get_auth_cookie(self.datadir_path, self.chain)
                self.log.debug("Cookie credentials successfully retrieved")
                return
            except ValueError:  # cookie file not found and no rpcuser or rpcpassword; bitcoind is still starting
                pass            # so we continue polling until RPC credentials are retrieved
            time.sleep(1.0 / poll_per_s)
        self._raise_assertion_error("Unable to retrieve cookie credentials after {}s".format(self.rpc_timeout))

    def generate(self, nblocks, maxtries=1000000, **kwargs):
        self.log.debug("TestNode.generate() dispatches `generate` call to `generatetoaddress`")
        return self.generatetoaddress(nblocks=nblocks, address=self.get_deterministic_priv_key().address, maxtries=maxtries, **kwargs)

    def generateblock(self, *args, called_by_framework, **kwargs):
        assert called_by_framework, "Direct call of this mining RPC is discouraged. Please use one of the self.generate* methods on the test framework, which sync the nodes to avoid intermittent test issues. You may use sync_fun=self.no_op to disable the sync explicitly."
        return self.__getattr__('generateblock')(*args, **kwargs)

    def generatetoaddress(self, *args, called_by_framework, **kwargs):
        assert called_by_framework, "Direct call of this mining RPC is discouraged. Please use one of the self.generate* methods on the test framework, which sync the nodes to avoid intermittent test issues. You may use sync_fun=self.no_op to disable the sync explicitly."
        return self.__getattr__('generatetoaddress')(*args, **kwargs)

    def generatetodescriptor(self, *args, called_by_framework, **kwargs):
        assert called_by_framework, "Direct call of this mining RPC is discouraged. Please use one of the self.generate* methods on the test framework, which sync the nodes to avoid intermittent test issues. You may use sync_fun=self.no_op to disable the sync explicitly."

Review comment (suggestion):
Nit: this formatting pushes everything out of my screen:
```suggestion
                # Suppress similarly to the above JSONRPCException errors.
                if e.errno not in [
                    errno.ECONNRESET,  # This might happen when the RPC server is in warmup, but shut down before the call to getblockcount succeeds.
                    errno.ETIMEDOUT,   # Treat identical to ECONNRESET
                    errno.ECONNREFUSED # Port not yet open?
                ]: 
                    raise  # unknown OS error
```

Code after:
                self.rpc = rpc
                self.url = self.rpc.rpc_url
                return
            except JSONRPCException as e:
                # Suppress these as they are expected during initialization.
                # -28 RPC in warmup
                # -342 Service unavailable, could be starting up or shutting down
                if e.error['code'] not in [-28, -342]:
                    raise  # unknown JSON RPC exception
                suppressed_errors[f"JSONRPCException {e.error['code']}"] += 1
                latest_error = repr(e)
            except OSError as e:
                error_num = e.errno
                # Work around issue where socket timeouts don't have errno set.
                # https://github.com/python/cpython/issues/109601
                if error_num is None and isinstance(e, TimeoutError):
                    error_num = errno.ETIMEDOUT

                # Suppress similarly to the above JSONRPCException errors.
                if error_num not in [
                    errno.ECONNRESET,   # This might happen when the RPC server is in warmup,
                                        # but shut down before the call to getblockcount succeeds.
                    errno.ETIMEDOUT,    # Treat identical to ECONNRESET
                    errno.ECONNREFUSED  # Port not yet open?
                ]:
                    raise  # unknown OS error
                suppressed_errors[f"OSError {errno.errorcode[error_num]}"] += 1
                latest_error = repr(e)
            except ValueError as e:
                # Suppress if cookie file isn't generated yet and no rpcuser or rpcpassword; bitcoind may be starting.
                if "No RPC credentials" not in str(e):
                    raise
                suppressed_errors["missing_credentials"] += 1
                latest_error = repr(e)
            time.sleep(1.0 / poll_per_s)
        self._raise_assertion_error(f"Unable to connect to bitcoind after {self.rpc_timeout}s (ignored errors: {str(dict(suppressed_errors))}, latest error: {latest_error})")

    def wait_for_cookie_credentials(self):
        """Ensures auth cookie credentials can be read, e.g. for testing CLI with -rpcwait before RPC connection is up."""
        self.log.debug("Waiting for cookie credentials")
        # Poll at a rate of four times per second.
        poll_per_s = 4
        for _ in range(poll_per_s * self.rpc_timeout):
            try:
                get_auth_cookie(self.datadir_path, self.chain)
                self.log.debug("Cookie credentials successfully retrieved")
                return
            except ValueError:  # cookie file not found and no rpcuser or rpcpassword; bitcoind is still starting
                pass            # so we continue polling until RPC credentials are retrieved
            time.sleep(1.0 / poll_per_s)
        self._raise_assertion_error("Unable to retrieve cookie credentials after {}s".format(self.rpc_timeout))