ethereum.paris.fork

Ethereum Specification ^^^^^^^^^^^^^^^^^^^^^^

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Entry point for the Ethereum specification.

BASE_FEE_MAX_CHANGE_DENOMINATOR

57
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

58
ELASTICITY_MULTIPLIER = Uint(2)

GAS_LIMIT_ADJUSTMENT_FACTOR

59
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

60
GAS_LIMIT_MINIMUM = Uint(5000)

EMPTY_OMMER_HASH

61
EMPTY_OMMER_HASH = keccak256(rlp.encode([]))

BlockChain

History and current state of the block chain.

64
@dataclass
class BlockChain:

blocks

70
    blocks: List[Block]

state

71
    state: State

chain_id

72
    chain_id: U64

apply_fork

Transforms the state from the previous hard fork (old) into the block chain object for this hard fork and returns it.

When forks need to implement an irregular state transition, this function is used to handle the irregularity. See the :ref:DAO Fork <dao-fork> for an example.

Parameters

old : Previous block chain object.

Returns

new : BlockChain Upgraded block chain object for this hard fork.

def apply_fork(old: BlockChain) -> BlockChain:
76
    """
77
    Transforms the state from the previous hard fork (`old`) into the block
78
    chain object for this hard fork and returns it.
79
80
    When forks need to implement an irregular state transition, this function
81
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
82
    an example.
83
84
    Parameters
85
    ----------
86
    old :
87
        Previous block chain object.
88
89
    Returns
90
    -------
91
    new : `BlockChain`
92
        Upgraded block chain object for this hard fork.
93
    """
94
    return old

get_last_256_block_hashes

Obtain the list of hashes of the previous 256 blocks in order of increasing block number.

This function will return less hashes for the first 256 blocks.

The BLOCKHASH opcode needs to access the latest hashes on the chain, therefore this function retrieves them.

Parameters

chain : History and current state.

Returns

recent_block_hashes : List[Hash32] Hashes of the recent 256 blocks in order of increasing block number.

def get_last_256_block_hashes(chain: BlockChain) -> List[Hash32]:
98
    """
99
    Obtain the list of hashes of the previous 256 blocks in order of
100
    increasing block number.
101
102
    This function will return less hashes for the first 256 blocks.
103
104
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
105
    therefore this function retrieves them.
106
107
    Parameters
108
    ----------
109
    chain :
110
        History and current state.
111
112
    Returns
113
    -------
114
    recent_block_hashes : `List[Hash32]`
115
        Hashes of the recent 256 blocks in order of increasing block number.
116
    """
117
    recent_blocks = chain.blocks[-255:]
118
    # TODO: This function has not been tested rigorously
119
    if len(recent_blocks) == 0:
120
        return []
121
122
    recent_block_hashes = []
123
124
    for block in recent_blocks:
125
        prev_block_hash = block.header.parent_hash
126
        recent_block_hashes.append(prev_block_hash)
127
128
    # We are computing the hash only for the most recent block and not for
129
    # the rest of the blocks as they have successors which have the hash of
130
    # the current block as parent hash.
131
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
132
    recent_block_hashes.append(most_recent_block_hash)
133
134
    return recent_block_hashes

state_transition

Attempts to apply a block to an existing block chain.

All parts of the block's contents need to be verified before being added to the chain. Blocks are verified by ensuring that the contents of the block make logical sense with the contents of the parent block. The information in the block's header must also match the corresponding information in the block.

To implement Ethereum, in theory clients are only required to store the most recent 255 blocks of the chain since as far as execution is concerned, only those blocks are accessed. Practically, however, clients should store more blocks to handle reorgs.

Parameters

chain : History and current state. block : Block to apply to chain.

def state_transition(chain: BlockChain, ​​block: Block) -> None:
138
    """
139
    Attempts to apply a block to an existing block chain.
140
141
    All parts of the block's contents need to be verified before being added
142
    to the chain. Blocks are verified by ensuring that the contents of the
143
    block make logical sense with the contents of the parent block. The
144
    information in the block's header must also match the corresponding
145
    information in the block.
146
147
    To implement Ethereum, in theory clients are only required to store the
148
    most recent 255 blocks of the chain since as far as execution is
149
    concerned, only those blocks are accessed. Practically, however, clients
150
    should store more blocks to handle reorgs.
151
152
    Parameters
153
    ----------
154
    chain :
155
        History and current state.
156
    block :
157
        Block to apply to `chain`.
158
    """
159
    parent_header = chain.blocks[-1].header
160
    validate_header(block.header, parent_header)
161
    if block.ommers != ():
162
        raise InvalidBlock
