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: aggchain-proof-builder #29

Merged
merged 15 commits into from
Feb 13, 2025
667 changes: 632 additions & 35 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ prover-utils = { path = "crates/prover-utils" }
agglayer-telemetry = { git = "https://github.com/agglayer/agglayer.git", branch = "release/0.2.1" }

# Core dependencies
alloy = { version = "0.8.1", features = ["full"] }
alloy-primitives = "0.8.1"
alloy = { version = '0.11.0', features = ["full"] }
alloy-primitives = { version = "0.8.15", features = ["serde", "k256"] }
anyhow = "1.0.94"
arc-swap = "1.7.1"
async-trait = "0.1.82"
Expand Down
8 changes: 8 additions & 0 deletions crates/aggchain-proof-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@ edition.workspace = true
license.workspace = true

[dependencies]
alloy.workspace = true
anyhow.workspace = true
futures.workspace = true
thiserror.workspace = true
tower = { workspace = true, features = ["timeout"] }
tracing.workspace = true
serde = { workspace = true, features = ["derive"] }
sp1-sdk = { workspace = true, features = ["native-gnark"] }
url.workspace = true

aggchain-proof-core.workspace = true
aggkit-prover-config.workspace = true

[lints]
workspace = true
130 changes: 120 additions & 10 deletions crates/aggchain-proof-builder/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,119 @@
mod provider;

use std::sync::Arc;
use std::task::{Context, Poll};

use aggchain_proof_core::proof::AggchainProofWitness;
use aggkit_prover_config::aggchain_proof_service::{
HTTP_RPC_NODE_BACKOFF_MAX_RETRIES, HTTP_RPC_NODE_INITIAL_BACKOFF_MS,
};
use aggkit_prover_config::AggchainProofBuilderConfig;
use alloy::eips::{BlockId, BlockNumberOrTag};
use alloy::network::primitives::BlockTransactionsKind;
use alloy::primitives::B256;
use alloy::providers::Provider;
use alloy::transports::{RpcError, TransportErrorKind};
use futures::{future::BoxFuture, FutureExt};
use serde::{Deserialize, Serialize};
use sp1_sdk::SP1ProofWithPublicValues;

use crate::provider::json_rpc::{build_http_retry_provider, AlloyProvider};

/// Aggchain proof is generated from FEP proof and additional
/// bridge inputs.
/// Resulting work of the aggchain proof builder.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct AggchainProof {
//pub proof: SP1ProofWithPublicValues,
//TODO add all necessary fields
}

pub struct Request {}
pub struct Response {}
pub struct AggchainProofBuilderRequest {
pub agg_span_proof: SP1ProofWithPublicValues,
// TODO add rest of the fields
}

#[derive(Clone, Debug)]
pub struct AggchainProofBuilderResponse {
pub proof: AggchainProof,
}

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Noop")]
Noop,
#[error(transparent)]
AlloyProviderError(anyhow::Error),

