Skip to content

Commit 94e1237

Browse files
cburgdorfPeppece
authored andcommitted
Tighten type support
1 parent 0432a8c commit 94e1237

File tree

21 files changed

+181
-49
lines changed

21 files changed

+181
-49
lines changed

eth/_utils/headers.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from eth_typing import (
55
Address
66
)
7+
8+
from eth.abc import BlockHeaderAPI
79
from eth.constants import (
810
GENESIS_GAS_LIMIT,
911
GAS_LIMIT_EMA_DENOMINATOR,
@@ -17,7 +19,7 @@
1719
)
1820

1921

20-
def compute_gas_limit_bounds(parent: BlockHeader) -> Tuple[int, int]:
22+
def compute_gas_limit_bounds(parent: BlockHeaderAPI) -> Tuple[int, int]:
2123
"""
2224
Compute the boundaries for the block gas limit based on the parent block.
2325
"""
@@ -27,7 +29,7 @@ def compute_gas_limit_bounds(parent: BlockHeader) -> Tuple[int, int]:
2729
return lower_bound, upper_bound
2830

2931

30-
def compute_gas_limit(parent_header: BlockHeader, gas_limit_floor: int) -> int:
32+
def compute_gas_limit(parent_header: BlockHeaderAPI, gas_limit_floor: int) -> int:
3133
"""
3234
A simple strategy for adjusting the gas limit.
3335
@@ -78,8 +80,8 @@ def compute_gas_limit(parent_header: BlockHeader, gas_limit_floor: int) -> int:
7880

7981

8082
def generate_header_from_parent_header(
81-
compute_difficulty_fn: Callable[[BlockHeader, int], int],
82-
parent_header: BlockHeader,
83+
compute_difficulty_fn: Callable[[BlockHeaderAPI, int], int],
84+
parent_header: BlockHeaderAPI,
8385
coinbase: Address,
8486
timestamp: Optional[int] = None,
8587
extra_data: bytes = b'') -> BlockHeader:

eth/_utils/transactions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
ValidationError,
1414
)
1515

16+
from eth.abc import UnsignedTransactionAPI
1617
from eth.constants import (
1718
CREATE_CONTRACT_ADDRESS,
1819
)
@@ -53,7 +54,7 @@ def extract_signature_v(v: int) -> int:
5354
return V_OFFSET
5455

5556

56-
def create_transaction_signature(unsigned_txn: BaseTransaction,
57+
def create_transaction_signature(unsigned_txn: UnsignedTransactionAPI,
5758
private_key: datatypes.PrivateKey,
5859
chain_id: int=None) -> VRS:
5960

eth/abc.py

Lines changed: 125 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@
1919
Type,
2020
TypeVar,
2121
Union,
22+
Hashable,
2223
)
2324

24-
import rlp
25-
2625
from eth_bloom import BloomFilter
2726

2827
from eth_typing import (
@@ -53,7 +52,7 @@
5352
T = TypeVar('T')
5453

5554

56-
class MiningHeaderAPI(rlp.Serializable, ABC):
55+
class MiningHeaderAPI(ABC):
5756
"""
5857
A class to define a block header without ``mix_hash`` and ``nonce`` which can act as a
5958
temporary representation during mining before the block header is sealed.
@@ -72,6 +71,53 @@ class MiningHeaderAPI(rlp.Serializable, ABC):
7271
timestamp: int
7372
extra_data: bytes
7473

