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, Bytes], 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]

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