ethereum.frontier.fork

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

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

Introduction

Entry point for the Ethereum specification.

BLOCK_REWARD

50
BLOCK_REWARD = U256(5 * 10**18)

GAS_LIMIT_ADJUSTMENT_FACTOR

51
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

52
GAS_LIMIT_MINIMUM = Uint(5000)

MINIMUM_DIFFICULTY

53
MINIMUM_DIFFICULTY = Uint(131072)

MAX_OMMER_DEPTH

54
MAX_OMMER_DEPTH = Uint(6)

BlockChain

History and current state of the block chain.

57
@dataclass
class BlockChain:

blocks

63
    blocks: List[Block]

state

64
    state: State

chain_id

65
    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:
69
    """
70
    Transforms the state from the previous hard fork (`old`) into the block
71
    chain object for this hard fork and returns it.
72
73
    When forks need to implement an irregular state transition, this function
74
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
75
    an example.
76
77
    Parameters
78
    ----------
79
    old :
80
        Previous block chain object.
81
82
    Returns
83
    -------
84
    new : `BlockChain`
85
        Upgraded block chain object for this hard fork.
86
    """
87
    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]:
91
    """
92
    Obtain the list of hashes of the previous 256 blocks in order of
93
    increasing block number.
94
95
    This function will return less hashes for the first 256 blocks.
96
97
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
98
    therefore this function retrieves them.
99
100
    Parameters
101
    ----------
102
    chain :
103
        History and current state.
104
105
    Returns
106
    -------
107
    recent_block_hashes : `List[Hash32]`
108
        Hashes of the recent 256 blocks in order of increasing block number.
109
    """
110
    recent_blocks = chain.blocks[-255:]
111
    # TODO: This function has not been tested rigorously
112
    if len(recent_blocks) == 0:
113
        return []
114
115
    recent_block_hashes = []
116
117
    for block in recent_blocks:
118
        prev_block_hash = block.header.parent_hash
119
        recent_block_hashes.append(prev_block_hash)
120
121
    # We are computing the hash only for the most recent block and not for
122
    # the rest of the blocks as they have successors which have the hash of
123
    # the current block as parent hash.
124
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
125
    recent_block_hashes.append(most_recent_block_hash)
126
127
    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:
131
    """
132
    Attempts to apply a block to an existing block chain.
133
134
    All parts of the block's contents need to be verified before being added
135
    to the chain. Blocks are verified by ensuring that the contents of the
136
    block make logical sense with the contents of the parent block. The
137
    information in the block's header must also match the corresponding
138
    information in the block.
139
140
    To implement Ethereum, in theory clients are only required to store the
141
    most recent 255 blocks of the chain since as far as execution is
142
    concerned, only those blocks are accessed. Practically, however, clients
143
    should store more blocks to handle reorgs.
144
145
    Parameters
146
    ----------
147
    chain :
148
        History and current state.
149
    block :
150
        Block to apply to `chain`.
151
    """
152
    parent_header = chain.blocks[-1].header
153
    validate_header(block.header, parent_header)
154
    validate_ommers(block.ommers, block.header, chain)
155
    apply_body_output = apply_body(
156
        chain.state,
157
        get_last_256_block_hashes(chain),
158
        block.header.coinbase,
159
        block.header.number,
160
        block.header.gas_limit,
161
        block.header.timestamp,
162
        block.header.difficulty,
163
        block.transactions,
164
        block.ommers,
165
    )
166
    if apply_body_output.block_gas_used != block.header.gas_used:
167
        raise InvalidBlock(
168
            f"{apply_body_output.block_gas_used} != {block.header.gas_used}"
169
        )
170
    if apply_body_output.transactions_root != block.header.transactions_root:
171
        raise InvalidBlock
172
    if apply_body_output.state_root != block.header.state_root:
173
        raise InvalidBlock
174
    if apply_body_output.receipt_root != block.header.receipt_root:
175
        raise InvalidBlock
176
    if apply_body_output.block_logs_bloom != block.header.bloom:
177
        raise InvalidBlock
178
179
    chain.blocks.append(block)
180
    if len(chain.blocks) > 255:
