Merge remote-tracking branch 'origin/deneb-free-blobs' into tree-states

This commit is contained in:
Michael Sproul
2023-09-29 16:34:29 +10:00
253 changed files with 21791 additions and 3122 deletions

View File

@@ -1,12 +1,19 @@
use beacon_chain::{
test_utils::{AttestationStrategy, BlockStrategy},
GossipVerifiedBlock,
GossipVerifiedBlock, IntoGossipVerifiedBlockContents,
};
use eth2::types::{
BroadcastValidation, SignedBeaconBlock, SignedBlindedBeaconBlock, SignedBlockContents,
SignedBlockContentsTuple,
};
use eth2::types::{BroadcastValidation, SignedBeaconBlock, SignedBlindedBeaconBlock};
use http_api::test_utils::InteractiveTester;
use http_api::{publish_blinded_block, publish_block, reconstruct_block, ProvenancedBlock};
use std::sync::Arc;
use tree_hash::TreeHash;
use types::{Hash256, MainnetEthSpec, Slot};
use types::{
BlindedBlobSidecar, BlindedPayload, BlobSidecar, FullPayload, Hash256, MainnetEthSpec,
SignedSidecarList, Slot,
};
use warp::Rejection;
use warp_utils::reject::CustomBadRequest;
@@ -63,7 +70,7 @@ pub async fn gossip_invalid() {
tester.harness.advance_slot();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) = tester
.harness
.make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero();
@@ -73,7 +80,7 @@ pub async fn gossip_invalid() {
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(&SignedBlockContents::new(block, blobs), validation_level)
.await;
assert!(response.is_err());
@@ -83,7 +90,7 @@ pub async fn gossip_invalid() {
assert_eq!(error_response.status(), Some(StatusCode::BAD_REQUEST));
assert!(
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 }".to_string())
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: BlockError(NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 })".to_string())
);
}
@@ -115,7 +122,7 @@ pub async fn gossip_partial_pass() {
tester.harness.advance_slot();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) = tester
.harness
.make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::random()
@@ -124,7 +131,7 @@ pub async fn gossip_partial_pass() {
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(&SignedBlockContents::new(block, blobs), validation_level)
.await;
assert!(response.is_err());
@@ -161,11 +168,15 @@ pub async fn gossip_full_pass() {
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 ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a, slot_b).await;
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(
&SignedBlockContents::new(block.clone(), blobs),
validation_level,
)
.await;
assert!(response.is_ok());
@@ -203,18 +214,19 @@ pub async fn gossip_full_pass_ssz() {
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 (block_contents_tuple, _) = tester.harness.make_block(state_a, slot_b).await;
let block_contents = block_contents_tuple.into();
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2_ssz(&block, validation_level)
.post_beacon_blocks_v2_ssz(&block_contents, validation_level)
.await;
assert!(response.is_ok());
assert!(tester
.harness
.chain
.block_is_known_to_fork_choice(&block.canonical_root()));
.block_is_known_to_fork_choice(&block_contents.signed_block().canonical_root()));
}
/// This test checks that a block that is **invalid** from a gossip perspective gets rejected when using `broadcast_validation=consensus`.
@@ -244,7 +256,7 @@ pub async fn consensus_invalid() {
tester.harness.advance_slot();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) = tester
.harness
.make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero();
@@ -254,7 +266,7 @@ pub async fn consensus_invalid() {
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(&SignedBlockContents::new(block, blobs), validation_level)
.await;
assert!(response.is_err());
@@ -264,7 +276,7 @@ pub async fn consensus_invalid() {
assert_eq!(error_response.status(), Some(StatusCode::BAD_REQUEST));
assert!(
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 }".to_string())
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: BlockError(NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 })".to_string())
);
}
@@ -296,14 +308,14 @@ pub async fn consensus_gossip() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) = tester
.harness
.make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero())
.await;
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(&SignedBlockContents::new(block, blobs), validation_level)
.await;
assert!(response.is_err());
@@ -346,18 +358,20 @@ pub async fn consensus_partial_pass_only_consensus() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block_a, state_after_a): (SignedBeaconBlock<E>, _) =
let ((block_a, _), state_after_a): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a.clone(), slot_b).await;
let (block_b, state_after_b): (SignedBeaconBlock<E>, _) =
let ((block_b, blobs_b), state_after_b): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a, slot_b).await;
let block_b_root = block_b.canonical_root();
/* check for `make_block` curios */
assert_eq!(block_a.state_root(), state_after_a.tree_hash_root());
assert_eq!(block_b.state_root(), state_after_b.tree_hash_root());
assert_ne!(block_a.state_root(), block_b.state_root());
let gossip_block_b = GossipVerifiedBlock::new(block_b.clone().into(), &tester.harness.chain);
assert!(gossip_block_b.is_ok());
let gossip_block_contents_b = SignedBlockContents::new(block_b, blobs_b)
.into_gossip_verified_block(&tester.harness.chain);
assert!(gossip_block_contents_b.is_ok());
let gossip_block_a = GossipVerifiedBlock::new(block_a.clone().into(), &tester.harness.chain);
assert!(gossip_block_a.is_err());
@@ -366,7 +380,7 @@ pub async fn consensus_partial_pass_only_consensus() {
let publication_result = publish_block(
None,
ProvenancedBlock::local(gossip_block_b.unwrap()),
ProvenancedBlock::local(gossip_block_contents_b.unwrap()),
tester.harness.chain.clone(),
&channel.0,
test_logger,
@@ -379,7 +393,7 @@ pub async fn consensus_partial_pass_only_consensus() {
assert!(tester
.harness
.chain
.block_is_known_to_fork_choice(&block_b.canonical_root()));
.block_is_known_to_fork_choice(&block_b_root));
}
/// This test checks that a block that is valid from both a gossip and consensus perspective is accepted when using `broadcast_validation=consensus`.
@@ -410,11 +424,15 @@ pub async fn consensus_full_pass() {
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 ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a, slot_b).await;
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(
&SignedBlockContents::new(block.clone(), blobs),
validation_level,
)
.await;
assert!(response.is_ok());
@@ -453,7 +471,7 @@ pub async fn equivocation_invalid() {
tester.harness.advance_slot();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) = tester
.harness
.make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero();
@@ -463,7 +481,7 @@ pub async fn equivocation_invalid() {
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(&SignedBlockContents::new(block, blobs), validation_level)
.await;
assert!(response.is_err());
@@ -473,7 +491,7 @@ pub async fn equivocation_invalid() {
assert_eq!(error_response.status(), Some(StatusCode::BAD_REQUEST));
assert!(
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 }".to_string())
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: BlockError(NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 })".to_string())
);
}
@@ -506,9 +524,9 @@ pub async fn equivocation_consensus_early_equivocation() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block_a, state_after_a): (SignedBeaconBlock<E>, _) =
let ((block_a, blobs_a), state_after_a): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a.clone(), slot_b).await;
let (block_b, state_after_b): (SignedBeaconBlock<E>, _) =
let ((block_b, blobs_b), state_after_b): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a, slot_b).await;
/* check for `make_block` curios */
@@ -519,7 +537,10 @@ pub async fn equivocation_consensus_early_equivocation() {
/* submit `block_a` as valid */
assert!(tester
.client
.post_beacon_blocks_v2(&block_a, validation_level)
.post_beacon_blocks_v2(
&SignedBlockContents::new(block_a.clone(), blobs_a),
validation_level
)
.await
.is_ok());
assert!(tester
@@ -530,7 +551,10 @@ pub async fn equivocation_consensus_early_equivocation() {
/* submit `block_b` which should induce equivocation */
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block_b, validation_level)
.post_beacon_blocks_v2(
&SignedBlockContents::new(block_b.clone(), blobs_b),
validation_level,
)
.await;
assert!(response.is_err());
@@ -539,7 +563,7 @@ pub async fn equivocation_consensus_early_equivocation() {
assert_eq!(error_response.status(), Some(StatusCode::BAD_REQUEST));
assert!(
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: Slashable".to_string())
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: BlockError(Slashable)".to_string())
);
}
@@ -572,14 +596,14 @@ pub async fn equivocation_gossip() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) = tester
.harness
.make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero())
.await;
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(&SignedBlockContents::new(block, blobs), validation_level)
.await;
assert!(response.is_err());
@@ -593,9 +617,11 @@ pub async fn equivocation_gossip() {
);
}
/// This test checks that a block that is valid from both a gossip and consensus perspective but that equivocates **late** is rejected when using `broadcast_validation=consensus_and_equivocation`.
/// This test checks that a block that is valid from both a gossip and consensus perspective but
/// that equivocates **late** is rejected when using `broadcast_validation=consensus_and_equivocation`.
///
/// This test is unique in that we can't actually test the HTTP API directly, but instead have to hook into the `publish_blocks` code manually. This is in order to handle the late equivocation case.
/// This test is unique in that we can't actually test the HTTP API directly, but instead have to
/// hook into the `publish_blocks` code manually. This is in order to handle the late equivocation case.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
pub async fn equivocation_consensus_late_equivocation() {
/* this test targets gossip-level validation */
@@ -625,9 +651,9 @@ pub async fn equivocation_consensus_late_equivocation() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block_a, state_after_a): (SignedBeaconBlock<E>, _) =
let ((block_a, blobs_a), state_after_a): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a.clone(), slot_b).await;
let (block_b, state_after_b): (SignedBeaconBlock<E>, _) =
let ((block_b, blobs_b), state_after_b): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a, slot_b).await;
/* check for `make_block` curios */
@@ -635,16 +661,18 @@ pub async fn equivocation_consensus_late_equivocation() {
assert_eq!(block_b.state_root(), state_after_b.tree_hash_root());
assert_ne!(block_a.state_root(), block_b.state_root());
let gossip_block_b = GossipVerifiedBlock::new(block_b.clone().into(), &tester.harness.chain);
assert!(gossip_block_b.is_ok());
let gossip_block_a = GossipVerifiedBlock::new(block_a.clone().into(), &tester.harness.chain);
assert!(gossip_block_a.is_err());
let gossip_block_contents_b = SignedBlockContents::new(block_b, blobs_b)
.into_gossip_verified_block(&tester.harness.chain);
assert!(gossip_block_contents_b.is_ok());
let gossip_block_contents_a = SignedBlockContents::new(block_a, blobs_a)
.into_gossip_verified_block(&tester.harness.chain);
assert!(gossip_block_contents_a.is_err());
let channel = tokio::sync::mpsc::unbounded_channel();
let publication_result = publish_block(
None,
ProvenancedBlock::local(gossip_block_b.unwrap()),
ProvenancedBlock::local(gossip_block_contents_b.unwrap()),
tester.harness.chain,
&channel.0,
test_logger,
@@ -694,11 +722,15 @@ pub async fn equivocation_full_pass() {
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 ((block, blobs), _): ((SignedBeaconBlock<E>, _), _) =
tester.harness.make_block(state_a, slot_b).await;
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(
&SignedBlockContents::new(block.clone(), blobs),
validation_level,
)
.await;
assert!(response.is_ok());
@@ -736,7 +768,7 @@ pub async fn blinded_gossip_invalid() {
tester.harness.advance_slot();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let (block_contents_tuple, _) = tester
.harness
.make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero();
@@ -744,11 +776,11 @@ pub async fn blinded_gossip_invalid() {
})
.await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into();
let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level)
.post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await;
assert!(response.is_err());
@@ -758,7 +790,7 @@ pub async fn blinded_gossip_invalid() {
assert_eq!(error_response.status(), Some(StatusCode::BAD_REQUEST));
assert!(
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 }".to_string())
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: BlockError(NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 })".to_string())
);
}
@@ -790,18 +822,18 @@ pub async fn blinded_gossip_partial_pass() {
tester.harness.advance_slot();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let (block_contents_tuple, _) = tester
.harness
.make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero()
})
.await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into();
let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level)
.post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await;
assert!(response.is_err());
@@ -838,19 +870,18 @@ pub async fn blinded_gossip_full_pass() {
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 (block_contents_tuple, _) = tester.harness.make_blinded_block(state_a, slot_b).await;
let block_contents = block_contents_tuple.into();
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&block, validation_level)
.post_beacon_blinded_blocks_v2(&block_contents, validation_level)
.await;
assert!(response.is_ok());
assert!(tester
.harness
.chain
.block_is_known_to_fork_choice(&block.canonical_root()));
.block_is_known_to_fork_choice(&block_contents.signed_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`.
@@ -881,19 +912,19 @@ pub async fn blinded_gossip_full_pass_ssz() {
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 (block_contents_tuple, _) = tester.harness.make_blinded_block(state_a, slot_b).await;
let block_contents = block_contents_tuple.into();
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2_ssz(&block, validation_level)
.post_beacon_blinded_blocks_v2_ssz(&block_contents, validation_level)
.await;
assert!(response.is_ok());
assert!(tester
.harness
.chain
.block_is_known_to_fork_choice(&block.canonical_root()));
.block_is_known_to_fork_choice(&block_contents.signed_block().canonical_root()));
}
/// This test checks that a block that is **invalid** from a gossip perspective gets rejected when using `broadcast_validation=consensus`.
@@ -924,7 +955,7 @@ pub async fn blinded_consensus_invalid() {
tester.harness.advance_slot();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let (block_contents_tuple, _) = tester
.harness
.make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero();
@@ -932,11 +963,11 @@ pub async fn blinded_consensus_invalid() {
})
.await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into();
let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level)
.post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await;
assert!(response.is_err());
@@ -946,7 +977,7 @@ pub async fn blinded_consensus_invalid() {
assert_eq!(error_response.status(), Some(StatusCode::BAD_REQUEST));
assert!(
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 }".to_string())
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: BlockError(NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 })".to_string())
);
}
@@ -978,16 +1009,16 @@ pub async fn blinded_consensus_gossip() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let (block_contents_tuple, _) = tester
.harness
.make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero())
.await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into();
let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level)
.post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await;
assert!(response.is_err());
@@ -1029,19 +1060,19 @@ pub async fn blinded_consensus_full_pass() {
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 (block_contents_tuple, _) = tester.harness.make_blinded_block(state_a, slot_b).await;
let block_contents = block_contents_tuple.into();
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&block, validation_level)
.post_beacon_blinded_blocks_v2(&block_contents, validation_level)
.await;
assert!(response.is_ok());
assert!(tester
.harness
.chain
.block_is_known_to_fork_choice(&block.canonical_root()));
.block_is_known_to_fork_choice(&block_contents.signed_block().canonical_root()));
}
/// This test checks that a block that is **invalid** from a gossip perspective gets rejected when using `broadcast_validation=consensus_and_equivocation`.
@@ -1073,7 +1104,7 @@ pub async fn blinded_equivocation_invalid() {
tester.harness.advance_slot();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let (block_contents_tuple, _) = tester
.harness
.make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero();
@@ -1081,11 +1112,11 @@ pub async fn blinded_equivocation_invalid() {
})
.await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into();
let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level)
.post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await;
assert!(response.is_err());
@@ -1095,7 +1126,7 @@ pub async fn blinded_equivocation_invalid() {
assert_eq!(error_response.status(), Some(StatusCode::BAD_REQUEST));
assert!(
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 }".to_string())
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: BlockError(NotFinalizedDescendant { block_parent_root: 0x0000000000000000000000000000000000000000000000000000000000000000 })".to_string())
);
}
@@ -1128,14 +1159,18 @@ pub async fn blinded_equivocation_consensus_early_equivocation() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block_a, state_after_a): (SignedBlindedBeaconBlock<E>, _) = tester
let (block_contents_tuple_a, state_after_a) = tester
.harness
.make_blinded_block(state_a.clone(), slot_b)
.await;
let (block_b, state_after_b): (SignedBlindedBeaconBlock<E>, _) =
let (block_contents_tuple_b, state_after_b) =
tester.harness.make_blinded_block(state_a, slot_b).await;
/* check for `make_blinded_block` curios */
let block_contents_a: SignedBlockContents<E, BlindedPayload<E>> = block_contents_tuple_a.into();
let block_contents_b: SignedBlockContents<E, BlindedPayload<E>> = block_contents_tuple_b.into();
let block_a = block_contents_a.signed_block();
let block_b = block_contents_b.signed_block();
assert_eq!(block_a.state_root(), state_after_a.tree_hash_root());
assert_eq!(block_b.state_root(), state_after_b.tree_hash_root());
assert_ne!(block_a.state_root(), block_b.state_root());
@@ -1143,7 +1178,7 @@ pub async fn blinded_equivocation_consensus_early_equivocation() {
/* submit `block_a` as valid */
assert!(tester
.client
.post_beacon_blinded_blocks_v2(&block_a, validation_level)
.post_beacon_blinded_blocks_v2(&block_contents_a, validation_level)
.await
.is_ok());
assert!(tester
@@ -1154,7 +1189,7 @@ pub async fn blinded_equivocation_consensus_early_equivocation() {
/* submit `block_b` which should induce equivocation */
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&block_b, validation_level)
.post_beacon_blinded_blocks_v2(&block_contents_b, validation_level)
.await;
assert!(response.is_err());
@@ -1163,7 +1198,7 @@ pub async fn blinded_equivocation_consensus_early_equivocation() {
assert_eq!(error_response.status(), Some(StatusCode::BAD_REQUEST));
assert!(
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: Slashable".to_string())
matches!(error_response, eth2::Error::ServerMessage(err) if err.message == "BAD_REQUEST: BlockError(Slashable)".to_string())
);
}
@@ -1196,16 +1231,16 @@ pub async fn blinded_equivocation_gossip() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block, _): (SignedBeaconBlock<E>, _) = tester
let (block_contents_tuple, _) = tester
.harness
.make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero())
.await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into();
let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level)
.post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await;
assert!(response.is_err());
@@ -1251,11 +1286,11 @@ pub async fn blinded_equivocation_consensus_late_equivocation() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block_a, state_after_a): (SignedBlindedBeaconBlock<E>, _) = tester
let ((block_a, blobs_a), state_after_a): ((SignedBlindedBeaconBlock<E>, _), _) = tester
.harness
.make_blinded_block(state_a.clone(), slot_b)
.await;
let (block_b, state_after_b): (SignedBlindedBeaconBlock<E>, _) =
let ((block_b, blobs_b), state_after_b): ((SignedBlindedBeaconBlock<E>, _), _) =
tester.harness.make_blinded_block(state_a, slot_b).await;
/* check for `make_blinded_block` curios */
@@ -1265,16 +1300,16 @@ pub async fn blinded_equivocation_consensus_late_equivocation() {
let unblinded_block_a = reconstruct_block(
tester.harness.chain.clone(),
block_a.state_root(),
block_a,
block_a.canonical_root(),
SignedBlockContents::new(block_a, blobs_a),
test_logger.clone(),
)
.await
.unwrap();
let unblinded_block_b = reconstruct_block(
tester.harness.chain.clone(),
block_b.clone().state_root(),
block_b.clone(),
block_b.canonical_root(),
SignedBlockContents::new(block_b.clone(), blobs_b.clone()),
test_logger.clone(),
)
.await
@@ -1289,15 +1324,21 @@ pub async fn blinded_equivocation_consensus_late_equivocation() {
ProvenancedBlock::Builder(b, _) => b,
};
let gossip_block_b = GossipVerifiedBlock::new(inner_block_b, &tester.harness.chain);
let gossip_block_b = GossipVerifiedBlock::new(
Arc::new(inner_block_b.clone().deconstruct().0),
&tester.harness.chain,
);
assert!(gossip_block_b.is_ok());
let gossip_block_a = GossipVerifiedBlock::new(inner_block_a, &tester.harness.chain);
let gossip_block_a = GossipVerifiedBlock::new(
Arc::new(inner_block_a.clone().deconstruct().0),
&tester.harness.chain,
);
assert!(gossip_block_a.is_err());
let channel = tokio::sync::mpsc::unbounded_channel();
let publication_result = publish_blinded_block(
block_b,
SignedBlockContents::new(block_b, blobs_b),
tester.harness.chain,
&channel.0,
test_logger,
@@ -1342,12 +1383,15 @@ pub async fn blinded_equivocation_full_pass() {
let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state();
let (block, _): (SignedBlindedBeaconBlock<E>, _) =
let ((block, blobs), _): ((SignedBlindedBeaconBlock<E>, _), _) =
tester.harness.make_blinded_block(state_a, slot_b).await;
let response: Result<(), eth2::Error> = tester
.client
.post_beacon_blocks_v2(&block, validation_level)
.post_beacon_blocks_v2(
&SignedBlockContents::new(block.clone(), blobs),
validation_level,
)
.await;
assert!(response.is_ok());
@@ -1356,3 +1400,20 @@ pub async fn blinded_equivocation_full_pass() {
.chain
.block_is_known_to_fork_choice(&block.canonical_root()));
}
fn into_signed_blinded_block_contents(
block_contents_tuple: SignedBlockContentsTuple<E, FullPayload<E>>,
) -> SignedBlockContents<E, BlindedPayload<E>> {
let (block, maybe_blobs) = block_contents_tuple;
SignedBlockContents::new(block.into(), maybe_blobs.map(into_blinded_blob_sidecars))
}
fn into_blinded_blob_sidecars(
blobs: SignedSidecarList<E, BlobSidecar<E>>,
) -> SignedSidecarList<E, BlindedBlobSidecar> {
blobs
.into_iter()
.map(|blob| blob.into())
.collect::<Vec<_>>()
.into()
}

View File

@@ -4,6 +4,7 @@ use beacon_chain::{
StateSkipConfig,
};
use eth2::types::{IndexedErrorMessage, StateId, SyncSubcommittee};
use execution_layer::test_utils::generate_genesis_header;
use genesis::{bls_withdrawal_credentials, interop_genesis_state_with_withdrawal_credentials};
use http_api::test_utils::*;
use std::collections::HashSet;
@@ -355,12 +356,13 @@ async fn bls_to_execution_changes_update_all_around_capella_fork() {
.iter()
.map(|keypair| bls_withdrawal_credentials(&keypair.as_ref().unwrap().pk, &spec))
.collect::<Vec<_>>();
let header = generate_genesis_header(&spec, true);
let genesis_state = interop_genesis_state_with_withdrawal_credentials(
&validator_keypairs,
&withdrawal_credentials,
HARNESS_GENESIS_TIME,
Hash256::from_slice(DEFAULT_ETH1_BLOCK_HASH),
None,
header,
&spec,
)
.unwrap();

View File

@@ -391,8 +391,8 @@ pub async fn proposer_boost_re_org_test(
) {
assert!(head_slot > 0);
// Test using Capella so that we simulate conditions as similar to mainnet as possible.
let mut spec = ForkName::Capella.make_genesis_spec(E::default_spec());
// Test using the latest fork so that we simulate conditions as similar to mainnet as possible.
let mut spec = ForkName::latest().make_genesis_spec(E::default_spec());
spec.terminal_total_difficulty = 1.into();
// Ensure there are enough validators to have `attesters_per_slot`.
@@ -551,7 +551,7 @@ pub async fn proposer_boost_re_org_test(
// Produce block B and process it halfway through the slot.
let (block_b, mut state_b) = harness.make_block(state_a.clone(), slot_b).await;
let block_b_root = block_b.canonical_root();
let block_b_root = block_b.0.canonical_root();
let obs_time = slot_clock.start_of(slot_b).unwrap() + slot_clock.slot_duration() / 2;
slot_clock.set_current_time(obs_time);
@@ -617,12 +617,13 @@ pub async fn proposer_boost_re_org_test(
let randao_reveal = harness
.sign_randao_reveal(&state_b, proposer_index, slot_c)
.into();
let unsigned_block_c = tester
let unsigned_block_contents_c = tester
.client
.get_validator_blocks(slot_c, &randao_reveal, None)
.await
.unwrap()
.data;
let (unsigned_block_c, block_c_blobs) = unsigned_block_contents_c.deconstruct();
let block_c = harness.sign_beacon_block(unsigned_block_c, &state_b);
if should_re_org {
@@ -633,9 +634,13 @@ pub async fn proposer_boost_re_org_test(
assert_eq!(block_c.parent_root(), block_b_root);
}
// Sign blobs.
let block_c_signed_blobs =
block_c_blobs.map(|blobs| harness.sign_blobs(blobs, &state_b, proposer_index));
// Applying block C should cause it to become head regardless (re-org or continuation).
let block_root_c = harness
.process_block_result(block_c.clone())
.process_block_result((block_c.clone(), block_c_signed_blobs))
.await
.unwrap()
.into();
@@ -643,8 +648,18 @@ pub async fn proposer_boost_re_org_test(
// Check the fork choice updates that were sent.
let forkchoice_updates = forkchoice_updates.lock();
let block_a_exec_hash = block_a.message().execution_payload().unwrap().block_hash();
let block_b_exec_hash = block_b.message().execution_payload().unwrap().block_hash();
let block_a_exec_hash = block_a
.0
.message()
.execution_payload()
.unwrap()
.block_hash();
let block_b_exec_hash = block_b
.0
.message()
.execution_payload()
.unwrap()
.block_hash();
let block_c_timestamp = block_c.message().execution_payload().unwrap().timestamp();
@@ -688,6 +703,11 @@ pub async fn proposer_boost_re_org_test(
assert_ne!(expected_withdrawals, pre_advance_withdrawals);
}
// Check that the `parent_beacon_block_root` of the payload attributes are correct.
if let Ok(parent_beacon_block_root) = payload_attribs.parent_beacon_block_root() {
assert_eq!(parent_beacon_block_root, block_c.parent_root());
}
let lookahead = slot_clock
.start_of(slot_c)
.unwrap()
@@ -749,7 +769,7 @@ pub async fn fork_choice_before_proposal() {
let state_a = harness.get_current_state();
let (block_b, state_b) = harness.make_block(state_a.clone(), slot_b).await;
let block_root_b = harness
.process_block(slot_b, block_b.canonical_root(), block_b)
.process_block(slot_b, block_b.0.canonical_root(), block_b)
.await
.unwrap();
@@ -764,7 +784,7 @@ pub async fn fork_choice_before_proposal() {
let (block_c, state_c) = harness.make_block(state_a, slot_c).await;
let block_root_c = harness
.process_block(slot_c, block_c.canonical_root(), block_c.clone())
.process_block(slot_c, block_c.0.canonical_root(), block_c.clone())
.await
.unwrap();
@@ -804,7 +824,9 @@ pub async fn fork_choice_before_proposal() {
.get_validator_blocks::<E, FullPayload<E>>(slot_d, &randao_reveal, None)
.await
.unwrap()
.data;
.data
.deconstruct()
.0;
// Head is now B.
assert_eq!(

View File

@@ -100,9 +100,10 @@ async fn el_error_on_new_payload() {
// Make a block.
let pre_state = harness.get_current_state();
let (block, _) = harness
let (block_contents, _) = harness
.make_block(pre_state, Slot::new(num_blocks + 1))
.await;
let (block, blobs) = block_contents;
let block_hash = block
.message()
.body()
@@ -118,7 +119,9 @@ async fn el_error_on_new_payload() {
// Attempt to process the block, which should error.
harness.advance_slot();
assert!(matches!(
harness.process_block_result(block.clone()).await,
harness
.process_block_result((block.clone(), blobs.clone()))
.await,
Err(BlockError::ExecutionPayloadError(_))
));
@@ -137,7 +140,7 @@ async fn el_error_on_new_payload() {
validation_error: None,
},
);
harness.process_block_result(block).await.unwrap();
harness.process_block_result((block, blobs)).await.unwrap();
let api_response = tester.client.get_node_syncing().await.unwrap().data;
assert_eq!(api_response.el_offline, Some(false));

View File

@@ -62,8 +62,8 @@ struct ApiTester {
harness: Arc<BeaconChainHarness<EphemeralHarnessType<E>>>,
chain: Arc<BeaconChain<EphemeralHarnessType<E>>>,
client: BeaconNodeHttpClient,
next_block: SignedBeaconBlock<E>,
reorg_block: SignedBeaconBlock<E>,
next_block: SignedBlockContents<E>,
reorg_block: SignedBlockContents<E>,
attestations: Vec<Attestation<E>>,
contribution_and_proofs: Vec<SignedContributionAndProof<E>>,
attester_slashing: AttesterSlashing<E>,
@@ -171,11 +171,13 @@ impl ApiTester {
let (next_block, _next_state) = harness
.make_block(head.beacon_state.clone(), harness.chain.slot().unwrap())
.await;
let next_block = SignedBlockContents::from(next_block);
// `make_block` adds random graffiti, so this will produce an alternate block
let (reorg_block, _reorg_state) = harness
.make_block(head.beacon_state.clone(), harness.chain.slot().unwrap() + 1)
.await;
let reorg_block = SignedBlockContents::from(reorg_block);
let head_state_root = head.beacon_state_root();
let attestations = harness
@@ -314,11 +316,13 @@ impl ApiTester {
let (next_block, _next_state) = harness
.make_block(head.beacon_state.clone(), harness.chain.slot().unwrap())
.await;
let next_block = SignedBlockContents::from(next_block);
// `make_block` adds random graffiti, so this will produce an alternate block
let (reorg_block, _reorg_state) = harness
.make_block(head.beacon_state.clone(), harness.chain.slot().unwrap())
.await;
let reorg_block = SignedBlockContents::from(reorg_block);
let head_state_root = head.beacon_state_root();
let attestations = harness
@@ -1256,9 +1260,9 @@ impl ApiTester {
}
pub async fn test_post_beacon_blocks_valid(mut self) -> Self {
let next_block = &self.next_block;
let next_block = self.next_block.clone();
self.client.post_beacon_blocks(next_block).await.unwrap();
self.client.post_beacon_blocks(&next_block).await.unwrap();
assert!(
self.network_rx.network_recv.recv().await.is_some(),
@@ -1297,7 +1301,11 @@ impl ApiTester {
.await
.0;
assert!(self.client.post_beacon_blocks(&block).await.is_err());
assert!(self
.client
.post_beacon_blocks(&SignedBlockContents::from(block))
.await
.is_err());
assert!(
self.network_rx.network_recv.recv().await.is_some(),
@@ -1320,7 +1328,11 @@ impl ApiTester {
.await
.0;
assert!(self.client.post_beacon_blocks_ssz(&block).await.is_err());
assert!(self
.client
.post_beacon_blocks_ssz(&SignedBlockContents::from(block))
.await
.is_err());
assert!(
self.network_rx.network_recv.recv().await.is_some(),
@@ -1331,48 +1343,56 @@ impl ApiTester {
}
pub async fn test_post_beacon_blocks_duplicate(self) -> Self {
let block = self
let block_contents = self
.harness
.make_block(
self.harness.get_current_state(),
self.harness.get_current_slot(),
)
.await
.0;
.0
.into();
assert!(self.client.post_beacon_blocks(&block).await.is_ok());
assert!(self
.client
.post_beacon_blocks(&block_contents)
.await
.is_ok());
let blinded_block = block.clone_as_blinded();
let blinded_block_contents = block_contents.clone_as_blinded();
// Test all the POST methods in sequence, they should all behave the same.
let responses = vec![
self.client.post_beacon_blocks(&block).await.unwrap_err(),
self.client
.post_beacon_blocks_v2(&block, None)
.post_beacon_blocks(&block_contents)
.await
.unwrap_err(),
self.client
.post_beacon_blocks_ssz(&block)
.post_beacon_blocks_v2(&block_contents, None)
.await
.unwrap_err(),
self.client
.post_beacon_blocks_v2_ssz(&block, None)
.post_beacon_blocks_ssz(&block_contents)
.await
.unwrap_err(),
self.client
.post_beacon_blinded_blocks(&blinded_block)
.post_beacon_blocks_v2_ssz(&block_contents, None)
.await
.unwrap_err(),
self.client
.post_beacon_blinded_blocks_v2(&blinded_block, None)
.post_beacon_blinded_blocks(&blinded_block_contents)
.await
.unwrap_err(),
self.client
.post_beacon_blinded_blocks_ssz(&blinded_block)
.post_beacon_blinded_blocks_v2(&blinded_block_contents, None)
.await
.unwrap_err(),
self.client
.post_beacon_blinded_blocks_v2_ssz(&blinded_block, None)
.post_beacon_blinded_blocks_ssz(&blinded_block_contents)
.await
.unwrap_err(),
self.client
.post_beacon_blinded_blocks_v2_ssz(&blinded_block_contents, None)
.await
.unwrap_err(),
];
@@ -1798,9 +1818,9 @@ impl ApiTester {
pub async fn test_get_config_spec(self) -> Self {
let result = self
.client
.get_config_spec::<ConfigAndPresetCapella>()
.get_config_spec::<ConfigAndPresetDeneb>()
.await
.map(|res| ConfigAndPreset::Capella(res.data))
.map(|res| ConfigAndPreset::Deneb(res.data))
.unwrap();
let expected = ConfigAndPreset::from_chain_spec::<E>(&self.chain.spec, None);
@@ -2499,11 +2519,18 @@ impl ApiTester {
.get_validator_blocks::<E, FullPayload<E>>(slot, &randao_reveal, None)
.await
.unwrap()
.data;
.data
.deconstruct()
.0;
let signed_block = block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
let signed_block_contents =
SignedBlockContents::try_from(signed_block.clone()).unwrap();
self.client.post_beacon_blocks(&signed_block).await.unwrap();
self.client
.post_beacon_blocks(&signed_block_contents)
.await
.unwrap();
assert_eq!(self.chain.head_beacon_block().as_ref(), &signed_block);
@@ -2558,18 +2585,22 @@ impl ApiTester {
.unwrap()
.expect("block bytes");
let block =
BeaconBlock::<E, FullPayload<E>>::from_ssz_bytes(&block_bytes, &self.chain.spec)
.expect("block bytes can be decoded");
let block_contents =
BlockContents::<E, FullPayload<E>>::from_ssz_bytes(&block_bytes, &self.chain.spec)
.expect("block contents bytes can be decoded");
let signed_block = block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
let signed_block_contents =
block_contents.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
self.client
.post_beacon_blocks_ssz(&signed_block)
.post_beacon_blocks_ssz(&signed_block_contents)
.await
.unwrap();
assert_eq!(self.chain.head_beacon_block().as_ref(), &signed_block);
assert_eq!(
self.chain.head_beacon_block().as_ref(),
signed_block_contents.signed_block()
);
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
}
@@ -2591,7 +2622,9 @@ impl ApiTester {
)
.await
.unwrap()
.data;
.data
.deconstruct()
.0;
assert_eq!(block.slot(), slot);
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
}
@@ -2705,14 +2738,16 @@ impl ApiTester {
.unwrap()
.data;
let signed_block = block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
let signed_block_contents =
block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
self.client
.post_beacon_blinded_blocks(&signed_block)
.post_beacon_blinded_blocks(&signed_block_contents)
.await
.unwrap();
// This converts the generic `Payload` to a concrete type for comparison.
let signed_block = signed_block_contents.deconstruct().0;
let head_block = SignedBeaconBlock::from(signed_block.clone());
assert_eq!(head_block, signed_block);
@@ -2758,24 +2793,29 @@ impl ApiTester {
sk.sign(message).into()
};
let block_bytes = self
let block_contents_bytes = self
.client
.get_validator_blinded_blocks_ssz::<E, Payload>(slot, &randao_reveal, None)
.await
.unwrap()
.expect("block bytes");
let block = BeaconBlock::<E, Payload>::from_ssz_bytes(&block_bytes, &self.chain.spec)
.expect("block bytes can be decoded");
let block_contents = BlockContents::<E, Payload>::from_ssz_bytes(
&block_contents_bytes,
&self.chain.spec,
)
.expect("block contents bytes can be decoded");
let signed_block = block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
let signed_block_contents =
block_contents.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
self.client
.post_beacon_blinded_blocks_ssz(&signed_block)
.post_beacon_blinded_blocks_ssz(&signed_block_contents)
.await
.unwrap();
// This converts the generic `Payload` to a concrete type for comparison.
let signed_block = signed_block_contents.deconstruct().0;
let head_block = SignedBeaconBlock::from(signed_block.clone());
assert_eq!(head_block, signed_block);
@@ -2789,7 +2829,7 @@ impl ApiTester {
for _ in 0..E::slots_per_epoch() {
let slot = self.chain.slot().unwrap();
let block = self
let block_contents = self
.client
.get_validator_blinded_blocks_modular::<E, Payload>(
slot,
@@ -2800,7 +2840,7 @@ impl ApiTester {
.await
.unwrap()
.data;
assert_eq!(block.slot(), slot);
assert_eq!(block_contents.block().slot(), slot);
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
}
@@ -3336,6 +3376,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3376,6 +3417,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3418,6 +3460,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3466,6 +3509,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3513,6 +3557,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3559,6 +3604,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3604,6 +3650,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3636,6 +3683,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3673,6 +3721,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3716,6 +3765,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3745,6 +3795,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3794,6 +3845,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3833,6 +3885,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3876,6 +3929,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3916,6 +3970,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3952,6 +4007,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -3988,6 +4044,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -4024,6 +4081,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -4050,19 +4108,6 @@ impl ApiTester {
)));
let slot = self.chain.slot().unwrap();
let propose_state = self
.harness
.chain
.state_at_slot(slot, StateSkipConfig::WithoutStateRoots)
.unwrap();
let withdrawals = get_expected_withdrawals(&propose_state, &self.chain.spec).unwrap();
let withdrawals_root = withdrawals.tree_hash_root();
// Set withdrawals root for builder
self.mock_builder
.as_ref()
.unwrap()
.add_operation(Operation::WithdrawalsRoot(withdrawals_root));
let epoch = self.chain.epoch().unwrap();
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
@@ -4072,6 +4117,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -4088,6 +4134,42 @@ impl ApiTester {
self
}
pub async fn test_builder_works_post_deneb(self) -> Self {
// Ensure builder payload is chosen
self.mock_builder
.as_ref()
.unwrap()
.add_operation(Operation::Value(Uint256::from(
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI + 1,
)));
let slot = self.chain.slot().unwrap();
let epoch = self.chain.epoch().unwrap();
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
let block_contents = self
.client
.get_validator_blinded_blocks::<E, BlindedPayload<E>>(slot, &randao_reveal, None)
.await
.unwrap()
.data;
let (block, maybe_sidecars) = block_contents.deconstruct();
// Response should contain blob sidecars
assert!(maybe_sidecars.is_some());
// The builder's payload should've been chosen, so this cache should not be populated
let payload: BlindedPayload<E> = block.body().execution_payload().unwrap().into();
assert!(self
.chain
.execution_layer
.as_ref()
.unwrap()
.get_payload_by_root(&payload.tree_hash_root())
.is_none());
self
}
pub async fn test_lighthouse_rejects_invalid_withdrawals_root(self) -> Self {
// Ensure builder payload *would be* chosen
self.mock_builder
@@ -4112,6 +4194,7 @@ impl ApiTester {
.await
.unwrap()
.data
.block()
.body()
.execution_payload()
.unwrap()
@@ -4367,12 +4450,12 @@ impl ApiTester {
// Submit the next block, which is on an epoch boundary, so this will produce a finalized
// checkpoint event, head event, and block event
let block_root = self.next_block.canonical_root();
let block_root = self.next_block.signed_block().canonical_root();
// current_duty_dependent_root = block root because this is the first slot of the epoch
let current_duty_dependent_root = self.chain.head_beacon_block_root();
let current_slot = self.chain.slot().unwrap();
let next_slot = self.next_block.slot();
let next_slot = self.next_block.signed_block().slot();
let finalization_distance = E::slots_per_epoch() * 2;
let expected_block = EventKind::Block(SseBlock {
@@ -4384,7 +4467,7 @@ impl ApiTester {
let expected_head = EventKind::Head(SseHead {
block: block_root,
slot: next_slot,
state: self.next_block.state_root(),
state: self.next_block.signed_block().state_root(),
current_duty_dependent_root,
previous_duty_dependent_root: self
.chain
@@ -4433,13 +4516,17 @@ impl ApiTester {
.unwrap();
let expected_reorg = EventKind::ChainReorg(SseChainReorg {
slot: self.reorg_block.slot(),
slot: self.reorg_block.signed_block().slot(),
depth: 1,
old_head_block: self.next_block.canonical_root(),
old_head_state: self.next_block.state_root(),
new_head_block: self.reorg_block.canonical_root(),
new_head_state: self.reorg_block.state_root(),
epoch: self.next_block.slot().epoch(E::slots_per_epoch()),
old_head_block: self.next_block.signed_block().canonical_root(),
old_head_state: self.next_block.signed_block().state_root(),
new_head_block: self.reorg_block.signed_block().canonical_root(),
new_head_state: self.reorg_block.signed_block().state_root(),
epoch: self
.next_block
.signed_block()
.slot()
.epoch(E::slots_per_epoch()),
execution_optimistic: false,
});
@@ -4569,8 +4656,8 @@ impl ApiTester {
.await
.unwrap();
let block_root = self.next_block.canonical_root();
let next_slot = self.next_block.slot();
let block_root = self.next_block.signed_block().canonical_root();
let next_slot = self.next_block.signed_block().slot();
let expected_block = EventKind::Block(SseBlock {
block: block_root,
@@ -4581,7 +4668,7 @@ impl ApiTester {
let expected_head = EventKind::Head(SseHead {
block: block_root,
slot: next_slot,
state: self.next_block.state_root(),
state: self.next_block.signed_block().state_root(),
current_duty_dependent_root: self.chain.genesis_block_root,
previous_duty_dependent_root: self.chain.genesis_block_root,
epoch_transition: false,
@@ -5284,6 +5371,26 @@ async fn builder_works_post_capella() {
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn builder_works_post_deneb() {
let mut config = ApiTesterConfig {
builder_threshold: Some(0),
retain_historic_states: false,
spec: E::default_spec(),
};
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));
ApiTester::new_from_config(config)
.await
.test_post_validator_register_validator()
.await
.test_builder_works_post_deneb()
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn post_validator_liveness_epoch() {
ApiTester::new()