ethereum.muir_glacier.transactionsethereum.berlin.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

Transaction

Atomic operation performed on the block chain.

26
@slotted_freezable
27
@dataclass
class Transaction:

nonce

33
    nonce: U256

gas_price

34
    gas_price: Uint

gas

35
    gas: Uint

to

36
    to: Union[Bytes0, Address]

value

37
    value: U256

data

38
    data: Bytes

v

39
    v: U256

r

40
    r: U256

s

41
    s: U256

Transaction

67
Transaction = Union[LegacyTransaction, AccessListTransaction]

encode_transaction

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

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

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: Transaction, ​​chain_id: U64) -> Hash32:
252
    """
253
    Compute the hash of a transaction used in a EIP 155 signature.
254
255
    Parameters
256
    ----------
257
    tx :
258
        Transaction of interest.
259
    chain_id :
260
        The id of the current chain.
261
262
    Returns
263
    -------
264
    hash : `ethereum.crypto.hash.Hash32`
265
        Hash of the transaction.
266
    """
267
    return keccak256(
268
        rlp.encode(
269
            (
270
                tx.nonce,
271
                tx.gas_price,
272
                tx.gas,
273
                tx.to,
274
                tx.value,
275
                tx.data,
276
                chain_id,
277
                Uint(0),
278
                Uint(0),
279
            )
280
        )
281
    )

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:
285
    """
286
    Compute the hash of a transaction used in a EIP 2930 signature.
287
288
    Parameters
289
    ----------
290
    tx :
291
        Transaction of interest.
292
293
    Returns
294
    -------
295
    hash : `ethereum.crypto.hash.Hash32`
296
        Hash of the transaction.
297
    """
298
    return keccak256(
299
        b"\x01"
300
        + rlp.encode(
301
            (
302
                tx.chain_id,
303
                tx.nonce,
304
                tx.gas_price,
305
                tx.gas,
306
                tx.to,
307
                tx.value,
308
                tx.data,
309
                tx.access_list,
310
            )
311
        )
312
    )