163
    apply_body_output = apply_body(
164
        chain.state,
165
        get_last_256_block_hashes(chain),
166
        block.header.coinbase,
167
        block.header.number,
168
        block.header.base_fee_per_gas,
169
        block.header.gas_limit,
170
        block.header.timestamp,
171
        block.header.prev_randao,
172
        block.transactions,
173
        chain.chain_id,
174
    )
175
    if apply_body_output.block_gas_used != block.header.gas_used:
176
        raise InvalidBlock(
177
            f"{apply_body_output.block_gas_used} != {block.header.gas_used}"
178
        )
179
    if apply_body_output.transactions_root != block.header.transactions_root:
180
        raise InvalidBlock
181
    if apply_body_output.state_root != block.header.state_root:
182
        raise InvalidBlock
183
    if apply_body_output.receipt_root != block.header.receipt_root:
184
        raise InvalidBlock
185
    if apply_body_output.block_logs_bloom != block.header.bloom:
186
        raise InvalidBlock
187
188
    chain.blocks.append(block)
189
    if len(chain.blocks) > 255:
190
        # Real clients have to store more blocks to deal with reorgs, but the
191
        # protocol only requires the last 255
192
        chain.blocks = chain.blocks[-255:]

calculate_base_fee_per_gas

Calculates the base fee per gas for the block.

Parameters

block_gas_limit : Gas limit of the block for which the base fee is being calculated. parent_gas_limit : Gas limit of the parent block. parent_gas_used : Gas used in the parent block. parent_base_fee_per_gas : Base fee per gas of the parent block.

Returns

base_fee_per_gas : Uint Base fee per gas for the block.

def calculate_base_fee_per_gas(block_gas_limit: Uint, ​​parent_gas_limit: Uint, ​​parent_gas_used: Uint, ​​parent_base_fee_per_gas: Uint) -> Uint:
201
    """
202
    Calculates the base fee per gas for the block.
203
204
    Parameters
205
    ----------
206
    block_gas_limit :
207
        Gas limit of the block for which the base fee is being calculated.
208
    parent_gas_limit :
209
        Gas limit of the parent block.
210
    parent_gas_used :
211
        Gas used in the parent block.
212
    parent_base_fee_per_gas :
213
        Base fee per gas of the parent block.
214
215
    Returns
216
    -------
217
    base_fee_per_gas : `Uint`
218
        Base fee per gas for the block.
219
    """
220
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
221
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
222
        raise InvalidBlock
223
224
    if parent_gas_used == parent_gas_target:
225
        expected_base_fee_per_gas = parent_base_fee_per_gas
226
    elif parent_gas_used > parent_gas_target:
227
        gas_used_delta = parent_gas_used - parent_gas_target
228
229
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
230
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
231
232
        base_fee_per_gas_delta = max(
233
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
234
            Uint(1),
235
        )
236
237
        expected_base_fee_per_gas = (
238
            parent_base_fee_per_gas + base_fee_per_gas_delta
239
        )
240
    else:
241
        gas_used_delta = parent_gas_target - parent_gas_used
242
243
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
244
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
245
246
        base_fee_per_gas_delta = (
247
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
248
        )
249
250
        expected_base_fee_per_gas = (
251
            parent_base_fee_per_gas - base_fee_per_gas_delta
252
        )
253
254
    return Uint(expected_base_fee_per_gas)

validate_header

Verifies a block header.

In order to consider a block's header valid, the logic for the quantities in the header should match the logic for the block itself. For example the header timestamp should be greater than the block's parent timestamp because the block was created after the parent block. Additionally, the block's number should be directly following the parent block's number since it is the next block in the sequence.

Parameters

header : Header to check for correctness. parent_header : Parent Header of the header to check for correctness

def validate_header(header: Header, ​​parent_header: Header) -> None:
258
    """
259
    Verifies a block header.
260
261
    In order to consider a block's header valid, the logic for the
262
    quantities in the header should match the logic for the block itself.
263
    For example the header timestamp should be greater than the block's parent
264
    timestamp because the block was created *after* the parent block.
265
    Additionally, the block's number should be directly following the parent
266
    block's number since it is the next block in the sequence.
267
268
    Parameters
269
    ----------
270
    header :
271
        Header to check for correctness.
272
    parent_header :
273
        Parent Header of the header to check for correctness
274
    """
275
    if header.gas_used > header.gas_limit:
276
        raise InvalidBlock
277
278
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
279
        header.gas_limit,
280
        parent_header.gas_limit,
281
        parent_header.gas_used,
282
        parent_header.base_fee_per_gas,
283
    )
284
    if expected_base_fee_per_gas != header.base_fee_per_gas:
