GovernorBase.spec 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Governor.sol base definitions
  2. methods {
  3. proposalSnapshot(uint256) returns uint256 envfree // matches proposalVoteStart
  4. proposalDeadline(uint256) returns uint256 envfree
  5. hashProposal(address[],uint256[],bytes[],bytes32) returns uint256 envfree
  6. isExecuted(uint256) returns bool envfree
  7. isCanceled(uint256) returns bool envfree
  8. // internal functions made public in harness:
  9. _quorumReached(uint256) returns bool envfree
  10. _voteSucceeded(uint256) returns bool envfree
  11. }
  12. /*
  13. ghost proposalVoteStart(uint256) returns uint64 {
  14. init_state axiom forall uint256 pId. proposalVoteStart(pId) == 0;
  15. }
  16. ghost proposalVoteEnd(uint256) returns uint64 {
  17. init_state axiom forall uint256 pId. proposalVoteEnd(pId) == 0;
  18. }
  19. */
  20. /*
  21. ghost proposalExecuted(uint256) returns bool {
  22. init_state axiom forall uint256 pId. !proposalExecuted(pId);
  23. }
  24. ghost proposalCanceled(uint256) returns bool {
  25. init_state axiom forall uint256 pId. !proposalCanceled(pId);
  26. }
  27. */
  28. /*
  29. hook Sstore _proposals[KEY uint256 pId].voteStart._deadline uint64 newValue STORAGE {
  30. havoc proposalVoteStart assuming (
  31. proposalVoteStart@new(pId) == newValue
  32. && (forall uint256 pId2. pId != pId2 => proposalVoteStart@new(pId2) == proposalVoteStart@old(pId2))
  33. );
  34. }
  35. hook Sload uint64 value _proposals[KEY uint256 pId].voteStart._deadline STORAGE {
  36. require proposalVoteStart(pId) == value;
  37. }
  38. hook Sstore _proposals[KEY uint256 pId].voteEnd._deadline uint64 newValue STORAGE {
  39. havoc proposalVoteEnd assuming (
  40. proposalVoteEnd@new(pId) == newValue
  41. && (forall uint256 pId2. pId != pId2 => proposalVoteEnd@new(pId2) == proposalVoteEnd@old(pId2))
  42. );
  43. }
  44. hook Sload uint64 value _proposals[KEY uint256 pId].voteEnd._deadline STORAGE {
  45. require proposalVoteEnd(pId) == value;
  46. }
  47. */
  48. //////////////////////////////////////////////////////////////////////////////
  49. //////////////////////////// SANITY CHECKS ///////////////////////////////////
  50. //////////////////////////////////////////////////////////////////////////////
  51. //
  52. /*
  53. rule sanityCheckVoteStart(method f, uint256 pId) {
  54. uint64 preGhost = _proposals(pId).voteStart._deadline;
  55. uint256 pre = proposalSnapshot(pId);
  56. env e;
  57. calldataarg arg;
  58. f(e, arg);
  59. uint64 postGhost = _proposals(pId).voteStart._deadline;
  60. uint256 post = proposalSnapshot(pId);
  61. assert preGhost == postGhost <=> pre == post, "ghost changes are correlated with getter changes";
  62. assert pre == preGhost => post == postGhost, "if correlated at the beginning should be correlated at the end";
  63. }
  64. rule sanityCheckVoteEnd(method f, uint256 pId) {
  65. uint64 preGhost = proposalVoteEnd(pId);
  66. uint256 pre = proposalSnapshot(pId);
  67. env e;
  68. calldataarg arg;
  69. f(e, arg);
  70. uint64 postGhost = proposalVoteEnd(pId);
  71. uint256 post = proposalSnapshot(pId);
  72. assert preGhost == postGhost <=> pre == post, "ghost changes are correlated with getter changes";
  73. assert pre == preGhost => post == postGhost, "if correlated at the beginning should be correlated at the end";
  74. }
  75. */
  76. //////////////////////////////////////////////////////////////////////////////
  77. ////////////////////////////// INVARIANTS ////////////////////////////////////
  78. //////////////////////////////////////////////////////////////////////////////
  79. //
  80. invariant inizialized()
  81. forall uint256 pId. proposalSnapshot(pId) != 0 && proposalDeadline(pId) != 0
  82. => pId != 0
  83. invariant uninizialized(uint256 pId)
  84. proposalSnapshot(pId) == 0 => proposalDeadline(pId) == 0
  85. /**
  86. * A proposal cannot end unless it started.
  87. */
  88. //invariant voteStartBeforeVoteEnd1(uint256 pId) proposalSnapshot(pId) < proposalDeadline(pId)
  89. // ALARM
  90. invariant voteStartBeforeVoteEnd(uint256 pId)
  91. (proposalSnapshot(pId) == 0 <=> proposalDeadline(pId) == 0) &&
  92. proposalSnapshot(pId) < proposalDeadline(pId)
  93. /**
  94. * A proposal cannot be both executed and canceled.
  95. */
  96. // @AK - no violations
  97. invariant noBothExecutedAndCanceled(uint256 pId) !isExecuted(pId) || !isCanceled(pId)
  98. /**
  99. * A proposal cannot be neither executed nor canceled before it starts
  100. */
  101. // @AK - violations convert to a rule
  102. invariant noExecuteOrCancelBeforeStarting(env e, uint256 pId) e.block.number < proposalSnapshot(pId)
  103. => !isExecuted(pId) && !isCanceled(pId)
  104. /**
  105. * A proposal could be executed only if quorum was reached and vote succeeded
  106. */
  107. // @AK - no violations
  108. invariant executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId) isExecuted(pId) => _quorumReached(pId) && _voteSucceeded(pId)
  109. /**
  110. * The voting must start not before the proposal’s creation time
  111. */
  112. rule noStartBeforeCreation(uint256 pId) {
  113. uint previousStart = proposalSnapshot(pId);
  114. require previousStart == 0;
  115. env e;
  116. calldataarg arg;
  117. propose(e, arg);
  118. uint newStart = proposalSnapshot(pId);
  119. // if created, start is after creation
  120. assert newStart != 0 => newStart >= e.block.number;
  121. }
  122. /**
  123. * Check hashProposal hashing is reliable (different inputs lead to different buffers hashed)
  124. */
  125. /*
  126. rule checkHashProposal {
  127. address[] t1;
  128. address[] t2;
  129. uint256[] v1;
  130. uint256[] v2;
  131. bytes[] c1;
  132. bytes[] c2;
  133. bytes32 d1;
  134. bytes32 d2;
  135. uint256 h1 = hashProposal(t1,v1,c1,d1);
  136. uint256 h2 = hashProposal(t2,v2,c2,d2);
  137. bool equalHashes = h1 == h2;
  138. assert equalHashes => t1.length == t2.length;
  139. assert equalHashes => v1.length == v2.length;
  140. assert equalHashes => c1.length == c2.length;
  141. assert equalHashes => d1 == d2;
  142. }
  143. */
  144. /**
  145. * Once a proposal is created, voteStart and voteEnd are immutable
  146. */
  147. // @AK - no violations
  148. rule immutableFieldsAfterProposalCreation(uint256 pId, method f) {
  149. uint _voteStart = proposalSnapshot(pId);
  150. uint _voteEnd = proposalDeadline(pId);
  151. require _voteStart > 0; // proposal was created
  152. env e;
  153. calldataarg arg;
  154. f(e, arg);
  155. uint voteStart_ = proposalSnapshot(pId);
  156. uint voteEnd_ = proposalDeadline(pId);
  157. assert _voteStart == voteStart_;
  158. assert _voteEnd == voteEnd_;
  159. }