浏览代码

Nonces FV (#4528)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Ernesto García 2 年之前
父节点
当前提交
3eb5cfb22a
共有 3 个文件被更改,包括 111 次插入0 次删除
  1. 14 0
      certora/harnesses/NoncesHarness.sol
  2. 5 0
      certora/specs.json
  3. 92 0
      certora/specs/Nonces.spec

+ 14 - 0
certora/harnesses/NoncesHarness.sol

@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import {Nonces} from "../patched/utils/Nonces.sol";
+
+contract NoncesHarness is Nonces {
+    function useNonce(address account) external returns (uint256) {
+        return _useNonce(account);
+    }
+
+    function useCheckedNonce(address account, uint256 nonce) external {
+        _useCheckedNonce(account, nonce);
+    }
+}

+ 5 - 0
certora/specs.json

@@ -101,5 +101,10 @@
     "contract": "TimelockControllerHarness",
     "files": ["certora/harnesses/TimelockControllerHarness.sol"],
     "options": ["--optimistic_hashing", "--optimistic_loop"]
+  },
+  {
+    "spec": "Nonces",
+    "contract": "NoncesHarness",
+    "files": ["certora/harnesses/NoncesHarness.sol"]
   }
 ]

+ 92 - 0
certora/specs/Nonces.spec

@@ -0,0 +1,92 @@
+import "helpers/helpers.spec";
+
+methods {
+    function nonces(address) external returns (uint256) envfree;
+    function useNonce(address) external returns (uint256) envfree;
+    function useCheckedNonce(address,uint256) external envfree;
+}
+
+/*
+┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+│ Helpers                                                                                                             │
+└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+*/
+function nonceSanity(address account) returns bool {
+    return nonces(account) < max_uint256;
+}
+
+/*
+┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+│ Function correctness: useNonce uses nonce                                                                           │
+└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+*/
+rule useNonce(address account) {
+    require nonceSanity(account);
+
+    address other;
+
+    mathint nonceBefore = nonces(account);
+    mathint otherNonceBefore = nonces(other);
+
+    mathint nonceUsed = useNonce@withrevert(account);
+    bool success = !lastReverted;
+
+    mathint nonceAfter = nonces(account);
+    mathint otherNonceAfter = nonces(other);
+
+    // liveness
+    assert success, "doesn't revert";
+
+    // effect
+    assert nonceAfter == nonceBefore + 1 && nonceBefore == nonceUsed, "nonce is used";
+
+    // no side effect
+    assert otherNonceBefore != otherNonceAfter => other == account, "no other nonce is used";
+}
+
+/*
+┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+│ Function correctness: useCheckedNonce uses only the current nonce                                                   │
+└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+*/
+rule useCheckedNonce(address account, uint256 currentNonce) {
+    require nonceSanity(account);
+
+    address other;
+
+    mathint nonceBefore = nonces(account);
+    mathint otherNonceBefore = nonces(other);
+
+    useCheckedNonce@withrevert(account, currentNonce);
+    bool success = !lastReverted;
+
+    mathint nonceAfter = nonces(account);
+    mathint otherNonceAfter = nonces(other);
+
+    // liveness
+    assert success <=> to_mathint(currentNonce) == nonceBefore, "works iff current nonce is correct";
+
+    // effect
+    assert success => nonceAfter == nonceBefore + 1, "nonce is used";
+
+    // no side effect
+    assert otherNonceBefore != otherNonceAfter => other == account, "no other nonce is used";
+}
+
+/*
+┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+│ Rule: nonce only increments                                                                                         │
+└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+*/
+rule nonceOnlyIncrements(address account) {
+    require nonceSanity(account);
+
+    mathint nonceBefore = nonces(account);
+
+    env e; method f; calldataarg args;
+    f(e, args);
+
+    mathint nonceAfter = nonces(account);
+
+    assert nonceAfter == nonceBefore || nonceAfter == nonceBefore + 1, "nonce only increments";
+}