Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Output counterexamples for failed Foundry proofs #1946

Merged
merged 15 commits into from
Jul 12, 2023

Conversation

palinatolmach
Copy link
Contributor

@palinatolmach palinatolmach commented Jul 7, 2023

Closes #1927.

  1. Using get-model request, adds concrete counterexamples (i.e., models) of failing and pending nodes to print_failure_info(proof, kcfg_explore).
    UPDATE: after a discussion with @nwatson22, we decided that we should probably only show counterexamples for failing (not pending) nodes by default.
    This information is shown in the output of foundry-prove if any of the proofs has failed, or foundry-show --failure-information. Also, prints the invitation to the Discord channel once in print_failure_info(print_failure_info(proof, kcfg_explore) (instead of printing it with every failing node info), and fixes the link to the channel.
    UPDATE: the counterexample is generated if foundry-prove and foundry-show are called with the --counterexample-information option.
    The output looks like this:
> `kevm foundry-prove --test ExampleTest.testBackdoor`

... 

PROOF FAILED: ExampleTest.testBackdoor
1 Failure nodes. (0 pending and 1 failing)

Failing nodes:

  Node id: 20
  Failure reason:
    Implication check failed, the following is the remaining implication:
    ( ( { true #Equals 0 <=Int CALLER_ID:Int }
    ...
  Path condition:
    { true #Equals chop ... ==Int 0 }
  Model:
    CALLER_ID = 0
    NUMBER_CELL = 0
    ORIGIN_ID = maxUInt160
    VV0_x_114b9705 = 6912213124124532

Join the Runtime Verification Discord server for support: https://discord.com/invite/CurfmXNtbN

Access documentation for KEVM foundry integration at https://docs.runtimeverification.com/kevm-integration-for-foundry/
  1. Adds foundry-get-model command that shows models of nodes from a specific test. Can be called with --node NODE_ID, --failing, and --pending options. If none of these arguments are provided, the models of failing and pending nodes will be shown (i.e., missing --node, --failing and/or --pending is equivalent to --failing --pending), and a corresponding warning is shown to the user. The output looks like this:
> kevm foundry-get-model ExampleTest.testBackdoor --node 20

Node id: 20
  Model:
    CALLER_ID = 0
    NUMBER_CELL = 0
    ORIGIN_ID = maxUInt160
    VV0_x_114b9705 = 6912213124124532

Comment on lines +233 to +244
def print_model(node: KCFG.Node, kcfg_explore: KCFGExplore) -> list[str]:
res_lines: list[str] = []
result_subst = kcfg_explore.cterm_get_model(node.cterm)
if type(result_subst) is Subst:
res_lines.append(' Model:')
for var, term in result_subst.to_dict().items():
term_kast = KInner.from_dict(term)
res_lines.append(f' {var} = {kcfg_explore.kprint.pretty_print(term_kast)}')
else:
res_lines.append(' Failed to generate a model.')

return res_lines
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We rewrote the print_failure_info function in pyk to separate the printing from the RPC calls here: runtimeverification/pyk@6c28b66
Possibly we would want to do something similar here, since it makes testing cleaner. I realized we haven't updated kevm to use that function yet and we still just use the kevm version, so actually we can probably just refactor this when we make those changes later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Noah! I can probably try integrating the new failure_info function into kevm to include it in this PR, if this works--will update you on that tomorrow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, didn't have a chance to do this, and I'll unfortunately be travelling starting tomorrow. Could you please advise if we should merge it in as it is and refactor print_failure_info later? I'll create a separate issue for it, in this case.

Comment on lines 831 to 832
model_info = print_model(node, kcfg_explore)
res_lines.extend(model_info)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
model_info = print_model(node, kcfg_explore)
res_lines.extend(model_info)
res_lines.extend(print_model(node, kcfg_explore))

I'm not sure which is better (same for other places this occurs).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I agree, done in 13c0f97.

@palinatolmach
Copy link
Contributor Author

Updates: (1) added the temporary --counterexample-information option to foundry-prove and foundry-show, which generates the counterexample for each failing node and adds it to the output. Since it's currently part of the print_failure_info() implementation, in foundry-show, it should be called with the --failure-information option (it's reflected in its description), i.e., foundry-show --failure-information --counterexample-information. The purpose of adding this option is to make sure this change (and the SMT solver requests it includes) doesn't cause major performance issues, while we test it a bit more.

(2) when foundry-prove --counterexample-information is called, the counterexamples are only generated for failing (and not pending) nodes.

@palinatolmach palinatolmach marked this pull request as ready for review July 12, 2023 04:28
@@ -795,6 +797,44 @@ def foundry_section_edge(
apr_proof.write_proof()


def foundry_get_model(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should produce a data structure (maybe FoundryModel | None). Function print_model can be a method on this class (without the "Failed to ..." branch). Function print_failure_info then can be redefined as

def print_failure_info(kprint: KPrint, proof: Proof, *, model: FoundryModel | None = None) -> list[str]:
    ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I agree! Will add the FoundryModel class and modify the printing functions accordingly (there's some more refactoring to be done, as suggested by @nwatson22), but I need a bit more time to work on it. Would you recommend to merge the current PR and refactor it later, or should I include this change in this PR? Thank you!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine either way. If you decide to merge now, please open an issue to document the requested changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue created: #1955

@palinatolmach palinatolmach merged commit cf3b0f7 into master Jul 12, 2023
@palinatolmach palinatolmach deleted the foundry-counterexamples branch July 12, 2023 12:59
iFrostizz pushed a commit that referenced this pull request Aug 28, 2023
* Showing counterexamples for failed Foundry tests

* Add `smt-hook` to `chop` for SMT solving

* Prettier counterexample printing

* Revert `smtlib` -> `smt-hook` change to `chop` after fix

* Fixed Discord link, counterexample error message

* Refactor `print_failure_info`, add counterexamples

* Add `foundry-get-model` command

* Fix merge conflicts

* Show Discord invite once in `print_failure_info`

* Minor code quality fix

* Set Version: 1.0.232

* Minor code refactor; update tests w/new output

* Remove pending nodes model generation by default

* Add `--counterexample-information` to prove, show

* Use `counterexample_info=True` in Foundry tests

---------

Co-authored-by: devops <devops@runtimeverification.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Output concrete counter-example for failed proofs
3 participants