-
Notifications
You must be signed in to change notification settings - Fork 150
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
Execution of contract initialization code #2020
Conversation
…ing contract init code
…nit code proof, expand macros in all initial nodes for proofs with multiple start points
…m after account cell replacement
…timeverification/evm-semantics into noah/contract-initialization
I've now implemented a third execution stage for contract symbolic execution which runs the contract initialization code. One problem I'm not sure how to handle is that the constructor, if not marked Still to do:
|
…or compound proof not being set correctly
…timeverification/evm-semantics into noah/contract-initialization
…timeverification/evm-semantics into noah/contract-initialization
…onstructor parameter its own test function
…timeverification/evm-semantics into noah/contract-initialization
Thanks @nwatson22! It's better to check this, but I'm almost certain that Foundry runs every test on the state produced by the execution of the I found this discussion in Foundry's repo which suggests that a test should be using either
Considering this, I was thinking that we might execute either initialization code or @ehildenb @RaoulSchaffranek @iFrostizz do you guys have any suggestions and/or experience with the contracts containing the initialization code we didn't consider? |
…onstructor proof caching
… is specified, warn if associated method is out of date
…timeverification/evm-semantics into noah/contract-initialization
…timeverification/evm-semantics into noah/contract-initialization
@nwatson22 can you move this PR over to runtimeverification/kontrol repo instead? |
Moved to kontrol: runtimeverification/kontrol#54 |
The solidity compiler gives us two EVM bytecode strings per contract, a
deployedBytecode
andbytecode
field. The first is the bytecode that will actually exist on the blockchain and the second is the code that only runs once when the contract is created, returns thedeployedBytecode
, and then is discarded. For our purposes thebytecode
is where the contract constructor code is automatically run, and any default variable assignments like in:Currently the
bytecode
field is ignored by KEVM. For engagements we had been using workarounds such as moving any variable initializations into the constructor and calling the constructor at the top of the methods we are actually executing. However this is especially important to avoid having to do for other people's foundry tests, because if you modify them like that, you arguably aren't actually verifying the same test.While the constructor is actually contained as a function call available in
deployedBytecode
, from what I understand, the contract-level default variable assignments are not accessible unless we bring in thebytecode
. I've done that here by creating a different macro#initBytecode
which is an analogue of#binRuntime
and rewrites to the initialization bytecode of the contract.The difference between the constructor/initialization code and the
setUp()
function, which is built into foundry, and which we already handle, is thesetUp()
function is run before every test by foundry, whereas I guess there is no guarantee that this will be the case for the former, so perhaps a test like this:would not actually make any sense because as soon as you start adding other tests that could change the value of a, it's not necessarily going to pass depending on the order the tests are run in.
For this reason I think we need to have a discussion on what a sensible default should be for "what state should the contract be in when we execute a method". My initial thought would just be to assume the contract has just been initialized for each method, and to possibly provide some sort of interface for selecting a different option, but I would want to hear from people who have actually used the Kontrol tool in engagements.
An additional concern I have is that the implementation I am envisioning would treat the initialization as a separate execution step, similar to how we already treat the
setUp()
function, since the "initial state" generated from this step would be shared among all tests in the contract. But this would create yet another stage slowing down execution + slowing down the CI job, and this stage wouldn't be avoidable as thesetUp()
function is by not including the function. (Every contract has this initialization step, although possibly we could make it optional to skip it as in many cases it doesn't do anything for our purposes, i.e., if there is no constructor and no default values to storage vars).