Skip to content

test_multi_authorization_intra_tx_state()

Documentation for tests/amsterdam/eip2780_reduce_intrinsic_tx_gas/test_authorization_charges.py::test_multi_authorization_intra_tx_state@26332146.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/amsterdam/eip2780_reduce_intrinsic_tx_gas/test_authorization_charges.py::test_multi_authorization_intra_tx_state --fork Amsterdam

Two authorizations in one transaction, charged against the state each leaves for the next.

set_delegation applies authorizations in list order and reads live state, so a second authorization on the same authority sees the code the first installed:

  • set_then_modify: the first sets a fresh delegation on an empty EOA (paying AUTH_BASE); the second re-points it. The authority now has code, so the second pays no AUTH_BASE.
  • create_then_modify: the first creates the authority and delegates it (NEW_ACCOUNT + ACCOUNT_WRITE + AUTH_BASE); the second re-points it and pays no further state charge.
  • clear_then_set: the first clears an existing delegation and the second re-delegates. The authority was already delegated before the transaction, so the indicator slot was already paid for: neither authorization writes a net-new indicator and no AUTH_BASE is charged.
  • different_accounts: the two authorizations touch distinct authorities and are charged independently.

Consecutive authorizations on one authority use consecutive nonces (the first bumps the nonce), and the post-state confirms both were applied rather than the second being silently skipped.

Source code in tests/amsterdam/eip2780_reduce_intrinsic_tx_gas/test_authorization_charges.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
@pytest.mark.parametrize(
    "scenario",
    [
        "set_then_modify",
        "create_then_modify",
        "clear_then_set",
        "different_accounts",
    ],
)
def test_multi_authorization_intra_tx_state(
    fork: Fork,
    pre: Alloc,
    state_test: StateTestFiller,
    scenario: str,
) -> None:
    """
    Two authorizations in one transaction, charged against the state
    each leaves for the next.

    ``set_delegation`` applies authorizations in list order and reads
    live state, so a second authorization on the same authority sees the
    code the first installed:

    - ``set_then_modify``: the first sets a fresh delegation on an empty
      EOA (paying ``AUTH_BASE``); the second re-points it. The authority
      now has code, so the second pays no ``AUTH_BASE``.
    - ``create_then_modify``: the first creates the authority and
      delegates it (``NEW_ACCOUNT`` + ``ACCOUNT_WRITE`` + ``AUTH_BASE``);
      the second re-points it and pays no further state charge.
    - ``clear_then_set``: the first clears an existing delegation and
      the second re-delegates. The authority was already delegated
      before the transaction, so the indicator slot was already paid
      for: neither authorization writes a net-new indicator and no
      ``AUTH_BASE`` is charged.
    - ``different_accounts``: the two authorizations touch distinct
      authorities and are charged independently.

    Consecutive authorizations on one authority use consecutive nonces
    (the first bumps the nonce), and the post-state confirms both were
    applied rather than the second being silently skipped.
    """
    sender = pre.fund_eoa()
    recipient = pre.deploy_contract(code=Op.STOP)

    if scenario == "different_accounts":
        first = build_authorization(pre, AuthorizationAction.CREATES_ACCOUNT)
        second = build_authorization(
            pre, AuthorizationAction.SETS_NEW_DELEGATION
        )
        authorization_list = [first.authorization, second.authorization]
        expected_authorities = {
            first.authority: first.applied_account,
            second.authority: second.applied_account,
        }
    else:
        first_action = {
            "set_then_modify": AuthorizationAction.SETS_NEW_DELEGATION,
            "create_then_modify": AuthorizationAction.CREATES_ACCOUNT,
            "clear_then_set": AuthorizationAction.CLEARS_DELEGATION,
        }[scenario]
        leg = build_authorization(pre, first_action)
        new_target = pre.deploy_contract(code=Op.STOP)

        # The second authorization runs on the same authority right
        # after the first, using the next nonce. The first already
        # wrote the authority's leaf (no second ``ACCOUNT_WRITE``) and
        # either set a delegation in this transaction or found one from
        # before it, so the re-point writes no net-new indicator and
        # pays no ``AUTH_BASE``.
        applied_nonce = int(leg.applied_account.nonce)
        second_auth = AuthorizationTuple(
            address=new_target,
            nonce=applied_nonce,
            signer=leg.authority,
            creates_account=False,
            writes_delegation=False,
            first_write=False,
        )
        authorization_list = [leg.authorization, second_auth]
        expected_authorities = {
            leg.authority: Account(
                nonce=applied_nonce + 1,
                balance=int(leg.applied_account.balance),
                code=Spec7702.delegation_designation(new_target),
            ),
        }

    total_gas_cost = authorization_transaction_cost(fork, authorization_list)

    tx = Transaction(
        sender=sender,
        to=recipient,
        value=0,
        authorization_list=authorization_list,
        gas_limit=total_gas_cost,
        expected_receipt=TransactionReceipt(
            cumulative_gas_used=total_gas_cost,
        ),
    )

    post = {
        **expected_authorities,
    }

    state_test(pre=pre, tx=tx, post=post)

Parametrized Test Cases

This test generates 4 parametrized test cases across 1 fork.