285
        raise InvalidBlock
286
    if header.timestamp <= parent_header.timestamp:
287
        raise InvalidBlock
288
    if header.number != parent_header.number + Uint(1):
289
        raise InvalidBlock
290
    if len(header.extra_data) > 32:
291
        raise InvalidBlock
292
    if header.difficulty != 0:
293
        raise InvalidBlock
294
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
295
        raise InvalidBlock
296
    if header.ommers_hash != EMPTY_OMMER_HASH:
297
        raise InvalidBlock
298
299
    block_parent_hash = keccak256(rlp.encode(parent_header))
300
    if header.parent_hash != block_parent_hash:
301
        raise InvalidBlock

check_transaction

Check if the transaction is includable in the block.

Parameters

tx : The transaction. base_fee_per_gas : The block base fee. gas_available : The gas remaining in the block. chain_id : The ID of the current chain.

Returns

sender_address : The sender of the transaction. effective_gas_price : The price to charge for gas when the transaction is executed.

Raises

InvalidBlock : If the transaction is not includable.

def check_transaction(tx: Transaction, ​​base_fee_per_gas: Uint, ​​gas_available: Uint, ​​chain_id: U64) -> Tuple[Address, Uint]:
310
    """
311
    Check if the transaction is includable in the block.
312
313
    Parameters
314
    ----------
315
    tx :
316
        The transaction.
317
    base_fee_per_gas :
318
        The block base fee.
319
    gas_available :
320
        The gas remaining in the block.
321
    chain_id :
322
        The ID of the current chain.
323
324
    Returns
325
    -------
326
    sender_address :
327
        The sender of the transaction.
328
    effective_gas_price :
329
        The price to charge for gas when the transaction is executed.
330
331
    Raises
332
    ------
333
    InvalidBlock :
334
        If the transaction is not includable.
335
    """
336
    if tx.gas > gas_available:
337
        raise InvalidBlock
338
    sender_address = recover_sender(chain_id, tx)
339
340
    if isinstance(tx, FeeMarketTransaction):
341
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
342
            raise InvalidBlock
343
        if tx.max_fee_per_gas < base_fee_per_gas:
344
            raise InvalidBlock
345
346
        priority_fee_per_gas = min(
347
            tx.max_priority_fee_per_gas,
348
            tx.max_fee_per_gas - base_fee_per_gas,
349
        )
350
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
351
    else:
352
        if tx.gas_price < base_fee_per_gas:
353
            raise InvalidBlock
354
        effective_gas_price = tx.gas_price
355
356
    return sender_address, effective_gas_price

make_receipt

Make the receipt for a transaction that was executed.

Parameters

tx : The executed transaction. error : The error from the execution if any. cumulative_gas_used : The total gas used so far in the block after the transaction was executed. logs : The logs produced by the transaction.

Returns

receipt : The receipt for the transaction.

def make_receipt(tx: Transaction, ​​error: Optional[Exception], ​​cumulative_gas_used: Uint, ​​logs: Tuple[Log, ...]) -> Union[Bytes, Receipt]:
365
    """
366
    Make the receipt for a transaction that was executed.
367
368
    Parameters
369
    ----------
370
    tx :
371
        The executed transaction.
372
    error :
373
        The error from the execution if any.
374
    cumulative_gas_used :
375
        The total gas used so far in the block after the transaction was
376
        executed.
377
    logs :
378
        The logs produced by the transaction.
379
380
    Returns
381
    -------
382
    receipt :
383
        The receipt for the transaction.
384
    """
385
    receipt = Receipt(
386
        succeeded=error is None,
387
        cumulative_gas_used=cumulative_gas_used,
388
        bloom=logs_bloom(logs),
389
        logs=logs,
390
    )
391
392
    if isinstance(tx, AccessListTransaction):
393
        return b"\x01" + rlp.encode(receipt)
394
    elif isinstance(tx, FeeMarketTransaction):
395
        return b"\x02" + rlp.encode(receipt)
396
    else:
397
        return receipt

ApplyBodyOutput

Output from applying the block body to the present state.

Contains the following:

block_gas_used : ethereum.base_types.Uint Gas used for executing all transactions. transactions_root : ethereum.fork_types.Root Trie root of all the transactions in the block. receipt_root : ethereum.fork_types.Root Trie root of all the receipts in the block. block_logs_bloom : Bloom Logs bloom of all the logs included in all the transactions of the block. state_root : ethereum.fork_types.Root State root after all transactions have been executed.

400
@dataclass
class ApplyBodyOutput:

block_gas_used

420
    block_gas_used: Uint

transactions_root

421
    transactions_root: Root

