#ethereum #view #state #zero #risc #query #address

risc0-ethereum-view-call

一个用于查询 Ethereum 状态或 RISC Zero zkVM 中任何其他基于 EVM 的区块链状态的库

1 个不稳定版本

0.9.0 2024 年 3 月 29 日

#26 in #risc

Apache-2.0

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(&ETH_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(&ETH_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