Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.lock

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

22 changes: 22 additions & 0 deletions crates/common/checkpoint_sync/lean/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ repository.workspace = true
rust-version.workspace = true
version.workspace = true

[features]
default = ["devnet1"]
devnet1 = []
devnet2 = [
"ream-consensus-lean/devnet2",
"ream-fork-choice-lean/devnet2",
"ream-rpc-lean/devnet2",
]

[dependencies]
alloy-primitives.workspace = true
anyhow.workspace = true
Expand All @@ -21,5 +30,18 @@ tree_hash.workspace = true
# ream dependencies
ream-consensus-lean.workspace = true

[dev-dependencies]
actix-web.workspace = true
ssz_types.workspace = true
tokio.workspace = true

# ream dependencies (tests)
ream-fork-choice-lean.workspace = true
ream-network-spec.workspace = true
ream-post-quantum-crypto.workspace = true
ream-rpc-lean.workspace = true
ream-storage.workspace = true
ream-sync.workspace = true

[lints]
workspace = true
115 changes: 111 additions & 4 deletions crates/common/checkpoint_sync/lean/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,120 @@ impl LeanCheckpointClient {
}

pub fn verify_checkpoint_state(state: &LeanState) -> bool {
if state.slot == 0 {
return false;
}

if state.validators.is_empty() {
return false;
}

true
}

#[cfg(all(test, feature = "devnet2"))]
mod tests {
use std::net::TcpListener;

use actix_web::{
App, HttpServer,
web::{Data, scope},
};
use ream_consensus_lean::{
attestation::{AggregatedAttestations, AttestationData},
block::{BlockSignatures, BlockWithAttestation, SignedBlockWithAttestation},
checkpoint::Checkpoint,
utils::generate_default_validators,
};
use ream_fork_choice_lean::{genesis::setup_genesis, store::Store};
use ream_network_spec::networks::{LeanNetworkSpec, lean_network_spec, set_lean_network_spec};
use ream_post_quantum_crypto::leansig::signature::Signature;
use ream_rpc_lean::handlers::state::get_state;
use ream_storage::db::ReamDB;
use ream_sync::rwlock::Writer;
use reqwest::Url;
use ssz_types::VariableList;
use tree_hash::TreeHash;

use super::{LeanCheckpointClient, verify_checkpoint_state};

async fn sample_store(no_of_validators: usize) -> Store {
set_lean_network_spec(LeanNetworkSpec::ephemery().into());
let (genesis_block, genesis_state) = setup_genesis(
lean_network_spec().genesis_time,
generate_default_validators(no_of_validators),
);

let checkpoint = Checkpoint {
slot: genesis_block.slot,
root: genesis_block.tree_hash_root(),
};
let signed_genesis_block = SignedBlockWithAttestation {
message: BlockWithAttestation {
proposer_attestation: AggregatedAttestations {
validator_id: genesis_block.proposer_index,
data: AttestationData {
slot: genesis_block.slot,
head: checkpoint,
target: checkpoint,
source: checkpoint,
},
},
block: genesis_block,
},
signature: BlockSignatures {
attestation_signatures: VariableList::default(),
proposer_signature: Signature::blank(),
},
};

let temp_path = std::env::temp_dir().join(format!(
"checkpoint_sync_lean_test_{}_{:?}",
std::process::id(),
std::thread::current().id()
));
std::fs::create_dir_all(&temp_path).expect("Failed to create temp directory");
let ream_db = ReamDB::new(temp_path).expect("Failed to init Ream Database");
let lean_db = ream_db.init_lean_db().expect("Failed to init lean db");

Store::get_forkchoice_store(signed_genesis_block, genesis_state, lean_db, Some(0))
.expect("Failed to create forkchoice store")
}

#[tokio::test]
async fn test_client_fetches_and_deserializes_state() {
let store = sample_store(10).await;
let (_writer, reader) = Writer::new(store);

let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind random port");
let addr = listener.local_addr().expect("Failed to get local addr");

let server = HttpServer::new(move || {
App::new()
.app_data(Data::new(reader.clone()))
.service(scope("/lean/v0").service(get_state))
})
.listen(listener)
.expect("Failed to attach listener")
.run();

let server_handle = server.handle();
tokio::spawn(server);

let client = LeanCheckpointClient::new();
let base_url = Url::parse(&format!("http://{addr}")).expect("Failed to parse base URL");

let state = client
.fetch_finalized_state(&base_url)
.await
.expect("Client failed to fetch finalized state");

assert_eq!(state.slot, 0);
assert!(verify_checkpoint_state(&state));

let (_, genesis_state) = setup_genesis(
lean_network_spec().genesis_time,
generate_default_validators(10),
);

assert_eq!(state, genesis_state);

server_handle.stop(true).await;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl SignedBeaconBlock {
kzg_commitment_inclusion_proof: self
.message
.body
.blob_kzg_commitment_inclusion_proof(index)?
.blob_kzg_commitment_inclusion_proof()?
.try_into().map_err(|err| anyhow!("Failed to convert blob_kzg_commitment_inclusion_proof to FixedVector: {err:?}"))?,
})
}
Expand Down
34 changes: 2 additions & 32 deletions crates/common/consensus/beacon/src/electra/beacon_block_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use ream_bls::BLSSignature;
use ream_consensus_misc::{
constants::beacon::{
BLOB_KZG_COMMITMENTS_INDEX, BLOCK_BODY_MERKLE_DEPTH, EXECUTION_PAYLOAD_INDEX,
KZG_COMMITMENTS_MERKLE_DEPTH,
},
deposit::Deposit,
eth_1_data::Eth1Data,
Expand Down Expand Up @@ -78,37 +77,8 @@ impl BeaconBlockBody {
generate_proof(&tree, index, BLOCK_BODY_MERKLE_DEPTH)
}

pub fn blob_kzg_commitment_inclusion_proof(&self, index: u64) -> anyhow::Result<Vec<B256>> {
// inclusion proof for blob_kzg_commitment in blob_kzg_commitments
let tree = merkle_tree(
self.blob_kzg_commitments
.iter()
.map(|commitment| commitment.tree_hash_root())
.collect::<Vec<_>>()
.as_slice(),
KZG_COMMITMENTS_MERKLE_DEPTH,
)?;
let kzg_commitment_to_kzg_commitments_proof =
generate_proof(&tree, index, KZG_COMMITMENTS_MERKLE_DEPTH)?;

// add branch for length of blob_kzg_commitments
let kzg_commitments_length_root = self
.blob_kzg_commitments
.len()
.to_le_bytes()
.tree_hash_root();

// inclusion proof for blob_kzg_commitments in beacon_block_body
let kzg_commitments_to_block_body_proof =
self.data_inclusion_proof(BLOB_KZG_COMMITMENTS_INDEX)?;

// merge proofs data
Ok([
kzg_commitment_to_kzg_commitments_proof,
vec![kzg_commitments_length_root],
kzg_commitments_to_block_body_proof,
]
.concat())
pub fn blob_kzg_commitment_inclusion_proof(&self) -> anyhow::Result<Vec<B256>> {
self.data_inclusion_proof(BLOB_KZG_COMMITMENTS_INDEX)
}

pub fn execution_payload_inclusion_proof(&self) -> anyhow::Result<Vec<B256>> {
Expand Down
Loading