ethereum.paris.transactionsethereum.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""):
186
        create_cost = TX_CREATE_COST
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
        public_key = secp256k1_recover(
252
            r, s, tx.y_parity, signing_hash_2930(tx)
253
        )
254
    elif isinstance(tx, FeeMarketTransaction):
255
        public_key = secp256k1_recover(
256
            r, s, tx.y_parity, signing_hash_1559(tx)
257
        )
258
259
    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:
263
    """
264
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
265
266
    Parameters
267
    ----------
268
    tx :
269
        Transaction of interest.
270
271
    Returns
272
    -------
273
    hash : `ethereum.crypto.hash.Hash32`
274
        Hash of the transaction.
275
    """
276
    return keccak256(
277
        rlp.encode(
278
            (
279
                tx.nonce,
280
                tx.gas_price,
281
                tx.gas,
282
                tx.to,
283
                tx.value,
284
                tx.data,
285
            )
286
        )
287
    )

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

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

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