refactor: Move prefix code from rust-cid to here

Using prefixes for creating CIDs is tightly coupled to Bitswap. Hence moving
this functionality from rust-cid [1] directly into bitswap.

[1]: fcb8ea3f48/src/prefix.rs
This commit is contained in:
Volker Mische 2020-03-27 14:19:20 +01:00 committed by David Craven
parent 6cbf679644
commit d9955928bb
4 changed files with 92 additions and 4 deletions

View File

@ -17,5 +17,7 @@ libipld = "0.1.0"
libp2p-core = "0.16.0"
libp2p-swarm = "0.16.1"
log = "0.4.8"
multihash = "0.10.1"
prost = "0.6.1"
thiserror = "1.0.11"
unsigned-varint = "0.3.2"

View File

@ -1,9 +1,10 @@
use crate::bitswap_pb;
use crate::block::Block;
use crate::error::BitswapError;
use crate::prefix::Prefix;
use core::convert::TryFrom;
use core::marker::PhantomData;
use libipld::cid::{Cid, Prefix};
use libipld::cid::Cid;
use prost::Message as ProstMessage;
use std::collections::HashMap;
@ -168,7 +169,7 @@ impl Into<Vec<u8>> for &Message<O> {
}
for block in self.blocks() {
let mut payload = bitswap_pb::message::Block::default();
payload.prefix = block.cid().prefix().as_bytes();
payload.prefix = Prefix::from(block.cid()).to_bytes();
payload.data = block.data().to_vec();
proto.payload.push(payload);
}
@ -204,8 +205,8 @@ impl TryFrom<&[u8]> for Message<I> {
}
}
for payload in proto.payload {
let prefix = Prefix::new_from_bytes(&payload.prefix)?;
let cid = Cid::new_from_prefix(&prefix, &payload.data);
let prefix = Prefix::new(&payload.prefix)?;
let cid = prefix.to_cid(&payload.data)?;
let block = Block {
cid,
data: payload.data.to_vec().into_boxed_slice(),

View File

@ -6,6 +6,7 @@ mod behaviour;
mod block;
mod error;
mod ledger;
mod prefix;
mod protocol;
mod strategy;

84
bitswap/src/prefix.rs Normal file
View File

@ -0,0 +1,84 @@
use std::convert::TryFrom;
use libipld::cid::{self, Cid, Codec, Version};
use multihash::Code;
use unsigned_varint::{decode as varint_decode, encode as varint_encode};
/// Prefix represents all metadata of a CID, without the actual content.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Prefix {
/// The version of CID.
pub version: Version,
/// The codec of CID.
pub codec: Codec,
/// The multihash type of CID.
pub mh_type: Code,
/// The multihash length of CID.
pub mh_len: usize,
}
impl Prefix {
/// Create a new prefix from encoded bytes.
pub fn new(data: &[u8]) -> Result<Prefix, cid::Error> {
let (raw_version, remain) = varint_decode::u64(data)?;
let version = Version::try_from(raw_version)?;
let (raw_codec, remain) = varint_decode::u64(remain)?;
let codec = Codec::try_from(raw_codec)?;
let (raw_mh_type, remain) = varint_decode::u64(remain)?;
let mh_type = match multihash::Code::from_u64(raw_mh_type) {
multihash::Code::Custom(_) => return Err(cid::Error::UnknownCodec),
code => code,
};
let (mh_len, _remain) = varint_decode::usize(remain)?;
Ok(Prefix {
version,
codec,
mh_type,
mh_len,
})
}
/// Convert the prefix to encoded bytes.
pub fn to_bytes(&self) -> Vec<u8> {
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.into(), &mut buf);
res.extend_from_slice(codec);
let mut buf = varint_encode::u64_buffer();
let mh_type = varint_encode::u64(self.mh_type.to_u64(), &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
}
/// Create a CID out of the prefix and some data that will be hashed
pub fn to_cid(&self, data: &[u8]) -> Result<Cid, cid::Error> {
let mut hash = self.mh_type.hasher().unwrap().digest(data);
if self.mh_len < hash.digest().len() {
hash = multihash::wrap(hash.algorithm(), &hash.digest()[..self.mh_len]);
}
Cid::new(self.version, self.codec, hash)
}
}
impl From<&Cid> for Prefix {
fn from(cid: &Cid) -> Self {
Self {
version: cid.version(),
codec: cid.codec(),
mh_type: cid.hash().algorithm(),
mh_len: cid.hash().digest().len(),
}
}
}