74+
@property
75+
@abstractmethod
76+
def hash(self) -> Hash32:
77+
"""
78+
Return the hash of the block header.
79+
"""
80+
...
81+
82+
@property
83+
@abstractmethod
84+
def mining_hash(self) -> Hash32:
85+
"""
86+
Return the mining hash of the block header.
87+
"""
88+
89+
@property
90+
def hex_hash(self) -> str:
91+
"""
92+
Return the hash as a hex string.
93+
"""
94+
...
95+
96+
@property
97+
@abstractmethod
98+
def is_genesis(self) -> bool:
99+
"""
100+
Return ``True`` if this header represents the genesis block of the chain,
101+
otherwise ``False``.
102+
"""
103+
...
104+
105+
# We can remove this API and inherit from rlp.Serializable when it becomes typesafe
106+
@abstractmethod
107+
def build_changeset(self, *args: Any, **kwargs: Any) -> Any:
108+
"""
109+
Open a changeset to modify the header.
110+
"""
111+
...
112+
113+
# We can remove this API and inherit from rlp.Serializable when it becomes typesafe
114+
@abstractmethod
115+
def as_dict(self) -> Dict[Hashable, Any]:
116+
"""
117+
Return a dictionary representation of the header.
118+
"""
119+
...
120+
75121

76122
class BlockHeaderAPI(MiningHeaderAPI):
77123
"""
@@ -81,8 +127,16 @@ class BlockHeaderAPI(MiningHeaderAPI):
81127
mix_hash: Hash32
82128
nonce: bytes
83129

130+
# We can remove this API and inherit from rlp.Serializable when it becomes typesafe
131+
@abstractmethod
132+
def copy(self, *args: Any, **kwargs: Any) -> 'BlockHeaderAPI':
133+
"""
134+
Return a copy of the header, optionally overwriting any of its properties.
135+
"""
136+
...
137+
84138

85-
class LogAPI(rlp.Serializable, ABC):
139+
class LogAPI(ABC):
86140
"""
87141
A class to define a written log.
88142
"""
@@ -96,7 +150,7 @@ def bloomables(self) -> Tuple[bytes, ...]:
96150
...
97151

98152

99-
class ReceiptAPI(rlp.Serializable, ABC):
153+
class ReceiptAPI(ABC):
100154
"""
101155
A class to define a receipt to capture the outcome of a transaction.
102156
"""
@@ -110,6 +164,15 @@ class ReceiptAPI(rlp.Serializable, ABC):
110164
def bloom_filter(self) -> BloomFilter:
111165
...
112166

167+
# We can remove this API and inherit from rlp.Serializable when it becomes typesafe
168+
def copy(self, *args: Any, **kwargs: Any) -> 'ReceiptAPI':
169+
"""
170+
Return a copy of the receipt, optionally overwriting any of its properties.
171+
"""
172+
# This method isn't marked abstract because derived classes implement it by deriving from
173+
# rlp.Serializable but mypy won't recognize it as implemented.
174+
...
175+
113176

114177
class BaseTransactionAPI(ABC):
115178
"""
@@ -148,6 +211,7 @@ def gas_used_by(self, computation: 'ComputationAPI') -> int:
148211
"""
149212
...
150213

214+
# We can remove this API and inherit from rlp.Serializable when it becomes typesafe
151215
@abstractmethod
152216
def copy(self: T, **overrides: Any) -> T:
153217
"""
@@ -172,11 +236,15 @@ class TransactionFieldsAPI(ABC):
172236

173237
@property
174238
@abstractmethod
175-
def hash(self) -> bytes:
239+
def hash(self) -> Hash32:
240+
"""
241+
Return the hash of the transaction.
242+
"""
176243
...
177244

178245

179-
class UnsignedTransactionAPI(rlp.Serializable, BaseTransactionAPI):
246+
class UnsignedTransactionAPI(BaseTransactionAPI):
247+
180248
"""
181249
A class representing a transaction before it is signed.
182250
"""
@@ -199,7 +267,11 @@ def as_signed_transaction(self, private_key: PrivateKey) -> 'SignedTransactionAP
199267
...
200268

201269

