Skip to content

Commit a089f30

Browse files
feat: aggregation mode sdk (#1861)
Co-authored-by: MauroFab <[email protected]>
1 parent 3f48779 commit a089f30

File tree

19 files changed

+627
-38
lines changed

19 files changed

+627
-38
lines changed

aggregation_mode/Cargo.lock

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

batcher/Cargo.lock

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

batcher/aligned-sdk/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ hex = "0.4.3"
2525
ciborium = "=0.2.2"
2626
serde_repr = "0.1.19"
2727
dialoguer = "0.11.0"
28+
reqwest = { version = "0.12", features = ["json"] }

batcher/aligned-sdk/abi/AlignedProofAggregationService.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

batcher/aligned-sdk/src/beacon.rs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
use std::str::FromStr;
2+
3+
use ethers::core::k256::sha2::{Digest, Sha256};
4+
use reqwest::{Client, Url};
5+
use serde::{Deserialize, Serialize};
6+
use serde_json::Value;
7+
8+
// See https://eips.ethereum.org/EIPS/eip-4844#parameters
9+
pub const KZG_VERSIONED_HASH: u8 = 0x1;
10+
11+
pub struct BeaconClient {
12+
beacon_client_url: String,
13+
api_client: Client,
14+
}
15+
16+
#[derive(Debug, Serialize, Deserialize)]
17+
#[serde(untagged)]
18+
enum BeaconAPIResponse {
19+
Success { data: Value },
20+
Error { code: u64, message: String },
21+
}
22+
23+
#[derive(Debug)]
24+
pub enum BeaconClientError {
25+
Url(url::ParseError),
26+
ReqwestError(reqwest::Error),
27+
APIError { code: u64, message: String },
28+
Deserialization(serde_json::Error),
29+
}
30+
31+
#[derive(Deserialize, Debug)]
32+
#[allow(dead_code)]
33+
// https://ethereum.github.io/beacon-APIs/#/Beacon/getBlobSidecars
34+
pub struct BlobData {
35+
pub index: String,
36+
pub blob: String,
37+
pub kzg_commitment: String,
38+
pub kzg_proof: String,
39+
pub kzg_commitment_inclusion_proof: Vec<String>,
40+
}
41+
42+
#[derive(Deserialize, Debug)]
43+
#[allow(dead_code)]
44+
// https://ethereum.github.io/beacon-APIs/#/Beacon/getBlockHeaders
45+
pub struct BeaconBlock {
46+
pub root: String,
47+
pub canonical: bool,
48+
pub header: BeaconBlockHeader,
49+
}
50+
51+
#[derive(Deserialize, Debug)]
52+
53+
pub struct BeaconBlockHeader {
54+
pub message: BeaconBlockMessage,
55+
}
56+
57+
#[derive(Deserialize, Debug)]
58+
#[allow(dead_code)]
59+
pub struct BeaconBlockMessage {
60+
pub slot: String,
61+
pub proposer_index: String,
62+
pub parent_root: String,
63+
pub state_root: String,
64+
pub body_root: String,
65+
}
66+
67+
impl BeaconClient {
68+
pub fn new(beacon_client_url: String) -> Self {
69+
Self {
70+
api_client: Client::new(),
71+
beacon_client_url,
72+
}
73+
}
74+
75+
pub async fn get_block_header_from_parent_hash(
76+
&self,
77+
parent_block_hash: [u8; 32],
78+
) -> Result<Option<BeaconBlock>, BeaconClientError> {
79+
let parent_block_hash_hex = format!("0x{}", hex::encode(parent_block_hash));
80+
let data = self
81+
.beacon_get(&format!(
82+
"/eth/v1/beacon/headers?parent_root={}",
83+
parent_block_hash_hex
84+
))
85+
.await?;
86+
87+
let res =
88+
Vec::<BeaconBlock>::deserialize(data).map_err(BeaconClientError::Deserialization)?;
89+
90+
let block = res
91+
.into_iter()
92+
.find(|block| block.header.message.parent_root == parent_block_hash_hex);
93+
94+
Ok(block)
95+
}
96+
97+
pub async fn get_blobs_from_slot(&self, slot: u64) -> Result<Vec<BlobData>, BeaconClientError> {
98+
let data = self
99+
.beacon_get(&format!("/eth/v1/beacon/blob_sidecars/{}", slot))
100+
.await?;
101+
102+
Vec::<BlobData>::deserialize(data).map_err(BeaconClientError::Deserialization)
103+
}
104+
105+
pub async fn get_blob_by_versioned_hash(
106+
&self,
107+
slot: u64,
108+
blob_versioned_hash: [u8; 32],
109+
) -> Result<Option<BlobData>, BeaconClientError> {
110+
let res = self.get_blobs_from_slot(slot).await?;
111+
112+
let blob = res.into_iter().find(|blob| {
113+
let kzg_commitment_bytes =
114+
hex::decode(blob.kzg_commitment.replace("0x", "")).expect("A valid commitment");
115+
116+
let mut hasher = Sha256::new();
117+
hasher.update(&kzg_commitment_bytes);
118+
let mut versioned_hash: [u8; 32] = hasher.finalize().into();
119+
versioned_hash[0] = KZG_VERSIONED_HASH;
120+
121+
versioned_hash == blob_versioned_hash
122+
});
123+
124+
Ok(blob)
125+
}
126+
127+
async fn beacon_get(&self, path: &str) -> Result<Value, BeaconClientError> {
128+
let url = Url::from_str(&format!("{}{}", self.beacon_client_url, path))
129+
.map_err(BeaconClientError::Url)?;
130+
let req = self
131+
.api_client
132+
.get(url)
133+
.header("content-type", "application/json")
134+
.header("accept", "application/json");
135+
136+
let res = req.send().await.map_err(BeaconClientError::ReqwestError)?;
137+
let beacon_response = res.json().await.map_err(BeaconClientError::ReqwestError)?;
138+
139+
match beacon_response {
140+
BeaconAPIResponse::Success { data } => Ok(data),
141+
BeaconAPIResponse::Error { code, message } => {
142+
Err(BeaconClientError::APIError { code, message })
143+
}
144+
}
145+
}
146+
}

batcher/aligned-sdk/src/core/constants.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ pub const ALIGNED_SERVICE_MANAGER_MAINNET: &str = "0xeF2A435e5EE44B2041100EF8cbC
7171
pub const ALIGNED_SERVICE_MANAGER_MAINNET_STAGE: &str =
7272
"0x96b6a29D7B98519Ae66E6398BD27A76B30a5dC3f";
7373

74+
// AlignedProofAggregationService
75+
pub const ALIGNED_PROOF_AGG_SERVICE_ADDRESS_MAINNET: &str = "0x0";
76+
pub const ALIGNED_PROOF_AGG_SERVICE_ADDRESS_MAINNET_STAGE: &str = "0x0";
77+
pub const ALIGNED_PROOF_AGG_SERVICE_ADDRESS_HOLESKY_STAGE: &str =
78+
"0x7Eace34A8d4C4CacE633946C6F7CF4BeF3F33513";
79+
pub const ALIGNED_PROOF_AGG_SERVICE_ADDRESS_HOLESKY: &str = "0x0";
80+
pub const ALIGNED_PROOF_AGG_SERVICE_ADDRESS_DEVNET: &str =
81+
"0xcbEAF3BDe82155F56486Fb5a1072cb8baAf547cc";
82+
7483
/// Batcher URL's
7584
pub const BATCHER_URL_DEVNET: &str = "ws://localhost:8080";
7685
pub const BATCHER_URL_HOLESKY: &str = "wss://batcher.alignedlayer.com";

0 commit comments

Comments
 (0)