181
        # Real clients have to store more blocks to deal with reorgs, but the
182
        # protocol only requires the last 255
183
        chain.blocks = chain.blocks[-255:]

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:
187
    """
188
    Verifies a block header.
189
190
    In order to consider a block's header valid, the logic for the
191
    quantities in the header should match the logic for the block itself.
192
    For example the header timestamp should be greater than the block's parent
193
    timestamp because the block was created *after* the parent block.
194
    Additionally, the block's number should be directly following the parent
195
    block's number since it is the next block in the sequence.
196
197
    Parameters
198
    ----------
199
    header :
200
        Header to check for correctness.
201
    parent_header :
202
        Parent Header of the header to check for correctness
203
    """
204
    if header.timestamp <= parent_header.timestamp:
205
        raise InvalidBlock
206
    if header.number != parent_header.number + Uint(1):
207
        raise InvalidBlock
208
    if not check_gas_limit(header.gas_limit, parent_header.gas_limit):
209
        raise InvalidBlock
210
    if len(header.extra_data) > 32:
211
        raise InvalidBlock
212
213
    block_difficulty = calculate_block_difficulty(
214
        header.number,
215
        header.timestamp,
216
        parent_header.timestamp,
217
        parent_header.difficulty,
218
    )
219
    if header.difficulty != block_difficulty:
220
        raise InvalidBlock
221
222
    block_parent_hash = keccak256(rlp.encode(parent_header))
223
    if header.parent_hash != block_parent_hash:
224
        raise InvalidBlock
225
226
    validate_proof_of_work(header)

generate_header_hash_for_pow

Generate rlp hash of the header which is to be used for Proof-of-Work verification.

In other words, the PoW artefacts mix_digest and nonce are ignored while calculating this hash.

A particular PoW is valid for a single hash, that hash is computed by this function. The nonce and mix_digest are omitted from this hash because they are being changed by miners in their search for a sufficient proof-of-work.

Parameters

header : The header object for which the hash is to be generated.

Returns

hash : Hash32 The PoW valid rlp hash of the passed in header.

def generate_header_hash_for_pow(header: Header) -> Hash32:
230
    """
231
    Generate rlp hash of the header which is to be used for Proof-of-Work
232
    verification.
233
234
    In other words, the PoW artefacts `mix_digest` and `nonce` are ignored
235
    while calculating this hash.
236
237
    A particular PoW is valid for a single hash, that hash is computed by
238
    this function. The `nonce` and `mix_digest` are omitted from this hash
239
    because they are being changed by miners in their search for a sufficient
240
    proof-of-work.
241
242
    Parameters
243
    ----------
244
    header :
245
        The header object for which the hash is to be generated.
246
247
    Returns
248
    -------
249
    hash : `Hash32`
250
        The PoW valid rlp hash of the passed in header.
251
    """
252
    header_data_without_pow_artefacts = (
253
        header.parent_hash,
254
        header.ommers_hash,
255
        header.coinbase,
256
        header.state_root,
257
        header.transactions_root,
258
        header.receipt_root,
259
        header.bloom,
260
        header.difficulty,
261
        header.number,
262
        header.gas_limit,
263
        header.gas_used,
264
        header.timestamp,
265
        header.extra_data,
266
    )
267
268
    return rlp.rlp_hash(header_data_without_pow_artefacts)

validate_proof_of_work

Validates the Proof of Work constraints.

In order to verify that a miner's proof-of-work is valid for a block, a mix-digest and result are calculated using the hashimoto_light hash function. The mix digest is a hash of the header and the nonce that is passed through and it confirms whether or not proof-of-work was done on the correct block. The result is the actual hash value of the block.

Parameters

header : Header of interest.

def validate_proof_of_work(header: Header) -> None:
272
    """
273
    Validates the Proof of Work constraints.
274
275
    In order to verify that a miner's proof-of-work is valid for a block, a
276
    ``mix-digest`` and ``result`` are calculated using the ``hashimoto_light``
277
    hash function. The mix digest is a hash of the header and the nonce that
278
    is passed through and it confirms whether or not proof-of-work was done
279
    on the correct block. The result is the actual hash value of the block.
280
281
    Parameters
282
    ----------
283
    header :
284
        Header of interest.
285
    """
