diff --git a/.github/actions/cargo-risczero-install/action.yaml b/.github/actions/cargo-risczero-install/action.yaml index c35db0ba..8d72e0b8 100644 --- a/.github/actions/cargo-risczero-install/action.yaml +++ b/.github/actions/cargo-risczero-install/action.yaml @@ -28,11 +28,11 @@ runs: ref: ${{ inputs.ref }} lfs: true - name: install cargo-risczero - run: cargo install --path risc0/cargo-risczero --no-default-features --features "${{ inputs.features }}" + run: cargo install --locked --path risc0/cargo-risczero --no-default-features --features "${{ inputs.features }}" working-directory: tmp/risc0 shell: bash - name: install r0vm - run: cargo install --bin r0vm --path risc0/cargo-risczero --features "${{ inputs.features }}" + run: cargo install --locked --bin r0vm --path risc0/cargo-risczero --features "${{ inputs.features }}" shell: bash working-directory: tmp/risc0 - name: install toolchains diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index acaf00c0..80ae37c3 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -66,7 +66,7 @@ jobs: - uses: risc0/risc0/.github/actions/sccache@main with: key: ${{ matrix.os }}-${{ matrix.feature }} - - uses: risc0/foundry-toolchain@2fe7e70b520f62368a0e3c464f997df07ede420f + - uses: foundry-rs/foundry-toolchain@v1 - uses: ./.github/actions/cargo-risczero-install with: ref: ${{ env.RISC0_MONOREPO_REF }} @@ -82,7 +82,7 @@ jobs: shell: bash - name: Start local Ethereum testnet run: | - kurtosis --enclave local-eth-testnet run github.com/ethpandaops/ethereum-package@2e9e5a41784f792a206f1a108c2c96830b2c95ef + kurtosis --enclave local-eth-testnet run github.com/ethpandaops/ethereum-package@4.4.0 echo "ETH_TESTNET_EL_URL=http://$(kurtosis port print local-eth-testnet el-1-geth-lighthouse rpc)" >> $GITHUB_ENV echo "ETH_TESTNET_CL_URL=$(kurtosis port print local-eth-testnet cl-1-lighthouse-geth http)" >> $GITHUB_ENV - name: Wait for the local Ethereum testnet to come up diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 12e71a88..af910d98 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,7 +58,7 @@ jobs: - name: cargo check examples run: ../.github/scripts/cargo-check.sh working-directory: examples - - uses: risc0/foundry-toolchain@2fe7e70b520f62368a0e3c464f997df07ede420f + - uses: foundry-rs/foundry-toolchain@v1 - name: forge check risc0-ethereum run: forge fmt --check working-directory: contracts @@ -102,12 +102,14 @@ jobs: env: RUSTFLAGS: -Dwarnings RISC0_SKIP_BUILD: true + RISC0_SKIP_BUILD_KERNEL: true, - name: cargo clippy $CARGO_LOCKED all examples run: ../.github/scripts/cargo-clippy.sh working-directory: examples env: RUSTFLAGS: -Dwarnings RISC0_SKIP_BUILD: true + RISC0_SKIP_BUILD_KERNEL: true, - run: sccache --show-stats test-risc0-ethereum: @@ -145,13 +147,13 @@ jobs: ref: ${{ env.RISC0_MONOREPO_REF }} toolchain-version: ${{ env.RISC0_TOOLCHAIN_VERSION }} features: ${{ matrix.feature }} - - uses: risc0/foundry-toolchain@2fe7e70b520f62368a0e3c464f997df07ede420f + - uses: foundry-rs/foundry-toolchain@v1 - name: cargo build run: cargo build $CARGO_LOCKED --workspace --all-features - name: cargo test run: cargo test $CARGO_LOCKED --workspace --all-features --timings - name: Upload timings artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cargo-timings-${{ matrix.os }}-${{ matrix.device }} path: target/cargo-timings/ @@ -188,7 +190,7 @@ jobs: ref: ${{ env.RISC0_MONOREPO_REF }} toolchain-version: ${{ env.RISC0_TOOLCHAIN_VERSION }} features: ${{ matrix.feature }} - - uses: risc0/foundry-toolchain@2fe7e70b520f62368a0e3c464f997df07ede420f + - uses: foundry-rs/foundry-toolchain@v1 - name: cargo test all examples run: ../.github/scripts/cargo-test.sh working-directory: examples @@ -206,8 +208,11 @@ jobs: with: submodules: recursive - uses: risc0/risc0/.github/actions/rustup@main - - uses: risc0/foundry-toolchain@2fe7e70b520f62368a0e3c464f997df07ede420f + - uses: foundry-rs/foundry-toolchain@v1 - run: cargo doc $CARGO_LOCKED --all-features --no-deps --workspace + env: + RISC0_SKIP_BUILD: true, + RISC0_SKIP_BUILD_KERNEL: true, - run: forge doc # Run as a separate job because we need to install a different set of tools. diff --git a/contracts/deployment-test/Deployment.t.sol b/contracts/deployment-test/Deployment.t.sol index df66e6c7..5c91200d 100644 --- a/contracts/deployment-test/Deployment.t.sol +++ b/contracts/deployment-test/Deployment.t.sol @@ -22,6 +22,8 @@ import {TimelockController} from "openzeppelin/contracts/governance/TimelockCont import {RiscZeroVerifierRouter} from "../src/RiscZeroVerifierRouter.sol"; import {IRiscZeroVerifier} from "../src/IRiscZeroVerifier.sol"; import {ConfigLoader, Deployment, DeploymentLib, VerifierDeployment} from "../src/config/Config.sol"; +import {IRiscZeroSelectable} from "../src/IRiscZeroSelectable.sol"; +import {RiscZeroVerifierEmergencyStop} from "../src/RiscZeroVerifierEmergencyStop.sol"; /// Test designed to be run against a chain with an active deployment of the RISC Zero contracts. /// Checks that the deployment matches what is recorded in the deployment.toml file. @@ -118,7 +120,9 @@ contract DeploymentTest is Test { IRiscZeroVerifier verifierImpl = router.getVerifier(verifierConfig.selector); require(address(verifierImpl) != address(0), "verifier impl returned the zero address"); require(keccak256(address(verifierImpl).code) != keccak256(bytes("")), "verifier impl has no deployed code"); - // TODO: When SELECTOR is added to the public verifier interface, also check the verifier has the expected selector. + address verifierImplAddress = address(RiscZeroVerifierEmergencyStop(address(verifierImpl)).verifier()); + IRiscZeroSelectable verifierSelectable = IRiscZeroSelectable(verifierImplAddress); + require(verifierConfig.selector == verifierSelectable.SELECTOR(), "selector mismatch"); } } } diff --git a/contracts/deployment.toml b/contracts/deployment.toml index ecc45312..472d232f 100644 --- a/contracts/deployment.toml +++ b/contracts/deployment.toml @@ -13,6 +13,7 @@ router = "0x8EaB2D97Dfce405A1692a21b3ff3A172d593D319" # TODO: Add information for 1.0 contracts. [[chains.ethereum-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -20,6 +21,7 @@ verifier = "0x5a99469f18a5863D3258E577892589386dFD965E" estop = "0xB839eA7bBA8e6bB2893ca5252F3f3C13323D74F7" [[chains.ethereum-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x94A4684d6F7085C19138Bd4f9F3295fa9943C622" @@ -41,6 +43,7 @@ timelock-delay = 1 router = "0x925d8331ddc0a1F0d96E68CF073DFE1d92b69187" [[chains.ethereum-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -48,6 +51,7 @@ verifier = "0xf4D938c73Bcc124e02A2D6c7557e98838B5E91B4" estop = "0x1C182869A6bF84DfAc0a70B46e2f9b3aeE9100e1" [[chains.ethereum-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0xd9b0d07CeCd808a8172F21fA7C97992168f045CA" @@ -69,6 +73,7 @@ timelock-delay = 1 router = "0xf70aBAb028Eb6F4100A24B203E113D94E87DE93C" [[chains.ethereum-holesky.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -76,6 +81,7 @@ verifier = "0xDC986a09728F76110FF666eE7b20d99086501d15" estop = "0x0b144E07A0826182B6b59788c34b32Bfa86Fb711" [[chains.ethereum-holesky.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x44c220f0598345195cE99AD6A57aDfFcb9Ea33e7" @@ -97,6 +103,7 @@ timelock-delay = 604800 router = "0x0b144e07a0826182b6b59788c34b32bfa86fb711" [[chains.arbitrum-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -104,6 +111,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.arbitrum-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" @@ -125,6 +133,7 @@ timelock-delay = 1 router = "0x0b144e07a0826182b6b59788c34b32bfa86fb711" [[chains.arbitrum-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -132,6 +141,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.arbitrum-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" @@ -153,6 +163,7 @@ timelock-delay = 604800 router = "0x0b144E07A0826182B6b59788c34b32Bfa86Fb711" [[chains.avalanche-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -160,6 +171,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.avalanche-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" @@ -181,6 +193,7 @@ timelock-delay = 1 router = "0x0b144E07A0826182B6b59788c34b32Bfa86Fb711" [[chains.avalanche-fuji.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -188,6 +201,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.avalanche-fuji.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" @@ -209,6 +223,7 @@ timelock-delay = 604800 router = "0x0b144e07a0826182b6b59788c34b32bfa86fb711" [[chains.base-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -216,6 +231,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.base-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" @@ -237,6 +253,7 @@ timelock-delay = 1 router = "0x0b144e07a0826182b6b59788c34b32bfa86fb711" [[chains.base-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -244,6 +261,7 @@ verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" estop = "0x5E36f0D56741013d864d8FEb5950AB0E7Eff9Ab1" [[chains.base-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x2DEfEA335392bb62d01f74e338697C7B31De254C" @@ -265,6 +283,7 @@ timelock-delay = 604800 router = "0x0b144e07a0826182b6b59788c34b32bfa86fb711" [[chains.optimism-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -272,6 +291,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.optimism-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" @@ -295,6 +315,7 @@ router = "0xB369b4dd27FBfb59921d3A4a3D23AC2fc32FB908" # NOTE: 1.0 was not deployed to OP Sepolia. [[chains.optimism-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -302,6 +323,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.optimism-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" @@ -323,6 +345,7 @@ timelock-delay = 604800 router = "0x0b144e07a0826182b6b59788c34b32bfa86fb711" [[chains.linea-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -330,6 +353,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.linea-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" @@ -357,6 +381,7 @@ router = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" # As a result, the router is deployed, but it is empty and useless. [[chains.linea-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -364,6 +389,7 @@ verifier = "0x0b144E07A0826182B6b59788c34b32Bfa86Fb711" estop = "0x8EaB2D97Dfce405A1692a21b3ff3A172d593D319" [[chains.linea-sepolia.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" unroutable = true selector = "0x50bd1769" @@ -386,6 +412,7 @@ timelock-delay = 604800 router = "0x0b144e07a0826182b6b59788c34b32bfa86fb711" [[chains.polygon-zkevm-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.2" unroutable = true selector = "0x4c630d87" @@ -393,6 +420,7 @@ verifier = "0xBDaEd5bbf8016AfD05Fc4659572e5fEb5854aAD4" estop = "0x27983ee173aD10E171D17C9c5C14d5baFE997609" [[chains.polygon-zkevm-mainnet.verifiers]] +name = "RiscZeroGroth16Verifier" version = "1.1.0-rc.3" selector = "0x50bd1769" verifier = "0x84b943E31e7fAe6072ce5F75eb4694C7D5F9b0cF" diff --git a/contracts/script/Manage.s.sol b/contracts/script/Manage.s.sol index 823b7c53..26b9ed3a 100644 --- a/contracts/script/Manage.s.sol +++ b/contracts/script/Manage.s.sol @@ -25,6 +25,7 @@ import {RiscZeroVerifierEmergencyStop} from "../src/RiscZeroVerifierEmergencySto import {IRiscZeroVerifier} from "../src/IRiscZeroVerifier.sol"; import {IRiscZeroSelectable} from "../src/IRiscZeroSelectable.sol"; import {ControlID, RiscZeroGroth16Verifier} from "../src/groth16/RiscZeroGroth16Verifier.sol"; +import {RiscZeroSetVerifier, RiscZeroSetVerifierLib} from "../src/RiscZeroSetVerifier.sol"; /// @notice Compare strings for equality. function stringEq(string memory a, string memory b) pure returns (bool) { @@ -108,7 +109,7 @@ contract RiscZeroManagementScript is Script { if (address(_verifier) != address(0)) { return _verifier; } - _verifier = IRiscZeroVerifier(address(verifierEstop().verifier())); + _verifier = verifierEstop().verifier(); console2.log("Using IRiscZeroVerifier at address", address(_verifier)); return _verifier; } @@ -173,8 +174,21 @@ contract DeployTimelockRouter is RiscZeroManagementScript { } } +/// @notice Script for printing the selector of the RiscZeroSetVerifier. +/// @dev Use the following environment variable to control the script: +/// * SET_BUILDER_IMAGE_ID image ID of the SetBuilder guest +contract SetVerifierSelector is RiscZeroManagementScript { + function run() external view { + bytes32 SET_BUILDER_IMAGE_ID = vm.envBytes32("SET_BUILDER_IMAGE_ID"); + console2.log("SET_BUILDER_IMAGE_ID:", Strings.toHexString(uint256(SET_BUILDER_IMAGE_ID))); + bytes4 selector = RiscZeroSetVerifierLib.selector(SET_BUILDER_IMAGE_ID); + console2.log("selector:", Strings.toHexString(uint256(uint32(selector)))); + } +} + /// @notice Deployment script for the RISC Zero verifier with Emergency Stop mechanism. /// @dev Use the following environment variable to control the deployment: +/// * CHAIN_KEY key of the target chain /// * VERIFIER_ESTOP_OWNER owner of the emergency stop contract /// /// See the Foundry documentation for more information about Solidity scripts. @@ -190,7 +204,7 @@ contract DeployEstopVerifier is RiscZeroManagementScript { vm.broadcast(deployerAddress()); RiscZeroGroth16Verifier groth16Verifier = new RiscZeroGroth16Verifier(ControlID.CONTROL_ROOT, ControlID.BN254_CONTROL_ID); - _verifier = IRiscZeroVerifier(address(groth16Verifier)); + _verifier = groth16Verifier; vm.broadcast(deployerAddress()); _verifierEstop = new RiscZeroVerifierEmergencyStop(groth16Verifier, verifierEstopOwner); @@ -198,6 +212,7 @@ contract DeployEstopVerifier is RiscZeroManagementScript { // Print in TOML format console2.log(""); console2.log(string.concat("[[chains.", chainKey, ".verifiers]]")); + console2.log("name = \"RiscZeroGroth16Verifier\""); console2.log(string.concat("version = \"", groth16Verifier.VERSION(), "\"")); console2.log( string.concat("selector = \"", Strings.toHexString(uint256(uint32(groth16Verifier.SELECTOR())), 4), "\"") @@ -207,6 +222,48 @@ contract DeployEstopVerifier is RiscZeroManagementScript { } } +/// @notice Deployment script for the RISC Zero SetVerifier with Emergency Stop mechanism. +/// @dev Use the following environment variable to control the deployment: +/// * CHAIN_KEY key of the target chain +/// * VERIFIER_ESTOP_OWNER owner of the emergency stop contract +/// * SET_BUILDER_IMAGE_ID image ID of the SetBuilder guest +/// * SET_BUILDER_GUEST_URL URL of the SetBuilder guest +/// +/// See the Foundry documentation for more information about Solidity scripts. +/// https://book.getfoundry.sh/tutorials/solidity-scripting +contract DeployEstopSetVerifier is RiscZeroManagementScript { + function run() external { + string memory chainKey = vm.envString("CHAIN_KEY"); + console2.log("chainKey:", chainKey); + address verifierEstopOwner = vm.envAddress("VERIFIER_ESTOP_OWNER"); + console2.log("verifierEstopOwner:", verifierEstopOwner); + bytes32 SET_BUILDER_IMAGE_ID = vm.envBytes32("SET_BUILDER_IMAGE_ID"); + console2.log("SET_BUILDER_IMAGE_ID:", Strings.toHexString(uint256(SET_BUILDER_IMAGE_ID))); + string memory SET_BUILDER_GUEST_URL = vm.envString("SET_BUILDER_GUEST_URL"); + console2.log("SET_BUILDER_GUEST_URL:", SET_BUILDER_GUEST_URL); + + // Deploy new contracts + vm.broadcast(deployerAddress()); + RiscZeroSetVerifier setVerifier = + new RiscZeroSetVerifier(verifierRouter(), SET_BUILDER_IMAGE_ID, SET_BUILDER_GUEST_URL); + _verifier = setVerifier; + + vm.broadcast(deployerAddress()); + _verifierEstop = new RiscZeroVerifierEmergencyStop(_verifier, verifierEstopOwner); + + // Print in TOML format + console2.log(""); + console2.log(string.concat("[[chains.", chainKey, ".verifiers]]")); + console2.log("name = \"RiscZeroSetVerifier\""); + console2.log(string.concat("version = \"", setVerifier.VERSION(), "\"")); + console2.log( + string.concat("selector = \"", Strings.toHexString(uint256(uint32(setVerifier.SELECTOR())), 4), "\"") + ); + console2.log(string.concat("verifier = \"", Strings.toHexString(uint256(uint160(address(setVerifier)))), "\"")); + console2.log(string.concat("estop = \"", Strings.toHexString(uint256(uint160(address(_verifierEstop)))), "\"")); + } +} + /// @notice Schedule addition of verifier to router. /// @dev Use the following environment variable to control the deployment: /// * SCHEDULE_DELAY (optional) minimum delay in seconds for the scheduled action diff --git a/contracts/script/README.md b/contracts/script/README.md index cb052c91..ca37cabe 100644 --- a/contracts/script/README.md +++ b/contracts/script/README.md @@ -302,6 +302,128 @@ Make sure to set `TIMELOCK_CONTROLLER` and `VERIFIER_ROUTER`. 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 ``` +## Deploy a set verifier with emergency stop mechanism + +This is a two-step process, guarded by the `TimelockController`. + +### Deploy the set verifier + +1. Make available for download the `set-builder` elf and export its image ID and url in the `SET_BUILDER_IMAGE_ID` and `SET_BUILDER_GUEST_URL` env variables respectively. + + To generate a deterministic image ID run (from the repo root folder): + + ```zsh + RISC0_USE_DOCKER=true cargo build + ``` + + > [!NOTE] + > This will populate the image ID in the `contracts/src/SetBuilderImageID.sol`. + > You can then upload the file located in `target/riscv-guest/riscv32im-risc0-zkvm-elf/docker/set_builder/set-builder` + > to some HTTP server (such as Pinata) and get back a download URL. + > Finally export these values in the in the `SET_BUILDER_IMAGE_ID` and `SET_BUILDER_GUEST_URL` env variables. + +2. Set the verifier selector for the `RiscZeroSetVerifier` contract you will be deploying: + + ```zsh + export VERIFIER_SELECTOR=$(bash contracts/script/manage SetVerifierSelector | grep selector | awk -F': ' '{print $2}' | tee /dev/stderr) + ``` + +3. Dry run deployment of the set verifier and estop: + + ```zsh + VERIFIER_ESTOP_OWNER=${ADMIN_ADDRESS:?} \ + bash contracts/script/manage DeployEstopSetVerifier + ``` + + > [!IMPORTANT] + > Check the logs from this dry run to verify the estop owner is the expected address. + > It should be equal to the RISC Zero admin address on the given chain. + > Note that it should not be the `TimelockController`. + > Also check the chain ID to ensure you are deploying to the chain you expect. + > And check the selector to make sure it matches what you expect. + +4. Send deployment transactions for the set verifier by running the command again with `--broadcast`. + + This will result in two transactions sent from the deployer address. + + > [!NOTE] + > When using Fireblocks, sending a transaction to a particular address may require allow-listing it. + > In order to ensure that estop operations are possible, make sure to allow-list the new estop contract. + +5. Verify the contracts on Etherscan (or its equivalent) by running the command again without `--broadcast` and add `--verify`. + +6. Add the addresses for the newly deployed contract to the `deployment.toml` file. + + Load the deployed addresses into the environment: + + ```zsh + export TIMELOCK_CONTROLLER=$(yq eval -e ".chains[\"${CHAIN_KEY:?}\"].timelock-controller" contracts/deployment.toml | tee /dev/stderr) + export VERIFIER_ROUTER=$(yq eval -e ".chains[\"${CHAIN_KEY:?}\"].router" contracts/deployment.toml | tee /dev/stderr) + export VERIFIER_ESTOP=$(yq eval -e ".chains[\"${CHAIN_KEY:?}\"].verifiers[] | select(.selector == \"${VERIFIER_SELECTOR:?}\") | .estop" contracts/deployment.toml | tee /dev/stderr) + ``` + +6. Test the deployment. + + ```console + cast call --rpc-url ${RPC_URL:?} \ + ${VERIFIER_ESTOP:?} \ + 'paused()(bool)' + false + + cast call --rpc-url ${RPC_URL:?} \ + ${VERIFIER_ESTOP:?} \ + 'owner()(address)' + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 + ``` + +7. Dry run the operation to schedule the operation to add the verifier to the router. + + Fill in the addresses for the relevant chain below. + `ADMIN_PUBLIC_KEY` should be set to the Fireblocks admin address. + + ```zsh + bash contracts/script/manage ScheduleAddVerifier + ``` + +8. Send the transaction for the scheduled update by running the command again with `--broadcast`. + + This will send one transaction from the admin address. + + > [!IMPORTANT] + > If the admin address is in Fireblocks, this will prompt the admins for approval. + +### Finish the update + +After the delay on the timelock controller has pass, the operation to add the new set verifier to the router can be executed. + +Make sure to set `TIMELOCK_CONTROLLER` and `VERIFIER_ROUTER`. + +1. Set the verifier selector and estop address for the set verifier: + + ```zsh + export VERIFIER_SELECTOR=$(bash contracts/script/manage SetVerifierSelector | grep selector | awk -F': ' '{print $2}' | tee /dev/stderr) + export VERIFIER_ESTOP=$(yq eval -e ".chains[\"${CHAIN_KEY:?}\"].verifiers[] | select(.selector == \"${VERIFIER_SELECTOR:?}\") | .estop" contracts/deployment.toml | tee /dev/stderr) + ``` + +2. Dry the transaction to execute the add verifier operation: + + ```zsh + bash contracts/script/manage FinishAddVerifier + ``` + +3. Run the command again with `--broadcast` + + This will send one transaction from the admin address. + +4. Test the deployment. + + ```bash + cast call --rpc-url ${RPC_URL:?} \ + ${VERIFIER_ROUTER:?} \ + 'getVerifier(bytes4)(address)' ${VERIFIER_SELECTOR:?} + 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 + ``` + ## Remove a verifier This is a two-step process, guarded by the `TimelockController`. @@ -310,7 +432,7 @@ This is a two-step process, guarded by the `TimelockController`. 1. Set the verifier selector and estop address for the verifier: - > TIP: One place to find this information is in `./contracts/test/RiscZeroGroth16Verifier.t.sol` + > TIP: One place to find this information is in `./contracts/test/RiscZeroGroth16Verifier.t.sol` for the `RiscZeroGroth16Verifier` or you can run `bash contracts/script/manage SetVerifierSelector` for the `RiscZeroSetVerifier`. ```zsh export VERIFIER_SELECTOR="0x..." @@ -330,7 +452,7 @@ This is a two-step process, guarded by the `TimelockController`. 1. Set the verifier selector and estop address for the verifier: - > TIP: One place to find this information is in `./contracts/test/RiscZeroGroth16Verifier.t.sol` + > TIP: One place to find this information is in `./contracts/test/RiscZeroGroth16Verifier.t.sol` for the `RiscZeroGroth16Verifier` or you can run `bash contracts/script/manage SetVerifierSelector` for the `RiscZeroSetVerifier`. ```zsh export VERIFIER_SELECTOR="0x..." diff --git a/contracts/src/RiscZeroSetVerifier.sol b/contracts/src/RiscZeroSetVerifier.sol index 4e1b897e..dc5bfda3 100644 --- a/contracts/src/RiscZeroSetVerifier.sol +++ b/contracts/src/RiscZeroSetVerifier.sol @@ -25,6 +25,23 @@ import {IRiscZeroSetVerifier, Seal} from "./IRiscZeroSetVerifier.sol"; /// usually indicates a mismatch between the version of the prover and this verifier. error SelectorMismatch(bytes4 received, bytes4 expected); +library RiscZeroSetVerifierLib { + function selector(bytes32 imageId) internal pure returns (bytes4) { + return bytes4( + sha256( + abi.encodePacked( + // tag + sha256("risc0.SetInclusionReceiptVerifierParameters"), + // down + imageId, + // down length + uint16(1) << 8 + ) + ) + ); + } +} + /// @notice RiscZeroSetVerifier verifier contract for RISC Zero receipts of execution. contract RiscZeroSetVerifier is IRiscZeroSetVerifier { using ReceiptClaimLib for ReceiptClaim; @@ -58,18 +75,7 @@ contract RiscZeroSetVerifier is IRiscZeroSetVerifier { IMAGE_ID = imageId; imageUrl = _imageUrl; - SELECTOR = bytes4( - sha256( - abi.encodePacked( - // tag - sha256("risc0.SetInclusionReceiptVerifierParameters"), - // down - imageId, - // down length - uint16(1) << 8 - ) - ) - ); + SELECTOR = RiscZeroSetVerifierLib.selector(imageId); } /// @inheritdoc IRiscZeroVerifier diff --git a/contracts/src/config/Config.sol b/contracts/src/config/Config.sol index 3bd50289..fce929b3 100644 --- a/contracts/src/config/Config.sol +++ b/contracts/src/config/Config.sol @@ -26,6 +26,7 @@ import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; /// Many verifiers may be part of a deployment, with the router serving the purpose of making them /// all accessible at a single address. struct VerifierDeployment { + string name; string version; bytes4 selector; address verifier; @@ -157,6 +158,7 @@ library ConfigParser { verifierKey = string.concat(chain, ".verifiers[", VM.toString(verifierIndex), "]"); while (stdToml.keyExists(config, verifierKey)) { VerifierDeployment memory verifier; + verifier.name = stdToml.readStringOr(config, string.concat(verifierKey, ".name"), ""); verifier.version = stdToml.readStringOr(config, string.concat(verifierKey, ".version"), ""); verifier.selector = bytes4(stdToml.readUint(config, string.concat(verifierKey, ".selector")).toUint32()); verifier.verifier = stdToml.readAddress(config, string.concat(verifierKey, ".verifier"));