GovernorBase.spec 5.3 KB

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