headers.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. from typing import (
  2. cast,
  3. overload,
  4. )
  5. import rlp
  6. from rlp.sedes import (
  7. big_endian_int,
  8. Binary,
  9. binary,
  10. )
  11. from eth_typing import (
  12. Address,
  13. BlockNumber,
  14. Hash32,
  15. )
  16. from eth_hash.auto import keccak
  17. from eth_utils import (
  18. encode_hex,
  19. )
  20. from eth._utils.headers import (
  21. new_timestamp_from_parent,
  22. )
  23. from eth.abc import (
  24. BlockHeaderAPI,
  25. MiningHeaderAPI,
  26. )
  27. from eth.constants import (
  28. ZERO_ADDRESS,
  29. ZERO_HASH32,
  30. EMPTY_UNCLE_HASH,
  31. GENESIS_NONCE,
  32. GENESIS_PARENT_HASH,
  33. BLANK_ROOT_HASH,
  34. )
  35. from eth.typing import HeaderParams
  36. from .sedes import (
  37. address,
  38. hash32,
  39. uint256,
  40. trie_root,
  41. )
  42. class MiningHeader(rlp.Serializable, MiningHeaderAPI):
  43. fields = [
  44. ('parent_hash', hash32),
  45. ('uncles_hash', hash32),
  46. ('coinbase', address),
  47. ('state_root', trie_root),
  48. ('transaction_root', trie_root),
  49. ('receipt_root', trie_root),
  50. ('bloom', uint256),
  51. ('difficulty', big_endian_int),
  52. ('block_number', big_endian_int),
  53. ('gas_limit', big_endian_int),
  54. ('gas_used', big_endian_int),
  55. ('timestamp', big_endian_int),
  56. ('extra_data', binary),
  57. ]
  58. class BlockHeader(rlp.Serializable, BlockHeaderAPI):
  59. fields = [
  60. ('parent_hash', hash32),
  61. ('uncles_hash', hash32),
  62. ('coinbase', address),
  63. ('state_root', trie_root),
  64. ('transaction_root', trie_root),
  65. ('receipt_root', trie_root),
  66. ('bloom', uint256),
  67. ('difficulty', big_endian_int),
  68. ('block_number', big_endian_int),
  69. ('gas_limit', big_endian_int),
  70. ('gas_used', big_endian_int),
  71. ('timestamp', big_endian_int),
  72. ('extra_data', binary),
  73. ('mix_hash', binary),
  74. ('nonce', Binary(8, allow_empty=True))
  75. ]
  76. @overload
  77. def __init__(self, **kwargs: HeaderParams) -> None:
  78. ...
  79. @overload # noqa: F811
  80. def __init__(self,
  81. difficulty: int,
  82. block_number: BlockNumber,
  83. gas_limit: int,
  84. timestamp: int = None,
  85. coinbase: Address = ZERO_ADDRESS,
  86. parent_hash: Hash32 = ZERO_HASH32,
  87. uncles_hash: Hash32 = EMPTY_UNCLE_HASH,
  88. state_root: Hash32 = BLANK_ROOT_HASH,
  89. transaction_root: Hash32 = BLANK_ROOT_HASH,
  90. receipt_root: Hash32 = BLANK_ROOT_HASH,
  91. bloom: int = 0,
  92. gas_used: int = 0,
  93. extra_data: bytes = b'',
  94. mix_hash: Hash32 = ZERO_HASH32,
  95. nonce: bytes = GENESIS_NONCE) -> None:
  96. ...
  97. def __init__(self, # type: ignore # noqa: F811
  98. difficulty: int,
  99. block_number: BlockNumber,
  100. gas_limit: int,
  101. timestamp: int = None,
  102. coinbase: Address = ZERO_ADDRESS,
  103. parent_hash: Hash32 = ZERO_HASH32,
  104. uncles_hash: Hash32 = EMPTY_UNCLE_HASH,
  105. state_root: Hash32 = BLANK_ROOT_HASH,
  106. transaction_root: Hash32 = BLANK_ROOT_HASH,
  107. receipt_root: Hash32 = BLANK_ROOT_HASH,
  108. bloom: int = 0,
  109. gas_used: int = 0,
  110. extra_data: bytes = b'',
  111. mix_hash: Hash32 = ZERO_HASH32,
  112. nonce: bytes = GENESIS_NONCE) -> None:
  113. if timestamp is None:
  114. if parent_hash == ZERO_HASH32:
  115. timestamp = new_timestamp_from_parent(None)
  116. else:
  117. # without access to the parent header, we cannot select a new timestamp correctly
  118. raise ValueError("Must set timestamp explicitly if this is not a genesis header")
  119. super().__init__(
  120. parent_hash=parent_hash,
  121. uncles_hash=uncles_hash,
  122. coinbase=coinbase,
  123. state_root=state_root,
  124. transaction_root=transaction_root,
  125. receipt_root=receipt_root,
  126. bloom=bloom,
  127. difficulty=difficulty,
  128. block_number=block_number,
  129. gas_limit=gas_limit,
  130. gas_used=gas_used,
  131. timestamp=timestamp,
  132. extra_data=extra_data,
  133. mix_hash=mix_hash,
  134. nonce=nonce,
  135. )
  136. def __str__(self) -> str:
  137. return f'<BlockHeader #{self.block_number} {encode_hex(self.hash)[2:10]}>'
  138. _hash = None
  139. @property
  140. def hash(self) -> Hash32:
  141. if self._hash is None:
  142. self._hash = keccak(rlp.encode(self))
  143. return cast(Hash32, self._hash)
  144. @property
  145. def mining_hash(self) -> Hash32:
  146. result = keccak(rlp.encode(self[:-2], MiningHeader))
  147. return cast(Hash32, result)
  148. @property
  149. def hex_hash(self) -> str:
  150. return encode_hex(self.hash)
  151. @property
  152. def is_genesis(self) -> bool:
  153. # if removing the block_number == 0 test, consider the validation consequences.
  154. # validate_header stops trying to check the current header against a parent header.
  155. # Can someone trick us into following a high difficulty header with genesis parent hash?
  156. return self.parent_hash == GENESIS_PARENT_HASH and self.block_number == 0
  157. @property
  158. def base_fee_per_gas(self) -> int:
  159. raise AttributeError("Base fee per gas not available until London fork")