Repository: ethereum/web3.py

Issue:
local_filter_middleware doesn't work with geth nodes
Hi,

`get_filter_changes()` raises exception when used with `local_filter_middleware`.

```
Traceback (most recent call last):
  File "/pyroot/lib/python3.7/site-packages/web3/_utils/filters.py", line 121, in get_new_entries
    log_entries = self._filter_valid_entries(self.web3.eth.getFilterChanges(self.filter_id))
  File "/pyroot/lib/python3.7/site-packages/web3/eth.py", line 402, in getFilterChanges
    "eth_getFilterChanges", [filter_id],
  File "/pyroot/lib/python3.7/site-packages/web3/manager.py", line 109, in request_blocking
    response = self._make_request(method, params)
  File "/pyroot/lib/python3.7/site-packages/web3/manager.py", line 96, in _make_request
    return request_func(method, params)
  File "/pyroot/lib/python3.7/site-packages/web3/middleware/filter.py", line 313, in middleware
    return {'result': next(_filter.filter_changes)}
StopIteration
```

* Version: 5.3.0
* Python: 3.7
* OS: linux
* Node type: geth
* Node version: 1.9.7-stable



Discussion:
@tsudmi will you provide a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) please? That will help troubleshoot exactly what is going on. Thanks!
Hi @kclowes ,

I run something like this:
```python
from web3 import Web3
from web3.middleware import geth_poa_middleware, local_filter_middleware

WEB3_WS_ENDPOINT = ''
CONTRACT_ADDRESS = ''
ABI = []

w3 = Web3(Web3.WebsocketProvider(WEB3_WS_ENDPOINT))
w3.middleware_onion.add(local_filter_middleware)

contract = w3.eth.contract(
    abi=ABI,
    address=CONTRACT_ADDRESS
)
event_filter = contract.events.SomeEvent.createFilter(fromBlock=w3.eth.blockNumber)
events = event_filter.get_new_entries()
```
The error occures quite randomly, but regularly.
@kclowes it looks a lot like that `StopIteration` just needs to be caught and handled.  Without having looked at the code I suspect it will mean "no new logs" but I'm not confident in that diagnosis.

Resolving patch:
diff --git a/web3/middleware/filter.py b/web3/middleware/filter.py
--- a/web3/middleware/filter.py
+++ b/web3/middleware/filter.py
@@ -121,12 +121,10 @@ def iter_latest_block(
     """Returns a generator that dispenses the latest block, if
     any new blocks have been mined since last iteration.
 
-    If there are no new blocks None is returned.
+    If there are no new blocks or the latest block is greater than
+    the ``to_block`` None is returned.
 
-    If ``to_block`` is defined, ``StopIteration`` is raised
-    after to_block is reached.
-
-    >>> mined_blocks = dispense_mined_blocks(w3, 0, 10)
+    >>> new_blocks = iter_latest_block(w3, 0, 10)
     >>> next(new_blocks)  # Latest block = 0
     0
     >>> next(new_blocks)  # No new blocks
@@ -134,11 +132,7 @@ def iter_latest_block(
     1
     >>> next(new_blocks)  # Latest block = 10
     10
-    >>> next(new_blocks)
-    Traceback (most recent call last):
-      File "<stdin>", line 1, in <module>
-      StopIteration
-    >>>
+    >>> next(new_blocks)  # latest block > to block
     """
     _last = None
 
@@ -151,7 +145,7 @@ def iter_latest_block(
         latest_block = w3.eth.blockNumber
         # type ignored b/c is_bounded_range prevents unsupported comparison
         if is_bounded_range and latest_block > to_block:  # type: ignore
-            return
+            yield None
         #  No new blocks since last iteration.
         if _last is not None and _last == latest_block:
             yield None
@@ -256,16 +250,16 @@ def _get_filter_changes(self) -> Iterator[List[LogReceipt]]:
         for start, stop in iter_latest_block_ranges(self.w3, self.from_block, self.to_block):
             if None in (start, stop):
                 yield []
-
-            yield list(
-                concat(
-                    get_logs_multipart(
-                        self.w3,
-                        start,
-                        stop,
-                        self.address,
-                        self.topics,
-                        max_blocks=MAX_BLOCK_REQUEST)))
+            else:
+                yield list(
+                    concat(
+                        get_logs_multipart(
+                            self.w3,
+                            start,
+                            stop,
+                            self.address,
+                            self.topics,
+                            max_blocks=MAX_BLOCK_REQUEST)))
 
     def get_logs(self) -> List[LogReceipt]:
         return list(


Test patch:
diff --git a/tests/core/middleware/test_filter_middleware.py b/tests/core/middleware/test_filter_middleware.py
--- a/tests/core/middleware/test_filter_middleware.py
+++ b/tests/core/middleware/test_filter_middleware.py
@@ -101,6 +101,18 @@ def test_block_ranges(start, stop, expected):
         (1, 19),
         (20, 55),
     ]),
+    (0, None, [10], [
+        (0, 10),
+    ]),
+    (0, 10, [12], [
+        (None, None),
+    ]),
+    (12, 10, [12], [
+        (None, None),
+    ]),
+    (12, 10, [None], [
+        (None, None),
+    ]),
 ])
 def test_iter_latest_block_ranges(
         w3,