ethereum.shanghai.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

Transaction

88
Transaction = Union[
89
    LegacyTransaction, AccessListTransaction, FeeMarketTransaction
90
]

encode_transaction

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

def encode_transaction(tx: Transaction) -> Union[LegacyTransaction, Bytes]:
94
    """
95
    Encode a transaction. Needed because non-legacy transactions aren't RLP.
96
    """
97
    if isinstance(tx, LegacyTransaction):
98
        return tx
99
    elif isinstance(tx, AccessListTransaction):
100
        return b"\x01" + rlp.encode(tx)
101
    elif isinstance(tx, FeeMarketTransaction):
102
        return b"\x02" + rlp.encode(tx)
103
    else:
104
        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:
108
    """
109
    Decode a transaction. Needed because non-legacy transactions aren't RLP.
110
    """
111
    if isinstance(tx, Bytes):
112
        if tx[0] == 1:
113
            return rlp.decode_to(AccessListTransaction, tx[1:])
114
        elif tx[0] == 2:
115
            return rlp.decode_to(FeeMarketTransaction, tx[1:])
116
        else:
117
            raise TransactionTypeError(tx[0])
118
    else:
119
        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:
123
    """
124
    Verifies a transaction.
125
126
    The gas in a transaction gets used to pay for the intrinsic cost of
127
    operations, therefore if there is insufficient gas then it would not
128
    be possible to execute a transaction and it will be declared invalid.
129
130
    Additionally, the nonce of a transaction must not equal or exceed the
131
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
132
    In practice, defining the limit as ``2**64-1`` has no impact because
133
    sending ``2**64-1`` transactions is improbable. It's not strictly
134
    impossible though, ``2**64-1`` transactions is the entire capacity of the
135
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
136
137
    Parameters
138
    ----------
139
    tx :
140
        Transaction to validate.
141
142
    Returns
143
    -------
144
    verified : `bool`
145
        True if the transaction can be executed, or False otherwise.
146
    """
147
    from .vm.interpreter import MAX_CODE_SIZE
148
149
    if calculate_intrinsic_cost(tx) > tx.gas:
150
        return False
151
    if tx.nonce >= U256(U64.MAX_VALUE):
152
        return False
153
    if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE:
154
        return False
155
156
    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:
160
    """
161
    Calculates the gas that is charged before execution is started.
162
163
    The intrinsic cost of the transaction is charged before execution has
164
    begun. Functions/operations in the EVM cost money to execute so this
165
    intrinsic cost is for the operations that need to be paid for as part of
166
    the transaction. Data transfer, for example, is part of this intrinsic
167
    cost. It costs ether to send data over the wire and that ether is
168
    accounted for in the intrinsic cost calculated in this function. This
169
    intrinsic cost must be calculated and paid for before execution in order
170
    for all operations to be implemented.
171
172
    Parameters
173
    ----------
174
    tx :
175
        Transaction to compute the intrinsic cost of.
176
177
    Returns
178
    -------
179
    verified : `ethereum.base_types.Uint`
180
        The intrinsic cost of the transaction.
181
    """
182
    from .vm.gas import init_code_cost
183
184
    data_cost = 0
185
186
    for byte in tx.data:
187
        if byte == 0:
188
            data_cost += TX_DATA_COST_PER_ZERO
189
        else:
190
            data_cost += TX_DATA_COST_PER_NON_ZERO
191
192
    if tx.to == Bytes0(b""):
193
        create_cost = TX_CREATE_COST + int(init_code_cost(Uint(len(tx.data))))
194
    else:
195
        create_cost = 0
196
197
    access_list_cost = 0
198
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
199
        for _address, keys in tx.access_list:
200
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
201
            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
202
203
    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:
207
    """
208
    Extracts the sender address from a transaction.
209
210
    The v, r, and s values are the three parts that make up the signature
211
    of a transaction. In order to recover the sender of a transaction the two
212
    components needed are the signature (``v``, ``r``, and ``s``) and the
213
    signing hash of the transaction. The sender's public key can be obtained
214
    with these two values and therefore the sender address can be retrieved.
215
216
    Parameters
217
    ----------
218
    tx :
219
        Transaction of interest.
220
    chain_id :
221
        ID of the executing chain.
222
223
    Returns
224
    -------
225
    sender : `ethereum.fork_types.Address`
226
        The address of the account that signed the transaction.
227
    """
228
    r, s = tx.r, tx.s
229
    if U256(0) >= r or r >= SECP256K1N:
230
        raise InvalidSignatureError("bad r")
231
    if U256(0) >= s or s > SECP256K1N // U256(2):
232
        raise InvalidSignatureError("bad s")
233
234
    if isinstance(tx, LegacyTransaction):
235
        v = tx.v
236
        if v == 27 or v == 28:
237
            public_key = secp256k1_recover(
238
                r, s, v - U256(27), signing_hash_pre155(tx)
239
            )
240
        else:
241
            chain_id_x2 = U256(chain_id) * U256(2)
242
            if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
243
                raise InvalidSignatureError("bad v")
244
            public_key = secp256k1_recover(
245
                r,
246
                s,
247
                v - U256(35) - chain_id_x2,
248
                signing_hash_155(tx, chain_id),
249
            )
250
    elif isinstance(tx, AccessListTransaction):
251
        if tx.y_parity not in (U256(0), U256(1)):
252
            raise InvalidSignatureError("bad y_parity")
253
        public_key = secp256k1_recover(
254
            r, s, tx.y_parity, signing_hash_2930(tx)
255
        )
256
    elif isinstance(tx, FeeMarketTransaction):
257
        if tx.y_parity not in (U256(0), U256(1)):
258
            raise InvalidSignatureError("bad y_parity")
259
        public_key = secp256k1_recover(
260
            r, s, tx.y_parity, signing_hash_1559(tx)
261
        )
262
263
    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:
267
    """
268
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
269
270
    Parameters
271
    ----------
272
    tx :
273
        Transaction of interest.
274
275
    Returns
276
    -------
277
    hash : `ethereum.crypto.hash.Hash32`
278
        Hash of the transaction.
279
    """
280
    return keccak256(
281
        rlp.encode(
282
            (
283
                tx.nonce,
284
                tx.gas_price,
285
                tx.gas,
286
                tx.to,
287
                tx.value,
288
                tx.data,
289
            )
290
        )
291
    )

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:
295
    """
296
    Compute the hash of a transaction used in a EIP 155 signature.
297
298
    Parameters
299
    ----------
300
    tx :
301
        Transaction of interest.
302
    chain_id :
303
        The id of the current chain.
304
305
    Returns
306
    -------
307
    hash : `ethereum.crypto.hash.Hash32`
308
        Hash of the transaction.
309
    """
310
    return keccak256(
311
        rlp.encode(
312
            (
313
                tx.nonce,
314
                tx.gas_price,
315
                tx.gas,
316
                tx.to,
317
                tx.value,
318
                tx.data,
319
                chain_id,
320
                Uint(0),
321
                Uint(0),
322
            )
323
        )
324
    )

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

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