Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add onchain verification for Nexus #55

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@
[submodule "lib/nexus"]
path = lib/nexus
url = https://github.com/availproject/nexus
[submodule "contracts/lib/risc0-ethereum"]
path = contracts/lib/risc0-ethereum
url = https://github.com/risc0/risc0-ethereum
25 changes: 20 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions contracts/lib/risc0-ethereum
Submodule risc0-ethereum added at 3c1fd2
1 change: 1 addition & 0 deletions contracts/remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ forge-std/=lib/forge-std/src/
halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/
openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/
openzeppelin-contracts/=lib/openzeppelin-contracts/
risc0/=lib/risc0-ethereum/contracts/src/
23 changes: 23 additions & 0 deletions contracts/src/GethImageID.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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

// This file is automatically generated

pragma solidity ^0.8.20;

library ImageID {
bytes32 public constant ADAPTER_ID = bytes32(0xaeabf8b190380e3ed793aceb060303f78626eb061bd67cca8e455efe60eb8a45);
}
51 changes: 49 additions & 2 deletions contracts/src/NexusProofManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,36 @@
pragma solidity ^0.8.21;

import {JellyfishMerkleTreeVerifier} from "./lib/JellyfishMerkleTreeVerifier.sol";
import {RiscZeroVerifierRouter} from "risc0/RiscZeroVerifierRouter.sol";
import {ImageID} from "./GethImageID.sol"; // auto-generated from cargo-build

contract NexusProofManager {
uint256 public latestNexusBlockNumber = 0;

RiscZeroVerifierRouter public immutable risc0Router;
bytes32 public constant imageId = ImageID.ADAPTER_ID; // added for the auto-generated contract
struct NexusBlock {
bytes32 stateRoot;
bytes32 blockHash;
}

/*
pub parent_hash: H256,
pub prev_state_root: H256,
pub state_root: H256,
pub tx_root: H256,
pub avail_header_hash: H256,
pub number: u32,
*/

struct NexusHeader {
bytes32 parentHash;
bytes32 prevStateRoot;
bytes32 stateRoot;
bytes32 txRoot;
bytes32 availHeaderHash;
uint32 number;
}

mapping(uint256 => NexusBlock) public nexusBlock;
mapping(bytes32 => uint256) public nexusAppIDToLatestBlockNumber;
mapping(bytes32 => mapping(uint256 => bytes32)) public nexusAppIDToState;
Expand All @@ -26,19 +47,45 @@ contract NexusProofManager {
uint128 lastProofHeight;
uint128 height;
}

constructor(address _risc0Router) {
risc0Router = RiscZeroVerifierRouter(_risc0Router);
}

// nexus state root
// updated when we verify the zk proof and then st block updated
function updateNexusBlock(
uint256 blockNumber,
NexusBlock calldata nexusBlockInfo
NexusBlock calldata nexusBlockInfo,
bytes calldata proof,
NexusHeader calldata header
) external {
if (nexusBlock[blockNumber].stateRoot != bytes32(0)) {
revert AlreadyUpdatedBlock(blockNumber);
}
nexusBlock[blockNumber] = nexusBlockInfo;
// TODO: verify a zk proof from nexus

// add risc0 verification here
// ethereum mainnet => 0x8EaB2D97Dfce405A1692a21b3ff3A172d593D319
// ethereum Holesky => 0xf70aBAb028Eb6F4100A24B203E113D94E87DE93C

// the header is what we get from commiting the proof on risc0
bytes memory journal = abi.encode(
header.parentHash,
header.prevStateRoot,
header.stateRoot,
header.txRoot,
header.availHeaderHash,
header.number
);

risc0Router.verifyProof(
proof, // bytes calldata seal
imageId, // bytes32 ImageID
sha256(journal) // bytes32 JournalDigest
);

if (blockNumber > latestNexusBlockNumber) {
latestNexusBlockNumber = blockNumber;
}
Expand Down
24 changes: 24 additions & 0 deletions contracts/src/ZksyncImageID.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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

// This file is automatically generated

pragma solidity ^0.8.20;

library ImageID {
bytes32 public constant ZKSYNC_ADAPTER_ID =
bytes32(0xb5a9ab432ef7aaa39f50b37c47b909e8c8c27a72443688b006bd5887e761b9bb);
}
24 changes: 24 additions & 0 deletions contracts/test/GethElf.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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

// This file is automatically generated

pragma solidity ^0.8.20;

library Elf {
string public constant ADAPTER_PATH =
"/Users/prabhatverma/work/nexus/target/riscv-guest/geth-methods/adapter/riscv32im-risc0-zkvm-elf/release/adapter";
}
24 changes: 24 additions & 0 deletions contracts/test/ZksyncElf.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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

// This file is automatically generated

pragma solidity ^0.8.20;

library Elf {
string public constant ZKSYNC_ADAPTER_PATH =
"/Users/prabhatverma/work/nexus/target/riscv-guest/zksync-methods/zksync-adapter/riscv32im-risc0-zkvm-elf/release/zksync-adapter";
}
1 change: 1 addition & 0 deletions examples/mock_geth_adapter/methods/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[build-dependencies]
risc0-build = { version = "1.1.1" }
risc0-build-ethereum = { version = "1.1.1"}

[package.metadata.risc0]
methods = ["guest"]
13 changes: 12 additions & 1 deletion examples/mock_geth_adapter/methods/build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
use risc0_build_ethereum::generate_solidity_files;

// Paths where the generated Solidity files will be written.
const SOLIDITY_IMAGE_ID_PATH: &str = "../../../contracts/src/GethImageID.sol";
const SOLIDITY_ELF_PATH: &str = "../../../contracts/test/GethElf.sol";

fn main() {
risc0_build::embed_methods();
let guests = risc0_build::embed_methods();
let solidity_opts = risc0_build_ethereum::Options::default()
.with_image_id_sol_path(SOLIDITY_IMAGE_ID_PATH)
.with_elf_sol_path(SOLIDITY_ELF_PATH);

generate_solidity_files(guests.as_slice(), &solidity_opts).unwrap();
}
3 changes: 2 additions & 1 deletion examples/zksync_adapter/methods/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ edition = "2021"
[build-dependencies]
risc0-build = { version = "1.0.1", optional = true }
sp1-build = { version = "3.4.0", optional = true }
risc0-build-ethereum = { version = "1.0.1", optional = true }

[package.metadata.risc0]
methods = ["risc0-guest"]

[features]
# default = ["risc0"]
sp1 = ["sp1-build"]
risc0 = ["risc0-build"]
risc0 = ["risc0-build" ,"risc0-build-ethereum"]
19 changes: 18 additions & 1 deletion examples/zksync_adapter/methods/build.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
#[cfg(any(feature = "sp1"))]
use sp1_build::build_program;

#[cfg(any(feature = "risc0"))]
use risc0_build_ethereum::generate_solidity_files;

// Paths where the generated Solidity files will be written.
#[cfg(any(feature = "risc0"))]
const SOLIDITY_IMAGE_ID_PATH: &str = "../../../contracts/src/ZksyncImageID.sol";

#[cfg(any(feature = "risc0"))]
const SOLIDITY_ELF_PATH: &str = "../../../contracts/test/ZksyncElf.sol";

fn main() {
#[cfg(any(feature = "risc0"))]
risc0_build::embed_methods();
{
let guests = risc0_build::embed_methods();
let solidity_opts = risc0_build_ethereum::Options::default()
.with_image_id_sol_path(SOLIDITY_IMAGE_ID_PATH)
.with_elf_sol_path(SOLIDITY_ELF_PATH);

generate_solidity_files(guests.as_slice(), &solidity_opts).unwrap();
}

#[cfg(any(feature = "sp1"))]
build_program("./sp1-guest")
Expand Down
6 changes: 5 additions & 1 deletion nexus_js/src/proofManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const proofManagerAbi = require("./abi/proofManager.json");

import { Provider } from "zksync-ethers";
import { AccountState } from "./types/index.js";
import { NexusHeader} from "./types/index.js";
import { hexlify } from "ethers";

class ProofManagerClient {
Expand All @@ -27,11 +28,14 @@ class ProofManagerClient {
blockNumber: number,
stateHash: string,
blockHash: string,
proof: string
proof: string,
nexus_header: NexusHeader
) {
const response = await this.proofManager.updateNexusBlock(blockNumber, {
stateRoot: stateHash,
blockHash,
proof,
nexusHeader: nexus_header,
});
}

Expand Down
9 changes: 9 additions & 0 deletions nexus_js/src/types/nexus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ type AccountState = {
height: number;
};

type NexusHeader = {
parent_hash: string;
prev_state_root: string;
state_root: string;
avail_header_hash: string;
number: number;
}

type AccountApiResponse = {
info: NexusState;
chainStateNumber: number;
Expand All @@ -32,4 +40,5 @@ export {
NexusState,
AccountState,
AccountApiResponse,
NexusHeader
}
Loading