-
Notifications
You must be signed in to change notification settings - Fork 51
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
Fix in equivalence checking #650
base: main
Are you sure you want to change the base?
Conversation
Just a note to self, the issue is:
Where the first part of the |
So with some digging: resultsDiffer :: Expr End -> Expr End -> Prop
resultsDiffer aEnd bEnd = case (aEnd, bEnd) of
(Success _ _ aOut aState, Success _ _ bOut bState) ->
case (aOut == bOut, aState == bState) of
(True, True) -> PBool False
(False, True) -> aOut ./= bOut
(True, False) -> statesDiffer aState bState
(False, False) -> statesDiffer aState bState .|| aOut ./= bOut where There, aOut and bOut are actually different -- they are the concrete bytecode that gets deployed onchain, as the contract code. This is because when the init code is executed, the returndata is the final contract code. So the outputs differ, because they deploy different contracts! NOTE: |
What we COULD do, is for such initcode we actually do two checks -- one that the state is the same after deployment (i.e.
Note that SOME of the deployed code could be abstract -- the initcode could actually take parameters and place them into the aOut/bOut as symbolic values (filling in constants), though that's not the case with the simple initcode above. Thes kinds of symbolic values in the deployed contract is fine as long as it's not code, but data. The |
Just some update. A stupid verison of this is already running. It doesn't yet deal with: contract C {
uint x;
uint private immutable CONST_NUM;
constructor(uint k) {
CONST_NUM = k;
}
function stuff(uint a) public returns (uint256) {
unchecked {
return (a*2)+CONST_NUM;
}
}
} where the code returned is actually partially symbolic, which is what #649 is about, but I'm making progress. It should not be too big of a deal to make that work, either. There are some things that need to be ironed out, in particular, what the return signature of Anyway, for the moment, these: contract C {
uint x;
constructor() {
x = 0;
}
function stuff(uint a) public returns (uint256) {
unchecked {
return (a*2);
}
}
} and contract C {
uint x;
function stuff(uint a) public returns (uint256) {
unchecked {
return (a<<1);
}
}
} are compared and are deemed equivalent -- they are checked as expected, i.e. first for initcode, and then for the deployed code. The absolutely hideous code is at branch |
NOTE to self: I have a significantly improved version of this under branch |
Description
The equivalence checker was not taking into account that an empty store is equivalent to a store with all slots initialized to zero. This was not allowing us to prove equivalence for certain smart contracts.
Summary of Changes
symExec
function has now a flag that allows deployment code to be checked for equivalenceCloses #647.
Checklist