Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: Gustavo Inacio <[email protected]>
  • Loading branch information
gusinacio committed Nov 4, 2024
1 parent 4b62d16 commit 560957b
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 58 deletions.
10 changes: 9 additions & 1 deletion crates/header-accumulator/src/epoch.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::array::IntoIter;

use alloy_primitives::map::HashSet;
use ethportal_api::types::execution::accumulator::HeaderRecord;
use ethportal_api::types::execution::accumulator::{EpochAccumulator, HeaderRecord};

use crate::{errors::EraValidateError, types::ExtHeaderRecord};

Expand Down Expand Up @@ -30,6 +30,7 @@ pub const MERGE_BLOCK: u64 = 15537394;
/// 0 must start from block 0 to block 8191.
///
/// All blocks must be at the same epoch
#[derive(Clone)]
pub struct Epoch {
number: usize,
data: Box<[HeaderRecord; MAX_EPOCH_SIZE]>,
Expand Down Expand Up @@ -81,6 +82,13 @@ impl TryFrom<Vec<ExtHeaderRecord>> for Epoch {
}
}

impl From<Epoch> for EpochAccumulator {
fn from(value: Epoch) -> Self {
let vec: Vec<HeaderRecord> = value.data.into_iter().collect();
EpochAccumulator::from(vec)
}
}

