GovernorPreventLateQuorum.spec 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import "helpers.spec"
  2. import "methods/IGovernor.spec"
  3. import "Governor.helpers.spec"
  4. import "GovernorInvariants.spec"
  5. methods {
  6. lateQuorumVoteExtension() returns uint64 envfree
  7. getExtendedDeadline(uint256) returns uint64 envfree
  8. }
  9. use invariant proposalStateConsistency
  10. use invariant votesImplySnapshotPassed
  11. /*
  12. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  13. │ Rule: │
  14. │ * Deadline can never be reduced │
  15. │ * If deadline increases then we are in `deadlineExtended` state and `castVote` was called. │
  16. │ * A proposal's deadline can't change in `deadlineExtended` state. │
  17. │ * A proposal's deadline can't be unextended. │
  18. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  19. */
  20. rule deadlineChangeToPreventLateQuorum(uint256 pId, env e, method f, calldataarg args)
  21. filtered { f -> !skip(f) }
  22. {
  23. requireInvariant proposalStateConsistency(pId);
  24. requireInvariant votesImplySnapshotPassed(e, pId);
  25. // This is not (easily) provable as an invariant because the prover think `_totalSupplyCheckpoints`
  26. // can arbitrarily change, which causes the quorum() to change. Not sure how to fix that.
  27. require !quorumReached(pId) <=> getExtendedDeadline(pId) == 0;
  28. uint256 deadlineBefore = proposalDeadline(pId);
  29. bool deadlineExtendedBefore = getExtendedDeadline(pId) > 0;
  30. bool quorumReachedBefore = quorumReached(pId);
  31. f(e, args);
  32. uint256 deadlineAfter = proposalDeadline(pId);
  33. bool deadlineExtendedAfter = getExtendedDeadline(pId) > 0;
  34. bool quorumReachedAfter = quorumReached(pId);
  35. // deadline can never be reduced
  36. assert deadlineBefore <= proposalDeadline(pId);
  37. // deadline can only be extended in proposal or on cast vote
  38. assert deadlineAfter != deadlineBefore => (
  39. (
  40. !deadlineExtendedBefore &&
  41. !deadlineExtendedAfter &&
  42. f.selector == propose(address[], uint256[], bytes[], string).selector
  43. ) || (
  44. !deadlineExtendedBefore &&
  45. deadlineExtendedAfter &&
  46. !quorumReachedBefore && // Not sure how to prove that
  47. quorumReachedAfter &&
  48. deadlineAfter == clock(e) + lateQuorumVoteExtension() &&
  49. votingAll(f)
  50. )
  51. );
  52. // a deadline can only be extended once
  53. assert deadlineExtendedBefore => deadlineBefore == deadlineAfter;
  54. // a deadline cannot be un-extended
  55. assert deadlineExtendedBefore => deadlineExtendedAfter;
  56. }