referrerpolicy=no-referrer-when-downgrade

sc_rpc_spec_v2/bitswap/
bitswap.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Implementation of the `bitswap_v1_get` RPC method.
20//!
21//! See <https://github.com/paritytech/json-rpc-interface-spec/blob/main/src/api/bitswap_v1_get.md>
22
23use crate::bitswap::{api::BitswapApiServer, error::Error};
24use cid::Cid;
25use jsonrpsee::core::RpcResult;
26use multihash_codetable::Code;
27use sc_client_api::BlockBackend;
28use sp_core::H256;
29use sp_runtime::traits::Block as BlockT;
30use std::sync::Arc;
31
32/// Log target for this file.
33const LOG_TARGET: &str = "rpc-spec-v2";
34
35/// Bitswap RPC implementation.
36pub struct Bitswap<Block, Client> {
37	client: Arc<Client>,
38	sync_oracle: Arc<dyn sp_consensus::SyncOracle + Send + Sync>,
39	_phantom: std::marker::PhantomData<Block>,
40}
41
42impl<Block, Client> Bitswap<Block, Client> {
43	/// Creates a new [`Bitswap`] instance.
44	pub fn new(
45		client: Arc<Client>,
46		sync_oracle: Arc<dyn sp_consensus::SyncOracle + Send + Sync>,
47	) -> Self {
48		Self { client, sync_oracle, _phantom: std::marker::PhantomData }
49	}
50}
51
52impl<Block, Client> BitswapApiServer for Bitswap<Block, Client>
53where
54	Block: BlockT,
55	Client: BlockBackend<Block> + Send + Sync + 'static,
56{
57	fn bitswap_v1_get(&self, cid_str: String) -> RpcResult<String> {
58		let cid = Cid::try_from(cid_str.as_str()).map_err(|e| Error::InvalidCid(format!("{e}")))?;
59
60		// Only CIDv1 version is supported according to the spec.
61		if cid.version() != cid::Version::V1 {
62			return Err(Error::InvalidCid("Only CIDv1 is supported".into()).into());
63		}
64
65		let hash = cid.hash();
66
67		// Only sha2-256, blake2b-256 & keccak-256 hash functions are supported according to the
68		// spec.
69		if hash.code() != u64::from(Code::Sha2_256) &&
70			hash.code() != u64::from(Code::Blake2b256) &&
71			hash.code() != u64::from(Code::Keccak256)
72		{
73			return Err(Error::InvalidCid(
74				"Only sha2-256, blake2b-256 & keccak-256 hash functions are supported".into(),
75			)
76			.into());
77		}
78
79		// `H256::from_slice` panics below if the size is incorrect, so double-check the size is
80		// correct, even though we checked the hash function type above.
81		if hash.size() != 32 {
82			return Err(Error::InvalidCid("Only 256-bit hash digests are supported".into()).into());
83		}
84
85		let digest = H256::from_slice(hash.digest());
86
87		match self.client.indexed_transaction(digest) {
88			Ok(Some(data)) => Ok(crate::hex_string(&data)),
89			Ok(None) => {
90				if self.sync_oracle.is_major_syncing() {
91					Err(Error::MajorSyncing.into())
92				} else {
93					Err(Error::NotFound.into())
94				}
95			},
96			Err(err) => {
97				// Note: this never happens in practice, because `indexed_transaction`
98				// implementation in `substrate/client/db` always returns Ok(_), and is only
99				// needed to handle possible future API changes.
100				log::warn!(target: LOG_TARGET, "Indexed transaction fetch failed: {err:?}");
101
102				Err(Error::Internal(err).into())
103			},
104		}
105	}
106}