mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-29 20:27:14 +00:00
Ensure /eth/v2/beacon/pool/attestations honors committee_index (#7298)
#7294 Fix the filtering logic so that we actually filter by committee index for both `Base` and `Electra` attestations. Added a tiny optimization when calculating committee_index to prevent unneeded memory allocations Added a regression test
This commit is contained in:
@@ -68,6 +68,7 @@ use slog::{crit, debug, error, info, warn, Logger};
|
||||
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;
|
||||
@@ -85,13 +86,14 @@ use tokio_stream::{
|
||||
wrappers::{errors::BroadcastStreamRecvError, BroadcastStream},
|
||||
StreamExt,
|
||||
};
|
||||
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::{
|
||||
@@ -2032,11 +2034,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);
|
||||
@@ -2045,7 +2047,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
|
||||
|
||||
@@ -28,6 +28,7 @@ use http_api::{
|
||||
use lighthouse_network::{types::SyncState, Enr, EnrExt, PeerId};
|
||||
use logging::test_logger;
|
||||
use network::NetworkReceivers;
|
||||
use operation_pool::attestation_storage::CheckpointKey;
|
||||
use proto_array::ExecutionStatus;
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use slot_clock::SlotClock;
|
||||
@@ -2119,7 +2120,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)
|
||||
@@ -2138,9 +2139,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 {
|
||||
@@ -6463,10 +6535,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
|
||||
|
||||
Reference in New Issue
Block a user