ethereum.cancun.transactions

Transactions are atomic units of work created externally to Ethereum and submitted to be executed. If Ethereum is viewed as a state machine, transactions are the events that move between states.

TX_BASE_COST

21
TX_BASE_COST = 21000

TX_DATA_COST_PER_NON_ZERO

22
TX_DATA_COST_PER_NON_ZERO = 16

TX_DATA_COST_PER_ZERO

23
TX_DATA_COST_PER_ZERO = 4

TX_CREATE_COST

24
TX_CREATE_COST = 32000

TX_ACCESS_LIST_ADDRESS_COST

25
TX_ACCESS_LIST_ADDRESS_COST = 2400

TX_ACCESS_LIST_STORAGE_KEY_COST

26
TX_ACCESS_LIST_STORAGE_KEY_COST = 1900

LegacyTransaction

Atomic operation performed on the block chain.

29
@slotted_freezable
30
@dataclass
class LegacyTransaction:

nonce

36
    nonce: U256

gas_price

37
    gas_price: Uint

gas

38
    gas: Uint

to

39
    to: Union[Bytes0, Address]

value

40
    value: U256

data

41
    data: Bytes

v

42
    v: U256

r

43
    r: U256

s

44
    s: U256

AccessListTransaction

The transaction type added in EIP-2930 to support access lists.

47
@slotted_freezable
48
@dataclass
class AccessListTransaction:

chain_id

54
    chain_id: U64

nonce

55
    nonce: U256

gas_price

56
    gas_price: Uint

gas

57
    gas: Uint

to

58
    to: Union[Bytes0, Address]

value

59
    value: U256

data

60
    data: Bytes

access_list

61
    access_list: Tuple[Tuple[Address, Tuple[Bytes32, ...]], ...]

y_parity

62
    y_parity: U256

r

63
    r: U256

s

64
    s: U256

FeeMarketTransaction

The transaction type added in EIP-1559.

67
@slotted_freezable
68
@dataclass
class FeeMarketTransaction:

chain_id

74
    chain_id: U64

nonce

75
    nonce: U256

max_priority_fee_per_gas

76
    max_priority_fee_per_gas: Uint

max_fee_per_gas

77
    max_fee_per_gas: Uint

gas

78
    gas: Uint

to

79
    to: Union[Bytes0, Address]

value

80
    value: U256

data

81
    data: Bytes

access_list

82
    access_list: Tuple[Tuple[Address, Tuple[Bytes32, ...]], ...]

y_parity

83
    y_parity: U256

r

84
    r: U256

s

85
    s: U256

BlobTransaction

The transaction type added in EIP-4844.

88
@slotted_freezable
89
@dataclass
class BlobTransaction:

chain_id

95
    chain_id: U64

nonce

96
    nonce: U256

max_priority_fee_per_gas

97
    max_priority_fee_per_gas: Uint

max_fee_per_gas

98
    max_fee_per_gas: Uint

gas

99
    gas: Uint

to

100
    to: Address

value

101
    value: U256

data

102
    data: Bytes

access_list

103
    access_list: Tuple[Tuple[Address, Tuple[Bytes32, ...]], ...]

max_fee_per_blob_gas

104
    max_fee_per_blob_gas: U256

blob_versioned_hashes

105
    blob_versioned_hashes: Tuple[VersionedHash, ...]

y_parity

106
    y_parity: U256

r

107
    r: U256

s

108
    s: U256

Transaction

111
Transaction = Union[
112
    LegacyTransaction,
113
    AccessListTransaction,
114
    FeeMarketTransaction,
115
    BlobTransaction,
116
]

encode_transaction

Encode a transaction. Needed because non-legacy transactions aren't RLP.

def encode_transaction(tx: Transaction) -> Union[LegacyTransaction, Bytes]:
120
    """
121
    Encode a transaction. Needed because non-legacy transactions aren't RLP.
122
    """
123
    if isinstance(tx, LegacyTransaction):
124
        return tx
125
    elif isinstance(tx, AccessListTransaction):
126
        return b"\x01" + rlp.encode(tx)
127
    elif isinstance(tx, FeeMarketTransaction):
128
        return b"\x02" + rlp.encode(tx)
129
    elif isinstance(tx, BlobTransaction):
130
        return b"\x03" + rlp.encode(tx)
131
    else:
132
        raise Exception(f"Unable to encode transaction of type {type(tx)}")

decode_transaction

Decode a transaction. Needed because non-legacy transactions aren't RLP.