286
    header_hash = generate_header_hash_for_pow(header)
287
    # TODO: Memoize this somewhere and read from that data instead of
288
    # calculating cache for every block validation.
289
    cache = generate_cache(header.number)
290
    mix_digest, result = hashimoto_light(
291
        header_hash, header.nonce, cache, dataset_size(header.number)
292
    )
293
    if mix_digest != header.mix_digest:
294
        raise InvalidBlock
295
296
    limit = Uint(U256.MAX_VALUE) + Uint(1)
297
    if Uint.from_be_bytes(result) > (limit // header.difficulty):
298
        raise InvalidBlock

check_transaction

Check if the transaction is includable in the block.

Parameters

tx : The transaction. gas_available : The gas remaining in the block.

Returns

sender_address : The sender of the transaction.

Raises

InvalidBlock : If the transaction is not includable.

def check_transaction(tx: Transaction, ​​gas_available: Uint) -> Address:
305
    """
306
    Check if the transaction is includable in the block.
307
308
    Parameters
309
    ----------
310
    tx :
311
        The transaction.
312
    gas_available :
313
        The gas remaining in the block.
314
315
    Returns
316
    -------
317
    sender_address :
318
        The sender of the transaction.
319
320
    Raises
321
    ------
322
    InvalidBlock :
323
        If the transaction is not includable.
324
    """
325
    if tx.gas > gas_available:
326
        raise InvalidBlock
327
    sender_address = recover_sender(tx)
328
329
    return sender_address

make_receipt

Make the receipt for a transaction that was executed.

Parameters

tx : The executed transaction. post_state : The state root immediately after this transaction. 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, ​​post_state: Bytes32, ​​cumulative_gas_used: Uint, ​​logs: Tuple[Log, ...]) -> Receipt:
338
    """
339
    Make the receipt for a transaction that was executed.
340
341
    Parameters
342
    ----------
343
    tx :
344
        The executed transaction.
345
    post_state :
346
        The state root immediately after this transaction.
347
    cumulative_gas_used :
348
        The total gas used so far in the block after the transaction was
349
        executed.
350
    logs :
351
        The logs produced by the transaction.
352
353
    Returns
354
    -------
355
    receipt :
356
        The receipt for the transaction.
357
    """
358
    receipt = Receipt(
359
        post_state=post_state,
360
        cumulative_gas_used=cumulative_gas_used,
361
        bloom=logs_bloom(logs),
362
        logs=logs,
363
    )
364
365
    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.

368
@dataclass
class ApplyBodyOutput:

block_gas_used

388
    block_gas_used: Uint

transactions_root

389
    transactions_root: Root

receipt_root

390
    receipt_root: Root

block_logs_bloom

391
    block_logs_bloom: Bloom

state_root

392
    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. 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. block_difficulty : Difficulty of the block. transactions : Transactions included in the block. ommers : Headers of ancestor blocks which are not direct parents (formerly uncles.)

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, ​​block_gas_limit: Uint, ​​block_time: U256, ​​block_difficulty: Uint, ​​transactions: Tuple[Transaction, ...], ​​ommers: Tuple[Header, ...]) -> ApplyBodyOutput:
406
    """
407
    Executes a block.
408
409
    Many of the contents of a block are stored in data structures called
410
    tries. There is a transactions trie which is similar to a ledger of the
411
    transactions stored in the current block. There is also a receipts trie
412
    which stores the results of executing a transaction, like the post state
413
    and gas used. This function creates and executes the block that is to be
414
    added to the chain.
415
416
    Parameters
417
    ----------
418
    state :
419
        Current account state.
420
    block_hashes :
421
        List of hashes of the previous 256 blocks in the order of
422
        increasing block number.
423
    coinbase :
424
        Address of account which receives block reward and transaction fees.
425
    block_number :
426
        Position of the block within the chain.
427
    block_gas_limit :
428
        Initial amount of gas available for execution in this block.
429
    block_time :
430
        Time the block was produced, measured in seconds since the epoch.
431
    block_difficulty :
432
        Difficulty of the block.
433
    transactions :
434
        Transactions included in the block.
435
    ommers :
436
        Headers of ancestor blocks which are not direct parents (formerly
437
        uncles.)
438
439
    Returns
440
    -------
441
    apply_body_output : `ApplyBodyOutput`
442
        Output of applying the block body to the state.
443
    """
