1use ipfs_unixfs::file::adder::Chunker;
2use ipfs_unixfs::file::adder::FileAdder;
3
4#[derive(Debug)]
16pub struct IpfsHasher {
17 chunk_size: Option<usize>,
18}
19
20impl Default for IpfsHasher {
21 fn default() -> Self {
22 Self { chunk_size: None }
23 }
24}
25
26impl IpfsHasher {
27 #[cfg(test)]
28 pub fn new(chunk_size: usize) -> Self {
29 Self { chunk_size: Some(chunk_size) }
30 }
31
32 pub fn compute(&self, content: &[u8]) -> String {
34 let mut adder = match self.chunk_size {
35 None => FileAdder::default(),
36 Some(size) => FileAdder::builder().with_chunker(Chunker::Size(size)).build(),
37 };
38
39 let mut written = 0;
40
41 while written < content.len() {
42 let slice = &content[written..];
43 let (_blocks, pushed) = adder.push(slice);
44 written += pushed;
45 }
46
47 let res = adder.finish();
48 let (cid, _data) = res.last().unwrap();
49
50 cid.to_string()
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::IpfsHasher;
57 use wasm_loader::{OnchainBlock, Source, WasmLoader};
58
59 #[test]
60 fn it_works_with_single_block() {
61 let hasher = IpfsHasher::default();
62 let ipfs = hasher.compute(b"foobar\n");
63 assert!(ipfs.to_string() == "QmRgutAxd8t7oGkSm4wmeuByG6M51wcTso6cubDdQtuEfL");
64 }
65
66 #[test]
67 fn it_works_with_multiple_blocks() {
68 let hasher = IpfsHasher::new(2);
69 let ipfs = hasher.compute(b"foobar\n");
70 assert!(ipfs.to_string() == "QmRJHYTNvC3hmd9gJQARxLR1QMEincccBV53bBw524yyq6");
71 }
72
73 #[test]
74 #[ignore = "Onchain data..."]
75 fn it_computes_a_runtime_ipfs_hash() {
76 const POLKADOT_BLOCK20: &str = "0x4d6a0bca208b85d41833a7f35cf73d1ae6974f4bad8ab576e2c3f751d691fe6c"; let ocb = OnchainBlock::new("wss://rpc.polkadot.io", Some(POLKADOT_BLOCK20.to_string()));
79 let loader = WasmLoader::load_from_source(&Source::Chain(ocb)).unwrap();
80 let hasher = IpfsHasher::default();
81 let cid = hasher.compute(loader.bytes());
82 assert!(cid == "QmevKMGkRViXfQMSZ38DBdcJ1cXcXf9sXdfXie8Jkc7ZGs");
83 }
84}