Skip to content

Commit b4a3da4

Browse files
Merge branch 'staging' into feat/aggregation-mode-rename-endpoints
2 parents 8bca829 + 8019324 commit b4a3da4

26 files changed

+600
-41
lines changed

.github/workflows/build-and-test-go.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,34 +31,81 @@ jobs:
3131
- name: foundry-toolchain
3232
uses: foundry-rs/[email protected]
3333

34+
- name: Cache SP1 bindings
35+
id: cache-sp1
36+
uses: actions/cache@v4
37+
with:
38+
path: operator/sp1/lib/libsp1_verifier_ffi.so
39+
key: sp1-bindings-${{ runner.os }}-${{ hashFiles('operator/sp1/lib/**/*.rs', 'operator/sp1/lib/Cargo.*') }}
40+
3441
- name: Build SP1 bindings
42+
if: steps.cache-sp1.outputs.cache-hit != 'true'
3543
run: make build_sp1_linux
3644

3745
- name: Clean SP1 build artifacts
46+
if: steps.cache-sp1.outputs.cache-hit != 'true'
3847
run: rm -rf operator/sp1/lib/target
3948

49+
- name: Cache Risc Zero bindings
50+
id: cache-risc-zero
51+
uses: actions/cache@v4
52+
with:
53+
path: operator/risc_zero/lib/librisc_zero_verifier_ffi.so
54+
key: risc-zero-bindings-${{ runner.os }}-${{ hashFiles('operator/risc_zero/lib/**/*.rs', 'operator/risc_zero/lib/Cargo.*') }}
55+
4056
- name: Build Risc Zero go bindings
57+
if: steps.cache-risc-zero.outputs.cache-hit != 'true'
4158
run: make build_risc_zero_linux
4259

4360
- name: Clean Risc Zero build artifacts
61+
if: steps.cache-risc-zero.outputs.cache-hit != 'true'
4462
run: rm -rf operator/risc_zero/lib/target
4563

64+
- name: Cache Merkle Tree bindings
65+
id: cache-merkle-tree
66+
uses: actions/cache@v4
67+
with:
68+
path: |
69+
operator/merkle_tree/lib/libmerkle_tree.so
70+
operator/merkle_tree/lib/libmerkle_tree.a
71+
key: merkle-tree-bindings-${{ runner.os }}-${{ hashFiles('operator/merkle_tree/lib/**/*.rs', 'operator/merkle_tree/lib/Cargo.*') }}
72+
4673
- name: Build Merkle Tree bindings
74+
if: steps.cache-merkle-tree.outputs.cache-hit != 'true'
4775
run: make build_merkle_tree_linux
4876

4977
- name: Clean Merkle Tree build artifacts
78+
if: steps.cache-merkle-tree.outputs.cache-hit != 'true'
5079
run: rm -rf operator/merkle_tree/lib/target
5180

81+
- name: Cache Mina bindings
82+
id: cache-mina
83+
uses: actions/cache@v4
84+
with:
85+
path: operator/mina/lib/libmina_state_verifier_ffi.so
86+
key: mina-bindings-${{ runner.os }}-${{ hashFiles('operator/mina/lib/**/*.rs', 'operator/mina/lib/Cargo.*') }}
87+
5288
- name: Build Mina bindings
89+
if: steps.cache-mina.outputs.cache-hit != 'true'
5390
run: make build_mina_linux
5491

5592
- name: Clean Mina build artifacts
93+
if: steps.cache-mina.outputs.cache-hit != 'true'
5694
run: rm -rf operator/mina/lib/target
5795

96+
- name: Cache Mina Account bindings
97+
id: cache-mina-account
98+
uses: actions/cache@v4
99+
with:
100+
path: operator/mina_account/lib/libmina_account_verifier_ffi.so
101+
key: mina-account-bindings-${{ runner.os }}-${{ hashFiles('operator/mina_account/lib/**/*.rs', 'operator/mina_account/lib/Cargo.*') }}
102+
58103
- name: Build Mina Account bindings
104+
if: steps.cache-mina-account.outputs.cache-hit != 'true'
59105
run: make build_mina_account_linux
60106

61107
- name: Clean Mina Account build artifacts
108+
if: steps.cache-mina-account.outputs.cache-hit != 'true'
62109
run: rm -rf operator/mina_account/lib/target
63110

