ethereum.genesis
Types and functions for beginning a new chain.
Genesis is the term for the beginning of a new chain, and so a genesis block
is a block with no parent (its parent_hash
is all zeros.)
The genesis configuration for a chain is specified with a
GenesisConfiguration
, and genesis blocks are created with
add_genesis_block
.
GenesisConfiguration
Configuration for the first block of an Ethereum chain.
Specifies the allocation of ether set out in the pre-sale, and some of the fields of the genesis block.
36 | @slotted_freezable |
---|
37 | @dataclass |
---|
class GenesisConfiguration:
chain_id
46 | chain_id: U64 |
---|
difficulty
51 | difficulty: Uint |
---|
extra_data
58 | extra_data: Bytes |
---|
gas_limit
65 | gas_limit: Uint |
---|
nonce
72 | nonce: Bytes8 |
---|
timestamp
79 | timestamp: U256 |
---|
initial_accounts
86 | initial_accounts: Dict[str, Dict] |
---|
get_genesis_configuration
Read a genesis configuration from the given JSON file path.
The genesis file should be present in the assets
directory.
def get_genesis_configuration(genesis_file: str) -> GenesisConfiguration:
93 | """ |
---|---|
94 | Read a genesis configuration from the given JSON file path. |
95 |
|
96 | The genesis file should be present in the `assets` directory. |
97 | """ |
98 | genesis_path = f"assets/{genesis_file}" |
99 | genesis_bytes = pkgutil.get_data("ethereum", genesis_path) |
100 | if genesis_bytes is None: |
101 | raise Exception(f"Unable to read genesis from `{genesis_path}`") |
102 | |
103 | genesis_data = json.loads(genesis_bytes.decode()) |
104 | |
105 | return GenesisConfiguration( |
106 | chain_id=U64(genesis_data["config"]["chainId"]), |
107 | difficulty=hex_to_uint(genesis_data["difficulty"]), |
108 | extra_data=hex_to_bytes(genesis_data["extraData"]), |
109 | gas_limit=hex_to_uint(genesis_data["gasLimit"]), |
110 | nonce=hex_to_bytes8(genesis_data["nonce"]), |
111 | timestamp=hex_or_base_10_str_to_u256(genesis_data["timestamp"]), |
112 | initial_accounts=genesis_data["alloc"], |
113 | ) |
hex_or_base_10_str_to_u256
Convert a string in either hexadecimal or base-10 to a U256
.
def hex_or_base_10_str_to_u256(balance: str) -> U256:
117 | """ |
---|---|
118 | Convert a string in either hexadecimal or base-10 to a `U256`. |
119 | """ |
120 | if balance.startswith("0x"): |
121 | return hex_to_u256(balance) |
122 | else: |
123 | return U256(int(balance)) |
AddressT
126 | AddressT = TypeVar("AddressT", bound=FixedBytes) |
---|
AccountT
127 | AccountT = TypeVar("AccountT") |
---|
StateT
128 | StateT = TypeVar("StateT") |
---|
TrieT
129 | TrieT = TypeVar("TrieT") |
---|
BloomT
130 | BloomT = TypeVar("BloomT") |
---|
HeaderT
131 | HeaderT = TypeVar("HeaderT") |
---|
BlockT
132 | BlockT = TypeVar("BlockT") |
---|
GenesisFork
Pointers to the various types and functions required to build a genesis block.
135 | @slotted_freezable |
---|
136 | @dataclass |
---|
class GenesisFork:
Address
145 | Address: Type[FixedBytes] |
---|
Account
146 | Account: Callable[[Uint, U256, bytes], AccountT] |
---|
Trie
147 | Trie: Callable[[bool, object], TrieT] |
---|
Bloom
148 | Bloom: Type[FixedBytes] |
---|
Header
149 | Header: Type[HeaderT] |
---|
Block
150 | Block: Type[BlockT] |
---|
hex_to_address
151 | hex_to_address: Callable[[str], AddressT] |
---|
set_account
152 | set_account: Callable[[StateT, AddressT, AccountT], object] |
---|
set_storage
153 | set_storage: Callable[[StateT, AddressT, Bytes32, U256], object] |
---|
state_root
154 | state_root: Callable[[StateT], Hash32] |
---|
root
155 | root: Callable[[TrieT], object] |
---|
add_genesis_block
Adds the genesis block to an empty blockchain.
The genesis block is an entirely sui generis block (unique) that is not governed by the general rules applying to all other Ethereum blocks. Instead, the only consensus requirement is that it must be identical to the block added by this function.
The mainnet genesis configuration was originally created using the
mk_genesis_block.py
script. It is long since defunct, but is still
available at https://github.com/ethereum/genesis_block_generator.
The initial state is populated with balances based on the Ethereum presale that happened on the Bitcoin blockchain. Additional ether worth 1.98% of the presale was given to the foundation.
The state_root
is set to the root of the initial state. The gas_limit
and difficulty
are set to suitable starting values. In particular the
low gas limit made sending transactions impossible in the early stages of
Frontier.
The nonce
field is 0x42
referencing Douglas Adams' "HitchHiker's Guide
to the Galaxy".
The extra_data
field contains the hash of block 1028201
on
the pre-launch Olympus testnet. The creation of block 1028201
on Olympus
marked the "starting gun" for Ethereum block creation. Including its hash
in the genesis block ensured a fair launch of the Ethereum mining process.
The remaining fields are set to appropriate default values.
On testnets the genesis configuration usually allocates 1 wei to addresses
0x00
to 0xFF
to avoid edge cases around precompiles being created or
cleared (by EIP-161).
def add_genesis_block(hardfork: GenesisFork[AddressT, AccountT, StateT, TrieT, BloomT, HeaderT, BlockT], chain: Any, genesis: GenesisConfiguration) -> None:
165 | """ |
---|---|
166 | Adds the genesis block to an empty blockchain. |
167 |
|
168 | The genesis block is an entirely sui generis block (unique) that is not |
169 | governed by the general rules applying to all other Ethereum blocks. |
170 | Instead, the only consensus requirement is that it must be identical to |
171 | the block added by this function. |
172 |
|
173 | The mainnet genesis configuration was originally created using the |
174 | `mk_genesis_block.py` script. It is long since defunct, but is still |
175 | available at <https://github.com/ethereum/genesis_block_generator>. |
176 |
|
177 | The initial state is populated with balances based on the Ethereum presale |
178 | that happened on the Bitcoin blockchain. Additional ether worth 1.98% of |
179 | the presale was given to the foundation. |
180 |
|
181 | The `state_root` is set to the root of the initial state. The `gas_limit` |
182 | and `difficulty` are set to suitable starting values. In particular the |
183 | low gas limit made sending transactions impossible in the early stages of |
184 | Frontier. |
185 |
|
186 | The `nonce` field is `0x42` referencing Douglas Adams' "HitchHiker's Guide |
187 | to the Galaxy". |
188 |
|
189 | The `extra_data` field contains the hash of block `1028201` on |
190 | the pre-launch Olympus testnet. The creation of block `1028201` on Olympus |
191 | marked the "starting gun" for Ethereum block creation. Including its hash |
192 | in the genesis block ensured a fair launch of the Ethereum mining process. |
193 |
|
194 | The remaining fields are set to appropriate default values. |
195 |
|
196 | On testnets the genesis configuration usually allocates 1 wei to addresses |
197 | `0x00` to `0xFF` to avoid edge cases around precompiles being created or |
198 | cleared (by [EIP-161]). |
199 |
|
200 | [EIP-161]: https://eips.ethereum.org/EIPS/eip-161 |
201 | """ |
202 | Address: Type[FixedBytes] = hardfork.Address |
203 | assert issubclass(Address, FixedBytes) |
204 | |
205 | for hex_address, account in genesis.initial_accounts.items(): |
206 | address = hardfork.hex_to_address(hex_address) |
207 | hardfork.set_account( |
208 | chain.state, |
209 | address, |
210 | hardfork.Account( |
211 | Uint(int(account.get("nonce", "0"))), |
212 | hex_or_base_10_str_to_u256(account.get("balance", 0)), |
213 | hex_to_bytes(account.get("code", "0x")), |
214 | ), |
215 | ) |
216 | for key, value in account.get("storage", {}).items(): |
217 | hardfork.set_storage( |
218 | chain.state, address, hex_to_bytes32(key), hex_to_u256(value) |
219 | ) |
220 | |
221 | fields = { |
222 | "parent_hash": Hash32(b"\0" * 32), |
223 | "ommers_hash": rlp.rlp_hash(()), |
224 | "coinbase": Address(b"\0" * Address.LENGTH), |
225 | "state_root": hardfork.state_root(chain.state), |
226 | "transactions_root": hardfork.root(hardfork.Trie(False, None)), |
227 | "receipt_root": hardfork.root(hardfork.Trie(False, None)), |
228 | "bloom": hardfork.Bloom(b"\0" * 256), |
229 | "difficulty": genesis.difficulty, |
230 | "number": Uint(0), |
231 | "gas_limit": genesis.gas_limit, |
232 | "gas_used": Uint(0), |
233 | "timestamp": genesis.timestamp, |
234 | "extra_data": genesis.extra_data, |
235 | "nonce": genesis.nonce, |
236 | } |
237 | |
238 | if has_field(hardfork.Header, "mix_digest"): |
239 | fields["mix_digest"] = Hash32(b"\0" * 32) |
240 | else: |
241 | fields["prev_randao"] = Hash32(b"\0" * 32) |
242 | |
243 | if has_field(hardfork.Header, "base_fee_per_gas"): |
244 | fields["base_fee_per_gas"] = Uint(10**9) |
245 | |
246 | if has_field(hardfork.Header, "withdrawals_root"): |
247 | fields["withdrawals_root"] = hardfork.root(hardfork.Trie(False, None)) |
248 | |
249 | if has_field(hardfork.Header, "blob_gas_used"): |
250 | fields["blob_gas_used"] = U64(0) |
251 | |
252 | if has_field(hardfork.Header, "excess_blob_gas"): |
253 | fields["excess_blob_gas"] = U64(0) |
254 | |
255 | if has_field(hardfork.Header, "parent_beacon_block_root"): |
256 | fields["parent_beacon_block_root"] = Hash32(b"\0" * 32) |
257 | |
258 | genesis_header = hardfork.Header(**fields) |
259 | |
260 | block_fields = { |
261 | "header": genesis_header, |
262 | "transactions": (), |
263 | "ommers": (), |
264 | } |
265 | |
266 | if has_field(hardfork.Block, "withdrawals"): |
267 | block_fields["withdrawals"] = () |
268 | |
269 | genesis_block = hardfork.Block(**block_fields) |
270 | |
271 | chain.blocks.append(genesis_block) |
272 | chain.chain_id = genesis.chain_id |