Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement wnfs-unixfs-file crate for encoding big byte arrays in IPLD #375

Merged
merged 22 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6c932ff
feat: Copy over iroh-unixfs without prost codegen
matheus23 Nov 29, 2023
6b3ad5a
chore: Remove `hamt` stuff
matheus23 Nov 29, 2023
c6bbfe9
refactor: Remove directory support
matheus23 Nov 29, 2023
47ae81a
refactor: Remove Symlink support
matheus23 Nov 29, 2023
672bd1c
refactor: Remove ability to read from file path
matheus23 Nov 29, 2023
fa95eaa
refactor: Replace `ContentLoader` with WNFS's `BlockStore`
matheus23 Nov 29, 2023
38fe3f9
refactor: Rename `UnixfsContentReader` to `..FileReader`
matheus23 Nov 29, 2023
6288466
refactor: Borrow `BlockStore` instead of cloning
matheus23 Nov 29, 2023
6732aa8
refactor: Delete unused structs & code
matheus23 Nov 29, 2023
307e7fe
refactor: minor rename `Unixfs` -> `UnixFs`
matheus23 Nov 29, 2023
314c9ef
refactor: Remove need to provide name for files
matheus23 Nov 29, 2023
0311b37
refactor: Write a round-trip proptest
matheus23 Nov 29, 2023
95b0a2f
refactor: Use `BlockStore` to compute hashes & store blocks
matheus23 Nov 29, 2023
0059b7f
chore: Make sure `async_std` runtime also works
matheus23 Nov 29, 2023
246a2d1
chore: Write README (add add a proptest for seeking)
matheus23 Nov 29, 2023
9b2a0e2
chore: Write more readme
matheus23 Nov 29, 2023
1b6dcf0
chore: Fix typo
matheus23 Nov 29, 2023
30f1615
chore: Fix lint
matheus23 Nov 29, 2023
922f8d5
chore: Remove unused dependencies
matheus23 Nov 29, 2023
030ba9c
chore: Document crate dependencies in the readme
matheus23 Nov 30, 2023
9e78912
fix: More accurate lifetimes for `AsyncRead` and `AsyncSeek`
matheus23 Nov 30, 2023
bf4f949
feat: Add constructor
matheus23 Nov 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"wnfs-common",
"wnfs-hamt",
"wnfs-nameaccumulator",
"wnfs-unixfs-file",
"wnfs-wasm",
]

Expand Down
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,27 @@ This library is designed with WebAssembly in mind. You can follow instructions o
## Crates

- [wnfs](https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs)
- [wnfs-wasm](https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs-wasm)
- [wnfs-common](https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs-common)
- [wnfs-hamt](https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs-hamt)
- [wnfs-nameaccumulator](https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs-nameaccumulator)
- [wnfs-wasm](https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs-wasm)
- [wnfs-unixfs-file](https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs-unixfs-file)

This is the dependency graph between these crates:
```mermaid
flowchart TD
wnfs-wasm --> wnfs
wnfs-wasm --> wnfs-nameaccumulator
%% wnfs-bench --> wnfs
%% wnfs-bench --> wnfs-hamt
%% wnfs-bench --> wnfs-nameaccumulator
wnfs --> wnfs-hamt
wnfs --> wnfs-common
wnfs --> wnfs-unixfs-file
wnfs --> wnfs-nameaccumulator
wnfs-unixfs-file --> wnfs-common
wnfs-hamt --> wnfs-common
```

## Building the Project

