TimelockController.spec 10 KB

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