referrerpolicy=no-referrer-when-downgrade

sc_network/litep2p/shim/
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//! Shim for litep2p's Bitswap implementation to make it work with `sc-network`.
20
21use futures::StreamExt;
22use litep2p::protocol::libp2p::bitswap::{
23	BitswapEvent, BitswapHandle, BlockPresenceType, Config, ResponseType, WantType,
24};
25
26use sc_client_api::BlockBackend;
27use sp_runtime::traits::Block as BlockT;
28
29use std::{future::Future, pin::Pin, sync::Arc};
30
31/// Logging target for the file.
32const LOG_TARGET: &str = "sub-libp2p::bitswap";
33
34pub struct BitswapServer<Block: BlockT> {
35	/// Bitswap handle.
36	handle: BitswapHandle,
37
38	/// Blockchain client.
39	client: Arc<dyn BlockBackend<Block> + Send + Sync>,
40}
41
42impl<Block: BlockT> BitswapServer<Block> {
43	/// Create new [`BitswapServer`].
44	pub fn new(
45		client: Arc<dyn BlockBackend<Block> + Send + Sync>,
46	) -> (Pin<Box<dyn Future<Output = ()> + Send>>, Config) {
47		let (config, handle) = Config::new();
48		let bitswap = Self { client, handle };
49
50		(Box::pin(async move { bitswap.run().await }), config)
51	}
52
53	async fn run(mut self) {
54		log::debug!(target: LOG_TARGET, "starting bitswap server");
55
56		while let Some(event) = self.handle.next().await {
57			match event {
58				BitswapEvent::Request { peer, cids } => {
59					log::debug!(target: LOG_TARGET, "handle bitswap request from {peer:?} for {cids:?}");
60
61					let response: Vec<ResponseType> = cids
62						.into_iter()
63						.map(|(cid, want_type)| {
64							let mut hash = Block::Hash::default();
65							hash.as_mut().copy_from_slice(&cid.hash().digest()[0..32]);
66							let transaction = match self.client.indexed_transaction(hash) {
67								Ok(ex) => ex,
68								Err(error) => {
69									log::error!(target: LOG_TARGET, "error retrieving transaction {hash}: {error}");
70									None
71								},
72							};
73
74							match transaction {
75								Some(transaction) => {
76									log::trace!(target: LOG_TARGET, "found cid {cid:?}, hash {hash:?}");
77
78									match want_type {
79										WantType::Block =>
80											ResponseType::Block { cid, block: transaction },
81										_ => ResponseType::Presence {
82											cid,
83											presence: BlockPresenceType::Have,
84										},
85									}
86								},
87								None => {
88									log::trace!(target: LOG_TARGET, "missing cid {cid:?}, hash {hash:?}");
89
90									ResponseType::Presence {
91										cid,
92										presence: BlockPresenceType::DontHave,
93									}
94								},
95							}
96						})
97						.collect();
98
99					self.handle.send_response(peer, response).await;
100				},
101			}
102		}
103	}
104}