GovernorInvariants.spec 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import "helpers/helpers.spec"
  2. import "helpers/Governor.helpers.spec"
  3. /*
  4. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  5. │ Invariant: clock is consistent between the goernor and the token │
  6. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  7. */
  8. rule clockMode(env e) {
  9. require clockSanity(e);
  10. assert clock(e) == e.block.number || clock(e) == e.block.timestamp;
  11. assert clock(e) == token_clock(e);
  12. /// This causes a failure in the prover
  13. // assert CLOCK_MODE(e) == token_CLOCK_MODE(e);
  14. }
  15. /*
  16. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  17. │ Invariant: Votes start and end are either initialized (non zero) or uninitialized (zero) simultaneously │
  18. │ │
  19. │ This invariant assumes that the block number cannot be 0 at any stage of the contract cycle │
  20. │ This is very safe assumption as usually the 0 block is genesis block which is uploaded with data │
  21. │ by the developers and will not be valid to raise proposals (at the current way that block chain is functioning) │
  22. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  23. */
  24. invariant proposalStateConsistency(uint256 pId)
  25. (proposalProposer(pId) == 0 <=> proposalSnapshot(pId) == 0) &&
  26. (proposalProposer(pId) == 0 <=> proposalDeadline(pId) == 0)
  27. {
  28. preserved with (env e) {
  29. require clockSanity(e);
  30. }
  31. }
  32. /*
  33. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  34. │ Invariant: votes recorded => created │
  35. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  36. */
  37. invariant votesImplyCreated(uint256 pId)
  38. (
  39. getAgainstVotes(pId) > 0 ||
  40. getForVotes(pId) > 0 ||
  41. getAbstainVotes(pId) > 0
  42. ) => proposalCreated(pId)
  43. {
  44. preserved with (env e) {
  45. require clockSanity(e);
  46. requireInvariant proposalStateConsistency(pId);
  47. }
  48. }
  49. /*
  50. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  51. │ Invariant: cancel => created │
  52. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  53. */
  54. invariant canceledImplyCreated(uint pId)
  55. isCanceled(pId) => proposalCreated(pId)
  56. {
  57. preserved with (env e) {
  58. require clockSanity(e);
  59. requireInvariant proposalStateConsistency(pId);
  60. }
  61. }
  62. /*
  63. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  64. │ Invariant: executed => created │
  65. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  66. */
  67. invariant executedImplyCreated(uint pId)
  68. isExecuted(pId) => proposalCreated(pId)
  69. {
  70. preserved with (env e) {
  71. require clockSanity(e);
  72. requireInvariant proposalStateConsistency(pId);
  73. }
  74. }
  75. /*
  76. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  77. │ Invariant: queued => created │
  78. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  79. */
  80. invariant queuedImplyCreated(uint pId)
  81. isQueued(pId) => proposalCreated(pId)
  82. {
  83. preserved with (env e) {
  84. require clockSanity(e);
  85. requireInvariant proposalStateConsistency(pId);
  86. }
  87. }
  88. /*
  89. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  90. │ Invariant: timings │
  91. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  92. */
  93. invariant votesImplySnapshotPassed(env e, uint256 pId)
  94. (
  95. getAgainstVotes(pId) > 0 ||
  96. getForVotes(pId) > 0 ||
  97. getAbstainVotes(pId) > 0
  98. ) => proposalSnapshot(pId) < clock(e)
  99. {
  100. preserved with (env e2) {
  101. // In this invariant, `env e` is representing the present. And `clock(e)` the current timestamp.
  102. // It should hold for any transitions in the pasts
  103. require clock(e2) <= clock(e);
  104. }
  105. }
  106. invariant queuedImplyDeadlineOver(env e, uint pId)
  107. isQueued(pId) => proposalDeadline(pId) < clock(e)
  108. {
  109. preserved {
  110. require clockSanity(e);
  111. requireInvariant proposalStateConsistency(pId);
  112. }
  113. }
  114. /*
  115. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  116. │ Invariant: Votes start before it ends │
  117. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  118. */
  119. invariant voteStartBeforeVoteEnd(uint256 pId)
  120. proposalSnapshot(pId) <= proposalDeadline(pId)
  121. {
  122. preserved {
  123. requireInvariant proposalStateConsistency(pId);
  124. }
  125. }
  126. /*
  127. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  128. │ Invariant: A proposal cannot be both executed and canceled simultaneously │
  129. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  130. */
  131. invariant noBothExecutedAndCanceled(uint256 pId)
  132. !isExecuted(pId) || !isCanceled(pId)
  133. /*
  134. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  135. │ Invariant: the "governance call" dequeue is empty │
  136. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  137. */
  138. invariant governanceCallLength()
  139. governanceCallLength() == 0