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