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.

37
@slotted_freezable
38
@dataclass
class GenesisConfiguration:

chain_id

Discriminant between diverged blockchains; 1 for Ethereum's main network.

47
    chain_id: U64

difficulty

See difficulty (and subsequent forks.)

52
    difficulty: Uint

extra_data

See extra_data (and subsequent forks.)

59
    extra_data: Bytes

gas_limit

See gas_limit (and subsequent forks.)

66
    gas_limit: Uint

nonce

See nonce (and subsequent forks.)

73
    nonce: Bytes8

timestamp

See timestamp (and subsequent forks.)

80
    timestamp: U256

initial_accounts

State of the blockchain at genesis.

87
    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:
94
    """
95
    Read a genesis configuration from the given JSON file path.
96
97
    The genesis file should be present in the `assets` directory.
98
    """
99
    genesis_path = f"assets/{genesis_file}"
100
    genesis_bytes = pkgutil.get_data("ethereum", genesis_path)
101
    if genesis_bytes is None:
102
        raise Exception(f"Unable to read genesis from `{genesis_path}`")
103
104
    genesis_data = json.loads(genesis_bytes.decode())
105
106
    return GenesisConfiguration(
107
        chain_id=U64(genesis_data["config"]["chainId"]),
108
        difficulty=hex_to_uint(genesis_data["difficulty"]),
109
        extra_data=hex_to_bytes(genesis_data["extraData"]),
110
        gas_limit=hex_to_uint(genesis_data["gasLimit"]),
111
        nonce=hex_to_bytes8(genesis_data["nonce"]),
112
        timestamp=hex_or_base_10_str_to_u256(genesis_data["timestamp"]),
113
        initial_accounts=genesis_data["alloc"],
114
    )

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:
118
    """
119
    Convert a string in either hexadecimal or base-10 to a `U256`.
120
    """
121
    if balance.startswith("0x"):
122
        return hex_to_u256(balance)
123
    else:
124
        return U256(int(balance))

AddressT

127
AddressT = TypeVar("AddressT", bound=FixedBytes)

AccountT

128
AccountT = TypeVar("AccountT")

StateT

129
StateT = TypeVar("StateT")

TrieT

130
TrieT = TypeVar("TrieT")

BloomT

131
BloomT = TypeVar("BloomT")

HeaderT

132
HeaderT = TypeVar("HeaderT")

BlockT

133
BlockT = TypeVar("BlockT")

GenesisFork

Pointers to the various types and functions required to build a genesis block.

136
@slotted_freezable
137
@dataclass
class GenesisFork:

Address

146
    Address: Type[FixedBytes]

Account

147
    Account: Callable[[Uint, U256, Hash32], AccountT]

Trie

148
    Trie: Callable[[bool, object], TrieT]

Bloom

149
    Bloom: Type[FixedBytes]

Header

150
    Header: Type[HeaderT]

Block

151
    Block: Type[BlockT]

hex_to_address

152
    hex_to_address: Callable[[str], AddressT]

set_account

153
    set_account: Callable[[StateT, AddressT, AccountT], object]

set_storage

154
    set_storage: Callable[[StateT, AddressT, Bytes32, U256], object]

state_root

155
    state_root: Callable[[StateT], Hash32]

root

156
    root: Callable[[TrieT], object]

store_code

157
    store_code: Callable[[StateT, Bytes], Hash32]

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:
167
    """
168
    Adds the genesis block to an empty blockchain.
169
170
    The genesis block is an entirely sui generis block (unique) that is not
171
    governed by the general rules applying to all other Ethereum blocks.
172
    Instead, the only consensus requirement is that it must be identical to
173
    the block added by this function.
174
175
    The mainnet genesis configuration was originally created using the
176
    `mk_genesis_block.py` script. It is long since defunct, but is still
177
    available at <https://github.com/ethereum/genesis_block_generator>.
178
179
    The initial state is populated with balances based on the Ethereum presale
180
    that happened on the Bitcoin blockchain. Additional ether worth 1.98% of
181
    the presale was given to the foundation.
182
183
    The `state_root` is set to the root of the initial state. The `gas_limit`
184
    and `difficulty` are set to suitable starting values. In particular the
185
    low gas limit made sending transactions impossible in the early stages of
186
    Frontier.
187
188
    The `nonce` field is `0x42` referencing Douglas Adams' "HitchHiker's Guide
189
    to the Galaxy".
190
191
    The `extra_data` field contains the hash of block `1028201` on
192
    the pre-launch Olympus testnet. The creation of block `1028201` on Olympus
193
    marked the "starting gun" for Ethereum block creation. Including its hash
194
    in the genesis block ensured a fair launch of the Ethereum mining process.
195
196
    The remaining fields are set to appropriate default values.
197
198
    On testnets the genesis configuration usually allocates 1 wei to addresses
199
    `0x00` to `0xFF` to avoid edge cases around precompiles being created or
200
    cleared (by [EIP-161]).
201
202
    [EIP-161]: https://eips.ethereum.org/EIPS/eip-161
203
    """
