Initializable.spec 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. methods {
  2. initialize(uint256, uint256, uint256) envfree
  3. reinitialize(uint256, uint256, uint256, uint8) envfree
  4. initialized() returns uint8 envfree
  5. initializing() returns bool envfree
  6. thisIsContract() returns bool envfree
  7. returnsV1() returns uint256 envfree
  8. returnsVN(uint8) returns uint256 envfree
  9. returnsAV1() returns uint256 envfree
  10. returnsAVN(uint8) returns uint256 envfree
  11. returnsBV1() returns uint256 envfree
  12. returnsBVN(uint8) returns uint256 envfree
  13. a() returns uint256 envfree
  14. b() returns uint256 envfree
  15. val() returns uint256 envfree
  16. }
  17. definition isUninitialized() returns bool = initialized() == 0;
  18. definition isInitialized() returns bool = initialized() > 0;
  19. definition isInitializedOnce() returns bool = initialized() == 1;
  20. definition isReinitialized() returns bool = initialized() > 1;
  21. definition isDisabled() returns bool = initialized() == 255;
  22. /*
  23. idea : need extensive harness to test upgrading with reinitialize
  24. Setup:
  25. contracts A, B, C
  26. Scenario where B extends A and both are being initialized
  27. Potentially need to summarize ‘isContract’
  28. Multiple Versioning within one contract
  29. Test Cases:
  30. Simple
  31. 1 contract with initialize and reinitialize methods (v 1-3)
  32. Multiple Inheritance
  33. Contracts A, B, C
  34. C Inherits from B, which Inherits from A
  35. Properties
  36. /// You can only initialize once
  37. /// two rules prove initialize is equivalent to reinitialize(1) property (?) -- what other effects from these calls?
  38. // if reinitialize(1) is called successfully, _initialized is set to 1
  39. // if initialize is called successfully, _initialized is set to 1
  40. /// disabled stays disabled
  41. // invariant
  42. // or rule?
  43. /// n increase iff reinitialize succeeds
  44. // n only increases
  45. // reinitialize called => n increases
  46. /// You can reinitialize(n) iff n > _initialized && initialized < 256 (maxuint8)
  47. // <=
  48. // =>
  49. /// can only cal v1 function in v1
  50. Question: can we handle reentrancy?
  51. */
  52. // You can only initialize once
  53. rule initOnce() {
  54. uint256 val; uint256 a; uint256 b;
  55. require isInitialized();
  56. initialize@withrevert(val, a, b);
  57. assert lastReverted;
  58. }
  59. /// two rules prove initialize is equivalent to reinitialize(1) property (?) -- what other effects from these calls?
  60. // if reinitialize(1) is called successfully, _initialized is set to 1
  61. rule basicReinitializeEffects() {
  62. uint256 val; uint256 a; uint256 b;
  63. reinitialize(val, a, b, 1);
  64. assert isInitializedOnce();
  65. }
  66. // if initialize is called successfully, _initialized is set to 1
  67. rule initalizeEffects(method f) {
  68. env e; calldataarg args;
  69. f(e, args);
  70. assert f.selector == initialize(uint256, uint256, uint256).selector => isInitializedOnce();
  71. }
  72. /// disabled stays disabled
  73. // invariant
  74. invariant disabledStaysDisabledInv()
  75. isDisabled() => isDisabled()
  76. // or rule?
  77. rule disabledStaysDisabled(method f) {
  78. env e; calldataarg args;
  79. bool disabledBefore = isDisabled();
  80. f(e, args);
  81. bool disabledAfter = isDisabled();
  82. assert disabledBefore => disabledAfter;
  83. }
  84. /// n increase iff reinitialize succeeds
  85. // n only increases
  86. rule increasingInitialized(method f) {
  87. env e; calldataarg args;
  88. uint8 initBefore = initialized();
  89. f(e, args);
  90. uint8 initAfter = initialized();
  91. assert initBefore <= initAfter;
  92. }
  93. // reinitialize called => n increases
  94. rule reinitializeIncreasesInit() {
  95. uint256 val; uint8 n; uint256 a; uint256 b;
  96. uint8 initBefore = initialized();
  97. reinitialize(val, a, b, n);
  98. uint8 initAfter = initialized();
  99. assert initAfter > initBefore;
  100. }
  101. /// You can reinitialize(n) iff n > _initialized && initialized < 256 (maxuint8)
  102. // <=
  103. rule reinitializeLiveness() {
  104. env e; uint256 val; uint8 n; uint256 a; uint256 b;
  105. require !initializing();
  106. uint8 initVal = initialized();
  107. reinitialize@withrevert(val, a, b, n);
  108. assert n > initVal && initVal < 255 => !lastReverted;
  109. }
  110. // =>
  111. rule reinitializeRule() {
  112. env e; calldataarg args; uint256 val; uint8 n; uint256 a; uint256 b;
  113. uint8 initBefore = initialized();
  114. reinitialize(val, a, b, n);
  115. uint8 initAfter = initialized();
  116. assert initAfter > initBefore => n > initBefore;
  117. }
  118. // can only call v1 functions in v1
  119. rule initVersionCheck() {
  120. env e; calldataarg args; uint256 val; uint256 a; uint256 b; uint8 n;
  121. require n != 1;
  122. initialize(val, a, b);
  123. assert returnsV1() == val / 2;
  124. assert returnsAV1() == a / 2;
  125. assert returnsBV1() == b / 2;
  126. returnsVN@withrevert(n);
  127. assert lastReverted;
  128. returnsAVN@withrevert(n);
  129. assert lastReverted;
  130. returnsBVN@withrevert(n);
  131. assert lastReverted;
  132. }
  133. // can only call V_n functions in V_n
  134. rule reinitVersionCheck() {
  135. env e; calldataarg args; uint256 val; uint256 a; uint256 b; uint8 n; uint8 m;
  136. require n != m;
  137. reinitialize(val, a, b, n);
  138. assert returnsVN(n) == val / (n + 1);
  139. assert returnsAVN(n) == a / (n + 1);
  140. assert returnsBVN(n) == b / (n + 1);
  141. returnsVN@withrevert(m);
  142. assert lastReverted;
  143. returnsAVN@withrevert(m);
  144. assert lastReverted;
  145. returnsBVN@withrevert(m);
  146. assert lastReverted;
  147. }
  148. rule inheritanceCheck() {
  149. env e; calldataarg args; uint256 val; uint8 n; uint256 a; uint256 b;
  150. initialize(val, a, b);
  151. assert val() == val && a() == a && b() == b;
  152. }