All notable changes to this project will be documented in this file.
- Introduce
Eip2935HistoryCommitto enable historical state proofs using the EIP-2935 history storage contract. This provides a more direct and efficient alternative to the existing beacon-basedHistoryCommit. - Add a new
precompilesmodule with type-safe wrappers for the EIP-2935HistoryStorageand EIP-4788BeaconRootscontracts. - The
ContractAPI now includes arawmethod to allow for direct calls with raw calldata. This provides greater flexibility when interacting with non-standard interfaces, such as precompiles. - Add
Eventsupport for chains other than Ethereum. - Added
MultiblockEvmEnvand `MultiblockEvmInput to enable verifiable computation across multiple blocks within a single proof. The guest environment now securely validates the integrity of the block sequence by verifying commitments between each consecutive block. - Improve EVM error handling to support calls without return data.
- The
Steel.sollibrary now uses the OpenZeppelin Blockhash library to provide safer access to historical block hashes up to 8,191 blocks. - Adapt
SteelVerifierto use the history storage contract when available, in line withSteel.validateCommitment. It now includes optimizations for directly verifying adjacent blocks via the parent hash field. - The
EvmEnv::mergefunction is now more flexible, allowing environments with different commitments to be merged.
- Check the commitment config ID in
Steel.validateCommitment#17- This improves the safety guarantees of Steel by detecting if the EVM config does not match the expected value.
- As a result, programs may select from a list of well-known config IDs instead of being required to compile just one config into the guest.
tracinglog lines have been downgraded todebug.Commitmentnow implementsserde::Serializeandserde::Deserialize.BlockNumberOrTagnow implementsFrom<u64>.- Updated dependencies:
alloy-evm(to 0.20),revm(to 29.0).
- With the feature to check the config ID, tests and incorrectly configured guest programs / contracts may need to be adjusted.
- If your guest does not use the EVM config matches the one provided for the verifier chain, then
Steel.validateCommitmentwill revert. - If the guest program is using a
ChainSpecthat does not match the queried chain, then the guest should be updated (e.g. if usingETH_SEPOLIA_CHAIN_SPECwhile querying Ethereum Mainnet). - If the verifier needs to use a custom EVM config, then the
Steel.validateCommitmentWithConfigfunction can be used. - In Forge tests,
vm.chainId(ChainSpec.STEEL_TEST_PRAGUE_CHAIN_ID)can be used to setup the chain with can ID used by Steel for a testnet, using the Prague hardfork.
- If your guest does not use the EVM config matches the one provided for the verifier chain, then
- In
OpSteel, theOpSteel.validateCommitmentfunction has been removed in this version. Please useOpSteel.validateCommitmentWithConfig.
The crates steel and op-steel have been moved to the new repository github.com/boundless-xyz/steel.
- Updated dependencies:
alloy-evm(to 0.18),revm(to 28.0). - Disable default features for
alloy.
- Update to alloy 1.0: This release updates Steel's alloy dependency to 1.0 🎉
- Improve Validation in
Steel.validatedCommitment: Update the Steel beacon block commit validation to always revert on invalid timestamps #605- Prior to this fix a beacon block commitment with a zero digest and invalid timestamp would be accepted by
Steel.validateCommitment, violating the semantics ofvalidateCommitment. - No correct Steel guest would create such a commitment, and no opening proofs can be generated against it.
- Prior to this fix a beacon block commitment with a zero digest and invalid timestamp would be accepted by
- Introduce the
EvmFactorytrait (EthEvmFactory) to abstract over different EVM implementations, enabling better code reuse and support for chain-specific logic like Optimism's transaction types and state handling. - Introduce the capability to query Ethereum events. The new
Eventallows to query events of a specific type in Steel. Its usage is very similar to the existingContract, during the preflight step and in the guest. This functionality is currently marked unstable and must be enabled using theunstable-eventfeature. - Add support for the Prague Ethereum fork on Mainnet, Sepolia, and Holešky testnets via updated
EthChainSpec. - Enable KZG point evaluation precompile.
- Improve
HistoryCommitproof generation logic. The algorithm now reliably chains state proofs backward from the commitment block by querying the beacon roots contract state to verify linkage to the execution block commitment, replacing the previous forward-stepping approach. - Introduce
SteelVerifier::verify_with_config_idon host and guest to allow verifying aCommitmentagainst an explicitly provided configuration ID. - Stabilize
event,historyandverifier.
- Add verification of the
Commitment::configIDfield inSteelVerifier::verifyon both host and guest against the environment's configuration ID. This corrects an omission where commitments with mismatched configurations could pass verification. - Fix error in storage proof processing where necessary Merkle proof nodes could be discarded if the same storage trie was accessed via multiple accounts and different storage keys. Proof nodes for shared tries are now correctly merged.
EvmFactoryAbstraction: The core typesEvmEnv,EvmInput,BlockInput,Contract,CallBuilder,Account,Event,SteelVerifier, and host builder methods are now generic over anEvmFactoryimplementation (e.g.,EthEvmFactory) instead of just a block header type. This is a fundamental change affecting environment creation, contract interaction, and type signatures throughout the library.CallBuilderAPI: The API for configuring contract calls has changed significantly. Fluent methods like.from(),.gas(),.value(),.gas_price()have been removed. Call parameters must now be set by directly modifying the publictxfield of theCallBuilderinstance before execution (e.g.,builder.tx.caller = my_address; builder.tx.gas_limit = 100_000;). Consult the specificTxtype documentation for yourEvmFactory(e.g.,revm::context::TxEnvforEthEvmFactory) for available fields.EvmBlockHeaderTrait: The trait now requires an associated typeSpecand mandates implementingfn to_block_env(&self, spec: Self::Spec) -> BlockEnvinstead of the previousfill_block_env.ChainSpecGenerics:ChainSpecis now generic over the specification type instead of being fixed torevm::primitives::SpecId. Use the provided type aliasesEthChainSpec(forSpecId). The hashing mechanism forChainSpec::digest()has changed.- Chain specification handling refactored:
- Removed
HostEvmEnv::with_chain_spec. Chain specification must now be provided via the new.chain_spec()builder method before calling.build().EvmEnvBuildernow track the chain spec via a type parameter. - Methods like
EvmInput::into_envnow require a&ChainSpec<...>argument to reconstruct the environment in the guest, ensuring consistent configuration.
- Removed
- Replace
HostEvmEnv::extend(&mut self, other: Self)withHostEvmEnv::merge(self, other: Self) -> Result<Self>. The newmergefunction consumes both environment instances and returns a new merged instance upon success, whereasextendmodified the existing environment in place. This change improves safety and clarity when combining environments, especially after parallel preflight operations. - Remove deprecated
EvmEnv::into_beacon_input. - Alloy 1.0/0.14 Updates:
- Methods like
abi_decodeno longer take avalidate: boolargument (useabi_decode(&data)). - Contract call results now directly return the value, not a single-element tuple (use
resultinstead ofresult._0).
- Methods like
- Updated major dependencies:
alloy*(to 0.14/1.0),revm(to 22.0). - Added new dependencies:
alloy-evm,alloy-op-evm,op-revm,bincode.
- Introduce the
SteelVerifier, which acts as a built-in SteelContractto verify Steel commitments. It is used like any otherContract, during the preflight step and in the guest. This functionality is currently marked unstable and must be enabled using theunstable-verifierfeature.
- Introduce
HistoryInput, which decouples the EVM execution block from the commitment block. This allows verification against a commitment that is more recent than the execution, allowing secure interaction with the historical state. This functionality is currently marked "unstable" and must be enabled using theunstable-historyfeature. - Make
EvmEnvBuilderpublic.
- Remove
EvmEnv::from_rpcandEvmEnv::from_providerwhich have been deprecated since0.12.0.
1.1.4 - 2024-10-07
- Add
try_call()method toCallBuilderwhen explicit error handling is necessary. - Make
BeaconInput,BlockInputandStateDbpublic. - Implement custom
Debugformatter forCommitment. - Implement
DerefforRlpHeader.
- Return specific error, when no
Contract::preflightwas called. - Use
decode_exactwhen RLP-decoding the MPT leaves.
- The Solidity
Commitmentnow also contains a hash of the chain specification including chain ID, and fork configuration. - Instead of committing to the root of a beacon block referenced by its timestamp, we commit to the root of a beacon block referenced by its child timestamp, or equivalently, we commit to the root of the parent beacon block referenced by its timestamp. While this may sound counterintuitive, this is exactly how the EIP-4788 beacon root contract stores its data. This makes the verification side in Solidity much easier and less expensive, and gets rid of the weird code that was necessary to query the child of a beacon block during creation.
- Introduce the
ComposeInputas a generalized type to represent different commitments. TheBeaconInputis now aComposeInput. This changes the binary input data, but does not require any code changes.
0.13.0 - 2024-09-10
- Add support for creating a commitment to a beacon block root using
EvmEnv::into_beacon_input, which can be verified using the EIP-4788 beacon roots contract. - Add the
EvmEnvBuilderto simplify the creation of anEvmEnvon the host. - If an individual
eth_getProofRPC call contains many storage keys, it will be automatically split. The chunk size can be configured using theEvmEnvBuilder. - Add
CallBuilder::prefetch_access_listandCallBuilder::call_with_prefetchfor that host that prefetch storage proofs and values to drastically reduce the number of RPC calls.
EvmInputhas been changed to anenumto support different input types for the guest, such as the newBeaconInput. This changes the binary input data, but does not require any code changes.SolCommitmenthas been renamed toCommitment.
0.12.0 - 2024-08-09
- Replace
ethersdependency completely withalloy. - Make
hostfunctionsasync. - Add support to build
EvmEnvfrom anyalloyprovider. - Add more efficient RLP-based serialization for the header.
- Store the commitment inside the
EvmEnv. - Use
eth_getTransactionCountandeth_getBalanceinstead ofeth_getProofto query basic account information. - Switch tests from pre-recorded RPC responses to
Anvil.
EthEvmEnv::from_rpcnow accepts aUrlinstead of a&strfor the HTTP RPC endpoint.EvmEnv::from_providernow requires analloyprovider, and the block number parameter has been changed to aBlockNumberOrTag.EvmEnv::sol_commitmenthas been replaced withEvmEnv::commitment(to get a reference), orEvmEnv::into_commitment(to consume and return the commitment).ETH_SEPOLIA_CHAIN_SPECandETH_MAINNET_CHAIN_SPEChave been moved to theethereummodule.CachedProviderhas been removed completely. As alternatives, you can:- Use
anvil --fork-url https://ethereum-rpc.publicnode.com@20475759to create a cached fork for block20475759. - Cache the RPC responses on an HTTP level using Tower or a caching forward proxy.
- Use
- The host functions are now
asyncinstead of blocking:
// Create an EVM environment from an RPC endpoint and a block number or tag.
let mut env = EthEvmEnv::from_rpc(args.rpc_url, BlockNumberOrTag::Latest).await?;
// 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().await?;
// Finally, construct the input from the environment.
let input = env.into_input().await?;