mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 00:31:50 +00:00
Merge branch 'unstable' into merge-unstable-to-deneb-20230808
# Conflicts: # Cargo.lock # beacon_node/beacon_chain/src/lib.rs # beacon_node/execution_layer/src/engine_api.rs # beacon_node/execution_layer/src/engine_api/http.rs # beacon_node/execution_layer/src/test_utils/mod.rs # beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs # beacon_node/lighthouse_network/src/rpc/handler.rs # beacon_node/lighthouse_network/src/rpc/protocol.rs # beacon_node/lighthouse_network/src/service/utils.rs # beacon_node/lighthouse_network/tests/rpc_tests.rs # beacon_node/network/Cargo.toml # beacon_node/network/src/network_beacon_processor/tests.rs # lcli/src/parse_ssz.rs # scripts/cross/Dockerfile # validator_client/src/block_service.rs # validator_client/src/validator_store.rs
This commit is contained in:
@@ -182,6 +182,48 @@ pub async fn gossip_full_pass() {
|
||||
.block_is_known_to_fork_choice(&block.canonical_root()));
|
||||
}
|
||||
|
||||
// This test checks that a block that is valid from both a gossip and consensus perspective is accepted when using `broadcast_validation=gossip`.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn gossip_full_pass_ssz() {
|
||||
/* this test targets gossip-level validation */
|
||||
let validation_level: Option<BroadcastValidation> = Some(BroadcastValidation::Gossip);
|
||||
|
||||
// Validator count needs to be at least 32 or proposer boost gets set to 0 when computing
|
||||
// `validator_count // 32`.
|
||||
let validator_count = 64;
|
||||
let num_initial: u64 = 31;
|
||||
let tester = InteractiveTester::<E>::new(None, validator_count).await;
|
||||
|
||||
// Create some chain depth.
|
||||
tester.harness.advance_slot();
|
||||
tester
|
||||
.harness
|
||||
.extend_chain(
|
||||
num_initial as usize,
|
||||
BlockStrategy::OnCanonicalHead,
|
||||
AttestationStrategy::AllValidators,
|
||||
)
|
||||
.await;
|
||||
tester.harness.advance_slot();
|
||||
|
||||
let slot_a = Slot::new(num_initial);
|
||||
let slot_b = slot_a + 1;
|
||||
|
||||
let state_a = tester.harness.get_current_state();
|
||||
let (block, _): (SignedBeaconBlock<E>, _) = tester.harness.make_block(state_a, slot_b).await;
|
||||
|
||||
let response: Result<(), eth2::Error> = tester
|
||||
.client
|
||||
.post_beacon_blocks_v2_ssz(&block, validation_level)
|
||||
.await;
|
||||
|
||||
assert!(response.is_ok());
|
||||
assert!(tester
|
||||
.harness
|
||||
.chain
|
||||
.block_is_known_to_fork_choice(&block.canonical_root()));
|
||||
}
|
||||
|
||||
/// This test checks that a block that is **invalid** from a gossip perspective gets rejected when using `broadcast_validation=consensus`.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn consensus_invalid() {
|
||||
@@ -836,6 +878,49 @@ pub async fn blinded_gossip_full_pass() {
|
||||
.block_is_known_to_fork_choice(&block.canonical_root()));
|
||||
}
|
||||
|
||||
// This test checks that a block that is valid from both a gossip and consensus perspective is accepted when using `broadcast_validation=gossip`.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn blinded_gossip_full_pass_ssz() {
|
||||
/* this test targets gossip-level validation */
|
||||
let validation_level: Option<BroadcastValidation> = Some(BroadcastValidation::Gossip);
|
||||
|
||||
// Validator count needs to be at least 32 or proposer boost gets set to 0 when computing
|
||||
// `validator_count // 32`.
|
||||
let validator_count = 64;
|
||||
let num_initial: u64 = 31;
|
||||
let tester = InteractiveTester::<E>::new(None, validator_count).await;
|
||||
|
||||
// Create some chain depth.
|
||||
tester.harness.advance_slot();
|
||||
tester
|
||||
.harness
|
||||
.extend_chain(
|
||||
num_initial as usize,
|
||||
BlockStrategy::OnCanonicalHead,
|
||||
AttestationStrategy::AllValidators,
|
||||
)
|
||||
.await;
|
||||
tester.harness.advance_slot();
|
||||
|
||||
let slot_a = Slot::new(num_initial);
|
||||
let slot_b = slot_a + 1;
|
||||
|
||||
let state_a = tester.harness.get_current_state();
|
||||
let (block, _): (SignedBlindedBeaconBlock<E>, _) =
|
||||
tester.harness.make_blinded_block(state_a, slot_b).await;
|
||||
|
||||
let response: Result<(), eth2::Error> = tester
|
||||
.client
|
||||
.post_beacon_blinded_blocks_v2_ssz(&block, validation_level)
|
||||
.await;
|
||||
|
||||
assert!(response.is_ok());
|
||||
assert!(tester
|
||||
.harness
|
||||
.chain
|
||||
.block_is_known_to_fork_choice(&block.canonical_root()));
|
||||
}
|
||||
|
||||
/// This test checks that a block that is **invalid** from a gossip perspective gets rejected when using `broadcast_validation=consensus`.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn blinded_consensus_invalid() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use beacon_chain::test_utils::RelativeSyncCommittee;
|
||||
use beacon_chain::{
|
||||
test_utils::{AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType},
|
||||
BeaconChain, StateSkipConfig, WhenSlotSkipped, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
|
||||
BeaconChain, StateSkipConfig, WhenSlotSkipped,
|
||||
};
|
||||
use environment::null_logger;
|
||||
use eth2::{
|
||||
@@ -1251,6 +1251,22 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_post_beacon_blocks_ssz_valid(mut self) -> Self {
|
||||
let next_block = &self.next_block;
|
||||
|
||||
self.client
|
||||
.post_beacon_blocks_ssz(next_block)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
self.network_rx.network_recv.recv().await.is_some(),
|
||||
"valid blocks should be sent to network"
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_post_beacon_blocks_invalid(mut self) -> Self {
|
||||
let block = self
|
||||
.harness
|
||||
@@ -1278,6 +1294,29 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_post_beacon_blocks_ssz_invalid(mut self) -> Self {
|
||||
let block = self
|
||||
.harness
|
||||
.make_block_with_modifier(
|
||||
self.harness.get_current_state(),
|
||||
self.harness.get_current_slot(),
|
||||
|b| {
|
||||
*b.state_root_mut() = Hash256::zero();
|
||||
},
|
||||
)
|
||||
.await
|
||||
.0;
|
||||
|
||||
assert!(self.client.post_beacon_blocks_ssz(&block).await.is_err());
|
||||
|
||||
assert!(
|
||||
self.network_rx.network_recv.recv().await.is_some(),
|
||||
"gossip valid blocks should be sent to network"
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_beacon_blocks(self) -> Self {
|
||||
for block_id in self.interesting_block_ids() {
|
||||
let expected = block_id
|
||||
@@ -2282,7 +2321,9 @@ impl ApiTester {
|
||||
.unwrap();
|
||||
|
||||
self.chain.slot_clock.set_current_time(
|
||||
current_epoch_start - MAXIMUM_GOSSIP_CLOCK_DISPARITY - Duration::from_millis(1),
|
||||
current_epoch_start
|
||||
- self.chain.spec.maximum_gossip_clock_disparity()
|
||||
- Duration::from_millis(1),
|
||||
);
|
||||
|
||||
let dependent_root = self
|
||||
@@ -2319,9 +2360,9 @@ impl ApiTester {
|
||||
"should not get attester duties outside of tolerance"
|
||||
);
|
||||
|
||||
self.chain
|
||||
.slot_clock
|
||||
.set_current_time(current_epoch_start - MAXIMUM_GOSSIP_CLOCK_DISPARITY);
|
||||
self.chain.slot_clock.set_current_time(
|
||||
current_epoch_start - self.chain.spec.maximum_gossip_clock_disparity(),
|
||||
);
|
||||
|
||||
self.client
|
||||
.get_validator_duties_proposer(current_epoch)
|
||||
@@ -2554,6 +2595,66 @@ impl ApiTester {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn test_blinded_block_production_ssz<Payload: AbstractExecPayload<E>>(&self) {
|
||||
let fork = self.chain.canonical_head.cached_head().head_fork();
|
||||
let genesis_validators_root = self.chain.genesis_validators_root;
|
||||
|
||||
for _ in 0..E::slots_per_epoch() * 3 {
|
||||
let slot = self.chain.slot().unwrap();
|
||||
let epoch = self.chain.epoch().unwrap();
|
||||
|
||||
let proposer_pubkey_bytes = self
|
||||
.client
|
||||
.get_validator_duties_proposer(epoch)
|
||||
.await
|
||||
.unwrap()
|
||||
.data
|
||||
.into_iter()
|
||||
.find(|duty| duty.slot == slot)
|
||||
.map(|duty| duty.pubkey)
|
||||
.unwrap();
|
||||
let proposer_pubkey = (&proposer_pubkey_bytes).try_into().unwrap();
|
||||
|
||||
let sk = self
|
||||
.validator_keypairs()
|
||||
.iter()
|
||||
.find(|kp| kp.pk == proposer_pubkey)
|
||||
.map(|kp| kp.sk.clone())
|
||||
.unwrap();
|
||||
|
||||
let randao_reveal = {
|
||||
let domain = self.chain.spec.get_domain(
|
||||
epoch,
|
||||
Domain::Randao,
|
||||
&fork,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let message = epoch.signing_root(domain);
|
||||
sk.sign(message).into()
|
||||
};
|
||||
|
||||
let block = self
|
||||
.client
|
||||
.get_validator_blinded_blocks::<E, Payload>(slot, &randao_reveal, None)
|
||||
.await
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let signed_block = block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
|
||||
|
||||
self.client
|
||||
.post_beacon_blinded_blocks_ssz(&signed_block)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// This converts the generic `Payload` to a concrete type for comparison.
|
||||
let head_block = SignedBeaconBlock::from(signed_block.clone());
|
||||
assert_eq!(head_block, signed_block);
|
||||
|
||||
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn test_blinded_block_production_no_verify_randao<Payload: AbstractExecPayload<E>>(
|
||||
self,
|
||||
) -> Self {
|
||||
@@ -2997,6 +3098,69 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_post_validator_liveness_epoch(self) -> Self {
|
||||
let epoch = self.chain.epoch().unwrap();
|
||||
let head_state = self.chain.head_beacon_state_cloned();
|
||||
let indices = (0..head_state.validators().len())
|
||||
.map(|i| i as u64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Construct the expected response
|
||||
let expected: Vec<StandardLivenessResponseData> = head_state
|
||||
.validators()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, _)| StandardLivenessResponseData {
|
||||
index: index as u64,
|
||||
is_live: false,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let result = self
|
||||
.client
|
||||
.post_validator_liveness_epoch(epoch, indices.clone())
|
||||
.await
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
assert_eq!(result, expected);
|
||||
|
||||
// Attest to the current slot
|
||||
self.client
|
||||
.post_beacon_pool_attestations(self.attestations.as_slice())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result = self
|
||||
.client
|
||||
.post_validator_liveness_epoch(epoch, indices.clone())
|
||||
.await
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let committees = head_state
|
||||
.get_beacon_committees_at_slot(self.chain.slot().unwrap())
|
||||
.unwrap();
|
||||
let attesting_validators: Vec<usize> = committees
|
||||
.into_iter()
|
||||
.flat_map(|committee| committee.committee.iter().cloned())
|
||||
.collect();
|
||||
// All attesters should now be considered live
|
||||
let expected = expected
|
||||
.into_iter()
|
||||
.map(|mut a| {
|
||||
if attesting_validators.contains(&(a.index as usize)) {
|
||||
a.is_live = true;
|
||||
}
|
||||
a
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(result, expected);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
// Helper function for tests that require a valid RANDAO signature.
|
||||
async fn get_test_randao(&self, slot: Slot, epoch: Epoch) -> (u64, SignatureBytes) {
|
||||
let fork = self.chain.canonical_head.cached_head().head_fork();
|
||||
@@ -4409,6 +4573,22 @@ async fn post_beacon_blocks_valid() {
|
||||
ApiTester::new().await.test_post_beacon_blocks_valid().await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn post_beacon_blocks_ssz_valid() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_post_beacon_blocks_ssz_valid()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_post_beacon_blocks_ssz_invalid() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_post_beacon_blocks_ssz_invalid()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn post_beacon_blocks_invalid() {
|
||||
ApiTester::new()
|
||||
@@ -4605,6 +4785,14 @@ async fn blinded_block_production_full_payload_premerge() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn blinded_block_production_ssz_full_payload_premerge() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_blinded_block_production_ssz::<FullPayload<_>>()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn blinded_block_production_with_skip_slots_full_payload_premerge() {
|
||||
ApiTester::new()
|
||||
@@ -4614,6 +4802,15 @@ async fn blinded_block_production_with_skip_slots_full_payload_premerge() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn blinded_block_production_ssz_with_skip_slots_full_payload_premerge() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.skip_slots(E::slots_per_epoch() * 2)
|
||||
.test_blinded_block_production_ssz::<FullPayload<_>>()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn blinded_block_production_no_verify_randao_full_payload_premerge() {
|
||||
ApiTester::new()
|
||||
@@ -4891,6 +5088,14 @@ async fn builder_works_post_capella() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn post_validator_liveness_epoch() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_post_validator_liveness_epoch()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn lighthouse_endpoints() {
|
||||
ApiTester::new()
|
||||
|
||||
Reference in New Issue
Block a user