diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..d1a566a8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,138 @@ +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "base-x" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "block-buffer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cid" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "integer-encoding 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "multihash 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crunchy" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "digest" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "generic-array" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "integer-encoding" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "multibase" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "multihash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "sha1 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rust-ipfs" +version = "0.1.0" +dependencies = [ + "cid 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "multihash 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha1" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "sha2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tiny-keccak" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d55aa264e822dbafa12db4d54767aff17c6ba55ea2d8559b3e17392c7d000e5d" +"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum cid 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0e37fba0087d9f3f4e269827a55dc511abf3e440cc097a0c154ff4e6584f988" +"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" +"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +"checksum integer-encoding 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26746cbc2e680af687e88d717f20ff90079bd10fc984ad57d277cd0e37309fa5" +"checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" +"checksum multihash 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c62469025f45dee2464ef9fc845f4683c543993792c1993e7d903c17a4546b74" +"checksum sha1 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "171698ce4ec7cbb93babeb3190021b4d72e96ccb98e33d277ae4ea959d6f2d9e" +"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" +"checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" +"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" diff --git a/Cargo.toml b/Cargo.toml index 3a88876d..bf0c7d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,6 @@ authors = ["David Craven "] edition = "2018" [dependencies] +cid = "*" +multibase = "*" +multihash = "*" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..81d2037e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,121 @@ +//! IPFS node implementation +#![deny(missing_docs)] +#![deny(warnings)] +use cid::Cid; +use std::collections::HashMap; +use std::sync::Arc; + +/// Ipfs struct creates a new IPFS node and is the main entry point +/// for interacting with IPFS. +pub struct Ipfs { + blocks: HashMap, Block>, +} + +impl Ipfs { + /// Creates a new ipfs node. + pub fn new() -> Self { + Ipfs { + blocks: HashMap::new(), + } + } + + /// Puts a block into the ipfs repo. + pub fn put_block(&mut self, block: Block) -> Result { + let cid = block.cid(); + self.blocks.insert(cid.to_bytes(), block); + Ok(cid) + } + + /// Retrives a block from the ipfs repo. + pub fn get_block(&self, cid: &Cid) -> Result { + self.blocks.get(&cid.to_bytes()) + .map_or(Err(()), |block| Ok((*block).clone())) + } +} + +#[derive(Clone, Debug, PartialEq)] +/// An immutable ipfs block. +pub struct Block { + content: Arc>, +} + +impl Block { + /// Creates a new immutable ipfs block. + pub fn new(content: Vec) -> Self { + Block { content: Arc::new(content) } + } + + /// Returns the size of the block in bytes. + pub fn size(&self) -> usize { + self.content.len() + } + + /// Returns the content id of the block. + pub fn cid(&self) -> Cid { + let prefix = cid::Prefix { + version: cid::Version::V0, + codec: cid::Codec::DagProtobuf, + mh_type: multihash::Hash::SHA2256, + mh_len: 32, + }; + Cid::new_from_prefix(&prefix, &self.content) + } +} + +impl From<&str> for Block { + fn from(content: &str) -> Block { + Block::new(content.as_bytes().to_vec()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_raw_block_cid() { + let content = "hello\n".as_bytes(); + let cid = "zb2rhcc1wJn2GHDLT2YkmPq5b69cXc2xfRZZmyufbjFUfBkxr"; + let prefix = cid::Prefix { + version: cid::Version::V1, + codec: cid::Codec::Raw, + mh_type: multihash::Hash::SHA2256, + mh_len: 32, + }; + let computed_cid = Cid::new_from_prefix( + &prefix, + &content, + ).to_string(); + assert_eq!(cid, computed_cid); + } + + #[test] + fn test_dag_pb_block_cid() { + let content = "hello\n".as_bytes(); + let cid = "QmUJPTFZnR2CPGAzmfdYPghgrFtYFB6pf1BqMvqfiPDam8"; + let prefix = cid::Prefix { + version: cid::Version::V0, + codec: cid::Codec::DagProtobuf, + mh_type: multihash::Hash::SHA2256, + mh_len: 32, + }; + let computed_cid = Cid::new_from_prefix( + &prefix, + &content, + ).to_string(); + assert_eq!(cid, computed_cid); + } + + #[test] + fn test_put_and_get_block() { + let mut ipfs = Ipfs::new(); + let block = Block::from("hello block\n"); + assert_eq!(block.cid().to_string(), + "QmVNrZhKw9JwYa4YPEZVccQxfgQJq993yP78QEN28927vq"); + assert_eq!(block.size(), 12); + + let cid = ipfs.put_block(block.clone()).unwrap(); + let new_block = ipfs.get_block(&cid).unwrap(); + assert_eq!(block, new_block); + } +}