make tests work for all forks

This commit is contained in:
realbigsean
2023-05-02 10:00:07 -04:00
parent 93bcd6281c
commit 8edefb7e0d
7 changed files with 847 additions and 677 deletions

View File

@@ -118,6 +118,20 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Run operation_pool tests for all known forks - name: Run operation_pool tests for all known forks
run: make test-op-pool run: make test-op-pool
network-minimal-tests:
name: network-minimal-tests
runs-on: ubuntu-latest
needs: cargo-fmt
steps:
- uses: actions/checkout@v3
- name: Get latest version of stable Rust
run: rustup update stable
- name: Install Protoc
uses: arduino/setup-protoc@e52d9eb8f7b63115df1ac544a1376fdbf5a39612
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Run network tests for all known forks using the minimal spec
run: make test-network-minimal
slasher-tests: slasher-tests:
name: slasher-tests name: slasher-tests
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -143,6 +143,13 @@ test-op-pool-%:
--features 'beacon_chain/fork_from_env'\ --features 'beacon_chain/fork_from_env'\
-p operation_pool -p operation_pool
test-network-minimal: $(patsubst %,test-network-minimal-%,$(FORKS))
test-network-minimal-%:
env FORK_NAME=$* cargo test --release \
--features 'fork_from_env,spec-minimal'\
-p network
# Run the tests in the `slasher` crate for all supported database backends. # Run the tests in the `slasher` crate for all supported database backends.
test-slasher: test-slasher:
cargo test --release -p slasher --features mdbx cargo test --release -p slasher --features mdbx

View File

@@ -61,7 +61,7 @@ use types::{typenum::U4294967296, *};
// 4th September 2019 // 4th September 2019
pub const HARNESS_GENESIS_TIME: u64 = 1_567_552_690; pub const HARNESS_GENESIS_TIME: u64 = 1_567_552_690;
// Environment variable to read if `fork_from_env` feature is enabled. // Environment variable to read if `fork_from_env` feature is enabled.
const FORK_NAME_ENV_VAR: &str = "FORK_NAME"; pub const FORK_NAME_ENV_VAR: &str = "FORK_NAME";
// Default target aggregators to set during testing, this ensures an aggregator at each slot. // Default target aggregators to set during testing, this ensures an aggregator at each slot.
// //

View File

