From dfa7d0b92b9288d862b075acd10515176571d58f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Thu, 2 Dec 2021 16:19:36 +1100 Subject: [PATCH] Add simple invalidation test --- .../tests/payload_invalidation.rs | 79 ++++++++++++++++--- .../src/test_utils/handle_rpc.rs | 10 +++ .../execution_layer/src/test_utils/mod.rs | 5 ++ 3 files changed, 81 insertions(+), 13 deletions(-) diff --git a/beacon_node/beacon_chain/tests/payload_invalidation.rs b/beacon_node/beacon_chain/tests/payload_invalidation.rs index e9432f333de..4d89134495f 100644 --- a/beacon_node/beacon_chain/tests/payload_invalidation.rs +++ b/beacon_node/beacon_chain/tests/payload_invalidation.rs @@ -11,9 +11,11 @@ const VALIDATOR_COUNT: usize = 32; type E = MainnetEthSpec; +#[derive(PartialEq)] enum Payload { Valid, - Invalid, + Invalid { latest_valid_hash: Option }, + Syncing, } struct InvalidPayloadRig { @@ -45,6 +47,23 @@ impl InvalidPayloadRig { } } + fn block_hash(&self, block_root: Hash256) -> Hash256 { + self.harness + .chain + .get_block(&block_root) + .unwrap() + .unwrap() + .message() + .body() + .execution_payload() + .unwrap() + .block_hash + } + + fn fork_choice(&self) { + self.harness.chain.fork_choice().unwrap(); + } + fn move_to_terminal_block(&self) { let mock_execution_layer = self.harness.mock_execution_layer.as_ref().unwrap(); mock_execution_layer @@ -64,22 +83,23 @@ impl InvalidPayloadRig { let block_root = block.canonical_root(); match is_valid { - Payload::Valid => { - mock_execution_layer.server.full_payload_verification(); + Payload::Valid | Payload::Syncing => { + if is_valid == Payload::Syncing { + mock_execution_layer.server.all_payloads_syncing(); + } else { + mock_execution_layer.server.full_payload_verification(); + } self.harness.process_block(slot, block.clone()).unwrap(); self.valid_blocks.insert(block_root); + // TODO: check syncing blocks are optimistic. } - Payload::Invalid => { - let parent = self - .harness - .chain - .get_block(&block.message().parent_root()) - .unwrap() - .unwrap(); - let parent_payload = parent.message().body().execution_payload().unwrap(); + Payload::Invalid { latest_valid_hash } => { + let latest_valid_hash = latest_valid_hash + .unwrap_or_else(|| self.block_hash(block.message().parent_root())); + mock_execution_layer .server - .all_payloads_invalid(parent_payload.block_hash); + .all_payloads_invalid(latest_valid_hash); match self.harness.process_block(slot, block.clone()) { Err(BlockError::ExecutionPayloadError( @@ -105,7 +125,9 @@ fn invalid_during_processing() { let roots = &[ rig.import_block(Payload::Valid), - rig.import_block(Payload::Invalid), + rig.import_block(Payload::Invalid { + latest_valid_hash: None, + }), rig.import_block(Payload::Valid), ]; @@ -117,3 +139,34 @@ fn invalid_during_processing() { let head = rig.harness.chain.head_info().unwrap(); assert_eq!(head.block_root, roots[2]); } + +#[test] +fn invalid_after_optimistic_sync() { + let mut rig = InvalidPayloadRig::new(); + rig.move_to_terminal_block(); + + let mut roots = vec![ + rig.import_block(Payload::Syncing), + rig.import_block(Payload::Syncing), + rig.import_block(Payload::Syncing), + ]; + + for root in &roots { + assert!(rig.harness.chain.get_block(root).unwrap().is_some()); + } + + // 2 should be the head. + let head = rig.harness.chain.head_info().unwrap(); + assert_eq!(head.block_root, roots[2]); + + roots.push(rig.import_block(Payload::Invalid { + latest_valid_hash: Some(rig.block_hash(roots[1])), + })); + + // Running fork choice is necessary since a block has been invalidated. + rig.fork_choice(); + + // 1 should be the head, since 2 was invalidated. + let head = rig.harness.chain.head_info().unwrap(); + assert_eq!(head.block_root, roots[1]); +} diff --git a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs index a963dfaa714..3204e023d8d 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -77,6 +77,16 @@ pub async fn handle_rpc( status: ExecutePayloadResponseStatus::Invalid { latest_valid_hash }, message: None, }, + FixedPayloadResponse::Syncing => { + // Try to import the block, ignore the response. + ctx.execution_block_generator + .write() + .execute_payload(request.into()); + ExecutePayloadResponse { + status: ExecutePayloadResponseStatus::Syncing, + message: None, + } + } }; let (status, latest_valid_hash) = match response.status { diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index b7f0b98a9f6..8fe69193cbb 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -31,6 +31,7 @@ pub enum FixedPayloadResponse { None, Valid, Invalid { latest_valid_hash: Hash256 }, + Syncing, } pub struct MockServer { @@ -130,6 +131,10 @@ impl MockServer { FixedPayloadResponse::Invalid { latest_valid_hash }; } + pub fn all_payloads_syncing(&self) { + *self.ctx.fixed_payload_response.lock() = FixedPayloadResponse::Syncing; + } + pub fn full_payload_verification(&self) { *self.ctx.fixed_payload_response.lock() = FixedPayloadResponse::None; }