diff --git a/substrate/client/rpc-spec-v2/src/archive/api.rs b/substrate/client/rpc-spec-v2/src/archive/api.rs
new file mode 100644
index 000000000000..ca94779c887c
--- /dev/null
+++ b/substrate/client/rpc-spec-v2/src/archive/api.rs
@@ -0,0 +1,56 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+//! API trait of the archive methods.
+
+use jsonrpsee::{core::RpcResult, proc_macros::rpc};
+
+#[rpc(client, server)]
+pub trait ArchiveApi {
+ /// Retrieves the body (list of transactions) of a given block hash.
+ ///
+ /// Returns an array of strings containing the hexadecimal-encoded SCALE-codec-encoded
+ /// transactions in that block. If no block with that hash is found, null.
+ ///
+ /// # Unstable
+ ///
+ /// This method is unstable and subject to change in the future.
+ #[method(name = "archive_unstable_body")]
+ fn archive_unstable_body(&self, hash: Hash) -> RpcResult>>;
+
+ /// Get the chain's genesis hash.
+ ///
+ /// Returns a string containing the hexadecimal-encoded hash of the genesis block of the chain.
+ ///
+ /// # Unstable
+ ///
+ /// This method is unstable and subject to change in the future.
+ #[method(name = "archive_unstable_genesisHash")]
+ fn archive_unstable_genesis_hash(&self) -> RpcResult;
+
+ /// Get the block's header.
+ ///
+ /// Returns a string containing the hexadecimal-encoded SCALE-codec encoding header of the
+ /// block.
+ ///
+ /// # Unstable
+ ///
+ /// This method is unstable and subject to change in the future.
+ #[method(name = "archive_unstable_header")]
+ fn archive_unstable_header(&self, hash: Hash) -> RpcResult>;
+}
diff --git a/substrate/client/rpc-spec-v2/src/archive/archive.rs b/substrate/client/rpc-spec-v2/src/archive/archive.rs
new file mode 100644
index 000000000000..4fb2e5671d30
--- /dev/null
+++ b/substrate/client/rpc-spec-v2/src/archive/archive.rs
@@ -0,0 +1,86 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+//! API implementation for `archive`.
+
+use super::ArchiveApiServer;
+use crate::chain_head::hex_string;
+use codec::Encode;
+use jsonrpsee::core::{async_trait, RpcResult};
+use sc_client_api::{Backend, BlockBackend, BlockchainEvents, ExecutorProvider, StorageProvider};
+use sp_api::CallApiAt;
+use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
+use sp_runtime::traits::Block as BlockT;
+use std::{marker::PhantomData, sync::Arc};
+
+/// An API for archive RPC calls.
+pub struct Archive, Block: BlockT, Client> {
+ /// Substrate client.
+ client: Arc,
+ /// The hexadecimal encoded hash of the genesis block.
+ genesis_hash: String,
+ /// Phantom member to pin the block type.
+ _phantom: PhantomData<(Block, BE)>,
+}
+
+impl, Block: BlockT, Client> Archive {
+ /// Create a new [`Archive`].
+ pub fn new>(client: Arc, genesis_hash: GenesisHash) -> Self {
+ let genesis_hash = hex_string(&genesis_hash.as_ref());
+ Self { client, genesis_hash, _phantom: PhantomData }
+ }
+}
+
+#[async_trait]
+impl ArchiveApiServer for Archive
+where
+ Block: BlockT + 'static,
+ Block::Header: Unpin,
+ BE: Backend + 'static,
+ Client: BlockBackend
+ + ExecutorProvider
+ + HeaderBackend
+ + HeaderMetadata
+ + BlockchainEvents
+ + CallApiAt
+ + StorageProvider
+ + 'static,
+{
+ fn archive_unstable_body(&self, hash: Block::Hash) -> RpcResult>> {
+ let Ok(Some(signed_block)) = self.client.block(hash) else { return Ok(None) };
+
+ let extrinsics = signed_block
+ .block
+ .extrinsics()
+ .iter()
+ .map(|extrinsic| hex_string(&extrinsic.encode()))
+ .collect();
+
+ Ok(Some(extrinsics))
+ }
+
+ fn archive_unstable_genesis_hash(&self) -> RpcResult {
+ Ok(self.genesis_hash.clone())
+ }
+
+ fn archive_unstable_header(&self, hash: Block::Hash) -> RpcResult> {
+ let Ok(Some(header)) = self.client.header(hash) else { return Ok(None) };
+
+ Ok(Some(hex_string(&header.encode())))
+ }
+}
diff --git a/substrate/client/rpc-spec-v2/src/archive/mod.rs b/substrate/client/rpc-spec-v2/src/archive/mod.rs
new file mode 100644
index 000000000000..767f658ecd75
--- /dev/null
+++ b/substrate/client/rpc-spec-v2/src/archive/mod.rs
@@ -0,0 +1,31 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+//! Substrate archive API.
+//!
+//! # Note
+//!
+//! Methods are prefixed by `archive`.
+
+#[cfg(test)]
+mod tests;
+
+pub mod api;
+pub mod archive;
+
+pub use api::ArchiveApiServer;
diff --git a/substrate/client/rpc-spec-v2/src/archive/tests.rs b/substrate/client/rpc-spec-v2/src/archive/tests.rs
new file mode 100644
index 000000000000..bc75fc749acc
--- /dev/null
+++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs
@@ -0,0 +1,113 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+use crate::chain_head::hex_string;
+
+use super::{archive::Archive, *};
+
+use codec::{Decode, Encode};
+use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule};
+use sc_block_builder::BlockBuilderProvider;
+
+use sp_consensus::BlockOrigin;
+use std::sync::Arc;
+use substrate_test_runtime_client::{
+ prelude::*, runtime, Backend, BlockBuilderExt, Client, ClientBlockImportExt,
+};
+
+const CHAIN_GENESIS: [u8; 32] = [0; 32];
+const INVALID_HASH: [u8; 32] = [1; 32];
+
+type Header = substrate_test_runtime_client::runtime::Header;
+type Block = substrate_test_runtime_client::runtime::Block;
+
+fn setup_api() -> (Arc>, RpcModule>>) {
+ let builder = TestClientBuilder::new();
+ let client = Arc::new(builder.build());
+
+ let api = Archive::new(client.clone(), CHAIN_GENESIS).into_rpc();
+
+ (client, api)
+}
+
+#[tokio::test]
+async fn archive_genesis() {
+ let (_client, api) = setup_api();
+
+ let genesis: String =
+ api.call("archive_unstable_genesisHash", EmptyParams::new()).await.unwrap();
+ assert_eq!(genesis, hex_string(&CHAIN_GENESIS));
+}
+
+#[tokio::test]
+async fn archive_body() {
+ let (mut client, api) = setup_api();
+
+ // Invalid block hash.
+ let invalid_hash = hex_string(&INVALID_HASH);
+ let res: Option> = api.call("archive_unstable_body", [invalid_hash]).await.unwrap();
+ assert!(res.is_none());
+
+ // Import a new block with an extrinsic.
+ let mut builder = client.new_block(Default::default()).unwrap();
+ builder
+ .push_transfer(runtime::Transfer {
+ from: AccountKeyring::Alice.into(),
+ to: AccountKeyring::Ferdie.into(),
+ amount: 42,
+ nonce: 0,
+ })
+ .unwrap();
+ let block = builder.build().unwrap().block;
+ let block_hash = format!("{:?}", block.header.hash());
+ client.import(BlockOrigin::Own, block.clone()).await.unwrap();
+
+ let expected_tx = hex_string(&block.extrinsics[0].encode());
+
+ let body: Vec = api.call("archive_unstable_body", [block_hash]).await.unwrap();
+ assert_eq!(vec![expected_tx], body);
+}
+
+#[tokio::test]
+async fn archive_header() {
+ let (mut client, api) = setup_api();
+
+ // Invalid block hash.
+ let invalid_hash = hex_string(&INVALID_HASH);
+ let res: Option = api.call("archive_unstable_header", [invalid_hash]).await.unwrap();
+ assert!(res.is_none());
+
+ // Import a new block with an extrinsic.
+ let mut builder = client.new_block(Default::default()).unwrap();
+ builder
+ .push_transfer(runtime::Transfer {
+ from: AccountKeyring::Alice.into(),
+ to: AccountKeyring::Ferdie.into(),
+ amount: 42,
+ nonce: 0,
+ })
+ .unwrap();
+ let block = builder.build().unwrap().block;
+ let block_hash = format!("{:?}", block.header.hash());
+ client.import(BlockOrigin::Own, block.clone()).await.unwrap();
+
+ let header: String = api.call("archive_unstable_header", [block_hash]).await.unwrap();
+ let bytes = array_bytes::hex2bytes(&header).unwrap();
+ let header: Header = Decode::decode(&mut &bytes[..]).unwrap();
+ assert_eq!(header, block.header);
+}
diff --git a/substrate/client/rpc-spec-v2/src/lib.rs b/substrate/client/rpc-spec-v2/src/lib.rs
index 7c22ef5d5231..9a455c5984a5 100644
--- a/substrate/client/rpc-spec-v2/src/lib.rs
+++ b/substrate/client/rpc-spec-v2/src/lib.rs
@@ -23,6 +23,7 @@
#![warn(missing_docs)]
#![deny(unused_crate_dependencies)]
+pub mod archive;
pub mod chain_head;
pub mod chain_spec;
pub mod transaction;