-
Notifications
You must be signed in to change notification settings - Fork 460
Description
Summary
In 🐍 snekmate, I run symbolic execution nightly tests in the CI based on halmos (latest master version) using the Yices SMT solver version 2.6.4:
- https://github.com/pcaversaccio/snekmate/blob/main/.github/workflows/halmos.yml,
- https://github.com/pcaversaccio/snekmate/blob/main/.github/workflows/halmos-venom.yml.
3 days ago the nightly tests started failing since they were running out of time (i.e. beyond the standard 3hrs GitHub threshold):
- https://github.com/pcaversaccio/snekmate/actions/workflows/halmos.yml,
- https://github.com/pcaversaccio/snekmate/actions/workflows/halmos-venom.yml.
After careful (and time-consuming lol) investigation, I was able to find the issue. I updated 4 days ago to the latest forge-std master commit c7be2a3. After running and testing the CI for hours, the following commit introduces the "regression": 276ccaa.
So what's the underlying problem? Specifically, my ERC1155TestHalmos test contract and its test testHalmosAssertNoBackdoor is running out of time. You can see the usage of assertLe and assertGe here:
for (uint256 i = 0; i < tokenIds.length; i++) {
assertLe(erc1155.balanceOf(caller, tokenIds[i]), oldBalanceCaller[i]);
assertGe(erc1155.balanceOf(other, tokenIds[i]), oldBalanceOther[i]);
}But also the test testHalmosSafeTransferFrom struggles since I use assertEq here:
if (from != to) {
assertEq(newBalanceFrom, oldBalanceFrom - amounts[0]);
assertEq(newBalanceTo, oldBalanceTo + amounts[0]);
} else {
assertEq(newBalanceFrom, oldBalanceFrom);
assertEq(newBalanceTo, oldBalanceTo);
}
assertEq(newBalanceOther, oldBalanceOther);The commit 276ccaa (and the refactor later 349b909) introduce additional branching conditions which produce a path explosion. I'm not a formal verification expert, so I can't explain exactly why, but you can see the tests here:
- https://github.com/pcaversaccio/snekmate/actions/runs/16704445274 (this is based on commit 369dd01 which is the last commit before you introduce the new logic),
- https://github.com/pcaversaccio/snekmate/actions/runs/16706057262 (this is based on commit 276ccaa).
There are 2 ways forward for me in the current status quo:
- Pin an older
forge-stdversion -> not sustainable - Directly use
vm.assertGeandvm.assertLe-> ugly solution
I'm not sure if you are open to reconsider this change, but it's important to understand that such small optimisation changes can have breaking impacts downstream.