github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/kontrol/README.md (about)

     1  # Kontrol Verification
     2  
     3  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
     4  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
     5  
     6  - [Getting Started](#getting-started)
     7    - [Overview](#overview)
     8    - [Directory structure](#directory-structure)
     9    - [Installation](#installation)
    10  - [Usage](#usage)
    11    - [Build Deployment Summary](#build-deployment-summary)
    12    - [Execute Proofs](#execute-proofs)
    13    - [Add New Proofs](#add-new-proofs)
    14  - [Implementation Details](#implementation-details)
    15    - [Assumptions](#assumptions)
    16    - [Deployment Summary Process](#deployment-summary-process)
    17  
    18  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
    19  
    20  ## Getting Started
    21  
    22  ### Overview
    23  
    24  [Kontrol](https://github.com/runtimeverification/kontrol) is a tool by [Runtime Verification](https://runtimeverification.com/) (RV) that enables formal verification of Ethereum smart contracts. Quoting from the Kontrol [docs](https://docs.runtimeverification.com/kontrol/overview/readme):
    25  
    26  > Kontrol combines [KEVM](https://github.com/runtimeverification/evm-semantics) and [Foundry](https://book.getfoundry.sh/) to grant developers the ability to perform [formal verification](https://en.wikipedia.org/wiki/Formal_verification) without learning a new language or tool. This is especially useful for those who are not verification engineers. Additionally, developers can leverage Foundry test suites they have already developed and use symbolic execution to increase the level of confidence.
    27  >
    28  > KEVM is a tool that enables formal verification of smart contracts on the Ethereum blockchain. It provides a mathematical foundation for specifying and implementing smart contracts. Developers can use KEVM to rigorously reason about the behavior of their smart contracts, ensuring correctness and reducing the likelihood of vulnerabilities in the contract code.
    29  
    30  This document details the Kontrol setup used in this repo to run various proofs against the contracts in the [`contracts-bedrock`](../../) directory.
    31  
    32  ### Directory structure
    33  
    34  The directory is structured as follows
    35  
    36  <pre>
    37  ├── <a href="./pausability-lemmas.md">pausability-lemmas.md</a>: File containing the necessary lemmas for this project
    38  ├── <a href="./deployment">deployment</a>: Custom deploy sequence for Kontrol proofs and tests for its <a href="https://github.com/runtimeverification/kontrol/pull/271">fast summarization</a>
    39  │   ├── <a href="./deployment/KontrolDeployment.sol">KontrolDeployment.sol</a>: Simplified deployment sequence for Kontrol proofs
    40  │   └── <a href="./deployment/DeploymentSummary.t.sol">DeploymentSummary.t.sol</a>: Tests for the summarization of custom deployment
    41  ├── <a href="./proofs">proofs</a>: Where the proofs (tests) themselves live
    42  │   ├── *.k.sol</a>: Symbolic property tests for contracts
    43  │   ├── <a href="./proofs/interfaces">interfaces</a>: Interface files for src contracts, to avoid unnecessary compilation of contracts
    44  │   └── <a href="./proofs/utils">utils</a>: Proof dependencies, including the autogenerated deployment summary contracts
    45  └── <a href="./scripts">scripts</a>: Where the scripts of the projects live
    46      ├── <a href="./scripts/json">json</a>: Data cleaning scripts for the output of <a href="./deployment/KontrolDeployment.sol">KontrolDeployment.sol</a>
    47      ├── <a href="./scripts/make-summary-deployment.sh">make-summary-deployment.sh</a>: Executes <a href="./deployment/KontrolDeployment.sol">KontrolDeployment.sol</a>, curates the result and writes the summary deployment contract
    48      └── <a href="./scripts/run-kontrol.sh">run-kontrol.sh</a>: Wrapper around the kontrol CLI to run the proofs
    49  </pre>
    50  
    51  ### Installation
    52  
    53  1. `cd` to the root of this repo.
    54  2. Install Foundry by running `pnpm install:foundry`. This installs `foundryup`, the foundry toolchain installer, then installs the required foundry version.
    55  3. Install Kontrol by running `pnpm install:kontrol`. This installs `kup`, the package manager for RV tools, then installs the required kontrol version.
    56  4. Install Docker.
    57  
    58  ## Usage
    59  
    60  Verifying proofs has two steps: build, and execute.
    61  
    62  ### Build Deployment Summary
    63  
    64  First, generate a deployment summary contract from the deploy script in [`KontrolDeployment.sol`](./deployment/KontrolDeployment.sol) by running the following command:
    65  
    66  ```
    67  ./test/kontrol/scripts/make-summary-deployment.sh [container|local|dev]
    68  ```
    69  
    70  The [`make-summary-deployment.sh`](./scripts/make-summary-deployment.sh) supports the same execution modes as `run-kontrol.sh` below.
    71  
    72  [`KontrolDeployment.sol`](./deployment/KontrolDeployment.sol) contains the minimal deployment sequence required by the proofs.
    73  The [`make-summary-deployment.sh`](./scripts/make-summary-deployment.sh) script will generate a JSON state diff. This state diff is used in two ways by Kontrol.
    74  First, Kontrol generates a summary contract recreating the state diffs recorded in the JSON. This contract is used to test that the information contained in the generated JSON is correct and aids in the specification of the symbolic property tests. The generation of this contract is also handled by the `make-summary-deployment.sh` script.
    75  Second, the state diff JSON is used to load the post-deployment state directly into Kontrol when running the proofs.
    76  
    77  This step is optional if an up-to-date summary contract already exists, which will be the case until the `KontrolDeployment` contract changes, or any of the source contracts under test change.
    78  See the [Implementation Details](#implementation-details) section for more information, and to learn about the CI check that ensures the committed autogenerated files from this step are up-to-date.
    79  
    80  The summary contract can be found in [`DeploymentSummary.sol`](./proofs/utils/DeploymentSummary.sol), which is summarization (state changes) of the [`KontrolDeployment.sol`](./deployment/KontrolDeployment.sol) contract.
    81  
    82  ### Execute Proofs
    83  
    84  Use the [`run-kontrol.sh`](./scripts/run-kontrol.sh) script to runs the proofs in all `*.k.sol` files.
    85  
    86  ```
    87  ./test/kontrol/scripts/run-kontrol.sh [container|local|dev] [script|tests]
    88  ```
    89  
    90  The `run-kontrol.sh` script supports three modes of proof execution:
    91  
    92  - `container`: Runs the proofs using the same Docker image used in CI. This is the default execution mode—if no arguments are provided, the proofs will be executed in this mode.
    93  - `local`: Runs the proofs with your local Kontrol install, and enforces that the Kontrol version matches the one used in CI, which is specified in [`versions.json`](../../../../versions.json).
    94  - `dev`: Run the proofs with your local Kontrol install, without enforcing any version in particular. The intended use case is proof development and related matters.
    95  
    96  It also supports two methods for specifying which tests to execute:
    97  
    98  - `script`: Runs the tests specified in the `test_list` variable
    99  - `tests`: Names of the tests to be executed. `tests` can have two forms:
   100      - `ContractName.testName`: e.g., `run-kontrol.sh ContractName.test1 ContractName.test2`
   101      - Empty, executing all the functions starting with `test`, `prove` or `check` present in the defined `out` directory. For instance, `./test/kontrol/scripts/run-kontrol.sh` will execute all `prove_*` functions in the [proofs](./proofs/) directory using the same Docker image as in CI. [Warning: executing all proofs in parallel is _very_ resource intensive]
   102  
   103  For a similar description of the options run `run-kontrol.sh --help`.
   104  
   105  ### Add New Proofs
   106  
   107  These are the instructions to add a new proof to this project. If all functions involved in the new proof are from a contract already deployed by [`KontrolDeployment`](./deployment/KontrolDeployment.sol) the first two steps can be skipped.
   108  
   109  #### Make Kontrol aware of the new contract being tested
   110  
   111  The `runKontrolDeployment` function of [`KontrolDeployment`](./deployment/KontrolDeployment.sol) partially reproduces the deployment process laid out in the `_run` function of [`Deploy.s.sol`](../../scripts/Deploy.s.sol). `runKontrolDeployment` has the `stateDiff` modifier to make use of [Foundry's state diff cheatcodes](https://book.getfoundry.sh/cheatcodes/start-state-diff-recording). Kontrol utilizes the JSON resulting from this modifier for two purposes:
   112  1. Load all the state updates generated by `runKontrolDeployment` as the initial configuration for all proofs, effectively offloading the computation of the deployment process to `forge` and thus improving performance.
   113  2. Produce the [`DeploymentSummary`](./proofs/utils/DeploymentSummary.sol) script contract to test that the produced JSON contains correct updates.
   114  
   115  Hence, in order to write a proof for a contract which is not present in `KontrolDeployment` it must be added there first. To add a new contract, properly inspect the above-mentioned `_run` function and place the corresponding deployment steps of the contract appropriately within the `runKontrolDeployment` function.
   116  
   117  Once new deployment steps have been added to `runKontrolDeployment` the state-diff files have to [be rebuilt](#build-deployment-summary).
   118  
   119  #### Include existing tests on the new state-diff recorded bytecode
   120  
   121  The next step is to include tests for the newly included state updates in [`DeploymentSummary.t.sol`](deployment/DeploymentSummary.t.sol). These tests inherit the tests from [`test`](../L1) of the contracts deployed by `runKontrolDeployment`. This ensures that deployment steps were implemented correctly and that the state updates are correct.
   122  
   123  It might be necessary to set some of the existing tests from [`test`](../L1) as virtual because they can't be executed as is. See [`DeploymentSummary.t.sol`](deployment/DeploymentSummary.t.sol) for more concrete examples.
   124  
   125  #### Add function signatures to [`KontrolInterfaces`](./proofs/interfaces/KontrolInterfaces.sol)
   126  
   127  So far we've got all the state updates ready to be added to the initial configuration of each proof, but we cannot yet write any proof about the function. We still need to add the relevant signatures into `KontrolInterfaces`. The reason for having `KontrolInterfaces` instead of using directly the contracts is to reduce the amount of compiled contracts by Kontrol.
   128  In the future there might interfaces for all contracts under `contracts-bedrock`, which would imply the removal of `KontrolInterfaces`.
   129  
   130  #### Write the proof
   131  
   132  Write your proof in a `.k.sol` file in the [`proofs`](./proofs/) folder, which is the `test` directory used by the `kprove` profile to run the proofs (see [Deployment Summary Process](#deployment-summary-process)). The name of the new proofs should start with `prove` (or `check`) instead of `test` to avoid `forge test` running them. The reason for this is that if Kontrol cheatcodes (see [Kontrol's own cheatcodes](https://github.com/runtimeverification/kontrol-cheatcodes/blob/master/src/KontrolCheats.sol)) are used in a test, it will not be runnable by `forge`. Currently, none of the tests are using custom Kontrol cheatcodes, but this is something to bear in mind.
   133  
   134  To reference the correct addresses for writing the tests, first import the signatures as in this example:
   135  ```solidity
   136  import {
   137      IOptimismPortal as OptimismPortal,
   138      ISuperchainConfig as SuperchainConfig
   139  } from "./interfaces/KontrolInterfaces.sol";
   140  ```
   141  Declare the correspondent variables and cast the correct signatures to the correct addresses:
   142  ```solidity
   143  OptimismPortal optimismPortal;
   144  SuperchainConfig superchainConfig;
   145  
   146  function setUp() public {
   147      optimismPortal = OptimismPortal(payable(optimismPortalProxyAddress));
   148      superchainConfig = SuperchainConfig(superchainConfigProxyAddress);
   149  }
   150  ```
   151  Note that the names of the addresses come from [`DeploymentSummary.t.sol`](deployment/DeploymentSummary.t.sol) and are automatically generated by the [`make-summary-deployment.sh`](./scripts/make-summary-deployment.sh) script.
   152  
   153  #### Add your test to [`run-kontrol.sh`](./scripts/run-kontrol.sh)
   154  
   155  As described in [Execute Proofs](#execute-proofs), there's a `script` mode for specifying which proofs to run, and that is the mode used in CI. To run the new proofs with the `script` option, add `ContractName.prove_functionName_paused` to the variable `test_list` in the `run-kontrol.sh` script.
   156  
   157  ## Implementation Details
   158  
   159  ### Assumptions
   160  
   161  1. A critical invariant of the `KontrolDeployment.sol` contract is that it stays in sync with the original `Deploy.s.sol` contract.
   162     Currently, this is partly enforced by running some of the standard post-`setUp` deployment assertions in `DeploymentSummary.t.sol`.
   163     A more rigorous approach may be to leverage the `ChainAssertions` library, but more investigation is required to determine if this is feasible without large changes to the deploy script.
   164  
   165  2. Size of `bytes[]` arguments. In [`OptimismPortal.k.sol`](./proofs/OptimismPortal.k.sol), the `prove_proveWithdrawalTransaction_paused` proof is broken down into 11 different proofs, each corresponding to a different size of the `_withdrawalProof` argument, which is of type `bytes[]`. We execute the same logic for lengths of `_withdrawalProof` ranging from 0 to 10, setting the length of each symbolic `bytes` element to 600.
   166      - The reason for a max length of 10 is that it provides a conservative upper bound based on [historical data](https://dune.com/queries/3433954/5768623) for proof sizes.
   167      - The reason for choosing 600 as the length for the elements of `_withdrawalProof` is that each element is `17 * 32 = 544` bytes long, so adding a 10% margin for RLP encoding and rounding up yields 600 bytes. The same historical data confirms this is a valid bound.
   168      - All other symbolic `bytes` arguments that are not part of a `bytes` array have a symbolic length bounded by `2^63`.
   169  
   170  ### Deployment Summary Process
   171  
   172  As mentioned above, a deployment summary contract is first generated before executing the proofs.
   173  This is because the proof execution leverages Kontrol's [fast summarization](https://github.com/runtimeverification/kontrol/pull/271) feature, which allows loading the post-`setUp` state directly into Kontrol.
   174  This provides a significant reduction in proof execution time, as it avoids the need to execute the deployment script every time the proofs are run.
   175  
   176  All code executed in Kontrol—even when execution is concrete and not symbolic—is significantly slower than in Foundry, due to the mathematical representation of the EVM in Kontrol.
   177  Therefore we want to minimize the amount of code executed in Kontrol, and the fast summarization feature allows us to reduce `setUp` execution time.
   178  
   179  This project uses two different [`foundry.toml` profiles](../../foundry.toml), `kdeploy` and `kprove`, to facilitate usage of this fast summarization feature.:
   180  
   181  - `kdeploy`: Used by [`make-summary-deployment.sh`](./scripts/make-summary-deployment.sh) to generate the [`DeploymentSummary.sol`](./proofs/utils/DeploymentSummary.sol) contract based on execution of the [`KontrolDeployment.sol`](./deployment/KontrolDeployment.sol) contract using Foundry's state diff recording cheatcodes.
   182    This is where all necessary [`src/L1`](../../src/L1) files are compiled with their bytecode saved into the [`DeploymentSummaryCode.sol`](./proofs/utils/DeploymentSummaryCode.sol) file, which is inherited by `DeploymentSummary`.
   183  
   184  - `kprove`: Used by the [`run-kontrol.sh`](./scrpts/run-kontrol.sh) script to execute proofs, which can be run once a `DeploymentSummary.sol` contract is present. This profile's `src` and `script` paths point to a test folder because we only want to compile what is in the `test/kontrol/proofs` folder, since that folder contains all bytecode and proofs.
   185  
   186  The `make-summary-deployment.sh` scripts saves off the generated JSON state diff to `snapshots/state-diff/Kontrol-Deploy.json`, and is run as part of the `snapshots` script in `package.json`.
   187  Therefore, the snapshots CI check will fail if the committed Kontrol state diff is out of sync.
   188  Note that the CI check only compares the JSON state diff, not the generated `DeploymentSummary.sol` or `DeploymentSummaryCode` contracts.
   189  This is for simplicity, as those three files will be in sync upon successful execution of the `make-summary-deployment.sh` script.
   190  We commit the `DeploymentSummary.sol` and `DeploymentSummaryCode.sol` contracts, because forge fails to build if those contracts are not present—it is simpler to commit these autogenerated files than to workaround their absence in forge builds.
   191  
   192  During `make-summary-deployment.sh`, the `mustGetAddress` usage in `Deploy.s.sol` is temporarily replaced by `getAddress`—the former reverts if the deployed contract does not exist, while the latter returns the zero address.
   193  This is required because the deploy script in `KontrolDeployment.sol` is does not fully reproduce all deployments in `Deploy.s.sol`, so the `mustGetAddress` usage would cause the script to revert since some contracts are not deployed.
   194  `KontrolDeployment.sol` is a simplified, minimal deployment sequence for Kontrol proofs, and is not intended to be a full deployment sequence for the contracts in `contracts-bedrock`.