GovernorBase.spec 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // Governor.sol base definitions
  2. methods {
  3. proposalSnapshot(uint256) returns uint256 envfree // matches proposalVoteStart
  4. }
  5. ghost proposalVoteStart(uint256) returns uint64 {
  6. init_state axiom forall uint256 pId. proposalVoteStart(pId) == 0;
  7. }
  8. ghost proposalVoteEnd(uint256) returns uint64 {
  9. init_state axiom forall uint256 pId. proposalVoteEnd(pId) == 0;
  10. }
  11. ghost proposalExecuted(uint256) returns bool {
  12. init_state axiom forall uint256 pId. !proposalExecuted(pId);
  13. }
  14. ghost proposalCanceled(uint256) returns bool {
  15. init_state axiom forall uint256 pId. !proposalCanceled(pId);
  16. }
  17. definition mask_uint64() returns uint256 = max_uint64 - 1;
  18. hook Sstore _proposals[KEY uint256 pId] uint64 newValue STORAGE {
  19. havoc proposalVoteStart assuming (
  20. proposalVoteStart@new(pId) == newValue & mask_uint64()
  21. && (forall uint256 pId2. pId != pId2 => proposalVoteStart@new(pId2) == proposalVoteStart@old(pId2))
  22. );
  23. }
  24. hook Sload uint64 value _proposals[KEY uint256 pId] STORAGE {
  25. require proposalVoteStart(pId) == value & mask_uint64();
  26. }
  27. hook Sstore _proposals[KEY uint256 pId].(offset 32).(offset 0) uint64 newValue STORAGE {
  28. havoc proposalVoteEnd assuming (
  29. proposalVoteEnd@new(pId) == newValue & mask_uint64()
  30. && (forall uint256 pId2. pId != pId2 => proposalVoteEnd@new(pId2) == proposalVoteEnd@old(pId2))
  31. );
  32. }
  33. hook Sload uint64 value _proposals[KEY uint256 pId].(offset 32).(offset 0) STORAGE {
  34. require proposalVoteEnd(pId) == value & mask_uint64();
  35. }
  36. rule sanityCheckVoteStart(method f, uint256 pId) {
  37. uint64 preGhost = proposalVoteStart(pId);
  38. uint256 pre = proposalSnapshot(pId);
  39. env e;
  40. calldataarg arg;
  41. f(e, arg);
  42. uint64 postGhost = proposalVoteStart(pId);
  43. uint256 post = proposalSnapshot(pId);
  44. assert preGhost == postGhost <=> pre == post, "ghost changes are correlated with getter changes";
  45. assert pre == preGhost => post == postGhost, "if correlated at the beginning should be correlated at the end";
  46. }
  47. rule sanityCheckVoteEnd(method f, uint256 pId) {
  48. uint64 preGhost = proposalVoteEnd(pId);
  49. uint256 pre = proposalSnapshot(pId);
  50. env e;
  51. calldataarg arg;
  52. f(e, arg);
  53. uint64 postGhost = proposalVoteEnd(pId);
  54. uint256 post = proposalSnapshot(pId);
  55. assert preGhost == postGhost <=> pre == post, "ghost changes are correlated with getter changes";
  56. assert pre == preGhost => post == postGhost, "if correlated at the beginning should be correlated at the end";
  57. }
  58. /**
  59. * A proposal cannot end unless it started.
  60. */
  61. invariant voteStartBeforeVoteEnd(uint256 pId) proposalVoteStart(pId) < proposalVoteEnd(pId)
  62. /**
  63. * A proposal cannot be both executed and canceled.
  64. */
  65. invariant noBothExecutedAndCanceled(uint256 pId) !proposalExecuted(pId) || !proposalCanceled(pId)