@@ -3,7 +3,10 @@
//! determines whether attestations should be aggregated and/or passed to the beacon node. //! determines whether attestations should be aggregated and/or passed to the beacon node.
use super::SubnetServiceMessage; use super::SubnetServiceMessage;
#[cfg(any(test, feature = "deterministic_long_lived_attnets"))] #[cfg(any(
all(test, feature = "spec-mainnet"),
feature = "deterministic_long_lived_attnets"
))]
use std::collections::HashSet; use std::collections::HashSet;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::pin::Pin; use std::pin::Pin;
@@ -201,7 +204,7 @@ impl<T: BeaconChainTypes> AttestationService<T> {
} }
/// Return count of all currently subscribed subnets (long-lived **and** short-lived). /// Return count of all currently subscribed subnets (long-lived **and** short-lived).
#[cfg(test)] #[cfg(all(test, feature = "spec-mainnet"))]
pub fn subscription_count(&self) -> usize { pub fn subscription_count(&self) -> usize {
if self.subscribe_all_subnets { if self.subscribe_all_subnets {
self.beacon_chain.spec.attestation_subnet_count as usize self.beacon_chain.spec.attestation_subnet_count as usize
@@ -225,7 +228,7 @@ impl<T: BeaconChainTypes> AttestationService<T> {
} }
/// Returns whether we are subscribed to a subnet for testing purposes. /// Returns whether we are subscribed to a subnet for testing purposes.
#[cfg(test)] #[cfg(all(test, feature = "spec-mainnet"))]
pub(crate) fn is_subscribed( pub(crate) fn is_subscribed(
&self, &self,
subnet_id: &SubnetId, subnet_id: &SubnetId,

View File

@@ -87,7 +87,7 @@ impl<T: BeaconChainTypes> SyncCommitteeService<T> {
} }
/// Return count of all currently subscribed subnets. /// Return count of all currently subscribed subnets.
#[cfg(test)] #[cfg(all(test, feature = "spec-mainnet"))]
pub fn subscription_count(&self) -> usize { pub fn subscription_count(&self) -> usize {
use types::consts::altair::SYNC_COMMITTEE_SUBNET_COUNT; use types::consts::altair::SYNC_COMMITTEE_SUBNET_COUNT;
if self.subscribe_all_subnets { if self.subscribe_all_subnets {

View File

@@ -1,3 +1,4 @@
#![cfg(feature = "spec-mainnet")]
use super::*; use super::*;
use beacon_chain::{ use beacon_chain::{
builder::{BeaconChainBuilder, Witness}, builder::{BeaconChainBuilder, Witness},

View File

@@ -1,3 +1,4 @@
#![cfg(feature = "spec-minimal")]
use std::sync::Arc; use std::sync::Arc;
use crate::service::RequestId; use crate::service::RequestId;
@@ -36,6 +37,11 @@ struct TestRig {
const D: Duration = Duration::new(0, 0); const D: Duration = Duration::new(0, 0);
enum NumBlobs {
Random,
None,
}
impl TestRig { impl TestRig {
fn test_setup(enable_log: bool) -> (BlockLookups<T>, SyncNetworkContext<T>, Self) { fn test_setup(enable_log: bool) -> (BlockLookups<T>, SyncNetworkContext<T>, Self) {
let log = build_log(slog::Level::Debug, enable_log); let log = build_log(slog::Level::Debug, enable_log);
@@ -79,12 +85,13 @@ impl TestRig {
} }
fn rand_block(&mut self, fork_name: ForkName) -> SignedBeaconBlock<E> { fn rand_block(&mut self, fork_name: ForkName) -> SignedBeaconBlock<E> {
self.rand_block_and_blobs(fork_name).0 self.rand_block_and_blobs(fork_name, NumBlobs::None).0
} }
fn rand_block_and_blobs( fn rand_block_and_blobs(
&mut self, &mut self,
fork_name: ForkName, fork_name: ForkName,
num_blobs: NumBlobs,
) -> (SignedBeaconBlock<E>, Vec<BlobSidecar<E>>) { ) -> (SignedBeaconBlock<E>, Vec<BlobSidecar<E>>) {
let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(&mut self.rng)); let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(&mut self.rng));
let mut block = let mut block =
@@ -93,7 +100,10 @@ impl TestRig {
if let Ok(message) = block.message_deneb_mut() { if let Ok(message) = block.message_deneb_mut() {
// get random number between 0 and Max Blobs // get random number between 0 and Max Blobs
let mut payload: &mut FullPayloadDeneb<E> = &mut message.body.execution_payload; let mut payload: &mut FullPayloadDeneb<E> = &mut message.body.execution_payload;
let num_blobs = rand::random::<usize>() % E::max_blobs_per_block(); let num_blobs = match num_blobs {
NumBlobs::Random => rand::random::<usize>() % E::max_blobs_per_block(),
NumBlobs::None => 0,
};
let (bundle, transactions) = execution_layer::test_utils::generate_random_blobs::<E>( let (bundle, transactions) = execution_layer::test_utils::generate_random_blobs::<E>(
num_blobs, num_blobs,
&self.harness.chain.kzg.as_ref().unwrap(), &self.harness.chain.kzg.as_ref().unwrap(),
@@ -239,16 +249,14 @@ impl TestRig {
} }
} }
macro_rules! common_tests { #[test]
($mod_name: ident, $fork_name: ident) => { fn test_single_block_lookup_happy_path() {
#[cfg(test)]
mod $mod_name {
use super::*;
#[test]
fn test_single_block_lookup_happy_path() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let block = rig.rand_block(fork_name); let block = rig.rand_block(fork_name);
let peer_id = PeerId::random(); let peer_id = PeerId::random();
@@ -256,6 +264,11 @@ macro_rules! common_tests {
// Trigger the request // Trigger the request
bl.search_block(block_root, peer_id, PeerShouldHave::BlockAndBlobs, &mut cx); bl.search_block(block_root, peer_id, PeerShouldHave::BlockAndBlobs, &mut cx);
let id = rig.expect_block_request(response_type); let id = rig.expect_block_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_block_request(ResponseType::Blob);
}
// The peer provides the correct block, should not be penalized. Now the block should be sent // The peer provides the correct block, should not be penalized. Now the block should be sent
// for processing. // for processing.
@@ -277,12 +290,16 @@ macro_rules! common_tests {
); );
rig.expect_empty_network(); rig.expect_empty_network();
assert_eq!(bl.single_block_lookups.len(), 0); assert_eq!(bl.single_block_lookups.len(), 0);
} }
#[test] #[test]
fn test_single_block_lookup_empty_response() { fn test_single_block_lookup_empty_response() {
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let block_hash = Hash256::random(); let block_hash = Hash256::random();
let peer_id = PeerId::random(); let peer_id = PeerId::random();
@@ -290,26 +307,39 @@ macro_rules! common_tests {
// Trigger the request // Trigger the request
bl.search_block(block_hash, peer_id, PeerShouldHave::BlockAndBlobs, &mut cx); bl.search_block(block_hash, peer_id, PeerShouldHave::BlockAndBlobs, &mut cx);
let id = rig.expect_block_request(response_type); let id = rig.expect_block_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_block_request(ResponseType::Blob);
}
// The peer does not have the block. It should be penalized. // The peer does not have the block. It should be penalized.
bl.single_block_lookup_response(id, peer_id, None, D, &mut cx); bl.single_block_lookup_response(id, peer_id, None, D, &mut cx);
rig.expect_penalty(); rig.expect_penalty();
rig.expect_block_request(response_type); // it should be retried rig.expect_block_request(response_type); // it should be retried
} }
#[test] #[test]
fn test_single_block_lookup_wrong_response() { fn test_single_block_lookup_wrong_response() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let block_hash = Hash256::random(); let block_hash = Hash256::random();
let peer_id = PeerId::random(); let peer_id = PeerId::random();
// Trigger the request // Trigger the request
bl.search_block(block_hash, peer_id, PeerShouldHave::BlockAndBlobs, &mut cx); bl.search_block(block_hash, peer_id, PeerShouldHave::BlockAndBlobs, &mut cx);
let id = rig.expect_block_request(response_type); let id = rig.expect_block_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_block_request(ResponseType::Blob);
}
// Peer sends something else. It should be penalized. // Peer sends something else. It should be penalized.
let bad_block = rig.rand_block(fork_name); let bad_block = rig.rand_block(fork_name);
@@ -320,32 +350,44 @@ macro_rules! common_tests {
// Send the stream termination. This should not produce an additional penalty. // Send the stream termination. This should not produce an additional penalty.
bl.single_block_lookup_response(id, peer_id, None, D, &mut cx); bl.single_block_lookup_response(id, peer_id, None, D, &mut cx);
rig.expect_empty_network(); rig.expect_empty_network();
} }
#[test] #[test]
fn test_single_block_lookup_failure() { fn test_single_block_lookup_failure() {
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let block_hash = Hash256::random(); let block_hash = Hash256::random();
let peer_id = PeerId::random(); let peer_id = PeerId::random();
// Trigger the request // Trigger the request
bl.search_block(block_hash, peer_id, PeerShouldHave::BlockAndBlobs, &mut cx); bl.search_block(block_hash, peer_id, PeerShouldHave::BlockAndBlobs, &mut cx);
let id = rig.expect_block_request(response_type); let id = rig.expect_block_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_block_request(ResponseType::Blob);
}
// The request fails. RPC failures are handled elsewhere so we should not penalize the peer. // The request fails. RPC failures are handled elsewhere so we should not penalize the peer.
bl.single_block_lookup_failed(id, &peer_id, &mut cx, RPCError::UnsupportedProtocol); bl.single_block_lookup_failed(id, &peer_id, &mut cx, RPCError::UnsupportedProtocol);
rig.expect_block_request(response_type); rig.expect_block_request(response_type);
rig.expect_empty_network(); rig.expect_empty_network();
} }
#[test] #[test]
fn test_single_block_lookup_becomes_parent_request() { fn test_single_block_lookup_becomes_parent_request() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let block = Arc::new(rig.rand_block(fork_name)); let block = Arc::new(rig.rand_block(fork_name));
let peer_id = PeerId::random(); let peer_id = PeerId::random();
@@ -357,6 +399,11 @@ macro_rules! common_tests {
&mut cx, &mut cx,
); );
let id = rig.expect_block_request(response_type); let id = rig.expect_block_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_block_request(ResponseType::Blob);
}
// The peer provides the correct block, should not be penalized. Now the block should be sent // The peer provides the correct block, should not be penalized. Now the block should be sent
// for processing. // for processing.
@@ -377,16 +424,24 @@ macro_rules! common_tests {
); );
assert_eq!(bl.single_block_lookups.len(), 1); assert_eq!(bl.single_block_lookups.len(), 1);
rig.expect_parent_request(response_type); rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
rig.expect_empty_network(); rig.expect_empty_network();
assert_eq!(bl.parent_lookups.len(), 1); assert_eq!(bl.parent_lookups.len(), 1);
} }
#[test] #[test]
fn test_parent_lookup_happy_path() { fn test_parent_lookup_happy_path() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let parent = rig.rand_block(fork_name); let parent = rig.rand_block(fork_name);
let block = rig.block_with_parent(parent.canonical_root(), fork_name); let block = rig.block_with_parent(parent.canonical_root(), fork_name);
let chain_hash = block.canonical_root(); let chain_hash = block.canonical_root();
@@ -398,6 +453,11 @@ macro_rules! common_tests {
// Trigger the request // Trigger the request
bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx); bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx);
let id = rig.expect_parent_request(response_type); let id = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
// Peer sends the right block, it should be sent for processing. Peer should not be penalized. // Peer sends the right block, it should be sent for processing. Peer should not be penalized.
bl.parent_lookup_response(id, peer_id, Some(parent.into()), D, &mut cx); bl.parent_lookup_response(id, peer_id, Some(parent.into()), D, &mut cx);
@@ -417,14 +477,17 @@ macro_rules! common_tests {
}; };
bl.parent_chain_processed(chain_hash, process_result, &mut cx); bl.parent_chain_processed(chain_hash, process_result, &mut cx);
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
} }
#[test] #[test]
fn test_parent_lookup_wrong_response() { fn test_parent_lookup_wrong_response() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let parent = rig.rand_block(fork_name); let parent = rig.rand_block(fork_name);
let block = rig.block_with_parent(parent.canonical_root(), fork_name); let block = rig.block_with_parent(parent.canonical_root(), fork_name);
let chain_hash = block.canonical_root(); let chain_hash = block.canonical_root();
@@ -436,6 +499,11 @@ macro_rules! common_tests {
// Trigger the request // Trigger the request
bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx); bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx);
let id1 = rig.expect_parent_request(response_type); let id1 = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
// Peer sends the wrong block, peer should be penalized and the block re-requested. // Peer sends the wrong block, peer should be penalized and the block re-requested.
let bad_block = rig.rand_block(fork_name); let bad_block = rig.rand_block(fork_name);
@@ -464,14 +532,17 @@ macro_rules! common_tests {
}; };
bl.parent_chain_processed(chain_hash, process_result, &mut cx); bl.parent_chain_processed(chain_hash, process_result, &mut cx);
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
} }
#[test] #[test]
fn test_parent_lookup_empty_response() { fn test_parent_lookup_empty_response() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let parent = rig.rand_block(fork_name); let parent = rig.rand_block(fork_name);
let block = rig.block_with_parent(parent.canonical_root(), fork_name); let block = rig.block_with_parent(parent.canonical_root(), fork_name);
let chain_hash = block.canonical_root(); let chain_hash = block.canonical_root();
@@ -483,6 +554,11 @@ macro_rules! common_tests {
// Trigger the request // Trigger the request
bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx); bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx);
let id1 = rig.expect_parent_request(response_type); let id1 = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
// Peer sends an empty response, peer should be penalized and the block re-requested. // Peer sends an empty response, peer should be penalized and the block re-requested.
bl.parent_lookup_response(id1, peer_id, None, D, &mut cx); bl.parent_lookup_response(id1, peer_id, None, D, &mut cx);
@@ -506,14 +582,17 @@ macro_rules! common_tests {
}; };
bl.parent_chain_processed(chain_hash, process_result, &mut cx); bl.parent_chain_processed(chain_hash, process_result, &mut cx);
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
} }
#[test] #[test]
fn test_parent_lookup_rpc_failure() { fn test_parent_lookup_rpc_failure() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let parent = rig.rand_block(fork_name); let parent = rig.rand_block(fork_name);
let block = rig.block_with_parent(parent.canonical_root(), fork_name); let block = rig.block_with_parent(parent.canonical_root(), fork_name);
let chain_hash = block.canonical_root(); let chain_hash = block.canonical_root();
@@ -525,6 +604,11 @@ macro_rules! common_tests {
// Trigger the request // Trigger the request
bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx); bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx);
let id1 = rig.expect_parent_request(response_type); let id1 = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
// The request fails. It should be tried again. // The request fails. It should be tried again.
bl.parent_lookup_failed( bl.parent_lookup_failed(
@@ -555,14 +639,17 @@ macro_rules! common_tests {
}; };
bl.parent_chain_processed(chain_hash, process_result, &mut cx); bl.parent_chain_processed(chain_hash, process_result, &mut cx);
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
} }
#[test] #[test]
fn test_parent_lookup_too_many_attempts() { fn test_parent_lookup_too_many_attempts() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let parent = rig.rand_block(fork_name); let parent = rig.rand_block(fork_name);
let block = rig.block_with_parent(parent.canonical_root(), fork_name); let block = rig.block_with_parent(parent.canonical_root(), fork_name);
let peer_id = PeerId::random(); let peer_id = PeerId::random();
@@ -574,6 +661,11 @@ macro_rules! common_tests {
bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx); bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx);
for i in 1..=parent_lookup::PARENT_FAIL_TOLERANCE { for i in 1..=parent_lookup::PARENT_FAIL_TOLERANCE {
let id = rig.expect_parent_request(response_type); let id = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) && i == 1 {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
match i % 2 { match i % 2 {
// make sure every error is accounted for // make sure every error is accounted for
0 => { 0 => {
@@ -591,13 +683,7 @@ macro_rules! common_tests {
_ => { _ => {
// Send a bad block this time. It should be tried again. // Send a bad block this time. It should be tried again.
let bad_block = rig.rand_block(fork_name); let bad_block = rig.rand_block(fork_name);
bl.parent_lookup_response( bl.parent_lookup_response(id, peer_id, Some(bad_block.into()), D, &mut cx);
id,
peer_id,
Some(bad_block.into()),
D,
&mut cx,
);
// Send the stream termination // Send the stream termination
bl.parent_lookup_response(id, peer_id, None, D, &mut cx); bl.parent_lookup_response(id, peer_id, None, D, &mut cx);
rig.expect_penalty(); rig.expect_penalty();
@@ -609,14 +695,17 @@ macro_rules! common_tests {
} }
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
} }
#[test] #[test]
fn test_parent_lookup_too_many_download_attempts_no_blacklist() { fn test_parent_lookup_too_many_download_attempts_no_blacklist() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let parent = rig.rand_block(fork_name); let parent = rig.rand_block(fork_name);
let block = rig.block_with_parent(parent.canonical_root(), fork_name); let block = rig.block_with_parent(parent.canonical_root(), fork_name);
let block_hash = block.canonical_root(); let block_hash = block.canonical_root();
@@ -630,6 +719,11 @@ macro_rules! common_tests {
for i in 1..=parent_lookup::PARENT_FAIL_TOLERANCE { for i in 1..=parent_lookup::PARENT_FAIL_TOLERANCE {
assert!(!bl.failed_chains.contains(&block_hash)); assert!(!bl.failed_chains.contains(&block_hash));
let id = rig.expect_parent_request(response_type); let id = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) && i == 1 {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
if i % 2 != 0 { if i % 2 != 0 {
// The request fails. It should be tried again. // The request fails. It should be tried again.
bl.parent_lookup_failed( bl.parent_lookup_failed(
@@ -655,14 +749,17 @@ macro_rules! common_tests {
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
assert!(!bl.failed_chains.contains(&block_hash)); assert!(!bl.failed_chains.contains(&block_hash));
assert!(!bl.failed_chains.contains(&parent.canonical_root())); assert!(!bl.failed_chains.contains(&parent.canonical_root()));
} }
#[test] #[test]
fn test_parent_lookup_too_many_processing_attempts_must_blacklist() { fn test_parent_lookup_too_many_processing_attempts_must_blacklist() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
const PROCESSING_FAILURES: u8 = parent_lookup::PARENT_FAIL_TOLERANCE / 2 + 1; const PROCESSING_FAILURES: u8 = parent_lookup::PARENT_FAIL_TOLERANCE / 2 + 1;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let parent = Arc::new(rig.rand_block(fork_name)); let parent = Arc::new(rig.rand_block(fork_name));
let block = rig.block_with_parent(parent.canonical_root(), fork_name); let block = rig.block_with_parent(parent.canonical_root(), fork_name);
@@ -675,8 +772,13 @@ macro_rules! common_tests {
bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx); bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx);
// Fail downloading the block // Fail downloading the block
for _ in 0..(parent_lookup::PARENT_FAIL_TOLERANCE - PROCESSING_FAILURES) { for i in 0..(parent_lookup::PARENT_FAIL_TOLERANCE - PROCESSING_FAILURES) {
let id = rig.expect_parent_request(response_type); let id = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) && i == 0 {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
// The request fails. It should be tried again. // The request fails. It should be tried again.
bl.parent_lookup_failed( bl.parent_lookup_failed(
id, id,
@@ -692,6 +794,8 @@ macro_rules! common_tests {
// Now fail processing a block in the parent request // Now fail processing a block in the parent request
for _ in 0..PROCESSING_FAILURES { for _ in 0..PROCESSING_FAILURES {
let id = dbg!(rig.expect_parent_request(response_type)); let id = dbg!(rig.expect_parent_request(response_type));
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
assert!(!bl.failed_chains.contains(&block_root)); assert!(!bl.failed_chains.contains(&block_root));
// send the right parent but fail processing // send the right parent but fail processing
bl.parent_lookup_response(id, peer_id, Some(parent.clone()), D, &mut cx); bl.parent_lookup_response(id, peer_id, Some(parent.clone()), D, &mut cx);
@@ -707,16 +811,18 @@ macro_rules! common_tests {
assert!(bl.failed_chains.contains(&block_root)); assert!(bl.failed_chains.contains(&block_root));
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
} }
#[test] #[test]
fn test_parent_lookup_too_deep() { fn test_parent_lookup_too_deep() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let mut blocks = Vec::<Arc<SignedBeaconBlock<E>>>::with_capacity( let fork_name = rig
parent_lookup::PARENT_DEPTH_TOLERANCE, .harness
); .spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let mut blocks =
Vec::<Arc<SignedBeaconBlock<E>>>::with_capacity(parent_lookup::PARENT_DEPTH_TOLERANCE);
while blocks.len() < parent_lookup::PARENT_DEPTH_TOLERANCE { while blocks.len() < parent_lookup::PARENT_DEPTH_TOLERANCE {
let parent = blocks let parent = blocks
.last() .last()
@@ -742,6 +848,12 @@ macro_rules! common_tests {
for block in blocks.into_iter().rev() { for block in blocks.into_iter().rev() {
let id = rig.expect_parent_request(response_type); let id = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
dbg!("here");
let _ = rig.expect_parent_request(ResponseType::Blob);
}
// the block // the block
bl.parent_lookup_response(id, peer_id, Some(block.clone()), D, &mut cx); bl.parent_lookup_response(id, peer_id, Some(block.clone()), D, &mut cx);
// the stream termination // the stream termination
@@ -759,13 +871,16 @@ macro_rules! common_tests {
rig.expect_penalty(); rig.expect_penalty();
assert!(bl.failed_chains.contains(&chain_hash)); assert!(bl.failed_chains.contains(&chain_hash));
} }
#[test] #[test]
fn test_parent_lookup_disconnection() { fn test_parent_lookup_disconnection() {
let fork_name = ForkName::$fork_name;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let trigger_block = rig.rand_block(fork_name); let trigger_block = rig.rand_block(fork_name);
let trigger_block_root = trigger_block.canonical_root(); let trigger_block_root = trigger_block.canonical_root();
let trigger_parent_root = trigger_block.parent_root(); let trigger_parent_root = trigger_block.parent_root();
@@ -780,14 +895,17 @@ macro_rules! common_tests {
bl.peer_disconnected(&peer_id, &mut cx); bl.peer_disconnected(&peer_id, &mut cx);
assert!(bl.parent_lookups.is_empty()); assert!(bl.parent_lookups.is_empty());
} }
#[test] #[test]
fn test_single_block_lookup_ignored_response() { fn test_single_block_lookup_ignored_response() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let block = rig.rand_block(fork_name); let block = rig.rand_block(fork_name);
let peer_id = PeerId::random(); let peer_id = PeerId::random();
@@ -799,6 +917,11 @@ macro_rules! common_tests {
&mut cx, &mut cx,
); );
let id = rig.expect_block_request(response_type); let id = rig.expect_block_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_block_request(ResponseType::Blob);
}
// The peer provides the correct block, should not be penalized. Now the block should be sent // The peer provides the correct block, should not be penalized. Now the block should be sent
// for processing. // for processing.
@@ -813,22 +936,20 @@ macro_rules! common_tests {
// after processing. // after processing.
bl.single_block_lookup_response(id, peer_id, None, D, &mut cx); bl.single_block_lookup_response(id, peer_id, None, D, &mut cx);
// Send an Ignored response, the request should be dropped // Send an Ignored response, the request should be dropped
bl.single_block_processed( bl.single_block_processed(id, BlockProcessingResult::Ignored, response_type, &mut cx);
id,
BlockProcessingResult::Ignored,
response_type,
&mut cx,
);
rig.expect_empty_network(); rig.expect_empty_network();
assert_eq!(bl.single_block_lookups.len(), 0); assert_eq!(bl.single_block_lookups.len(), 0);
} }
#[test] #[test]
fn test_parent_lookup_ignored_response() { fn test_parent_lookup_ignored_response() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
let parent = rig.rand_block(fork_name); let parent = rig.rand_block(fork_name);
let block = rig.block_with_parent(parent.canonical_root(), fork_name); let block = rig.block_with_parent(parent.canonical_root(), fork_name);
let chain_hash = block.canonical_root(); let chain_hash = block.canonical_root();
@@ -841,6 +962,12 @@ macro_rules! common_tests {
bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx); bl.search_parent(slot, block_root, parent_root, peer_id, &mut cx);
let id = rig.expect_parent_request(response_type); let id = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
// Peer sends the right block, it should be sent for processing. Peer should not be penalized. // Peer sends the right block, it should be sent for processing. Peer should not be penalized.
bl.parent_lookup_response(id, peer_id, Some(parent.into()), D, &mut cx); bl.parent_lookup_response(id, peer_id, Some(parent.into()), D, &mut cx);
rig.expect_block_process(response_type); rig.expect_block_process(response_type);
@@ -855,15 +982,18 @@ macro_rules! common_tests {
); );
rig.expect_empty_network(); rig.expect_empty_network();
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
} }
/// This is a regression test. /// This is a regression test.
#[test] #[test]
fn test_same_chain_race_condition() { fn test_same_chain_race_condition() {
let fork_name = ForkName::$fork_name;
let response_type = ResponseType::Block; let response_type = ResponseType::Block;
let (mut bl, mut cx, mut rig) = TestRig::test_setup(true); let (mut bl, mut cx, mut rig) = TestRig::test_setup(true);
let fork_name = rig
.harness
.spec
.fork_name_at_slot::<E>(rig.harness.chain.slot().unwrap());
#[track_caller] #[track_caller]
fn parent_lookups_consistency(bl: &BlockLookups<T>) { fn parent_lookups_consistency(bl: &BlockLookups<T>) {
let hashes: Vec<_> = bl let hashes: Vec<_> = bl
@@ -910,6 +1040,11 @@ macro_rules! common_tests {
for (i, block) in blocks.into_iter().rev().enumerate() { for (i, block) in blocks.into_iter().rev().enumerate() {
let id = rig.expect_parent_request(response_type); let id = rig.expect_parent_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
if matches!(fork_name, ForkName::Deneb) {
let _ = rig.expect_parent_request(ResponseType::Blob);
}
// the block // the block
bl.parent_lookup_response(id, peer_id, Some(block.clone()), D, &mut cx); bl.parent_lookup_response(id, peer_id, Some(block.clone()), D, &mut cx);
// the stream termination // the stream termination
@@ -958,28 +1093,38 @@ macro_rules! common_tests {
}; };
bl.parent_chain_processed(chain_hash, process_result, &mut cx); bl.parent_chain_processed(chain_hash, process_result, &mut cx);
assert_eq!(bl.parent_lookups.len(), 0); assert_eq!(bl.parent_lookups.len(), 0);
}
}
};
} }
common_tests!(base, Base);
common_tests!(capella, Capella);
common_tests!(deneb, Deneb);
mod deneb_only { mod deneb_only {
use super::*; use super::*;
use std::str::FromStr;
fn get_fork_name() -> ForkName {
ForkName::from_str(
&std::env::var(beacon_chain::test_utils::FORK_NAME_ENV_VAR).unwrap_or_else(|e| {
panic!(
"{} env var must be defined when using fork_from_env: {:?}",
beacon_chain::test_utils::FORK_NAME_ENV_VAR,
e
)
}),
)
.unwrap()
}
#[test] #[test]
fn test_single_block_lookup_happy_path() { fn test_single_block_lookup_happy_path() {
let fork_name = ForkName::Deneb; let fork_name = get_fork_name();
if !matches!(fork_name, ForkName::Deneb) {
return;
}
let (mut bl, mut cx, mut rig) = TestRig::test_setup(false); let (mut bl, mut cx, mut rig) = TestRig::test_setup(false);
rig.harness rig.harness
.chain .chain
.slot_clock .slot_clock
.set_slot(E::slots_per_epoch() * rig.harness.spec.deneb_fork_epoch.unwrap().as_u64()); .set_slot(E::slots_per_epoch() * rig.harness.spec.deneb_fork_epoch.unwrap().as_u64());
let (block, blobs) = rig.rand_block_and_blobs(fork_name); let (block, blobs) = rig.rand_block_and_blobs(fork_name, NumBlobs::Random);
let slot = block.slot(); let slot = block.slot();
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let block_root = block.canonical_root(); let block_root = block.canonical_root();