64111
- name: Build operator

Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ proof_aggregator_start_dev: is_aggregator_set reset_last_aggregated_block ./aggr
252252
proof_aggregator_start_dev_ethereum_package: is_aggregator_set reset_last_aggregated_block ./aggregation_mode/target/release/proof_aggregator_dev ## Starts proof aggregator with mock proofs (DEV mode) in ethereum package. Parameters: AGGREGATOR=<sp1|risc0>
253253
AGGREGATOR=$(AGGREGATOR) RISC0_DEV_MODE=1 ./aggregation_mode/target/release/proof_aggregator_dev config-files/config-proof-aggregator-mock-ethereum-package.yaml
254254

255+
proof_aggregator_test_without_compiling_agg_programs:
256+
cd aggregation_mode && SKIP_AGG_PROGRAMS_BUILD=1 cargo test -p proof_aggregator --tests -- --nocapture
257+
255258
### All CPU proof aggregator receipts
256259
./aggregation_mode/target/release/proof_aggregator_cpu: $(AGGREGATION_MODE_SOURCES)
257260
AGGREGATOR=$(AGGREGATOR) cargo build --features prove --manifest-path ./aggregation_mode/Cargo.toml --release --bin proof_aggregator_cpu
@@ -320,6 +323,22 @@ agg_mode_batcher_start_local: agg_mode_run_migrations
320323
agg_mode_batcher_start_ethereum_package: agg_mode_run_migrations
321324
cargo run --manifest-path ./aggregation_mode/Cargo.toml --release --bin agg_mode_batcher -- config-files/config-agg-mode-batcher-ethereum-package.yaml
322325

