TimelockController.spec 9.5 KB

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