Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit c5d0bd1

Browse files
committed
Simplify previous hash lookups w/ cached iterable
1 parent 210ea80 commit c5d0bd1

File tree

4 files changed

+21
-29
lines changed

4 files changed

+21
-29
lines changed

eth/_utils/generator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import itertools
2-
from typing import (
2+
from typing import ( # noqa: F401
33
Generic,
44
Iterable,
55
Iterator,
@@ -12,14 +12,14 @@
1212

1313

1414
class CachedIterable(Generic[TItem], Iterable[TItem]):
15-
def __init__(self, iterator: Iterable[TItem]) -> None:
16-
self._cached_results: List[TItem] = []
17-
self._iterator = iterator
15+
def __init__(self, iterable: Iterable[TItem]) -> None:
16+
self._cached_results = [] # type: List[TItem]
17+
self._iterator = iter(iterable)
1818

1919
def __iter__(self) -> Iterator[TItem]:
2020
return itertools.chain(self._cached_results, self._cache_and_yield())
2121

22-
def _cache_and_yield(self) -> Iterable[TItem]:
22+
def _cache_and_yield(self) -> Iterator[TItem]:
2323
for item in self._iterator:
2424
self._cached_results.append(item)
2525
yield item

eth/vm/execution_context.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
Hash32,
88
)
99

10+
from eth._utils.generator import CachedIterable
11+
1012

1113
class ExecutionContext:
1214
_coinbase = None
@@ -30,7 +32,7 @@ def __init__(
3032
self._block_number = block_number
3133
self._difficulty = difficulty
3234
self._gas_limit = gas_limit
33-
self._prev_hashes = prev_hashes
35+
self._prev_hashes = CachedIterable(prev_hashes)
3436

3537
@property
3638
def coinbase(self) -> Address:

eth/vm/state.py

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
abstractmethod
44
)
55
import contextlib
6-
import itertools
76
import logging
87
from typing import ( # noqa: F401
98
cast,
@@ -20,6 +19,7 @@
2019
Address,
2120
Hash32,
2221
)
22+
from eth_utils.toolz import nth
2323

2424
from eth.constants import (
2525
BLANK_ROOT_HASH,
@@ -85,14 +85,11 @@ class for vm execution.
8585
transaction_context_class = None # type: Type[BaseTransactionContext]
8686
account_db_class = None # type: Type[BaseAccountDB]
8787
transaction_executor = None # type: Type[BaseTransactionExecutor]
88-
prev_hashes_generator_backup = None
8988

9089
def __init__(self, db: BaseDB, execution_context: ExecutionContext, state_root: bytes) -> None:
9190
self._db = db
9291
self.execution_context = execution_context
9392
self.account_db = self.get_account_db_class()(self._db, state_root)
94-
if execution_context:
95-
self.prev_hashes_generator_backup = execution_context.prev_hashes
9693

9794
#
9895
# Logging
@@ -201,12 +198,6 @@ def get_ancestor_hash(self, block_number: int) -> Hash32:
201198
Return the empty bytestring ``b''`` if the block number is outside of the
202199
range of available block numbers (typically the last 255 blocks).
203200
"""
204-
# Create a copy of the generator so that traversing it doesn't change the
205-
# original generator
206-
self.prev_hashes_generator_backup, temp_prev_hashes_generator = itertools.tee(
207-
self.prev_hashes_generator_backup
208-
)
209-
210201
ancestor_depth = self.block_number - block_number - 1
211202
is_ancestor_depth_out_of_range = (
212203
ancestor_depth >= MAX_PREV_HEADER_DEPTH or
@@ -216,19 +207,11 @@ def get_ancestor_hash(self, block_number: int) -> Hash32:
216207
if is_ancestor_depth_out_of_range:
217208
return Hash32(b'')
218209

219-
current_ancestor_depth = 0
220-
current_ancestor_hash = None
221-
while True:
222-
try:
223-
current_ancestor_hash = next(temp_prev_hashes_generator)
224-
except StopIteration:
225-
# Ancestor with specified depth not present
226-
return Hash32(b'')
227-
if current_ancestor_depth == ancestor_depth:
228-
return current_ancestor_hash
229-
current_ancestor_depth += 1
230-
231-
raise Exception("Invariant: unreachable code path")
210+
try:
211+
return nth(ancestor_depth, self.execution_context.prev_hashes)
212+
except StopIteration:
213+
# Ancestor with specified depth not present
214+
return Hash32(b'')
232215

233216
#
234217
# Computation

tests/core/generator-utils/test_cached_iteratable.py renamed to tests/core/generator-utils/test_cached_iterable.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,10 @@ def crash_after_first_val():
2323
repeated_use = CachedIterable(crash_after_first_val())
2424
assert first(repeated_use) == 1
2525
assert first(repeated_use) == 1
26+
27+
28+
def test_cached_generator_iterable():
29+
input_vals = [2]
30+
repeated_use = CachedIterable(input_vals)
31+
assert list(repeated_use) == input_vals
32+
assert list(repeated_use) == input_vals

0 commit comments

Comments
 (0)