326+
AGG_MODE_SENDER ?= 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
327+
agg_mode_batcher_send_payment:
328+
@cast send --value 1ether \
329+
0x922D6956C99E12DFeB3224DEA977D0939758A1Fe \
330+
--private-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
331+
332+
agg_mode_batcher_send_sp1_proof:
333+
@NONCE=$$(curl -s http://127.0.0.1:8089/nonce/0x70997970C51812dc3A010C7d01b50e0d17dc79C8 | jq -r '.data.nonce'); \
334+
curl -X POST \
335+
-H "Content-Type: multipart/form-data" \
336+
-F "nonce=$${NONCE}" \
337+
-F "proof=@scripts/test_files/sp1/sp1_fibonacci_5_0_0.proof" \
338+
-F "program_vk=@scripts/test_files/sp1/sp1_fibonacci_5_0_0_vk.bin" \
339+
-F "signature_hex=0x0" \
340+
http://127.0.0.1:8089/proof/sp1
341+
323342
__AGGREGATOR__: ## ____
324343

325344
aggregator_start: ## Start the Aggregator. Parameters: ENVIRONMENT=<devnet|testnet|mainnet>, AGG_CONFIG_FILE

aggregation_mode/Cargo.lock

Lines changed: 75 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aggregation_mode/batcher/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ serde = { workspace = true }
88
serde_json = { workspace = true }
99
serde_yaml = { workspace = true }
1010
aligned-sdk = { workspace = true }
11+
sp1-sdk = { workspace = true }
1112
tracing = { version = "0.1", features = ["log"] }
1213
tracing-subscriber = { version = "0.3.0", features = ["env-filter"] }
14+
bincode = "1.3.3"
1315
actix-web = "4"
16+
actix-multipart = "0.7.2"
1417
alloy = { workspace = true }
1518
tokio = { version = "1", features = ["time"]}
1619
# TODO: enable tls

aggregation_mode/batcher/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ pub mod config;
22
pub mod db;
33
pub mod payments;
44
pub mod server;
5+
mod verifiers;

aggregation_mode/batcher/src/server/http.rs

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ use std::{
33
time::{SystemTime, UNIX_EPOCH},
44
};
55

6+
use actix_multipart::form::MultipartForm;
67
use actix_web::{
78
web::{self, Data},
89
App, HttpRequest, HttpResponse, HttpServer, Responder,
910
};
1011
use aligned_sdk::aggregation_layer::AggregationModeProvingSystem;
12+
use sp1_sdk::{SP1ProofWithPublicValues, SP1VerifyingKey};
1113
use sqlx::types::BigDecimal;
1214

1315
use super::{
@@ -18,10 +20,8 @@ use super::{
1820
use crate::{
1921
config::Config,
2022
db::Db,
21-
server::types::{
22-
GetReceiptsResponse, SubmitProofRequest, SubmitProofRequestMessageRisc0,
23-
SubmitProofRequestMessageSP1,
24-
},
23+
server::types::{GetReceiptsResponse, SubmitProofRequestRisc0, SubmitProofRequestSP1},
24+
verifiers::{verify_sp1_proof, VerificationError},
2525
};
2626

2727
#[derive(Clone, Debug)]
@@ -79,7 +79,6 @@ impl BatcherServer {
7979
let address = address_raw.to_lowercase();
8080

8181
// TODO: validate valid ethereum address
82-
8382
let Some(state) = req.app_data::<Data<BatcherServer>>() else {
8483
return HttpResponse::InternalServerError()
8584
.json(AppResponse::new_unsucessfull("Internal server error", 500));
@@ -100,11 +99,8 @@ impl BatcherServer {
10099
// Posts an SP1 proof to the batcher, recovering the address from the signature
101100
async fn post_proof_sp1(
102101
req: HttpRequest,
103-
body: web::Json<SubmitProofRequest<SubmitProofRequestMessageSP1>>,
102+
MultipartForm(data): MultipartForm<SubmitProofRequestSP1>,
104103
) -> impl Responder {
105-
let data = body.into_inner();
106-
107-
// TODO: validate signature
108104
let recovered_address = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8".to_lowercase();
109105

110106
let Some(state) = req.app_data::<Data<BatcherServer>>() else {
@@ -118,7 +114,7 @@ impl BatcherServer {
118114
.json(AppResponse::new_unsucessfull("Internal server error", 500));
119115
};
120116

121-
if data.nonce != (count as u64) {
117+
if data.nonce.0 != (count as u64) {
122118
return HttpResponse::BadRequest().json(AppResponse::new_unsucessfull(
123119
&format!("Invalid nonce, expected nonce = {count}"),
124120
400,
@@ -156,15 +152,42 @@ impl BatcherServer {
156152
));
157153
}
158154

159-
// TODO: decode proof and validate it
155+
let Ok(proof_content) = tokio::fs::read(data.proof.file.path()).await else {
156+
return HttpResponse::InternalServerError()
157+
.json(AppResponse::new_unsucessfull("Internal server error", 500));
158+
};
159+
160+
let Ok(proof) = bincode::deserialize::<SP1ProofWithPublicValues>(&proof_content) else {
161+
return HttpResponse::BadRequest()
162+
.json(AppResponse::new_unsucessfull("Invalid SP1 proof", 400));
163+
};
164+
165+
let Ok(vk_content) = tokio::fs::read(data.program_vk.file.path()).await else {
166+
return HttpResponse::InternalServerError()
167+
.json(AppResponse::new_unsucessfull("Internal server error", 500));
168+
};
169+
170+
let Ok(vk) = bincode::deserialize::<SP1VerifyingKey>(&vk_content) else {
171+
return HttpResponse::BadRequest()
172+
.json(AppResponse::new_unsucessfull("Invalid vk", 400));
173+
};
174+
175+
if let Err(e) = verify_sp1_proof(&proof, &vk) {
176+
let message = match e {
177+
VerificationError::InvalidProof => "Proof verification failed",
178+
VerificationError::UnsupportedProof => "Unsupported proof",
179+
};
180+
181+
return HttpResponse::BadRequest().json(AppResponse::new_unsucessfull(message, 400));
182+
};
160183

161184
match state
162185
.db
163186
.insert_task(
164187
&recovered_address,
165188
AggregationModeProvingSystem::SP1.as_u16() as i32,
166-
&data.message.proof,
167-
&data.message.program_vk_commitment,
189+
&proof_content,
190+
&vk_content,
168191
None,
169192
data.nonce as i64,
170193
)
@@ -182,7 +205,7 @@ impl BatcherServer {
182205
// Posts a Risc0 proof to the batcher, recovering the address from the signature
183206
async fn post_proof_risc0(
184207
_req: HttpRequest,
185-
_body: web::Json<SubmitProofRequest<SubmitProofRequestMessageRisc0>>,
208+
MultipartForm(_): MultipartForm<SubmitProofRequestRisc0>,
186209
) -> impl Responder {
187210
HttpResponse::Ok().json(AppResponse::new_sucessfull(serde_json::json!({})))
188211
}

0 commit comments

Comments
 (0)