Expand Down
2 changes: 1 addition & 1 deletion wnfs-hamt/src/strategies/changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub(crate) fn generate_changes<K: Debug + Clone, V: Debug + Clone>(
pairs
.clone()
.into_iter()
.zip(randoms.into_iter())
.zip(randoms)
.filter(|(_, (num, _))| *num != 0)
.map(|((k, _), (num, val))| match num {
1 => Change::Add(k, val),
Expand Down
1 change: 1 addition & 0 deletions wnfs-unixfs-file/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Changelog
44 changes: 44 additions & 0 deletions wnfs-unixfs-file/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[package]
name = "wnfs-unixfs-file"
version = "0.1.25"
description = "IPLD UnixFS File implementation for Webnative Filesystem"
keywords = ["wnfs", "unixfs", "webnative", "ipfs", "decentralisation"]
categories = [
"filesystem",
"cryptography",
"web-programming",
"wasm",
]
license = "Apache-2.0"
readme = "README.md"
edition = "2021"
repository = "https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs-unixfs-file"
homepage = "https://fission.codes"
authors = ["The Fission Authors"]

[dependencies]
anyhow = "1.0"
async-stream = "0.3"
bytes = "1.5"
futures = "0.3"
libipld = { version = "0.16", features = [] }
num_enum = "0.5"
proptest = { version = "1.1", optional = true }
prost = "0.12"
rand_core = "0.6"
testresult = "0.3"
tokio = { version = "1.34", features = ["io-util"] }
wnfs-common = { path = "../wnfs-common", version = "=0.1.25" }

[dev-dependencies]
async-std = { version = "1.11", features = ["attributes"] }
data-encoding = "2.5.0"
proptest = "1.1"
rand = "0.8"
rand_chacha = "0.3.1"
tempfile = "3.8.1"
test-strategy = "0.3"
tokio = { version = "1.34", features = ["fs", "rt", "macros"] }
tokio-test = "0.4.3"
tokio-util = { version = "0.7", features = ["io"] }
wnfs-common = { path = "../wnfs-common", features = ["test_utils"] }
79 changes: 79 additions & 0 deletions wnfs-unixfs-file/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<div align="center">
<a href="https://github.com/wnfs-wg" target="_blank">
<img src="https://raw.githubusercontent.com/wnfs-wg/rs-wnfs/main/assets/logo.png" alt="WNFS Logo" width="100" height="100"></img>
</a>

<h1 align="center">wnfs-unixfs-file</h1>

<p>
<a href="https://crates.io/crates/wnfs-unixfs-file">
<img src="https://img.shields.io/crates/v/wnfs-unixfs-file?label=crates" alt="Docs">
</a>
<a href="https://codecov.io/gh/wnfs-wg/rs-wnfs">
<img src="https://codecov.io/gh/wnfs-wg/rs-wnfs/branch/main/graph/badge.svg?token=95YHXFMFF4" alt="Code Coverage"/>
</a>
<a href="https://github.com/wnfs-wg/rs-wnfs/actions?query=">
<img src="https://github.com/wnfs-wg/rs-wnfs/actions/workflows/checks.yaml/badge.svg" alt="Build Status">
</a>
<a href="https://github.com/wnfs-wg/rs-wnfs/blob/main/LICENSE">
<img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License">
</a>
<a href="https://docs.rs/wnfs">
<img src="https://img.shields.io/static/v1?label=Docs&message=docs.rs&color=blue" alt="Docs">
</a>
<a href="https://discord.gg/zAQBDEq">
<img src="https://img.shields.io/static/v1?label=Discord&message=join%20us!&color=mediumslateblue" alt="Discord">
</a>
</p>
</div>

<div align="center"><sub>:warning: Work in progress :warning:</sub></div>

##

This Rust crate provides an implementation of UnixFs files. WNFS uses the UnixFs file encoding purely to chunk big byte arrays into multiple blocks and produce a single CID for them to link to from WNFS structures.

This crate is a fork from beetle (previously "iroh")'s [iroh-unixfs crate](https://github.com/n0-computer/beetle/tree/3e137cb2bc18e1d458c3f72d5e817b03d9537d5d/iroh-unixfs).

Major changes relative to that implementation include:
- Removed prost code generation, instead it's some hard-coded structs with prost annotations
- Removed support for any UnixFs structures other than files (no directories, directory shards or symlinks)
- Removed parallelization for hashing to make the crate async runtime-independent (so it can be used in wasm with wasm-bindgen-futures!)
- Doesn't hard-code use of SHA-256 anymore
- Integrated with the wnfs-common `BlockStore` trait

## Usage

```rs
use wnfs_unixfs_file::builder::FileBuilder;
use wnfs_common::MemoryBlockStore;
use tokio::io::AsyncReadExt;

// Where data is stored
let store = &MemoryBlockStore::new();

// Encoding byte arrays, getting a CID
let data = vec![1u8; 1_000_000]; // 1MiB of ones
let root_cid = FileBuilder::new()
.content_bytes(data)
.build()?
.store(store)
.await?;

// Taking a CID, reading back a byte array:
let file = UnixFsFile::load(&root_cid, store).await?;
println!("filesize: {}", file.filesize());
let mut buffer = Vec::new();
let mut reader = file.into_content_reader(store, None)?;
reader.read_to_end(&mut buffer).await?;
// buffer now has 1 million ones

// You can also seek
use tokio::io::AsyncSeekExt;
use std::io::SeekFrom;
let mut reader = file.into_content_reader(store, None)?;
reader.seek(SeekFrom::Start(10_000)).await?;
let mut slice = [0u8; 10_000];
reader.read_exact(&mut slice).await?;
// slice now has 10_000 ones
```
8 changes: 8 additions & 0 deletions wnfs-unixfs-file/proptest-regressions/builder.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc 376480a4a772236f8ba598f595ea690a0a12ff4456b4fe61a9d8caccc03b9a17 # shrinks to input = _TestEncodeDecodeRoundtripArgs { data: [] }
cc 77c264b383e78eb742f9da87cbff6aa4e6de7d87991ef955792e5637b8134e46 # shrinks to input = _TestSeekSubarrayArgs { seed: 0, degree: 2, len: 87383, seek_start: 43680, seek_len: 23, chunker: Rabin }
Loading
Loading