GovernorBase.spec 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. //////////////////////////////////////////////////////////////////////////////
  2. ///////////////////// Governor.sol base definitions //////////////////////////
  3. //////////////////////////////////////////////////////////////////////////////
  4. methods {
  5. proposalSnapshot(uint256) returns uint256 envfree // matches proposalVoteStart
  6. proposalDeadline(uint256) returns uint256 envfree
  7. hashProposal(address[],uint256[],bytes[],bytes32) returns uint256 envfree
  8. isExecuted(uint256) returns bool envfree
  9. isCanceled(uint256) returns bool envfree
  10. execute(address[], uint256[], bytes[], bytes32) returns uint256
  11. // initialized(uint256) returns bool envfree
  12. hasVoted(uint256, address) returns bool
  13. castVote(uint256, uint8) returns uint256
  14. // internal functions made public in harness:
  15. _quorumReached(uint256) returns bool envfree
  16. _voteSucceeded(uint256) returns bool envfree
  17. }
  18. //////////////////////////////////////////////////////////////////////////////
  19. ////////////////////////////// INVARIANTS ////////////////////////////////////
  20. //////////////////////////////////////////////////////////////////////////////
  21. /*
  22. * A proposal cannot end unless it started.
  23. */
  24. invariant voteStartBeforeVoteEnd(uint256 pId)
  25. (proposalSnapshot(pId) > 0 => proposalSnapshot(pId) < proposalDeadline(pId))
  26. && (proposalSnapshot(pId) == 0 => proposalDeadline(pId) == 0)
  27. /**
  28. * A proposal cannot be both executed and canceled.
  29. */
  30. invariant noBothExecutedAndCanceled(uint256 pId)
  31. !isExecuted(pId) || !isCanceled(pId)
  32. /**
  33. * A proposal could be executed only if quorum was reached and vote succeeded
  34. */
  35. invariant executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId)
  36. isExecuted(pId) => _quorumReached(pId) && _voteSucceeded(pId)
  37. //////////////////////////////////////////////////////////////////////////////
  38. /////////////////////////////////// RULES ////////////////////////////////////
  39. //////////////////////////////////////////////////////////////////////////////
  40. /*
  41. * No functions should be allowed to run after a job is deemed as canceled
  42. */
  43. rule cannotSetIfCanceled(uint256 pId, method f) filtered { f-> !f.isView }{
  44. require(isCanceled(pId));
  45. env e; calldataarg args;
  46. f(e, args);
  47. assert(isCanceled(pId) => lastReverted == true, "Function did not revert when canceled");
  48. }
  49. /*
  50. * No functions should be allowed to run after a job is deemed as executed
  51. */
  52. rule cannotSetIfExecuted(uint256 pId, method f) filtered { f-> !f.isView }{
  53. require(isExecuted(pId));
  54. env e; calldataarg args;
  55. f(e, args);
  56. assert(isExecuted(pId) => lastReverted == true, "Function did not revert after executed");
  57. }
  58. /*
  59. * The voting must start not before the proposal’s creation time
  60. */
  61. rule noStartBeforeCreation(uint256 pId) {
  62. uint previousStart = proposalSnapshot(pId);
  63. require previousStart == 0;
  64. env e;
  65. calldataarg arg;
  66. propose(e, arg);
  67. uint newStart = proposalSnapshot(pId);
  68. // if created, start is after creation
  69. assert(newStart != 0 => newStart >= e.block.number);
  70. }
  71. /*
  72. * Once a proposal is created, voteStart and voteEnd are immutable
  73. */
  74. rule immutableFieldsAfterProposalCreation(uint256 pId, method f) {
  75. uint _voteStart = proposalSnapshot(pId);
  76. uint _voteEnd = proposalDeadline(pId);
  77. require _voteStart > 0; // proposal was created
  78. env e;
  79. calldataarg arg;
  80. f(e, arg);
  81. uint voteStart_ = proposalSnapshot(pId);
  82. uint voteEnd_ = proposalDeadline(pId);
  83. assert _voteStart == voteStart_;
  84. assert _voteEnd == voteEnd_;
  85. }
  86. /*
  87. * A user cannot vote twice
  88. */
  89. rule doubleVoting(uint256 pId, uint8 sup) {
  90. env e;
  91. address user = e.msg.sender;
  92. bool votedCheck = hasVoted(e, pId, user);
  93. castVote@withrevert(e, pId, sup);
  94. bool reverted = lastReverted;
  95. assert votedCheck => reverted, "double voting accured";
  96. }
  97. /*
  98. * When a proposal is created the start and end date are created in the future.
  99. */
  100. rule proposalCreatedStartAndEndDateInFuture(address[] targets, uint256[] values, bytes[] calldatas){
  101. env e;
  102. uint256 pId = callPropose(e, targets, values, calldatas);
  103. uint256 startDate = proposalSnapshot(pId);
  104. uint256 endDate = proposalDeadline(pId);
  105. assert(startDate >= e.block.number && endDate >= e.block.number, "Start or end date were set in the past");
  106. }
  107. /**
  108. * Check hashProposal hashing is reliable (different inputs lead to different buffers hashed)
  109. */
  110. /*
  111. rule checkHashProposal {
  112. address[] t1;
  113. address[] t2;
  114. uint256[] v1;
  115. uint256[] v2;
  116. bytes[] c1;
  117. bytes[] c2;
  118. bytes32 d1;
  119. bytes32 d2;
  120. uint256 h1 = hashProposal(t1,v1,c1,d1);
  121. uint256 h2 = hashProposal(t2,v2,c2,d2);
  122. bool equalHashes = h1 == h2;
  123. assert equalHashes => t1.length == t2.length;
  124. assert equalHashes => v1.length == v2.length;
  125. assert equalHashes => c1.length == c2.length;
  126. assert equalHashes => d1 == d2;
  127. }
  128. */
  129. /**
  130. * A proposal cannot be neither executed nor canceled before it starts
  131. */
  132. rule noExecuteOrCancelBeforeStarting(uint256 pId, method f){
  133. env e;
  134. require !isExecuted(pId) && !isCanceled(pId);
  135. calldataarg arg;
  136. f(e, arg);
  137. assert e.block.number < proposalSnapshot(pId) => (!isExecuted(pId) && !isCanceled(pId)), "executed/cancelled before start";
  138. }
  139. /**
  140. * A proposal cannot be neither executed nor canceled before proposal's deadline
  141. */
  142. rule noExecuteOrCancelBeforeDeadline(uint256 pId, method f){
  143. env e;
  144. requireInvariant voteStartBeforeVoteEnd(pId);
  145. require !isExecuted(pId) && !isCanceled(pId);
  146. calldataarg arg;
  147. f(e, arg);
  148. assert e.block.number < proposalDeadline(pId) => (!isExecuted(pId) && !isCanceled(pId)), "executed/cancelled before start";
  149. }