Skip to content

Commit

Permalink
Lookahead fault proof - waiting for slot, handling different lists si…
Browse files Browse the repository at this point in the history
…zes (#106)

* lookahead pointer for fault proof

* Wait for the proper slot to  post a fault lookahead proof

* fixed checking different lists size
  • Loading branch information
mskrzypkows authored Sep 9, 2024
1 parent 43ea115 commit 8d55995
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 31 deletions.
5 changes: 5 additions & 0 deletions Node/src/ethereum_l1/slot_clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ impl SlotClock {
}
}

pub fn duration_to_slot_from_now(&self, slot: Slot) -> Result<Duration, Error> {
let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
self.duration_to_slot(slot, now)
}

pub fn slot_of(&self, now: Duration) -> Result<Slot, Error> {
let genesis = self.genesis_duration;

Expand Down
150 changes: 119 additions & 31 deletions Node/src/node/lookahead_updated_receiver.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use crate::ethereum_l1::{execution_layer::PreconfTaskManager, merkle_proofs::*, EthereumL1};
use crate::{
ethereum_l1::{execution_layer::PreconfTaskManager, merkle_proofs::*, EthereumL1},
utils::types::*,
};
use anyhow::Error;
use beacon_api_client::ProposerDuty;
use futures_util::StreamExt;
use std::{sync::Arc, time::Duration};
use tracing::{debug, error, info, warn};
use tracing::{debug, error, info};

type LookaheadUpdated = Vec<PreconfTaskManager::LookaheadSetParam>;

Expand Down Expand Up @@ -47,9 +50,8 @@ impl LookaheadUpdatedEventReceiver {
"Received lookahead updated event with {} params.",
lookahead_params.len()
);
if let Err(e) = self.check_lookahead_correctness(&lookahead_params).await {
error!("Error checking lookahead correctness: {:?}", e);
}
let handler = LookaheadUpdatedEventHandler::new(self.ethereum_l1.clone());
handler.handle_lookahead_updated_event(lookahead_params);
}
Err(e) => {
error!("Error receiving lookahead updated event: {:?}", e);
Expand All @@ -63,13 +65,32 @@ impl LookaheadUpdatedEventReceiver {
}
}
}
}

pub struct LookaheadUpdatedEventHandler {
ethereum_l1: Arc<EthereumL1>,
}

impl LookaheadUpdatedEventHandler {
pub fn new(ethereum_l1: Arc<EthereumL1>) -> Self {
Self { ethereum_l1 }
}

pub fn handle_lookahead_updated_event(
self,
lookahead_params: Vec<PreconfTaskManager::LookaheadSetParam>,
) {
tokio::spawn(async move {
if let Err(e) = self.check_lookahead_correctness(lookahead_params).await {
error!("Error checking lookahead correctness: {:?}", e);
}
});
}

async fn check_lookahead_correctness(
&self,
lookahead_updated_next_epoch: &LookaheadUpdated,
lookahead_updated_next_epoch: LookaheadUpdated,
) -> Result<(), Error> {
// TODO: wait for the epoch to start

let epoch = self
.ethereum_l1
.slot_clock
Expand All @@ -90,40 +111,94 @@ impl LookaheadUpdatedEventReceiver {
.get_lookahead_params_for_epoch_using_cl_lookahead(epoch_begin_timestamp, &epoch_duties)
.await?;

for (i, (param, updated_param)) in epoch_lookahead_params
if let Some(slot_timestamp) = Self::find_a_slot_timestamp_to_prove_incorrect_lookahead(
&epoch_lookahead_params,
&lookahead_updated_next_epoch,
)? {
let slot = self
.ethereum_l1
.slot_clock
.slot_of(Duration::from_secs(slot_timestamp))?;
let corresponding_epoch_slot_index =
(slot % self.ethereum_l1.slot_clock.get_slots_per_epoch()) as usize;
self.wait_for_the_slot_to_prove_incorrect_lookahead(slot + 1)
.await?;
self.prove_incorrect_lookahead(
slot,
slot_timestamp,
&epoch_duties[corresponding_epoch_slot_index],
)
.await?;
}

Ok(())
}

fn find_a_slot_timestamp_to_prove_incorrect_lookahead(
lookahead_params: &[PreconfTaskManager::LookaheadSetParam],
lookahead_updated_event_params: &[PreconfTaskManager::LookaheadSetParam],
) -> Result<Option<u64>, Error> {
// compare corresponding params in the two lists
for (param, updated_param) in lookahead_params
.iter()
.zip(lookahead_updated_next_epoch.iter())
.enumerate()
.zip(lookahead_updated_event_params.iter())
{
if param.preconfer != updated_param.preconfer {
if param.timestamp != updated_param.timestamp {
warn!("Lookahead timestamp mismatch at index {i}: param.timestamp: {}, updated_param.timestamp: {}", param.timestamp, updated_param.timestamp);
continue;
}

self.prove_incorrect_lookahead(param.timestamp.try_into()?, &epoch_duties[i])
.await?;
if param.preconfer != updated_param.preconfer
|| param.timestamp != updated_param.timestamp
{
return Ok(Some(updated_param.timestamp.try_into()?));
}
}

if lookahead_params.len() > lookahead_updated_event_params.len() {
// the lookahead updated doesn't contain enough params
let first_proper_lookahead_params_missing_in_the_event =
&lookahead_params[lookahead_updated_event_params.len()];
return Ok(Some(
first_proper_lookahead_params_missing_in_the_event
.timestamp
.try_into()?,
));
} else if lookahead_params.len() < lookahead_updated_event_params.len() {
// the lookahead updated contains additional, wrong params
let first_additional_wrong_param =
&lookahead_updated_event_params[lookahead_params.len()];
return Ok(Some(first_additional_wrong_param.timestamp.try_into()?));
}

return Ok(None);
}

async fn wait_for_the_slot_to_prove_incorrect_lookahead(
&self,
slot: Slot,
) -> Result<(), Error> {
tokio::time::sleep(
self.ethereum_l1
.slot_clock
.duration_to_slot_from_now(slot)?,
)
.await;
Ok(())
}

async fn prove_incorrect_lookahead(
&self,
slot: Slot,
slot_timestamp: u64,
epoch_duty: &ProposerDuty,
) -> Result<(), Error> {
let slot = self
.ethereum_l1
.slot_clock
.slot_of(Duration::from_secs(slot_timestamp))?;
info!("Lookahead mismatch found for slot: {}", slot);

let next_slot = slot + 1;

let lookahead_pointer = self.find_lookahead_pointer(slot_timestamp).await?;

let pub_key = &epoch_duty.public_key;
let beacon_state = self
.ethereum_l1
.consensus_layer
.get_beacon_state(slot)
.get_beacon_state(next_slot)
.await?;
let validators = beacon_state.validators();
let validator_index = validators
Expand All @@ -141,18 +216,13 @@ impl LookaheadUpdatedEventReceiver {
validator_index,
)?;

let beacon_state = self
.ethereum_l1
.consensus_layer
.get_beacon_state(slot)
.await?;
let (beacon_state_proof, beacon_state_root) =
create_merkle_proof_for_validator_list_being_part_of_beacon_state(&beacon_state)?;

let beacon_block = self
.ethereum_l1
.consensus_layer
.get_beacon_block(slot)
.get_beacon_block(next_slot)
.await?;
let (beacon_block_proof_for_state, beacon_block_proof_for_proposer_index) =
create_merkle_proofs_for_beacon_block_containing_beacon_state_and_validator_index(
Expand All @@ -162,7 +232,7 @@ impl LookaheadUpdatedEventReceiver {
self.ethereum_l1
.execution_layer
.prove_incorrect_lookahead(
0, //TODO: pass lookahead pointer
lookahead_pointer,
slot_timestamp,
pub_key.as_ref().try_into()?,
&ssz_encoded_validator,
Expand All @@ -177,4 +247,22 @@ impl LookaheadUpdatedEventReceiver {
)
.await
}

async fn find_lookahead_pointer(&self, slot_timestamp: u64) -> Result<u64, Error> {
let lookahead_preconfer_buffer = self
.ethereum_l1
.execution_layer
.get_lookahead_preconfer_buffer()
.await?;

lookahead_preconfer_buffer
.iter()
.position(|entry| {
slot_timestamp > entry.prevTimestamp && slot_timestamp <= entry.timestamp
})
.ok_or(anyhow::anyhow!(
"find_lookahead_pointer: Lookahead pointer not found"
))
.map(|i| i as u64)
}
}

0 comments on commit 8d55995

Please sign in to comment.