diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index aba9be326..4d086fcdf 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -957,22 +957,24 @@ impl BeaconChain { &self, block_root: &Hash256, ) -> Result< - ( - Option>>, - Option>>, - ), + Option<( + Arc>, + Arc>, + )>, Error, > { if let (Some(block), Some(blobs)) = ( self.early_attester_cache.get_block(*block_root), self.early_attester_cache.get_blobs(*block_root), ) { - return Ok((Some(block), Some(blobs))); + return Ok(Some((block, blobs))); + } + if let Some(block) = self.get_block(block_root).await?.map(Arc::new) { + let blobs = self.get_blobs(block_root)?.map(Arc::new); + Ok(blobs.map(|blobs| (block, blobs))) + } else { + Ok(None) } - Ok(( - self.get_block(block_root).await?.map(Arc::new), - self.get_blobs(block_root)?.map(Arc::new), - )) } /// Returns the block at the given root, if any. @@ -1044,8 +1046,8 @@ impl BeaconChain { /// Returns the blobs at the given root, if any. /// - /// Returns `Ok(None)` if the blobs are not found. This could indicate the blob has been pruned - /// or that the block it is referenced by doesn't exist in our database. + /// Returns `Ok(None)` if the blobs and associated block are not found. The block referenced by + /// the blob doesn't exist in our database. /// /// If we can find the corresponding block in our database, we know whether we *should* have /// blobs. If we should have blobs and no blobs are found, this will error. If we shouldn't, @@ -1055,6 +1057,7 @@ impl BeaconChain { /// - any database read errors /// - block and blobs are inconsistent in the database /// - this method is called with a pre-eip4844 block root + /// - this method is called for a blob that is beyond the prune depth pub fn get_blobs( &self, block_root: &Hash256, @@ -1073,10 +1076,7 @@ impl BeaconChain { Err(_) => return Err(Error::NoKzgCommitmentsFieldOnBlock), }; if expected_kzg_commitments.is_empty() { - Ok(Some(BlobsSidecar::empty_from_parts( - *block_root, - block.slot(), - ))) + Ok(BlobsSidecar::empty_from_parts(*block_root, block.slot())) } else { if let Some(boundary) = self.data_availability_boundary() { // We should have blobs for all blocks younger than the boundary. @@ -1084,11 +1084,10 @@ impl BeaconChain { return Err(Error::BlobsUnavailable); } } - Err(Error::BlobsOlderThanDataAvailabilityBoundary) + Err(Error::BlobsOlderThanDataAvailabilityBoundary(block.epoch())) } }) .transpose() - .map(Option::flatten) } } } diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index 9a9b09fe1..fcb2c53a4 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -211,7 +211,7 @@ pub enum BeaconChainError { ProposerHeadForkChoiceError(fork_choice::Error), BlobsUnavailable, NoKzgCommitmentsFieldOnBlock, - BlobsOlderThanDataAvailabilityBoundary, + BlobsOlderThanDataAvailabilityBoundary(Epoch), } easy_from_to!(SlotProcessingError, BeaconChainError); diff --git a/beacon_node/lighthouse_network/src/peer_manager/mod.rs b/beacon_node/lighthouse_network/src/peer_manager/mod.rs index f0ccc72af..9176f16f2 100644 --- a/beacon_node/lighthouse_network/src/peer_manager/mod.rs +++ b/beacon_node/lighthouse_network/src/peer_manager/mod.rs @@ -513,6 +513,7 @@ impl PeerManager { Protocol::MetaData => PeerAction::LowToleranceError, Protocol::Status => PeerAction::LowToleranceError, }, + RPCResponseErrorCode::BlobsNotFoundForBlock => PeerAction::LowToleranceError, }, RPCError::SSZDecodeError(_) => PeerAction::Fatal, RPCError::UnsupportedProtocol => { diff --git a/beacon_node/lighthouse_network/src/rpc/methods.rs b/beacon_node/lighthouse_network/src/rpc/methods.rs index 8ee427da5..7563b8f13 100644 --- a/beacon_node/lighthouse_network/src/rpc/methods.rs +++ b/beacon_node/lighthouse_network/src/rpc/methods.rs @@ -330,6 +330,7 @@ pub struct LightClientBootstrapRequest { #[strum(serialize_all = "snake_case")] pub enum RPCResponseErrorCode { RateLimited, + BlobsNotFoundForBlock, InvalidRequest, ServerError, /// Error spec'd to indicate that a peer does not have blocks on a requested range. @@ -359,6 +360,7 @@ impl RPCCodedResponse { 2 => RPCResponseErrorCode::ServerError, 3 => RPCResponseErrorCode::ResourceUnavailable, 139 => RPCResponseErrorCode::RateLimited, + 142 => RPCResponseErrorCode::BlobsNotFoundForBlock, _ => RPCResponseErrorCode::Unknown, }; RPCCodedResponse::Error(code, err) @@ -397,6 +399,7 @@ impl RPCResponseErrorCode { RPCResponseErrorCode::ResourceUnavailable => 3, RPCResponseErrorCode::Unknown => 255, RPCResponseErrorCode::RateLimited => 139, + RPCResponseErrorCode::BlobsNotFoundForBlock => 140, } } } @@ -425,6 +428,7 @@ impl std::fmt::Display for RPCResponseErrorCode { RPCResponseErrorCode::ServerError => "Server error occurred", RPCResponseErrorCode::Unknown => "Unknown error occurred", RPCResponseErrorCode::RateLimited => "Rate limited", + RPCResponseErrorCode::BlobsNotFoundForBlock => "No blobs for the given root", }; f.write_str(repr) } diff --git a/beacon_node/network/src/beacon_processor/worker/rpc_methods.rs b/beacon_node/network/src/beacon_processor/worker/rpc_methods.rs index f08dac547..d9a3c2eea 100644 --- a/beacon_node/network/src/beacon_processor/worker/rpc_methods.rs +++ b/beacon_node/network/src/beacon_processor/worker/rpc_methods.rs @@ -230,7 +230,7 @@ impl Worker { .get_block_and_blobs_checking_early_attester_cache(root) .await { - Ok((Some(block), Some(blobs))) => { + Ok(Some((block, blobs))) => { self.send_response( peer_id, Response::BlobsByRoot(Some(SignedBeaconBlockAndBlobsSidecar { @@ -241,7 +241,7 @@ impl Worker { ); send_block_count += 1; } - Ok((None, None)) => { + Ok(None) => { debug!( self.log, "Peer requested unknown block and blobs"; @@ -249,9 +249,41 @@ impl Worker { "request_root" => ?root ); } - Ok((Some(block), None)) => { + Err(BeaconChainError::BlobsUnavailable) => { + error!( + self.log, + "No blobs in the store for block root"; + "request" => %request, + "peer" => %peer_id, + "block_root" => ?root + ); + self.send_error_response( + peer_id, + RPCResponseErrorCode::BlobsNotFoundForBlock, + "Blobs not found for block root".into(), + request_id, + ); + send_response = false; + break; + } + Err(BeaconChainError::NoKzgCommitmentsFieldOnBlock) => { + error!( + self.log, + "No kzg_commitments field in block"; + "peer" => %peer_id, + "block_root" => ?root, + ); + self.send_error_response( + peer_id, + RPCResponseErrorCode::ResourceUnavailable, + "Failed reading field kzg_commitments from block".into(), + request_id, + ); + send_response = false; + break; + } + Err(BeaconChainError::BlobsOlderThanDataAvailabilityBoundary(block_epoch)) => { let finalized_data_availability_boundary = self.chain.finalized_data_availability_boundary(); - let block_epoch = block.epoch(); match finalized_data_availability_boundary { Some(boundary_epoch) => { @@ -264,6 +296,14 @@ impl Worker { "request_root" => ?root, "finalized_data_availability_boundary" => %boundary_epoch, ); + self.send_error_response( + peer_id, + RPCResponseErrorCode::ResourceUnavailable, + "Blobs older than data availability boundary".into(), + request_id, + ); + send_response = false; + break; } else { debug!( self.log, @@ -287,32 +327,6 @@ impl Worker { } } } - Ok((None, Some(_))) => { - error!( - self.log, - "Peer requested block and blob, but no block found"; - "request" => %request, - "peer" => %peer_id, - "request_root" => ?root - ); - } - Err(BeaconChainError::BlobsUnavailable) => { - error!( - self.log, - "No blobs in the store for block root"; - "request" => %request, - "peer" => %peer_id, - "block_root" => ?root - ); - self.send_error_response( - peer_id, - RPCResponseErrorCode::ResourceUnavailable, - "Blobs unavailable".into(), - request_id, - ); - send_response = false; - break; - } Err(BeaconChainError::BlockHashMissingFromExecutionLayer(_)) => { debug!( self.log, @@ -807,40 +821,6 @@ impl Worker { send_response = false; break; } - Err(BeaconChainError::NoKzgCommitmentsFieldOnBlock) => { - error!( - self.log, - "No kzg_commitments field in block"; - "request" => %req, - "peer" => %peer_id, - "block_root" => ?root, - ); - self.send_error_response( - peer_id, - RPCResponseErrorCode::ResourceUnavailable, - "Failed reading field kzg_commitments from block".into(), - request_id, - ); - send_response = false; - break; - } - Err(BeaconChainError::BlobsOlderThanDataAvailabilityBoundary) => { - error!( - self.log, - "Failed loading blobs older than data availability boundary"; - "request" => %req, - "peer" => %peer_id, - "block_root" => ?root, - ); - self.send_error_response( - peer_id, - RPCResponseErrorCode::ResourceUnavailable, - "Blobs older than data availability boundary".into(), - request_id, - ); - send_response = false; - break; - } Err(e) => { error!( self.log,