Skip to content

Commit cf32783

Browse files
committed
feat: get merkle path for proof in sdk
1 parent aa1e8fb commit cf32783

File tree

1 file changed

+116
-65
lines changed

1 file changed

+116
-65
lines changed

batcher/aligned-sdk/src/sdk/aggregation.rs

Lines changed: 116 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
};
55
use ethers::{
66
providers::{Http, Middleware, Provider},
7-
types::Filter,
7+
types::{Filter, Log},
88
};
99
use lambdaworks_crypto::merkle_tree::{merkle::MerkleTree, traits::IsMerkleTreeBackend};
1010
use sha3::{Digest, Keccak256};
@@ -109,9 +109,63 @@ pub async fn is_proof_verified_in_aggregation_mode(
109109
beacon_client_url: String,
110110
from_block: Option<u64>,
111111
) -> Result<[u8; 32], ProofVerificationAggModeError> {
112+
let logs = get_aggregated_proofs_logs(network, eth_rpc_url.clone(), from_block).await?;
113+
114+
for log in logs {
115+
let Ok((merkle_root, leaves)) =
116+
get_blob_data_from_log(eth_rpc_url.clone(), beacon_client_url.clone(), log).await
117+
else {
118+
continue;
119+
};
120+
121+
let leaves: Vec<Hash32> = leaves.iter().map(|leaf| Hash32(*leaf)).collect();
122+
let merkle_tree: MerkleTree<Hash32> = MerkleTree::build(&leaves).unwrap();
123+
124+
if leaves.contains(&Hash32(verification_data.commitment())) {
125+
return if merkle_tree.root == merkle_root {
126+
Ok(merkle_root)
127+
} else {
128+
Err(ProofVerificationAggModeError::UnmatchedBlobAndEventMerkleRoot)
129+
};
130+
}
131+
}
132+
133+
Err(ProofVerificationAggModeError::ProofNotFoundInLogs)
134+
}
135+
136+
pub async fn get_merkle_path_for_proof(
137+
network: Network,
138+
eth_rpc_url: String,
139+
beacon_client_url: String,
140+
from_block: Option<u64>,
141+
proof_commitment: [u8; 32],
142+
) -> Result<Option<Vec<[u8; 32]>>, ProofVerificationAggModeError> {
143+
let logs = get_aggregated_proofs_logs(network, eth_rpc_url.clone(), from_block).await?;
144+
145+
for log in logs {
146+
let (_merkle_root, leaves) =
147+
get_blob_data_from_log(eth_rpc_url.clone(), beacon_client_url.clone(), log).await?;
148+
149+
let leaves: Vec<Hash32> = leaves.iter().map(|leaf| Hash32(*leaf)).collect();
150+
let merkle_tree: MerkleTree<Hash32> = MerkleTree::build(&leaves).unwrap();
151+
152+
let Some(pos) = leaves.iter().position(|p| p.0 == proof_commitment) else {
153+
continue;
154+
};
155+
156+
return Ok(Some(merkle_tree.get_proof_by_pos(pos).unwrap().merkle_path));
157+
}
158+
159+
Ok(None)
160+
}
161+
162+
async fn get_aggregated_proofs_logs(
163+
network: Network,
164+
eth_rpc_url: String,
165+
from_block: Option<u64>,
166+
) -> Result<Vec<Log>, ProofVerificationAggModeError> {
112167
let eth_rpc_provider = Provider::<Http>::try_from(eth_rpc_url)
113168
.map_err(|e| ProofVerificationAggModeError::EthereumProviderError(e.to_string()))?;
114-
let beacon_client = BeaconClient::new(beacon_client_url);
115169

116170
let from_block = match from_block {
117171
Some(from_block) => from_block,
@@ -132,76 +186,73 @@ pub async fn is_proof_verified_in_aggregation_mode(
132186
.event("AggregatedProofVerified(bytes32,bytes32)")
133187
.from_block(from_block);
134188

135-
let logs = eth_rpc_provider.get_logs(&filter).await.unwrap();
136-
for log in logs {
137-
// First 32 bytes of the data are the bytes of the blob versioned hash
138-
let blob_versioned_hash: [u8; 32] = log.data[0..32]
139-
.try_into()
140-
.map_err(|_| ProofVerificationAggModeError::EventDecoding)?;
141-
142-
// Event is indexed by merkle root
143-
let merkle_root = log.topics[1].0;
144-
145-
// Block Number shouldn't be empty, in case it is,
146-
// there is a problem with this log, and we skip it
147-
// This same logic is replicated for other checks.
148-
let Some(block_number) = log.block_number else {
149-
continue;
150-
};
189+
Ok(eth_rpc_provider.get_logs(&filter).await.unwrap())
190+
}
151191

152-
let Some(block) = eth_rpc_provider
153-
.get_block(block_number.as_u64())
154-
.await
155-
.map_err(|e| ProofVerificationAggModeError::EthereumProviderError(e.to_string()))?
156-
else {
157-
continue;
158-
};
192+
async fn get_blob_data_from_log(
193+
eth_rpc_url: String,
194+
beacon_client_url: String,
195+
log: Log,
196+
) -> Result<([u8; 32], Vec<[u8; 32]>), ProofVerificationAggModeError> {
197+
let eth_rpc_provider = Provider::<Http>::try_from(eth_rpc_url)
198+
.map_err(|e| ProofVerificationAggModeError::EthereumProviderError(e.to_string()))?;
199+
let beacon_client = BeaconClient::new(beacon_client_url);
159200

160-
let Some(beacon_parent_root) = block.parent_beacon_block_root else {
161-
continue;
162-
};
201+
// First 32 bytes of the data are the bytes of the blob versioned hash
202+
let blob_versioned_hash: [u8; 32] = log.data[0..32]
203+
.try_into()
204+
.map_err(|_| ProofVerificationAggModeError::EventDecoding)?;
163205

164-
let Some(beacon_block) = beacon_client
165-
.get_block_header_from_parent_hash(beacon_parent_root.0)
166-
.await
167-
.map_err(ProofVerificationAggModeError::BeaconClient)?
168-
else {
169-
continue;
170-
};
206+
// Event is indexed by merkle root
207+
let merkle_root = log.topics[1].0;
171208

172-
let slot: u64 = beacon_block
173-
.header
174-
.message
175-
.slot
176-
.parse()
177-
.expect("Slot to be parsable number");
178-
179-
let Some(blob_data) = beacon_client
180-
.get_blob_by_versioned_hash(slot, blob_versioned_hash)
181-
.await
182-
.map_err(ProofVerificationAggModeError::BeaconClient)?
183-
else {
184-
continue;
185-
};
209+
// Block Number shouldn't be empty, in case it is,
210+
// there is a problem with this log, and we skip it
211+
// This same logic is replicated for other checks.
212+
let Some(block_number) = log.block_number else {
213+
return Err(ProofVerificationAggModeError::EventDecoding);
214+
};
186215

187-
let blob_bytes =
188-
hex::decode(blob_data.blob.replace("0x", "")).expect("A valid hex encoded data");
189-
let proof_commitments: Vec<Hash32> = decoded_blob(blob_bytes)
190-
.iter()
191-
.map(|p| Hash32(*p))
192-
.collect();
193-
let merkle_tree: MerkleTree<Hash32> = MerkleTree::build(&proof_commitments).unwrap();
216+
let Some(block) = eth_rpc_provider
217+
.get_block(block_number.as_u64())
218+
.await
219+
.map_err(|e| ProofVerificationAggModeError::EthereumProviderError(e.to_string()))?
220+
else {
221+
return Err(ProofVerificationAggModeError::EventDecoding);
222+
};
194223

195-
if proof_commitments.contains(&Hash32(verification_data.commitment())) {
196-
return if merkle_tree.root == merkle_root {
197-
Ok(merkle_root)
198-
} else {
199-
Err(ProofVerificationAggModeError::UnmatchedBlobAndEventMerkleRoot)
200-
};
201-
}
202-
}
224+
let Some(beacon_parent_root) = block.parent_beacon_block_root else {
225+
return Err(ProofVerificationAggModeError::EventDecoding);
226+
};
203227

204-
Err(ProofVerificationAggModeError::ProofNotFoundInLogs)
228+
let Some(beacon_block) = beacon_client
229+
.get_block_header_from_parent_hash(beacon_parent_root.0)
230+
.await
231+
.map_err(ProofVerificationAggModeError::BeaconClient)?
232+
else {
233+
return Err(ProofVerificationAggModeError::EventDecoding);
234+
};
235+
236+
let slot: u64 = beacon_block
237+
.header
238+
.message
239+
.slot
240+
.parse()
241+
.expect("Slot to be parsable number");
242+
243+
let Some(blob_data) = beacon_client
244+
.get_blob_by_versioned_hash(slot, blob_versioned_hash)
245+
.await
246+
.map_err(ProofVerificationAggModeError::BeaconClient)?
247+
else {
248+
return Err(ProofVerificationAggModeError::EventDecoding);
249+
};
250+
251+
let blob_bytes =
252+
hex::decode(blob_data.blob.replace("0x", "")).expect("A valid hex encoded data");
253+
let proof_commitments = decoded_blob(blob_bytes);
254+
255+
Ok((merkle_root, proof_commitments))
205256
}
206257

207258
fn decoded_blob(blob_data: Vec<u8>) -> Vec<[u8; 32]> {

0 commit comments

Comments
 (0)