halmos
halmos copied to clipboard
consider implementing strict/fail-fast/no-fork mode when running `setUp()`
Problem
sometimes symbolic state can cause forks during the execution of setUp()
in surprising ways. For instance:
// in a contract not meant to be deployed to a real network
// the fork is benign though, because we ignore the failing path
require(block.number < 100, "not for deployment");
// in a DeterministicAccountFactory contract
address account = getCreate2Address(salt);
if (account.code.length > 0) {
// already deployed
return account;
} else {
return deployAccount(salt);
}
This last example is trickier, account.code.length
is symbolic so we explore both sides of the conditional, and the account is only deployed in one of them. But the intent is that in setUp(), we do want to deploy the account, and if we arbitrarily pick the execution where the account is not deployed, then further tests will fail.
Proposed Solution
In this case, our current optimistic behavior (warn and pick an arbitrary execution) leads to a hard to debug issue. It would have been better to fail fast and say explicitly that there is a fork due to a condition on account.code.length
, which would be more actionable.