Skip to content
This repository has been archived by the owner on Oct 23, 2022. It is now read-only.

Commit

Permalink
refactor: Move prefix code from rust-cid to here
Browse files Browse the repository at this point in the history
Using prefixes for creating CIDs is tightly coupled to Bitswap. Hence moving
this functionality from rust-cid [1] directly into bitswap.

[1]: https://github.com/multiformats/rust-cid/blob/fcb8ea3f48eb4eb03c85a373d3e55ba57ce49817/src/prefix.rs
  • Loading branch information
vmx authored and David Craven committed Mar 27, 2020
1 parent 6cbf679 commit d995592
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 4 deletions.
2 changes: 2 additions & 0 deletions bitswap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
9 changes: 5 additions & 4 deletions bitswap/src/ledger.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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(),
Expand Down
1 change: 1 addition & 0 deletions bitswap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod behaviour;
mod block;
mod error;
mod ledger;
mod prefix;
mod protocol;
mod strategy;

Expand Down
84 changes: 84 additions & 0 deletions bitswap/src/prefix.rs
Original file line number Diff line number Diff line change
@@ -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(),
}
}
}

0 comments on commit d995592

Please sign in to comment.