444
    gas_available = block_gas_limit
445
    transactions_trie: Trie[Bytes, Optional[Transaction]] = Trie(
446
        secured=False, default=None
447
    )
448
    receipts_trie: Trie[Bytes, Optional[Receipt]] = Trie(
449
        secured=False, default=None
450
    )
451
    block_logs: Tuple[Log, ...] = ()
452
453
    for i, tx in enumerate(transactions):
454
        trie_set(transactions_trie, rlp.encode(Uint(i)), tx)
455
456
        sender_address = check_transaction(tx, gas_available)
457
458
        env = vm.Environment(
459
            caller=sender_address,
460
            origin=sender_address,
461
            block_hashes=block_hashes,
462
            coinbase=coinbase,
463
            number=block_number,
464
            gas_limit=block_gas_limit,
465
            gas_price=tx.gas_price,
466
            time=block_time,
467
            difficulty=block_difficulty,
468
            state=state,
469
            traces=[],
470
        )
471
472
        gas_used, logs = process_transaction(env, tx)
473
        gas_available -= gas_used
474
475
        receipt = make_receipt(
476
            tx, state_root(state), (block_gas_limit - gas_available), logs
477
        )
478
479
        trie_set(
480
            receipts_trie,
481
            rlp.encode(Uint(i)),
482
            receipt,
483
        )
484
485
        block_logs += logs
486
487
    pay_rewards(state, block_number, coinbase, ommers)
488
489
    block_gas_used = block_gas_limit - gas_available
490
491
    block_logs_bloom = logs_bloom(block_logs)
492
493
    return ApplyBodyOutput(
494
        block_gas_used,
495
        root(transactions_trie),
496
        root(receipts_trie),
497
        block_logs_bloom,
498
        state_root(state),
499
    )

validate_ommers

Validates the ommers mentioned in the block.

An ommer block is a block that wasn't canonically added to the blockchain because it wasn't validated as fast as the canonical block but was mined at the same time.

To be considered valid, the ommers must adhere to the rules defined in the Ethereum protocol. The maximum amount of ommers is 2 per block and there cannot be duplicate ommers in a block. Many of the other ommer constraints are listed in the in-line comments of this function.

Parameters

ommers : List of ommers mentioned in the current block. block_header: The header of current block. chain : History and current state.

def validate_ommers(ommers: Tuple[Header, ...], ​​block_header: Header, ​​chain: BlockChain) -> None:
505
    """
506
    Validates the ommers mentioned in the block.
507
508
    An ommer block is a block that wasn't canonically added to the
509
    blockchain because it wasn't validated as fast as the canonical block
510
    but was mined at the same time.
511
512
    To be considered valid, the ommers must adhere to the rules defined in
513
    the Ethereum protocol. The maximum amount of ommers is 2 per block and
514
    there cannot be duplicate ommers in a block. Many of the other ommer
515
    constraints are listed in the in-line comments of this function.
516
517
    Parameters
518
    ----------
519
    ommers :
520
        List of ommers mentioned in the current block.
521
    block_header:
522
        The header of current block.
523
    chain :
524
        History and current state.
525
    """
526
    block_hash = rlp.rlp_hash(block_header)
527
    if rlp.rlp_hash(ommers) != block_header.ommers_hash:
528
        raise InvalidBlock
529
530
    if len(ommers) == 0:
531
        # Nothing to validate
532
        return
533
534
    # Check that each ommer satisfies the constraints of a header
535
    for ommer in ommers:
536
        if Uint(1) > ommer.number or ommer.number >= block_header.number:
537
            raise InvalidBlock
538
        ommer_parent_header = chain.blocks[
539
            -(block_header.number - ommer.number) - 1
540
        ].header
541
        validate_header(ommer, ommer_parent_header)
542
    if len(ommers) > 2:
543
        raise InvalidBlock
