diff --git a/.github/workflows/bonsai.yml b/.github/workflows/bonsai.yml index ec2e8382..01acb877 100644 --- a/.github/workflows/bonsai.yml +++ b/.github/workflows/bonsai.yml @@ -17,7 +17,7 @@ permissions: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} RISC0_TOOLCHAIN_VERSION: v2024-04-22.0 - RISC0_MONOREPO_REF: "v1.0.0-rc.7" + RISC0_MONOREPO_REF: "release-1.0" jobs: e2e-test: @@ -30,8 +30,8 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - uses: risc0/risc0/.github/actions/rustup@v1.0.0-rc.7 - - uses: risc0/risc0/.github/actions/sccache@v1.0.0-rc.7 + - uses: risc0/risc0/.github/actions/rustup@release-1.0 + - uses: risc0/risc0/.github/actions/sccache@release-1.0 with: key: Linux-default - uses: risc0/foundry-toolchain@2fe7e70b520f62368a0e3c464f997df07ede420f diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 31a4e78c..e96ee2d2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ permissions: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} RISC0_TOOLCHAIN_VERSION: v2024-04-22.0 - RISC0_MONOREPO_REF: "v1.0.0-rc.7" + RISC0_MONOREPO_REF: "release-1.0" jobs: # see: https://github.com/orgs/community/discussions/26822 @@ -45,7 +45,7 @@ jobs: # Full history is required by license-check.py fetch-depth: 0 submodules: recursive - - uses: risc0/risc0/.github/actions/rustup@v1.0.0-rc.7 + - uses: risc0/risc0/.github/actions/rustup@release-1.0 - name: Install cargo-sort uses: risc0/cargo-install@b9307573043522ab0d3e3be64a51763b765b52a4 with: @@ -93,9 +93,9 @@ jobs: with: submodules: recursive - if: matrix.feature == 'cuda' - uses: risc0/risc0/.github/actions/cuda@v1.0.0-rc.7 - - uses: risc0/risc0/.github/actions/rustup@v1.0.0-rc.7 - - uses: risc0/risc0/.github/actions/sccache@v1.0.0-rc.7 + uses: risc0/risc0/.github/actions/cuda@release-1.0 + - uses: risc0/risc0/.github/actions/rustup@release-1.0 + - uses: risc0/risc0/.github/actions/sccache@release-1.0 with: key: ${{ matrix.os }}-${{ matrix.feature }} - uses: ./.github/actions/cargo-risczero-install @@ -134,9 +134,9 @@ jobs: with: submodules: recursive - if: matrix.feature == 'cuda' - uses: risc0/risc0/.github/actions/cuda@v1.0.0-rc.7 - - uses: risc0/risc0/.github/actions/rustup@v1.0.0-rc.7 - - uses: risc0/risc0/.github/actions/sccache@v1.0.0-rc.7 + uses: risc0/risc0/.github/actions/cuda@release-1.0 + - uses: risc0/risc0/.github/actions/rustup@release-1.0 + - uses: risc0/risc0/.github/actions/sccache@release-1.0 with: key: ${{ matrix.os }}-${{ matrix.feature }} - uses: risc0/foundry-toolchain@2fe7e70b520f62368a0e3c464f997df07ede420f @@ -167,8 +167,8 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - uses: risc0/risc0/.github/actions/rustup@v1.0.0-rc.7 - - uses: risc0/risc0/.github/actions/sccache@v1.0.0-rc.7 + - uses: risc0/risc0/.github/actions/rustup@release-1.0 + - uses: risc0/risc0/.github/actions/sccache@release-1.0 with: key: macOS-default - uses: risc0/foundry-toolchain@2fe7e70b520f62368a0e3c464f997df07ede420f diff --git a/Cargo.lock b/Cargo.lock index 4cb0d6d2..e7e0f3fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -672,9 +672,9 @@ dependencies = [ [[package]] name = "bonsai-sdk" -version = "0.8.0-rc.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ddc06a9da40f1814918e077807a38bdfe9ed92d08ca600fcdb27f19685718ad" +checksum = "a7781292e9bcc1f54de6839dbab88b4032d2a20ab1d4fb3d8f045e9cecf5486e" dependencies = [ "reqwest 0.12.4", "risc0-groth16", @@ -3425,9 +3425,9 @@ dependencies = [ [[package]] name = "risc0-binfmt" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8675cbcc76c912d5e766ee6fe377c2204d8a6c8dd47a540c0bd9a673590d7279" +checksum = "b0277e19d88c8b9e3d425ac446cb8fa334231764fd2621129b770a691451f4b9" dependencies = [ "anyhow", "elf", @@ -3439,9 +3439,9 @@ dependencies = [ [[package]] name = "risc0-build" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea96470ab985621e5398bf51b537288b651502b14f6ae412e73c638935dc3ea1" +checksum = "30ec1efbbed55de3e3a8c6f5e462e9f5325d467b872bb09049a8bd6a32e3b445" dependencies = [ "anyhow", "cargo_metadata", @@ -3457,7 +3457,7 @@ dependencies = [ [[package]] name = "risc0-build-ethereum" -version = "1.0.0-rc.7" +version = "1.0.0" dependencies = [ "anyhow", "hex", @@ -3468,9 +3468,9 @@ dependencies = [ [[package]] name = "risc0-circuit-recursion" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459f0690e4e6da6579108b6a42ae0d32082c51b2c96c8b6889d319be742fe295" +checksum = "2db3e76adef5f6883c44cf3705eb7668566df4d6b66443ca2d93c656acc7ef90" dependencies = [ "anyhow", "bytemuck", @@ -3482,9 +3482,9 @@ dependencies = [ [[package]] name = "risc0-circuit-rv32im" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e1868cbd856dfcd30a8dcf41bd981e2d40867302ead41c93f3ef76bfcc20fa" +checksum = "f6abc6d66871cb9b833ddf0a4ce76928c1cfa53a2d619de64dd403e907491360" dependencies = [ "anyhow", "risc0-binfmt", @@ -3497,9 +3497,9 @@ dependencies = [ [[package]] name = "risc0-core" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fa2b29c4232accff05dfb2025ba6596e7be11a8da5e8d73e657fdabfffee46" +checksum = "3eefc8c4376c184e3f7ee8f88fc95f49f062307294ccdfb19ad82506777db587" dependencies = [ "bytemuck", "rand_core", @@ -3507,7 +3507,7 @@ dependencies = [ [[package]] name = "risc0-ethereum-contracts" -version = "1.0.0-rc.7" +version = "1.0.0" dependencies = [ "alloy-sol-types", "anyhow", @@ -3519,7 +3519,7 @@ dependencies = [ [[package]] name = "risc0-forge-ffi" -version = "1.0.0-rc.7" +version = "1.0.0" dependencies = [ "anyhow", "clap", @@ -3531,9 +3531,9 @@ dependencies = [ [[package]] name = "risc0-groth16" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "270a9a9560168788c0cac60ff51ad201f7240416ffc0cad1a1cb9f851376f7d1" +checksum = "9cb82c5ad39105da54c9035896199b6793436a859e0e16e29bc308eb83c1e791" dependencies = [ "anyhow", "ark-bn254", @@ -3576,9 +3576,9 @@ dependencies = [ [[package]] name = "risc0-zkp" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b98e4ff1642e3b7b91edc8f2dd074207864320711b6ef0b290e05dcbae40513" +checksum = "ba1e45db2d5c9806110e8251ada5c6d6850434778378fbd1630363b6f59fde01" dependencies = [ "anyhow", "blake2", @@ -3598,9 +3598,9 @@ dependencies = [ [[package]] name = "risc0-zkvm" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c3c905a3fb48c8c600cd3d9e40c41e1f7db2562c3b41535ad966f4ff5d0ab2" +checksum = "bf582a2b8f7ef826ffc0dc2104965b36d47c94bac8847baeaf9ba8d691744026" dependencies = [ "anyhow", "bincode", @@ -3628,9 +3628,9 @@ dependencies = [ [[package]] name = "risc0-zkvm-platform" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1585bd97cf03bedfd60534923542f26a60ff7c7aa2be15710b7e57ceb5705a" +checksum = "b40eaf89f1ed393326db06a2ae2058fff21db7a8e7fac18eb6ae894fa40f35ff" dependencies = [ "bytemuck", "getrandom", diff --git a/Cargo.toml b/Cargo.toml index 9a965e8e..a8778a72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = ["build", "contracts", "ffi", "steel"] [workspace.package] -version = "1.0.0-rc.7" +version = "1.0.0" edition = "2021" license = "Apache-2.0" homepage = "https://risczero.com/" @@ -11,15 +11,15 @@ repository = "https://github.com/risc0/risc0-ethereum/" [workspace.dependencies] # Intra-workspace dependencies -risc0-build-ethereum = { version = "1.0.0-rc.7", default-features = false, path = "build" } -risc0-ethereum-contracts = { version = "1.0.0-rc.7", default-features = false, path = "contracts" } +risc0-build-ethereum = { version = "1.0.0", default-features = false, path = "build" } +risc0-ethereum-contracts = { version = "1.0.0", default-features = false, path = "contracts" } risc0-steel = { version = "0.11.0", default-features = false, path = "steel" } -risc0-forge-ffi = { version = "1.0.0-rc.7", default-features = false, path = "ffi" } +risc0-forge-ffi = { version = "1.0.0", default-features = false, path = "ffi" } # risc0 monorepo dependencies. -risc0-build = { version = "1.0.0-rc.7", default-features = false } -risc0-zkp = { version = "1.0.0-rc.7", default-features = false } -risc0-zkvm = { version = "1.0.0-rc.7", default-features = false } +risc0-build = { version = "1.0", default-features = false } +risc0-zkp = { version = "1.0", default-features = false } +risc0-zkvm = { version = "1.0", default-features = false } alloy-primitives = { version = "0.7", features = ["serde", "rlp", "std"] } alloy-rlp = { version = "0.3.4", default-features = false } diff --git a/contracts/src/steel/Steel.sol b/contracts/src/steel/Steel.sol new file mode 100644 index 00000000..7fd91b6c --- /dev/null +++ b/contracts/src/steel/Steel.sol @@ -0,0 +1,34 @@ +// Copyright 2024 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.9; + +/// @title Steel Library +/// @notice This library provides a collection of utilities to work with Steel commitments in Solidity. +library Steel { + /// @notice A Commitment struct representing a block number and its block hash. + struct Commitment { + uint256 blockNumber; // Block number at which the commitment was made. + bytes32 blockHash; // Hash of the block at the specified block number. + } + + /// @notice Validates if the provided Commitment matches the block hash of the given block number. + /// @param commitment The Commitment struct to validate. + /// @return isValid True if the commitment's block hash matches the block hash of the block number, false otherwise. + function validateCommitment(Commitment memory commitment) internal view returns (bool isValid) { + return commitment.blockHash == blockhash(commitment.blockNumber); + } +} diff --git a/examples/erc20-counter/Cargo.lock b/examples/erc20-counter/Cargo.lock index 2a97fc5e..9d03753c 100644 --- a/examples/erc20-counter/Cargo.lock +++ b/examples/erc20-counter/Cargo.lock @@ -673,9 +673,9 @@ dependencies = [ [[package]] name = "bonsai-sdk" -version = "0.8.0-rc.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ddc06a9da40f1814918e077807a38bdfe9ed92d08ca600fcdb27f19685718ad" +checksum = "a7781292e9bcc1f54de6839dbab88b4032d2a20ab1d4fb3d8f045e9cecf5486e" dependencies = [ "reqwest 0.12.4", "risc0-groth16", @@ -3402,9 +3402,9 @@ dependencies = [ [[package]] name = "risc0-binfmt" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8675cbcc76c912d5e766ee6fe377c2204d8a6c8dd47a540c0bd9a673590d7279" +checksum = "b0277e19d88c8b9e3d425ac446cb8fa334231764fd2621129b770a691451f4b9" dependencies = [ "anyhow", "elf", @@ -3416,9 +3416,9 @@ dependencies = [ [[package]] name = "risc0-build" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea96470ab985621e5398bf51b537288b651502b14f6ae412e73c638935dc3ea1" +checksum = "30ec1efbbed55de3e3a8c6f5e462e9f5325d467b872bb09049a8bd6a32e3b445" dependencies = [ "anyhow", "cargo_metadata", @@ -3434,7 +3434,7 @@ dependencies = [ [[package]] name = "risc0-build-ethereum" -version = "1.0.0-rc.7" +version = "1.0.0" dependencies = [ "anyhow", "hex", @@ -3444,9 +3444,9 @@ dependencies = [ [[package]] name = "risc0-circuit-recursion" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459f0690e4e6da6579108b6a42ae0d32082c51b2c96c8b6889d319be742fe295" +checksum = "2db3e76adef5f6883c44cf3705eb7668566df4d6b66443ca2d93c656acc7ef90" dependencies = [ "anyhow", "bytemuck", @@ -3458,9 +3458,9 @@ dependencies = [ [[package]] name = "risc0-circuit-rv32im" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e1868cbd856dfcd30a8dcf41bd981e2d40867302ead41c93f3ef76bfcc20fa" +checksum = "f6abc6d66871cb9b833ddf0a4ce76928c1cfa53a2d619de64dd403e907491360" dependencies = [ "anyhow", "risc0-binfmt", @@ -3473,9 +3473,9 @@ dependencies = [ [[package]] name = "risc0-core" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fa2b29c4232accff05dfb2025ba6596e7be11a8da5e8d73e657fdabfffee46" +checksum = "3eefc8c4376c184e3f7ee8f88fc95f49f062307294ccdfb19ad82506777db587" dependencies = [ "bytemuck", "rand_core", @@ -3483,7 +3483,7 @@ dependencies = [ [[package]] name = "risc0-ethereum-contracts" -version = "1.0.0-rc.7" +version = "1.0.0" dependencies = [ "alloy-sol-types", "anyhow", @@ -3493,9 +3493,9 @@ dependencies = [ [[package]] name = "risc0-groth16" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "270a9a9560168788c0cac60ff51ad201f7240416ffc0cad1a1cb9f851376f7d1" +checksum = "9cb82c5ad39105da54c9035896199b6793436a859e0e16e29bc308eb83c1e791" dependencies = [ "anyhow", "ark-bn254", @@ -3535,9 +3535,9 @@ dependencies = [ [[package]] name = "risc0-zkp" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b98e4ff1642e3b7b91edc8f2dd074207864320711b6ef0b290e05dcbae40513" +checksum = "ba1e45db2d5c9806110e8251ada5c6d6850434778378fbd1630363b6f59fde01" dependencies = [ "anyhow", "blake2", @@ -3557,9 +3557,9 @@ dependencies = [ [[package]] name = "risc0-zkvm" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c3c905a3fb48c8c600cd3d9e40c41e1f7db2562c3b41535ad966f4ff5d0ab2" +checksum = "bf582a2b8f7ef826ffc0dc2104965b36d47c94bac8847baeaf9ba8d691744026" dependencies = [ "anyhow", "bincode", @@ -3587,9 +3587,9 @@ dependencies = [ [[package]] name = "risc0-zkvm-platform" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1585bd97cf03bedfd60534923542f26a60ff7c7aa2be15710b7e57ceb5705a" +checksum = "b40eaf89f1ed393326db06a2ae2058fff21db7a8e7fac18eb6ae894fa40f35ff" dependencies = [ "bytemuck", "getrandom", diff --git a/examples/erc20-counter/Cargo.toml b/examples/erc20-counter/Cargo.toml index 8b82368e..b01ed046 100644 --- a/examples/erc20-counter/Cargo.toml +++ b/examples/erc20-counter/Cargo.toml @@ -14,9 +14,9 @@ risc0-ethereum-contracts = { path = "../../contracts" } risc0-steel = { path = "../../steel" } # risc0 monorepo dependencies. -risc0-build = { version = "1.0.0-rc.7", features = ["docker"] } -risc0-zkvm = { version = "1.0.0-rc.7", default-features = false } -risc0-zkp = { version = "1.0.0-rc.7", default-features = false } +risc0-build = { version = "1.0", features = ["docker"] } +risc0-zkvm = { version = "1.0", default-features = false } +risc0-zkp = { version = "1.0", default-features = false } alloy-primitives = { version = "0.7", default-features = false, features = ["rlp", "serde", "std"] } alloy-sol-types = { version = "0.7" } diff --git a/examples/erc20-counter/README.md b/examples/erc20-counter/README.md index 39b8e236..2ca6b630 100644 --- a/examples/erc20-counter/README.md +++ b/examples/erc20-counter/README.md @@ -1,33 +1,30 @@ # RISC Zero View Call Proofs ERC20-Counter Example -> ***WARNING***: This software is still experimental, we do not recommend it for production use. - -This example implements a counter that increments based on off-chain view call proofs submitted to the [Counter] contract. -The contract interacts with ERC-20 tokens, using view call proofs to verify that an account holds at least 1 token before incrementing the counter. -This contract leverages RISC Zero as a [coprocessor] for generating and verifying these proofs. +This example implements a counter that increments based on off-chain RISC Zero [Steel] proofs submitted to the [Counter] contract. +The contract interacts with ERC-20 tokens, using [Steel] proofs to verify that an account holds at least 1 token before incrementing the counter. ## Overview -The [Counter] contract is designed to interact with the Ethereum blockchain, leveraging the power of RISC Zero view call proofs to perform a specific operation: incrementing a counter based on the token holdings of an account. +The [Counter] contract is designed to interact with the Ethereum blockchain, leveraging the power of RISC Zero [Steel] proofs to perform a specific operation: incrementing a counter based on the token holdings of an account. ### Contract Functionality #### Increment Counter -The core functionality of the [Counter] contract is to increment an internal counter whenever a valid view call proof is submitted. +The core functionality of the [Counter] contract is to increment an internal counter whenever a valid proof was submitted. This proof must demonstrate that a specified account holds at least one unit of a particular ERC-20 token. The contract ensures that the counter is only incremented when the proof is verified and the condition of holding at least one token is met. -#### View Call Proof Submission +#### Steel Proof Submission -Users or entities can submit view call proofs to the [Counter] contract. +Users or entities can submit proofs to the [Counter] contract. These proofs are generated off-chain using the RISC Zero zkVM. The proof encapsulates the verification of an account's token balance without exposing the account's details or requiring direct on-chain queries. #### Token Balance Verification -Upon receiving a view call proof, the [Counter] contract decodes and verifies it against the specified ERC-20 token contract. -This process involves validating the proof against the contract's state at a specific block height, ensuring the account in question indeed holds at least one token at the time of the proof's generation. +Upon receiving a [Steel] proof, the [Counter] contract decodes the proof and validates it against the contract's state at a certain block height. +This ensures that the account in question actually holds at least one token at the time the proof was generated. #### Counter Management @@ -80,7 +77,7 @@ When you're ready, follow the [deployment guide] to get your application running [RISC Zero]: https://www.risczero.com/ [Sepolia]: https://www.alchemy.com/overviews/sepolia-testnet [cargo-binstall]: https://github.com/cargo-bins/cargo-binstall#cargo-binaryinstall -[coprocessor]: https://www.risczero.com/news/a-guide-to-zk-coprocessors-for-scalability [deployment guide]: ./deployment-guide.md [install Rust]: https://doc.rust-lang.org/cargo/getting-started/installation.html [Counter]: ./contracts/Counter.sol +[Steel]: https://www.risczero.com/blog/introducing-steel diff --git a/examples/erc20-counter/apps/src/bin/publisher.rs b/examples/erc20-counter/apps/src/bin/publisher.rs index 4e71b378..2066d886 100644 --- a/examples/erc20-counter/apps/src/bin/publisher.rs +++ b/examples/erc20-counter/apps/src/bin/publisher.rs @@ -16,34 +16,26 @@ // to the Bonsai proving service and publish the received proofs directly // to your deployed app contract. -use alloy_primitives::{address, Address}; -use alloy_sol_types::{sol, SolCall, SolInterface}; +use alloy_primitives::Address; +use alloy_sol_types::{sol, SolCall}; use anyhow::Result; use apps::TxSender; use clap::Parser; use erc20_counter_methods::BALANCE_OF_ELF; use risc0_ethereum_contracts::groth16::encode; -use risc0_steel::{config::ETH_SEPOLIA_CHAIN_SPEC, ethereum::EthViewCallEnv, Contract, EvmHeader}; +use risc0_steel::{config::ETH_SEPOLIA_CHAIN_SPEC, ethereum::EthEvmEnv, Contract, EvmBlockHeader}; use risc0_zkvm::{default_prover, ExecutorEnv, ProverOpts, VerifierContext}; use tracing_subscriber::EnvFilter; -/// Address of the deployed contract to call the function on. Here: USDT contract on Sepolia -/// Must match the guest code. -const CONTRACT: Address = address!("299Da20a3e957c78d7634A55D88195224C9f9f6b"); - sol! { /// ERC-20 balance function signature. + /// This must match the signature in the guest. interface IERC20 { function balanceOf(address account) external view returns (uint); } } -// `ICounter` interface automatically generated via the alloy `sol!` macro. -sol! { - interface ICounter { - function increment(bytes calldata journal, bytes calldata seal); - } -} +sol!("../contracts/ICounter.sol"); /// Arguments of the publisher CLI. #[derive(Parser, Debug)] @@ -63,7 +55,11 @@ struct Args { /// Counter's contract address on Ethereum #[clap(long)] - contract: String, + contract: Address, + + /// ERC20 contract address on Ethereum + #[clap(long)] + token: Address, /// Account address to read the balance_of on Ethereum #[clap(long)] @@ -75,43 +71,38 @@ fn main() -> Result<()> { tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env()) .init(); + // parse the command line arguments let args = Args::parse(); - // Create a new `TxSender`. - let tx_sender = TxSender::new( - args.chain_id, - &args.rpc_url, - &args.eth_wallet_private_key, - &args.contract, - )?; - - // Create a view call environment from an RPC endpoint and a block number. If no block number is - // provided, the latest block is used. The `with_chain_spec` method is used to specify the - // chain configuration. - let mut env = - EthViewCallEnv::from_rpc(&args.rpc_url, None)?.with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); - let number = env.header().number(); - let mut contract = Contract::preflight(CONTRACT, &mut env); + // Create an EVM environment from an RPC endpoint and a block number. If no block number is + // provided, the latest block is used. + let mut env = EthEvmEnv::from_rpc(&args.rpc_url, None)?; + // The `with_chain_spec` method is used to specify the chain configuration. + env = env.with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); - // Function to call - let account = args.account; - let call = IERC20::balanceOfCall { account }; + // Prepare the function call + let call = IERC20::balanceOfCall { + account: args.account, + }; - // Preflight the view call to construct the input that is required to execute the function in - // the guest. It also returns the result of the call. + // Preflight the call to execute the function in the guest. + let mut contract = Contract::preflight(args.token, &mut env); let returns = contract.call_builder(&call).call()?; - let view_call_input = env.into_input()?; println!( - "For block {} `{}` returns: {}", - number, + "For block {} calling `{}` on {} returns: {}", + env.header().number(), IERC20::balanceOfCall::SIGNATURE, + args.token, returns._0 ); + println!("proving..."); + let view_call_input = env.into_input()?; let env = ExecutorEnv::builder() .write(&view_call_input)? - .write(&account)? + .write(&args.token)? + .write(&args.account)? .build()?; let receipt = default_prover() @@ -122,20 +113,31 @@ fn main() -> Result<()> { &ProverOpts::groth16(), )? .receipt; + println!("proving...done"); + + // Create a new `TxSender`. + let tx_sender = TxSender::new( + args.chain_id, + &args.rpc_url, + &args.eth_wallet_private_key, + &args.contract.to_string(), + )?; // Encode the groth16 seal with the selector let seal = encode(receipt.inner.groth16()?.seal.clone())?; // Encode the function call for `ICounter.increment(journal, seal)`. - let calldata = ICounter::ICounterCalls::increment(ICounter::incrementCall { - journal: receipt.journal.bytes.clone().into(), + let calldata = ICounter::incrementCall { + journalData: receipt.journal.bytes.into(), seal: seal.into(), - }) + } .abi_encode(); // Send the calldata to Ethereum. + println!("sending tx..."); let runtime = tokio::runtime::Runtime::new()?; runtime.block_on(tx_sender.send(calldata))?; + println!("sending tx...done"); Ok(()) } diff --git a/examples/erc20-counter/apps/src/lib.rs b/examples/erc20-counter/apps/src/lib.rs index fcf50106..4b154739 100644 --- a/examples/erc20-counter/apps/src/lib.rs +++ b/examples/erc20-counter/apps/src/lib.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// The following library provides utility functions to help with sending +// The following library provides utility functions to help with sending // transactions to a deployed app contract on Ethereum. use anyhow::Result; diff --git a/examples/erc20-counter/contracts/Counter.sol b/examples/erc20-counter/contracts/Counter.sol index 6819e02c..808f6d16 100644 --- a/examples/erc20-counter/contracts/Counter.sol +++ b/examples/erc20-counter/contracts/Counter.sol @@ -17,47 +17,56 @@ pragma solidity ^0.8.20; import {IRiscZeroVerifier} from "risc0/IRiscZeroVerifier.sol"; +import {Steel} from "risc0/steel/Steel.sol"; +import {ICounter} from "./ICounter.sol"; import {ImageID} from "./ImageID.sol"; // auto-generated contract after running `cargo build`. -/// @title Counter. -/// @notice Implements a counter that increments based on off-chain view call proofs submitted to this contract. -/// @dev The contract interacts with ERC-20 tokens, using view call proofs to verify that an account holds at least 1 token +/// @title Counter +/// @notice Implements a counter that increments based on off-chain Steel proofs submitted to this contract. +/// @dev The contract interacts with ERC-20 tokens, using Steel proofs to verify that an account holds at least 1 token /// before incrementing the counter. This contract leverages RISC0-zkVM for generating and verifying these proofs. -contract Counter { - struct BlockCommitment { - bytes32 blockHash; - uint256 blockNumber; - } - /// @notice RISC Zero verifier contract address. - - IRiscZeroVerifier public immutable verifier; +contract Counter is ICounter { /// @notice Image ID of the only zkVM binary to accept verification from. bytes32 public constant imageId = ImageID.BALANCE_OF_ID; + /// @notice RISC Zero verifier contract address. + IRiscZeroVerifier public immutable verifier; + + /// @notice Address of the ERC-20 token contract. + address public immutable tokenAddress; + /// @notice Counter to track the number of successful verifications. uint256 public counter; - /// @notice Initialize the contract, binding it to a specified RISC Zero verifier. - constructor(IRiscZeroVerifier _verifier) { + /// @notice Journal that is committed to by the guest. + struct Journal { + Steel.Commitment commitment; + address tokenAddress; + } + + /// @notice Initialize the contract, binding it to a specified RISC Zero verifier and ERC-20 token address. + constructor(IRiscZeroVerifier _verifier, address _tokenAddress) { verifier = _verifier; + tokenAddress = _tokenAddress; counter = 0; } - /// @dev Increment the counter if the view call proof verifies that - /// the specified account holds at least 1 token. - /// - /// The view call proof must be generated off-chain using RISC0-zkVM and submitted here. - /// This function performs the proof verification process. - function increment(bytes calldata journal, bytes calldata seal) public { - // Construct the expected journal data. Verify will fail if journal does not match. - BlockCommitment memory commitment = abi.decode(journal, (BlockCommitment)); - require(blockhash(commitment.blockNumber) == commitment.blockHash); - verifier.verify(seal, imageId, sha256(journal)); - counter = counter + 1; + /// @inheritdoc ICounter + function increment(bytes calldata journalData, bytes calldata seal) external { + // Decode and validate the journal data + Journal memory journal = abi.decode(journalData, (Journal)); + require(journal.tokenAddress == tokenAddress, "Invalid token address"); + require(Steel.validateCommitment(journal.commitment), "Invalid commitment"); + + // Verify the proof + bytes32 journalHash = sha256(journalData); + verifier.verify(seal, imageId, journalHash); + + counter += 1; } - /// @notice Returns the value of the counter. - function get() public view returns (uint256) { + /// @inheritdoc ICounter + function get() external view returns (uint256) { return counter; } } diff --git a/examples/erc20-counter/contracts/ICounter.sol b/examples/erc20-counter/contracts/ICounter.sol new file mode 100644 index 00000000..3e01396e --- /dev/null +++ b/examples/erc20-counter/contracts/ICounter.sol @@ -0,0 +1,26 @@ +// Copyright 2024 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.20; + +interface ICounter { + /// @notice Increments the counter, if the Steel proof verifies that the specified account holds at least 1 token. + /// @dev The Steel proof must be generated off-chain using RISC0-zkVM and submitted here. + function increment(bytes calldata journalData, bytes calldata seal) external; + + /// @notice Returns the value of the counter. + function get() external view returns (uint256); +} diff --git a/examples/erc20-counter/methods/guest/Cargo.lock b/examples/erc20-counter/methods/guest/Cargo.lock index 939a1673..f15caf87 100644 --- a/examples/erc20-counter/methods/guest/Cargo.lock +++ b/examples/erc20-counter/methods/guest/Cargo.lock @@ -1427,9 +1427,9 @@ dependencies = [ [[package]] name = "risc0-binfmt" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8675cbcc76c912d5e766ee6fe377c2204d8a6c8dd47a540c0bd9a673590d7279" +checksum = "b0277e19d88c8b9e3d425ac446cb8fa334231764fd2621129b770a691451f4b9" dependencies = [ "anyhow", "elf", @@ -1441,9 +1441,9 @@ dependencies = [ [[package]] name = "risc0-circuit-recursion" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459f0690e4e6da6579108b6a42ae0d32082c51b2c96c8b6889d319be742fe295" +checksum = "2db3e76adef5f6883c44cf3705eb7668566df4d6b66443ca2d93c656acc7ef90" dependencies = [ "anyhow", "bytemuck", @@ -1455,9 +1455,9 @@ dependencies = [ [[package]] name = "risc0-circuit-rv32im" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e1868cbd856dfcd30a8dcf41bd981e2d40867302ead41c93f3ef76bfcc20fa" +checksum = "f6abc6d66871cb9b833ddf0a4ce76928c1cfa53a2d619de64dd403e907491360" dependencies = [ "anyhow", "risc0-binfmt", @@ -1470,9 +1470,9 @@ dependencies = [ [[package]] name = "risc0-core" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fa2b29c4232accff05dfb2025ba6596e7be11a8da5e8d73e657fdabfffee46" +checksum = "3eefc8c4376c184e3f7ee8f88fc95f49f062307294ccdfb19ad82506777db587" dependencies = [ "bytemuck", "rand_core", @@ -1480,9 +1480,9 @@ dependencies = [ [[package]] name = "risc0-groth16" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "270a9a9560168788c0cac60ff51ad201f7240416ffc0cad1a1cb9f851376f7d1" +checksum = "9cb82c5ad39105da54c9035896199b6793436a859e0e16e29bc308eb83c1e791" dependencies = [ "anyhow", "ark-bn254", @@ -1517,9 +1517,9 @@ dependencies = [ [[package]] name = "risc0-zkp" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b98e4ff1642e3b7b91edc8f2dd074207864320711b6ef0b290e05dcbae40513" +checksum = "ba1e45db2d5c9806110e8251ada5c6d6850434778378fbd1630363b6f59fde01" dependencies = [ "anyhow", "blake2", @@ -1539,9 +1539,9 @@ dependencies = [ [[package]] name = "risc0-zkvm" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c3c905a3fb48c8c600cd3d9e40c41e1f7db2562c3b41535ad966f4ff5d0ab2" +checksum = "bf582a2b8f7ef826ffc0dc2104965b36d47c94bac8847baeaf9ba8d691744026" dependencies = [ "anyhow", "bytemuck", @@ -1564,9 +1564,9 @@ dependencies = [ [[package]] name = "risc0-zkvm-platform" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1585bd97cf03bedfd60534923542f26a60ff7c7aa2be15710b7e57ceb5705a" +checksum = "b40eaf89f1ed393326db06a2ae2058fff21db7a8e7fac18eb6ae894fa40f35ff" dependencies = [ "bytemuck", "getrandom", diff --git a/examples/erc20-counter/methods/guest/Cargo.toml b/examples/erc20-counter/methods/guest/Cargo.toml index ca9142a7..65bda247 100644 --- a/examples/erc20-counter/methods/guest/Cargo.toml +++ b/examples/erc20-counter/methods/guest/Cargo.toml @@ -16,7 +16,7 @@ ahash = { version = "0.8", default-features = false, features = ["compile-time-r alloy-primitives = { version = "0.7" } alloy-sol-types = { version = "0.7" } risc0-steel = { path = "../../../../steel" } -risc0-zkvm = { version = "1.0.0-rc.7", default-features = false, features = ["std"] } +risc0-zkvm = { version = "1.0", default-features = false, features = ["std"] } [patch.crates-io] # use optimized risc0 circuit diff --git a/examples/erc20-counter/methods/guest/src/bin/balance_of.rs b/examples/erc20-counter/methods/guest/src/bin/balance_of.rs index 0d2dab76..58e16920 100644 --- a/examples/erc20-counter/methods/guest/src/bin/balance_of.rs +++ b/examples/erc20-counter/methods/guest/src/bin/balance_of.rs @@ -15,18 +15,15 @@ #![allow(unused_doc_comments)] #![no_main] -use alloy_primitives::{address, Address, U256}; +use alloy_primitives::{Address, U256}; use alloy_sol_types::{sol, SolValue}; -use risc0_steel::{config::ETH_SEPOLIA_CHAIN_SPEC, ethereum::EthViewCallInput, Contract}; +use risc0_steel::{config::ETH_SEPOLIA_CHAIN_SPEC, ethereum::EthEvmInput, Contract, SolCommitment}; use risc0_zkvm::guest::env; risc0_zkvm::guest::entry!(main); /// Specify the function to call using the [`sol!`] macro. -/// This parses the Solidity syntax to generate a struct that implements the [SolCall] trait. -/// The struct instantiated with the arguments can then be passed to the [ViewCall] to execute the -/// call. For example: -/// `IERC20::balanceOfCall { account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4") }` +/// This parses the Solidity syntax to generate a struct that implements the `SolCall` trait. sol! { /// ERC-20 balance function signature. interface IERC20 { @@ -34,25 +31,36 @@ sol! { } } -/// Address of the deployed contract to call the function on. Here: USDT contract on Sepolia -const CONTRACT: Address = address!("299Da20a3e957c78d7634A55D88195224C9f9f6b"); +/// ABI encodable journal data. +sol! { + struct Journal { + SolCommitment commitment; + address tokenAddress; + } +} fn main() { // Read the input from the guest environment. - let input: EthViewCallInput = env::read(); + let input: EthEvmInput = env::read(); + let contract: Address = env::read(); let account: Address = env::read(); - // Converts the input into a `ViewCallEnv` for execution. The `with_chain_spec` method is used + // Converts the input into a `EvmEnv` for execution. The `with_chain_spec` method is used // to specify the chain configuration. It checks that the state matches the state root in the // header provided in the input. - let view_call_env = input.into_env().with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); - let contract = Contract::new(CONTRACT, &view_call_env); - // Commit the block hash and number used when deriving `view_call_env` to the journal. - env::commit_slice(&view_call_env.block_commitment().abi_encode()); + let env = input.into_env().with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); // Execute the view call; it returns the result in the type generated by the `sol!` macro. let call = IERC20::balanceOfCall { account }; - let returns = contract.call_builder(&call).call(); + let returns = Contract::new(contract, &env).call_builder(&call).call(); + // Check that the given account holds at least 1 token. assert!(returns._0 >= U256::from(1)); + + // Commit the block hash and number used when deriving `view_call_env` to the journal. + let journal = Journal { + commitment: env.block_commitment(), + tokenAddress: contract, + }; + env::commit_slice(&journal.abi_encode()); } diff --git a/examples/erc20-counter/script/DeployCounter.s.sol b/examples/erc20-counter/script/DeployCounter.s.sol index 1ee13df8..266fc1bf 100644 --- a/examples/erc20-counter/script/DeployCounter.s.sol +++ b/examples/erc20-counter/script/DeployCounter.s.sol @@ -22,6 +22,7 @@ import {IRiscZeroVerifier} from "risc0/IRiscZeroVerifier.sol"; import {ControlID, RiscZeroGroth16Verifier} from "risc0/groth16/RiscZeroGroth16Verifier.sol"; import {Counter} from "../contracts/Counter.sol"; +import {ERC20} from "../contracts/ERC20.sol"; /// @notice Deployment script for the Counter contract. /// @dev Use the following environment variable to control the deployment: @@ -35,10 +36,13 @@ contract CounterrDeploy is Script { vm.startBroadcast(deployerKey); + ERC20 toyken = new ERC20("TOYKEN", "TOY", 0); + console2.log("Deployed ERC20 TOYKEN to", address(toyken)); + IRiscZeroVerifier verifier = new RiscZeroGroth16Verifier(ControlID.CONTROL_ROOT, ControlID.BN254_CONTROL_ID); console2.log("Deployed RiscZeroGroth16Verifier to", address(verifier)); - Counter counter = new Counter(verifier); + Counter counter = new Counter(verifier, address(toyken)); console2.log("Deployed Counter to", address(counter)); vm.stopBroadcast(); diff --git a/examples/erc20-counter/script/DeployERC20.s.sol b/examples/erc20-counter/script/DeployERC20.s.sol deleted file mode 100644 index f7d6cb9e..00000000 --- a/examples/erc20-counter/script/DeployERC20.s.sol +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 - -pragma solidity ^0.8.20; - -import {Script} from "forge-std/Script.sol"; -import {console2} from "forge-std/console2.sol"; -import {IRiscZeroVerifier} from "risc0/IRiscZeroVerifier.sol"; -import {ControlID, RiscZeroGroth16Verifier} from "risc0/groth16/RiscZeroGroth16Verifier.sol"; - -import {ERC20} from "../contracts/ERC20.sol"; - -/// @notice Deployment script for the ERC20 TOYKEN contract. -/// @dev Use the following environment variable to control the deployment: -/// * ETH_WALLET_PRIVATE_KEY private key of the wallet to be used for deployment. -/// -/// See the Foundry documentation for more information about Solidity scripts. -/// https://book.getfoundry.sh/tutorials/solidity-scripting -contract ERC20Deploy is Script { - function run() external { - uint256 deployerKey = uint256(vm.envBytes32("ETH_WALLET_PRIVATE_KEY")); - - vm.startBroadcast(deployerKey); - - ERC20 toyken = new ERC20("TOYKEN", "TOY", 0); - console2.log("Deployed ERC20 TOYKEN to", address(toyken)); - - vm.stopBroadcast(); - } -} diff --git a/examples/erc20-counter/test-local-deployment.sh b/examples/erc20-counter/test-local-deployment.sh index a4d1fae7..9abaacc5 100755 --- a/examples/erc20-counter/test-local-deployment.sh +++ b/examples/erc20-counter/test-local-deployment.sh @@ -25,31 +25,6 @@ sleep 5 export ETH_WALLET_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -# Deploy the ERC20 Toyken contract -echo "Deploying ERC20 Toyken contract..." -forge script --rpc-url http://localhost:8545 --broadcast script/DeployERC20.s.sol - -# Extract the Toyken address -export TOYKEN_ADDRESS=$(jq -re '.transactions[] | select(.contractName == "ERC20") | .contractAddress' ./broadcast/DeployERC20.s.sol/31337/run-latest.json) -echo "ERC20 Toyken Address: $TOYKEN_ADDRESS" - -# Mint Toyken to a specific address -echo "Minting Toyken to 0x9737100D2F42a196DE56ED0d1f6fF598a250E7E4..." -cast send --private-key $ETH_WALLET_PRIVATE_KEY --rpc-url http://localhost:8545 $TOYKEN_ADDRESS 'mint(address, uint256)' 0x9737100D2F42a196DE56ED0d1f6fF598a250E7E4 100 - -# Strip '0x' prefix from TOYKEN_ADDRESS, if it exists -STRIPPED_TOYKEN_ADDRESS=${TOYKEN_ADDRESS#0x} - -files=( - "apps/src/bin/publisher.rs" - "methods/guest/src/bin/balance_of.rs" -) - -# Loop through each file and use Perl for in-place editing -for file in "${files[@]}"; do - perl -pi -e "s/address!\(\"[a-zA-Z0-9]*\"\)/address!(\"$STRIPPED_TOYKEN_ADDRESS\")/g" "$file" -done - # Build the project echo "Building the project..." cargo build @@ -58,6 +33,14 @@ cargo build echo "Deploying the Counter contract..." forge script --rpc-url http://localhost:8545 --broadcast script/DeployCounter.s.sol +# Extract the Toyken address +export TOYKEN_ADDRESS=$(jq -re '.transactions[] | select(.contractName == "ERC20") | .contractAddress' ./broadcast/DeployCounter.s.sol/31337/run-latest.json) +echo "ERC20 Toyken Address: $TOYKEN_ADDRESS" + +# Mint Toyken to a specific address +echo "Minting Toyken to 0x9737100D2F42a196DE56ED0d1f6fF598a250E7E4..." +cast send --private-key $ETH_WALLET_PRIVATE_KEY --rpc-url http://localhost:8545 $TOYKEN_ADDRESS 'mint(address, uint256)' 0x9737100D2F42a196DE56ED0d1f6fF598a250E7E4 100 + # Extract the Counter contract address export COUNTER_ADDRESS=$(jq -re '.transactions[] | select(.contractName == "Counter") | .contractAddress' ./broadcast/DeployCounter.s.sol/31337/run-latest.json) echo "Counter Address: $COUNTER_ADDRESS" @@ -68,6 +51,7 @@ cargo run --bin publisher -- \ --chain-id=31337 \ --rpc-url=http://localhost:8545 \ --contract=${COUNTER_ADDRESS:?} \ + --token=${TOYKEN_ADDRESS:?} \ --account=0x9737100D2F42a196DE56ED0d1f6fF598a250E7E4 # Attempt to verify counter value as part of the script logic diff --git a/examples/erc20/Cargo.lock b/examples/erc20/Cargo.lock index 6c86d3e2..f8499f62 100644 --- a/examples/erc20/Cargo.lock +++ b/examples/erc20/Cargo.lock @@ -619,9 +619,9 @@ dependencies = [ [[package]] name = "bonsai-sdk" -version = "0.8.0-rc.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ddc06a9da40f1814918e077807a38bdfe9ed92d08ca600fcdb27f19685718ad" +checksum = "a7781292e9bcc1f54de6839dbab88b4032d2a20ab1d4fb3d8f045e9cecf5486e" dependencies = [ "reqwest 0.12.4", "risc0-groth16", @@ -2655,9 +2655,9 @@ dependencies = [ [[package]] name = "risc0-binfmt" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8675cbcc76c912d5e766ee6fe377c2204d8a6c8dd47a540c0bd9a673590d7279" +checksum = "b0277e19d88c8b9e3d425ac446cb8fa334231764fd2621129b770a691451f4b9" dependencies = [ "anyhow", "elf", @@ -2669,9 +2669,9 @@ dependencies = [ [[package]] name = "risc0-build" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea96470ab985621e5398bf51b537288b651502b14f6ae412e73c638935dc3ea1" +checksum = "30ec1efbbed55de3e3a8c6f5e462e9f5325d467b872bb09049a8bd6a32e3b445" dependencies = [ "anyhow", "cargo_metadata", @@ -2687,9 +2687,9 @@ dependencies = [ [[package]] name = "risc0-circuit-recursion" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459f0690e4e6da6579108b6a42ae0d32082c51b2c96c8b6889d319be742fe295" +checksum = "2db3e76adef5f6883c44cf3705eb7668566df4d6b66443ca2d93c656acc7ef90" dependencies = [ "anyhow", "bytemuck", @@ -2701,9 +2701,9 @@ dependencies = [ [[package]] name = "risc0-circuit-rv32im" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e1868cbd856dfcd30a8dcf41bd981e2d40867302ead41c93f3ef76bfcc20fa" +checksum = "f6abc6d66871cb9b833ddf0a4ce76928c1cfa53a2d619de64dd403e907491360" dependencies = [ "anyhow", "risc0-binfmt", @@ -2716,9 +2716,9 @@ dependencies = [ [[package]] name = "risc0-core" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fa2b29c4232accff05dfb2025ba6596e7be11a8da5e8d73e657fdabfffee46" +checksum = "3eefc8c4376c184e3f7ee8f88fc95f49f062307294ccdfb19ad82506777db587" dependencies = [ "bytemuck", "rand_core", @@ -2726,9 +2726,9 @@ dependencies = [ [[package]] name = "risc0-groth16" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "270a9a9560168788c0cac60ff51ad201f7240416ffc0cad1a1cb9f851376f7d1" +checksum = "9cb82c5ad39105da54c9035896199b6793436a859e0e16e29bc308eb83c1e791" dependencies = [ "anyhow", "ark-bn254", @@ -2768,9 +2768,9 @@ dependencies = [ [[package]] name = "risc0-zkp" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b98e4ff1642e3b7b91edc8f2dd074207864320711b6ef0b290e05dcbae40513" +checksum = "ba1e45db2d5c9806110e8251ada5c6d6850434778378fbd1630363b6f59fde01" dependencies = [ "anyhow", "blake2", @@ -2790,9 +2790,9 @@ dependencies = [ [[package]] name = "risc0-zkvm" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c3c905a3fb48c8c600cd3d9e40c41e1f7db2562c3b41535ad966f4ff5d0ab2" +checksum = "bf582a2b8f7ef826ffc0dc2104965b36d47c94bac8847baeaf9ba8d691744026" dependencies = [ "anyhow", "bincode", @@ -2820,9 +2820,9 @@ dependencies = [ [[package]] name = "risc0-zkvm-platform" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1585bd97cf03bedfd60534923542f26a60ff7c7aa2be15710b7e57ceb5705a" +checksum = "b40eaf89f1ed393326db06a2ae2058fff21db7a8e7fac18eb6ae894fa40f35ff" dependencies = [ "bytemuck", "getrandom", diff --git a/examples/erc20/Cargo.toml b/examples/erc20/Cargo.toml index c275d776..645cc002 100644 --- a/examples/erc20/Cargo.toml +++ b/examples/erc20/Cargo.toml @@ -17,7 +17,7 @@ nybbles = { version = "0.2.1", features = ["serde"] } once_cell = "1.19" revm = { version = "9.0", default-features = false, features = ["std"] } risc0-steel = { path = "../../steel" } -risc0-zkvm = { version = "1.0.0-rc.7", default-features = false } +risc0-zkvm = { version = "1.0", default-features = false } rlp = "0.5.2" serde = "1.0" thiserror = "1.0" diff --git a/examples/erc20/README.md b/examples/erc20/README.md index 899a3963..1d7184d6 100644 --- a/examples/erc20/README.md +++ b/examples/erc20/README.md @@ -2,8 +2,6 @@ **An example that uses the ERC20 interface's `balanceOf` method.** -> ***WARNING***: This software is still experimental, we do not recommend it for production use. - ## Prerequisites To get started, you need to have Rust installed. If you haven't done so, follow the instructions [here][install-rust]. @@ -34,15 +32,14 @@ RPC_URL=https://eth-sepolia.g.alchemy.com/v2/ RUST_LOG=info cargo run - The output should resemble the following: ```text -2024-03-12T11:06:14.549457Z INFO view_call::host: preflight 'balanceOf(address)' method by 0xf08A50178dfcDe18524640EA6618a1f965821715 on 0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0 -For block 5470081 `balanceOf(address)` returns: 399534748753251 +2024-06-04T09:32:22.119650Z INFO risc0_steel::contract: Executing preflight for 'balanceOf(address)' on contract 0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0 +For block 6037045 `balanceOf(address)` returns: 399534748753251 Running the guest with the constructed input: View call result: 399534748753251 -2024-03-12T11:06:17.018205Z INFO executor: risc0_zkvm::host::server::exec::executor: execution time: 538.5ms -2024-03-12T11:06:17.018224Z INFO executor: risc0_zkvm::host::server::session: number of segments: 6 -2024-03-12T11:06:17.018227Z INFO executor: risc0_zkvm::host::server::session: total cycles: 5505024 -2024-03-12T11:06:17.018229Z INFO executor: risc0_zkvm::host::server::session: user cycles: 4179903 -2024-03-12T11:06:17.018231Z INFO executor: risc0_zkvm::host::server::session: cycle efficiency: 75% +2024-06-04T09:32:24.152552Z INFO executor: risc0_zkvm::host::server::exec::executor: execution time: 218.576666ms +2024-06-04T09:32:24.152578Z INFO executor: risc0_zkvm::host::server::session: number of segments: 5 +2024-06-04T09:32:24.152581Z INFO executor: risc0_zkvm::host::server::session: total cycles: 5242880 +2024-06-04T09:32:24.152583Z INFO executor: risc0_zkvm::host::server::session: user cycles: 4126244 ``` ### Guest Code @@ -51,10 +48,7 @@ Here is a snippet of the [relevant code](./methods/guest/src/main.rs) of the gue ```rust /// Specify the function to call using the [`sol!`] macro. -/// This parses the Solidity syntax to generate a struct that implements the [SolCall] trait. -/// The struct instantiated with the arguments can then be passed to the [ViewCall] to execute the -/// call. For example: -/// `IERC20::balanceOfCall { account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4") }` +/// This parses the Solidity syntax to generate a struct that implements the `SolCall` trait. sol! { /// ERC-20 balance function signature. interface IERC20 { @@ -62,29 +56,29 @@ sol! { } } -/// Function to call, implements [SolCall] trait. +/// Function to call, implements the `SolCall` trait. const CALL: IERC20::balanceOfCall = IERC20::balanceOfCall { account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4"), }; -/// Address of the deployed contract to call the function on. Here: USDT contract on Sepolia +/// Address of the deployed contract to call the function on (USDT contract on Sepolia). const CONTRACT: Address = address!("aA8E23Fb1079EA71e0a56F48a2aA51851D8433D0"); -/// Address of the caller of the function. If not provided, the caller will be the [CONTRACT]. +/// Address of the caller. If not provided, the caller will be the [CONTRACT]. const CALLER: Address = address!("f08A50178dfcDe18524640EA6618a1f965821715"); fn main() { // Read the input from the guest environment. - let input: EthViewCallInput = env::read(); + let input: EthEvmInput = env::read(); - // Converts the input into a `ViewCallEnv` for execution. The `with_chain_spec` method is used + // Converts the input into a `EvmEnv` for execution. The `with_chain_spec` method is used // to specify the chain configuration. It checks that the state matches the state root in the // header provided in the input. - let view_call_env = input.into_env().with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); - let contract = Contract::new(CONTRACT, &view_call_env); - // Commit the block hash and number used when deriving `view_call_env` to the journal. - env::commit_slice(&view_call_env.block_commitment().abi_encode()); + let env = input.into_env().with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); + // Commit the block hash and number used when deriving `EvmEnv` to the journal. + env::commit_slice(&env.block_commitment().abi_encode()); // Execute the view call; it returns the result in the type generated by the `sol!` macro. + let contract = Contract::new(CONTRACT, &env); let returns = contract.call_builder(&CALL).from(CALLER).call(); println!("View call result: {}", returns._0); } @@ -95,16 +89,18 @@ fn main() { Here is a snippet to the [relevant code](./host/src/main.rs) on the host, it requires the same arguments as the guest: ```rust -// Create a view call environment from an RPC endpoint and a block number. If no block number is -// provided, the latest block is used. The `with_chain_spec` method is used to specify the -// chain configuration. -let mut env = - EthViewCallEnv::from_rpc(&args.rpc_url, None)?.with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); - -// Preflight the view call to construct the input that is required to execute the function in -// the guest. It also returns the result of the call. +// Create an EVM environment from an RPC endpoint and a block number. If no block number is +// provided, the latest block is used. +let mut env = EthEvmEnv::from_rpc(&args.rpc_url, None)?; +// The `with_chain_spec` method is used to specify the chain configuration. +env = env.with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); + +// Preflight the call to prepare the input that is required to execute the function in +// the guest without RPC access. It also returns the result of the call. let mut contract = Contract::preflight(CONTRACT, &mut env); let returns = contract.call_builder(&CALL).from(CALLER).call()?; + +// Finally, construct the input from the environment. let input = env.into_input()?; ``` diff --git a/examples/erc20/host/src/main.rs b/examples/erc20/host/src/main.rs index 0e367600..77858de9 100644 --- a/examples/erc20/host/src/main.rs +++ b/examples/erc20/host/src/main.rs @@ -17,26 +17,28 @@ use alloy_sol_types::{sol, SolCall, SolValue}; use anyhow::{Context, Result}; use clap::Parser; use erc20_methods::ERC20_GUEST_ELF; -use risc0_steel::{config::ETH_SEPOLIA_CHAIN_SPEC, ethereum::EthViewCallEnv, Contract, EvmHeader}; +use risc0_steel::{config::ETH_SEPOLIA_CHAIN_SPEC, ethereum::EthEvmEnv, Contract, EvmBlockHeader}; use risc0_zkvm::{default_executor, ExecutorEnv}; use tracing_subscriber::EnvFilter; -/// Address of the USDT contract on Ethereum Sepolia -const CONTRACT: Address = address!("aA8E23Fb1079EA71e0a56F48a2aA51851D8433D0"); -/// Function to call -const CALL: IERC20::balanceOfCall = IERC20::balanceOfCall { - account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4"), -}; -/// Caller address -const CALLER: Address = address!("f08A50178dfcDe18524640EA6618a1f965821715"); - sol! { /// ERC-20 balance function signature. + /// This must match the signature in the guest. interface IERC20 { function balanceOf(address account) external view returns (uint); } } +/// Function to call, implements the [SolCall] trait. +const CALL: IERC20::balanceOfCall = IERC20::balanceOfCall { + account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4"), +}; + +/// Address of the deployed contract to call the function on (USDT contract on Sepolia). +const CONTRACT: Address = address!("aA8E23Fb1079EA71e0a56F48a2aA51851D8433D0"); +/// Address of the caller. +const CALLER: Address = address!("f08A50178dfcDe18524640EA6618a1f965821715"); + /// Simple program to show the use of Ethereum contract data inside the guest. #[derive(Parser, Debug)] #[command(about, long_about = None)] @@ -51,29 +53,31 @@ fn main() -> Result<()> { tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env()) .init(); - // parse the command line arguments + // Parse the command line arguments. let args = Args::parse(); - // Create a view call environment from an RPC endpoint and a block number. If no block number is - // provided, the latest block is used. The `with_chain_spec` method is used to specify the - // chain configuration. - let mut env = - EthViewCallEnv::from_rpc(&args.rpc_url, None)?.with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); - let number = env.header().number(); + // Create an EVM environment from an RPC endpoint and a block number. If no block number is + // provided, the latest block is used. + let mut env = EthEvmEnv::from_rpc(&args.rpc_url, None)?; + // The `with_chain_spec` method is used to specify the chain configuration. + env = env.with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); + let commitment = env.block_commitment(); - // Preflight the view call to construct the input that is required to execute the function in - // the guest. It also returns the result of the call. + // Preflight the call to prepare the input that is required to execute the function in + // the guest without RPC access. It also returns the result of the call. let mut contract = Contract::preflight(CONTRACT, &mut env); let returns = contract.call_builder(&CALL).from(CALLER).call()?; - let input = env.into_input()?; println!( "For block {} `{}` returns: {}", - number, + env.header().number(), IERC20::balanceOfCall::SIGNATURE, returns._0 ); + // Finally, construct the input from the environment. + let input = env.into_input()?; + println!("Running the guest with the constructed input:"); let session_info = { let env = ExecutorEnv::builder() @@ -86,9 +90,9 @@ fn main() -> Result<()> { .context("failed to run executor")? }; - // extract the proof from the session info and validate it + // The commitment in the journal should match. let bytes = session_info.journal.as_ref(); - assert_eq!(&bytes[..64], &commitment.abi_encode()); + assert!(bytes.starts_with(&commitment.abi_encode())); Ok(()) } diff --git a/examples/erc20/methods/Cargo.toml b/examples/erc20/methods/Cargo.toml index 76b64b80..ae7c28e0 100644 --- a/examples/erc20/methods/Cargo.toml +++ b/examples/erc20/methods/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [build-dependencies] -risc0-build = { version = "1.0.0-rc.7" } +risc0-build = { version = "1.0" } [package.metadata.risc0] methods = ["guest"] diff --git a/examples/erc20/methods/guest/Cargo.lock b/examples/erc20/methods/guest/Cargo.lock index 4e5db1e9..e05300ac 100644 --- a/examples/erc20/methods/guest/Cargo.lock +++ b/examples/erc20/methods/guest/Cargo.lock @@ -1427,9 +1427,9 @@ dependencies = [ [[package]] name = "risc0-binfmt" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8675cbcc76c912d5e766ee6fe377c2204d8a6c8dd47a540c0bd9a673590d7279" +checksum = "b0277e19d88c8b9e3d425ac446cb8fa334231764fd2621129b770a691451f4b9" dependencies = [ "anyhow", "elf", @@ -1441,9 +1441,9 @@ dependencies = [ [[package]] name = "risc0-circuit-recursion" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459f0690e4e6da6579108b6a42ae0d32082c51b2c96c8b6889d319be742fe295" +checksum = "2db3e76adef5f6883c44cf3705eb7668566df4d6b66443ca2d93c656acc7ef90" dependencies = [ "anyhow", "bytemuck", @@ -1455,9 +1455,9 @@ dependencies = [ [[package]] name = "risc0-circuit-rv32im" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e1868cbd856dfcd30a8dcf41bd981e2d40867302ead41c93f3ef76bfcc20fa" +checksum = "f6abc6d66871cb9b833ddf0a4ce76928c1cfa53a2d619de64dd403e907491360" dependencies = [ "anyhow", "risc0-binfmt", @@ -1470,9 +1470,9 @@ dependencies = [ [[package]] name = "risc0-core" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fa2b29c4232accff05dfb2025ba6596e7be11a8da5e8d73e657fdabfffee46" +checksum = "3eefc8c4376c184e3f7ee8f88fc95f49f062307294ccdfb19ad82506777db587" dependencies = [ "bytemuck", "rand_core", @@ -1480,9 +1480,9 @@ dependencies = [ [[package]] name = "risc0-groth16" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "270a9a9560168788c0cac60ff51ad201f7240416ffc0cad1a1cb9f851376f7d1" +checksum = "9cb82c5ad39105da54c9035896199b6793436a859e0e16e29bc308eb83c1e791" dependencies = [ "anyhow", "ark-bn254", @@ -1517,9 +1517,9 @@ dependencies = [ [[package]] name = "risc0-zkp" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b98e4ff1642e3b7b91edc8f2dd074207864320711b6ef0b290e05dcbae40513" +checksum = "ba1e45db2d5c9806110e8251ada5c6d6850434778378fbd1630363b6f59fde01" dependencies = [ "anyhow", "blake2", @@ -1539,9 +1539,9 @@ dependencies = [ [[package]] name = "risc0-zkvm" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c3c905a3fb48c8c600cd3d9e40c41e1f7db2562c3b41535ad966f4ff5d0ab2" +checksum = "bf582a2b8f7ef826ffc0dc2104965b36d47c94bac8847baeaf9ba8d691744026" dependencies = [ "anyhow", "bytemuck", @@ -1564,9 +1564,9 @@ dependencies = [ [[package]] name = "risc0-zkvm-platform" -version = "1.0.0-rc.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1585bd97cf03bedfd60534923542f26a60ff7c7aa2be15710b7e57ceb5705a" +checksum = "b40eaf89f1ed393326db06a2ae2058fff21db7a8e7fac18eb6ae894fa40f35ff" dependencies = [ "bytemuck", "getrandom", diff --git a/examples/erc20/methods/guest/Cargo.toml b/examples/erc20/methods/guest/Cargo.toml index dd4e29f4..3fbddfad 100644 --- a/examples/erc20/methods/guest/Cargo.toml +++ b/examples/erc20/methods/guest/Cargo.toml @@ -12,7 +12,7 @@ ahash = { version = "0.8", default-features = false, features = ["compile-time-r alloy-primitives = { version = "0.7" } alloy-sol-types = { version = "0.7" } risc0-steel = { path = "../../../../steel" } -risc0-zkvm = { version = "1.0.0-rc.7", default-features = false, features = ["std"] } +risc0-zkvm = { version = "1.0", default-features = false, features = ["std"] } [patch.crates-io] # use optimized risc0 circuit diff --git a/examples/erc20/methods/guest/src/main.rs b/examples/erc20/methods/guest/src/main.rs index 754506b4..d63b4317 100644 --- a/examples/erc20/methods/guest/src/main.rs +++ b/examples/erc20/methods/guest/src/main.rs @@ -17,16 +17,13 @@ use alloy_primitives::{address, Address}; use alloy_sol_types::{sol, SolValue}; -use risc0_steel::{config::ETH_SEPOLIA_CHAIN_SPEC, ethereum::EthViewCallInput, Contract}; +use risc0_steel::{config::ETH_SEPOLIA_CHAIN_SPEC, ethereum::EthEvmInput, Contract}; use risc0_zkvm::guest::env; risc0_zkvm::guest::entry!(main); /// Specify the function to call using the [`sol!`] macro. -/// This parses the Solidity syntax to generate a struct that implements the [SolCall] trait. -/// The struct instantiated with the arguments can then be passed to the [ViewCall] to execute the -/// call. For example: -/// `IERC20::balanceOfCall { account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4") }` +/// This parses the Solidity syntax to generate a struct that implements the `SolCall` trait. sol! { /// ERC-20 balance function signature. interface IERC20 { @@ -34,29 +31,29 @@ sol! { } } -/// Function to call, implements [SolCall] trait. +/// Function to call, implements the `SolCall` trait. const CALL: IERC20::balanceOfCall = IERC20::balanceOfCall { account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4"), }; -/// Address of the deployed contract to call the function on. Here: USDT contract on Sepolia +/// Address of the deployed contract to call the function on (USDT contract on Sepolia). const CONTRACT: Address = address!("aA8E23Fb1079EA71e0a56F48a2aA51851D8433D0"); -/// Address of the caller of the function. If not provided, the caller will be the [CONTRACT]. +/// Address of the caller. If not provided, the caller will be the [CONTRACT]. const CALLER: Address = address!("f08A50178dfcDe18524640EA6618a1f965821715"); fn main() { // Read the input from the guest environment. - let input: EthViewCallInput = env::read(); + let input: EthEvmInput = env::read(); - // Converts the input into a `ViewCallEnv` for execution. The `with_chain_spec` method is used + // Converts the input into a `EvmEnv` for execution. The `with_chain_spec` method is used // to specify the chain configuration. It checks that the state matches the state root in the // header provided in the input. - let view_call_env = input.into_env().with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); - let contract = Contract::new(CONTRACT, &view_call_env); - // Commit the block hash and number used when deriving `view_call_env` to the journal. - env::commit_slice(&view_call_env.block_commitment().abi_encode()); + let env = input.into_env().with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); + // Commit the block hash and number used when deriving `EvmEnv` to the journal. + env::commit_slice(&env.block_commitment().abi_encode()); // Execute the view call; it returns the result in the type generated by the `sol!` macro. + let contract = Contract::new(CONTRACT, &env); let returns = contract.call_builder(&CALL).from(CALLER).call(); println!("View call result: {}", returns._0); } diff --git a/steel/README.md b/steel/README.md index 734fb5ba..e9a8304d 100644 --- a/steel/README.md +++ b/steel/README.md @@ -2,7 +2,9 @@ # Steel - Hardened off-chain Execution for EVM dapps -> ***WARNING***: This library is still in its experimental phase and under active development. Production use is not recommended until the software has matured sufficiently. +> ***WARNING*** +> This library is under active development, with breaking changes expected. +> We do not recommend the Steel library for production use at this time. In the realm of Ethereum and smart contracts, obtaining data directly from the blockchain without altering its state—known as "view calls" — are a fundamental operation. Traditionally, these operations, especially when it comes to proving and verifying off-chain computations, involve a degree of complexity: either via proof of storage mechanisms requiring detailed knowledge of slot indexes, or via query-specific circuit development. @@ -11,16 +13,13 @@ In contrast, this library abstracts away these complexities, allowing developers To demonstrate a simple instance of using the view call library, let's consider possibly the most common view call: querying the balance of an ERC-20 token for a specific address. You can find the full example [here](../examples/erc20/README.md). -## Guest Code +## Guest code Here is a snippet of the [relevant code](../examples/erc20/methods/guest/src/main.rs) of the guest: ```rust /// Specify the function to call using the [`sol!`] macro. /// This parses the Solidity syntax to generate a struct that implements the [SolCall] trait. -/// The struct instantiated with the arguments can then be passed to the [ViewCall] to execute the -/// call. For example: -/// `IERC20::balanceOfCall { account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4") }` sol! { /// ERC-20 balance function signature. interface IERC20 { @@ -28,88 +27,105 @@ sol! { } } -/// Function to call, implements [SolCall] trait. +/// Function to call, implements the [SolCall] trait. const CALL: IERC20::balanceOfCall = IERC20::balanceOfCall { account: address!("9737100D2F42a196DE56ED0d1f6fF598a250E7E4"), }; -/// Address of the deployed contract to call the function on. Here: USDT contract on Sepolia +/// Address of the deployed contract to call the function on (USDT contract on Sepolia). const CONTRACT: Address = address!("aA8E23Fb1079EA71e0a56F48a2aA51851D8433D0"); -/// Address of the caller of the function. If not provided, the caller will be the [CONTRACT]. +/// Address of the caller. If not provided, the caller will be the [CONTRACT]. const CALLER: Address = address!("f08A50178dfcDe18524640EA6618a1f965821715"); fn main() { // Read the input from the guest environment. - let input: EthViewCallInput = env::read(); + let input: EthEvmInput = env::read(); // Converts the input into a `ViewCallEnv` for execution. The `with_chain_spec` method is used - // to specify the chain configuration. It checks that the state matches the state root in the - // header provided in the input. + // to specify the chain configuration. let view_call_env = input.into_env().with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); - let contract = Contract::new(CONTRACT, &view_call_env); // Commit the block hash and number used when deriving `view_call_env` to the journal. env::commit_slice(&view_call_env.block_commitment().abi_encode()); // Execute the view call; it returns the result in the type generated by the `sol!` macro. + let contract = Contract::new(CONTRACT, &view_call_env); let returns = contract.call_builder(&CALL).from(CALLER).call(); println!("View call result: {}", returns._0); } ``` -## Host Code +## Host code Here is a snippet to the [relevant code](../examples/erc20/host/src/main.rs) on the host, it requires the same arguments as the guest: ```rust // Create a view call environment from an RPC endpoint and a block number. If no block number is -// provided, the latest block is used. The `with_chain_spec` method is used to specify the -// chain configuration. -let mut env = - EthViewCallEnv::from_rpc(&args.rpc_url, None)?.with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); -let number = env.header().number(); -let commitment = env.block_commitment(); - -// Preflight the view call to construct the input that is required to execute the function in +// provided, the latest block is used. +let mut env = EthViewCallEnv::from_rpc(&args.rpc_url, None)?; +// The `with_chain_spec` method is used to specify the chain configuration. +env = env.with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); + +// Preflight the call to construct the input that is required to execute the function in // the guest. It also returns the result of the call. let mut contract = Contract::preflight(CONTRACT, &mut env); let returns = contract.call_builder(&CALL).from(CALLER).call()?; let input = env.into_input()?; ``` -## Ethereum Integration +## Ethereum integration + +Steel can be integrated with the [Bonsai Foundry Template]. The Ethereum contract that validates the Groth16 proof must also validate the ViewCallEnv commitment. -This library can be used in conjunction with the [Bonsai Foundry Template]. The Ethereum Contract that validates the Groth16 proof must also validate the `ViewCallEnv` commitment. This commitment is the ABI-encoded bytes of the following type: +Here is an example of implementing the validation using the Solidity [Steel library]. The journal contains the commitment as well as additional data: -```solidity -struct BlockCommitment { - bytes32 blockHash; - uint blockNumber; +```Solidity +struct Journal { + Steel.Commitment commitment; + address tokenAddress; +} + +function validate(bytes calldata journalData, bytes calldata seal) external { + Journal memory journal = abi.decode(journalData, (Journal)); + require(Steel.validateCommitment(journal.commitment), "Invalid commitment"); + verifier.verify(seal, imageId, sha256(journalData)); } ``` -Here's an example of how to implement the validation: +The guest code to create the journal would look like the following: -```solidity -function validate(bytes calldata journal, bytes calldata seal) public { - BlockCommitment memory commitment = abi.decode(journal, (BlockCommitment)); - require(blockhash(commitment.blockNumber) == commitment.blockHash); - verifier.verify(seal, imageId, sha256(journal)); +```rust +use risc0_steel::SolCommitment; + +sol! { + struct Journal { + SolCommitment commitment; + address tokenAddress; + } } + +... + +let journal = Journal { + commitment: view_call_env.block_commitment(), + tokenAddress, +}; +env::commit_slice(&journal.abi_encode()); ``` We also provide an example, [erc20-counter], showcasing such integration. -### Getting the verified block hash +### Block hash validation -If the `blockhash` opcode is used for validation, the commitment must not be older than 256 blocks. +Since internally the `blockhash` opcode is used for validation, the commitment must not be older than 256 blocks. Given a block time of 12 seconds, this allows just over 50 minutes to create the proof and ensure that the validating transaction is included in a block. In many cases, this will work just fine: even very large computations such as proving an entire Ethereum block can be done in well under 50 minutes with sufficient resources. -When a verified block hash older than 256 blocks is needed on-chain, a number of strategies can be used: +For scenarios needing a verified block hash older than 256 blocks: -* When the block hash that will be needed is known ahead of time (e.g. when initiating a proposal for governance), that block hash can be saved to contract state. -* Another approach is to use RISC Zero to prove the hash chain from the block that was queried up until a block in the most recent 256. +* Save the required block hash to the contract state if known in advance (e.g., when initiating a governance proposal). +* Use RISC Zero to prove the hash chain from the queried block up to a block within the most recent 256. -[erc20-counter]: ./examples/erc20-counter/README.md +[erc20-counter]: ../examples/erc20-counter/README.md [Bonsai Foundry Template]: https://github.com/risc0/bonsai-foundry-template +[Steel library]: ../contracts/src/steel/Steel.sol diff --git a/steel/src/contract.rs b/steel/src/contract.rs index 8d84b180..932cdab5 100644 --- a/steel/src/contract.rs +++ b/steel/src/contract.rs @@ -13,12 +13,10 @@ // limitations under the License. #[cfg(feature = "host")] -use crate::host::{provider::Provider, HostViewCallEnv}; -use crate::{EvmHeader, GuestViewCallEnv, MerkleTrie, StateDB}; +use crate::host::{provider::Provider, HostEvmEnv}; +use crate::{EvmBlockHeader, GuestEvmEnv, MerkleTrie, StateDb}; use alloy_primitives::{keccak256, Address, Sealed, B256, U256}; - use alloy_sol_types::{SolCall, SolType}; - use revm::{ primitives::{ AccountInfo, Bytecode, CfgEnvWithHandlerCfg, ExecutionResult, HashMap, ResultAndState, @@ -36,13 +34,13 @@ use std::{convert::Infallible, fmt::Debug, marker::PhantomData, mem, rc::Rc}; /// ### Usage /// - **Preflight calls on the Host:** To prepare calls on the host environment and build the /// necessary proof, use [Contract::preflight]. The environment can be initialized using -/// [EthViewCallEnv::from_rpc] or [ViewCallEnv::new]. +/// [EthEvmEnv::from_rpc] or [EvmEnv::new]. /// - **Calls in the Guest:** To initialize the contract in the guest environment, use -/// [Contract::new]. The environment should be constructed using [ViewCallInput::into_env]. +/// [Contract::new]. The environment should be constructed using [EvmInput::into_env]. /// /// ### Examples /// ```rust no_run -/// # use risc0_steel::{ethereum::EthViewCallEnv, Contract}; +/// # use risc0_steel::{ethereum::EthEvmEnv, Contract}; /// # use alloy_primitives::{address}; /// # use alloy_sol_types::sol; /// @@ -59,43 +57,43 @@ use std::{convert::Infallible, fmt::Debug, marker::PhantomData, mem, rc::Rc}; /// }; /// /// // Host: -/// let mut env = EthViewCallEnv::from_rpc("https://ethereum-rpc.publicnode.com", None)?; +/// let mut env = EthEvmEnv::from_rpc("https://ethereum-rpc.publicnode.com", None)?; /// let mut contract = Contract::preflight(contract_address, &mut env); /// contract.call_builder(&get_balance).call()?; /// -/// let view_call_input = env.into_input()?; +/// let evm_input = env.into_input()?; /// /// // Guest: -/// let view_call_env = view_call_input.into_env(); -/// let contract = Contract::new(contract_address, &view_call_env); +/// let evm_env = evm_input.into_env(); +/// let contract = Contract::new(contract_address, &evm_env); /// contract.call_builder(&get_balance).call(); /// /// # Ok(()) /// # } /// ``` /// -/// [ViewCallInput::into_env]: crate::ViewCallInput::into_env -/// [ViewCallEnv::new]: crate::ViewCallEnv::new -/// [EthViewCallEnv::from_rpc]: crate::ethereum::EthViewCallEnv::from_rpc +/// [EvmInput::into_env]: crate::EvmInput::into_env +/// [EvmEnv::new]: crate::EvmEnv::new +/// [EthEvmEnv::from_rpc]: crate::ethereum::EthEvmEnv::from_rpc pub struct Contract { address: Address, env: E, } -impl<'a, H> Contract<&'a GuestViewCallEnv> { +impl<'a, H> Contract<&'a GuestEvmEnv> { /// Constructor for executing calls to an Ethereum contract in the guest. - pub fn new(address: Address, env: &'a GuestViewCallEnv) -> Self { + pub fn new(address: Address, env: &'a GuestEvmEnv) -> Self { Self { address, env } } /// Initializes a call builder to execute a call on the contract. - pub fn call_builder(&self, call: &C) -> CallBuilder> { + pub fn call_builder(&self, call: &C) -> CallBuilder> { CallBuilder::new(self.env, self.address, call) } } #[cfg(feature = "host")] -impl<'a, P, H> Contract<&'a mut HostViewCallEnv> +impl<'a, P, H> Contract<&'a mut HostEvmEnv> where P: Provider, { @@ -103,20 +101,17 @@ where /// /// Initializes the environment for calling functions on the Ethereum contract, fetching /// necessary data via the [Provider], and generating a storage proof for any accessed - /// elements using [ViewCallEnv::into_input]. + /// elements using [EvmEnv::into_input]. /// /// [Provider]: crate::host::provider::Provider - /// [ViewCallEnv::into_input]: crate::ViewCallEnv::into_input - /// [ViewCallEnv]: crate::ViewCallEnv - pub fn preflight(address: Address, env: &'a mut HostViewCallEnv) -> Self { + /// [EvmEnv::into_input]: crate::EvmEnv::into_input + /// [EvmEnv]: crate::EvmEnv + pub fn preflight(address: Address, env: &'a mut HostEvmEnv) -> Self { Self { address, env } } /// Initializes a call builder to execute a call on the contract. - pub fn call_builder( - &mut self, - call: &C, - ) -> CallBuilder> { + pub fn call_builder(&mut self, call: &C) -> CallBuilder> { CallBuilder::new(self.env, self.address, call) } } @@ -135,7 +130,7 @@ impl CallBuilder { /// The default gas limit for function calls. const DEFAULT_GAS_LIMIT: u64 = 30_000_000; - /// Creates a new view call to the given contract. + /// Creates a new builder for the given contract call. fn new(env: E, address: Address, call: &C) -> Self where C: SolCall, @@ -178,29 +173,35 @@ impl CallBuilder { } #[cfg(feature = "host")] -impl<'a, C, P, H> CallBuilder> +impl<'a, C, P, H> CallBuilder> where C: SolCall, P: Provider, - H: EvmHeader, + H: EvmBlockHeader, { - /// Executes the call with a [ViewCallEnv] constructed with [Contract::preflight]. + /// Executes the call with a [EvmEnv] constructed with [Contract::preflight]. /// - /// [ViewCallEnv]: crate::ViewCallEnv + /// [EvmEnv]: crate::EvmEnv pub fn call(self) -> anyhow::Result { + log::info!( + "Executing preflight for '{}' on contract {}", + C::SIGNATURE, + self.tx.to + ); + let evm = new_evm(&mut self.env.db, self.env.cfg_env.clone(), &self.env.header); self.tx.transact(evm).map_err(|err| anyhow::anyhow!(err)) } } -impl<'a, C, H> CallBuilder> +impl<'a, C, H> CallBuilder> where C: SolCall, - H: EvmHeader, + H: EvmBlockHeader, { - /// Executes the call with a [ViewCallEnv] constructed with [Contract::new]. + /// Executes the call with a [EvmEnv] constructed with [Contract::new]. /// - /// [ViewCallEnv]: crate::ViewCallEnv + /// [EvmEnv]: crate::EvmEnv pub fn call(self) -> C::Return { let evm = new_evm( WrapStateDb::new(&self.env.db), @@ -277,7 +278,7 @@ impl CallTxData { fn new_evm<'a, DB, H>(db: DB, cfg: CfgEnvWithHandlerCfg, header: &Sealed) -> Evm<'a, (), DB> where DB: Database, - H: EvmHeader, + H: EvmBlockHeader, { Evm::builder() .with_db(db) @@ -287,13 +288,13 @@ where } struct WrapStateDb<'a> { - inner: &'a StateDB, + inner: &'a StateDb, account_storage: HashMap>>, } impl<'a> WrapStateDb<'a> { /// Creates a new [Database] from the given [StateDb]. - pub(crate) fn new(inner: &'a StateDB) -> Self { + pub(crate) fn new(inner: &'a StateDb) -> Self { Self { inner, account_storage: HashMap::new(), diff --git a/steel/src/ethereum.rs b/steel/src/ethereum.rs index c8778532..41edee15 100644 --- a/steel/src/ethereum.rs +++ b/steel/src/ethereum.rs @@ -13,9 +13,9 @@ // limitations under the License. //! Type aliases for Ethereum. -use crate::ViewCallEnv; +use crate::EvmEnv; -use super::{EvmHeader, ViewCallInput}; +use super::{EvmBlockHeader, EvmInput}; use alloy_primitives::{ keccak256, Address, BlockHash, BlockNumber, Bloom, Bytes, Sealable, B256, B64, U256, }; @@ -23,11 +23,11 @@ use alloy_rlp_derive::RlpEncodable; use revm::primitives::BlockEnv; use serde::{Deserialize, Serialize}; -/// [ViewCallEnv] for Ethereum. -pub type EthViewCallEnv = ViewCallEnv; +/// [EvmEnv] for Ethereum. +pub type EthEvmEnv = EvmEnv; -/// [ViewCallInput] for Ethereum. -pub type EthViewCallInput = ViewCallInput; +/// [EvmInput] for Ethereum. +pub type EthEvmInput = EvmInput; /// Ethereum post-merge block header. #[derive(Debug, Clone, Serialize, Deserialize, RlpEncodable)] @@ -82,7 +82,7 @@ impl Sealable for EthBlockHeader { } } -impl EvmHeader for EthBlockHeader { +impl EvmBlockHeader for EthBlockHeader { #[inline] fn parent_hash(&self) -> &B256 { &self.parent_hash diff --git a/steel/src/host/mod.rs b/steel/src/host/mod.rs index 7675465c..bf18e0b6 100644 --- a/steel/src/host/mod.rs +++ b/steel/src/host/mod.rs @@ -18,7 +18,7 @@ use self::{ db::ProofDb, provider::{EthersProvider, Provider}, }; -use crate::{ethereum::EthViewCallEnv, EvmHeader, MerkleTrie, ViewCallEnv, ViewCallInput}; +use crate::{ethereum::EthEvmEnv, EvmBlockHeader, EvmEnv, EvmInput, MerkleTrie}; use alloy_primitives::{Sealable, B256}; use anyhow::{ensure, Context}; use ethers_providers::{Http, RetryClient}; @@ -29,13 +29,13 @@ pub mod db; pub mod provider; /// Alias for readability, do not make public. -pub(crate) type HostViewCallEnv = ViewCallEnv, H>; +pub(crate) type HostEvmEnv = EvmEnv, H>; /// The Ethers client type. pub type EthersClient = ethers_providers::Provider>; -impl EthViewCallEnv>> { - /// Creates a new provable [ViewCallEnv] for Ethereum from an RPC endpoint. +impl EthEvmEnv>> { + /// Creates a new provable [EvmEnv] for Ethereum from an RPC endpoint. pub fn from_rpc(url: &str, block_number: Option) -> anyhow::Result { let client = EthersClient::new_client(url, 3, 500)?; let provider = EthersProvider::new(client); @@ -46,12 +46,12 @@ impl EthViewCallEnv>> { None => provider.get_block_number()?, }; - ViewCallEnv::from_provider(provider, block_number) + EvmEnv::from_provider(provider, block_number) } } -impl ViewCallEnv, P::Header> { - /// Creates a new provable [ViewCallEnv] from a [Provider]. +impl EvmEnv, P::Header> { + /// Creates a new provable [EvmEnv] from a [Provider]. pub fn from_provider(provider: P, block_number: u64) -> anyhow::Result { let header = provider .get_block_header(block_number)? @@ -60,16 +60,16 @@ impl ViewCallEnv, P::Header> { // create a new database backed by the provider let db = ProofDb::new(provider, block_number); - Ok(ViewCallEnv::new(db, header.seal_slow())) + Ok(EvmEnv::new(db, header.seal_slow())) } } -impl ViewCallEnv, P::Header> { - /// Converts the environment into a [ViewCallInput]. +impl EvmEnv, P::Header> { + /// Converts the environment into a [EvmInput]. /// /// The resulting input contains inclusion proofs for all the required chain state data. It can /// therefore be used to execute the same calls in a verifiable way in the zkVM. - pub fn into_input(self) -> anyhow::Result> { + pub fn into_input(self) -> anyhow::Result> { let db = &self.db; // use the same provider as the database @@ -135,7 +135,7 @@ impl ViewCallEnv, P::Header> { debug!("blocks: {}", ancestors.len()); let header = self.header.into_inner(); - Ok(ViewCallInput { + Ok(EvmInput { header, state_trie, storage_tries, diff --git a/steel/src/host/provider/file.rs b/steel/src/host/provider/file.rs index 64f560ca..4868a558 100644 --- a/steel/src/host/provider/file.rs +++ b/steel/src/host/provider/file.rs @@ -13,7 +13,7 @@ // limitations under the License. use super::{EIP1186Proof, NullProvider, Provider}; -use crate::{ethereum::EthBlockHeader, EvmHeader}; +use crate::{ethereum::EthBlockHeader, EvmBlockHeader}; use alloy_primitives::{Address, BlockNumber, Bytes, StorageKey, StorageValue, TxNumber, U256}; use anyhow::Context; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -74,7 +74,7 @@ pub type FileProvider = CachedProvider>; impl FileProvider where - H: EvmHeader + Clone + Serialize + DeserializeOwned, + H: EvmBlockHeader + Clone + Serialize + DeserializeOwned, { /// Creates a new [FileProvider] loading the given file. pub fn from_file(file_path: &PathBuf) -> anyhow::Result { diff --git a/steel/src/host/provider/mod.rs b/steel/src/host/provider/mod.rs index ce7a152d..2e07459a 100644 --- a/steel/src/host/provider/mod.rs +++ b/steel/src/host/provider/mod.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::EvmHeader; +use crate::EvmBlockHeader; use alloy_primitives::{ Address, BlockNumber, Bytes, StorageKey, StorageValue, TxNumber, B256, U256, }; @@ -28,7 +28,7 @@ pub use file::{CachedProvider, EthFileProvider, FileProvider}; /// A trait for providers that fetch data from the Ethereum blockchain. pub trait Provider { type Error: StdError + Send + Sync + 'static; - type Header: EvmHeader; + type Header: EvmBlockHeader; fn get_block_header(&self, block: BlockNumber) -> Result, Self::Error>; fn get_transaction_count( @@ -75,7 +75,7 @@ pub struct EIP1186Proof { /// A simple provider that panics on all queries. pub struct NullProvider(PhantomData); -impl Provider for NullProvider { +impl Provider for NullProvider { type Error = Infallible; type Header = H; diff --git a/steel/src/lib.rs b/steel/src/lib.rs index f1c7bce6..5014a1ef 100644 --- a/steel/src/lib.rs +++ b/steel/src/lib.rs @@ -19,7 +19,6 @@ use alloy_primitives::{ b256, keccak256, Address, BlockNumber, Bytes, Sealable, Sealed, TxNumber, B256, U256, }; use alloy_rlp_derive::{RlpDecodable, RlpEncodable}; -use alloy_sol_types::sol; use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg, HashMap, SpecId}; use serde::{Deserialize, Serialize}; @@ -35,9 +34,9 @@ mod mpt; pub use contract::{CallBuilder, Contract}; pub use mpt::MerkleTrie; -/// The serializable input to derive and validate a [ViewCallEnv]. +/// The serializable input to derive and validate a [EvmEnv]. #[derive(Debug, Serialize, Deserialize)] -pub struct ViewCallInput { +pub struct EvmInput { pub header: H, pub state_trie: MerkleTrie, pub storage_tries: Vec, @@ -45,11 +44,11 @@ pub struct ViewCallInput { pub ancestors: Vec, } -impl ViewCallInput { - /// Converts the input into a [ViewCallEnv] for execution. +impl EvmInput { + /// Converts the input into a [EvmEnv] for execution. /// /// This method verifies that the state matches the state root in the header and panics if not. - pub fn into_env(self) -> GuestViewCallEnv { + pub fn into_env(self) -> GuestEvmEnv { // verify that the state root matches the state trie let state_root = self.state_trie.hash_slow(); assert_eq!(self.header.state_root(), &state_root, "State root mismatch"); @@ -75,37 +74,37 @@ impl ViewCallInput { previous_header = ancestor; } - let db = StateDB::new( + let db = StateDb::new( self.state_trie, self.storage_tries, self.contracts, block_hashes, ); - ViewCallEnv::new(db, header) + EvmEnv::new(db, header) } } -sol! { - /// Solidity struct representing the committed block used for validation. - struct BlockCommitment { - bytes32 blockHash; - uint blockNumber; - } +// Keep everything in the Steel library private except the commitment. +mod private { + alloy_sol_types::sol!("../contracts/src/steel/Steel.sol"); } +/// Solidity struct representing the committed block used for validation. +pub use private::Steel::Commitment as SolCommitment; + /// Alias for readability, do not make public. -pub(crate) type GuestViewCallEnv = ViewCallEnv; +pub(crate) type GuestEvmEnv = EvmEnv; -/// The [Contract] is configured from this object. -pub struct ViewCallEnv { +/// The environment to execute the contract calls in. +pub struct EvmEnv { db: D, cfg_env: CfgEnvWithHandlerCfg, header: Sealed, } -impl ViewCallEnv { - /// Creates a new view call environment. +impl EvmEnv { + /// Creates a new environment. /// It uses the default configuration for the latest specification. pub fn new(db: D, header: Sealed) -> Self { let cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(Default::default(), SpecId::LATEST); @@ -126,9 +125,9 @@ impl ViewCallEnv { self } - /// Returns the [BlockCommitment] used to validate the environment. - pub fn block_commitment(&self) -> BlockCommitment { - BlockCommitment { + /// Returns the [SolCommitment] used to validate the environment. + pub fn block_commitment(&self) -> SolCommitment { + SolCommitment { blockHash: self.header.seal(), blockNumber: U256::from(self.header.number()), } @@ -144,14 +143,14 @@ impl ViewCallEnv { /// /// It is backed by a single [MerkleTrie] for the accounts and one [MerkleTrie] each for the /// accounts' storages. It panics when data is queried that is not contained in the tries. -pub struct StateDB { +pub struct StateDb { state_trie: MerkleTrie, storage_tries: HashMap>, contracts: HashMap, block_hashes: HashMap, } -impl StateDB { +impl StateDb { /// Creates a new state database from the given tries. pub fn new( state_trie: MerkleTrie, @@ -232,7 +231,7 @@ impl Default for StateAccount { } /// An EVM abstraction of a block header. -pub trait EvmHeader: Sealable { +pub trait EvmBlockHeader: Sealable { /// Returns the hash of the parent block's header. fn parent_hash(&self) -> &B256; /// Returns the block number. diff --git a/steel/tests/view_call.rs b/steel/tests/eth_call.rs similarity index 97% rename from steel/tests/view_call.rs rename to steel/tests/eth_call.rs index f97bd598..99cde4cd 100644 --- a/steel/tests/view_call.rs +++ b/steel/tests/eth_call.rs @@ -18,7 +18,7 @@ use alloy_primitives::{address, b256, uint, Address, U256}; use alloy_sol_types::{sol, SolCall}; use risc0_steel::{ config::{ChainSpec, ETH_MAINNET_CHAIN_SPEC, ETH_SEPOLIA_CHAIN_SPEC}, - ethereum::EthViewCallEnv, + ethereum::EthEvmEnv, host, CallBuilder, Contract, }; use std::fmt::Debug; @@ -80,7 +80,7 @@ fn erc20_multi_balance_of() { account: address!("5a52E96BAcdaBb82fd05763E25335261B270Efcb"), }; - let mut env = EthViewCallEnv::from_provider(provider!(), ERC20_TEST_BLOCK) + let mut env = EthEvmEnv::from_provider(provider!(), ERC20_TEST_BLOCK) .unwrap() .with_chain_spec(Ð_MAINNET_CHAIN_SPEC); let mut contract = Contract::preflight(ERC20_TEST_CONTRACT, &mut env); @@ -288,7 +288,7 @@ fn multi_contract_calls() { #[test] fn call_eoa() { - let mut env = EthViewCallEnv::from_provider(provider!(), VIEW_CALL_TEST_BLOCK) + let mut env = EthEvmEnv::from_provider(provider!(), VIEW_CALL_TEST_BLOCK) .unwrap() .with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC); let mut contract = Contract::preflight(Address::ZERO, &mut env); @@ -328,7 +328,7 @@ where C: SolCall, ::Return: PartialEq + Debug, { - let mut env = EthViewCallEnv::from_provider(provider!(), block) + let mut env = EthEvmEnv::from_provider(provider!(), block) .unwrap() .with_chain_spec(chain_spec);