1 个不稳定版本
0.9.0 | 2024 年 3 月 29 日 |
---|
#26 in #risc
125KB
2K SLoC
RISC Zero Ethereum View Call Proofs 库
警告:此库仍处于实验阶段,处于积极开发中。在软件成熟足够之前,不建议在生产中使用。
在 Ethereum 和智能合约的领域内,从区块链中直接获取数据而不改变其状态——称为“查看调用”——是一个基本操作。传统上,这些操作,尤其是在证明和验证链下计算时,涉及一定程度的复杂性:要么通过需要详细了解槽索引的存储证明机制,要么通过针对特定查询的电路开发。相比之下,此库抽象掉了这些复杂性,允许开发者通过仅定义他们希望调用的 Solidity 方法来查询 Ethereum 的状态。为了演示使用查看调用库的简单实例,让我们考虑一个基本但常见的区块链操作:查询特定地址的 ERC-20 令牌余额。您可以在此处找到完整的示例 这里。
访客代码
以下是 相关代码 的片段。
/// 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 {
function balanceOf(address account) external view returns (uint);
}
}
/// Function to call, implements [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
const CONTRACT: Address = address!("aA8E23Fb1079EA71e0a56F48a2aA51851D8433D0");
/// Address of the caller of the function. 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();
// 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.
let view_call_env = input.into_env().with_chain_spec(Ð_SEPOLIA_CHAIN_SPEC);
// 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 returns = ViewCall::new(CALL, CONTRACT).with_caller(CALLER).execute(view_call_env);
println!("View call result: {}", returns._0);
}
主机代码
以下是主机上的相关代码片段,它需要与访客相同的参数 这里。
// 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 env = EthViewCallEnv::from_rpc(&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.
let (input, returns) = ViewCall::new(CALL, CONTRACT)
.with_caller(CALLER)
.preflight(env)?;
Ethereum 集成
此库可与 Bonsai Foundry 模板 一起使用。验证 Groth16 证明的 Ethereum 合同还必须验证 ViewCallEnv
承诺。此承诺是以下类型的 ABI 编码字节:
struct BlockCommitment {
bytes32 blockHash;
uint blockNumber;
}
以下是如何实现验证的示例
function validate(bytes calldata journal, bytes32 postStateDigest, bytes calldata seal) public {
BlockCommitment memory commitment = abi.decode(journal, (BlockCommitment));
require(blockhash(commitment.blockNumber) == commitment.blockHash);
require(verifier.verify(seal, imageId, postStateDigest, sha256(journal)));
}
我们还提供了一个示例,erc20-counter,展示了这种集成。
限制
如果使用 blockhash
操作码进行验证,承诺不能超过256个区块。考虑到12秒的区块时间,这允许大约50分钟的时间来创建证明并确保验证交易被包含在区块中。
依赖项
~25–41MB
~791K SLoC