202-
class SignedTransactionAPI(rlp.Serializable, BaseTransactionAPI, TransactionFieldsAPI):
270+
class SignedTransactionAPI(BaseTransactionAPI, TransactionFieldsAPI):
271+
272+
def __init__(self, *args: Any, **kwargs: Any) -> None:
273+
...
274+
203275
"""
204276
A class representing a transaction that was signed with a private key.
205277
"""
@@ -288,12 +360,29 @@ def create_unsigned_transaction(cls,
288360
"""
289361
...
290362

363+
# We can remove this API and inherit from rlp.Serializable when it becomes typesafe
364+
def as_dict(self) -> Dict[Hashable, Any]:
365+
"""
366+
Return a dictionary representation of the transaction.
367+
"""
368+
...
291369

292-
class BlockAPI(rlp.Serializable, ABC):
370+
371+
class BlockAPI(ABC):
293372
"""
294373
A class to define a block.
295374
"""
375+
header: BlockHeaderAPI
376+
transactions: Tuple[SignedTransactionAPI, ...]
296377
transaction_class: Type[SignedTransactionAPI] = None
378+
uncles: Tuple[BlockHeaderAPI, ...]
379+
380+
@abstractmethod
381+
def __init__(self,
382+
header: BlockHeaderAPI,
383+
transactions: Sequence[SignedTransactionAPI],
384+
uncles: Sequence[BlockHeaderAPI]):
385+
...
297386

298387
@classmethod
299388
@abstractmethod
@@ -311,6 +400,13 @@ def from_header(cls, header: BlockHeaderAPI, chaindb: 'ChainDatabaseAPI') -> 'Bl
311400
"""
312401
...
313402

403+
@abstractmethod
404+
def get_receipts(self, chaindb: 'ChainDatabaseAPI') -> Tuple[ReceiptAPI, ...]:
405+
"""
406+
Fetch the receipts for this block from the given ``chaindb``.
407+
"""
408+
...
409+
314410
@property
315411
@abstractmethod
316412
def hash(self) -> Hash32:
@@ -336,6 +432,15 @@ def is_genesis(self) -> bool:
336432
"""
337433
...
338434

435+
# We can remove this API and inherit from rlp.Serializable when it becomes typesafe
436+
def copy(self, *args: Any, **kwargs: Any) -> 'BlockAPI':
437+
"""
438+
Return a copy of the block, optionally overwriting any of its properties.
439+
"""
440+
# This method isn't marked abstract because derived classes implement it by deriving from
441+
# rlp.Serializable but mypy won't recognize it as implemented.
442+
...
443+
339444

340445
class MetaWitnessAPI(ABC):
341446
@property
@@ -1749,6 +1854,16 @@ def get_accessed_slots(self) -> FrozenSet[int]:
17491854
...
17501855

17511856

1857+
class AccountAPI(ABC):
1858+
"""
1859+
A class representing an Ethereum account.
1860+
"""
1861+
nonce: int
1862+
balance: int
1863+
storage_root: Hash32
1864+
code_hash: Hash32
1865+
1866+
17521867
class AccountDatabaseAPI(ABC):
17531868
"""
17541869
A class representing a database for accounts.
@@ -2807,7 +2922,7 @@ def previous_hashes(self) -> Optional[Iterable[Hash32]]:
28072922

28082923
@staticmethod
28092924
@abstractmethod
2810-
def get_uncle_reward(block_number: BlockNumber, uncle: BlockAPI) -> int:
2925+
def get_uncle_reward(block_number: BlockNumber, uncle: BlockHeaderAPI) -> int:
28112926
"""
28122927
Return the reward which should be given to the miner of the given `uncle`.
28132928

eth/chains/base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def get_ancestors(self, limit: int, header: BlockHeaderAPI) -> Tuple[BlockAPI, .
317317
# We construct a temporary block object
318318
vm_class = self.get_vm_class_for_block_number(header.block_number)
319319
block_class = vm_class.get_block_class()
320-
block = block_class(header=header, uncles=[])
320+
block = block_class(header=header, uncles=[], transactions=[])
321321

322322
ancestor_generator = iterate(compose(
323323
self.get_block_by_hash,
@@ -611,7 +611,7 @@ def validate_uncles(self, block: BlockAPI) -> None:
611611
uncle_parent = self.get_block_header_by_hash(uncle.parent_hash)
612612
except HeaderNotFound:
613613
raise ValidationError(
614-
f"Uncle ancestor not found: {uncle.parent_hash}"
614+
f"Uncle ancestor not found: {uncle.parent_hash!r}"
615615
)
616616

617617
uncle_vm_class = self.get_vm_class_for_block_number(uncle.block_number)
@@ -643,7 +643,7 @@ def apply_transaction(self,
643643

644644
# since we are building the block locally, we have to persist all the incremental state
645645
vm.state.persist()
646-
new_header = header_with_receipt.copy(state_root=vm.state.state_root)
646+
new_header: BlockHeaderAPI = header_with_receipt.copy(state_root=vm.state.state_root)
647647

648648
transactions = base_block.transactions + (transaction, )
649649
receipts = base_block.get_receipts(self.chaindb) + (receipt, )

eth/chains/tester/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
)
2222

2323
from eth.abc import (
24-
BlockAPI,
2524
BlockHeaderAPI,
2625
VirtualMachineAPI,
2726
)
@@ -147,7 +146,7 @@ class MainnetTesterChain(BaseMainnetTesterChain):
147146
configuration of fork rules.
148147
"""
149148

150-
def validate_seal(self, block: BlockAPI) -> None:
149+
def validate_seal(self, header: BlockHeaderAPI) -> None:
151150
"""
152151
We don't validate the proof of work seal on the tester chain.
153152
"""

eth/consensus/clique/_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def get_signature_hash(header: BlockHeaderAPI) -> Hash32:
6868
if len(header.extra_data) < SIGNATURE_LENGTH:
6969
raise ValueError("header.extra_data too short to contain signature")
7070

71-
signature_header = header.copy(
71+
signature_header: BlockHeaderAPI = header.copy(
7272
extra_data=header.extra_data[:len(header.extra_data) - SIGNATURE_LENGTH]
7373
)
7474
return signature_header.hash
@@ -162,7 +162,7 @@ def validate_header_integrity(header: BlockHeaderAPI, epoch_length: int) -> None
162162
raise ValidationError(f"Invalid mix hash: {header.mix_hash!r}")
163163

164164
if header.uncles_hash != EMPTY_UNCLE_HASH:
165-
raise ValidationError(f"Invalid uncle hash: {header.uncle_hash}")
165+
raise ValidationError(f"Invalid uncle hash: {header.uncles_hash!r}")
166166

167167
if header.difficulty not in ALLOWED_CLIQUE_DIFFICULTIES:
168168
raise ValidationError(f"Invalid difficulty: {header.difficulty}")

eth/db/chain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def persist_uncles(self, uncles: Tuple[BlockHeaderAPI]) -> Hash32:
280280
return self._persist_uncles(self.db, uncles)
281281

282282
@staticmethod
283-
def _persist_uncles(db: DatabaseAPI, uncles: Tuple[BlockHeaderAPI]) -> Hash32:
283+
def _persist_uncles(db: DatabaseAPI, uncles: Tuple[BlockHeaderAPI, ...]) -> Hash32:
284284
uncles_hash = keccak(rlp.encode(uncles))
285285
db.set(
286286
uncles_hash,

eth/rlp/accounts.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
big_endian_int,
44
)
55

6+
from eth.abc import AccountAPI
67
from eth.constants import (
78
EMPTY_SHA3,
89
BLANK_ROOT_HASH,
@@ -16,7 +17,7 @@
1617
from typing import Any
1718

1819

19-
class Account(rlp.Serializable):
20+
class Account(rlp.Serializable, AccountAPI):
2021
"""
2122
RLP object for accounts.
2223
"""

0 commit comments

Comments
 (0)