web3.py: Broken w3.geth.txpool.content()
Expected behavior
w3.geth.txpool.content() returns a list of all full pending transactions
Actual behavior
When using IPCProvider, w3.geth.txpool.content() returns:
[redacted file name]
txs = w3.geth.txpool.content()
File "/usr/local/lib/python3.6/dist-packages/web3/module.py", line 12, in caller
w3.manager.request_blocking(method_str, params),
File "/usr/local/lib/python3.6/dist-packages/web3/manager.py", line 94, in request_blocking
response = self._make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/manager.py", line 81, in _make_request
return request_func(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/gas_price_strategy.py", line 18, in middleware
return make_request(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/attrdict.py", line 18, in middleware
response = make_request(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/normalize_errors.py", line 9, in middleware
result = make_request(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/providers/ipc.py", line 238, in make_request
timeout.sleep(0)
File "/usr/local/lib/python3.6/dist-packages/web3/_utils/threads.py", line 68, in sleep
self.check()
File "/usr/local/lib/python3.6/dist-packages/web3/_utils/threads.py", line 61, in check
raise self
web3._utils.threads.Timeout: 10 seconds
When using WebsocketProvider, w3.geth.txpool.content() returns:
txs = = w3.geth.txpool.content()
File "/usr/local/lib/python3.6/dist-packages/web3/module.py", line 12, in caller
w3.manager.request_blocking(method_str, params),
File "/usr/local/lib/python3.6/dist-packages/web3/manager.py", line 94, in request_blocking
response = self._make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/manager.py", line 81, in _make_request
return request_func(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/gas_price_strategy.py", line 18, in middleware
return make_request(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/attrdict.py", line 18, in middleware
response = make_request(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/normalize_errors.py", line 9, in middleware
result = make_request(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
File "/usr/local/lib/python3.6/dist-packages/web3/middleware/formatting.py", line 50, in apply_formatters
response = make_request(method, params)
File "/usr/local/lib/python3.6/dist-packages/web3/providers/websocket.py", line 119, in make_request
return future.result()
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 432, in result
return self.__get_result()
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
File "/usr/local/lib/python3.6/dist-packages/web3/providers/websocket.py", line 107, in coro_make_request
timeout=self.websocket_timeout
File "/usr/lib/python3.6/asyncio/tasks.py", line 362, in wait_for
raise futures.TimeoutError()
concurrent.futures._base.TimeoutError
Steps to reproduce the behavior
Just running in the terminal python3 fileName where fileName has the following code included:
from web3 import Web3, IPCProvider, WebsocketProvider, HTTPProvider
IPCPath = '/root/.ethereum/geth.ipc'
w3 = Web3(IPCProvider(IPCPath))
txs = w3.geth.txpool.content().pending
Versions
web3.py 5.4.0 ubuntu 18.04.3 LTS python3.6.9 Geth 1.9.9-stable
Extra info
I’ve tried the following which all had no effect:
- using python3.7
- different versions of web3.py (5.2.0, 5.3.0 etc)
- changing the timeout in
w3 = Web3(IPCProvider(IPCPath, timeout=30))between 1s and 30s
w3.geth.txpool.status() works fine
w3.geth.txpool.inspect() works fine
Doing:
geth attach
txpool.content
works fine
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 20 (2 by maintainers)
I’ve had various issues with how WebsocketProvider seems to work and ultimately I figured the best way to figure things out is with doing some testing and logging things. I personally never ran into the IPCProvider problem unless there was some sort of permission issue with the actual file itself, which can be solved if you run the node not as root but as a regular user (assuming you’re running it as a service at startup, of course). WebsocketProvider though, needed a bit of tweaking to get working properly. A very basic setup that works is:
If all you need is to get it working, well, that works for me at least (Debian 10, Python 3.8.6, Web3.py 5.12.3).
To figure out what’s going on under the hood though, I did some quick logging, the logs are here: gist.github.com/jimtje/c0cdb6fd1310f6d5d7abc4f94c5e99c7
It gets truncated but essentially it takes about the same time (around 3 seconds) for both methods to work through the pending txes in the mempool, but whereas IPCProvider begins iterating results immediately while with WS, the entire pending pool is read out and then iterated. This creates a bottleneck with the default settings since the default max_size is 2 ** 20 (1,048,576) and default timeout is 10, and if there are a ton of pending it’s entirely possible that either one of the defaults won’t allow the whole pool to get read, especially if you’re not running a local node (I’m actually running a remote python interpreter through an ssh tunnel so it certainly feels like a much greater latency to me, although not to the actual script). I don’t know if there’s something specific to fix in the sense that this implementation seems to work as intended as long as the end user knows that the default settings may need some tweaking.
However I think this may be a pretty inefficient way to run a websocket client when it comes to processing txes in the mempool. I’d prefer using a trio/anyio type of setup since there exists a clear sort of parent/child task structure and each new block serves as a distinct demarcation point as to when the pool needs to be polled afresh, but that’s somewhat off topic. For this issue I think as long as you add a healthy overhead to both websocket_timeout and max_size you should be okay.