123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- import "helpers/helpers.spec";
- methods {
- // library
- function add(bytes32) external returns (bool) envfree;
- function remove(bytes32) external returns (bool) envfree;
- function contains(bytes32) external returns (bool) envfree;
- function length() external returns (uint256) envfree;
- function at_(uint256) external returns (bytes32) envfree;
- // FV
- function _positionOf(bytes32) external returns (uint256) envfree;
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Helpers โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- definition sanity() returns bool =
- length() < max_uint256;
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: All indexed keys are contained โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant indexedContained(uint256 index)
- index < length() => contains(at_(index))
- {
- preserved {
- requireInvariant consistencyIndex(index);
- requireInvariant consistencyIndex(require_uint256(length() - 1));
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: A value can only be stored at a single location โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant atUniqueness(uint256 index1, uint256 index2)
- index1 == index2 <=> at_(index1) == at_(index2)
- {
- preserved remove(bytes32 key) {
- requireInvariant atUniqueness(index1, require_uint256(length() - 1));
- requireInvariant atUniqueness(index2, require_uint256(length() - 1));
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: index <> key relationship is consistent โ
- โ โ
- โ Note that the two consistencyXxx invariants, put together, prove that at_ and _positionOf are inverse of one โ
- โ another. This proves that we have a bijection between indices (the enumerability part) and keys (the entries that โ
- โ are added and removed from the EnumerableSet). โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant consistencyIndex(uint256 index)
- index < length() => _positionOf(at_(index)) == require_uint256(index + 1)
- {
- preserved remove(bytes32 key) {
- requireInvariant consistencyIndex(require_uint256(length() - 1));
- }
- }
- invariant consistencyKey(bytes32 key)
- contains(key) => (
- _positionOf(key) > 0 &&
- _positionOf(key) <= length() &&
- at_(require_uint256(_positionOf(key) - 1)) == key
- )
- {
- preserved remove(bytes32 otherKey) {
- requireInvariant consistencyKey(otherKey);
- requireInvariant atUniqueness(
- require_uint256(_positionOf(key) - 1),
- require_uint256(_positionOf(otherKey) - 1)
- );
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: state only changes by adding or removing elements โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule stateChange(env e, bytes32 key) {
- require sanity();
- requireInvariant consistencyKey(key);
- uint256 lengthBefore = length();
- bool containsBefore = contains(key);
- method f;
- calldataarg args;
- f(e, args);
- uint256 lengthAfter = length();
- bool containsAfter = contains(key);
- assert lengthBefore != lengthAfter => (
- (f.selector == sig:add(bytes32).selector && lengthAfter == require_uint256(lengthBefore + 1)) ||
- (f.selector == sig:remove(bytes32).selector && lengthAfter == require_uint256(lengthBefore - 1))
- );
- assert containsBefore != containsAfter => (
- (f.selector == sig:add(bytes32).selector && containsAfter) ||
- (f.selector == sig:remove(bytes32).selector && containsBefore)
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: check liveness of view functions. โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule liveness_1(bytes32 key) {
- requireInvariant consistencyKey(key);
- // contains never revert
- contains@withrevert(key);
- assert !lastReverted;
- }
- rule liveness_2(uint256 index) {
- requireInvariant consistencyIndex(index);
- // length never revert
- uint256 length = length@withrevert();
- assert !lastReverted;
- // at reverts iff the index is out of bound
- at_@withrevert(index);
- assert !lastReverted <=> index < length;
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: add key to EnumerableSet if not already contained โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule add(bytes32 key, bytes32 otherKey) {
- require sanity();
- uint256 lengthBefore = length();
- bool containsBefore = contains(key);
- bool containsOtherBefore = contains(otherKey);
- bool added = add@withrevert(key);
- bool success = !lastReverted;
- assert success && contains(key),
- "liveness & immediate effect";
- assert added <=> !containsBefore,
- "return value: added iff not contained";
- assert length() == require_uint256(lengthBefore + to_mathint(added ? 1 : 0)),
- "effect: length increases iff added";
- assert added => at_(lengthBefore) == key,
- "effect: add at the end";
- assert containsOtherBefore != contains(otherKey) => (added && key == otherKey),
- "side effect: other keys are not affected";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: remove key from EnumerableSet if already contained โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule remove(bytes32 key, bytes32 otherKey) {
- requireInvariant consistencyKey(key);
- requireInvariant consistencyKey(otherKey);
- uint256 lengthBefore = length();
- bool containsBefore = contains(key);
- bool containsOtherBefore = contains(otherKey);
- bool removed = remove@withrevert(key);
- bool success = !lastReverted;
- assert success && !contains(key),
- "liveness & immediate effect";
- assert removed <=> containsBefore,
- "return value: removed iff contained";
- assert length() == require_uint256(lengthBefore - to_mathint(removed ? 1 : 0)),
- "effect: length decreases iff removed";
- assert containsOtherBefore != contains(otherKey) => (removed && key == otherKey),
- "side effect: other keys are not affected";
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: when adding a new key, the other keys remain in set, at the same index. โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule addEnumerability(bytes32 key, uint256 index) {
- require sanity();
- bytes32 atBefore = at_(index);
- add(key);
- bytes32 atAfter = at_@withrevert(index);
- bool atAfterSuccess = !lastReverted;
- assert atAfterSuccess;
- assert atBefore == atAfter;
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: when removing a existing key, the other keys remain in set, at the same index (except for the last one). โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule removeEnumerability(bytes32 key, uint256 index) {
- uint256 last = require_uint256(length() - 1);
- requireInvariant consistencyKey(key);
- requireInvariant consistencyIndex(index);
- requireInvariant consistencyIndex(last);
- bytes32 atBefore = at_(index);
- bytes32 lastBefore = at_(last);
- remove(key);
- // can't read last value (length decreased)
- bytes32 atAfter = at_@withrevert(index);
- assert lastReverted <=> index == last;
- // One value that is allowed to change is if previous value was removed,
- // in that case the last value before took its place.
- assert (
- index != last &&
- atBefore != atAfter
- ) => (
- atBefore == key &&
- atAfter == lastBefore
- );
- }
|