receipt_root

422
    receipt_root: Root

block_logs_bloom

423
    block_logs_bloom: Bloom

state_root

424
    state_root: Root

apply_body

Executes a block.

Many of the contents of a block are stored in data structures called tries. There is a transactions trie which is similar to a ledger of the transactions stored in the current block. There is also a receipts trie which stores the results of executing a transaction, like the post state and gas used. This function creates and executes the block that is to be added to the chain.

Parameters

state : Current account state. block_hashes : List of hashes of the previous 256 blocks in the order of increasing block number. coinbase : Address of account which receives block reward and transaction fees. block_number : Position of the block within the chain. base_fee_per_gas : Base fee per gas of within the block. block_gas_limit : Initial amount of gas available for execution in this block. block_time : Time the block was produced, measured in seconds since the epoch. prev_randao : The previous randao from the beacon chain. transactions : Transactions included in the block. ommers : Headers of ancestor blocks which are not direct parents (formerly uncles.) chain_id : ID of the executing chain.

Returns

apply_body_output : ApplyBodyOutput Output of applying the block body to the state.

def apply_body(state: State, ​​block_hashes: List[Hash32], ​​coinbase: Address, ​​block_number: Uint, ​​base_fee_per_gas: Uint, ​​block_gas_limit: Uint, ​​block_time: U256, ​​prev_randao: Bytes32, ​​transactions: Tuple[Union[LegacyTransaction, Bytes], ...], ​​chain_id: U64) -> ApplyBodyOutput:
439
    """
440
    Executes a block.
441
442
    Many of the contents of a block are stored in data structures called
443
    tries. There is a transactions trie which is similar to a ledger of the
444
    transactions stored in the current block. There is also a receipts trie
445
    which stores the results of executing a transaction, like the post state
446
    and gas used. This function creates and executes the block that is to be
447
    added to the chain.
448
449
    Parameters
450
    ----------
451
    state :
452
        Current account state.
453
    block_hashes :
454
        List of hashes of the previous 256 blocks in the order of
455
        increasing block number.
456
    coinbase :
457
        Address of account which receives block reward and transaction fees.
458
    block_number :
459
        Position of the block within the chain.
460
    base_fee_per_gas :
461
        Base fee per gas of within the block.
462
    block_gas_limit :
463
        Initial amount of gas available for execution in this block.
464
    block_time :
465
        Time the block was produced, measured in seconds since the epoch.
466
    prev_randao :
467
        The previous randao from the beacon chain.
468
    transactions :
469
        Transactions included in the block.
470
    ommers :
471
        Headers of ancestor blocks which are not direct parents (formerly
472
        uncles.)
473
    chain_id :
474
        ID of the executing chain.
475
476
    Returns
477
    -------
478
    apply_body_output : `ApplyBodyOutput`
479
        Output of applying the block body to the state.
480
    """
481
    gas_available = block_gas_limit
482
    transactions_trie: Trie[
483
        Bytes, Optional[Union[Bytes, LegacyTransaction]]
484
    ] = Trie(secured=False, default=None)
485
    receipts_trie: Trie[Bytes, Optional[Union[Bytes, Receipt]]] = Trie(
486
        secured=False, default=None
487
    )
488
    block_logs: Tuple[Log, ...] = ()
489
490
    for i, tx in enumerate(map(decode_transaction, transactions)):
491
        trie_set(
492
            transactions_trie, rlp.encode(Uint(i)), encode_transaction(tx)
493
        )
494
495
        sender_address, effective_gas_price = check_transaction(
496
            tx, base_fee_per_gas, gas_available, chain_id
497
        )
498
499
        env = vm.Environment(
500
            caller=sender_address,
501
            origin=sender_address,
502
            block_hashes=block_hashes,
503
            coinbase=coinbase,
504
            number=block_number,
505
            gas_limit=block_gas_limit,
506
            base_fee_per_gas=base_fee_per_gas,
507
            gas_price=effective_gas_price,
508
            time=block_time,
509
            prev_randao=prev_randao,
510
            state=state,
511
            chain_id=chain_id,
512
            traces=[],
513
        )
514
515
        gas_used, logs, error = process_transaction(env, tx)
516
        gas_available -= gas_used
517
518
        receipt = make_receipt(
519
            tx, error, (block_gas_limit - gas_available), logs
520
        )
521
522
        trie_set(
523
            receipts_trie,
524
            rlp.encode(Uint(i)),
525
            receipt,
526
        )
527
528
        block_logs += logs
529
530
    block_gas_used = block_gas_limit - gas_available
531
532
    block_logs_bloom = logs_bloom(block_logs)