impl Epoch {
pub fn number(&self) -> usize {
self.number
Expand Down
13 changes: 13 additions & 0 deletions crates/header-accumulator/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ pub enum EraValidateError {
#[error("Era accumulator mismatch")]
EraAccumulatorMismatch,

#[error("Block epoch {block_epoch} (block number {block_number}) could not be proven with provided epoch {epoch_number}.")]
EpochNotMatchForHeader {
epoch_number: usize,
block_number: u64,
block_epoch: usize,
},

#[error("Expected epoch {block_epoch} was not found in the provided epoch list. Epochs provided: {epoch_list:?}.")]
EpochNotFoundInProvidedList {
block_epoch: usize,
epoch_list: Vec<usize>,
},

#[error("Error generating inclusion proof")]
ProofGenerationFailure,
#[error("Error validating inclusion proof")]
Expand Down
115 changes: 60 additions & 55 deletions crates/header-accumulator/src/inclusion_proof.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{epoch::MAX_EPOCH_SIZE, errors::EraValidateError, types::ExtHeaderRecord};
use std::ops::Range;

use crate::{epoch::MAX_EPOCH_SIZE, errors::EraValidateError, types::ExtHeaderRecord, Epoch};

use alloy_primitives::FixedBytes;
use ethportal_api::{
Expand All @@ -15,6 +17,8 @@ use trin_validation::{
historical_roots_acc::HistoricalRootsAccumulator,
};

type InclusionProof = [Hash256; 15];

/// generates an inclusion proof over headers, given blocks between `start_block` and `end_block`
///
/// # Arguments
Expand All @@ -23,50 +27,49 @@ use trin_validation::{
/// to function without error
/// * `start_block` - The starting point of blocks that are to be included in the proofs. This interval is inclusive.
/// * `end_epoch` - The ending point of blocks that are to be included in the proofs. This interval is inclusive.
pub fn generate_inclusion_proof(
mut ext_headers: Vec<ExtHeaderRecord>,
start_block: u64,
end_block: u64,
) -> Result<Vec<[Hash256; 15]>, EraValidateError> {
if start_block > end_block {
return Err(EraValidateError::InvalidBlockRange(start_block, end_block));
}

// Compute the epoch accumulator for the blocks
// The epochs start on a multiple of 8192 blocks, so we need to round down to the nearest 8192
let epoch_start = start_block / MAX_EPOCH_SIZE as u64;

// The epochs end on a multiple of 8192 blocks, so we need to round up to the nearest 8192
let epoch_end = ((end_block as f32) / MAX_EPOCH_SIZE as f32).ceil() as u64;

pub fn generate_inclusion_proofs(
epochs: Vec<Epoch>,
headers_to_prove: Vec<Header>,
) -> Result<Vec<InclusionProof>, EraValidateError> {
// We need to load blocks from an entire epoch to be able to generate inclusion proofs
// First compute epoch accumulators and the Merkle tree for all the epochs of interest
let mut epoch_accumulators = Vec::new();
let mut inclusion_proof_vec: Vec<[FixedBytes<32>; 15]> = Vec::new();
let mut headers: Vec<Header> = Vec::new();
// let mut epoch_accumulators = Vec::new();
// let mut headers: Vec<Header> = Vec::new();
let mut inclusion_proof_vec: Vec<InclusionProof> = Vec::new();
let epoch_list: Vec<_> = epochs.iter().map(|epoch| epoch.number()).collect();

for _ in epoch_start..epoch_end {
let epoch_headers: Vec<ExtHeaderRecord> = ext_headers.drain(0..MAX_EPOCH_SIZE).collect();
let header_records: Vec<HeaderRecord> = epoch_headers.iter().map(Into::into).collect();
let tmp_headers: Vec<Header> = epoch_headers
.into_iter()
.map(ExtHeaderRecord::try_into)
.collect::<Result<_, _>>()?;
headers.extend(tmp_headers);
epoch_accumulators.push(EpochAccumulator::from(header_records));
for header in headers_to_prove {
let block_epoch = (header.number / MAX_EPOCH_SIZE as u64) as usize;
let epoch = epochs
.iter()
.find(|epoch| epoch.number() == block_epoch)
.ok_or(EraValidateError::EpochNotFoundInProvidedList {
block_epoch,
epoch_list: epoch_list.clone(),
})?;
inclusion_proof_vec.push(generate_inclusion_proof(header, epoch.clone())?);
}

for block_idx in start_block..=end_block {
let epoch = block_idx / MAX_EPOCH_SIZE as u64;
let epoch_acc = epoch_accumulators[epoch as usize].clone();
let header = headers[block_idx as usize].clone();
inclusion_proof_vec.push(
PreMergeAccumulator::construct_proof(&header, &epoch_acc)
.map_err(|_| EraValidateError::ProofGenerationFailure)?,
);
Ok(inclusion_proof_vec)
}

pub fn generate_inclusion_proof(
header: Header,
epoch: Epoch,
) -> Result<InclusionProof, EraValidateError> {
let block_epoch = (header.number / MAX_EPOCH_SIZE as u64) as usize;
if block_epoch != epoch.number() {
return Err(EraValidateError::EpochNotMatchForHeader {
epoch_number: epoch.number(),
block_number: header.number,
block_epoch,
});
}

Ok(inclusion_proof_vec)
let epoch_accumulator = EpochAccumulator::from(epoch);

PreMergeAccumulator::construct_proof(&header, &epoch_accumulator)
.map_err(|_| EraValidateError::ProofGenerationFailure)
}

/// verifies an inclusion proof generate by [`generate_inclusion_proof`]
Expand All @@ -75,32 +78,34 @@ pub fn generate_inclusion_proof(
/// * `pre_merge_accumulator_file`- An instance of [`PreMergeAccumulator`] which is a file that maintains a record of historical epoch
/// it is used to verify canonical-ness of headers accumulated from the `blocks`
/// * `inclusion_proof` - The inclusion proof generated from [`generate_inclusion_proof`].
pub fn verify_inclusion_proof(
blocks: Vec<Block>,
pub fn verify_inclusion_proofs(
pre_merge_accumulator_file: Option<PreMergeAccumulator>,
inclusion_proof: Vec<[Hash256; 15]>,
block_proofs: Vec<(Block, InclusionProof)>,
) -> Result<(), EraValidateError> {
let pre_merge_acc = pre_merge_accumulator_file.unwrap_or_default();

let header_validator = HeaderValidator {
pre_merge_acc,
historical_roots_acc: HistoricalRootsAccumulator::default(),
};

for (block_idx, _) in blocks.iter().enumerate() {
let bhp = BlockHeaderProof::PreMergeAccumulatorProof(PreMergeAccumulatorProof {
proof: inclusion_proof[block_idx],
});

let hwp = HeaderWithProof {
header: Header::try_from(&blocks[block_idx])?,
proof: bhp,
};

header_validator
.validate_header_with_proof(&hwp)
.map_err(|_| EraValidateError::ProofValidationFailure)?;
for (block, proof) in block_proofs {
let header = Header::try_from(&block)?;
verify_inclusion_proof(&header_validator, header, proof)?;
}

Ok(())
}

pub fn verify_inclusion_proof(
header_validator: &HeaderValidator,
header: Header,
proof: InclusionProof,
) -> Result<(), EraValidateError> {
let proof = BlockHeaderProof::PreMergeAccumulatorProof(PreMergeAccumulatorProof { proof });

let hwp = HeaderWithProof { header, proof };

header_validator
.validate_header_with_proof(&hwp)
.map_err(|_| EraValidateError::ProofValidationFailure)
}
4 changes: 2 additions & 2 deletions crates/header-accumulator/tests/inclusion_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ fn test_inclusion_proof() -> Result<(), EraValidateError> {

let start_block = 301;
let end_block = 402;
let inclusion_proof =
generate_inclusion_proof(headers, start_block, end_block).unwrap_or_else(|e| {
let inclusion_proof = generate_inclusion_proofs(headers, start_block, end_block)
.unwrap_or_else(|e| {
println!("Error occurred: {}", e);
// Handle the error, e.g., by exiting the program or returning a default value
std::process::exit(1); // Exiting the program, for example
Expand Down

0 comments on commit 560957b

Please sign in to comment.