Merge branch 'release-v7.0.0' into unstable

This commit is contained in:
Mac L
2025-04-11 20:21:40 +10:00
40 changed files with 825 additions and 432 deletions

View File

@@ -28,6 +28,7 @@ metrics = { workspace = true }
network = { workspace = true }
operation_pool = { workspace = true }
parking_lot = { workspace = true }
proto_array = { workspace = true }
rand = { workspace = true }
safe_arith = { workspace = true }
sensitive_url = { workspace = true }

View File

@@ -68,6 +68,7 @@ use serde_json::Value;
use slot_clock::SlotClock;
use ssz::Encode;
pub use state_id::StateId;
use std::collections::HashSet;
use std::future::Future;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::PathBuf;
@@ -86,13 +87,14 @@ use tokio_stream::{
StreamExt,
};
use tracing::{debug, error, info, warn};
use types::AttestationData;
use types::{
fork_versioned_response::EmptyMetadata, Attestation, AttestationData, AttestationShufflingId,
AttesterSlashing, BeaconStateError, ChainSpec, Checkpoint, CommitteeCache, ConfigAndPreset,
Epoch, EthSpec, ForkName, ForkVersionedResponse, Hash256, ProposerPreparationData,
ProposerSlashing, RelativeEpoch, SignedAggregateAndProof, SignedBlindedBeaconBlock,
SignedBlsToExecutionChange, SignedContributionAndProof, SignedValidatorRegistrationData,
SignedVoluntaryExit, Slot, SyncCommitteeMessage, SyncContributionData,
fork_versioned_response::EmptyMetadata, Attestation, AttestationShufflingId, AttesterSlashing,
BeaconStateError, ChainSpec, Checkpoint, CommitteeCache, ConfigAndPreset, Epoch, EthSpec,
ForkName, ForkVersionedResponse, Hash256, ProposerPreparationData, ProposerSlashing,
RelativeEpoch, SignedAggregateAndProof, SignedBlindedBeaconBlock, SignedBlsToExecutionChange,
SignedContributionAndProof, SignedValidatorRegistrationData, SignedVoluntaryExit, Slot,
SyncCommitteeMessage, SyncContributionData,
};
use validator::pubkey_to_validator_index;
use version::{
@@ -1145,6 +1147,39 @@ pub fn serve<T: BeaconChainTypes>(
},
);
// GET beacon/states/{state_id}/pending_consolidations
let get_beacon_state_pending_consolidations = beacon_states_path
.clone()
.and(warp::path("pending_consolidations"))
.and(warp::path::end())
.then(
|state_id: StateId,
task_spawner: TaskSpawner<T::EthSpec>,
chain: Arc<BeaconChain<T>>| {
task_spawner.blocking_json_task(Priority::P1, move || {
let (data, execution_optimistic, finalized) = state_id
.map_state_and_execution_optimistic_and_finalized(
&chain,
|state, execution_optimistic, finalized| {
let Ok(consolidations) = state.pending_consolidations() else {
return Err(warp_utils::reject::custom_bad_request(
"Pending consolidations not found".to_string(),
));
};
Ok((consolidations.clone(), execution_optimistic, finalized))
},
)?;
Ok(api_types::ExecutionOptimisticFinalizedResponse {
data,
execution_optimistic: Some(execution_optimistic),
finalized: Some(finalized),
})
})
},
);
// GET beacon/headers
//
// Note: this endpoint only returns information about blocks in the canonical chain. Given that
@@ -1927,11 +1962,11 @@ pub fn serve<T: BeaconChainTypes>(
chain: Arc<BeaconChain<T>>,
query: api_types::AttestationPoolQuery| {
task_spawner.blocking_response_task(Priority::P1, move || {
let query_filter = |data: &AttestationData| {
let query_filter = |data: &AttestationData, committee_indices: HashSet<u64>| {
query.slot.is_none_or(|slot| slot == data.slot)
&& query
.committee_index
.is_none_or(|index| index == data.index)
.is_none_or(|index| committee_indices.contains(&index))
};
let mut attestations = chain.op_pool.get_filtered_attestations(query_filter);
@@ -1940,7 +1975,9 @@ pub fn serve<T: BeaconChainTypes>(
.naive_aggregation_pool
.read()
.iter()
.filter(|&att| query_filter(att.data()))
.filter(|&att| {
query_filter(att.data(), att.get_committee_indices_map())
})
.cloned(),
);
// Use the current slot to find the fork version, and convert all messages to the
@@ -4737,6 +4774,7 @@ pub fn serve<T: BeaconChainTypes>(
.uor(get_beacon_state_randao)
.uor(get_beacon_state_pending_deposits)
.uor(get_beacon_state_pending_partial_withdrawals)
.uor(get_beacon_state_pending_consolidations)
.uor(get_beacon_headers)
.uor(get_beacon_headers_block_id)
.uor(get_beacon_block)

View File

@@ -4,7 +4,7 @@ use crate::version::{
use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes};
use eth2::types::{
self as api_types, ChainSpec, ForkVersionedResponse, LightClientUpdate,
LightClientUpdateResponseChunk, LightClientUpdateSszResponse, LightClientUpdatesQuery,
LightClientUpdateResponseChunk, LightClientUpdateResponseChunkInner, LightClientUpdatesQuery,
};
use ssz::Encode;
use std::sync::Arc;
@@ -37,15 +37,9 @@ pub fn get_light_client_updates<T: BeaconChainTypes>(
.map(|update| map_light_client_update_to_ssz_chunk::<T>(&chain, update))
.collect::<Vec<LightClientUpdateResponseChunk>>();
let ssz_response = LightClientUpdateSszResponse {
response_chunk_len: (light_client_updates.len() as u64).to_le_bytes().to_vec(),
response_chunk: response_chunks.as_ssz_bytes(),
}
.as_ssz_bytes();
Response::builder()
.status(200)
.body(ssz_response)
.body(response_chunks.as_ssz_bytes())
.map(|res: Response<Vec<u8>>| add_ssz_content_type_header(res))
.map_err(|e| {
warp_utils::reject::custom_server_error(format!(
@@ -159,16 +153,24 @@ fn map_light_client_update_to_ssz_chunk<T: BeaconChainTypes>(
) -> LightClientUpdateResponseChunk {
let fork_name = chain
.spec
.fork_name_at_slot::<T::EthSpec>(*light_client_update.signature_slot());
.fork_name_at_slot::<T::EthSpec>(light_client_update.attested_header_slot());
let fork_digest = ChainSpec::compute_fork_digest(
chain.spec.fork_version_for_name(fork_name),
chain.genesis_validators_root,
);
LightClientUpdateResponseChunk {
let payload = light_client_update.as_ssz_bytes();
let response_chunk_len = fork_digest.len() + payload.len();
let response_chunk = LightClientUpdateResponseChunkInner {
context: fork_digest,
payload: light_client_update.as_ssz_bytes(),
payload,
};
LightClientUpdateResponseChunk {
response_chunk_len: response_chunk_len as u64,
response_chunk,
}
}

View File

@@ -27,6 +27,7 @@ use http_api::{
};
use lighthouse_network::{types::SyncState, Enr, EnrExt, PeerId};
use network::NetworkReceivers;
use operation_pool::attestation_storage::CheckpointKey;
use proto_array::ExecutionStatus;
use sensitive_url::SensitiveUrl;
use slot_clock::SlotClock;
@@ -1241,6 +1242,33 @@ impl ApiTester {
self
}
pub async fn test_beacon_states_pending_consolidations(self) -> Self {
for state_id in self.interesting_state_ids() {
let mut state_opt = state_id
.state(&self.chain)
.ok()
.map(|(state, _execution_optimistic, _finalized)| state);
let result = self
.client
.get_beacon_states_pending_consolidations(state_id.0)
.await
.unwrap()
.map(|res| res.data);
if result.is_none() && state_opt.is_none() {
continue;
}
let state = state_opt.as_mut().expect("result should be none");
let expected = state.pending_consolidations().unwrap();
assert_eq!(result.unwrap(), expected.to_vec());
}
self
}
pub async fn test_beacon_headers_all_slots(self) -> Self {
for slot in 0..CHAIN_LENGTH {
let slot = Slot::from(slot);
@@ -2087,7 +2115,7 @@ impl ApiTester {
self
}
pub async fn test_get_beacon_pool_attestations(self) -> Self {
pub async fn test_get_beacon_pool_attestations(self) {
let result = self
.client
.get_beacon_pool_attestations_v1(None, None)
@@ -2106,9 +2134,80 @@ impl ApiTester {
.await
.unwrap()
.data;
assert_eq!(result, expected);
self
let result_committee_index_filtered = self
.client
.get_beacon_pool_attestations_v1(None, Some(0))
.await
.unwrap()
.data;
let expected_committee_index_filtered = expected
.clone()
.into_iter()
.filter(|att| att.get_committee_indices_map().contains(&0))
.collect::<Vec<_>>();
assert_eq!(
result_committee_index_filtered,
expected_committee_index_filtered
);
let result_committee_index_filtered = self
.client
.get_beacon_pool_attestations_v1(None, Some(1))
.await
.unwrap()
.data;
let expected_committee_index_filtered = expected
.clone()
.into_iter()
.filter(|att| att.get_committee_indices_map().contains(&1))
.collect::<Vec<_>>();
assert_eq!(
result_committee_index_filtered,
expected_committee_index_filtered
);
let fork_name = self
.harness
.chain
.spec
.fork_name_at_slot::<E>(self.harness.chain.slot().unwrap());
// aggregate electra attestations
if fork_name.electra_enabled() {
// Take and drop the lock in a block to avoid clippy complaining
// about taking locks across await points
{
let mut all_attestations = self.chain.op_pool.attestations.write();
let (prev_epoch_key, curr_epoch_key) =
CheckpointKey::keys_for_state(&self.harness.get_current_state());
all_attestations.aggregate_across_committees(prev_epoch_key);
all_attestations.aggregate_across_committees(curr_epoch_key);
}
let result_committee_index_filtered = self
.client
.get_beacon_pool_attestations_v2(None, Some(0))
.await
.unwrap()
.data;
let mut expected = self.chain.op_pool.get_all_attestations();
expected.extend(self.chain.naive_aggregation_pool.read().iter().cloned());
let expected_committee_index_filtered = expected
.clone()
.into_iter()
.filter(|att| att.get_committee_indices_map().contains(&0))
.collect::<Vec<_>>();
assert_eq!(
result_committee_index_filtered,
expected_committee_index_filtered
);
}
}
pub async fn test_post_beacon_pool_attester_slashings_valid_v1(mut self) -> Self {
@@ -6386,6 +6485,8 @@ async fn beacon_get_state_info_electra() {
.test_beacon_states_pending_deposits()
.await
.test_beacon_states_pending_partial_withdrawals()
.await
.test_beacon_states_pending_consolidations()
.await;
}
@@ -6416,10 +6517,30 @@ async fn beacon_get_blocks() {
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn beacon_get_pools() {
async fn test_beacon_pool_attestations_electra() {
let mut config = ApiTesterConfig::default();
config.spec.altair_fork_epoch = Some(Epoch::new(0));
config.spec.bellatrix_fork_epoch = Some(Epoch::new(0));
config.spec.capella_fork_epoch = Some(Epoch::new(0));
config.spec.deneb_fork_epoch = Some(Epoch::new(0));
config.spec.electra_fork_epoch = Some(Epoch::new(0));
ApiTester::new_from_config(config)
.await
.test_get_beacon_pool_attestations()
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_beacon_pool_attestations_base() {
ApiTester::new()
.await
.test_get_beacon_pool_attestations()
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn beacon_get_pools() {
ApiTester::new()
.await
.test_get_beacon_pool_attester_slashings()
.await