diff --git a/polkadot/node/core/chain-api/src/lib.rs b/polkadot/node/core/chain-api/src/lib.rs index 9a272e7d1d..b41c017cda 100644 --- a/polkadot/node/core/chain-api/src/lib.rs +++ b/polkadot/node/core/chain-api/src/lib.rs @@ -22,6 +22,7 @@ //! //! Supported requests: //! * Block hash to number +//! * Block hash to header //! * Finalized block number to hash //! * Last finalized block number //! * Ancestors @@ -85,6 +86,13 @@ where subsystem.metrics.on_request(result.is_ok()); let _ = response_channel.send(result); }, + ChainApiMessage::BlockHeader(hash, response_channel) => { + let result = subsystem.client + .header(BlockId::Hash(hash)) + .map_err(|e| e.to_string().into()); + subsystem.metrics.on_request(result.is_ok()); + let _ = response_channel.send(result); + }, ChainApiMessage::FinalizedBlockHash(number, response_channel) => { // Note: we don't verify it's finalized let result = subsystem.client.hash(number).map_err(|e| e.to_string().into()); @@ -319,6 +327,30 @@ mod tests { }) } + #[test] + fn request_block_header() { + test_harness(|client, mut sender| { + async move { + const NOT_HERE: Hash = Hash::repeat_byte(0x5); + let test_cases = [ + (TWO, client.header(BlockId::Hash(TWO)).unwrap()), + (NOT_HERE, client.header(BlockId::Hash(NOT_HERE)).unwrap()), + ]; + for (hash, expected) in &test_cases { + let (tx, rx) = oneshot::channel(); + + sender.send(FromOverseer::Communication { + msg: ChainApiMessage::BlockHeader(*hash, tx), + }).await; + + assert_eq!(rx.await.unwrap().unwrap(), *expected); + } + + sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await; + }.boxed() + }) + } + #[test] fn request_finalized_hash() { test_harness(|client, mut sender| { diff --git a/polkadot/node/subsystem/src/messages.rs b/polkadot/node/subsystem/src/messages.rs index 35f92eca8a..22e9f097ff 100644 --- a/polkadot/node/subsystem/src/messages.rs +++ b/polkadot/node/subsystem/src/messages.rs @@ -31,12 +31,13 @@ use polkadot_node_primitives::{ CollationGenerationConfig, MisbehaviorReport, SignedFullStatement, ValidationResult, }; use polkadot_primitives::v1::{ - AuthorityDiscoveryId, AvailableData, BackedCandidate, BlockNumber, CandidateDescriptor, - CandidateEvent, CandidateReceipt, CollatorId, CommittedCandidateReceipt, - CoreState, ErasureChunk, GroupRotationInfo, Hash, Id as ParaId, - OccupiedCoreAssumption, PersistedValidationData, PoV, SessionIndex, SignedAvailabilityBitfield, - TransientValidationData, ValidationCode, ValidatorId, ValidationData, ValidatorIndex, - ValidatorSignature, + AuthorityDiscoveryId, AvailableData, BackedCandidate, BlockNumber, + Header as BlockHeader, CandidateDescriptor, CandidateEvent, CandidateReceipt, + CollatorId, CommittedCandidateReceipt, CoreState, ErasureChunk, + GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, + PersistedValidationData, PoV, SessionIndex, SignedAvailabilityBitfield, + TransientValidationData, ValidationCode, ValidatorId, ValidationData, + ValidatorIndex, ValidatorSignature, }; use std::sync::Arc; @@ -336,6 +337,9 @@ pub enum ChainApiMessage { /// Request the block number by hash. /// Returns `None` if a block with the given hash is not present in the db. BlockNumber(Hash, ChainApiResponseChannel>), + /// Request the block header by hash. + /// Returns `None` if a block with the given hash is not present in the db. + BlockHeader(Hash, ChainApiResponseChannel>), /// Request the finalized block hash by number. /// Returns `None` if a block with the given number is not present in the db. /// Note: the caller must ensure the block is finalized. @@ -404,10 +408,10 @@ pub enum RuntimeApiRequest { /// the block in whose state this request is executed. CandidateEvents(RuntimeApiSender>), /// Get the `AuthorityDiscoveryId`s corresponding to the given `ValidatorId`s. - /// Currently this request is limited to validators in the current session. + /// Currently this request is limited to validators in the current session. /// /// Returns `None` for validators not found in the current session. - ValidatorDiscovery(Vec, RuntimeApiSender>>), + ValidatorDiscovery(Vec, RuntimeApiSender>>), } /// A message to the Runtime API subsystem. diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/chain-api.md b/polkadot/roadmap/implementers-guide/src/node/utility/chain-api.md index 6469db262a..7695b73a05 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/chain-api.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/chain-api.md @@ -14,6 +14,7 @@ On receipt of `ChainApiMessage`, answer the request and provide the response to Currently, the following requests are supported: * Block hash to number +* Block hash to header * Finalized block number to hash * Last finalized block number * Ancestors diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index e32a17f804..ef6d847343 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -140,6 +140,9 @@ enum ChainApiMessage { /// Get the block number by hash. /// Returns `None` if a block with the given hash is not present in the db. BlockNumber(Hash, ResponseChannel, Error>>), + /// Request the block header by hash. + /// Returns `None` if a block with the given hash is not present in the db. + BlockHeader(Hash, ResponseChannel, Error>>), /// Get the finalized block hash by number. /// Returns `None` if a block with the given number is not present in the db. /// Note: the caller must ensure the block is finalized.