204
    Address: Type[FixedBytes] = hardfork.Address  # noqa N806
205
    assert issubclass(Address, FixedBytes)
206
207
    for hex_address, account in genesis.initial_accounts.items():
208
        address = hardfork.hex_to_address(hex_address)
209
        code = hex_to_bytes(account.get("code", "0x"))
210
        code_hash = hardfork.store_code(chain.state, code)
211
        hardfork.set_account(
212
            chain.state,
213
            address,
214
            hardfork.Account(
215
                Uint(int(account.get("nonce", "0"))),
216
                hex_or_base_10_str_to_u256(account.get("balance", 0)),
217
                code_hash,
218
            ),
219
        )
220
        for key, value in account.get("storage", {}).items():
221
            hardfork.set_storage(
222
                chain.state, address, hex_to_bytes32(key), hex_to_u256(value)
223
            )
224
225
    fields = {
226
        "parent_hash": Hash32(b"\0" * 32),
227
        "ommers_hash": keccak256(rlp.encode(())),
228
        "coinbase": Address(b"\0" * Address.LENGTH),
229
        "state_root": hardfork.state_root(chain.state),
230
        "transactions_root": hardfork.root(hardfork.Trie(False, None)),
231
        "receipt_root": hardfork.root(hardfork.Trie(False, None)),
232
        "bloom": hardfork.Bloom(b"\0" * 256),
233
        "difficulty": genesis.difficulty,
234
        "number": Uint(0),
235
        "gas_limit": genesis.gas_limit,
236
        "gas_used": Uint(0),
237
        "timestamp": genesis.timestamp,
238
        "extra_data": genesis.extra_data,
239
        "nonce": genesis.nonce,
240
    }
241
242
    if has_field(hardfork.Header, "mix_digest"):
243
        fields["mix_digest"] = Hash32(b"\0" * 32)
244
    else:
245
        fields["prev_randao"] = Hash32(b"\0" * 32)
246
247
    if has_field(hardfork.Header, "base_fee_per_gas"):
248
        fields["base_fee_per_gas"] = Uint(10**9)
249
250
    if has_field(hardfork.Header, "withdrawals_root"):
251
        fields["withdrawals_root"] = hardfork.root(hardfork.Trie(False, None))
252
253
    if has_field(hardfork.Header, "blob_gas_used"):
254
        fields["blob_gas_used"] = U64(0)
255
256
    if has_field(hardfork.Header, "excess_blob_gas"):
257
        fields["excess_blob_gas"] = U64(0)
258
259
    if has_field(hardfork.Header, "parent_beacon_block_root"):
260
        fields["parent_beacon_block_root"] = Hash32(b"\0" * 32)
261
262
    if has_field(hardfork.Header, "requests_hash"):
263
        fields["requests_hash"] = Hash32(b"\0" * 32)
264
265
    if has_field(hardfork.Header, "block_access_list_hash"):
266
        fields["block_access_list_hash"] = keccak256(rlp.encode([]))
267
268
    genesis_header = hardfork.Header(**fields)
269
270
    block_fields = {
271
        "header": genesis_header,
272
        "transactions": (),
273
        "ommers": (),
274
    }
275
276
    if has_field(hardfork.Block, "withdrawals"):
277
        block_fields["withdrawals"] = ()
278
279
    if has_field(hardfork.Block, "requests"):
280
        block_fields["requests"] = ()
281
282
    genesis_block = hardfork.Block(**block_fields)
283
284
    chain.blocks.append(genesis_block)
285
    chain.chain_id = genesis.chain_id