diff --git a/docs/overview_and_guide.rst b/docs/overview_and_guide.rst index 06e016ccf8..5a39954468 100644 --- a/docs/overview_and_guide.rst +++ b/docs/overview_and_guide.rst @@ -137,7 +137,7 @@ Using geth Run the Ethereum client and let it sync:: - geth --fast --rpc --rpcapi eth,net,web3 + geth --fast --rpc --rpcapi eth,net,web3,txpool .. note:: When you want to use a testnet add the ``--testnet`` or ``--rinkeby`` flags or set the network id with ``--networkid`` directly. diff --git a/raiden/network/rpc/client.py b/raiden/network/rpc/client.py index 9b400ba7e4..b8bcbd6aae 100644 --- a/raiden/network/rpc/client.py +++ b/raiden/network/rpc/client.py @@ -32,6 +32,46 @@ log = structlog.get_logger(__name__) # pylint: disable=invalid-name +def discover_next_available_nonce( + web3: Web3, + address: typing.Address, + client_version: str, +) -> typing.Nonce: + """Returns the next available nonce for `address`.""" + + if client_version.startswith('Parity'): + return int(web3.manager.request_blocking( + "parity_nextNonce", + [address], + ), 16) + + # The nonces of the mempool transactions are considered used, and it's + # assumed these transactions are different from the ones currently pending + # in the client. This is a simplification, otherwise it would be necessary + # to filter the local pending transactions based on the mempool. + pool = web3.txpool.inspect or {} + + # pool is roughly: + # + # {'queued': {'account1': {nonce1: ... nonce2: ...}, 'account2': ...}, 'pending': ...} + # + # Pending refers to the current block and if it contains transactions from + # the user, these will be the younger transactions. Because this needs the + # largest nonce, queued is checked first. + + queued = pool.get('queued', {}).get(address) + if queued: + return max(queued.keys()) + 1 + + pending = pool.get('pending', {}).get(address) + if pending: + return max(pending.keys()) + 1 + + # The first valid nonce is 0, therefore the count is already the next + # available nonce + return web3.eth.getTransactionCount(address, 'latest') + + def check_address_has_code( client: 'JSONRPCClient', address: typing.Address, @@ -135,7 +175,6 @@ class JSONRPCClient: host: Ethereum node host address. port: Ethereum node port number. privkey: Local user private key, used to sign transactions. - nonce_offset: Network's default base nonce number. """ def __init__( @@ -143,7 +182,6 @@ def __init__( web3: Web3, privkey: bytes, gas_price_strategy: typing.Callable = rpc_gas_price_strategy, - nonce_offset: int = 0, block_num_confirmations: int = 0, ): if privkey is None or len(privkey) != 32: @@ -164,8 +202,12 @@ def __init__( _, eth_node = is_supported_client(version) address = privatekey_to_address(privkey) - transaction_count = web3.eth.getTransactionCount(to_checksum_address(address), 'pending') - _available_nonce = transaction_count + nonce_offset + + available_nonce = discover_next_available_nonce( + web3, + to_checksum_address(address), + version, + ) self.eth_node = eth_node self.privkey = privkey @@ -173,14 +215,13 @@ def __init__( self.web3 = web3 self.default_block_num_confirmations = block_num_confirmations - self._available_nonce = _available_nonce + self._available_nonce = available_nonce self._nonce_lock = Semaphore() - self._nonce_offset = nonce_offset log.debug( 'JSONRPCClient created', node=pex(self.address), - available_nonce=_available_nonce, + available_nonce=available_nonce, client=version, ) diff --git a/raiden/tests/utils/geth.py b/raiden/tests/utils/geth.py index 23811713f9..cabc26d24b 100644 --- a/raiden/tests/utils/geth.py +++ b/raiden/tests/utils/geth.py @@ -93,7 +93,7 @@ def geth_to_cmd( cmd.extend([ '--nodiscover', '--rpc', - '--rpcapi', 'eth,net,web3,personal', + '--rpcapi', 'eth,net,web3,personal,txpool', '--rpcaddr', '0.0.0.0', '--networkid', str(chain_id), '--verbosity', str(verbosity), diff --git a/raiden/ui/cli.py b/raiden/ui/cli.py index 70184a9cff..43e6bbbebf 100644 --- a/raiden/ui/cli.py +++ b/raiden/ui/cli.py @@ -475,6 +475,10 @@ def smoketest(ctx, debug, local_matrix, **kwargs): # pylint: disable=unused-arg report_file = mktemp(suffix='.log') configure_logging({'': 'DEBUG'}, log_file=report_file) + click.secho( + f'Report file: {report_file}', + fg='yellow', + ) def append_report(subject, data): with open(report_file, 'a', encoding='UTF-8') as handler: @@ -578,9 +582,9 @@ def _run_smoketest(): append_report('Ethereum stdout', out) append_report('Ethereum stderr', err) if success: - print_step(f'Smoketest successful, report was written to {report_file}') + print_step(f'Smoketest successful') else: - print_step(f'Smoketest had errors, report was written to {report_file}', error=True) + print_step(f'Smoketest had errors', error=True) return success if args['transport'] == 'udp':