|
92 | 92 | from execution_testing.test_types.execution_witness import ( |
93 | 93 | ExecutionWitnessCodesExpectation, |
94 | 94 | ExecutionWitnessHeadersExpectation, |
| 95 | + ExecutionWitnessStateExpectation, |
95 | 96 | ) |
96 | 97 |
|
97 | 98 | from .base import BaseTest, FillResult, OpMode, verify_result |
@@ -148,6 +149,71 @@ def count_blobs(txs: List[Transaction]) -> int: |
148 | 149 | ) |
149 | 150 |
|
150 | 151 |
|
| 152 | +def execution_witness_implicit_codes_for_block( |
| 153 | + *, |
| 154 | + fork: Fork, |
| 155 | + alloc: Alloc | LazyAlloc, |
| 156 | + block_number: int, |
| 157 | + timestamp: int, |
| 158 | +) -> List[Bytes]: |
| 159 | + """ |
| 160 | + Return ambient witness bytecodes implied by block-level execution. |
| 161 | +
|
| 162 | + These codes are resolved from the effective pre-state for the block, not |
| 163 | + from raw fork defaults, so test `pre` overrides are respected. |
| 164 | + """ |
| 165 | + active_fork = fork.fork_at(block_number=block_number, timestamp=timestamp) |
| 166 | + addresses = active_fork.execution_witness_implicit_code_addresses( |
| 167 | + block_number=block_number, |
| 168 | + timestamp=timestamp, |
| 169 | + ) |
| 170 | + if not addresses: |
| 171 | + return [] |
| 172 | + |
| 173 | + effective_alloc = alloc.get() if isinstance(alloc, LazyAlloc) else alloc |
| 174 | + |
| 175 | + codes: List[Bytes] = [] |
| 176 | + seen: set[Bytes] = set() |
| 177 | + for address in addresses: |
| 178 | + if address not in effective_alloc: |
| 179 | + continue |
| 180 | + account = effective_alloc[address] |
| 181 | + if account is None or len(account.code) == 0: |
| 182 | + continue |
| 183 | + code = Bytes(account.code) |
| 184 | + if code in seen: |
| 185 | + continue |
| 186 | + codes.append(code) |
| 187 | + seen.add(code) |
| 188 | + return codes |
| 189 | + |
| 190 | + |
| 191 | +def with_execution_witness_implicit_codes( |
| 192 | + *, |
| 193 | + expectation: ExecutionWitnessCodesExpectation, |
| 194 | + fork: Fork, |
| 195 | + alloc: Alloc | LazyAlloc, |
| 196 | + block_number: int, |
| 197 | + timestamp: int, |
| 198 | +) -> ExecutionWitnessCodesExpectation: |
| 199 | + """Return expectation copy with ambient block-level codes added.""" |
| 200 | + codes_present = list(expectation.codes_present) |
| 201 | + seen = set(codes_present) |
| 202 | + |
| 203 | + for code in execution_witness_implicit_codes_for_block( |
| 204 | + fork=fork, |
| 205 | + alloc=alloc, |
| 206 | + block_number=block_number, |
| 207 | + timestamp=timestamp, |
| 208 | + ): |
| 209 | + if code in seen: |
| 210 | + continue |
| 211 | + codes_present.append(code) |
| 212 | + seen.add(code) |
| 213 | + |
| 214 | + return expectation.model_copy(update={"codes_present": codes_present}) |
| 215 | + |
| 216 | + |
151 | 217 | class Header(CamelModel): |
152 | 218 | """Header type used to describe block header properties in test specs.""" |
153 | 219 |
|
@@ -283,6 +349,13 @@ class Block(Header): |
283 | 349 | If set, the execution witness codes will be verified and potentially |
284 | 350 | modified for invalid tests. |
285 | 351 | """ |
| 352 | + expected_execution_witness_state: ( |
| 353 | + ExecutionWitnessStateExpectation | None |
| 354 | + ) = None |
| 355 | + """ |
| 356 | + If set, the execution witness state will be verified and potentially |
| 357 | + modified for invalid tests. |
| 358 | + """ |
286 | 359 | expected_execution_witness_headers: ( |
287 | 360 | ExecutionWitnessHeadersExpectation | None |
288 | 361 | ) = None |
@@ -464,6 +537,9 @@ def get_fixture_block( |
464 | 537 | in self.expected_exception |
465 | 538 | else fixture_block.without_rlp() |
466 | 539 | ), |
| 540 | + execution_witness=self.execution_witness, |
| 541 | + stateless_input_bytes=self.stateless_input_bytes, |
| 542 | + stateless_output_bytes=self.stateless_output_bytes, |
467 | 543 | ) |
468 | 544 |
|
469 | 545 | return fixture_block |
@@ -830,17 +906,33 @@ def generate_block_data( |
830 | 906 | # update the header hash |
831 | 907 | header.block_access_list_hash = Hash(bal.rlp.keccak256()) |
832 | 908 |
|
833 | | - # If expected witness codes defined, verify against actual |
| 909 | + # If expected witness state/codes defined, verify against actual |
834 | 910 | t8n_witness = transition_tool_output.result.execution_witness |
835 | 911 | execution_witness = t8n_witness |
| 912 | + state_expectation = block.expected_execution_witness_state |
| 913 | + if state_expectation is not None and execution_witness is not None: |
| 914 | + state_expectation.verify_against(execution_witness) |
| 915 | + execution_witness = state_expectation.modify_if_invalid_test( |
| 916 | + execution_witness |
| 917 | + ) |
| 918 | + |
836 | 919 | if ( |
837 | 920 | block.expected_execution_witness_codes is not None |
838 | | - and t8n_witness is not None |
| 921 | + and execution_witness is not None |
839 | 922 | ): |
840 | | - block.expected_execution_witness_codes.verify_against(t8n_witness) |
| 923 | + effective_codes_expectation = ( |
| 924 | + with_execution_witness_implicit_codes( |
| 925 | + expectation=block.expected_execution_witness_codes, |
| 926 | + fork=self.fork, |
| 927 | + alloc=previous_alloc, |
| 928 | + block_number=env.number, |
| 929 | + timestamp=env.timestamp, |
| 930 | + ) |
| 931 | + ) |
| 932 | + effective_codes_expectation.verify_against(execution_witness) |
841 | 933 | execution_witness = ( |
842 | 934 | block.expected_execution_witness_codes.modify_if_invalid_test( |
843 | | - t8n_witness |
| 935 | + execution_witness |
844 | 936 | ) |
845 | 937 | ) |
846 | 938 |
|
@@ -892,6 +984,11 @@ def generate_block_data( |
892 | 984 | block.expected_block_access_list is not None |
893 | 985 | and block.expected_block_access_list._modifier is not None |
894 | 986 | ) |
| 987 | + and not ( |
| 988 | + block.expected_execution_witness_state is not None |
| 989 | + and block.expected_execution_witness_state._modifier |
| 990 | + is not None |
| 991 | + ) |
895 | 992 | and not ( |
896 | 993 | block.expected_execution_witness_codes is not None |
897 | 994 | and block.expected_execution_witness_codes._modifier |
|
0 commit comments