Nonces.spec 5.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import "helpers/helpers.spec";
  2. methods {
  3. function nonces(address) external returns (uint256) envfree;
  4. function useNonce(address) external returns (uint256) envfree;
  5. function useCheckedNonce(address,uint256) external envfree;
  6. }
  7. /*
  8. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  9. │ Helpers │
  10. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  11. */
  12. function nonceSanity(address account) returns bool {
  13. return nonces(account) < max_uint256;
  14. }
  15. /*
  16. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  17. │ Function correctness: useNonce uses nonce │
  18. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  19. */
  20. rule useNonce(address account) {
  21. require nonceSanity(account);
  22. address other;
  23. mathint nonceBefore = nonces(account);
  24. mathint otherNonceBefore = nonces(other);
  25. mathint nonceUsed = useNonce@withrevert(account);
  26. bool success = !lastReverted;
  27. mathint nonceAfter = nonces(account);
  28. mathint otherNonceAfter = nonces(other);
  29. // liveness
  30. assert success, "doesn't revert";
  31. // effect
  32. assert nonceAfter == nonceBefore + 1 && nonceBefore == nonceUsed, "nonce is used";
  33. // no side effect
  34. assert otherNonceBefore != otherNonceAfter => other == account, "no other nonce is used";
  35. }
  36. /*
  37. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  38. │ Function correctness: useCheckedNonce uses only the current nonce │
  39. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  40. */
  41. rule useCheckedNonce(address account, uint256 currentNonce) {
  42. require nonceSanity(account);
  43. address other;
  44. mathint nonceBefore = nonces(account);
  45. mathint otherNonceBefore = nonces(other);
  46. useCheckedNonce@withrevert(account, currentNonce);
  47. bool success = !lastReverted;
  48. mathint nonceAfter = nonces(account);
  49. mathint otherNonceAfter = nonces(other);
  50. // liveness
  51. assert success <=> to_mathint(currentNonce) == nonceBefore, "works iff current nonce is correct";
  52. // effect
  53. assert success => nonceAfter == nonceBefore + 1, "nonce is used";
  54. // no side effect
  55. assert otherNonceBefore != otherNonceAfter => other == account, "no other nonce is used";
  56. }
  57. /*
  58. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  59. │ Rule: nonce only increments │
  60. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  61. */
  62. rule nonceOnlyIncrements(address account) {
  63. require nonceSanity(account);
  64. mathint nonceBefore = nonces(account);
  65. env e; method f; calldataarg args;
  66. f(e, args);
  67. mathint nonceAfter = nonces(account);
  68. assert nonceAfter == nonceBefore || nonceAfter == nonceBefore + 1, "nonce only increments";
  69. }