544
545
    ommers_hashes = [rlp.rlp_hash(ommer) for ommer in ommers]
546
    if len(ommers_hashes) != len(set(ommers_hashes)):
547
        raise InvalidBlock
548
549
    recent_canonical_blocks = chain.blocks[-(MAX_OMMER_DEPTH + Uint(1)) :]
550
    recent_canonical_block_hashes = {
551
        rlp.rlp_hash(block.header) for block in recent_canonical_blocks
552
    }
553
    recent_ommers_hashes: Set[Hash32] = set()
554
    for block in recent_canonical_blocks:
555
        recent_ommers_hashes = recent_ommers_hashes.union(
556
            {rlp.rlp_hash(ommer) for ommer in block.ommers}
557
        )
558
559
    for ommer_index, ommer in enumerate(ommers):
560
        ommer_hash = ommers_hashes[ommer_index]
561
        if ommer_hash == block_hash:
562
            raise InvalidBlock
563
        if ommer_hash in recent_canonical_block_hashes:
564
            raise InvalidBlock
565
        if ommer_hash in recent_ommers_hashes:
566
            raise InvalidBlock
567
568
        # Ommer age with respect to the current block. For example, an age of
569
        # 1 indicates that the ommer is a sibling of previous block.
570
        ommer_age = block_header.number - ommer.number
571
        if Uint(1) > ommer_age or ommer_age > MAX_OMMER_DEPTH:
572
            raise InvalidBlock
573
        if ommer.parent_hash not in recent_canonical_block_hashes:
574
            raise InvalidBlock
575
        if ommer.parent_hash == block_header.parent_hash:
576
            raise InvalidBlock

pay_rewards

Pay rewards to the block miner as well as the ommers miners.

The miner of the canonical block is rewarded with the predetermined block reward, BLOCK_REWARD, plus a variable award based off of the number of ommer blocks that were mined around the same time, and included in the canonical block's header. An ommer block is a block that wasn't added to the canonical blockchain because it wasn't validated as fast as the accepted block but was mined at the same time. Although not all blocks that are mined are added to the canonical chain, miners are still paid a reward for their efforts. This reward is called an ommer reward and is calculated based on the number associated with the ommer block that they mined.

Parameters

state : Current account state. block_number : Position of the block within the chain. coinbase : Address of account which receives block reward and transaction fees. ommers : List of ommers mentioned in the current block.

def pay_rewards(state: State, ​​block_number: Uint, ​​coinbase: Address, ​​ommers: Tuple[Header, ...]) -> None:
585
    """
586
    Pay rewards to the block miner as well as the ommers miners.
587
588
    The miner of the canonical block is rewarded with the predetermined
589
    block reward, ``BLOCK_REWARD``, plus a variable award based off of the
590
    number of ommer blocks that were mined around the same time, and included
591
    in the canonical block's header. An ommer block is a block that wasn't
592
    added to the canonical blockchain because it wasn't validated as fast as
593
    the accepted block but was mined at the same time. Although not all blocks
594
    that are mined are added to the canonical chain, miners are still paid a
595
    reward for their efforts. This reward is called an ommer reward and is
596
    calculated based on the number associated with the ommer block that they
597
    mined.
598
599
    Parameters
600
    ----------
601
    state :
602
        Current account state.
603
    block_number :
604
        Position of the block within the chain.
605
    coinbase :
606
        Address of account which receives block reward and transaction fees.
607
    ommers :
608
        List of ommers mentioned in the current block.
609
    """
610
    ommer_count = U256(len(ommers))