def decode_transaction(tx: Union[LegacyTransaction, Bytes]) -> Transaction:
136
    """
137
    Decode a transaction. Needed because non-legacy transactions aren't RLP.
138
    """
139
    if isinstance(tx, Bytes):
140
        if tx[0] == 1:
141
            return rlp.decode_to(AccessListTransaction, tx[1:])
142
        elif tx[0] == 2:
143
            return rlp.decode_to(FeeMarketTransaction, tx[1:])
144
        elif tx[0] == 3:
145
            return rlp.decode_to(BlobTransaction, tx[1:])
146
        else:
147
            raise TransactionTypeError(tx[0])
148
    else:
149
        return tx

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:
153
    """
154
    Verifies a transaction.
155
156
    The gas in a transaction gets used to pay for the intrinsic cost of
157
    operations, therefore if there is insufficient gas then it would not
158
    be possible to execute a transaction and it will be declared invalid.
159
160
    Additionally, the nonce of a transaction must not equal or exceed the
161
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
162
    In practice, defining the limit as ``2**64-1`` has no impact because
163
    sending ``2**64-1`` transactions is improbable. It's not strictly
164
    impossible though, ``2**64-1`` transactions is the entire capacity of the
165
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
166
167
    Parameters
168
    ----------
169
    tx :
170
        Transaction to validate.
171
172
    Returns
173
    -------
174
    verified : `bool`
175
        True if the transaction can be executed, or False otherwise.
176
    """
177
    from .vm.interpreter import MAX_CODE_SIZE
178
179
    if calculate_intrinsic_cost(tx) > tx.gas:
180
        return False
181
    if tx.nonce >= U256(U64.MAX_VALUE):
182
        return False
183
    if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE:
184
        return False
185
186
    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:
190
    """
191
    Calculates the gas that is charged before execution is started.
192
193
    The intrinsic cost of the transaction is charged before execution has
194
    begun. Functions/operations in the EVM cost money to execute so this
195
    intrinsic cost is for the operations that need to be paid for as part of
196
    the transaction. Data transfer, for example, is part of this intrinsic
197
    cost. It costs ether to send data over the wire and that ether is
198
    accounted for in the intrinsic cost calculated in this function. This
199
    intrinsic cost must be calculated and paid for before execution in order
200
    for all operations to be implemented.
201
202
    Parameters
203
    ----------
204
    tx :
205
        Transaction to compute the intrinsic cost of.
206
207
    Returns
208
    -------
209
    verified : `ethereum.base_types.Uint`
210
        The intrinsic cost of the transaction.
211
    """
212
    from .vm.gas import init_code_cost
213
214
    data_cost = 0
215
216
    for byte in tx.data:
217
        if byte == 0:
218
            data_cost += TX_DATA_COST_PER_ZERO
219
        else:
220
            data_cost += TX_DATA_COST_PER_NON_ZERO
221
222
    if tx.to == Bytes0(b""):
223
        create_cost = TX_CREATE_COST + int(init_code_cost(Uint(len(tx.data))))
224
    else:
225
        create_cost = 0
226
227
    access_list_cost = 0
228
    if isinstance(
229
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
230
    ):
231
        for _address, keys in tx.access_list:
232
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
233
            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
234
235
    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:
239
    """
240
    Extracts the sender address from a transaction.
241
242
    The v, r, and s values are the three parts that make up the signature
243
    of a transaction. In order to recover the sender of a transaction the two
244
    components needed are the signature (``v``, ``r``, and ``s``) and the
245
    signing hash of the transaction. The sender's public key can be obtained
246
    with these two values and therefore the sender address can be retrieved.
247
248
    Parameters
249
    ----------
250
    tx :
251
        Transaction of interest.
252
    chain_id :
253
        ID of the executing chain.
254
255
    Returns
256
    -------
257
    sender : `ethereum.fork_types.Address`
258
        The address of the account that signed the transaction.
259
    """
260
    r, s = tx.r, tx.s
261
    if U256(0) >= r or r >= SECP256K1N:
262
        raise InvalidSignatureError("bad r")
263
    if U256(0) >= s or s > SECP256K1N // U256(2):
264
        raise InvalidSignatureError("bad s")
265
266
    if isinstance(tx, LegacyTransaction):
267
        v = tx.v
268
        if v == 27 or v == 28:
269
            public_key = secp256k1_recover(
270
                r, s, v - U256(27), signing_hash_pre155(tx)
271
            )
272
        else:
273
            chain_id_x2 = U256(chain_id) * U256(2)
