GovernorBase.spec 5.2 KB

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