GovernorStates.spec 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import "helpers.spec"
  2. import "methods/IGovernor.spec"
  3. import "Governor.helpers.spec"
  4. import "GovernorInvariants.spec"
  5. use invariant proposalStateConsistency
  6. /*
  7. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  8. │ Rule: state returns one of the value in the enumeration │
  9. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  10. */
  11. rule stateConsistency(env e, uint256 pId) {
  12. uint8 result = state(e, pId);
  13. assert (
  14. result == PENDING() ||
  15. result == ACTIVE() ||
  16. result == CANCELED() ||
  17. result == DEFEATED() ||
  18. result == SUCCEEDED() ||
  19. result == QUEUED() ||
  20. result == EXECUTED()
  21. );
  22. }
  23. /*
  24. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  25. │ Rule: State transitions caused by function calls │
  26. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  27. */
  28. rule stateTransitionFn(uint256 pId, env e, method f, calldataarg args)
  29. filtered { f -> !skip(f) }
  30. {
  31. require clock(e) > 0; // Sanity
  32. uint8 stateBefore = state(e, pId);
  33. f(e, args);
  34. uint8 stateAfter = state(e, pId);
  35. assert (stateBefore != stateAfter) => (
  36. stateBefore == UNSET() => (
  37. stateAfter == PENDING() && f.selector == propose(address[],uint256[],bytes[],string).selector
  38. ) &&
  39. stateBefore == PENDING() => (
  40. (stateAfter == CANCELED() && f.selector == cancel(address[],uint256[],bytes[],bytes32).selector)
  41. ) &&
  42. stateBefore == SUCCEEDED() => (
  43. (stateAfter == QUEUED() && f.selector == queue(address[],uint256[],bytes[],bytes32).selector) ||
  44. (stateAfter == EXECUTED() && f.selector == execute(address[],uint256[],bytes[],bytes32).selector)
  45. ) &&
  46. stateBefore == QUEUED() => (
  47. (stateAfter == EXECUTED() && f.selector == execute(address[],uint256[],bytes[],bytes32).selector)
  48. ) &&
  49. stateBefore == ACTIVE() => false &&
  50. stateBefore == CANCELED() => false &&
  51. stateBefore == DEFEATED() => false &&
  52. stateBefore == EXECUTED() => false
  53. );
  54. }
  55. /*
  56. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  57. │ Rule: State transitions caused by time passing │
  58. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  59. */
  60. rule stateTransitionWait(uint256 pId, env e1, env e2) {
  61. require clock(e1) > 0; // Sanity
  62. require clock(e2) > clock(e1);
  63. uint8 stateBefore = state(e1, pId);
  64. uint8 stateAfter = state(e2, pId);
  65. assert (stateBefore != stateAfter) => (
  66. stateBefore == PENDING() => stateAfter == ACTIVE() &&
  67. stateBefore == ACTIVE() => (stateAfter == SUCCEEDED() || stateAfter == DEFEATED()) &&
  68. stateBefore == UNSET() => false &&
  69. stateBefore == SUCCEEDED() => false &&
  70. stateBefore == QUEUED() => false &&
  71. stateBefore == CANCELED() => false &&
  72. stateBefore == DEFEATED() => false &&
  73. stateBefore == EXECUTED() => false
  74. );
  75. }
  76. /*
  77. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  78. │ Rule: State corresponds to the vote timing and results │
  79. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  80. */
  81. rule stateFollowsVoteTimmingAndResult(uint256 pId, env e) {
  82. require clock(e) > 0; // Sanity
  83. requireInvariant proposalStateConsistency(pId);
  84. uint8 currentState = state(e, pId);
  85. uint48 currentClock = clock(e);
  86. // Pending = before vote starts
  87. assert currentState == PENDING() => (
  88. proposalSnapshot(pId) >= currentClock
  89. );
  90. // Active = after vote starts & before vote ends
  91. assert currentState == ACTIVE() => (
  92. proposalSnapshot(pId) < currentClock &&
  93. proposalDeadline(pId) >= currentClock
  94. );
  95. // Succeeded = after vote end, with vote successful and quorum reached
  96. assert currentState == SUCCEEDED() => (
  97. proposalDeadline(pId) < currentClock &&
  98. (
  99. quorumReached(pId) &&
  100. voteSucceeded(pId)
  101. )
  102. );
  103. // Succeeded = after vote end, with vote not successful or quorum not reached
  104. assert currentState == DEFEATED() => (
  105. proposalDeadline(pId) < currentClock &&
  106. (
  107. !quorumReached(pId) ||
  108. !voteSucceeded(pId)
  109. )
  110. );
  111. }