Commit 876e16ad authored by Juan C's avatar Juan C Committed by GitHub

Final version for Kontrol pausability proofs (#9530)

* Update tests to native symbolic `bytes` and `bytes[]`

* adding lemmas

* `run-kontrol.sh`: add more sensible parameters

* Change `startPrank` by `prank`

* Replace `mockCall` workaround with `vm.mockCall`

* Make `bytes` length symbolic

* `KontrolUtils`: remove symbolic workarounds

* `run-kontrol.sh`: add `prove_proveWithdrawalTransaction_paused`

* `forge fmt`

* `versions.json`: bump Kontrol from `0.1.127` to `0.1.156`

* Remove `ASSUME` comments

* ci: run kontrol on develop and allow manual dispatch

* ci: rename parameter

* `OptimismPortalKontrol`: add remaining ranges for `_withdrawalProof`

* Add forge-like UX to `run-kontrol.sh`

* `pausability-lemmas.k`: clean file

* general tests, further lemmas, summary claim

* Address shellcheck failures

* Change `pausability-lemmas.k` to `pausability-lemmas.md`

* `versions.json`: bump `kontrol` from `0.1.156` to `0.1.178`

* `OptimismPortalKontrol`: update `kontrol` natspec to version 0.1.178

* `pausability-lemmas.md`: remove unused `Lemmas` header

* Update packages/contracts-bedrock/test/kontrol/pausability-lemmas.md
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* Update packages/contracts-bedrock/test/kontrol/pausability-lemmas.md
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* Update packages/contracts-bedrock/test/kontrol/pausability-lemmas.md
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* Update packages/contracts-bedrock/test/kontrol/pausability-lemmas.md
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* `pausability-lemmas.md`: fix spelling typo

* `pausability-lemmas.md`: fix typo `bytearrays` to `byte arrays`

* `run-kontrol.sh`: correctly format temorarily unexecuted lemmas

* `common.sh`: execute `copy_to_docker` only when in docker mode

* `make-summary-deployment.sh`: add argument check before parsing

* Reflect `kontrol summary` change to `kontrol load-state-diff`

From version `0.1.162`, `kontrol summary` has been renamed to `kontrol
load-state-diff`.
The reason of this renaming is that `kontrol summary` will be
used by kontrol's compositional symbolic execution.
Also, changing the name to `load-state-diff` makes more explicit what the
command does.
Related PR: https://github.com/runtimeverification/kontrol/pull/374

* `pausability-lemmas.md`: remove upstreamed lemmas

* fix: writing typos

* lemma text pass

* paragraph about summary maintainability

* README.md: include latest changes

* pausability-lemmas.md: markdown link typo

* KontrolUtils: add documentation comment

* pausability-lemmas.md: fix markdown typo vol2

* pausability-lemmas.md: fix markdown typo vol3

* Add specialized usage functions

* `README.md`: remove `bash` in `make-summary-deployment.sh` description

* `README.md`: complete `Add New Proofs` section

* versions.json: bump kontrol from 0.1.178 to 0.1.196

* run-kontrol.sh: add `--xml-test-report` flag

* .gitignore: add `kontrol_prove_report.xml`

* foundry.toml: set `ast = true` in `kprove` profile

* config.yml: set correct path for kontrol `store_artifacts`

* config.yml: add `store_test_results` step to `kontrol-tests` job

* package.json: execute `run-kontrol.sh` with `script` option

We run `run-kontrol.sh` with the `script` option to avoid executing all proofs

* run-kontrol.sh: remove proof with 10 elements in favor of 0 and 1

The longer the `_withdrawalProof` array the longer the execution time
Adding the lengths 0 and 1 fits within the max cpus and won't take as long to run

* chore: typos and formatting

* ci: fix kontrol trigger

* README.md: minor typo

---------
Co-authored-by: default avatarPetar Maksimovic <petar.maksimovic@runtimeverification.com>
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>
parent df32e7e8
...@@ -23,6 +23,9 @@ parameters: ...@@ -23,6 +23,9 @@ parameters:
fault_proofs_dispatch: fault_proofs_dispatch:
type: boolean type: boolean
default: false default: false
kontrol_dispatch:
type: boolean
default: false
orbs: orbs:
go: circleci/go@1.8.0 go: circleci/go@1.8.0
...@@ -1485,7 +1488,9 @@ jobs: ...@@ -1485,7 +1488,9 @@ jobs:
command: pnpm test:kontrol command: pnpm test:kontrol
working_directory: ./packages/contracts-bedrock working_directory: ./packages/contracts-bedrock
- store_artifacts: - store_artifacts:
path: ./packages/contracts-bedrock/kontrol-results_latest.tar.gz path: ./packages/contracts-bedrock/test/kontrol/logs/kontrol-results_latest.tar.gz
- store_test_results:
path: ./packages/contracts-bedrock/kontrol_prove_report.xml
- notify-failures-on-develop - notify-failures-on-develop
workflows: workflows:
...@@ -2078,9 +2083,14 @@ workflows: ...@@ -2078,9 +2083,14 @@ workflows:
context: context:
- slack - slack
scheduled-kontrol-tests: develop-kontrol-tests:
when: when:
equal: [ build_four_hours, <<pipeline.schedule.name>> ] and:
- or:
- equal: [ "develop", <<pipeline.git.branch>> ]
- equal: [ true, <<pipeline.parameters.kontrol_dispatch>> ]
- not:
equal: [ scheduled_pipeline, << pipeline.trigger_source >> ]
jobs: jobs:
- kontrol-tests: - kontrol-tests:
context: context:
......
...@@ -13,6 +13,7 @@ coverage.out ...@@ -13,6 +13,7 @@ coverage.out
# Testing State # Testing State
.testdata .testdata
kontrol_prove_report.xml
# Scripts # Scripts
scripts/go-ffi/go-ffi scripts/go-ffi/go-ffi
......
...@@ -87,3 +87,4 @@ src = 'test/kontrol/proofs' ...@@ -87,3 +87,4 @@ src = 'test/kontrol/proofs'
out = 'kout-proofs' out = 'kout-proofs'
test = 'test/kontrol/proofs' test = 'test/kontrol/proofs'
script = 'test/kontrol/proofs' script = 'test/kontrol/proofs'
ast = true
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
"build:go-ffi": "(cd scripts/go-ffi && go build)", "build:go-ffi": "(cd scripts/go-ffi && go build)",
"autogen:invariant-docs": "npx tsx scripts/autogen/generate-invariant-docs.ts", "autogen:invariant-docs": "npx tsx scripts/autogen/generate-invariant-docs.ts",
"test": "pnpm build:go-ffi && forge test", "test": "pnpm build:go-ffi && forge test",
"test:kontrol": "./test/kontrol/scripts/run-kontrol.sh", "test:kontrol": "./test/kontrol/scripts/run-kontrol.sh script",
"genesis": "./scripts/generate-l2-genesis.sh", "genesis": "./scripts/generate-l2-genesis.sh",
"coverage": "pnpm build:go-ffi && forge coverage", "coverage": "pnpm build:go-ffi && forge coverage",
"coverage:lcov": "pnpm build:go-ffi && forge coverage --report lcov", "coverage:lcov": "pnpm build:go-ffi && forge coverage --report lcov",
......
requires "evm.md"
requires "foundry.md"
module PAUSABILITY-LEMMAS
imports BOOL
imports FOUNDRY
imports INFINITE-GAS
imports INT-SYMBOLIC
// Your lemmas go here
endmodule
This diff is collapsed.
...@@ -19,25 +19,18 @@ contract L1CrossDomainMessengerKontrol is DeploymentSummary, KontrolUtils { ...@@ -19,25 +19,18 @@ contract L1CrossDomainMessengerKontrol is DeploymentSummary, KontrolUtils {
superchainConfig = SuperchainConfig(superchainConfigProxyAddress); superchainConfig = SuperchainConfig(superchainConfigProxyAddress);
} }
/// TODO: Replace struct parameters and workarounds with the appropriate
/// types once Kontrol supports symbolic `bytes` and `bytes[]`
/// Tracking issue: https://github.com/runtimeverification/kontrol/issues/272
function prove_relayMessage_paused( function prove_relayMessage_paused(
uint256 _nonce, uint256 _nonce,
address _sender, address _sender,
address _target, address _target,
uint256 _value, uint256 _value,
uint256 _gas uint256 _gas,
bytes calldata _message
) )
external external
{ {
setUpInlined(); setUpInlined();
// ASSUME: Conservative upper bound on the `_message` length. Most contract calls will have
// a message length less than 600 bytes. This assumption can be removed once Kontrol
// supports symbolic `bytes`: https://github.com/runtimeverification/kontrol/issues/272
bytes memory _message = freshBigBytes(600);
// Pause System // Pause System
vm.prank(superchainConfig.guardian()); vm.prank(superchainConfig.guardian());
superchainConfig.pause("identifier"); superchainConfig.pause("identifier");
......
...@@ -6,6 +6,7 @@ import { KontrolUtils } from "./utils/KontrolUtils.sol"; ...@@ -6,6 +6,7 @@ import { KontrolUtils } from "./utils/KontrolUtils.sol";
import { Types } from "src/libraries/Types.sol"; import { Types } from "src/libraries/Types.sol";
import { import {
IL1ERC721Bridge as L1ERC721Bridge, IL1ERC721Bridge as L1ERC721Bridge,
IL1CrossDomainMessenger as CrossDomainMessenger,
ISuperchainConfig as SuperchainConfig ISuperchainConfig as SuperchainConfig
} from "./interfaces/KontrolInterfaces.sol"; } from "./interfaces/KontrolInterfaces.sol";
...@@ -18,43 +19,30 @@ contract L1ERC721BridgeKontrol is DeploymentSummary, KontrolUtils { ...@@ -18,43 +19,30 @@ contract L1ERC721BridgeKontrol is DeploymentSummary, KontrolUtils {
superchainConfig = SuperchainConfig(superchainConfigProxyAddress); superchainConfig = SuperchainConfig(superchainConfigProxyAddress);
} }
/// TODO: Replace symbolic workarounds with the appropriate
/// types once Kontrol supports symbolic `bytes` and `bytes[]`
/// Tracking issue: https://github.com/runtimeverification/kontrol/issues/272
function prove_finalizeBridgeERC721_paused( function prove_finalizeBridgeERC721_paused(
address _localToken, address _localToken,
address _remoteToken, address _remoteToken,
address _from, address _from,
address _to, address _to,
uint256 _amount uint256 _amount,
bytes calldata _extraData
) )
public public
{ {
setUpInlined(); setUpInlined();
// Current workaround to be replaced with `vm.mockCall`, once the cheatcode is implemented in Kontrol
// This overrides the storage slot read by `CrossDomainMessenger::xDomainMessageSender`
// Tracking issue: https://github.com/runtimeverification/kontrol/issues/285
vm.store(
l1CrossDomainMessengerProxyAddress,
hex"00000000000000000000000000000000000000000000000000000000000000cc",
bytes32(uint256(uint160(address(l1ERC721Bridge.otherBridge()))))
);
// ASSUME: Conservative upper bound on the `_extraData` length, since extra data is optional
// for convenience of off-chain tooling. This assumption can be removed once Kontrol
// supports symbolic `bytes`: https://github.com/runtimeverification/kontrol/issues/272
bytes memory _extraData = freshBigBytes(64);
// Pause Standard Bridge // Pause Standard Bridge
vm.prank(superchainConfig.guardian()); vm.prank(superchainConfig.guardian());
superchainConfig.pause("identifier"); superchainConfig.pause("identifier");
// Pranking with `vm.prank` instead will result in failure from Kontrol vm.mockCall(
// Tracking issue: https://github.com/runtimeverification/kontrol/issues/316 address(l1ERC721Bridge.messenger()),
vm.startPrank(address(l1ERC721Bridge.messenger())); abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
abi.encode(address(l1ERC721Bridge.otherBridge()))
);
vm.prank(address(l1ERC721Bridge.messenger()));
vm.expectRevert("L1ERC721Bridge: paused"); vm.expectRevert("L1ERC721Bridge: paused");
l1ERC721Bridge.finalizeBridgeERC721(_localToken, _remoteToken, _from, _to, _amount, _extraData); l1ERC721Bridge.finalizeBridgeERC721(_localToken, _remoteToken, _from, _to, _amount, _extraData);
vm.stopPrank();
} }
} }
...@@ -6,6 +6,7 @@ import { KontrolUtils } from "./utils/KontrolUtils.sol"; ...@@ -6,6 +6,7 @@ import { KontrolUtils } from "./utils/KontrolUtils.sol";
import { Types } from "src/libraries/Types.sol"; import { Types } from "src/libraries/Types.sol";
import { import {
IL1StandardBridge as L1StandardBridge, IL1StandardBridge as L1StandardBridge,
IL1CrossDomainMessenger as CrossDomainMessenger,
ISuperchainConfig as SuperchainConfig ISuperchainConfig as SuperchainConfig
} from "./interfaces/KontrolInterfaces.sol"; } from "./interfaces/KontrolInterfaces.sol";
...@@ -18,77 +19,55 @@ contract L1StandardBridgeKontrol is DeploymentSummary, KontrolUtils { ...@@ -18,77 +19,55 @@ contract L1StandardBridgeKontrol is DeploymentSummary, KontrolUtils {
superchainConfig = SuperchainConfig(superchainConfigProxyAddress); superchainConfig = SuperchainConfig(superchainConfigProxyAddress);
} }
/// TODO: Replace symbolic workarounds with the appropriate
/// types once Kontrol supports symbolic `bytes` and `bytes[]`
/// Tracking issue: https://github.com/runtimeverification/kontrol/issues/272
function prove_finalizeBridgeERC20_paused( function prove_finalizeBridgeERC20_paused(
address _localToken, address _localToken,
address _remoteToken, address _remoteToken,
address _from, address _from,
address _to, address _to,
uint256 _amount uint256 _amount,
bytes calldata _extraData
) )
public public
{ {
setUpInlined(); setUpInlined();
// Current workaround to be replaced with `vm.mockCall`, once the cheatcode is implemented in Kontrol
// This overrides the storage slot read by `CrossDomainMessenger::xDomainMessageSender`
// Tracking issue: https://github.com/runtimeverification/kontrol/issues/285
vm.store(
l1CrossDomainMessengerProxyAddress,
hex"00000000000000000000000000000000000000000000000000000000000000cc",
bytes32(uint256(uint160(address(l1standardBridge.otherBridge()))))
);
// ASSUME: Upper bound on the `_extraData` length, since extra data is optional for
// for convenience of off-chain tooling, and should not affect execution This assumption
// can be removed once Kontrol supports symbolic `bytes`:
// https://github.com/runtimeverification/kontrol/issues/272
bytes memory _extraData = freshBigBytes(32);
// Pause Standard Bridge // Pause Standard Bridge
vm.prank(superchainConfig.guardian()); vm.prank(superchainConfig.guardian());
superchainConfig.pause("identifier"); superchainConfig.pause("identifier");
// Pranking with `vm.prank` instead will result in failure from Kontrol vm.mockCall(
// Tracking issue: https://github.com/runtimeverification/kontrol/issues/316 address(l1standardBridge.messenger()),
vm.startPrank(address(l1standardBridge.messenger())); abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
abi.encode(address(l1standardBridge.otherBridge()))
);
vm.prank(address(l1standardBridge.messenger()));
vm.expectRevert("StandardBridge: paused"); vm.expectRevert("StandardBridge: paused");
l1standardBridge.finalizeBridgeERC20(_localToken, _remoteToken, _from, _to, _amount, _extraData); l1standardBridge.finalizeBridgeERC20(_localToken, _remoteToken, _from, _to, _amount, _extraData);
vm.stopPrank();
} }
/// TODO: Replace symbolic workarounds with the appropriate function prove_finalizeBridgeETH_paused(
/// types once Kontrol supports symbolic `bytes` and `bytes[]` address _from,
/// Tracking issue: https://github.com/runtimeverification/kontrol/issues/272 address _to,
function prove_finalizeBridgeETH_paused(address _from, address _to, uint256 _amount) public { uint256 _amount,
bytes calldata _extraData
)
public
{
setUpInlined(); setUpInlined();
// Current workaround to be replaced with `vm.mockCall`, once the cheatcode is implemented in Kontrol
// This overrides the storage slot read by `CrossDomainMessenger::xDomainMessageSender`
// Tracking issue: https://github.com/runtimeverification/kontrol/issues/285
vm.store(
l1CrossDomainMessengerProxyAddress,
hex"00000000000000000000000000000000000000000000000000000000000000cc",
bytes32(uint256(uint160(address(l1standardBridge.otherBridge()))))
);
// ASSUME: Upper bound on the `_extraData` length, since extra data is optional for
// for convenience of off-chain tooling, and should not affect execution This assumption
// can be removed once Kontrol supports symbolic `bytes`:
// https://github.com/runtimeverification/kontrol/issues/272
bytes memory _extraData = freshBigBytes(32);
// Pause Standard Bridge // Pause Standard Bridge
vm.prank(superchainConfig.guardian()); vm.prank(superchainConfig.guardian());
superchainConfig.pause("identifier"); superchainConfig.pause("identifier");
// Pranking with `vm.prank` instead will result in failure from Kontrol vm.mockCall(
// Tracking issue: https://github.com/runtimeverification/kontrol/issues/316 address(l1standardBridge.messenger()),
vm.startPrank(address(l1standardBridge.messenger())); abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
abi.encode(address(l1standardBridge.otherBridge()))
);
vm.prank(address(l1standardBridge.messenger()));
vm.expectRevert("StandardBridge: paused"); vm.expectRevert("StandardBridge: paused");
l1standardBridge.finalizeBridgeETH(_from, _to, _amount, _extraData); l1standardBridge.finalizeBridgeETH(_from, _to, _amount, _extraData);
vm.stopPrank();
} }
} }
...@@ -20,78 +20,176 @@ contract OptimismPortalKontrol is DeploymentSummary, KontrolUtils { ...@@ -20,78 +20,176 @@ contract OptimismPortalKontrol is DeploymentSummary, KontrolUtils {
superchainConfig = SuperchainConfig(superchainConfigProxyAddress); superchainConfig = SuperchainConfig(superchainConfigProxyAddress);
} }
/// TODO: Replace struct parameters and workarounds with the appropriate function prove_finalizeWithdrawalTransaction_paused(Types.WithdrawalTransaction calldata _tx) external {
/// types once Kontrol supports symbolic `bytes` and `bytes[]` setUpInlined();
/// Tracking issue: https://github.com/runtimeverification/kontrol/issues/272
function prove_proveWithdrawalTransaction_paused( // Pause Optimism Portal
// WithdrawalTransaction args vm.prank(optimismPortal.guardian());
uint256 _nonce, superchainConfig.pause("identifier");
address _sender,
address _target, vm.expectRevert("OptimismPortal: paused");
uint256 _value, optimismPortal.finalizeWithdrawalTransaction(_tx);
uint256 _gasLimit, }
// bytes memory _data,
/// @dev Function containing the logic for prove_proveWithdrawalTransaction_paused
/// The reason for this is that we want the _withdrawalProof to range in size from
/// 0 to 10. These 11 proofs will exercise the same logic, which is contained in this function
function prove_proveWithdrawalTransaction_paused_internal(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex, uint256 _l2OutputIndex,
// OutputRootProof args Types.OutputRootProof calldata _outputRootProof,
bytes32 _outputRootProof0, bytes[] memory _withdrawalProof
bytes32 _outputRootProof1,
bytes32 _outputRootProof2,
bytes32 _outputRootProof3
) )
external internal
{ {
setUpInlined(); setUpInlined();
// ASSUME: This bound on the `_data` length is too low, and should be at least 1000 bytes.
// Kontrol currently hangs and fails with this value because of the resulting configuration
// size. For now we leave this as a low value to avoid the hang, but it should be increased
// once Kontrol is improved and supports symbolic `bytes`:
// https://github.com/runtimeverification/kontrol/issues/272
bytes memory _data = freshBigBytes(320);
bytes[] memory _withdrawalProof = freshWithdrawalProof();
Types.WithdrawalTransaction memory _tx =
Types.WithdrawalTransaction(_nonce, _sender, _target, _value, _gasLimit, _data);
Types.OutputRootProof memory _outputRootProof =
Types.OutputRootProof(_outputRootProof0, _outputRootProof1, _outputRootProof2, _outputRootProof3);
// Pause Optimism Portal // Pause Optimism Portal
vm.prank(optimismPortal.guardian()); vm.prank(optimismPortal.guardian());
superchainConfig.pause("identifier"); superchainConfig.pause("identifier");
// No one can call proveWithdrawalTransaction
vm.expectRevert("OptimismPortal: paused"); vm.expectRevert("OptimismPortal: paused");
optimismPortal.proveWithdrawalTransaction(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof); optimismPortal.proveWithdrawalTransaction(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
} }
/// TODO: Replace struct parameters and workarounds with the appropriate /// @custom:kontrol-array-length-equals _withdrawalProof: 10,
/// types once Kontrol supports symbolic `bytes` and `bytes[]` /// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
/// Tracking issue: https://github.com/runtimeverification/kontrol/issues/272 function prove_proveWithdrawalTransaction_paused10(
function prove_finalizeWithdrawalTransaction_paused( Types.WithdrawalTransaction memory _tx,
uint256 _nonce, uint256 _l2OutputIndex,
address _sender, Types.OutputRootProof calldata _outputRootProof,
address _target, bytes[] calldata _withdrawalProof
uint256 _value,
uint256 _gasLimit
) )
external external
{ {
setUpInlined(); prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
/// @custom:kontrol-array-length-equals _withdrawalProof: 9,
/// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
function prove_proveWithdrawalTransaction_paused9(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
// ASSUME: This bound on the `_data` length is too low, and should be at least 1000 bytes. /// @custom:kontrol-array-length-equals _withdrawalProof: 8,
// Kontrol currently hangs and fails with this value because of the resulting configuration /// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
// size. For now we leave this as a low value to avoid the hang, but it should be increased function prove_proveWithdrawalTransaction_paused8(
// once Kontrol is improved and supports symbolic `bytes`: Types.WithdrawalTransaction memory _tx,
// https://github.com/runtimeverification/kontrol/issues/272 uint256 _l2OutputIndex,
bytes memory _data = freshBigBytes(320); Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
// Pause Optimism Portal /// @custom:kontrol-array-length-equals _withdrawalProof: 7,
vm.prank(optimismPortal.guardian()); /// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
superchainConfig.pause("identifier"); function prove_proveWithdrawalTransaction_paused7(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
vm.expectRevert("OptimismPortal: paused"); /// @custom:kontrol-array-length-equals _withdrawalProof: 6,
optimismPortal.finalizeWithdrawalTransaction( /// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
Types.WithdrawalTransaction(_nonce, _sender, _target, _value, _gasLimit, _data) function prove_proveWithdrawalTransaction_paused6(
); Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
/// @custom:kontrol-array-length-equals _withdrawalProof: 5,
/// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
function prove_proveWithdrawalTransaction_paused5(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
/// @custom:kontrol-array-length-equals _withdrawalProof: 4,
/// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
function prove_proveWithdrawalTransaction_paused4(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
/// @custom:kontrol-array-length-equals _withdrawalProof: 3,
/// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
function prove_proveWithdrawalTransaction_paused3(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
/// @custom:kontrol-array-length-equals _withdrawalProof: 2,
/// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
function prove_proveWithdrawalTransaction_paused2(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
/// @custom:kontrol-array-length-equals _withdrawalProof: 1,
/// @custom:kontrol-bytes-length-equals _withdrawalProof: 600,
function prove_proveWithdrawalTransaction_paused1(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof,
bytes[] calldata _withdrawalProof
)
external
{
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
}
function prove_proveWithdrawalTransaction_paused0(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof calldata _outputRootProof
)
external
{
bytes[] memory _withdrawalProof = new bytes[](0);
prove_proveWithdrawalTransaction_paused_internal(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof);
} }
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
// This file was autogenerated by running `kontrol summary`. Do not edit this file manually. // This file was autogenerated by running `kontrol load-state-diff`. Do not edit this file manually.
pragma solidity ^0.8.13; pragma solidity ^0.8.13;
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
// This file was autogenerated by running `kontrol summary`. Do not edit this file manually. // This file was autogenerated by running `kontrol load-state-diff`. Do not edit this file manually.
pragma solidity ^0.8.13; pragma solidity ^0.8.13;
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
// This file exists to provide the `internal constant vm` on top of `KontrolCheats`.
// The reason for explicitly defining `vm` here instead of inheriting Forge's `Test`
// contract is the K summary of the `copy_memory_to_memory` function.
// This summary dependent on the bytecode of the test contract, which means that if `Test`
// was inherited, updating the version of `Test` could potentially imply having to adjust
// said summary for the latest version, introducing a flakiness source.
// Note that starting with version 0.8.24, the opcode `MCOPY` is introduced, removing the
// need for the `copy_memory_to_memory` function and its summary, and thus this workaround.
// For more information refer to the `copy_memory_to_memory` summary section of `pausability-lemmas.md`.
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Vm } from "forge-std/Vm.sol"; import { Vm } from "forge-std/Vm.sol";
import { KontrolCheats } from "kontrol-cheatcodes/KontrolCheats.sol"; import { KontrolCheats } from "kontrol-cheatcodes/KontrolCheats.sol";
// The GhostBytes contracts are a workaround to create a symbolic bytes array. This is slow, but
// required until symbolic bytes are supported in Kontrol: https://github.com/runtimeverification/kontrol/issues/272
contract GhostBytes {
bytes public ghostBytes;
}
contract GhostBytes10 {
bytes public ghostBytes0;
bytes public ghostBytes1;
bytes public ghostBytes2;
bytes public ghostBytes3;
bytes public ghostBytes4;
bytes public ghostBytes5;
bytes public ghostBytes6;
bytes public ghostBytes7;
bytes public ghostBytes8;
bytes public ghostBytes9;
function getGhostBytesArray() public view returns (bytes[] memory _arr) {
_arr = new bytes[](10);
_arr[0] = ghostBytes0;
_arr[1] = ghostBytes1;
_arr[2] = ghostBytes2;
_arr[3] = ghostBytes3;
_arr[4] = ghostBytes4;
_arr[5] = ghostBytes5;
_arr[6] = ghostBytes6;
_arr[7] = ghostBytes7;
_arr[8] = ghostBytes8;
_arr[9] = ghostBytes9;
}
}
/// @notice Tests inheriting this contract cannot be run with forge /// @notice Tests inheriting this contract cannot be run with forge
abstract contract KontrolUtils is KontrolCheats { abstract contract KontrolUtils is KontrolCheats {
Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
/// @dev Creates a fresh bytes with length greater than 31
/// @param bytesLength: Length of the fresh bytes. Should be concrete
function freshBigBytes(uint256 bytesLength) internal returns (bytes memory sBytes) {
require(bytesLength >= 32, "Small bytes");
uint256 bytesSlotValue;
unchecked {
bytesSlotValue = bytesLength * 2 + 1;
}
// Deploy ghost contract
GhostBytes ghostBytes = new GhostBytes();
// Make the storage of the ghost contract symbolic
kevm.symbolicStorage(address(ghostBytes));
// Load the size encoding into the first slot of ghostBytes
vm.store(address(ghostBytes), bytes32(uint256(0)), bytes32(bytesSlotValue));
sBytes = ghostBytes.ghostBytes();
}
/// @dev Creates a bounded symbolic bytes[] memory representing a withdrawal proof.
function freshWithdrawalProof() public returns (bytes[] memory withdrawalProof) {
// ASSUME: Withdrawal proofs do not currently exceed 6 elements in length. This can be
// shrank to 2 for faster proof speeds during testing and development.
// TODO: Allow the array length range between 0 and 10 elements. This can be done once
// symbolic bytes are supported in Kontrol: https://github.com/runtimeverification/kontrol/issues/272
uint256 arrayLength = 6;
withdrawalProof = new bytes[](arrayLength);
for (uint256 i = 0; i < withdrawalProof.length; ++i) {
// ASSUME: Each element is 600 bytes. Proof elements are 17 * 32 = 544 bytes long, plus
// ~10% margin for RLP encoding:, giving us the 600 byte assumption.
withdrawalProof[i] = freshBigBytes(600);
}
}
} }
...@@ -2,10 +2,31 @@ ...@@ -2,10 +2,31 @@
# Common functions and variables for run-kontrol.sh and make-summary-deployment.sh # Common functions and variables for run-kontrol.sh and make-summary-deployment.sh
notif() { echo "== $0: $*" >&2 ; } notif() { echo "== $0: $*" >&2 ; }
usage() {
# usage function for the run-kontrol.sh script
usage_run_kontrol() {
echo "Usage: $0 [-h|--help] [container|local|dev] [script|tests]" 1>&2
echo "" 1>&2
echo " -h, --help Display this help message." 1>&2
echo "" 1>&2
echo "Execution modes:"
echo " container Run in docker container. Reproduce CI execution. (Default)" 1>&2
echo " local Run locally, enforces registered versions.json version for better reproducibility. (Recommended)" 1>&2
echo " dev Run locally, does NOT enforce registered version. (Useful for developing with new versions and features)" 1>&2
echo "" 1>&2
echo "Tests executed:"
echo " script Execute the tests recorded in run-kontrol.sh" 1>&2
echo " tests Execute the tests provided as arguments" 1>&2
exit 0
}
# usage function for the make-summary-deployment.sh script
usage_make_summary() {
echo "Usage: $0 [-h|--help] [container|local|dev]" 1>&2 echo "Usage: $0 [-h|--help] [container|local|dev]" 1>&2
echo "Options:" 1>&2 echo "" 1>&2
echo " -h, --help Display this help message." 1>&2 echo " -h, --help Display this help message." 1>&2
echo "" 1>&2
echo "Execution modes:"
echo " container Run in docker container. Reproduce CI execution. (Default)" 1>&2 echo " container Run in docker container. Reproduce CI execution. (Default)" 1>&2
echo " local Run locally, enforces registered versions.json version for better reproducibility. (Recommended)" 1>&2 echo " local Run locally, enforces registered versions.json version for better reproducibility. (Recommended)" 1>&2
echo " dev Run locally, does NOT enforce registered version. (Useful for developing with new versions and features)" 1>&2 echo " dev Run locally, does NOT enforce registered version. (Useful for developing with new versions and features)" 1>&2
...@@ -20,25 +41,84 @@ export CONTAINER_NAME=kontrol-tests ...@@ -20,25 +41,84 @@ export CONTAINER_NAME=kontrol-tests
KONTROLRC=$(jq -r .kontrol < "$WORKSPACE_DIR/../../versions.json") KONTROLRC=$(jq -r .kontrol < "$WORKSPACE_DIR/../../versions.json")
export KONTROL_RELEASE=$KONTROLRC export KONTROL_RELEASE=$KONTROLRC
export LOCAL=false export LOCAL=false
export SCRIPT_TESTS=false
SCRIPT_OPTION=false
export CUSTOM_TESTS=0 # Store the position where custom tests start, interpreting 0 as no tests
CUSTOM_OPTION=0
export RUN_KONTROL=false # true if any functions are called from run-kontrol.sh
# General usage function, which discerns from which script is being called and displays the appropriate message
usage() {
if [ "$RUN_KONTROL" = "true" ]; then
usage_run_kontrol
else
usage_make_summary
fi
}
# Argument Parsing # Argument Parsing
# The logic behind argument parsing is the following (in order):
# - Execution mode argument: container (or empty), local, dev
# - Tests arguments (first if execution mode empty): script, specific test names
parse_args() { parse_args() {
if [ $# -gt 1 ]; then if [ $# -eq 0 ]; then
export LOCAL=false
export SCRIPT_TESTS=false
export CUSTOM_TESTS=0
# `script` argument caps the total possible arguments to its position
elif { [ $# -gt 1 ] && [ "$1" == "script" ]; } || { [ $# -gt 2 ] && [ "$2" == "script" ]; }; then
usage usage
elif [ $# -eq 0 ] || [ "$1" == "container" ]; then elif [ $# -eq 1 ]; then
SCRIPT_OPTION=false
CUSTOM_OPTION=0
parse_first_arg "$1"
elif [ $# -eq 2 ] && [ "$2" == "script" ]; then
if [ "$1" != "container" ] && [ "$1" != "local" ] && [ "$1" != "dev" ]; then
notif "Invalid first argument. Must be \`container\`, \`local\` or \`dev\`"
exit 1
fi
SCRIPT_OPTION=true
CUSTOM_OPTION=0
parse_first_arg "$1"
else
SCRIPT_OPTION=false
CUSTOM_OPTION=2
parse_first_arg "$1"
fi
}
# Parse the first argument passed to `run-kontrol.sh`
parse_first_arg() {
if [ "$1" == "container" ]; then
notif "Running in docker container (DEFAULT)" notif "Running in docker container (DEFAULT)"
export LOCAL=false export LOCAL=false
export SCRIPT_TESTS=$SCRIPT_OPTION
export CUSTOM_TESTS=$CUSTOM_OPTION
elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
usage usage
elif [ "$1" == "local" ]; then elif [ "$1" == "local" ]; then
notif "Running with LOCAL install, .kontrolrc CI version ENFORCED" notif "Running with LOCAL install, .kontrolrc CI version ENFORCED"
export SCRIPT_TESTS=$SCRIPT_OPTION
export CUSTOM_TESTS=$CUSTOM_OPTION
check_kontrol_version check_kontrol_version
elif [ "$1" == "dev" ]; then elif [ "$1" == "dev" ]; then
notif "Running with LOCAL install, IGNORING .kontrolrc version" notif "Running with LOCAL install, IGNORING .kontrolrc version"
export LOCAL=true export LOCAL=true
export SCRIPT_TESTS=$SCRIPT_OPTION
export CUSTOM_TESTS=$CUSTOM_OPTION
pushd "$WORKSPACE_DIR" > /dev/null || exit pushd "$WORKSPACE_DIR" > /dev/null || exit
elif [ "$1" == "script" ]; then
notif "Running in docker container (DEFAULT)"
export LOCAL=false
NEGATED_SCRIPT_TESTS=$([[ "${SCRIPT_OPTION}" == "true" ]] && echo false || echo true)
export SCRIPT_TESTS=$NEGATED_SCRIPT_TESTS
export CUSTOM_TESTS=$CUSTOM_OPTION
else else
usage notif "Running in docker container (DEFAULT)"
export LOCAL=false
export SCRIPT_TESTS=$SCRIPT_OPTION
export CUSTOM_TESTS=1 # Store the position where custom tests start
fi fi
} }
...@@ -87,13 +167,15 @@ copy_to_docker() { ...@@ -87,13 +167,15 @@ copy_to_docker() {
# Error response from daemon: invalid symlink "/home/user/workspace/node_modules/@typescript-eslint/eslint-plugin" -> "../../../../node_modules/.pnpm/@typescript-eslint+eslint-plugin@6.19.1_@typescript-eslint+parser@6.19.1_eslint@8.56.0_typescript@5.3.3/node_modules/@typescript-eslint/eslint-plugin" # Error response from daemon: invalid symlink "/home/user/workspace/node_modules/@typescript-eslint/eslint-plugin" -> "../../../../node_modules/.pnpm/@typescript-eslint+eslint-plugin@6.19.1_@typescript-eslint+parser@6.19.1_eslint@8.56.0_typescript@5.3.3/node_modules/@typescript-eslint/eslint-plugin"
# Even though we use a bind mount, we still need to copy the files to the # Even though we use a bind mount, we still need to copy the files to the
# container because we are running Docker on a remote host. # container because we are running Docker on a remote host.
TMP_DIR=$(mktemp -d) if [ "$LOCAL" == false ]; then
cp -r "$WORKSPACE_DIR/." "$TMP_DIR" TMP_DIR=$(mktemp -d)
rm -rf "$TMP_DIR/node_modules" cp -r "$WORKSPACE_DIR/." "$TMP_DIR"
docker cp --follow-link "$TMP_DIR/." $CONTAINER_NAME:/home/user/workspace rm -rf "$TMP_DIR/node_modules"
rm -rf "$TMP_DIR" docker cp --follow-link "$TMP_DIR/." $CONTAINER_NAME:/home/user/workspace
rm -rf "$TMP_DIR"
docker exec --user root "$CONTAINER_NAME" chown -R user:user /home/user docker exec --user root "$CONTAINER_NAME" chown -R user:user /home/user
fi
} }
clean_docker(){ clean_docker(){
......
...@@ -6,7 +6,18 @@ export FOUNDRY_PROFILE=kdeploy ...@@ -6,7 +6,18 @@ export FOUNDRY_PROFILE=kdeploy
SCRIPT_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" SCRIPT_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
# shellcheck source=/dev/null # shellcheck source=/dev/null
source "$SCRIPT_HOME/common.sh" source "$SCRIPT_HOME/common.sh"
parse_args "$@" # Sanity check on arguments
if [ $# -gt 1 ]; then
echo "At most one argument can be provided. Instead $# were provided" 1>&2
exit 1
elif [ $# -eq 1 ]; then
if [ "$1" != "-h" ] && [ "$1" != "--help" ] && [ "$1" != "container" ] && [ "$1" != "local" ] && [ "$1" != "dev" ]; then
notif "Invalid argument. Must be \`container\`, \`local\`, \`dev\`, \`-h\` or \`--help\`"
exit 1
else
parse_first_arg "$@"
fi
fi
cleanup() { cleanup() {
# Restore the original script from the backup # Restore the original script from the backup
...@@ -74,7 +85,7 @@ SUMMARY_NAME=DeploymentSummary ...@@ -74,7 +85,7 @@ SUMMARY_NAME=DeploymentSummary
LICENSE=MIT LICENSE=MIT
copy_to_docker # Copy the newly generated files to the docker container copy_to_docker # Copy the newly generated files to the docker container
run kontrol summary $SUMMARY_NAME snapshots/state-diff/$STATEDIFF --contract-names $CONTRACT_NAMES --output-dir $SUMMARY_DIR --license $LICENSE run kontrol load-state-diff $SUMMARY_NAME snapshots/state-diff/$STATEDIFF --contract-names $CONTRACT_NAMES --output-dir $SUMMARY_DIR --license $LICENSE
forge fmt $SUMMARY_DIR/$SUMMARY_NAME.sol forge fmt $SUMMARY_DIR/$SUMMARY_NAME.sol
forge fmt $SUMMARY_DIR/${SUMMARY_NAME}Code.sol forge fmt $SUMMARY_DIR/${SUMMARY_NAME}Code.sol
echo "Added state updates to $SUMMARY_DIR/$SUMMARY_NAME.sol" echo "Added state updates to $SUMMARY_DIR/$SUMMARY_NAME.sol"
...@@ -6,6 +6,7 @@ export FOUNDRY_PROFILE=kprove ...@@ -6,6 +6,7 @@ export FOUNDRY_PROFILE=kprove
SCRIPT_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" SCRIPT_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
# shellcheck source=/dev/null # shellcheck source=/dev/null
source "$SCRIPT_HOME/common.sh" source "$SCRIPT_HOME/common.sh"
export RUN_KONTROL=true
parse_args "$@" parse_args "$@"
############# #############
...@@ -32,10 +33,12 @@ kontrol_prove() { ...@@ -32,10 +33,12 @@ kontrol_prove() {
$reinit \ $reinit \
$bug_report \ $bug_report \
$break_on_calls \ $break_on_calls \
$break_every_step \
$auto_abstract \ $auto_abstract \
$tests \ $tests \
$use_booster \ $use_booster \
--init-node-from $state_diff --init-node-from $state_diff \
--xml-test-report
} }
dump_log_results(){ dump_log_results(){
...@@ -93,7 +96,7 @@ trap on_failure ERR INT ...@@ -93,7 +96,7 @@ trap on_failure ERR INT
# such as `rekompile`. Such a pattern is intended for easy use while locally # such as `rekompile`. Such a pattern is intended for easy use while locally
# developing and executing the proofs via this script. Comment/uncomment the # developing and executing the proofs via this script. Comment/uncomment the
# empty assignment to activate/deactivate the corresponding flag # empty assignment to activate/deactivate the corresponding flag
lemmas=test/kontrol/pausability-lemmas.k lemmas=test/kontrol/pausability-lemmas.md
base_module=PAUSABILITY-LEMMAS base_module=PAUSABILITY-LEMMAS
module=OptimismPortalKontrol:$base_module module=OptimismPortalKontrol:$base_module
rekompile=--rekompile rekompile=--rekompile
...@@ -105,13 +108,33 @@ regen= ...@@ -105,13 +108,33 @@ regen=
################################# #################################
# Tests to symbolically execute # # Tests to symbolically execute #
################################# #################################
# Missing: OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused
test_list=( "OptimismPortalKontrol.prove_finalizeWithdrawalTransaction_paused" \ # Temporarily unexecuted tests
"L1StandardBridgeKontrol.prove_finalizeBridgeERC20_paused" \ # "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused0" \
"L1StandardBridgeKontrol.prove_finalizeBridgeETH_paused" \ # "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused1" \
"L1ERC721BridgeKontrol.prove_finalizeBridgeERC721_paused" \ # "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused2" \
"L1CrossDomainMessengerKontrol.prove_relayMessage_paused" # "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused3" \
) # "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused4" \
# "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused5" \
# "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused6" \
# "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused7" \
# "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused8" \
# "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused9" \
# "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused10" \
test_list=()
if [ "$SCRIPT_TESTS" == true ]; then
test_list=( "OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused0" \
"OptimismPortalKontrol.prove_proveWithdrawalTransaction_paused1" \
"OptimismPortalKontrol.prove_finalizeWithdrawalTransaction_paused" \
"L1StandardBridgeKontrol.prove_finalizeBridgeERC20_paused" \
"L1StandardBridgeKontrol.prove_finalizeBridgeETH_paused" \
"L1ERC721BridgeKontrol.prove_finalizeBridgeERC721_paused" \
"L1CrossDomainMessengerKontrol.prove_relayMessage_paused"
)
elif [ "$CUSTOM_TESTS" != 0 ]; then
test_list=( "${@:${CUSTOM_TESTS}}" )
fi
tests="" tests=""
for test_name in "${test_list[@]}"; do for test_name in "${test_list[@]}"; do
tests+="--match-test $test_name " tests+="--match-test $test_name "
...@@ -120,18 +143,25 @@ done ...@@ -120,18 +143,25 @@ done
######################### #########################
# kontrol prove options # # kontrol prove options #
######################### #########################
max_depth=1000000 max_depth=10000
max_iterations=1000000 max_iterations=10000
smt_timeout=100000 smt_timeout=100000
max_workers=7 # Set to 7 since the CI machine has 8 CPUs max_workers=7 # Set to 7 since the CI machine has 8 CPUs
# workers is the minimum between max_workers and the length of test_list # workers is the minimum between max_workers and the length of test_list
workers=$((${#test_list[@]}>max_workers ? max_workers : ${#test_list[@]})) # unless no test arguments are provided, in which case we default to max_workers
if [ "$CUSTOM_TESTS" == 0 ] && [ "$SCRIPT_TESTS" == false ]; then
workers=${max_workers}
else
workers=$((${#test_list[@]}>max_workers ? max_workers : ${#test_list[@]}))
fi
reinit=--reinit reinit=--reinit
reinit= reinit=
break_on_calls=--no-break-on-calls break_on_calls=--no-break-on-calls
# break_on_calls= # break_on_calls=
break_every_step=--break-every-step
break_every_step=
auto_abstract=--auto-abstract-gas auto_abstract=--auto-abstract-gas
# auto_abstract= auto_abstract=
bug_report=--bug-report bug_report=--bug-report
bug_report= bug_report=
use_booster=--use-booster use_booster=--use-booster
......
...@@ -4,5 +4,5 @@ ...@@ -4,5 +4,5 @@
"geth": "v1.13.4", "geth": "v1.13.4",
"nvm": "v20.9.0", "nvm": "v20.9.0",
"slither": "0.10.0", "slither": "0.10.0",
"kontrol": "0.1.127" "kontrol": "0.1.196"
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment