Skip to content

Commit f5f14ef

Browse files
authored
feat: verify consensus anchor with SP1 Helios (#66)
* feat: verify consensus with SP1 Helios * fix: 404 * fix: don't use foundry nightly * fix: publish book on main only * fix: add sp1-helios remapping * fix: update remappings
1 parent 036a142 commit f5f14ef

File tree

12 files changed

+139
-78
lines changed

12 files changed

+139
-78
lines changed

.github/workflows/book.yml

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,56 @@
11
name: book
22

33
on:
4-
push:
5-
branches: [main]
6-
pull_request:
7-
branches: [main]
8-
paths:
9-
- "book/**"
10-
merge_group:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "book/**"
8+
merge_group:
119

1210
jobs:
13-
build:
14-
name: Build Docusaurus
15-
runs-on: ubuntu-latest
16-
steps:
17-
- uses: actions/checkout@v4
18-
with:
19-
fetch-depth: 0
20-
- uses: actions/setup-node@v4
21-
with:
22-
node-version: 18
23-
24-
- name: Install dependencies
25-
run: cd book && yarn install --frozen-lockfile
26-
- name: Build website
27-
run: |
28-
cd book
29-
yarn build-api
30-
mv ../target/doc ./static/api
31-
mv ./static/api/static.files/* ./static/api
32-
rmdir ./static/api/static.files
33-
yarn build-book
34-
35-
- name: Upload Build Artifact
36-
uses: actions/upload-pages-artifact@v3
37-
with:
38-
path: book/build
39-
40-
deploy:
41-
name: Deploy to GitHub Pages
42-
needs: build
43-
44-
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
45-
permissions:
46-
pages: write # to deploy to Pages
47-
id-token: write # to verify the deployment originates from an appropriate source
48-
49-
# Deploy to the github-pages environment
50-
environment:
51-
name: github-pages
52-
url: ${{ steps.deployment.outputs.page_url }}
53-
54-
runs-on: ubuntu-latest
55-
steps:
56-
- name: Deploy to GitHub Pages
57-
id: deployment
58-
uses: actions/deploy-pages@v4
11+
build:
12+
name: Build Docusaurus
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
- uses: actions/setup-node@v4
19+
with:
20+
node-version: 18
21+
22+
- name: Install dependencies
23+
run: cd book && yarn install --frozen-lockfile
24+
- name: Build website
25+
run: |
26+
cd book
27+
yarn build-api
28+
mv ../target/doc ./static/api
29+
mv ./static/api/static.files/* ./static/api
30+
rmdir ./static/api/static.files
31+
yarn build-book
32+
33+
- name: Upload Build Artifact
34+
uses: actions/upload-pages-artifact@v3
35+
with:
36+
path: book/build
37+
38+
deploy:
39+
name: Deploy to GitHub Pages
40+
needs: build
41+
42+
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
43+
permissions:
44+
pages: write # to deploy to Pages
45+
id-token: write # to verify the deployment originates from an appropriate source
46+
47+
# Deploy to the github-pages environment
48+
environment:
49+
name: github-pages
50+
url: ${{ steps.deployment.outputs.page_url }}
51+
52+
runs-on: ubuntu-latest
53+
steps:
54+
- name: Deploy to GitHub Pages
55+
id: deployment
56+
uses: actions/deploy-pages@v4

.github/workflows/pr.yml

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
image=ubuntu22-full-x64,
2323
spot=false,
2424
"run-id=${{ github.run_id }}",
25-
]
25+
]
2626
strategy:
2727
matrix:
2828
example:
@@ -39,12 +39,12 @@ jobs:
3939

4040
- name: "Install sp1up"
4141
run: |
42-
curl -L https://sp1.succinct.xyz | bash
43-
echo "$HOME/.sp1/bin" >> $GITHUB_PATH
42+
curl -L https://sp1.succinct.xyz | bash
43+
echo "$HOME/.sp1/bin" >> $GITHUB_PATH
4444
4545
- name: "Install SP1 toolchain"
4646
run: |
47-
sp1up
47+
sp1up
4848
4949
- name: "Set up RPC env"
5050
run: |
@@ -54,19 +54,19 @@ jobs:
5454
echo "OPTIMISM_RPC_URL=${{secrets.OPTIMISM_RPC_URL}}" >> $GITHUB_ENV
5555
5656
- name: Run ${{ matrix.example }}
57-
uses: actions-rs/cargo@v1
57+
uses: actions-rs/cargo@v1
5858
with:
5959
command: run
60-
args:
61-
--release --bin ${{ matrix.example }} --ignore-rust-version
60+
args: --release --bin ${{ matrix.example }} --ignore-rust-version
6261
env:
6362
RUSTFLAGS: -Copt-level=3 -Coverflow-checks=y -Cdebuginfo=0 -C target-cpu=native
6463
RUST_BACKTRACE: full
6564
RUST_LOG: info
6665

6766
test-e2e:
6867
name: E2E tests
69-
runs-on: ["runs-on", "runner=32cpu-linux-x64", "run-id=${{ github.run_id }}"]
68+
runs-on:
69+
["runs-on", "runner=32cpu-linux-x64", "run-id=${{ github.run_id }}"]
7070
env:
7171
CARGO_NET_GIT_FETCH_WITH_CLI: "true"
7272
steps:
@@ -93,8 +93,6 @@ jobs:
9393

9494
- name: Install Foundry
9595
uses: foundry-rs/foundry-toolchain@v1
96-
with:
97-
version: nightly
9896

9997
- name: Run Forge build
10098
run: |

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@
77
[submodule "contracts/lib/forge-std"]
88
path = contracts/lib/forge-std
99
url = https://github.com/foundry-rs/forge-std
10+
[submodule "contracts/lib/sp1-helios"]
11+
path = contracts/lib/sp1-helios
12+
url = https://github.com/succinctlabs/sp1-helios

book/docs/examples.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ You can add the `--prove` argument to generate a proof.
2121

2222
:::warning
2323

24-
Running with `--prove` will generate a plonk proof. This requires significant computational resources, so we recommend using the [SP1 Prover network](https://docs.succinct.xyz/docs/network/developers/intro).
24+
Running with `--prove` will generate a plonk proof. This requires significant computational resources, so we recommend using the [SP1 Prover network].
2525

2626
:::
2727

@@ -40,20 +40,20 @@ RUST_LOG=info cargo run --bin uniswap-onchain-verify --release
4040
By default, the `blockhash()` opcode is used, allowing to verify up to 256 blocks old, but the following arguments can be added to demonstrate the various features abaliable:
4141

4242
* If you provides a Beacon RPC endpoint with the `--beacon-sepolia-rpc-url` argument, the proof will be verified on chain with the beacon root using [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788), up to 8191 blocks old (~27h).
43-
* The window can even be extended up to the Cancun hardfork by chaining beacon roots using the `--reference-block` argument.
43+
* The window can even be extended up to the Cancun hardfork by chaining beacon roots using the `--reference-block` argument.
4444

4545
:::
4646

4747
:::warning
4848

49-
This example will generate a plonk proof. This requires significant computational resources, so we recommend using the [SP1 Prover network](https://docs.succinct.xyz/docs/network/developers/intro).
49+
This example will generate a plonk proof. This requires significant computational resources, so we recommend using the [SP1 Prover network].
5050

5151
:::
5252

5353

5454
## Multiplexer
5555

56-
The Multiplexer Oracle example demonstrates fetching exchange rates for multiple collateral tokens from an on-chain oracle contract and generating zero-knowledge proofs of the retrieved data.
56+
The Multiplexer Oracle example demonstrates fetching exchange rates for multiple collateral tokens from an on-chain oracle contract and generating zero-knowledge proofs of the retrieved data.
5757

5858
:::tip
5959

@@ -105,4 +105,6 @@ This example can be ran with the following command:
105105
RUST_LOG=info cargo run --bin events --release
106106
```
107107

108-
:::
108+
:::
109+
110+
[SP1 Prover network]: https://docs.succinct.xyz/docs/protocol/spn/architecture

book/docs/proof-verification.md

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,25 @@ SP1 Contract call retrieve the state for contract calls at a specific block (cal
99

1010
The anchor consists of an identifier that identifies the block and a hash that enables its verification. The method used to generate the anchor have a direct impact of the window between the execution block and the block on which the verify transaction is contained, as you can see in the table below:
1111

12-
| Method | Anchor Identifier | Anchor Hash | On-chain validation | Validation window |
13-
|-------------------------------------|-------------------|-------------|---------------------|-------------------|
14-
| [Block hash](#using-block-hash) | Block number | Block hash || 256 blocks |
15-
| [Beacon root](#using-beacon-root) | Timestamp | Beacon root || 8191 blocks |
16-
| [Beacon root (chained)](#chaining) | Timestamp | Beacon root || Up to Cancun |
17-
| [Consensus](#using-consensus) | Slot | Beacon root || N/A |
12+
| Method | Anchor Identifier | Anchor Hash | On-chain validation | Validation window |
13+
|-------------------------|-------------------|-------------|-----------------------|-------------------|
14+
| [Block hash] | Block number | Block hash || 256 blocks |
15+
| [Beacon root] | Timestamp | Beacon root || 8191 blocks |
16+
| [Beacon root (chained)] | Timestamp | Beacon root || Up to Cancun |
17+
| [Consensus] | Slot | Beacon root | ✅ (using SP1 Helios) | Up to Atlair |
18+
19+
[Beacon root]: #using-beacon-root
20+
[Block hash]: #using-block-hash
21+
[Beacon root (chained)]: #chaining
22+
[Consensus]: #using-consensus
23+
[with SP1 Helios]: #on-chain-validation-using-sp1-helios
1824

1925
## Using block hash
2026

2127
This method uses the `blockhash` opcode to commit to a block hash. This gives 256 blocks (approximately 50 minutes) to create the proof and confirm that the validating transaction is included in a block.
2228

29+
The [ContractCall] library `verify()` function can by used to validate the contract call proof public values on-chain.
30+
2331
## Using beacon root
2432

2533
This approach enables verification through the [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) beacon roots contract. By using this technique, the onchain proof validation window is extended to 8191 blocks (approximately 27 hours). The method requires a beacon API endpoint connection and can be activated by invoking [`EvmSketchBuilder::cl_rpc_url()`]:
@@ -33,6 +41,8 @@ let sketch = EvmSketch::builder()
3341
.await?;
3442
```
3543

44+
In the same way as with the block hash method, the [ContractCall] library `verify()` function can by used to validate the contract call proof public values on-chain.
45+
3646
### Chaining
3747

3848
The EIP-4788 anchor mechanism can be used to query view call state from blocks beyond the 8191 block limit by separating the anchor into two components: an execution block and a reference block. While the reference block acts as the anchor and must remain within the ~27 hour onchain validation timeframe, the execution block can extend significantly further into the past—up to the Cancun hardfork (March 13, 2024 on Mainnet).
@@ -77,7 +87,25 @@ let sketch = EvmSketch::builder()
7787
.await?;
7888
```
7989

90+
More specifically, it is possible to leverage [SP1 Helios], which consists of the following components:
91+
92+
* The SP1 Helios program. An SP1 program that verifies the consensus of a source chain in the execution environment of a destination chain using the [helios] library.
93+
* An `SP1Helios` contract. Contains the logic for verifying SP1 Helios proofs, storing the latest data from the Ethereum beacon chain, including the headers, execution state roots and sync committees.
94+
* The operator. A Rust script that fetches the latest data from a deployed SP1Helios contract and an Ethereum beacon chain, determines the block to request, requests for/generates a proof, and relays the proof to the SP1Helios contract.
95+
96+
You can have a look at the [SP1 Helios book] to learn how to deploy it. Then, you can use the [ContractCall] library `verifyWithSp1Helios()` function to validate the contract call proof public values. It will uses the `SP1Helios` contract to verify the anchor is valid.
97+
98+
:::tip
99+
100+
As hinted above, the consensus method can be used to validate the public values of proofs generated on another chain. You just need to deploy the `SP1Helios` contract on the destination chain, and configure the operator to fetch the data from the chain where the contract executions occured.
101+
102+
:::
103+
80104
[`Anchor`]: pathname:///api/sp1_cc_client_executor/enum.Anchor.html
81105
[`EvmSketchBuilder::cl_rpc_url()`]: pathname:///api/sp1_cc_host_executor/struct.EvmSketchBuilder.html#method.cl_rpc_url
82106
[`EvmSketchBuilder::at_reference_block()`]: pathname:///api/sp1_cc_host_executor/struct.EvmSketchBuilder.html#method.at_reference_block
83107
[`EvmSketchBuilder::consensus()`]: pathname:///api/sp1_cc_host_executor/struct.EvmSketchBuilder.html#method.consensus
108+
[SP1 Helios]: https://github.com/succinctlabs/sp1-helios
109+
[SP1 Helios book]: https://succinctlabs.github.io/sp1-helios/deployment.html
110+
[helios]: https://github.com/a16z/helios
111+
[ContractCall]: https://github.com/succinctlabs/sp1-contract-call/tree/main/contracts/src/ContractCall.sol

contracts/foundry.lock

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"../examples/uniswap/contracts/lib/forge-std": {
3+
"rev": "b8f065fda83b8cd94a6b2fec8fcd911dc3b444fd"
4+
},
5+
"../examples/uniswap/contracts/lib/sp1-contracts": {
6+
"rev": "a6ca9452af7d6175adcef28b634fcae8662ded03"
7+
},
8+
"lib/forge-std": {
9+
"rev": "b8f065fda83b8cd94a6b2fec8fcd911dc3b444fd"
10+
},
11+
"lib/sp1-helios": {
12+
"rev": "33d243728fe9ec4850e7b4fa1c2e373b7c8a61c6"
13+
}
14+
}

contracts/lib/sp1-helios

Submodule sp1-helios added at 3ad7783

contracts/remappings.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sp1-helios/=lib/sp1-helios/contracts/src/
2+
@sp1-contracts/=lib/sp1-helios/contracts/lib/sp1-contracts/contracts/src/

contracts/src/ContractCall.sol

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.20;
33

4+
import {SP1Helios} from "@sp1-helios/SP1Helios.sol";
5+
46
/// @notice The inputs used to verify a contract call.
57
struct ContractPublicValues {
68
uint256 id;
@@ -47,6 +49,18 @@ library ContractCall {
4749
revert AnchorTypeNotSupported(publicValues.anchorType);
4850
}
4951

52+
/// @notice Verify contract call public values, using a [`SP1Helios`] contract.
53+
/// @dev Panics if the [`AnchorType`] is not `Slot`.
54+
function verifyWithSp1Helios(ContractPublicValues memory publicValues, address sp1Helios) internal view {
55+
if (publicValues.anchorType != AnchorType.Slot) {
56+
revert AnchorTypeNotSupported(publicValues.anchorType);
57+
}
58+
59+
if (publicValues.anchorHash != SP1Helios(sp1Helios).headers(publicValues.id)) {
60+
revert AnchorMismatch();
61+
}
62+
}
63+
5064
/// @notice Verify if the provided block hash matches the one of the given block number.
5165
function verifyBlockAnchor(uint256 blockNumber, bytes32 blockHash) internal view {
5266
if (blockNumber >= block.number || block.number - blockNumber > 256) {

0 commit comments

Comments
 (0)