TimelockController.spec 10 KB

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