274
            if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
275
                raise InvalidSignatureError("bad v")
276
            public_key = secp256k1_recover(
277
                r,
278
                s,
279
                v - U256(35) - chain_id_x2,
280
                signing_hash_155(tx, chain_id),
281
            )
282
    elif isinstance(tx, AccessListTransaction):
283
        public_key = secp256k1_recover(
284
            r, s, tx.y_parity, signing_hash_2930(tx)
285
        )
286
    elif isinstance(tx, FeeMarketTransaction):
287
        public_key = secp256k1_recover(
288
            r, s, tx.y_parity, signing_hash_1559(tx)
289
        )
290
    elif isinstance(tx, BlobTransaction):
291
        public_key = secp256k1_recover(
292
            r, s, tx.y_parity, signing_hash_4844(tx)
293
        )
294
295
    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:
299
    """
300
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
301
302
    Parameters
303
    ----------
304
    tx :
305
        Transaction of interest.
306
307
    Returns
308
    -------
309
    hash : `ethereum.crypto.hash.Hash32`
310
        Hash of the transaction.
311
    """
312
    return keccak256(
313
        rlp.encode(
314
            (
315
                tx.nonce,
316
                tx.gas_price,
317
                tx.gas,
318
                tx.to,
319
                tx.value,
320
                tx.data,
321
            )
322
        )
323
    )

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:
327
    """
328
    Compute the hash of a transaction used in a EIP 155 signature.
329
330
    Parameters
331
    ----------
332
    tx :
333
        Transaction of interest.
334
    chain_id :
335
        The id of the current chain.
336
337
    Returns
338
    -------
339
    hash : `ethereum.crypto.hash.Hash32`
340
        Hash of the transaction.
341
    """
342
    return keccak256(
343
        rlp.encode(
344
            (
345
                tx.nonce,
346
                tx.gas_price,
347
                tx.gas,
348
                tx.to,
349
                tx.value,
350
                tx.data,
351
                chain_id,
352
                Uint(0),
353
                Uint(0),
354
            )
355
        )
356
    )

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:
360
    """
361
    Compute the hash of a transaction used in a EIP 2930 signature.
362
363
    Parameters
364
    ----------
365
    tx :
366
        Transaction of interest.
367
368
    Returns
369
    -------
370
    hash : `ethereum.crypto.hash.Hash32`
371
        Hash of the transaction.
372
    """
373
    return keccak256(
374
        b"\x01"
375
        + rlp.encode(
376
            (
377
                tx.chain_id,
378
                tx.nonce,
379
                tx.gas_price,
380
                tx.gas,
381
                tx.to,
382
                tx.value,
383
                tx.data,
384
                tx.access_list,
385
            )
386
        )
387
    )

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:
391
    """
392
    Compute the hash of a transaction used in a EIP 1559 signature.
393
394
    Parameters
395
    ----------
396
    tx :
397
        Transaction of interest.
398
399
    Returns
400
    -------
401
    hash : `ethereum.crypto.hash.Hash32`
402
        Hash of the transaction.
403
    """
404
    return keccak256(
405
        b"\x02"
406
        + rlp.encode(
407
            (
408
                tx.chain_id,
409
                tx.nonce,
410
                tx.max_priority_fee_per_gas,
411
                tx.max_fee_per_gas,
412
                tx.gas,
413
                tx.to,
414
                tx.value,
415
                tx.data,
416
                tx.access_list,
417
            )
418
        )
419
    )

signing_hash_4844

Compute the hash of a transaction used in a EIP-4844 signature.

Parameters

tx : Transaction of interest.

Returns

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

def signing_hash_4844(tx: BlobTransaction) -> Hash32:
423
    """
424
    Compute the hash of a transaction used in a EIP-4844 signature.
425
426
    Parameters
427
    ----------
428
    tx :
429
        Transaction of interest.
430
431
    Returns
432
    -------
433
    hash : `ethereum.crypto.hash.Hash32`
434
        Hash of the transaction.
435
    """
436
    return keccak256(
437
        b"\x03"
438
        + rlp.encode(
439
            (
440
                tx.chain_id,
441
                tx.nonce,
442
                tx.max_priority_fee_per_gas,
443
                tx.max_fee_per_gas,
444
                tx.gas,
445
                tx.to,
446
                tx.value,
447
                tx.data,
448
                tx.access_list,
449
                tx.max_fee_per_blob_gas,
450
                tx.blob_versioned_hashes,
451
            )
452
        )
453
    )