From ce79c6c9fa83e7e9abac67e41459bc888032fa80 Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Tue, 3 Dec 2024 11:55:47 +0200
Subject: [PATCH 01/17] draft FOUNDRYSemantics
---
src/kontrol/foundry.py | 87 +++++++++++++++++++++++++++++----
src/kontrol/kdist/cheatcodes.md | 21 ++++++++
src/kontrol/kdist/foundry.md | 4 ++
src/kontrol/prove.py | 14 ++++--
4 files changed, 111 insertions(+), 15 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index a690ea6fd..3c37df2a8 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -17,13 +17,22 @@
from typing import TYPE_CHECKING
import tomlkit
-from kevm_pyk.kevm import KEVM, KEVMNodePrinter, KEVMSemantics
+from kevm_pyk.kevm import KEVM, KEVMNodePrinter, KEVMSemantics, compute_jumpdests
from kevm_pyk.utils import byte_offset_to_lines, legacy_explore, print_failure_info, print_model
from pyk.cterm import CTerm
-from pyk.kast.inner import KApply, KInner, KSort, KToken, KVariable
-from pyk.kast.manip import cell_label_to_var_name, collect, extract_lhs, flatten_label, minimize_term, top_down
+from pyk.kast.inner import KApply, KInner, KSequence, KSort, KToken, KVariable
+from pyk.kast.manip import (
+ cell_label_to_var_name,
+ collect,
+ extract_lhs,
+ flatten_label,
+ minimize_term,
+ set_cell,
+ top_down,
+)
from pyk.kast.outer import KDefinition, KFlatModule, KImport, KRequire
from pyk.kcfg import KCFG
+from pyk.kcfg.kcfg import Step
from pyk.kcfg.minimize import KCFGMinimizer
from pyk.prelude.bytes import bytesToken
from pyk.prelude.collections import map_empty
@@ -57,6 +66,7 @@
from pyk.kast.outer import KAst
from pyk.kcfg.kcfg import NodeIdLike
+ from pyk.kcfg.semantics import KCFGExtendResult
from pyk.kcfg.tui import KCFGElem
from pyk.proof.implies import RefutationProof
from pyk.proof.show import NodePrinter
@@ -82,6 +92,63 @@
_LOGGER: Final = logging.getLogger(__name__)
+class FOUNDRYSemantics(KEVMSemantics):
+ def _check_load_pattern(self, cterm: CTerm) -> bool:
+ """Given a CTerm, check if the rule 'EVM.program.load' is at the top of the K_CELL.
+
+ This method checks if the `EVM.program.load` rule is at the top of the `K_CELL` in the given `cterm`.
+ If the rule matches, the resulting substitution is cached in `_cached_subst` for later use in `custom_step`
+ :param cterm: The CTerm representing the current state of the proof node.
+ :return: `True` if the pattern matches and a custom step can be made; `False` otherwise.
+ """
+ load_pattern = KSequence([KApply('loadProgram', KVariable('###BYTECODE')), KVariable('###CONTINUATION')])
+ self._cached_subst = load_pattern.match(cterm.cell('K_CELL'))
+ return self._cached_subst is not None
+
+ def _check_abstract_pattern(self, cterm: CTerm) -> bool:
+ """Given a CTerm, check if the rule 'FOUNDRY.abstract' is at the top of the K_CELL.
+
+ This method checks if the `FOUNDRY.abstract` rule is at the top of the `K_CELL` in the given `cterm`.
+ If the rule matches, the resulting substitution is cached in `_cached_subst` for later use in `custom_step`
+ :param cterm: The CTerm representing the current state of the proof node.
+ :return: `True` if the pattern matches and a custom step can be made; `False` otherwise.
+ """
+ abstract_pattern = KSequence(
+ [
+ KApply('cheatcode_abstract', [KVariable('###CONDITION1'), KVariable('###CONDITION2')]),
+ KVariable('###CONTINUATION'),
+ ]
+ )
+ self._cached_subst = abstract_pattern.match(cterm.cell('K_CELL'))
+ print('CHECKING ABSTRACT PATTERN')
+ return self._cached_subst is not None
+
+ def custom_step(self, cterm: CTerm) -> KCFGExtendResult | None:
+ """Given a CTerm, update the JUMPDESTS_CELL and PROGRAM_CELL if the rule 'EVM.program.load' is at the top of the K_CELL.
+
+ :param cterm: CTerm of a proof node.
+ :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. Otherwise, None is returned.
+ """
+ if self._check_load_pattern(cterm):
+ subst = self._cached_subst
+ assert subst is not None
+ bytecode_sections = flatten_label('_+Bytes__BYTES-HOOKED_Bytes_Bytes_Bytes', subst['###BYTECODE'])
+ jumpdests_set = compute_jumpdests(bytecode_sections)
+ new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'JUMPDESTS_CELL', jumpdests_set))
+ new_cterm = CTerm.from_kast(set_cell(new_cterm.kast, 'PROGRAM_CELL', subst['###BYTECODE']))
+ new_cterm = CTerm.from_kast(set_cell(new_cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
+ return Step(new_cterm, 1, (), ['EVM.program.load'], cut=True)
+ elif self._check_abstract_pattern(cterm):
+ print('ABSTRACT PATTERN CONFIRMED')
+ subst = self._cached_subst
+ assert subst is not None
+ fst_condition = subst['###CONDITION1']
+ snd_condition = subst['###CONDITION2']
+ print('fst', fst_condition)
+ print('snd', snd_condition)
+ return None
+
+
class FoundryKEVM(KEVM):
foundry: Foundry
@@ -841,7 +908,7 @@ def foundry_show(
if options.failure_info:
with legacy_explore(
foundry.kevm,
- kcfg_semantics=KEVMSemantics(),
+ kcfg_semantics=FOUNDRYSemantics(),
id=test_id,
smt_timeout=options.smt_timeout,
smt_retry_limit=options.smt_retry_limit,
@@ -908,7 +975,7 @@ def _collect_klabel(_k: KInner) -> None:
]
sentences = [sent for sent in sentences if not _contains_foundry_klabel(sent.body)]
sentences = [
- sent for sent in sentences if not KEVMSemantics().is_terminal(CTerm.from_kast(extract_lhs(sent.body)))
+ sent for sent in sentences if not FOUNDRYSemantics().is_terminal(CTerm.from_kast(extract_lhs(sent.body)))
]
if len(sentences) == 0:
_LOGGER.warning(f'No claims or rules retained for proof {proof.id}')
@@ -1098,7 +1165,7 @@ def foundry_simplify_node(
with legacy_explore(
foundry.kevm,
- kcfg_semantics=KEVMSemantics(),
+ kcfg_semantics=FOUNDRYSemantics(),
id=apr_proof.id,
bug_report=options.bug_report,
kore_rpc_command=kore_rpc_command,
@@ -1146,7 +1213,7 @@ def check_cells_equal(cell: str, nodes: Iterable[KCFG.Node]) -> bool:
check_cells_ne = [check_cell for check_cell in check_cells if not check_cells_equal(check_cell, nodes)]
if check_cells_ne:
- if not all(KEVMSemantics().same_loop(nodes[0].cterm, nd.cterm) for nd in nodes):
+ if not all(FOUNDRYSemantics().same_loop(nodes[0].cterm, nd.cterm) for nd in nodes):
raise ValueError(f'Nodes {options.nodes} cannot be merged because they differ in: {check_cells_ne}')
anti_unification = nodes[0].cterm
@@ -1186,7 +1253,7 @@ def foundry_step_node(
with legacy_explore(
foundry.kevm,
- kcfg_semantics=KEVMSemantics(),
+ kcfg_semantics=FOUNDRYSemantics(),
id=apr_proof.id,
bug_report=options.bug_report,
kore_rpc_command=kore_rpc_command,
@@ -1262,7 +1329,7 @@ def foundry_section_edge(
with legacy_explore(
foundry.kevm,
- kcfg_semantics=KEVMSemantics(),
+ kcfg_semantics=FOUNDRYSemantics(),
id=apr_proof.id,
bug_report=options.bug_report,
kore_rpc_command=kore_rpc_command,
@@ -1313,7 +1380,7 @@ def foundry_get_model(
with legacy_explore(
foundry.kevm,
- kcfg_semantics=KEVMSemantics(),
+ kcfg_semantics=FOUNDRYSemantics(),
id=proof.id,
bug_report=options.bug_report,
kore_rpc_command=kore_rpc_command,
diff --git a/src/kontrol/kdist/cheatcodes.md b/src/kontrol/kdist/cheatcodes.md
index 35892fc00..6ce0672f8 100644
--- a/src/kontrol/kdist/cheatcodes.md
+++ b/src/kontrol/kdist/cheatcodes.md
@@ -1106,6 +1106,25 @@ Mock functions
[priority(30)]
```
+
+Abstraction functions
+---------------------
+
+#### `abstract` - replaces the first condition in the current constraints with the second one provided.
+
+```
+ function abstract(bool cond1, bool cond2) external;
+```
+
+```k
+ rule [cheatcode.call.abstract]:
+ #cheatcode_call SELECTOR ARGS
+ => #abstract ( #range(ARGS,0,32), #range(ARGS,32,32))
+ ...
+
+ requires SELECTOR ==Int selector ( "replace_constraint(bool,bool)" )
+```
+
Utils
-----
@@ -1691,6 +1710,8 @@ Selectors for **implemented** cheat code functions.
rule ( selector ( "mockCall(address,bytes,bytes)" ) => 3110212580 )
rule ( selector ( "mockFunction(address,address,bytes)" ) => 2918731041 )
rule ( selector ( "copyStorage(address,address)" ) => 540912653 )
+ rule ( selector ( "replace_constraint(bool,bool)" ) => 1408652492 )
+ rule ( selector ( "forget(bool)" ) => 589442177 )
```
Selectors for **unimplemented** cheat code functions.
diff --git a/src/kontrol/kdist/foundry.md b/src/kontrol/kdist/foundry.md
index 2ac8861a7..740eb6a34 100644
--- a/src/kontrol/kdist/foundry.md
+++ b/src/kontrol/kdist/foundry.md
@@ -78,6 +78,10 @@ Then, we define helpers in K which can:
STORAGE => STORAGE [ #loc(FoundryCheat . Failed) <- 1 ]
...
+
+ syntax KItem ::= #abstract ( Bytes , Bytes ) [symbol(cheatcode_abstract)]
+ // -----------------------------------------------------------------------
+ rule [abstract]: #abstract(_C1, _C2) => .K ...
```
#### Structure of execution
diff --git a/src/kontrol/prove.py b/src/kontrol/prove.py
index 3f0446730..109ab4774 100644
--- a/src/kontrol/prove.py
+++ b/src/kontrol/prove.py
@@ -11,7 +11,7 @@
from typing import TYPE_CHECKING, Any, ContextManager, NamedTuple
from kevm_pyk.cli import EVMChainOptions
-from kevm_pyk.kevm import KEVM, KEVMSemantics, _process_jumpdests
+from kevm_pyk.kevm import KEVM, _process_jumpdests
from kevm_pyk.utils import KDefinition__expand_macros, abstract_cell_vars, run_prover
from multiprocess.pool import Pool # type: ignore
from pyk.cterm import CTerm, CTermSymbolic
@@ -35,7 +35,7 @@
from pyk.utils import hash_str, run_process_2, single, unique
from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn, TimeElapsedColumn
-from .foundry import Foundry, foundry_to_xml
+from .foundry import Foundry, FOUNDRYSemantics, foundry_to_xml
from .hevm import Hevm
from .options import ConfigType, TraceOptions
from .solc_to_k import Contract, hex_string_to_int
@@ -381,7 +381,7 @@ def create_kcfg_explore() -> KCFGExplore:
)
return KCFGExplore(
cterm_symbolic,
- kcfg_semantics=KEVMSemantics(auto_abstract_gas=options.auto_abstract_gas),
+ kcfg_semantics=FOUNDRYSemantics(auto_abstract_gas=options.auto_abstract_gas),
id=test.id,
)
@@ -425,7 +425,7 @@ def create_kcfg_explore() -> KCFGExplore:
}
),
)
- cut_point_rules = KEVMSemantics.cut_point_rules(
+ cut_point_rules = FOUNDRYSemantics.cut_point_rules(
options.break_on_jumpi,
options.break_on_jump,
options.break_on_calls,
@@ -441,6 +441,10 @@ def create_kcfg_explore() -> KCFGExplore:
rule.label for rule in foundry.kevm.definition.all_modules_dict['KONTROL-ASSERTIONS'].rules
)
+ cut_point_rules.append('FOUNDRY-ACCOUNTS.abstract')
+ print('CUT POINT RULES')
+ print(cut_point_rules)
+
extra_lemmas_module: KFlatModule | None = None
if options.extra_module:
extra_module_file, extra_module_name, *_ = options.extra_module.split(':')
@@ -465,7 +469,7 @@ def create_kcfg_explore() -> KCFGExplore:
max_depth=options.max_depth,
max_iterations=options.max_iterations,
cut_point_rules=cut_point_rules,
- terminal_rules=KEVMSemantics.terminal_rules(options.break_every_step),
+ terminal_rules=FOUNDRYSemantics.terminal_rules(options.break_every_step),
counterexample_info=options.counterexample_info,
max_frontier_parallel=options.max_frontier_parallel,
fail_fast=options.fail_fast,
From d2c69f40cd4c38dc5eada05ef01ad2755fa990ac Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Tue, 3 Dec 2024 14:06:56 +0200
Subject: [PATCH 02/17] forgetBranch
---
src/kontrol/foundry.py | 35 ++++++++++++++++++++++-----------
src/kontrol/kdist/cheatcodes.md | 13 ++++++------
src/kontrol/kdist/foundry.md | 4 ++--
src/kontrol/prove.py | 2 +-
4 files changed, 34 insertions(+), 20 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 3c37df2a8..9bbaff38c 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -105,22 +105,22 @@ def _check_load_pattern(self, cterm: CTerm) -> bool:
self._cached_subst = load_pattern.match(cterm.cell('K_CELL'))
return self._cached_subst is not None
- def _check_abstract_pattern(self, cterm: CTerm) -> bool:
- """Given a CTerm, check if the rule 'FOUNDRY.abstract' is at the top of the K_CELL.
+ def _check_forget_pattern(self, cterm: CTerm) -> bool:
+ """Given a CTerm, check if the rule 'FOUNDRY-ACCOUNTS.forget' is at the top of the K_CELL.
- This method checks if the `FOUNDRY.abstract` rule is at the top of the `K_CELL` in the given `cterm`.
+ This method checks if the 'FOUNDRY-ACCOUNTS.forget' rule is at the top of the `K_CELL` in the given `cterm`.
If the rule matches, the resulting substitution is cached in `_cached_subst` for later use in `custom_step`
:param cterm: The CTerm representing the current state of the proof node.
:return: `True` if the pattern matches and a custom step can be made; `False` otherwise.
"""
abstract_pattern = KSequence(
[
- KApply('cheatcode_abstract', [KVariable('###CONDITION1'), KVariable('###CONDITION2')]),
+ KApply('cheatcode_forget', [KVariable('###TERM1'), KVariable('###OPERATOR'), KVariable('###TERM2')]),
KVariable('###CONTINUATION'),
]
)
self._cached_subst = abstract_pattern.match(cterm.cell('K_CELL'))
- print('CHECKING ABSTRACT PATTERN')
+ print('CHECKING FORGET PATTERN')
return self._cached_subst is not None
def custom_step(self, cterm: CTerm) -> KCFGExtendResult | None:
@@ -138,14 +138,27 @@ def custom_step(self, cterm: CTerm) -> KCFGExtendResult | None:
new_cterm = CTerm.from_kast(set_cell(new_cterm.kast, 'PROGRAM_CELL', subst['###BYTECODE']))
new_cterm = CTerm.from_kast(set_cell(new_cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
return Step(new_cterm, 1, (), ['EVM.program.load'], cut=True)
- elif self._check_abstract_pattern(cterm):
- print('ABSTRACT PATTERN CONFIRMED')
+
+ elif self._check_forget_pattern(cterm):
+ _operators = ['_==Int_','_!=Int_', '_<=Int_', '_=Int_', '_>Int_']
+ print('FORGET PATTERN CONFIRMED')
subst = self._cached_subst
assert subst is not None
- fst_condition = subst['###CONDITION1']
- snd_condition = subst['###CONDITION2']
- print('fst', fst_condition)
- print('snd', snd_condition)
+ fst_term = subst['###TERM1']
+ snd_term = subst['###TERM2']
+ operator = subst['###OPERATOR']
+ print('fst', fst_term)
+ print('snd', snd_term)
+ print('operator', operator)
+ assert type(operator) is KToken
+ eq = KApply(_operators[int(operator.token)],fst_term, snd_term)
+ print('kapply',eq)
+ print('cterms', cterm.constraints)
+ print(eq in cterm.constraints)
+ new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
+ new_constraints = ( c for c in cterm.constraints if c is not eq )
+ return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
+
return None
diff --git a/src/kontrol/kdist/cheatcodes.md b/src/kontrol/kdist/cheatcodes.md
index 6ce0672f8..9259dda7a 100644
--- a/src/kontrol/kdist/cheatcodes.md
+++ b/src/kontrol/kdist/cheatcodes.md
@@ -1110,19 +1110,20 @@ Mock functions
Abstraction functions
---------------------
-#### `abstract` - replaces the first condition in the current constraints with the second one provided.
+#### `forgetBranch` - removes a given path constraint.
```
- function abstract(bool cond1, bool cond2) external;
+ function forgetBranch(uint256 op1, ComparisonOperator op, uint256 op2) external;
```
```k
rule [cheatcode.call.abstract]:
#cheatcode_call SELECTOR ARGS
- => #abstract ( #range(ARGS,0,32), #range(ARGS,32,32))
+ => #forget ( #asWord(#range(ARGS,0,32)), #asWord(#range(ARGS,32,32)), #asWord(#range(ARGS,64,32)))
...
- requires SELECTOR ==Int selector ( "replace_constraint(bool,bool)" )
+ requires SELECTOR ==Int selector ( "forgetBranch(uint256,uint8,uint256)" )
+
```
Utils
@@ -1710,8 +1711,8 @@ Selectors for **implemented** cheat code functions.
rule ( selector ( "mockCall(address,bytes,bytes)" ) => 3110212580 )
rule ( selector ( "mockFunction(address,address,bytes)" ) => 2918731041 )
rule ( selector ( "copyStorage(address,address)" ) => 540912653 )
- rule ( selector ( "replace_constraint(bool,bool)" ) => 1408652492 )
- rule ( selector ( "forget(bool)" ) => 589442177 )
+ rule ( selector ( "replaceConstraint(uint256,uint8,uint256,bool)" ) => 1408652492 )
+ rule ( selector ( "forgetBranch(uint256,uint8,uint256)" ) => 1720990067 )
```
Selectors for **unimplemented** cheat code functions.
diff --git a/src/kontrol/kdist/foundry.md b/src/kontrol/kdist/foundry.md
index 740eb6a34..871f0dd18 100644
--- a/src/kontrol/kdist/foundry.md
+++ b/src/kontrol/kdist/foundry.md
@@ -79,9 +79,9 @@ Then, we define helpers in K which can:
...
- syntax KItem ::= #abstract ( Bytes , Bytes ) [symbol(cheatcode_abstract)]
+ syntax KItem ::= #forget ( Int , Int , Int ) [symbol(cheatcode_forget)]
// -----------------------------------------------------------------------
- rule [abstract]: #abstract(_C1, _C2) => .K ...
+ rule [forget]: #forget(_C1,_OP,_C2) => .K ...
```
#### Structure of execution
diff --git a/src/kontrol/prove.py b/src/kontrol/prove.py
index 109ab4774..bf4708efe 100644
--- a/src/kontrol/prove.py
+++ b/src/kontrol/prove.py
@@ -441,7 +441,7 @@ def create_kcfg_explore() -> KCFGExplore:
rule.label for rule in foundry.kevm.definition.all_modules_dict['KONTROL-ASSERTIONS'].rules
)
- cut_point_rules.append('FOUNDRY-ACCOUNTS.abstract')
+ cut_point_rules.append('FOUNDRY-ACCOUNTS.forget')
print('CUT POINT RULES')
print(cut_point_rules)
From 5784068d8dd2ecc8920169d13eba3267bd7483a6 Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Tue, 3 Dec 2024 14:12:15 +0200
Subject: [PATCH 03/17] add mlEqualsTrue
---
src/kontrol/foundry.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 9bbaff38c..6a5cf1413 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -151,7 +151,7 @@ def custom_step(self, cterm: CTerm) -> KCFGExtendResult | None:
print('snd', snd_term)
print('operator', operator)
assert type(operator) is KToken
- eq = KApply(_operators[int(operator.token)],fst_term, snd_term)
+ eq = mlEqualsTrue( KApply(_operators[int(operator.token)],fst_term, snd_term))
print('kapply',eq)
print('cterms', cterm.constraints)
print(eq in cterm.constraints)
From 190c61d1c9eb890d431ed4ce64a6d31eb30ff544 Mon Sep 17 00:00:00 2001
From: Petar Maksimovic
Date: Tue, 3 Dec 2024 15:36:32 +0000
Subject: [PATCH 04/17] minor corrections
---
src/kontrol/foundry.py | 21 ++++++++++---------
.../test-data/foundry/test/ForgetBranch.t.sol | 20 ++++++++++++++++++
2 files changed, 31 insertions(+), 10 deletions(-)
create mode 100644 src/tests/integration/test-data/foundry/test/ForgetBranch.t.sol
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 6a5cf1413..d61650fa1 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -140,23 +140,24 @@ def custom_step(self, cterm: CTerm) -> KCFGExtendResult | None:
return Step(new_cterm, 1, (), ['EVM.program.load'], cut=True)
elif self._check_forget_pattern(cterm):
- _operators = ['_==Int_','_!=Int_', '_<=Int_', '_=Int_', '_>Int_']
- print('FORGET PATTERN CONFIRMED')
+ _operators = ['_==Int_', '_<=Int_', '_=Int_', '_>Int_']
+ print('Custom step: Forget pattern confirmed')
subst = self._cached_subst
assert subst is not None
fst_term = subst['###TERM1']
snd_term = subst['###TERM2']
operator = subst['###OPERATOR']
- print('fst', fst_term)
- print('snd', snd_term)
- print('operator', operator)
+ print('LHS:', fst_term)
+ print('Operator:', operator)
+ print('RHS:', snd_term)
assert type(operator) is KToken
- eq = mlEqualsTrue( KApply(_operators[int(operator.token)],fst_term, snd_term))
- print('kapply',eq)
- print('cterms', cterm.constraints)
- print(eq in cterm.constraints)
+ eq = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
+ print('Constraint to forget:', eq)
+ print(f'Current constraints:\n{cterm.constraints}')
+ print(f'Constraint to forget found: {eq in cterm.constraints}')
new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
- new_constraints = ( c for c in cterm.constraints if c is not eq )
+ new_constraints: tuple[KInner, ...] = tuple(c for c in cterm.constraints if c != eq)
+ print(f'New constraints:\n{new_constraints}')
return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
return None
diff --git a/src/tests/integration/test-data/foundry/test/ForgetBranch.t.sol b/src/tests/integration/test-data/foundry/test/ForgetBranch.t.sol
new file mode 100644
index 000000000..53ac90f3e
--- /dev/null
+++ b/src/tests/integration/test-data/foundry/test/ForgetBranch.t.sol
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity >=0.8.13;
+
+import "forge-std/Test.sol";
+import "kontrol-cheatcodes/KontrolCheats.sol";
+
+contract ForgetBranchTest is Test, KontrolCheats {
+
+ function test_forgetBranch(uint256 x) public {
+ uint256 y;
+
+ vm.assume(x > 200);
+ kevm.forgetBranch(200, 2, x);
+ if(x > 200){
+ y = 21;
+ } else {
+ y = 42;
+ }
+ }
+}
\ No newline at end of file
From adb8a704a9f8127b55c8c494abfe6603aa937fcf Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Wed, 4 Dec 2024 14:43:50 +0200
Subject: [PATCH 05/17] add simplification step
---
src/kontrol/foundry.py | 82 ++++++++++++++++++------------------------
1 file changed, 34 insertions(+), 48 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index d61650fa1..abc67251d 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -17,7 +17,7 @@
from typing import TYPE_CHECKING
import tomlkit
-from kevm_pyk.kevm import KEVM, KEVMNodePrinter, KEVMSemantics, compute_jumpdests
+from kevm_pyk.kevm import KEVM, KEVMNodePrinter, KEVMSemantics
from kevm_pyk.utils import byte_offset_to_lines, legacy_explore, print_failure_info, print_model
from pyk.cterm import CTerm
from pyk.kast.inner import KApply, KInner, KSequence, KSort, KToken, KVariable
@@ -34,9 +34,10 @@
from pyk.kcfg import KCFG
from pyk.kcfg.kcfg import Step
from pyk.kcfg.minimize import KCFGMinimizer
+from pyk.kdist import kdist
from pyk.prelude.bytes import bytesToken
from pyk.prelude.collections import map_empty
-from pyk.prelude.k import DOTS
+from pyk.prelude.k import DOTS, GENERATED_TOP_CELL
from pyk.prelude.kbool import notBool
from pyk.prelude.kint import INT, intToken
from pyk.prelude.ml import mlEqualsFalse, mlEqualsTrue
@@ -64,6 +65,7 @@
from collections.abc import Iterable
from typing import Any, Final
+ from pyk.cterm import CTermSymbolic
from pyk.kast.outer import KAst
from pyk.kcfg.kcfg import NodeIdLike
from pyk.kcfg.semantics import KCFGExtendResult
@@ -93,17 +95,6 @@
class FOUNDRYSemantics(KEVMSemantics):
- def _check_load_pattern(self, cterm: CTerm) -> bool:
- """Given a CTerm, check if the rule 'EVM.program.load' is at the top of the K_CELL.
-
- This method checks if the `EVM.program.load` rule is at the top of the `K_CELL` in the given `cterm`.
- If the rule matches, the resulting substitution is cached in `_cached_subst` for later use in `custom_step`
- :param cterm: The CTerm representing the current state of the proof node.
- :return: `True` if the pattern matches and a custom step can be made; `False` otherwise.
- """
- load_pattern = KSequence([KApply('loadProgram', KVariable('###BYTECODE')), KVariable('###CONTINUATION')])
- self._cached_subst = load_pattern.match(cterm.cell('K_CELL'))
- return self._cached_subst is not None
def _check_forget_pattern(self, cterm: CTerm) -> bool:
"""Given a CTerm, check if the rule 'FOUNDRY-ACCOUNTS.forget' is at the top of the K_CELL.
@@ -120,47 +111,42 @@ def _check_forget_pattern(self, cterm: CTerm) -> bool:
]
)
self._cached_subst = abstract_pattern.match(cterm.cell('K_CELL'))
- print('CHECKING FORGET PATTERN')
return self._cached_subst is not None
- def custom_step(self, cterm: CTerm) -> KCFGExtendResult | None:
- """Given a CTerm, update the JUMPDESTS_CELL and PROGRAM_CELL if the rule 'EVM.program.load' is at the top of the K_CELL.
+ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic) -> KCFGExtendResult:
+ """Given a CTerm, remove the constraint that's placed at the top of the K_CELL in the 'FOUNDRY-ACCOUNTS.forget' cut-rule.
:param cterm: CTerm of a proof node.
- :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. Otherwise, None is returned.
+ :cterm_symbolic: CTermSymbolic instance
+ :return: If the K_CELL matches the forget_pattern, a Step with depth 1 is returned together with the new configuration, also registering that the `FOUNDRY-ACCOUNTS.forget` rule has been applied.
"""
- if self._check_load_pattern(cterm):
- subst = self._cached_subst
- assert subst is not None
- bytecode_sections = flatten_label('_+Bytes__BYTES-HOOKED_Bytes_Bytes_Bytes', subst['###BYTECODE'])
- jumpdests_set = compute_jumpdests(bytecode_sections)
- new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'JUMPDESTS_CELL', jumpdests_set))
- new_cterm = CTerm.from_kast(set_cell(new_cterm.kast, 'PROGRAM_CELL', subst['###BYTECODE']))
- new_cterm = CTerm.from_kast(set_cell(new_cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
- return Step(new_cterm, 1, (), ['EVM.program.load'], cut=True)
-
- elif self._check_forget_pattern(cterm):
- _operators = ['_==Int_', '_<=Int_', '_=Int_', '_>Int_']
- print('Custom step: Forget pattern confirmed')
- subst = self._cached_subst
- assert subst is not None
- fst_term = subst['###TERM1']
- snd_term = subst['###TERM2']
- operator = subst['###OPERATOR']
- print('LHS:', fst_term)
- print('Operator:', operator)
- print('RHS:', snd_term)
- assert type(operator) is KToken
- eq = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
- print('Constraint to forget:', eq)
- print(f'Current constraints:\n{cterm.constraints}')
- print(f'Constraint to forget found: {eq in cterm.constraints}')
- new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
- new_constraints: tuple[KInner, ...] = tuple(c for c in cterm.constraints if c != eq)
- print(f'New constraints:\n{new_constraints}')
- return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
+ _operators = ['_==Int_', '_<=Int_', '_=Int_', '_>Int_']
+ _LOGGER.info('Custom step: Forget pattern confirmed')
+ subst = self._cached_subst
+ assert subst is not None
+ fst_term = subst['###TERM1']
+ snd_term = subst['###TERM2']
+ operator = subst['###OPERATOR']
+ assert type(operator) is KToken
+ eq = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
+ kevm = KEVM(kdist.get('kontrol.foundry'))
+ empty_config = kevm.definition.empty_config(GENERATED_TOP_CELL)
+ simplification_cterm = CTerm.from_kast(empty_config).add_constraint(eq)
+ result_cterm, _ = cterm_symbolic.simplify(simplification_cterm)
+ target_constraint = single(result_cterm.constraints)
+ new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
+ new_constraints: tuple[KInner, ...] = tuple(c for c in cterm.constraints if c != target_constraint)
+ _LOGGER.info(f'Custom step: removing constraint: {target_constraint}')
+ return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
+
+ def custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic) -> KCFGExtendResult | None:
+ if self._check_forget_pattern(cterm):
+ return self._exec_forget_custom_step(cterm, cterm_symbolic)
+ else:
+ return super().custom_step(cterm, cterm_symbolic)
- return None
+ def can_make_custom_step(self, cterm: CTerm) -> bool:
+ return self._check_forget_pattern(cterm) or super().can_make_custom_step(cterm)
class FoundryKEVM(KEVM):
From c5aff319a93397bb47d138fe6a683d298d6b6eac Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Wed, 4 Dec 2024 15:07:44 +0200
Subject: [PATCH 06/17] formatting
---
src/kontrol/foundry.py | 30 ++++++++++++++++++++++--------
src/kontrol/prove.py | 2 --
2 files changed, 22 insertions(+), 10 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index abc67251d..36aef9c76 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -113,30 +113,44 @@ def _check_forget_pattern(self, cterm: CTerm) -> bool:
self._cached_subst = abstract_pattern.match(cterm.cell('K_CELL'))
return self._cached_subst is not None
- def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic) -> KCFGExtendResult:
+ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic) -> KCFGExtendResult | None:
"""Given a CTerm, remove the constraint that's placed at the top of the K_CELL in the 'FOUNDRY-ACCOUNTS.forget' cut-rule.
:param cterm: CTerm of a proof node.
- :cterm_symbolic: CTermSymbolic instance
- :return: If the K_CELL matches the forget_pattern, a Step with depth 1 is returned together with the new configuration, also registering that the `FOUNDRY-ACCOUNTS.forget` rule has been applied.
+ :param cterm_symbolic: CTermSymbolic instance
+ :return: If the K_CELL matches the forget_pattern and the constraint is successfully removed, returns a Step with depth 1 along with the new configuration, registering that the `cheatcode_forget` rule has been applied. If the constraint is not found, returns None.
"""
_operators = ['_==Int_', '_<=Int_', '_=Int_', '_>Int_']
_LOGGER.info('Custom step: Forget pattern confirmed')
subst = self._cached_subst
assert subst is not None
+
+ # Extract the terms and operator from the substitution
fst_term = subst['###TERM1']
snd_term = subst['###TERM2']
operator = subst['###OPERATOR']
- assert type(operator) is KToken
- eq = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
+ assert isinstance(operator, KToken)
+ constraint = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
+
+ # Simplify the constraint
kevm = KEVM(kdist.get('kontrol.foundry'))
empty_config = kevm.definition.empty_config(GENERATED_TOP_CELL)
- simplification_cterm = CTerm.from_kast(empty_config).add_constraint(eq)
+ simplification_cterm = CTerm.from_kast(empty_config).add_constraint(constraint)
result_cterm, _ = cterm_symbolic.simplify(simplification_cterm)
target_constraint = single(result_cterm.constraints)
- new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
+
+ # Remove the target constraint from the current constraints
new_constraints: tuple[KInner, ...] = tuple(c for c in cterm.constraints if c != target_constraint)
- _LOGGER.info(f'Custom step: removing constraint: {target_constraint}')
+
+ # Check if the constraints have changed
+ if new_constraints == cterm.constraints:
+ _LOGGER.info('Custom step: Target constraint not found in path conditions; returning None')
+ return None
+
+ _LOGGER.info(f'Custom step: Removing constraint: {target_constraint}')
+
+ # Update the K_CELL with the continuation
+ new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
def custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic) -> KCFGExtendResult | None:
diff --git a/src/kontrol/prove.py b/src/kontrol/prove.py
index bf4708efe..ac248b39a 100644
--- a/src/kontrol/prove.py
+++ b/src/kontrol/prove.py
@@ -442,8 +442,6 @@ def create_kcfg_explore() -> KCFGExplore:
)
cut_point_rules.append('FOUNDRY-ACCOUNTS.forget')
- print('CUT POINT RULES')
- print(cut_point_rules)
extra_lemmas_module: KFlatModule | None = None
if options.extra_module:
From ae0ceb0d3d8c24b9c817d7650760ef9662725283 Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Wed, 4 Dec 2024 16:52:15 +0200
Subject: [PATCH 07/17] add back not equal
---
src/kontrol/foundry.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 36aef9c76..83dd9e1fb 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -120,7 +120,7 @@ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic)
:param cterm_symbolic: CTermSymbolic instance
:return: If the K_CELL matches the forget_pattern and the constraint is successfully removed, returns a Step with depth 1 along with the new configuration, registering that the `cheatcode_forget` rule has been applied. If the constraint is not found, returns None.
"""
- _operators = ['_==Int_', '_<=Int_', '_=Int_', '_>Int_']
+ _operators = ['_==Int_', '_!=Int_', '_<=Int_', '_=Int_', '_>Int_']
_LOGGER.info('Custom step: Forget pattern confirmed')
subst = self._cached_subst
assert subst is not None
From 88de162d751d020fcd888732f0efa7127d06ad27 Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Thu, 5 Dec 2024 08:23:56 +0200
Subject: [PATCH 08/17] rename FOUNDRYSemantics to KontrolSemantics
---
src/kontrol/foundry.py | 16 ++++++++--------
src/kontrol/prove.py | 8 ++++----
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 83dd9e1fb..ca1947eb4 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -94,7 +94,7 @@
_LOGGER: Final = logging.getLogger(__name__)
-class FOUNDRYSemantics(KEVMSemantics):
+class KontrolSemantics(KEVMSemantics):
def _check_forget_pattern(self, cterm: CTerm) -> bool:
"""Given a CTerm, check if the rule 'FOUNDRY-ACCOUNTS.forget' is at the top of the K_CELL.
@@ -922,7 +922,7 @@ def foundry_show(
if options.failure_info:
with legacy_explore(
foundry.kevm,
- kcfg_semantics=FOUNDRYSemantics(),
+ kcfg_semantics=KontrolSemantics(),
id=test_id,
smt_timeout=options.smt_timeout,
smt_retry_limit=options.smt_retry_limit,
@@ -989,7 +989,7 @@ def _collect_klabel(_k: KInner) -> None:
]
sentences = [sent for sent in sentences if not _contains_foundry_klabel(sent.body)]
sentences = [
- sent for sent in sentences if not FOUNDRYSemantics().is_terminal(CTerm.from_kast(extract_lhs(sent.body)))
+ sent for sent in sentences if not KontrolSemantics().is_terminal(CTerm.from_kast(extract_lhs(sent.body)))
]
if len(sentences) == 0:
_LOGGER.warning(f'No claims or rules retained for proof {proof.id}')
@@ -1179,7 +1179,7 @@ def foundry_simplify_node(
with legacy_explore(
foundry.kevm,
- kcfg_semantics=FOUNDRYSemantics(),
+ kcfg_semantics=KontrolSemantics(),
id=apr_proof.id,
bug_report=options.bug_report,
kore_rpc_command=kore_rpc_command,
@@ -1227,7 +1227,7 @@ def check_cells_equal(cell: str, nodes: Iterable[KCFG.Node]) -> bool:
check_cells_ne = [check_cell for check_cell in check_cells if not check_cells_equal(check_cell, nodes)]
if check_cells_ne:
- if not all(FOUNDRYSemantics().same_loop(nodes[0].cterm, nd.cterm) for nd in nodes):
+ if not all(KontrolSemantics().same_loop(nodes[0].cterm, nd.cterm) for nd in nodes):
raise ValueError(f'Nodes {options.nodes} cannot be merged because they differ in: {check_cells_ne}')
anti_unification = nodes[0].cterm
@@ -1267,7 +1267,7 @@ def foundry_step_node(
with legacy_explore(
foundry.kevm,
- kcfg_semantics=FOUNDRYSemantics(),
+ kcfg_semantics=KontrolSemantics(),
id=apr_proof.id,
bug_report=options.bug_report,
kore_rpc_command=kore_rpc_command,
@@ -1343,7 +1343,7 @@ def foundry_section_edge(
with legacy_explore(
foundry.kevm,
- kcfg_semantics=FOUNDRYSemantics(),
+ kcfg_semantics=KontrolSemantics(),
id=apr_proof.id,
bug_report=options.bug_report,
kore_rpc_command=kore_rpc_command,
@@ -1394,7 +1394,7 @@ def foundry_get_model(
with legacy_explore(
foundry.kevm,
- kcfg_semantics=FOUNDRYSemantics(),
+ kcfg_semantics=KontrolSemantics(),
id=proof.id,
bug_report=options.bug_report,
kore_rpc_command=kore_rpc_command,
diff --git a/src/kontrol/prove.py b/src/kontrol/prove.py
index ac248b39a..c0ac3bc3d 100644
--- a/src/kontrol/prove.py
+++ b/src/kontrol/prove.py
@@ -35,7 +35,7 @@
from pyk.utils import hash_str, run_process_2, single, unique
from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn, TimeElapsedColumn
-from .foundry import Foundry, FOUNDRYSemantics, foundry_to_xml
+from .foundry import Foundry, KontrolSemantics, foundry_to_xml
from .hevm import Hevm
from .options import ConfigType, TraceOptions
from .solc_to_k import Contract, hex_string_to_int
@@ -381,7 +381,7 @@ def create_kcfg_explore() -> KCFGExplore:
)
return KCFGExplore(
cterm_symbolic,
- kcfg_semantics=FOUNDRYSemantics(auto_abstract_gas=options.auto_abstract_gas),
+ kcfg_semantics=KontrolSemantics(auto_abstract_gas=options.auto_abstract_gas),
id=test.id,
)
@@ -425,7 +425,7 @@ def create_kcfg_explore() -> KCFGExplore:
}
),
)
- cut_point_rules = FOUNDRYSemantics.cut_point_rules(
+ cut_point_rules = KontrolSemantics.cut_point_rules(
options.break_on_jumpi,
options.break_on_jump,
options.break_on_calls,
@@ -467,7 +467,7 @@ def create_kcfg_explore() -> KCFGExplore:
max_depth=options.max_depth,
max_iterations=options.max_iterations,
cut_point_rules=cut_point_rules,
- terminal_rules=FOUNDRYSemantics.terminal_rules(options.break_every_step),
+ terminal_rules=KontrolSemantics.terminal_rules(options.break_every_step),
counterexample_info=options.counterexample_info,
max_frontier_parallel=options.max_frontier_parallel,
fail_fast=options.fail_fast,
From 2c6bf19373ad724a75a1acb115c3576168514dab Mon Sep 17 00:00:00 2001
From: Petar Maksimovic
Date: Fri, 6 Dec 2024 16:02:05 +0100
Subject: [PATCH 09/17] checking for negation as well
---
src/kontrol/foundry.py | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index ca1947eb4..619399912 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -130,28 +130,30 @@ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic)
snd_term = subst['###TERM2']
operator = subst['###OPERATOR']
assert isinstance(operator, KToken)
- constraint = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
+ pos_constraint = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
+ neg_constraint = mlEqualsTrue(notBool(KApply(_operators[int(operator.token)], fst_term, snd_term)))
# Simplify the constraint
kevm = KEVM(kdist.get('kontrol.foundry'))
empty_config = kevm.definition.empty_config(GENERATED_TOP_CELL)
- simplification_cterm = CTerm.from_kast(empty_config).add_constraint(constraint)
- result_cterm, _ = cterm_symbolic.simplify(simplification_cterm)
- target_constraint = single(result_cterm.constraints)
+ for constraint in [pos_constraint, neg_constraint]:
+ simplification_cterm = CTerm.from_kast(empty_config).add_constraint(constraint)
+ result_cterm, _ = cterm_symbolic.simplify(simplification_cterm)
+ target_constraint = single(result_cterm.constraints)
- # Remove the target constraint from the current constraints
- new_constraints: tuple[KInner, ...] = tuple(c for c in cterm.constraints if c != target_constraint)
+ # Remove the target constraint from the current constraints
+ new_constraints: tuple[KInner, ...] = tuple(c for c in cterm.constraints if c != target_constraint)
- # Check if the constraints have changed
- if new_constraints == cterm.constraints:
- _LOGGER.info('Custom step: Target constraint not found in path conditions; returning None')
- return None
-
- _LOGGER.info(f'Custom step: Removing constraint: {target_constraint}')
+ # Check if the constraints have changed
+ if new_constraints == cterm.constraints:
+ _LOGGER.info(f'Custom step: Target constraint:\n{target_constraint}\nnot found in current constraints')
+ else:
+ _LOGGER.info(f'Custom step: Removing constraint:\n{target_constraint}')
- # Update the K_CELL with the continuation
- new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
- return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
+ # Update the K_CELL with the continuation
+ new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
+ return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
+ return None
def custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic) -> KCFGExtendResult | None:
if self._check_forget_pattern(cterm):
From 7e474932ec829d131f1dfa666a8332ba2cb0e927 Mon Sep 17 00:00:00 2001
From: Petar Maksimovic
Date: Fri, 6 Dec 2024 21:00:06 +0100
Subject: [PATCH 10/17] correcting indentation
---
src/kontrol/foundry.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 619399912..76b1d6349 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -150,9 +150,9 @@ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic)
else:
_LOGGER.info(f'Custom step: Removing constraint:\n{target_constraint}')
- # Update the K_CELL with the continuation
- new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
- return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
+ # Update the K_CELL with the continuation
+ new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
+ return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
return None
def custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic) -> KCFGExtendResult | None:
From 088a17462c3e60490fdb19945ba925e28a53f25d Mon Sep 17 00:00:00 2001
From: Petar Maksimovic
Date: Sun, 8 Dec 2024 19:17:13 +0100
Subject: [PATCH 11/17] expanding functionality
---
src/kontrol/foundry.py | 67 ++++++++++++++++++++++++++++++------------
1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 76b1d6349..8d0c911f7 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -26,6 +26,7 @@
collect,
extract_lhs,
flatten_label,
+ free_vars,
minimize_term,
set_cell,
top_down,
@@ -130,30 +131,58 @@ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic)
snd_term = subst['###TERM2']
operator = subst['###OPERATOR']
assert isinstance(operator, KToken)
+ # Construct the positive and negative constraints
pos_constraint = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
neg_constraint = mlEqualsTrue(notBool(KApply(_operators[int(operator.token)], fst_term, snd_term)))
+ # Pinpoint variables of interest
+ variables_to_look_for: frozenset[str] = free_vars(fst_term).union(free_vars(snd_term))
+ # Range-constraint patterns
+ range_constraint_patterns: list[KInner] = [
+ mlEqualsTrue(KApply('_<=Int_', KToken('###NUM', INT), KVariable('###VAR'))),
+ mlEqualsTrue(KApply('_<=Int_', KVariable('###VAR'), KToken('###NUM', INT))),
+ mlEqualsTrue(KApply('_ KCFGExtendResult | None:
if self._check_forget_pattern(cterm):
From 92bf19639d38ce7015b5955cfbfd4ddd7f24ac70 Mon Sep 17 00:00:00 2001
From: Petar Maksimovic
Date: Sun, 8 Dec 2024 23:06:54 +0100
Subject: [PATCH 12/17] heuristic simplifications
---
src/kontrol/foundry.py | 83 ++++++++++++++++++++++--------------------
1 file changed, 43 insertions(+), 40 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 8d0c911f7..0411e01c6 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -115,17 +115,19 @@ def _check_forget_pattern(self, cterm: CTerm) -> bool:
return self._cached_subst is not None
def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic) -> KCFGExtendResult | None:
- """Given a CTerm, remove the constraint that's placed at the top of the K_CELL in the 'FOUNDRY-ACCOUNTS.forget' cut-rule.
+ """Remove the constraint at the top of K_CELL of a given CTerm from its path constraints,
+ as part of the 'FOUNDRY-ACCOUNTS.forget' cut-rule.
- :param cterm: CTerm of a proof node.
+ :param cterm: CTerm representing a proof node
:param cterm_symbolic: CTermSymbolic instance
- :return: If the K_CELL matches the forget_pattern and the constraint is successfully removed, returns a Step with depth 1 along with the new configuration, registering that the `cheatcode_forget` rule has been applied. If the constraint is not found, returns None.
+ :return: A Step of depth 1 carrying a new configuration in which the constraint is consumed from the top
+ of the K cell and is removed from the initial path constraints if it existed, together with
+ information that the `cheatcode_forget` rule has been applied.
"""
+ _LOGGER.info('forgetBranch: pattern confirmed')
_operators = ['_==Int_', '_!=Int_', '_<=Int_', '_=Int_', '_>Int_']
- _LOGGER.info('Custom step: Forget pattern confirmed')
subst = self._cached_subst
assert subst is not None
-
# Extract the terms and operator from the substitution
fst_term = subst['###TERM1']
snd_term = subst['###TERM2']
@@ -134,52 +136,53 @@ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic)
# Construct the positive and negative constraints
pos_constraint = mlEqualsTrue(KApply(_operators[int(operator.token)], fst_term, snd_term))
neg_constraint = mlEqualsTrue(notBool(KApply(_operators[int(operator.token)], fst_term, snd_term)))
- # Pinpoint variables of interest
- variables_to_look_for: frozenset[str] = free_vars(fst_term).union(free_vars(snd_term))
- # Range-constraint patterns
- range_constraint_patterns: list[KInner] = [
- mlEqualsTrue(KApply('_<=Int_', KToken('###NUM', INT), KVariable('###VAR'))),
- mlEqualsTrue(KApply('_<=Int_', KVariable('###VAR'), KToken('###NUM', INT))),
- mlEqualsTrue(KApply('_
Date: Mon, 9 Dec 2024 18:26:24 +0100
Subject: [PATCH 13/17] further refinement
---
src/kontrol/foundry.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index 0411e01c6..7784759a7 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -183,6 +183,13 @@ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic)
break
else:
_LOGGER.info(f'forgetBranch: constraint: {target_constraint} not found in current constraints')
+ else:
+ if len(result_constraints) == 0:
+ _LOGGER.info(f'forgetBranch: constraint {constraint} entailed by remaining constraints')
+ else:
+ _LOGGER.info(
+ f'forgetBranch: more than one constraint found after simplification and removal:\n{result_constraints}'
+ )
# Update the K_CELL with the continuation
new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
From d71a3ce1fe440e65e654d7baee3924aebcaa5cc5 Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Tue, 10 Dec 2024 11:14:58 +0200
Subject: [PATCH 14/17] refactoring _exec_forget_custom_step
---
src/kontrol/foundry.py | 112 ++++++++++++++++++++++++-----------------
src/kontrol/prove.py | 2 -
2 files changed, 65 insertions(+), 49 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index b2ddc782d..a97e8deb2 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -107,7 +107,7 @@ def cut_point_rules(
break_on_basic_blocks: bool,
break_on_load_program: bool,
) -> list[str]:
- return ['FOUNDRY-CHEAT-CODES.rename'] + KEVMSemantics.cut_point_rules(
+ return ['FOUNDRY-CHEAT-CODES.rename', 'FOUNDRY-ACCOUNTS.forget'] + KEVMSemantics.cut_point_rules(
break_on_jumpi,
break_on_jump,
break_on_calls,
@@ -182,8 +182,65 @@ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic)
of the K cell and is removed from the initial path constraints if it existed, together with
information that the `cheatcode_forget` rule has been applied.
"""
- _LOGGER.info('forgetBranch: pattern confirmed')
- _operators = ['_==Int_', '_!=Int_', '_<=Int_', '_=Int_', '_>Int_']
+
+ def _find_constraints_to_keep(cterm: CTerm, constraint_vars: frozenset[str]) -> set[KInner]:
+ range_patterns: list[KInner] = [
+ mlEqualsTrue(KApply('_ set[KInner]:
+ for constraint_variant in constraints_to_remove:
+ simplification_cterm = initial_cterm.add_constraint(constraint_variant)
+ result_cterm, _ = cterm_symbolic.simplify(simplification_cterm)
+ # Extract constraints that appear after simplification but are not in the 'to keep' set
+ result_constraints = set(result_cterm.constraints).difference(constraints_to_keep)
+
+ if len(result_constraints) == 1:
+ target_constraint = single(result_constraints)
+ if target_constraint in constraints:
+ _LOGGER.info(f'forgetBranch: removing constraint: {target_constraint}')
+ constraints.remove(target_constraint)
+ break
+ else:
+ _LOGGER.info(f'forgetBranch: constraint: {target_constraint} not found in current constraints')
+ else:
+ # If no constraints or multiple constraints appear, log this scenario.
+ if len(result_constraints) == 0:
+ _LOGGER.info(f'forgetBranch: constraint {constraint_variant} entailed by remaining constraints')
+ else:
+ _LOGGER.info(
+ f'forgetBranch: more than one constraint found after simplification and removal:\n{result_constraints}'
+ )
+ return constraints
+
+ _operators = ['_==Int_', '_=/=Int_', '_<=Int_', '_=Int_', '_>Int_']
subst = self._cached_subst
assert subst is not None
# Extract the terms and operator from the substitution
@@ -196,58 +253,19 @@ def _exec_forget_custom_step(self, cterm: CTerm, cterm_symbolic: CTermSymbolic)
neg_constraint = mlEqualsTrue(notBool(KApply(_operators[int(operator.token)], fst_term, snd_term)))
# To be able to better simplify, we maintain range constraints on the variables present in the constraint
constraint_vars: frozenset[str] = free_vars(fst_term).union(free_vars(snd_term))
- range_patterns: list[KInner] = [
- mlEqualsTrue(KApply('_ KCFGExplore:
rule.label for rule in foundry.kevm.definition.all_modules_dict['KONTROL-ASSERTIONS'].rules
)
- cut_point_rules.append('FOUNDRY-ACCOUNTS.forget')
-
extra_lemmas_module: KFlatModule | None = None
if options.extra_module:
extra_module_file, extra_module_name, *_ = options.extra_module.split(':')
From 9e05d194c36ee68c0e5f39b6a1ce5712b94f96f6 Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Tue, 10 Dec 2024 11:46:18 +0200
Subject: [PATCH 15/17] add show test
---
src/kontrol/kdist/cheatcodes.md | 1 -
.../test-data/end-to-end-prove-all | 29 +-
.../test-data/end-to-end-prove-show | 1 +
.../test-data/end-to-end-prove-skip | 34 +-
...chTest.test_forgetBranch(uint256).expected | 787 ++++++++++++++++++
.../{foundry/test => src}/ForgetBranch.t.sol | 5 +-
6 files changed, 823 insertions(+), 34 deletions(-)
create mode 100644 src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
rename src/tests/integration/test-data/{foundry/test => src}/ForgetBranch.t.sol (72%)
diff --git a/src/kontrol/kdist/cheatcodes.md b/src/kontrol/kdist/cheatcodes.md
index dac8848a8..15da6c2a9 100644
--- a/src/kontrol/kdist/cheatcodes.md
+++ b/src/kontrol/kdist/cheatcodes.md
@@ -1771,7 +1771,6 @@ Selectors for **implemented** cheat code functions.
rule ( selector ( "mockCall(address,bytes,bytes)" ) => 3110212580 )
rule ( selector ( "mockFunction(address,address,bytes)" ) => 2918731041 )
rule ( selector ( "copyStorage(address,address)" ) => 540912653 )
- rule ( selector ( "replaceConstraint(uint256,uint8,uint256,bool)" ) => 1408652492 )
rule ( selector ( "forgetBranch(uint256,uint8,uint256)" ) => 1720990067 )
```
diff --git a/src/tests/integration/test-data/end-to-end-prove-all b/src/tests/integration/test-data/end-to-end-prove-all
index 6a2bc826c..749effdd8 100644
--- a/src/tests/integration/test-data/end-to-end-prove-all
+++ b/src/tests/integration/test-data/end-to-end-prove-all
@@ -1,14 +1,25 @@
CounterTest.test_Increment()
+ForgetBranchTest.test_forgetBranch(uint256)
RandomVarTest.test_custom_names()
-RandomVarTest.test_randomBool()
RandomVarTest.test_randomAddress()
-RandomVarTest.test_randomUint()
-RandomVarTest.test_randomUint_192()
-RandomVarTest.test_randomUint_Range(uint256,uint256)
+RandomVarTest.test_randomBool()
RandomVarTest.test_randomBytes_length(uint256)
RandomVarTest.test_randomBytes4_length()
RandomVarTest.test_randomBytes8_length()
+RandomVarTest.test_randomUint_192()
+RandomVarTest.test_randomUint_Range(uint256,uint256)
+RandomVarTest.test_randomUint()
TransientStorageTest.testTransientStoreLoad(uint256,uint256)
+UnitTest.test_assert_eq_address_darray(address[])
+UnitTest.test_assert_eq_bool_darray(bool[])
+UnitTest.test_assert_eq_bytes32_darray(bytes32[])
+UnitTest.test_assert_eq_int256_darray(int256[])
+UnitTest.test_assert_eq_uint256_darray(uint256[])
+UnitTest.test_assertApproxEqAbs_int_same_sign(uint256,uint256,uint256)
+UnitTest.test_assertApproxEqAbs_uint(uint256,uint256,uint256)
+UnitTest.test_assertApproxEqRel_int_same_sign_unit()
+UnitTest.test_assertApproxEqRel_int_zero_cases_unit()
+UnitTest.test_assertApproxEqRel_uint_unit()
UnitTest.test_assertEq_address_err()
UnitTest.test_assertEq_bool_err()
UnitTest.test_assertEq_bytes32_err()
@@ -39,13 +50,3 @@ UnitTest.test_assertNotEq(bytes32,bytes32)
UnitTest.test_assertNotEq(int256,int256)
UnitTest.test_assertTrue_err()
UnitTest.test_assertTrue(bool)
-UnitTest.test_assertApproxEqAbs_uint(uint256,uint256,uint256)
-UnitTest.test_assertApproxEqAbs_int_same_sign(uint256,uint256,uint256)
-UnitTest.test_assertApproxEqRel_uint_unit()
-UnitTest.test_assertApproxEqRel_int_same_sign_unit()
-UnitTest.test_assertApproxEqRel_int_zero_cases_unit()
-UnitTest.test_assert_eq_bytes32_darray(bytes32[])
-UnitTest.test_assert_eq_bool_darray(bool[])
-UnitTest.test_assert_eq_int256_darray(int256[])
-UnitTest.test_assert_eq_uint256_darray(uint256[])
-UnitTest.test_assert_eq_address_darray(address[])
diff --git a/src/tests/integration/test-data/end-to-end-prove-show b/src/tests/integration/test-data/end-to-end-prove-show
index 028eb6cd8..067333b96 100644
--- a/src/tests/integration/test-data/end-to-end-prove-show
+++ b/src/tests/integration/test-data/end-to-end-prove-show
@@ -1 +1,2 @@
+ForgetBranchTest.test_forgetBranch(uint256)
RandomVarTest.test_custom_names()
diff --git a/src/tests/integration/test-data/end-to-end-prove-skip b/src/tests/integration/test-data/end-to-end-prove-skip
index 903580e0c..2668de8ef 100644
--- a/src/tests/integration/test-data/end-to-end-prove-skip
+++ b/src/tests/integration/test-data/end-to-end-prove-skip
@@ -1,3 +1,19 @@
+UnitTest.test_assert_eq_address_darray_err()
+UnitTest.test_assert_eq_bool_darray_err()
+UnitTest.test_assert_eq_bytes32_darray_err()
+UnitTest.test_assert_eq_int256_darray_err()
+UnitTest.test_assert_eq_uint256_darray_err()
+UnitTest.test_assertApproxEqAbs_int_opp_sign_err()
+UnitTest.test_assertApproxEqAbs_int_opp_sign(uint256,uint256,uint256)
+UnitTest.test_assertApproxEqAbs_int_same_sign_err()
+UnitTest.test_assertApproxEqAbs_int_zero_cases_err()
+UnitTest.test_assertApproxEqAbs_int_zero_cases(uint256,uint256)
+UnitTest.test_assertApproxEqAbs_uint_err()
+UnitTest.test_assertApproxEqRel_int_opp_sign_err()
+UnitTest.test_assertApproxEqRel_int_opp_sign_unit()
+UnitTest.test_assertApproxEqRel_int_same_sign_err()
+UnitTest.test_assertApproxEqRel_int_zero_cases_err()
+UnitTest.test_assertApproxEqRel_uint_err()
UnitTest.test_assertEq_address_err()
UnitTest.test_assertEq_bool_err()
UnitTest.test_assertEq_bytes32_err()
@@ -13,20 +29,4 @@ UnitTest.test_assertNotEq_bool_err()
UnitTest.test_assertNotEq_bytes32_err()
UnitTest.test_assertNotEq_err()
UnitTest.test_assertNotEq_int256_err()
-UnitTest.test_assertTrue_err()
-UnitTest.test_assertApproxEqAbs_uint_err()
-UnitTest.test_assertApproxEqAbs_int_same_sign_err()
-UnitTest.test_assertApproxEqAbs_int_opp_sign(uint256,uint256,uint256)
-UnitTest.test_assertApproxEqAbs_int_opp_sign_err()
-UnitTest.test_assertApproxEqAbs_int_zero_cases(uint256,uint256)
-UnitTest.test_assertApproxEqAbs_int_zero_cases_err()
-UnitTest.test_assertApproxEqRel_uint_err()
-UnitTest.test_assertApproxEqRel_int_same_sign_err()
-UnitTest.test_assertApproxEqRel_int_opp_sign_unit()
-UnitTest.test_assertApproxEqRel_int_opp_sign_err()
-UnitTest.test_assertApproxEqRel_int_zero_cases_err()
-UnitTest.test_assert_eq_bytes32_darray_err()
-UnitTest.test_assert_eq_bool_darray_err()
-UnitTest.test_assert_eq_int256_darray_err()
-UnitTest.test_assert_eq_address_darray_err()
-UnitTest.test_assert_eq_uint256_darray_err()
\ No newline at end of file
+UnitTest.test_assertTrue_err()
\ No newline at end of file
diff --git a/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected b/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
new file mode 100644
index 000000000..5a44b8953
--- /dev/null
+++ b/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
@@ -0,0 +1,787 @@
+
+┌─ 1 (root, init)
+│ k: #execute ~> CONTINUATION:K
+│ pc: 0
+│ callDepth: 0
+│ statusCode: STATUSCODE:StatusCode
+│ src: test/ForgetBranch.t.sol:8:21
+│ method: test%ForgetBranchTest.test_forgetBranch(uint256)
+│
+│ (755 steps)
+├─ 3
+│ k: #forget ( 200 , 5 , KV0_x:Int ) ~> #cheatcode_return 128 0 ~> #pc [ CALL ] ~> #e ...
+│ pc: 1294
+│ callDepth: 0
+│ statusCode: STATUSCODE:StatusCode
+│ src: test/ForgetBranch.t.sol:14:14
+│ method: test%ForgetBranchTest.test_forgetBranch(uint256)
+│
+│ (1 step)
+├─ 4
+│ k: #cheatcode_return 128 0 ~> #pc [ CALL ] ~> #execute ~> CONTINUATION:K
+│ pc: 1294
+│ callDepth: 0
+│ statusCode: STATUSCODE:StatusCode
+│ src: test/ForgetBranch.t.sol:14:14
+│ method: test%ForgetBranchTest.test_forgetBranch(uint256)
+│
+│ (112 steps)
+├─ 5 (terminal)
+│ k: #halt ~> CONTINUATION:K
+│ pc: 320
+│ callDepth: 0
+│ statusCode: EVMC_SUCCESS
+│ src: test/ForgetBranch.t.sol:10:20
+│ method: test%ForgetBranchTest.test_forgetBranch(uint256)
+│
+┊ constraint: true
+┊ subst: ...
+└─ 2 (leaf, target, terminal)
+ k: #halt ~> CONTINUATION:K
+ pc: PC_CELL_5d410f2a:Int
+ callDepth: CALLDEPTH_CELL_5d410f2a:Int
+ statusCode: STATUSCODE_FINAL:StatusCode
+
+
+
+
+module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
+
+
+ rule [BASIC-BLOCK-1-TO-3]:
+
+
+ ( .K => #forget ( 200 , 5 , KV0_x:Int )
+ ~> #cheatcode_return 128 0
+ ~> #pc [ CALL ] )
+ ~> #execute
+ ~> _CONTINUATION
+
+
+ NORMAL
+
+
+ CANCUN
+
+
+ false
+
+
+
+
+
+ .List
+
+
+ .List
+
+
+ .Set
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ CALLER_ID:Int
+
+
+ b"P#a\xd8" +Bytes #buf ( 32 , KV0_x:Int )
+
+
+ 0
+
+
+ ( .WordStack => ( 228 : ( selector ( "forgetBranch(uint256,uint8,uint256)" ) : ( 645326474426547203313410069153905908525362434349 : ( 0 : ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) ) ) ) ) )
+
+
+ ( b"" => b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05" +Bytes #buf ( 32 , KV0_x:Int ) )
+
+
+ 0
+
+
+ 0
+
+
+ false
+
+
+ 0
+
+ ...
+
+
+
+ .List
+
+
+ 0
+
+
+ ( .Set => SetItem ( 645326474426547203313410069153905908525362434349 ) )
+
+
+ .Map
+
+ ...
+
+
+ ORIGIN_ID:Int
+
+
+
+ NUMBER_CELL:Int
+
+
+ TIMESTAMP_CELL:Int
+
+ ...
+
+ ...
+
+
+
+ 1
+
+
+ (
+
+ 645326474426547203313410069153905908525362434349
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 0
+
+ ...
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 1
+
+ ...
+ )
+
+ ...
+
+
+ ...
+
+
+ false
+
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+ .List
+
+
+
+ .MockCallCellMap
+
+
+ .MockFunctionCellMap
+
+
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+
+ requires ( 0 <=Int KV0_x:Int
+ andBool ( 0 <=Int CALLER_ID:Int
+ andBool ( 0 <=Int ORIGIN_ID:Int
+ andBool ( pow24
+
+
+ ( #forget ( 200 , 5 , KV0_x:Int ) ~> .K => .K )
+ ~> #cheatcode_return 128 0
+ ~> #pc [ CALL ]
+ ~> #execute
+ ~> _CONTINUATION
+
+
+ NORMAL
+
+
+ CANCUN
+
+
+ false
+
+
+
+
+
+ .List
+
+
+ .List
+
+
+ .Set
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ CALLER_ID:Int
+
+
+ b"P#a\xd8" +Bytes #buf ( 32 , KV0_x:Int )
+
+
+ 0
+
+
+ ( 228 : ( selector ( "forgetBranch(uint256,uint8,uint256)" ) : ( 645326474426547203313410069153905908525362434349 : ( 0 : ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) ) ) ) )
+
+
+ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05" +Bytes #buf ( 32 , KV0_x:Int )
+
+
+ 0
+
+
+ 0
+
+
+ false
+
+
+ 0
+
+ ...
+
+
+
+ .List
+
+
+ 0
+
+
+ SetItem ( 645326474426547203313410069153905908525362434349 )
+
+
+ .Map
+
+ ...
+
+
+ ORIGIN_ID:Int
+
+
+
+ NUMBER_CELL:Int
+
+
+ TIMESTAMP_CELL:Int
+
+ ...
+
+ ...
+
+
+
+ 1
+
+
+ (
+
+ 645326474426547203313410069153905908525362434349
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 0
+
+ ...
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 1
+
+ ...
+ )
+
+ ...
+
+
+ ...
+
+
+ false
+
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+ .List
+
+
+
+ .MockCallCellMap
+
+
+ .MockFunctionCellMap
+
+
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+
+ requires ( 0 <=Int KV0_x:Int
+ andBool ( 200
+
+
+ ( #cheatcode_return 128 0
+ ~> #pc [ CALL ]
+ ~> #execute => #halt ~> .K )
+ ~> _CONTINUATION
+
+
+ NORMAL
+
+
+ CANCUN
+
+
+ false
+
+
+
+
+
+ ( _STATUSCODE => EVMC_SUCCESS )
+
+
+ .List
+
+
+ .List
+
+
+ .Set
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ CALLER_ID:Int
+
+
+ b"P#a\xd8" +Bytes #buf ( 32 , KV0_x:Int )
+
+
+ 0
+
+
+ ( ( 228 => selector ( "test_forgetBranch(uint256)" ) ) : ( ( selector ( "forgetBranch(uint256,uint8,uint256)" ) : ( 645326474426547203313410069153905908525362434349 : ( 0 : ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) ) ) ) => .WordStack ) )
+
+
+ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05" +Bytes #buf ( 32 , KV0_x:Int )
+
+
+ 0
+
+
+ 0
+
+
+ false
+
+
+ 0
+
+ ...
+
+
+
+ .List
+
+
+ 0
+
+
+ SetItem ( 645326474426547203313410069153905908525362434349 )
+
+
+ .Map
+
+ ...
+
+
+ ORIGIN_ID:Int
+
+
+
+ NUMBER_CELL:Int
+
+
+ TIMESTAMP_CELL:Int
+
+ ...
+
+ ...
+
+
+
+ 1
+
+
+ (
+
+ 645326474426547203313410069153905908525362434349
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 0
+
+ ...
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 1
+
+ ...
+ )
+
+ ...
+
+
+ ...
+
+
+ false
+
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+ .List
+
+
+
+ .MockCallCellMap
+
+
+ .MockFunctionCellMap
+
+
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+
+ requires ( 0 <=Int KV0_x:Int
+ andBool ( 200 =0.8.13;
-import "forge-std/Test.sol";
+import {Test, console} from "forge-std/Test.sol";
import "kontrol-cheatcodes/KontrolCheats.sol";
+
contract ForgetBranchTest is Test, KontrolCheats {
function test_forgetBranch(uint256 x) public {
uint256 y;
vm.assume(x > 200);
- kevm.forgetBranch(200, 2, x);
+ kevm.forgetBranch(200, KontrolCheatsBase.ComparisonOperator.GreaterThan, x);
if(x > 200){
y = 21;
} else {
From 49cee7babad42435d44a277b7cace14ef39fd27d Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Tue, 10 Dec 2024 13:40:40 +0200
Subject: [PATCH 16/17] fix test
---
src/kontrol/foundry.py | 16 +-
...chTest.test_forgetBranch(uint256).expected | 582 +++++++++++++++++-
.../test-data/src/ForgetBranch.t.sol | 2 +-
3 files changed, 575 insertions(+), 25 deletions(-)
diff --git a/src/kontrol/foundry.py b/src/kontrol/foundry.py
index a97e8deb2..b46764db5 100644
--- a/src/kontrol/foundry.py
+++ b/src/kontrol/foundry.py
@@ -215,6 +215,7 @@ def _filter_constraints_by_simplification(
constraints_to_remove: list[KInner],
constraints_to_keep: set[KInner],
constraints: set[KInner],
+ empty_config: CTerm,
) -> set[KInner]:
for constraint_variant in constraints_to_remove:
simplification_cterm = initial_cterm.add_constraint(constraint_variant)
@@ -234,6 +235,12 @@ def _filter_constraints_by_simplification(
# If no constraints or multiple constraints appear, log this scenario.
if len(result_constraints) == 0:
_LOGGER.info(f'forgetBranch: constraint {constraint_variant} entailed by remaining constraints')
+ result_cterm, _ = cterm_symbolic.simplify(CTerm(empty_config.config, [constraint_variant]))
+ if len(result_cterm.constraints) == 1:
+ to_remove = single(result_cterm.constraints)
+ if to_remove in constraints:
+ _LOGGER.info(f'forgetBranch: removing constraint: {to_remove}')
+ constraints.remove(to_remove)
else:
_LOGGER.info(
f'forgetBranch: more than one constraint found after simplification and removal:\n{result_constraints}'
@@ -261,11 +268,18 @@ def _filter_constraints_by_simplification(
empty_config: CTerm = CTerm.from_kast(kevm.definition.empty_config(GENERATED_TOP_CELL))
initial_cterm, _ = cterm_symbolic.simplify(CTerm(empty_config.config, constraints_to_keep))
constraints_to_keep = set(initial_cterm.constraints)
+
# Simplify in the presence of constraints to keep, then remove the constraints to keep to
# reveal simplified constraint, then remove if present in original constraints
new_constraints: set[KInner] = _filter_constraints_by_simplification(
- cterm_symbolic, initial_cterm, [pos_constraint, neg_constraint], constraints_to_keep, set(cterm.constraints)
+ cterm_symbolic=cterm_symbolic,
+ initial_cterm=initial_cterm,
+ constraints_to_remove=[pos_constraint, neg_constraint],
+ constraints_to_keep=constraints_to_keep,
+ constraints=set(cterm.constraints),
+ empty_config=empty_config,
)
+
# Update the K_CELL with the continuation
new_cterm = CTerm.from_kast(set_cell(cterm.kast, 'K_CELL', KSequence(subst['###CONTINUATION'])))
return Step(CTerm(new_cterm.config, new_constraints), 1, (), ['cheatcode_forget'], cut=True)
diff --git a/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected b/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
index 5a44b8953..75243bf5d 100644
--- a/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
+++ b/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
@@ -9,7 +9,7 @@
│
│ (755 steps)
├─ 3
-│ k: #forget ( 200 , 5 , KV0_x:Int ) ~> #cheatcode_return 128 0 ~> #pc [ CALL ] ~> #e ...
+│ k: #forget ( KV0_x:Int , 5 , 200 ) ~> #cheatcode_return 128 0 ~> #pc [ CALL ] ~> #e ...
│ pc: 1294
│ callDepth: 0
│ statusCode: STATUSCODE:StatusCode
@@ -25,22 +25,73 @@
│ src: test/ForgetBranch.t.sol:14:14
│ method: test%ForgetBranchTest.test_forgetBranch(uint256)
│
-│ (112 steps)
-├─ 5 (terminal)
-│ k: #halt ~> CONTINUATION:K
-│ pc: 320
+│ (72 steps)
+├─ 5 (split)
+│ k: JUMPI 1326 bool2Word ( KV0_x:Int <=Int 200 ) ~> #pc [ JUMPI ] ~> #execute ~> CON ...
+│ pc: 1322
│ callDepth: 0
-│ statusCode: EVMC_SUCCESS
-│ src: test/ForgetBranch.t.sol:10:20
+│ statusCode: STATUSCODE:StatusCode
+│ src: test/ForgetBranch.t.sol:15:19
│ method: test%ForgetBranchTest.test_forgetBranch(uint256)
-│
-┊ constraint: true
-┊ subst: ...
-└─ 2 (leaf, target, terminal)
- k: #halt ~> CONTINUATION:K
- pc: PC_CELL_5d410f2a:Int
- callDepth: CALLDEPTH_CELL_5d410f2a:Int
- statusCode: STATUSCODE_FINAL:StatusCode
+┃
+┃ (branch)
+┣━━┓ subst: .Subst
+┃ ┃ constraint:
+┃ ┃ KV0_x:Int <=Int 200
+┃ │
+┃ ├─ 6
+┃ │ k: JUMPI 1326 bool2Word ( KV0_x:Int <=Int 200 ) ~> #pc [ JUMPI ] ~> #execute ~> CON ...
+┃ │ pc: 1322
+┃ │ callDepth: 0
+┃ │ statusCode: STATUSCODE:StatusCode
+┃ │ src: test/ForgetBranch.t.sol:15:19
+┃ │ method: test%ForgetBranchTest.test_forgetBranch(uint256)
+┃ │
+┃ │ (49 steps)
+┃ ├─ 8 (terminal)
+┃ │ k: #halt ~> CONTINUATION:K
+┃ │ pc: 320
+┃ │ callDepth: 0
+┃ │ statusCode: EVMC_SUCCESS
+┃ │ src: test/ForgetBranch.t.sol:10:20
+┃ │ method: test%ForgetBranchTest.test_forgetBranch(uint256)
+┃ │
+┃ ┊ constraint: true
+┃ ┊ subst: ...
+┃ └─ 2 (leaf, target, terminal)
+┃ k: #halt ~> CONTINUATION:K
+┃ pc: PC_CELL_5d410f2a:Int
+┃ callDepth: CALLDEPTH_CELL_5d410f2a:Int
+┃ statusCode: STATUSCODE_FINAL:StatusCode
+┃
+┗━━┓ subst: .Subst
+ ┃ constraint:
+ ┃ 200 #pc [ JUMPI ] ~> #execute ~> CON ...
+ │ pc: 1322
+ │ callDepth: 0
+ │ statusCode: STATUSCODE:StatusCode
+ │ src: test/ForgetBranch.t.sol:15:19
+ │ method: test%ForgetBranchTest.test_forgetBranch(uint256)
+ │
+ │ (40 steps)
+ ├─ 9 (terminal)
+ │ k: #halt ~> CONTINUATION:K
+ │ pc: 320
+ │ callDepth: 0
+ │ statusCode: EVMC_SUCCESS
+ │ src: test/ForgetBranch.t.sol:10:20
+ │ method: test%ForgetBranchTest.test_forgetBranch(uint256)
+ │
+ ┊ constraint: true
+ ┊ subst: ...
+ └─ 2 (leaf, target, terminal)
+ k: #halt ~> CONTINUATION:K
+ pc: PC_CELL_5d410f2a:Int
+ callDepth: CALLDEPTH_CELL_5d410f2a:Int
+ statusCode: STATUSCODE_FINAL:StatusCode
@@ -51,7 +102,7 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
rule [BASIC-BLOCK-1-TO-3]:
- ( .K => #forget ( 200 , 5 , KV0_x:Int )
+ ( .K => #forget ( KV0_x:Int , 5 , 200 )
~> #cheatcode_return 128 0
~> #pc [ CALL ] )
~> #execute
@@ -97,7 +148,7 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
( .WordStack => ( 228 : ( selector ( "forgetBranch(uint256,uint8,uint256)" ) : ( 645326474426547203313410069153905908525362434349 : ( 0 : ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) ) ) ) ) )
- ( b"" => b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05" +Bytes #buf ( 32 , KV0_x:Int ) )
+ ( b"" => b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s" +Bytes #buf ( 32 , KV0_x:Int ) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8" )
0
@@ -293,7 +344,7 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
rule [BASIC-BLOCK-3-TO-4]:
- ( #forget ( 200 , 5 , KV0_x:Int ) ~> .K => .K )
+ ( #forget ( KV0_x:Int , 5 , 200 ) ~> .K => .K )
~> #cheatcode_return 128 0
~> #pc [ CALL ]
~> #execute
@@ -339,7 +390,7 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
( 228 : ( selector ( "forgetBranch(uint256,uint8,uint256)" ) : ( 645326474426547203313410069153905908525362434349 : ( 0 : ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) ) ) ) )
- b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05" +Bytes #buf ( 32 , KV0_x:Int )
+ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s" +Bytes #buf ( 32 , KV0_x:Int ) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8"
0
@@ -536,7 +587,248 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
( #cheatcode_return 128 0
- ~> #pc [ CALL ]
+ ~> #pc [ CALL ] => JUMPI 1326 bool2Word ( KV0_x:Int <=Int 200 )
+ ~> #pc [ JUMPI ] )
+ ~> #execute
+ ~> _CONTINUATION
+
+
+ NORMAL
+
+
+ CANCUN
+
+
+ false
+
+
+
+
+
+ .List
+
+
+ .List
+
+
+ .Set
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ CALLER_ID:Int
+
+
+ b"P#a\xd8" +Bytes #buf ( 32 , KV0_x:Int )
+
+
+ 0
+
+
+ ( ( 228 => 0 ) : ( ( selector ( "forgetBranch(uint256,uint8,uint256)" ) => KV0_x:Int ) : ( ( 645326474426547203313410069153905908525362434349 => 319 ) : ( ( 0 => selector ( "test_forgetBranch(uint256)" ) ) : ( ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) => .WordStack ) ) ) ) )
+
+
+ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s" +Bytes #buf ( 32 , KV0_x:Int ) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8"
+
+
+ 0
+
+
+ 0
+
+
+ false
+
+
+ 0
+
+ ...
+
+
+
+ .List
+
+
+ 0
+
+
+ SetItem ( 645326474426547203313410069153905908525362434349 )
+
+
+ .Map
+
+ ...
+
+
+ ORIGIN_ID:Int
+
+
+
+ NUMBER_CELL:Int
+
+
+ TIMESTAMP_CELL:Int
+
+ ...
+
+ ...
+
+
+
+ 1
+
+
+ (
+
+ 645326474426547203313410069153905908525362434349
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 0
+
+ ...
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 1
+
+ ...
+ )
+
+ ...
+
+
+ ...
+
+
+ false
+
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+ .List
+
+
+
+ .MockCallCellMap
+
+
+ .MockFunctionCellMap
+
+
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+
+ requires ( 0 <=Int KV0_x:Int
+ andBool ( 0 <=Int CALLER_ID:Int
+ andBool ( 0 <=Int ORIGIN_ID:Int
+ andBool ( pow24
+
+
+ ( JUMPI 1326 bool2Word ( KV0_x:Int <=Int 200 )
+ ~> #pc [ JUMPI ]
~> #execute => #halt ~> .K )
~> _CONTINUATION
@@ -580,10 +872,254 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
0
- ( ( 228 => selector ( "test_forgetBranch(uint256)" ) ) : ( ( selector ( "forgetBranch(uint256,uint8,uint256)" ) : ( 645326474426547203313410069153905908525362434349 : ( 0 : ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) ) ) ) => .WordStack ) )
+ ( ( 0 => selector ( "test_forgetBranch(uint256)" ) ) : ( ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) => .WordStack ) )
- b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05" +Bytes #buf ( 32 , KV0_x:Int )
+ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s" +Bytes #buf ( 32 , KV0_x:Int ) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8"
+
+
+ 0
+
+
+ 0
+
+
+ false
+
+
+ 0
+
+ ...
+
+
+
+ .List
+
+
+ 0
+
+
+ SetItem ( 645326474426547203313410069153905908525362434349 )
+
+
+ .Map
+
+ ...
+
+
+ ORIGIN_ID:Int
+
+
+
+ NUMBER_CELL:Int
+
+
+ TIMESTAMP_CELL:Int
+
+ ...
+
+ ...
+
+
+
+ 1
+
+
+ (
+
+ 645326474426547203313410069153905908525362434349
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 0
+
+ ...
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ 0
+
+
+ .Map
+
+
+ .Map
+
+
+ .Map
+
+
+ 1
+
+ ...
+ )
+
+ ...
+
+
+ ...
+
+
+ false
+
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+ ...
+
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+ .List
+
+
+
+ .MockCallCellMap
+
+
+ .MockFunctionCellMap
+
+
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ .List
+
+
+
+ requires ( 0 <=Int KV0_x:Int
+ andBool ( KV0_x:Int <=Int 200
+ andBool ( 0 <=Int CALLER_ID:Int
+ andBool ( 0 <=Int ORIGIN_ID:Int
+ andBool ( pow24
+
+
+ ( JUMPI 1326 bool2Word ( KV0_x:Int <=Int 200 )
+ ~> #pc [ JUMPI ]
+ ~> #execute => #halt ~> .K )
+ ~> _CONTINUATION
+
+
+ NORMAL
+
+
+ CANCUN
+
+
+ false
+
+
+
+
+
+ ( _STATUSCODE => EVMC_SUCCESS )
+
+
+ .List
+
+
+ .List
+
+
+ .Set
+
+
+
+ 728815563385977040452943777879061427756277306518
+
+
+ CALLER_ID:Int
+
+
+ b"P#a\xd8" +Bytes #buf ( 32 , KV0_x:Int )
+
+
+ 0
+
+
+ ( ( 0 => selector ( "test_forgetBranch(uint256)" ) ) : ( ( KV0_x:Int : ( 319 : ( selector ( "test_forgetBranch(uint256)" ) : .WordStack ) ) ) => .WordStack ) )
+
+
+ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x949s" +Bytes #buf ( 32 , KV0_x:Int ) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8"
0
@@ -774,7 +1310,7 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
andBool ( ( notBool #range ( 0 < CALLER_ID:Int <= 9 ) )
andBool ( ( notBool #range ( 0 < ORIGIN_ID:Int <= 9 ) )
))))))))))))))))
- [priority(20), label(BASIC-BLOCK-4-TO-5)]
+ [priority(20), label(BASIC-BLOCK-7-TO-9)]
endmodule
0 Failure nodes. (0 pending and 0 failing)
diff --git a/src/tests/integration/test-data/src/ForgetBranch.t.sol b/src/tests/integration/test-data/src/ForgetBranch.t.sol
index a813ac129..fe4064aa8 100644
--- a/src/tests/integration/test-data/src/ForgetBranch.t.sol
+++ b/src/tests/integration/test-data/src/ForgetBranch.t.sol
@@ -11,7 +11,7 @@ contract ForgetBranchTest is Test, KontrolCheats {
uint256 y;
vm.assume(x > 200);
- kevm.forgetBranch(200, KontrolCheatsBase.ComparisonOperator.GreaterThan, x);
+ kevm.forgetBranch(x, KontrolCheatsBase.ComparisonOperator.GreaterThan, 200);
if(x > 200){
y = 21;
} else {
From 2652f5874a62abdaa15a00b5777b7cf488d8b873 Mon Sep 17 00:00:00 2001
From: Andrei <16517508+anvacaru@users.noreply.github.com>
Date: Thu, 23 Jan 2025 09:52:06 +0200
Subject: [PATCH 17/17] update expected output
---
...BranchTest.test_forgetBranch(uint256).expected | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected b/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
index 75243bf5d..aec40fd4a 100644
--- a/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
+++ b/src/tests/integration/test-data/show/ForgetBranchTest.test_forgetBranch(uint256).expected
@@ -177,6 +177,9 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
.Map
+
+ .Set
+
...
@@ -419,6 +422,9 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
.Map
+
+ .Set
+
...
@@ -661,6 +667,9 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
.Map
+
+ .Set
+
...
@@ -904,6 +913,9 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
.Map
+
+ .Set
+
...
@@ -1148,6 +1160,9 @@ module SUMMARY-TEST%FORGETBRANCHTEST.TEST-FORGETBRANCH(UINT256):0
.Map
+
+ .Set
+
...