Files
lighthouse/beacon_node/beacon_chain/tests/column_verification.rs
Jimmy Chen 43c5e924d7 Add --semi-supernode support (#8254)
Addresses #8218

A simplified version of #8241 for the initial release.

I've tried to minimise the logic change in this PR, although introducing the `NodeCustodyType` enum still result in quite a bit a of diff, but the actual logic change in `CustodyContext` is quite small.

The main changes are in the `CustdoyContext` struct
* ~~combining `validator_custody_count` and `current_is_supernode` fields into a single `custody_group_count_at_head` field. We persist the cgc of the initial cli values into the `custody_group_count_at_head` field and only allow for increase (same behaviour as before).~~
* I noticed the above approach caused a backward compatibility issue, I've [made a fix](15569bc085) and changed the approach slightly (which was actually what I had originally in mind):
* when initialising, only override the  `validator_custody_count` value if either flag `--supernode` or `--semi-supernode` is used; otherwise leave it as the existing default `0`. Most other logic remains unchanged.

All existing validator custody unit tests are still all passing, and I've added additional tests to cover semi-supernode, and restoring `CustodyContext` from disk.

Note: I've added a `WARN` if the user attempts to switch to a `--semi-supernode` or `--supernode` - this currently has no effect, but once @eserilev column backfill is merged, we should be able to support this quite easily.

Things to test
- [x] cgc in metadata / enr
- [x] cgc in metrics
- [x] subscribed subnets
- [x] getBlobs endpoint


  


Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>
2025-10-22 05:23:17 +00:00

118 lines
3.5 KiB
Rust

#![cfg(not(debug_assertions))]
use beacon_chain::custody_context::NodeCustodyType;
use beacon_chain::test_utils::{
AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType,
generate_data_column_sidecars_from_block, test_spec,
};
use beacon_chain::{
AvailabilityProcessingStatus, BlockError, ChainConfig, InvalidSignature, NotifyExecutionLayer,
block_verification_types::AsBlock,
};
use logging::create_test_tracing_subscriber;
use std::sync::{Arc, LazyLock};
use types::*;
type E = MainnetEthSpec;
// Should ideally be divisible by 3.
const VALIDATOR_COUNT: usize = 24;
/// A cached set of keys.
static KEYPAIRS: LazyLock<Vec<Keypair>> =
LazyLock::new(|| types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT));
fn get_harness(
validator_count: usize,
spec: Arc<ChainSpec>,
node_custody_type: NodeCustodyType,
) -> BeaconChainHarness<EphemeralHarnessType<E>> {
create_test_tracing_subscriber();
let harness = BeaconChainHarness::builder(MainnetEthSpec)
.spec(spec)
.chain_config(ChainConfig {
reconstruct_historic_states: true,
..ChainConfig::default()
})
.keypairs(KEYPAIRS[0..validator_count].to_vec())
.node_custody_type(node_custody_type)
.fresh_ephemeral_store()
.mock_execution_layer()
.build();
harness.advance_slot();
harness
}
// Regression test for https://github.com/sigp/lighthouse/issues/7650
#[tokio::test]
async fn rpc_columns_with_invalid_header_signature() {
let spec = Arc::new(test_spec::<E>());
// Only run this test if columns are enabled.
if !spec.is_fulu_scheduled() {
return;
}
let harness = get_harness(VALIDATOR_COUNT, spec, NodeCustodyType::Supernode);
let num_blocks = E::slots_per_epoch() as usize;
// Add some chain depth.
harness
.extend_chain(
num_blocks,
BlockStrategy::OnCanonicalHead,
AttestationStrategy::AllValidators,
)
.await;
// Produce a block with blobs.
harness.execution_block_generator().set_min_blob_count(1);
let head_state = harness.get_current_state();
let slot = head_state.slot() + 1;
let ((signed_block, opt_blobs), _) = harness.make_block(head_state, slot).await;
let (_, blobs) = opt_blobs.unwrap();
assert!(!blobs.is_empty());
let block_root = signed_block.canonical_root();
// Process the block without blobs so that it doesn't become available.
harness.advance_slot();
let rpc_block = harness
.build_rpc_block_from_blobs(block_root, signed_block.clone(), None)
.unwrap();
let availability = harness
.chain
.process_block(
block_root,
rpc_block,
NotifyExecutionLayer::Yes,
BlockImportSource::RangeSync,
|| Ok(()),
)
.await
.unwrap();
assert_eq!(
availability,
AvailabilityProcessingStatus::MissingComponents(slot, block_root)
);
// Build blob sidecars with invalid signatures in the block header.
let mut corrupt_block = (*signed_block).clone();
*corrupt_block.signature_mut() = Signature::infinity().unwrap();
let data_column_sidecars =
generate_data_column_sidecars_from_block(&corrupt_block, &harness.chain.spec);
let err = harness
.chain
.process_rpc_custody_columns(data_column_sidecars)
.await
.unwrap_err();
assert!(matches!(
err,
BlockError::InvalidSignature(InvalidSignature::ProposerSignature)
));
}