533
534
    return ApplyBodyOutput(
535
        block_gas_used,
536
        root(transactions_trie),
537
        root(receipts_trie),
538
        block_logs_bloom,
539
        state_root(state),
540
    )

process_transaction

Execute a transaction against the provided environment.

This function processes the actions needed to execute a transaction. It decrements the sender's account after calculating the gas fee and refunds them the proper amount after execution. Calling contracts, deploying code, and incrementing nonces are all examples of actions that happen within this function or from a call made within this function.

Accounts that are marked for deletion are processed and destroyed after execution.

Parameters

env : Environment for the Ethereum Virtual Machine. tx : Transaction to execute.

Returns

gas_left : ethereum.base_types.U256 Remaining gas after execution. logs : Tuple[ethereum.blocks.Log, ...] Logs generated during execution.

def process_transaction(env: ethereum.paris.vm.Environment, ​​tx: Transaction) -> Tuple[Uint, Tuple[Log, ...], Optional[Exception]]:
546
    """
547
    Execute a transaction against the provided environment.
548
549
    This function processes the actions needed to execute a transaction.
550
    It decrements the sender's account after calculating the gas fee and
551
    refunds them the proper amount after execution. Calling contracts,
552
    deploying code, and incrementing nonces are all examples of actions that
553
    happen within this function or from a call made within this function.
554
555
    Accounts that are marked for deletion are processed and destroyed after
556
    execution.
557
558
    Parameters
559
    ----------
560
    env :
561
        Environment for the Ethereum Virtual Machine.
562
    tx :
563
        Transaction to execute.
564
565
    Returns
566
    -------
567
    gas_left : `ethereum.base_types.U256`
568
        Remaining gas after execution.
569
    logs : `Tuple[ethereum.blocks.Log, ...]`
570
        Logs generated during execution.
571
    """
572
    if not validate_transaction(tx):
573
        raise InvalidBlock
574
575
    sender = env.origin
576
    sender_account = get_account(env.state, sender)
577
578
    if isinstance(tx, FeeMarketTransaction):
579
        max_gas_fee = tx.gas * tx.max_fee_per_gas
580
    else:
581
        max_gas_fee = tx.gas * tx.gas_price
582
    if sender_account.nonce != tx.nonce:
583
        raise InvalidBlock
584
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
585
        raise InvalidBlock
586
    if sender_account.code != bytearray():
587
        raise InvalidSenderError("not EOA")
588
589
    effective_gas_fee = tx.gas * env.gas_price
590
591
    gas = tx.gas - calculate_intrinsic_cost(tx)
592
    increment_nonce(env.state, sender)
593
594
    sender_balance_after_gas_fee = (
595
        Uint(sender_account.balance) - effective_gas_fee
596
    )
597
    set_account_balance(env.state, sender, U256(sender_balance_after_gas_fee))
598
599
    preaccessed_addresses = set()
600
    preaccessed_storage_keys = set()
601
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
602
        for address, keys in tx.access_list:
603
            preaccessed_addresses.add(address)
604
            for key in keys:
605
                preaccessed_storage_keys.add((address, key))
606
607
    message = prepare_message(
608
        sender,
609
        tx.to,
610
        tx.value,
611
        tx.data,
612
        gas,
613
        env,
614
        preaccessed_addresses=frozenset(preaccessed_addresses),
615
        preaccessed_storage_keys=frozenset(preaccessed_storage_keys),
616
    )
617
618
    output = process_message_call(message, env)
619
620
    gas_used = tx.gas - output.gas_left
