TimelockController.spec 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. methods {
  2. PROPOSER_ROLE() returns(bytes32) envfree
  3. _DONE_TIMESTAMP() returns(uint256) envfree
  4. _minDelay() returns(uint256) envfree
  5. _checkRole(bytes32) => DISPATCHER(true)
  6. isOperation(bytes32) returns(bool) envfree
  7. isOperationPending(bytes32) returns(bool) envfree
  8. isOperationReady(bytes32) returns(bool)
  9. isOperationDone(bytes32) returns(bool) envfree
  10. getTimestamp(bytes32) returns(uint256) envfree
  11. getMinDelay() returns(uint256) envfree
  12. hashOperation(address, uint256, bytes, bytes32, bytes32) returns(bytes32) envfree
  13. hashOperationBatch(address[], uint256[], bytes[], bytes32, bytes32) returns(bytes32) envfree
  14. schedule(address, uint256, bytes, bytes32, bytes32, uint256)
  15. scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256)
  16. execute(address, uint256, bytes, bytes32, bytes32)
  17. executeBatch(address[], uint256[], bytes[], bytes32, bytes32)
  18. cancel(bytes32)
  19. }
  20. ////////////////////////////////////////////////////////////////////////////
  21. // Functions //
  22. ////////////////////////////////////////////////////////////////////////////
  23. function hashIdCorrelation(bytes32 id, address target, uint256 value, bytes data, bytes32 predecessor, bytes32 salt){
  24. require data.length < 32;
  25. require hashOperation(target, value, data, predecessor, salt) == id;
  26. }
  27. ////////////////////////////////////////////////////////////////////////////
  28. // Invariants //
  29. ////////////////////////////////////////////////////////////////////////////
  30. // STATUS - verified
  31. // `isOperation()` correctness check
  32. invariant operationCheck(bytes32 id)
  33. getTimestamp(id) > 0 <=> isOperation(id)
  34. filtered { f -> !f.isView }
  35. // STATUS - verified
  36. // `isOperationPending()` correctness check
  37. invariant pendingCheck(bytes32 id)
  38. getTimestamp(id) > _DONE_TIMESTAMP() <=> isOperationPending(id)
  39. filtered { f -> !f.isView }
  40. // STATUS - verified
  41. // `isOperationReady()` correctness check
  42. invariant readyCheck(env e, bytes32 id)
  43. (e.block.timestamp >= getTimestamp(id) && getTimestamp(id) > 1) <=> isOperationReady(e, id)
  44. filtered { f -> !f.isView }
  45. // STATUS - verified
  46. // `isOperationDone()` correctness check
  47. invariant doneCheck(bytes32 id)
  48. getTimestamp(id) == _DONE_TIMESTAMP() <=> isOperationDone(id)
  49. filtered { f -> !f.isView }
  50. ////////////////////////////////////////////////////////////////////////////
  51. // Rules //
  52. ////////////////////////////////////////////////////////////////////////////
  53. /////////////////////////////////////////////////////////////
  54. // STATE TRANSITIONS
  55. /////////////////////////////////////////////////////////////
  56. // STATUS - verified
  57. // Possible transitions: form `!isOperation()` to `!isOperation()` or `isOperationPending()` only
  58. rule unsetPendingTransitionGeneral(method f, env e){
  59. bytes32 id;
  60. require !isOperation(id);
  61. require e.block.timestamp > 1;
  62. calldataarg args;
  63. f(e, args);
  64. assert isOperationPending(id) || !isOperation(id);
  65. }
  66. // STATUS - verified
  67. // Possible transitions: form `!isOperation()` to `isOperationPending()` via `schedule()` and `scheduleBatch()` only
  68. rule unsetPendingTransitionMethods(method f, env e){
  69. bytes32 id;
  70. require !isOperation(id);
  71. calldataarg args;
  72. f(e, args);
  73. assert isOperationPending(id) => (f.selector == schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector
  74. || f.selector == scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256).selector), "Why do we need to follow the schedule?";
  75. }
  76. // STATUS - verified
  77. // Possible transitions: form `ready()` to `isOperationDone()` via `execute()` and `executeBatch()` only
  78. rule readyDoneTransition(method f, env e){
  79. bytes32 id;
  80. require isOperationReady(e, id);
  81. calldataarg args;
  82. f(e, args);
  83. assert isOperationDone(id) => f.selector == execute(address, uint256, bytes, bytes32, bytes32).selector
  84. || f.selector == executeBatch(address[], uint256[], bytes[], bytes32, bytes32).selector , "It's not isOperationDone yet!";
  85. }
  86. // STATUS - verified
  87. // isOperationPending() -> cancelled() via cancel() only
  88. rule pendingCancelledTransition(method f, env e){
  89. bytes32 id;
  90. require isOperationPending(id);
  91. calldataarg args;
  92. f(e, args);
  93. assert !isOperation(id) => f.selector == cancel(bytes32).selector, "How you dare to cancel me?";
  94. }
  95. // STATUS - verified
  96. // isOperationDone() -> nowhere
  97. rule doneToNothingTransition(method f, env e){
  98. bytes32 id;
  99. require isOperationDone(id);
  100. calldataarg args;
  101. f(e, args);
  102. assert isOperationDone(id), "Did you find a way to escape? There is no way! HA-HA-HA";
  103. }
  104. /////////////////////////////////////////////////////////////
  105. // THE REST
  106. /////////////////////////////////////////////////////////////
  107. // STATUS - verified
  108. // only TimelockController contract can change minDelay
  109. rule minDelayOnlyChange(method f, env e){
  110. uint256 delayBefore = _minDelay();
  111. calldataarg args;
  112. f(e, args);
  113. uint256 delayAfter = _minDelay();
  114. assert delayBefore != delayAfter => e.msg.sender == currentContract, "You cannot change your destiny! Only I can!";
  115. }
  116. // STATUS - verified
  117. // scheduled operation timestamp == block.timestamp + delay (kind of unit test)
  118. rule scheduleCheck(method f, env e){
  119. bytes32 id;
  120. address target; uint256 value; bytes data ;bytes32 predecessor; bytes32 salt; uint256 delay;
  121. hashIdCorrelation(id, target, value, data, predecessor, salt);
  122. schedule(e, target, value, data, predecessor, salt, delay);
  123. assert getTimestamp(id) == to_uint256(e.block.timestamp + delay), "Time doesn't obey to mortal souls";
  124. }
  125. // STATUS - verified
  126. // Cannot call `execute()` on a isOperationPending (not ready) operation
  127. rule cannotCallExecute(method f, env e){
  128. address target; uint256 value; bytes data; bytes32 predecessor; bytes32 salt;
  129. bytes32 id;
  130. hashIdCorrelation(id, target, value, data, predecessor, salt);
  131. require isOperationPending(id) && !isOperationReady(e, id);
  132. execute@withrevert(e, target, value, data, predecessor, salt);
  133. assert lastReverted, "you go against execution nature";
  134. }
  135. // STATUS - verified
  136. // Cannot call `execute()` on a !isOperation operation
  137. rule executeRevertsFromUnset(method f, env e, env e2){
  138. address target; uint256 value; bytes data; bytes32 predecessor; bytes32 salt;
  139. bytes32 id;
  140. hashIdCorrelation(id, target, value, data, predecessor, salt);
  141. require !isOperation(id);
  142. execute@withrevert(e, target, value, data, predecessor, salt);
  143. assert lastReverted, "you go against execution nature";
  144. }
  145. // STATUS - verified
  146. // Execute reverts => state returns to isOperationPending
  147. rule executeRevertsEffectCheck(method f, env e){
  148. address target; uint256 value; bytes data; bytes32 predecessor; bytes32 salt;
  149. bytes32 id;
  150. hashIdCorrelation(id, target, value, data, predecessor, salt);
  151. require isOperationPending(id) && !isOperationReady(e, id);
  152. execute@withrevert(e, target, value, data, predecessor, salt);
  153. bool reverted = lastReverted;
  154. assert lastReverted => isOperationPending(id) && !isOperationReady(e, id), "you go against execution nature";
  155. }
  156. // STATUS - verified
  157. // Canceled operations cannot be executed → can’t move from canceled to isOperationDone
  158. rule cancelledNotExecuted(method f, env e){
  159. bytes32 id;
  160. require !isOperation(id);
  161. require e.block.timestamp > 1;
  162. calldataarg args;
  163. f(e, args);
  164. assert !isOperationDone(id), "The ship is not a creature of the air";
  165. }
  166. // STATUS - verified
  167. // Only proposers can schedule
  168. rule onlyProposer(method f, env e) filtered { f -> f.selector == schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector
  169. || f.selector == scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256).selector } {
  170. bytes32 id;
  171. bytes32 role;
  172. address target; uint256 value; bytes data ;bytes32 predecessor; bytes32 salt; uint256 delay;
  173. _checkRole@withrevert(e, PROPOSER_ROLE());
  174. bool isCheckRoleReverted = lastReverted;
  175. calldataarg args;
  176. f@withrevert(e, args);
  177. bool isScheduleReverted = lastReverted;
  178. assert isCheckRoleReverted => isScheduleReverted, "Enemy was detected";
  179. }
  180. // STATUS - verified
  181. // if `ready` then has waited minimum period after isOperationPending()
  182. rule cooldown(method f, env e, env e2){
  183. bytes32 id;
  184. address target; uint256 value; bytes data ;bytes32 predecessor; bytes32 salt; uint256 delay;
  185. uint256 minDelay = getMinDelay();
  186. hashIdCorrelation(id, target, value, data, predecessor, salt);
  187. schedule(e, target, value, data, predecessor, salt, delay);
  188. calldataarg args;
  189. f(e, args);
  190. assert isOperationReady(e2, id) => (e2.block.timestamp - e.block.timestamp >= minDelay), "No rush! When I'm ready, I'm ready";
  191. }
  192. // STATUS - verified
  193. // `schedule()` should change only one id's timestamp
  194. rule scheduleChange(env e){
  195. bytes32 id; bytes32 otherId;
  196. address target; uint256 value; bytes data ;bytes32 predecessor; bytes32 salt; uint256 delay;
  197. uint256 otherIdTimestampBefore = getTimestamp(otherId);
  198. hashIdCorrelation(id, target, value, data, predecessor, salt);
  199. schedule(e, target, value, data, predecessor, salt, delay);
  200. assert id != otherId => otherIdTimestampBefore == getTimestamp(otherId), "Master of puppets, I'm pulling your strings";
  201. }
  202. // STATUS - verified
  203. // `execute()` should change only one id's timestamp
  204. rule executeChange(env e){
  205. bytes32 id; bytes32 otherId;
  206. address target; uint256 value; bytes data ;bytes32 predecessor; bytes32 salt;
  207. uint256 otherIdTimestampBefore = getTimestamp(otherId);
  208. hashIdCorrelation(id, target, value, data, predecessor, salt);
  209. execute(e, target, value, data, predecessor, salt);
  210. assert id != otherId => otherIdTimestampBefore == getTimestamp(otherId), "Master of puppets, I'm pulling your strings";
  211. }
  212. // STATUS - verified
  213. // `cancel()` should change only one id's timestamp
  214. rule cancelChange(env e){
  215. bytes32 id; bytes32 otherId;
  216. uint256 otherIdTimestampBefore = getTimestamp(otherId);
  217. cancel(e, id);
  218. assert id != otherId => otherIdTimestampBefore == getTimestamp(otherId), "Master of puppets, I'm pulling your strings";
  219. }