TimelockController.spec 12 KB

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