#[error(transparent)]
AlloyRpcTransportError(#[from] RpcError<TransportErrorKind>),

#[error(transparent)]
ProofGenerationError(#[from] aggchain_proof_core::error::ProofError),
}

/// This service is responsible for building an Aggchain proof.
#[derive(Default, Clone)]
pub struct AggchainProofBuilderService {}
#[derive(Debug, Clone)]
pub struct AggchainProofBuilder {
l1_client: Arc<AlloyProvider>,

_l2_client: Arc<AlloyProvider>,
}

impl AggchainProofBuilder {
pub fn new(config: &AggchainProofBuilderConfig) -> Result<Self, Error> {
Ok(AggchainProofBuilder {
l1_client: Arc::new(
build_http_retry_provider(
&config.l1_rpc_endpoint,
HTTP_RPC_NODE_INITIAL_BACKOFF_MS,
HTTP_RPC_NODE_BACKOFF_MAX_RETRIES,
)
.map_err(Error::AlloyProviderError)?,
),
_l2_client: Arc::new(
build_http_retry_provider(
&config.l2_rpc_endpoint,
HTTP_RPC_NODE_INITIAL_BACKOFF_MS,
HTTP_RPC_NODE_BACKOFF_MAX_RETRIES,
)
.map_err(Error::AlloyProviderError)?,
),
})
}

impl tower::Service<Request> for AggchainProofBuilderService {
type Response = Response;
pub async fn get_l1_block_hash(&self, block_num: u64) -> Result<B256, Error> {
let block = self
.l1_client
.get_block(
BlockId::Number(BlockNumberOrTag::Number(block_num)),
BlockTransactionsKind::Hashes,
)
.await
.map_err(Error::AlloyRpcTransportError)?
.ok_or(Error::AlloyProviderError(anyhow::anyhow!(
"target block {block_num} does not exist"
)))?;

Ok(block.header.hash)
}

// Retrieve l1 and l2 public data needed for aggchain proof generation
pub async fn retrieve_chain_data(&self) -> Result<(), Error> {
//TODO decide output structure
todo!()
}

// Generate aggchain proof
pub async fn generate_aggchain_proof(
&self,
mut _aggchain_proof_witness: AggchainProofWitness,
) -> Result<AggchainProof, Error> {
//TODO implement
todo!()
}
}

impl tower::Service<AggchainProofBuilderRequest> for AggchainProofBuilder {
type Response = AggchainProofBuilderResponse;

type Error = Error;

Expand All @@ -26,7 +123,20 @@ impl tower::Service<Request> for AggchainProofBuilderService {
todo!()
}

fn call(&mut self, _req: Request) -> Self::Future {
async move { Ok(Response {}) }.boxed()
fn call(&mut self, _req: AggchainProofBuilderRequest) -> Self::Future {
async move {
//TODO implement

// Call all necessary data retrieval
//self.retrieve_chain_data().await?;

// Generate proof
//self.generate_aggchain_proof().await?;

Ok(AggchainProofBuilderResponse {
proof: Default::default(),
})
}
.boxed()
}
}
46 changes: 46 additions & 0 deletions crates/aggchain-proof-builder/src/provider/json_rpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use std::time::Duration;

use alloy::network::Ethereum;
use alloy::providers::fillers::{
BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller,
};
use alloy::providers::Identity;
use alloy::transports::http::reqwest;
use alloy::transports::layers::RetryBackoffLayer;
use alloy::{
providers::{ProviderBuilder, RootProvider},
rpc::client::ClientBuilder,
};

const HTTP_CLIENT_CONNECTION_POOL_IDLE_TIMEOUT: u64 = 90;
const HTTP_CLIENT_MAX_IDLE_CONNECTIONS_PER_HOST: usize = 64;

pub type AlloyProvider = FillProvider<
JoinFill<
Identity,
JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
>,
RootProvider,
Ethereum,
>;

pub fn build_http_retry_provider(
rpc_url: &url::Url,
backoff: u64,
max_retries: u32,
) -> Result<AlloyProvider, anyhow::Error> {
let retry_policy = RetryBackoffLayer::new(max_retries, backoff, 5);
let reqwest_client = reqwest::ClientBuilder::new()
.pool_max_idle_per_host(HTTP_CLIENT_MAX_IDLE_CONNECTIONS_PER_HOST)
.pool_idle_timeout(Duration::from_secs(
HTTP_CLIENT_CONNECTION_POOL_IDLE_TIMEOUT,
))
.build()?;

let http = alloy::transports::http::Http::with_client(reqwest_client, rpc_url.clone());
let is_local = http.guess_local();
let client = ClientBuilder::default()
.layer(retry_policy)
.transport(http, is_local);
Ok(ProviderBuilder::new().on_client(client))
}
1 change: 1 addition & 0 deletions crates/aggchain-proof-builder/src/provider/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(crate) mod json_rpc;
2 changes: 1 addition & 1 deletion crates/aggchain-proof-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
alloy-primitives = { version = "0.8.15", features = ["serde", "k256"] }
alloy-primitives.workspace = true
k256 = "0.13.4"
serde = { version = "1.0.217", features = ["derive"] }
sha2 = { git = "https://github.com/sp1-patches/RustCrypto-hashes.git", package = "sha2", tag = "patch-sha2-0.10.8-sp1-4.0.0" }
Expand Down
2 changes: 1 addition & 1 deletion crates/aggchain-proof-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod digest;
mod error;
pub mod error;
mod full_execution_proof;
pub mod proof;
2 changes: 1 addition & 1 deletion crates/aggchain-proof-core/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl AggchainProofWitness {
}

/// Public values of the SP1 aggchain proof.
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AggchainProofPublicValues {
/// Previous local exit root.
pub prev_local_exit_root: Digest,
Expand Down
2 changes: 1 addition & 1 deletion crates/aggchain-proof-program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name = "sp1-ecdsa-verification-program"
edition = "2021"

[dependencies]
alloy-primitives = { version = "0.8.15", features = ["serde", "k256"] }
alloy-primitives.workspace = true
bincode = "1.3.3"
sp1-zkvm = "=4.0.0"
tiny-keccak = { git = "https://github.com/sp1-patches/tiny-keccak", tag = "patch-2.0.2-sp1-4.0.0", features = [
Expand Down
1 change: 1 addition & 0 deletions crates/aggkit-prover-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ humantime-serde = "1.1.1"
jsonrpsee.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_with.workspace = true
sp1-sdk = { workspace = true, features = ["native-gnark"] }
thiserror.workspace = true
toml.workspace = true
tracing.workspace = true
Expand Down
39 changes: 39 additions & 0 deletions crates/aggkit-prover-config/src/aggchain_proof_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::str::FromStr;

use jsonrpsee::core::Serialize;
use serde::Deserialize;
use url::Url;

/// The Aggchain proof builder configuration
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct AggchainProofBuilderConfig {
/// JSON-RPC endpoint of the l1 node.
#[serde(default = "default_l1_url")]
pub l1_rpc_endpoint: Url,

/// Json rpc endpoint of the l2 rollup node.
#[serde(default = "default_l2_url")]
pub l2_rpc_endpoint: Url,

/// Id of the rollup chain
pub network_id: u32,
}

impl Default for AggchainProofBuilderConfig {
fn default() -> Self {
AggchainProofBuilderConfig {
l1_rpc_endpoint: default_l1_url(),
l2_rpc_endpoint: default_l2_url(),
network_id: 0,
}
}
}

fn default_l1_url() -> Url {
Url::from_str("http://anvil-mock-l1-rpc:8545").unwrap()
}

fn default_l2_url() -> Url {
Url::from_str("http://anvil-mock-l2-rpc:8545").unwrap()
}
18 changes: 18 additions & 0 deletions crates/aggkit-prover-config/src/aggchain_proof_service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::fmt::Debug;

use serde::{Deserialize, Serialize};

use crate::aggchain_proof_builder::AggchainProofBuilderConfig;
use crate::proposer_service::ProposerServiceConfig;

pub const HTTP_RPC_NODE_INITIAL_BACKOFF_MS: u64 = 5000;

pub const HTTP_RPC_NODE_BACKOFF_MAX_RETRIES: u32 = 64;

/// The Aggchain proof service configuration
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "kebab-case")]
pub struct AggchainProofServiceConfig {
pub aggchain_proof_builder: AggchainProofBuilderConfig,
pub proposer_service: ProposerServiceConfig,
}
19 changes: 15 additions & 4 deletions crates/aggkit-prover-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@ use std::path::Path;

use prover_config::{NetworkProverConfig, ProverType};
use prover_logger::log::Log;
use prover_utils::with;
use serde::{Deserialize, Serialize};

pub use crate::{shutdown::ShutdownConfig, telemetry::TelemetryConfig};
use crate::aggchain_proof_service::AggchainProofServiceConfig;
pub use crate::{
aggchain_proof_builder::AggchainProofBuilderConfig, shutdown::ShutdownConfig,
telemetry::TelemetryConfig,
};

pub mod aggchain_proof_service;

pub mod aggchain_proof_builder;
pub mod proposer_service;
pub mod shutdown;
pub(crate) mod telemetry;

pub(crate) const DEFAULT_IP: std::net::Ipv4Addr = std::net::Ipv4Addr::new(0, 0, 0, 0);

/// The Aggkit Prover configuration.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct ProverConfig {
/// The gRPC endpoint used by the prover.
Expand All @@ -36,6 +43,9 @@ pub struct ProverConfig {
#[serde(default)]
pub shutdown: ShutdownConfig,

#[serde(default)]
pub aggchain_proof_service: AggchainProofServiceConfig,

/// The primary prover to be used for generation of the pessimistic proof
#[serde(default)]
pub primary_prover: ProverType,
Expand All @@ -52,6 +62,7 @@ impl Default for ProverConfig {
log: Log::default(),
telemetry: TelemetryConfig::default(),
shutdown: ShutdownConfig::default(),
aggchain_proof_service: AggchainProofServiceConfig::default(),
primary_prover: ProverType::NetworkProver(NetworkProverConfig::default()),
fallback_prover: None,
grpc: Default::default(),
Expand All @@ -74,7 +85,7 @@ impl ProverConfig {
}
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct GrpcConfig {
#[serde(
Expand Down
Loading