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) envfree
  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. }