611
    miner_reward = BLOCK_REWARD + (ommer_count * (BLOCK_REWARD // U256(32)))
612
    create_ether(state, coinbase, miner_reward)
613
614
    for ommer in ommers:
615
        # Ommer age with respect to the current block.
616
        ommer_age = U256(block_number - ommer.number)
617
        ommer_miner_reward = ((U256(8) - ommer_age) * BLOCK_REWARD) // U256(8)
618
        create_ether(state, ommer.coinbase, ommer_miner_reward)

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.frontier.vm.Environment, ​​tx: Transaction) -> Tuple[Uint, Tuple[Log, ...]]:
624
    """
625
    Execute a transaction against the provided environment.
626
627
    This function processes the actions needed to execute a transaction.
628
    It decrements the sender's account after calculating the gas fee and
629
    refunds them the proper amount after execution. Calling contracts,
630
    deploying code, and incrementing nonces are all examples of actions that
631
    happen within this function or from a call made within this function.
632
633
    Accounts that are marked for deletion are processed and destroyed after
634
    execution.
635
636
    Parameters
637
    ----------
638
    env :
639
        Environment for the Ethereum Virtual Machine.
640
    tx :
641
        Transaction to execute.
642
643
    Returns
644
    -------
645
    gas_left : `ethereum.base_types.U256`
646
        Remaining gas after execution.
647
    logs : `Tuple[ethereum.blocks.Log, ...]`
648
        Logs generated during execution.
649
    """
650
    if not validate_transaction(tx):
651
        raise InvalidBlock
652
653
    sender = env.origin
654
    sender_account = get_account(env.state, sender)
655
    gas_fee = tx.gas * tx.gas_price
656
    if sender_account.nonce != tx.nonce:
657
        raise InvalidBlock
658
    if Uint(sender_account.balance) < gas_fee + Uint(tx.value):
659
        raise InvalidBlock
660
    if sender_account.code != bytearray():
661
        raise InvalidSenderError("not EOA")
662
663
    gas = tx.gas - calculate_intrinsic_cost(tx)
664
    increment_nonce(env.state, sender)
665
    sender_balance_after_gas_fee = Uint(sender_account.balance) - gas_fee
666
    set_account_balance(env.state, sender, U256(sender_balance_after_gas_fee))
667
668
    message = prepare_message(
669
        sender,
670
        tx.to,
671
        tx.value,
672
        tx.data,
673
        gas,
674
        env,
675
    )
676
677
    output = process_message_call(message, env)
678
679
    gas_used = tx.gas - output.gas_left
680
    gas_refund = min(gas_used // Uint(2), Uint(output.refund_counter))
681
    gas_refund_amount = (output.gas_left + gas_refund) * tx.gas_price
682
    transaction_fee = (tx.gas - output.gas_left - gas_refund) * tx.gas_price
683
    total_gas_used = gas_used - gas_refund
684
685
    # refund gas
686
    sender_balance_after_refund = get_account(
687
        env.state, sender
688
    ).balance + U256(gas_refund_amount)
689
    set_account_balance(env.state, sender, sender_balance_after_refund)
690
691
    # transfer miner fees
692
    coinbase_balance_after_mining_fee = get_account(
693
        env.state, env.coinbase
694
    ).balance + U256(transaction_fee)
695
    set_account_balance(
696
        env.state, env.coinbase, coinbase_balance_after_mining_fee
697
    )
698
699
    for address in output.accounts_to_delete:
700
        destroy_account(env.state, address)
701
702
    return total_gas_used, output.logs

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:
706
    """
707
    Verifies a transaction.
708
709
    The gas in a transaction gets used to pay for the intrinsic cost of
710
    operations, therefore if there is insufficient gas then it would not
711
    be possible to execute a transaction and it will be declared invalid.
712
713
    Additionally, the nonce of a transaction must not equal or exceed the
714
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
715
    In practice, defining the limit as ``2**64-1`` has no impact because
716
    sending ``2**64-1`` transactions is improbable. It's not strictly
717
    impossible though, ``2**64-1`` transactions is the entire capacity of the
718
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
719
720
    Parameters
721
    ----------
722
    tx :
723
        Transaction to validate.
724
725
    Returns
726
    -------
727
    verified : `bool`
728
        True if the transaction can be executed, or False otherwise.
729
    """
730
    if calculate_intrinsic_cost(tx) > Uint(tx.gas):
731
        return False
732
    if tx.nonce >= U256(U64.MAX_VALUE):
733
        return False
734
    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:
738
    """
739
    Calculates the gas that is charged before execution is started.
740
741
    The intrinsic cost of the transaction is charged before execution has
742
    begun. Functions/operations in the EVM cost money to execute so this
743
    intrinsic cost is for the operations that need to be paid for as part of
744
    the transaction. Data transfer, for example, is part of this intrinsic
745
    cost. It costs ether to send data over the wire and that ether is
746
    accounted for in the intrinsic cost calculated in this function. This
747
    intrinsic cost must be calculated and paid for before execution in order
748
    for all operations to be implemented.
749
750
    Parameters
751
    ----------
752
    tx :
753
        Transaction to compute the intrinsic cost of.
754
755
    Returns
756
    -------
757
    verified : `ethereum.base_types.Uint`
758
        The intrinsic cost of the transaction.
759
    """
760
    data_cost = 0
761
762
    for byte in tx.data:
763
        if byte == 0:
764
            data_cost += TX_DATA_COST_PER_ZERO
765
        else:
766
            data_cost += TX_DATA_COST_PER_NON_ZERO
767
768
    return Uint(TX_BASE_COST + data_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.

Returns

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

def recover_sender(tx: Transaction) -> Address:
772
    """
773
    Extracts the sender address from a transaction.
774
775
    The v, r, and s values are the three parts that make up the signature
776
    of a transaction. In order to recover the sender of a transaction the two
777
    components needed are the signature (``v``, ``r``, and ``s``) and the
778
    signing hash of the transaction. The sender's public key can be obtained
779
    with these two values and therefore the sender address can be retrieved.
780
781
    Parameters
782
    ----------
783
    tx :
784
        Transaction of interest.
785
786
    Returns
787
    -------
788
    sender : `ethereum.fork_types.Address`
789
        The address of the account that signed the transaction.
790
    """
791
    v, r, s = tx.v, tx.r, tx.s
792
    if v != 27 and v != 28:
793
        raise InvalidBlock
794
    if U256(0) >= r or r >= SECP256K1N:
795
        raise InvalidBlock
796
    if U256(0) >= s or s >= SECP256K1N:
797
        raise InvalidBlock
798
799
    public_key = secp256k1_recover(r, s, v - U256(27), signing_hash(tx))
800
    return Address(keccak256(public_key)[12:32])

signing_hash

Compute the hash of a transaction used in the signature.

The values that are used to compute the signing hash set the rules for a transaction. For example, signing over the gas sets a limit for the amount of money that is allowed to be pulled out of the sender's account.

Parameters

tx : Transaction of interest.

Returns

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

def signing_hash(tx: Transaction) -> Hash32:
804
    """
805
    Compute the hash of a transaction used in the signature.
806
807
    The values that are used to compute the signing hash set the rules for a
808
    transaction. For example, signing over the gas sets a limit for the
809
    amount of money that is allowed to be pulled out of the sender's account.
810
811
    Parameters
812
    ----------
813
    tx :
814
        Transaction of interest.
815
816
    Returns
817
    -------
818
    hash : `ethereum.crypto.hash.Hash32`
819
        Hash of the transaction.
820
    """
821
    return keccak256(
822
        rlp.encode(
823
            (
824
                tx.nonce,
825
                tx.gas_price,
826
                tx.gas,
827
                tx.to,
828
                tx.value,
829
                tx.data,
830
            )
831
        )
832
    )

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:
836
    """
837
    Computes the hash of a block header.
838
839
    The header hash of a block is the canonical hash that is used to refer
840
    to a specific block and completely distinguishes a block from another.
841
842
    ``keccak256`` is a function that produces a 256 bit hash of any input.
843
    It also takes in any number of bytes as an input and produces a single
844
    hash for them. A hash is a completely unique output for a single input.
845
    So an input corresponds to one unique hash that can be used to identify
846
    the input exactly.
847
848
    Prior to using the ``keccak256`` hash function, the header must be
849
    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
850
    RLP encoding the header converts it into a space-efficient format that
851
    allows for easy transfer of data between nodes. The purpose of RLP is to
852
    encode arbitrarily nested arrays of binary data, and RLP is the primary
853
    encoding method used to serialize objects in Ethereum's execution layer.
854
    The only purpose of RLP is to encode structure; encoding specific data
855
    types (e.g. strings, floats) is left up to higher-order protocols.
856
857
    Parameters
858
    ----------
859
    header :
860
        Header of interest.
861
862
    Returns
863
    -------
864
    hash : `ethereum.crypto.hash.Hash32`
865
        Hash of the header.
866
    """
867
    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:
871
    """
872
    Validates the gas limit for a block.
873
874
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
875
    quotient of the parent block's gas limit and the
876
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
877
    passed through as a parameter is greater than or equal to the *sum* of
878
    the parent's gas and the adjustment delta then the limit for gas is too
879
    high and fails this function's check. Similarly, if the limit is less
880
    than or equal to the *difference* of the parent's gas and the adjustment
881
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
882
    check fails because the gas limit doesn't allow for a sufficient or
883
    reasonable amount of gas to be used on a block.
884
885
    Parameters
886
    ----------
887
    gas_limit :
888
        Gas limit to validate.
889
890
    parent_gas_limit :
891
        Gas limit of the parent block.
892
893
    Returns
894
    -------
895
    check : `bool`
896
        True if gas limit constraints are satisfied, False otherwise.
897
    """
898
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
899
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
900
        return False
901
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
902
        return False
903
    if gas_limit < GAS_LIMIT_MINIMUM:
904
        return False
905
906
    return True

calculate_block_difficulty

Computes difficulty of a block using its header and parent header.

The difficulty of a block is determined by the time the block was created after its parent. If a block's timestamp is more than 13 seconds after its parent block then its difficulty is set as the difference between the parent's difficulty and the max_adjustment_delta. Otherwise, if the time between parent and child blocks is too small (under 13 seconds) then, to avoid mass forking, the block's difficulty is set to the sum of the delta and the parent's difficulty.

Parameters

block_number : Block number of the block. block_timestamp : Timestamp of the block. parent_timestamp : Timestamp of the parent block. parent_difficulty : difficulty of the parent block.

Returns

difficulty : ethereum.base_types.Uint Computed difficulty for a block.

def calculate_block_difficulty(block_number: Uint, ​​block_timestamp: U256, ​​parent_timestamp: U256, ​​parent_difficulty: Uint) -> Uint:
915
    """
916
    Computes difficulty of a block using its header and
917
    parent header.
918
919
    The difficulty of a block is determined by the time the block was
920
    created after its parent. If a block's timestamp is more than 13
921
    seconds after its parent block then its difficulty is set as the
922
    difference between the parent's difficulty and the
923
    ``max_adjustment_delta``. Otherwise, if the time between parent and
924
    child blocks is too small (under 13 seconds) then, to avoid mass
925
    forking, the block's difficulty is set to the sum of the delta and
926
    the parent's difficulty.
927
928
    Parameters
929
    ----------
930
    block_number :
931
        Block number of the block.
932
    block_timestamp :
933
        Timestamp of the block.
934
    parent_timestamp :
935
        Timestamp of the parent block.
936
    parent_difficulty :
937
        difficulty of the parent block.
938
939
    Returns
940
    -------
941
    difficulty : `ethereum.base_types.Uint`
942
        Computed difficulty for a block.
943
    """
944
    max_adjustment_delta = parent_difficulty // Uint(2048)
945
    if block_timestamp < parent_timestamp + U256(13):
946
        difficulty = parent_difficulty + max_adjustment_delta
947
    else:  # block_timestamp >= parent_timestamp + 13
948
        difficulty = parent_difficulty - max_adjustment_delta
949
950
    # Historical Note: The difficulty bomb was not present in Ethereum at the
951
    # start of Frontier, but was added shortly after launch. However since the
952
    # bomb has no effect prior to block 200000 we pretend it existed from
953
    # genesis.
954
    # See https://github.com/ethereum/go-ethereum/pull/1588
955
    num_bomb_periods = (int(block_number) // 100000) - 2
956
    if num_bomb_periods >= 0:
957
        difficulty += 2**num_bomb_periods
958
959
    # Some clients raise the difficulty to `MINIMUM_DIFFICULTY` prior to adding
960
    # the bomb. This bug does not matter because the difficulty is always much
961
    # greater than `MINIMUM_DIFFICULTY` on Mainnet.
962
    return max(difficulty, MINIMUM_DIFFICULTY)