621
    gas_refund = min(gas_used // Uint(5), Uint(output.refund_counter))
622
    gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price
623
624
    # For non-1559 transactions env.gas_price == tx.gas_price
625
    priority_fee_per_gas = env.gas_price - env.base_fee_per_gas
626
    transaction_fee = (
627
        tx.gas - output.gas_left - gas_refund
628
    ) * priority_fee_per_gas
629
630
    total_gas_used = gas_used - gas_refund
631
632
    # refund gas
633
    sender_balance_after_refund = get_account(
634
        env.state, sender
635
    ).balance + U256(gas_refund_amount)
636
    set_account_balance(env.state, sender, sender_balance_after_refund)
637
638
    # transfer miner fees
639
    coinbase_balance_after_mining_fee = get_account(
640
        env.state, env.coinbase
641
    ).balance + U256(transaction_fee)
642
    if coinbase_balance_after_mining_fee != 0:
643
        set_account_balance(
644
            env.state, env.coinbase, coinbase_balance_after_mining_fee
645
        )
646
    elif account_exists_and_is_empty(env.state, env.coinbase):
647
        destroy_account(env.state, env.coinbase)
648
649
    for address in output.accounts_to_delete:
650
        destroy_account(env.state, address)
651
652
    for address in output.touched_accounts:
653
        if account_exists_and_is_empty(env.state, address):
654
            destroy_account(env.state, address)
655
656
    return total_gas_used, output.logs, output.error

validate_transaction

Verifies a transaction.

The gas in a transaction gets used to pay for the intrinsic cost of operations, therefore if there is insufficient gas then it would not be possible to execute a transaction and it will be declared invalid.

Additionally, the nonce of a transaction must not equal or exceed the limit defined in EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>_. In practice, defining the limit as 2**64-1 has no impact because sending 2**64-1 transactions is improbable. It's not strictly impossible though, 2**64-1 transactions is the entire capacity of the Ethereum blockchain at 2022 gas limits for a little over 22 years.

Parameters

tx : Transaction to validate.

Returns

verified : bool True if the transaction can be executed, or False otherwise.

def validate_transaction(tx: Transaction) -> bool:
660
    """
661
    Verifies a transaction.
662
663
    The gas in a transaction gets used to pay for the intrinsic cost of
664
    operations, therefore if there is insufficient gas then it would not
665
    be possible to execute a transaction and it will be declared invalid.
666
667
    Additionally, the nonce of a transaction must not equal or exceed the
668
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
669
    In practice, defining the limit as ``2**64-1`` has no impact because
670
    sending ``2**64-1`` transactions is improbable. It's not strictly
671
    impossible though, ``2**64-1`` transactions is the entire capacity of the
672
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
673
674
    Parameters
675
    ----------
676
    tx :
677
        Transaction to validate.
678
679
    Returns
680
    -------
681
    verified : `bool`
682
        True if the transaction can be executed, or False otherwise.
683
    """
684
    if calculate_intrinsic_cost(tx) > tx.gas:
685
        return False
686
    if tx.nonce >= U256(U64.MAX_VALUE):
687
        return False
688
    return True

calculate_intrinsic_cost

Calculates the gas that is charged before execution is started.

The intrinsic cost of the transaction is charged before execution has begun. Functions/operations in the EVM cost money to execute so this intrinsic cost is for the operations that need to be paid for as part of the transaction. Data transfer, for example, is part of this intrinsic cost. It costs ether to send data over the wire and that ether is accounted for in the intrinsic cost calculated in this function. This intrinsic cost must be calculated and paid for before execution in order for all operations to be implemented.

Parameters

tx : Transaction to compute the intrinsic cost of.

Returns

verified : ethereum.base_types.Uint The intrinsic cost of the transaction.

def calculate_intrinsic_cost(tx: Transaction) -> Uint:
692
    """
693
    Calculates the gas that is charged before execution is started.
694
695
    The intrinsic cost of the transaction is charged before execution has
696
    begun. Functions/operations in the EVM cost money to execute so this
697
    intrinsic cost is for the operations that need to be paid for as part of
698
    the transaction. Data transfer, for example, is part of this intrinsic
699
    cost. It costs ether to send data over the wire and that ether is
700
    accounted for in the intrinsic cost calculated in this function. This
701
    intrinsic cost must be calculated and paid for before execution in order
702
    for all operations to be implemented.
703
704
    Parameters
705
    ----------
706
    tx :
707
        Transaction to compute the intrinsic cost of.
708
709
    Returns
710
    -------
711
    verified : `ethereum.base_types.Uint`
712
        The intrinsic cost of the transaction.
713
    """
714
    data_cost = 0
715
716
    for byte in tx.data:
717
        if byte == 0:
718
            data_cost += TX_DATA_COST_PER_ZERO
719
        else:
720
            data_cost += TX_DATA_COST_PER_NON_ZERO
721
722
    if tx.to == Bytes0(b""):
723
        create_cost = TX_CREATE_COST
724
    else:
725
        create_cost = 0
726
727
    access_list_cost = 0
728
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
729
        for _address, keys in tx.access_list:
730
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
731
            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
732
733
    return Uint(TX_BASE_COST + data_cost + create_cost + access_list_cost)

recover_sender

Extracts the sender address from a transaction.

The v, r, and s values are the three parts that make up the signature of a transaction. In order to recover the sender of a transaction the two components needed are the signature (v, r, and s) and the signing hash of the transaction. The sender's public key can be obtained with these two values and therefore the sender address can be retrieved.

Parameters

tx : Transaction of interest. chain_id : ID of the executing chain.

Returns

sender : ethereum.fork_types.Address The address of the account that signed the transaction.

def recover_sender(chain_id: U64, ​​tx: Transaction) -> Address:
737
    """
738
    Extracts the sender address from a transaction.
739
740
    The v, r, and s values are the three parts that make up the signature
741
    of a transaction. In order to recover the sender of a transaction the two
742
    components needed are the signature (``v``, ``r``, and ``s``) and the
743
    signing hash of the transaction. The sender's public key can be obtained
744
    with these two values and therefore the sender address can be retrieved.
745
746
    Parameters
747
    ----------
748
    tx :
749
        Transaction of interest.
750
    chain_id :
751
        ID of the executing chain.
752
753
    Returns
754
    -------
755
    sender : `ethereum.fork_types.Address`
756
        The address of the account that signed the transaction.
757
    """
758
    r, s = tx.r, tx.s
759
    if U256(0) >= r or r >= SECP256K1N:
760
        raise InvalidBlock
761
    if U256(0) >= s or s > SECP256K1N // U256(2):
762
        raise InvalidBlock
763
764
    if isinstance(tx, LegacyTransaction):
765
        v = tx.v
766
        if v == 27 or v == 28:
767
            public_key = secp256k1_recover(
768
                r, s, v - U256(27), signing_hash_pre155(tx)
769
            )
770
        else:
771
            chain_id_x2 = U256(chain_id) * U256(2)
772
            if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
773
                raise InvalidBlock
774
            public_key = secp256k1_recover(
775
                r,
776
                s,
777
                v - U256(35) - chain_id_x2,
778
                signing_hash_155(tx, chain_id),
779
            )
780
    elif isinstance(tx, AccessListTransaction):
781
        public_key = secp256k1_recover(
782
            r, s, tx.y_parity, signing_hash_2930(tx)
783
        )
784
    elif isinstance(tx, FeeMarketTransaction):
785
        public_key = secp256k1_recover(
786
            r, s, tx.y_parity, signing_hash_1559(tx)
787
        )
788
789
    return Address(keccak256(public_key)[12:32])

signing_hash_pre155

Compute the hash of a transaction used in a legacy (pre EIP 155) signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_pre155(tx: LegacyTransaction) -> Hash32:
793
    """
794
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
795
796
    Parameters
797
    ----------
798
    tx :
799
        Transaction of interest.
800
801
    Returns
802
    -------
803
    hash : `ethereum.crypto.hash.Hash32`
804
        Hash of the transaction.
805
    """
806
    return keccak256(
807
        rlp.encode(
808
            (
809
                tx.nonce,
810
                tx.gas_price,
811
                tx.gas,
812
                tx.to,
813
                tx.value,
814
                tx.data,
815
            )
816
        )
817
    )

signing_hash_155

Compute the hash of a transaction used in a EIP 155 signature.

Parameters

tx : Transaction of interest. chain_id : The id of the current chain.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_155(tx: LegacyTransaction, ​​chain_id: U64) -> Hash32:
821
    """
822
    Compute the hash of a transaction used in a EIP 155 signature.
823
824
    Parameters
825
    ----------
826
    tx :
827
        Transaction of interest.
828
    chain_id :
829
        The id of the current chain.
830
831
    Returns
832
    -------
833
    hash : `ethereum.crypto.hash.Hash32`
834
        Hash of the transaction.
835
    """
836
    return keccak256(
837
        rlp.encode(
838
            (
839
                tx.nonce,
840
                tx.gas_price,
841
                tx.gas,
842
                tx.to,
843
                tx.value,
844
                tx.data,
845
                chain_id,
846
                Uint(0),
847
                Uint(0),
848
            )
849
        )
850
    )

signing_hash_2930

Compute the hash of a transaction used in a EIP 2930 signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_2930(tx: AccessListTransaction) -> Hash32:
854
    """
855
    Compute the hash of a transaction used in a EIP 2930 signature.
856
857
    Parameters
858
    ----------
859
    tx :
860
        Transaction of interest.
861
862
    Returns
863
    -------
864
    hash : `ethereum.crypto.hash.Hash32`
865
        Hash of the transaction.
866
    """
867
    return keccak256(
868
        b"\x01"
869
        + rlp.encode(
870
            (
871
                tx.chain_id,
872
                tx.nonce,
873
                tx.gas_price,
874
                tx.gas,
875
                tx.to,
876
                tx.value,
877
                tx.data,
878
                tx.access_list,
879
            )
880
        )
881
    )

signing_hash_1559

Compute the hash of a transaction used in a EIP 1559 signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_1559(tx: FeeMarketTransaction) -> Hash32:
885
    """
886
    Compute the hash of a transaction used in a EIP 1559 signature.
887
888
    Parameters
889
    ----------
890
    tx :
891
        Transaction of interest.
892
893
    Returns
894
    -------
895
    hash : `ethereum.crypto.hash.Hash32`
896
        Hash of the transaction.
897
    """
898
    return keccak256(
899
        b"\x02"
900
        + rlp.encode(
901
            (
902
                tx.chain_id,
903
                tx.nonce,
904
                tx.max_priority_fee_per_gas,
905
                tx.max_fee_per_gas,
906
                tx.gas,
907
                tx.to,
908
                tx.value,
909
                tx.data,
910
                tx.access_list,
911
            )
912
        )
913
    )

compute_header_hash

Computes the hash of a block header.

The header hash of a block is the canonical hash that is used to refer to a specific block and completely distinguishes a block from another.

keccak256 is a function that produces a 256 bit hash of any input. It also takes in any number of bytes as an input and produces a single hash for them. A hash is a completely unique output for a single input. So an input corresponds to one unique hash that can be used to identify the input exactly.

Prior to using the keccak256 hash function, the header must be encoded using the Recursive-Length Prefix. See :ref:rlp. RLP encoding the header converts it into a space-efficient format that allows for easy transfer of data between nodes. The purpose of RLP is to encode arbitrarily nested arrays of binary data, and RLP is the primary encoding method used to serialize objects in Ethereum's execution layer. The only purpose of RLP is to encode structure; encoding specific data types (e.g. strings, floats) is left up to higher-order protocols.

Parameters

header : Header of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the header.

def compute_header_hash(header: Header) -> Hash32:
917
    """
918
    Computes the hash of a block header.
919
920
    The header hash of a block is the canonical hash that is used to refer
921
    to a specific block and completely distinguishes a block from another.
922
923
    ``keccak256`` is a function that produces a 256 bit hash of any input.
924
    It also takes in any number of bytes as an input and produces a single
925
    hash for them. A hash is a completely unique output for a single input.
926
    So an input corresponds to one unique hash that can be used to identify
927
    the input exactly.
928
929
    Prior to using the ``keccak256`` hash function, the header must be
930
    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
931
    RLP encoding the header converts it into a space-efficient format that
932
    allows for easy transfer of data between nodes. The purpose of RLP is to
933
    encode arbitrarily nested arrays of binary data, and RLP is the primary
934
    encoding method used to serialize objects in Ethereum's execution layer.
935
    The only purpose of RLP is to encode structure; encoding specific data
936
    types (e.g. strings, floats) is left up to higher-order protocols.
937
938
    Parameters
939
    ----------
940
    header :
941
        Header of interest.
942
943
    Returns
944
    -------
945
    hash : `ethereum.crypto.hash.Hash32`
946
        Hash of the header.
947
    """
948
    return keccak256(rlp.encode(header))

check_gas_limit

Validates the gas limit for a block.

The bounds of the gas limit, max_adjustment_delta, is set as the quotient of the parent block's gas limit and the GAS_LIMIT_ADJUSTMENT_FACTOR. Therefore, if the gas limit that is passed through as a parameter is greater than or equal to the sum of the parent's gas and the adjustment delta then the limit for gas is too high and fails this function's check. Similarly, if the limit is less than or equal to the difference of the parent's gas and the adjustment delta or the predefined GAS_LIMIT_MINIMUM then this function's check fails because the gas limit doesn't allow for a sufficient or reasonable amount of gas to be used on a block.

Parameters

gas_limit : Gas limit to validate.

parent_gas_limit : Gas limit of the parent block.

Returns

check : bool True if gas limit constraints are satisfied, False otherwise.

def check_gas_limit(gas_limit: Uint, ​​parent_gas_limit: Uint) -> bool:
952
    """
953
    Validates the gas limit for a block.
954
955
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
956
    quotient of the parent block's gas limit and the
957
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
958
    passed through as a parameter is greater than or equal to the *sum* of
959
    the parent's gas and the adjustment delta then the limit for gas is too
960
    high and fails this function's check. Similarly, if the limit is less
961
    than or equal to the *difference* of the parent's gas and the adjustment
962
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
963
    check fails because the gas limit doesn't allow for a sufficient or
964
    reasonable amount of gas to be used on a block.
965
966
    Parameters
967
    ----------
968
    gas_limit :
969
        Gas limit to validate.
970
971
    parent_gas_limit :
972
        Gas limit of the parent block.
973
974
    Returns
975
    -------
976
    check : `bool`
977
        True if gas limit constraints are satisfied, False otherwise.
978
    """
979
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
980
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
981
        return False
982
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
983
        return False
984
    if gas_limit < GAS_LIMIT_MINIMUM:
985
        return False
986
987
    return True