35
35
if TYPE_CHECKING :
36
36
from collections .abc import Iterable
37
37
from pathlib import Path
38
- from typing import Final
38
+ from typing import Callable , Final , Tuple
39
39
40
40
from pyk .cterm import CTermSymbolic
41
41
from pyk .kast .inner import KAst , Subst
53
53
class KEVMSemantics (DefaultSemantics ):
54
54
auto_abstract_gas : bool
55
55
allow_symbolic_program : bool
56
- _cached_subst : Subst | None
56
+ _custom_step_definitions : Tuple [ Tuple [ KSequence , Callable [[ Subst , CTerm , CTermSymbolic ], KCFGExtendResult | None ]],...]
57
57
58
58
def __init__ (self , auto_abstract_gas : bool = False , allow_symbolic_program : bool = False ) -> None :
59
59
self .auto_abstract_gas = auto_abstract_gas
60
60
self .allow_symbolic_program = allow_symbolic_program
61
- self ._cached_subst = None
61
+ self ._custom_step_definitions = (( self . _load_pattern , self . _exec_load_custom_step ),)
62
62
63
63
@staticmethod
64
64
def is_functional (term : KInner ) -> bool :
@@ -145,11 +145,12 @@ def _replace(term: KInner) -> KInner:
145
145
146
146
return CTerm (config = bottom_up (_replace , cterm .config ), constraints = cterm .constraints )
147
147
148
- def custom_step (self , cterm : CTerm , _cterm_symbolic : CTermSymbolic ) -> KCFGExtendResult | None :
149
- if self ._check_load_pattern (cterm ):
150
- return self ._exec_load_custom_step (cterm )
151
- else :
152
- return None
148
+ def custom_step (self , cterm : CTerm , cterm_symbolic : CTermSymbolic ) -> KCFGExtendResult | None :
149
+ for abstract_pattern , custom_step_fn in self ._custom_step_definitions :
150
+ subst = abstract_pattern .match (cterm .cell ('K_CELL' ))
151
+ if subst is not None :
152
+ return custom_step_fn (subst , cterm , cterm_symbolic )
153
+ return None
153
154
154
155
@staticmethod
155
156
def cut_point_rules (
@@ -197,26 +198,16 @@ def terminal_rules(break_every_step: bool) -> list[str]:
197
198
terminal_rules .append ('EVM.step' )
198
199
return terminal_rules
199
200
200
- def _check_load_pattern (self , cterm : CTerm ) -> bool :
201
- """Given a CTerm, check if the rule 'EVM.program.load' is at the top of the K_CELL.
202
-
203
- This method checks if the `EVM.program.load` rule is at the top of the `K_CELL` in the given `cterm`.
204
- If the rule matches, the resulting substitution is cached in `_cached_subst` for later use in `custom_step`
205
- :param cterm: The CTerm representing the current state of the proof node.
206
- :return: `True` if the pattern matches and a custom step can be made; `False` otherwise.
207
- """
208
- load_pattern = KSequence ([KApply ('loadProgram' , KVariable ('###BYTECODE' )), KVariable ('###CONTINUATION' )])
209
- self ._cached_subst = load_pattern .match (cterm .cell ('K_CELL' ))
210
- return self ._cached_subst is not None
201
+ @property
202
+ def _load_pattern (self ) -> KSequence :
203
+ return KSequence ([KApply ('loadProgram' , KVariable ('###BYTECODE' )), KVariable ('###CONTINUATION' )])
211
204
212
- def _exec_load_custom_step (self , cterm : CTerm ) -> KCFGExtendResult :
205
+ def _exec_load_custom_step (self , subst : Subst , cterm : CTerm , _c : CTermSymbolic ) -> KCFGExtendResult :
213
206
"""Given a CTerm, update the JUMPDESTS_CELL and PROGRAM_CELL if the rule 'EVM.program.load' is at the top of the K_CELL.
214
207
215
208
:param cterm: CTerm of a proof node.
216
209
:return: If the K_CELL matches the load_pattern, a Step with depth 1 is returned together with the new configuration, also registering that the `EVM.program.load` rule has been applied.
217
210
"""
218
- subst = self ._cached_subst
219
- assert subst is not None
220
211
bytecode_sections = flatten_label ('_+Bytes__BYTES-HOOKED_Bytes_Bytes_Bytes' , subst ['###BYTECODE' ])
221
212
jumpdests_set = compute_jumpdests (bytecode_sections )
222
213
new_cterm = CTerm .from_kast (set_cell (cterm .kast , 'JUMPDESTS_CELL' , jumpdests_set ))
@@ -225,7 +216,10 @@ def _exec_load_custom_step(self, cterm: CTerm) -> KCFGExtendResult:
225
216
return Step (new_cterm , 1 , (), ['EVM.program.load' ], cut = True )
226
217
227
218
def can_make_custom_step (self , cterm : CTerm ) -> bool :
228
- return self ._check_load_pattern (cterm )
219
+ return any (
220
+ abstract_pattern .match (cterm .cell ('K_CELL' )) is not None
221
+ for abstract_pattern , _ in self ._custom_step_definitions
222
+ )
229
223
230
224
def is_mergeable (self , ct1 : CTerm , ct2 : CTerm ) -> bool :
231
225
"""Given two CTerms of Edges' targets, check if they are mergeable.
0 commit comments