-
Notifications
You must be signed in to change notification settings - Fork 37
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
Unclear semantics for environment variables in the invariant block #59
Comments
I'm not sure how hacky this sounds, but for the second case you could also do
Which doesn't really prove the same. We're still missing a mechanism to prove that something doesn't change after deployment. |
I find this pretty usatisfying tbh. It's a pretty common pattern and I think we need a cleaner way to handle stuff like this. |
@xwvvvvwx I'm not sure about this. If that's true, shouldn't https://github.com/ethereum/act/blob/master/tests/invariants/pass/ethEnv.act fail? |
Would it be completely crazy to allow all types of expressions as
Which is meant in the literal sense; |
Hmmmm, this is a very good point. Currently each invariant is split up into multiple queries (one for the constructor, and one for each case in the behaviours), we declare a fresh constant for each environment variable referenced by the behaviour or the invariant for each of these queries. The
This produces the following query for the invariant over the constructor: ;STORAGE:
(declare-const Env_value_post Int)
;CALLDATA:
;ENVIRONMENT:
(declare-const CALLVALUE Int)
;ASSERTIONS:
(assert (not (= Env_value_post CALLVALUE)))
(assert (and (<= 0 CALLVALUE) (<= CALLVALUE 115792089237316195423570985008687907853269984665640564039457584007913129639935)))
(assert (= Env_value_post CALLVALUE)) and for the invariant over the behaviour: ;STORAGE:
(declare-const Env_value_pre Int)
(declare-const Env_value_post Int)
;CALLDATA:
;ENVIRONMENT:
(declare-const CALLVALUE Int)
;ASSERTIONS:
(assert (= Env_value_pre CALLVALUE))
(assert (not (= Env_value_post CALLVALUE)))
(assert (and (<= 0 Env_value_pre) (<= Env_value_pre 115792089237316195423570985008687907853269984665640564039457584007913129639935)))
(assert (and (<= 0 CALLVALUE) (<= CALLVALUE 115792089237316195423570985008687907853269984665640564039457584007913129639935)))
(assert (= Env_value_pre Env_value_post) I'm actually not even sure what the semantics of environment variable references in the invariant blocks are in this case? As a final note, adding an |
In the second query, why is |
Oh I guess it's the pre part of the induction. |
yes, exactly |
I think the "problem" in the second query is that |
Can you also paste the check for that case? |
Sure, for the spec:
We generate the following querty for the ;STORAGE:
(declare-const Env_value_pre Int)
(declare-const Env_value_post Int)
;CALLDATA:
;ENVIRONMENT:
(declare-const CALLVALUE Int)
;ASSERTIONS:
(assert (not (= Env_value_pre CALLVALUE)))
(assert (and (<= 0 Env_value_pre) (<= Env_value_pre 115792089237316195423570985008687907853269984665640564039457584007913129639935)))
(assert (and (<= 0 CALLVALUE) (<= CALLVALUE 115792089237316195423570985008687907853269984665640564039457584007913129639935)))
(assert (= Env_value_pre Env_value_post))
Yes, this is the case |
You mean we should introduce a |
Only if that's the semantics we want haha.
|
I'm not even sure how to construct the queries so that |
I think the safe way is to give it a different name for every block it's part of. |
Isn't that already effectively the case? We construct a totally isolated query for each behaviour... |
Ah right, sorry, got confused again. I think the encoding of |
Taking this spec as an example:
I think this is actually impossible to implement in EVM. I don't see a way to implement I think that the nature of the inductive query implicitly forces the semantics that environment variable references in the invariant block refer to the value of that variable at constructor time? |
another alternative would be to not allow environment variables in invariant blocks at all. Restricting invariants to be formulas over state variables would make the matter moot. I think having environment variables in ensures blocks; |
I think I like this, removing all the constructor context from the invariants would also make the smt backend easier to implement. |
The semantics of invariants that refer to environment variables are currently very unclear. For example, does the following mean "
value
is always set to theCALLVALUE
as it was in the constructor" or "value
is always set to theCALLVALUE
as it is during each method call":As currently implemented the meaning is the second meaning (the value of the env var at the time of the method invocation).
After discussing this offline for a while (as well as in this pr), the consensus seems to be that the best approach is to seperate the
invariants
block from theconstructor
definition and to have the environment variables refer to the value of the variable during each method call.It can however sometimes be useful to be able to refer to the constructor arguments within the
invariants
block, for example:It would therefore perhaps be nice to allow
invariants
blocks to refer to constructor arguments in some way. Alternatively we may with to investigate adding some kind ofpre
/post
operators allowing us to reformulate the abovetotalSupply
invariant as:The text was updated successfully, but these errors were encountered: