Skip to content

Commit

Permalink
lookahead fault proof (#104)
Browse files Browse the repository at this point in the history
* EL functions to get lookahead event

* lookahead update receiver

* fixed consuming self in lookahead receiver

* lookahead updated event received in Node module

* new_epoch_started method

* proof lookahead preparation in the receiver

* get validator function for the inclusion proof

* validator serialized with ssz

* Merkle proof for validator being part of validators list

* phase0 -> deneb

* beacon state proof

* beacon block including beacon state and validator index

* Removed validator object, using ssz-rs serialization

* call of proveIncorrectLookahead contract

* Changed manually ssz serialization and merkle proof to implementation from ssz_rs
  • Loading branch information
mskrzypkows authored Sep 5, 2024
1 parent 9aee552 commit 43ea115
Show file tree
Hide file tree
Showing 14 changed files with 621 additions and 48 deletions.
2 changes: 2 additions & 0 deletions Node/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ hex = "0.4"
tiny-keccak = "2.0"
secp256k1 = "0.29"
beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus", package = "beacon-api-client" }
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", package = "ethereum-consensus" }
ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "84ef2b71aa004f6767420badb42c902ad56b8b72" }
dotenv = "0.15"
rand_core = "0.6"
chrono = "0.4"
Expand Down
26 changes: 25 additions & 1 deletion Node/src/ethereum_l1/consensus_layer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#![allow(dead_code)] // TODO: remove
use crate::utils::types::*;
use anyhow::Error;
use beacon_api_client::{mainnet::MainnetClientTypes, Client, GenesisDetails, ProposerDuty};
use beacon_api_client::{
mainnet::MainnetClientTypes, BlockId, Client, GenesisDetails, ProposerDuty, StateId,
};
use ethereum_consensus::types::mainnet::{BeaconState, SignedBeaconBlock};
use reqwest;

pub struct ConsensusLayer {
Expand All @@ -22,6 +26,26 @@ impl ConsensusLayer {
pub async fn get_genesis_details(&self) -> Result<GenesisDetails, Error> {
self.client.get_genesis_details().await.map_err(Error::new)
}

pub async fn get_beacon_state(&self, slot: Slot) -> Result<BeaconState, Error> {
let beacon_state = self
.client
.get_state(StateId::Slot(slot))
.await
.map_err(Error::new)?;

Ok(beacon_state)
}

pub async fn get_beacon_block(&self, slot: Slot) -> Result<SignedBeaconBlock, Error> {
let beacon_block = self
.client
.get_beacon_block(BlockId::Slot(slot))
.await
.map_err(Error::new)?;

Ok(beacon_block)
}
}

#[cfg(test)]
Expand Down
128 changes: 127 additions & 1 deletion Node/src/ethereum_l1/execution_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ sol!(
"src/ethereum_l1/abi/PreconfRegistry.json"
);

pub struct EventPollerLookaheadUpdated(
pub EventPoller<
alloy::transports::http::Http<reqwest::Client>,
PreconfTaskManager::LookaheadUpdated,
>,
);

impl ExecutionLayer {
pub async fn new(
rpc_url: &str,
Expand Down Expand Up @@ -362,7 +369,68 @@ impl ExecutionLayer {
Ok(())
}

pub async fn watch_for_registered_event(
pub async fn prove_incorrect_lookahead(
&self,
lookahead_pointer: u64,
slot_timestamp: u64,
validator_bls_pub_key: BLSCompressedPublicKey,
validator: &Vec<u8>,
validator_index: usize,
validator_proof: Vec<[u8; 32]>,
validators_root: [u8; 32],
nr_validators: u64,
beacon_state_proof: Vec<[u8; 32]>,
beacon_state_root: [u8; 32],
beacon_block_proof_for_state: Vec<[u8; 32]>,
beacon_block_proof_for_proposer_index: Vec<[u8; 32]>,
) -> Result<(), Error> {
let provider = self.create_provider();

let contract =
PreconfTaskManager::new(self.contract_addresses.avs.preconf_task_manager, provider);

let mut validator_chunks: [B256; 8] = Default::default();
for (i, chunk) in validator.chunks(32).enumerate() {
validator_chunks[i] = B256::from_slice(chunk);
}
let validator_index = U256::from(validator_index);

let validator_inclusion_proof = PreconfTaskManager::InclusionProof {
validator: validator_chunks,
validatorIndex: validator_index,
validatorProof: Self::convert_proof_to_fixed_bytes(validator_proof),
validatorsRoot: FixedBytes::from(validators_root),
nr_validators: U256::from(nr_validators),
beaconStateProof: Self::convert_proof_to_fixed_bytes(beacon_state_proof),
beaconStateRoot: FixedBytes::from(beacon_state_root),
beaconBlockProofForState: Self::convert_proof_to_fixed_bytes(
beacon_block_proof_for_state,
),
beaconBlockProofForProposerIndex: Self::convert_proof_to_fixed_bytes(
beacon_block_proof_for_proposer_index,
),
};
let tx_hash = contract
.proveIncorrectLookahead(
U256::from(lookahead_pointer),
U256::from(slot_timestamp),
Bytes::from(validator_bls_pub_key),
validator_inclusion_proof,
)
.send()
.await?
.watch()
.await?;
tracing::debug!("Proved incorrect lookahead: {tx_hash}");

Ok(())
}

fn convert_proof_to_fixed_bytes(proof: Vec<[u8; 32]>) -> Vec<FixedBytes<32>> {
proof.iter().map(|p| FixedBytes::from(p)).collect()
}

pub async fn subscribe_to_registered_event(
&self,
) -> Result<
EventPoller<
Expand Down Expand Up @@ -406,6 +474,19 @@ impl ExecutionLayer {
Ok(())
}

pub async fn subscribe_to_lookahead_updated_event(
&self,
) -> Result<EventPollerLookaheadUpdated, Error> {
let provider = self.create_provider();
let task_manager =
PreconfTaskManager::new(self.contract_addresses.avs.preconf_task_manager, provider);

let lookahead_updated_filter = task_manager.LookaheadUpdated_filter().watch().await?;
tracing::debug!("Subscribed to lookahead updated event");

Ok(EventPollerLookaheadUpdated(lookahead_updated_filter))
}

pub async fn get_lookahead_params_for_epoch_using_cl_lookahead(
&self,
epoch_begin_timestamp: u64,
Expand Down Expand Up @@ -653,4 +734,49 @@ mod tests {
// "Lookahead params should not be empty"
// );
}

#[tokio::test]
async fn test_prove_incorrect_lookahead() {
let anvil = Anvil::new().try_spawn().unwrap();
let rpc_url: reqwest::Url = anvil.endpoint().parse().unwrap();
let private_key = anvil.keys()[0].clone();
let el = ExecutionLayer::new_from_pk(rpc_url, private_key)
.await
.unwrap();

// Test parameters
let lookahead_pointer = 100;
let slot_timestamp = 1000;
let validator_bls_pub_key = [1u8; 48];
let validator = vec![2u8; 256];
let validator_index = 0;
let validator_proof = vec![[3u8; 32]; 5];
let validators_root = [4u8; 32];
let nr_validators = 1000;
let beacon_state_proof = vec![[5u8; 32]; 5];
let beacon_state_root = [6u8; 32];
let beacon_block_proof_for_state = vec![[7u8; 32]; 5];
let beacon_block_proof_for_proposer_index = vec![[8u8; 32]; 5];

// Call the method
let result = el
.prove_incorrect_lookahead(
lookahead_pointer,
slot_timestamp,
validator_bls_pub_key,
&validator,
validator_index,
validator_proof,
validators_root,
nr_validators,
beacon_state_proof,
beacon_state_root,
beacon_block_proof_for_state,
beacon_block_proof_for_proposer_index,
)
.await;

// Assert the result
assert!(result.is_ok(), "prove_incorrect_lookahead should succeed");
}
}
Loading

0 comments on commit 43ea115

Please sign in to comment.