TimelockController.spec 11 KB

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