// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate 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.
// Substrate 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 Substrate. If not, see .
//! Bitswap server for substrate.
//!
//! Allows querying transactions by hash over standard bitswap protocol
//! Only supports bitswap 1.2.0.
//! CID is expected to reference 256-bit Blake2b transaction hash.
use crate::schema::bitswap::{
message::{wantlist::WantType, Block as MessageBlock, BlockPresence, BlockPresenceType},
Message as BitswapMessage,
};
use cid::Version;
use core::pin::Pin;
use futures::{
io::{AsyncRead, AsyncWrite},
Future,
};
use libp2p::{
core::{
connection::ConnectionId, upgrade, InboundUpgrade, Multiaddr, OutboundUpgrade, PeerId,
UpgradeInfo,
},
swarm::{
NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler, PollParameters,
},
};
use log::{debug, error, trace};
use prost::Message;
use sc_client_api::BlockBackend;
use sp_runtime::traits::Block as BlockT;
use std::{
collections::VecDeque,
io,
marker::PhantomData,
sync::Arc,
task::{Context, Poll},
};
use unsigned_varint::encode as varint_encode;
const LOG_TARGET: &str = "bitswap";
// Undocumented, but according to JS the bitswap messages have a max size of 512*1024 bytes
// https://github.com/ipfs/js-ipfs-bitswap/blob/
// d8f80408aadab94c962f6b88f343eb9f39fa0fcc/src/decision-engine/index.js#L16
// We set it to the same value as max substrate protocol message
const MAX_PACKET_SIZE: usize = 16 * 1024 * 1024;
// Max number of queued responses before denying requests.
const MAX_RESPONSE_QUEUE: usize = 20;
// Max number of blocks per wantlist
const MAX_WANTED_BLOCKS: usize = 16;
const PROTOCOL_NAME: &[u8] = b"/ipfs/bitswap/1.2.0";
type FutureResult = Pin> + Send>>;
/// Bitswap protocol config
#[derive(Clone, Copy, Debug, Default)]
pub struct BitswapConfig;
impl UpgradeInfo for BitswapConfig {
type Info = &'static [u8];
type InfoIter = std::iter::Once;
fn protocol_info(&self) -> Self::InfoIter {
std::iter::once(PROTOCOL_NAME)
}
}
impl InboundUpgrade for BitswapConfig
where
TSocket: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
type Output = BitswapMessage;
type Error = BitswapError;
type Future = FutureResult;
fn upgrade_inbound(self, mut socket: TSocket, _info: Self::Info) -> Self::Future {
Box::pin(async move {
let packet = upgrade::read_length_prefixed(&mut socket, MAX_PACKET_SIZE).await?;
let message: BitswapMessage = Message::decode(packet.as_slice())?;
Ok(message)
})
}
}
impl UpgradeInfo for BitswapMessage {
type Info = &'static [u8];
type InfoIter = std::iter::Once;
fn protocol_info(&self) -> Self::InfoIter {
std::iter::once(PROTOCOL_NAME)
}
}
impl OutboundUpgrade for BitswapMessage
where
TSocket: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
type Output = ();
type Error = io::Error;
type Future = FutureResult;
fn upgrade_outbound(self, mut socket: TSocket, _info: Self::Info) -> Self::Future {
Box::pin(async move {
let data = self.encode_to_vec();
upgrade::write_length_prefixed(&mut socket, data).await
})
}
}
/// Internal protocol handler event.
#[derive(Debug)]
pub enum HandlerEvent {
/// We received a `BitswapMessage` from a remote.
Request(BitswapMessage),
/// We successfully sent a `BitswapMessage`.
ResponseSent,
}
impl From for HandlerEvent {
fn from(message: BitswapMessage) -> Self {
Self::Request(message)
}
}
impl From<()> for HandlerEvent {
fn from(_: ()) -> Self {
Self::ResponseSent
}
}
/// Prefix represents all metadata of a CID, without the actual content.
#[derive(PartialEq, Eq, Clone, Debug)]
struct Prefix {
/// The version of CID.
pub version: Version,
/// The codec of CID.
pub codec: u64,
/// The multihash type of CID.
pub mh_type: u64,
/// The multihash length of CID.
pub mh_len: u8,
}
impl Prefix {
/// Convert the prefix to encoded bytes.
pub fn to_bytes(&self) -> Vec {
let mut res = Vec::with_capacity(4);
let mut buf = varint_encode::u64_buffer();
let version = varint_encode::u64(self.version.into(), &mut buf);
res.extend_from_slice(version);
let mut buf = varint_encode::u64_buffer();
let codec = varint_encode::u64(self.codec, &mut buf);
res.extend_from_slice(codec);
let mut buf = varint_encode::u64_buffer();
let mh_type = varint_encode::u64(self.mh_type, &mut buf);
res.extend_from_slice(mh_type);
let mut buf = varint_encode::u64_buffer();
let mh_len = varint_encode::u64(self.mh_len as u64, &mut buf);
res.extend_from_slice(mh_len);
res
}
}
/// Bitswap trait
pub trait BitswapT {
/// Get single indexed transaction by content hash.
///
/// Note that this will only fetch transactions
/// that are indexed by the runtime with `storage_index_transaction`.
fn indexed_transaction(
&self,
hash: ::Hash,
) -> sp_blockchain::Result