datrs / hypercore Goto Github PK
View Code? Open in Web Editor NEWSecure, distributed, append-only log
Home Page: https://docs.rs/hypercore
License: Apache License 2.0
Secure, distributed, append-only log
Home Page: https://docs.rs/hypercore
License: Apache License 2.0
Hypercore should support not having a private key available. It currently doesn't.
We're forwarding the KeyPair
type from another crate. We should create a wrapper type for this.
We should also be able to have a half-opened state for these - e.g. read-write vs just read
Nowadays hypercore
is defined for storage where errors are failure::Error
eg
This predates when Rust had std::error::Error
trait, and could now be replaced with a Error + Send + Sync + 'static
, such as anyhow, snafu or coreerror for a no_std
crate.
This is also one less crate on the stack.
This should help us move into no_std
in the future, specially useful for WASM and embedded.
We could replace failure
with anyhow
on random-access-disk
and random-access-storage
to use context during errors, which is also compatible with std::error::Error
.
We can then define hypercore
using the std Error
trait, and broaden the types of Storages
hypercore
can use.
This is proposed in #40 and currently blocked by dalek-cryptography/curve25519-dalek#201. This will probably be resolved at some point, so we'll just have to wait until then.
We're forwarding the Signature
type from another crate. We should create a wrapper type for this.
Expose the builder as hypercore::builder
, just like hyper::Server::builder()
https://docs.rs/hyper/0.12.6/hyper/server/struct.Server.html#methods
Software | Version(s) |
---|---|
hypercore | 0.9.0 |
Rustc | rustc 1.34.1 (fc50f328b 2019-04-24) |
Operating System | linux |
So I'm not sure if I should ask this question here. I have tried to find help elsewhere but writing here as a last-resort.
I'm new to rust and I have been picking up the language at a steady pace.
But there's one issue that I've been struggling with to the point of insanity.
How do you store a hypercore::Feed
in a struct or define a function that can take a feed as a parameter?
// What is the correct type declaration for feed?
pub struct MyStruct {
m_feed: Feed<RandomAccess>,
};
pub fn (a_feed: &Feed<RandomAccess>) { ... }
// Or even slightly modifying the example from the docs:
let path = PathBuf::from("./my-first-dataset");
let mut feed: TYPE_DECLARATION = Feed::new(&path).unwrap();
I've literally spent a week trying all kinds of exotic declaration to satisfy the compiler traits, but to no avail..
Again humble apologies for asking this here, please help!
version 0.11.0 does not build.
Stacktrace:
Compiling hypercore v0.11.0
error[E0277]: the trait bound `random_access_memory::RandomAccessMemory: random_access_storage::RandomAccess` is not satisfied
--> /Users/dylan/.cargo/registry/src/github.com-1ecc6299db9ec823/hypercore-0.11.0/src/feed.rs:572:6
|
30 | pub struct Feed<T>
| ---- required by a bound in this
31 | where
32 | T: RandomAccess<Error = Error> + Debug,
| --------------------------- required by this bound in `feed::Feed`
...
572 | impl Default for Feed<RandomAccessMemory> {
| ^^^^^^^ the trait `random_access_storage::RandomAccess` is not implemented for `random_access_memory::RandomAccessMemory`
|
help: trait impl with same name found
--> /Users/dylan/.cargo/registry/src/github.com-1ecc6299db9ec823/random-access-memory-1.2.0/src/lib.rs:55:1
|
55 | / impl RandomAccess for RandomAccessMemory {
56 | | type Error = Box<dyn std::error::Error + Send + Sync>;
57 | |
58 | | fn write(&mut self, offset: u64, data: &[u8]) -> Result<(), Self::Error> {
... |
203 | | }
204 | | }
| |_^
= note: perhaps two different versions of crate `random_access_storage` are being used?
How do I read an existing hypercore on disk?
Software | Version(s) |
---|---|
hypercore | 0.10.0 |
Rustc | rustc 1.37.0 (eae3437df 2019-08-13) |
Operating System | macOS 10.12.6 (16G1815) |
I was doing some initial evaluation of rust hypercore. One of the things I wanted to try was to read existing hypercores, such as the ones written by mafintosh/hypercore. However, I could not figure out how to do that. Even when passing in the directory of an existing hypercore, the .len()
method returns 0.
I want to check compatibility with js hypercore and also compare read performance.
This issue is a proposal for merging the hypercore repo with its dependency libraries from the datrs project (and keeping them as separate crates if necessary). The merged dependency libraries would be the following:
There are a couple of benefits in doing this and not a lot of downsides that I know of. In short, it would facilitate faster development with fewer breakages and easier understanding of the whole project.
On the plus side:
cargo test
in the repo root.As for the disadvantages, these are what I could think of:
All in all, I think it's a net positive.
Why do it in the hypercore repo? It seems to me that this is the first layer of the Dat Project which should be usable on its own. The dependencies of this project are implementation details. Some of those could be usable on their own, so it might be worthwhile to keep them as separate crates. And I guess the least controversial move is to keep them as separate crates.
To keep the dependencies as separate crates, the workspace feature of cargo can be used: https://github.com/rust-lang/rfcs/blob/master/text/1525-cargo-workspace.md.
Here is a project using this feature: https://github.com/gfx-rs/gfx
What do you think?
If you think it might be worthwhile, I can do the merge in a test repo where anyone can try how it would work before committing to this repo overhaul.
Implement feed.audit()
to verify all data you think you have is actually there.
This gives us parity with holepunchto/hypercore#180.
Was thinking, a cleaner way of implementing many of the things we have in-source right now would be by using traits / structs a bit better. Currently we have the following problems:
crypto/key_pair
is unaware of methods that are available in crypto/mod
.Hash
struct yet.Signature
lives in storage, but is relevant to crypto
too.Something like the following:
KeyPair
, sign data. Alt name: Sign
.BLAKE2b
into a Hash
.Storage
instance.tree
data that is stored.random-access-storage
instance.It'd be good to have the Store
trait to implement a method that can write to a Storage
instance.
trait Storage {
fn from_bytes(index: usize, buf: &[u8]) -> Self;
fn to_vec(&self) -> Vec<u8>;
fn store<T>(&self, index: usize) -> Result<(), Error>;
}
The read/write
methods can then respectively just call the .from_bytes()
and .to_vec()
methods respectively. Persisting to disk can then be done by just calling out to .store()
.
By having it in a trait we should be able to simplify the Storage
module a bunch. We'll still need dedicated methods for reading / writing each type, but the hope is that we'll be able to do away with some of the inline magic numbers (e.g. 40
, 32
) and move them to be part of the corresponding structs.
I think it's pretty nice to have a separate submodule dedicated to crypto. By creating traits rather than functions, we can create a looser relationship between our crypto internals, and the way we provide data to the crypto functions.
This is a tracking issues on what I think we should merge for a breaking 0.12 release soonish:
breaking changes
non-breaking changes
I think it would be great to get those merged rather sooner than later, because at least the first three ones all change the public and internal API so that all other PRs oftenly have to be manually updated.
Because we don't have, I think, anyone using hypercore-rs, and because there is no one "properly" maintaining this at the moment, I propose that we let this issue sit here for a couple of days or a week and then go ahead, merge the PRs, and figure out bugs and issues in the process.
Also very open to other suggestions :)
Update to the most recent versions of the random-access-*
packages
RandomAccess
trait contains len
function, which seems to be required by #72Is there some reason this hasn't been done already? Are these packages in a state of flux? Are there any known issues which make this hard/impossible
hypercore
now works pretty well, it's time to implement the networking part.
feed.announce()
(ref)feed.unannounce()
(ref)pub feed.has()
(ref)pub feed.has_all()
(polymorphic variant of feed.has()
)pub feed.head()
(ref)pub feed.replicate()
(ref)pub feed.update()
(ref)pub feed.downloaded()
(ref)pub feed.finalize()
(ref)Peer
structEvent
enumI was looking into coupling hypercore-protocol-rs to hypercore today a bit.
However, I was unable to put any data into a cloned hypercore. It seems the put
method either has a bug or I did not understand how to use it correctly. I'll open a PR with a failing test.
https://github.com/dalek-cryptography/ed25519-dalek instead of the sodium lib
The design of hypercore on node is quite callback oriented, and operations may happen at some point. We could provide an async API that feels more like Rust instead of callbacks.
Translating the callback oriented operations from dat.js to Rust seems to prompt a more asynchronous API. Now with the stable async/await support, it seems to be ideal to provide such API as we would be dealing with file operations and network.
This would be a breaking change as I don't know yet how to propose maintaining both the sync and async API on the same crate.
We could have an API such as:
let mut feed = hypercore::open("./feed.db").await?;
feed.append(b"hello").await?;
feed.append(b"world").await?;
assert_eq!(feed.get(0).await?, Some(b"hello".to_vec()));
assert_eq!(feed.get(1).await?, Some(b"world".to_vec()));
This would require to change the underlying storage to benefit from async operations as well.
Async traits are not yet stable, but we could use https://crates.io/crates/async-trait to implement it.
We could implement on https://github.com/datrs/random-access-storage a blanket implementation:
#[async_trait]
trait AsyncRandomAccess {
async fn async_open(&mut self) -> Result<(), Self::Error>;
}
impl AsyncRandomAccess for RandomAccess {
async fn async_open(&mut self) -> Result<(), Self::Error> {
async_std::task::spawn_blocking({ self.open() }).await
}
}
This is how far I've thought about it and have a concrete example. I would need to test it out further, but I would like to open for feedback.
Not doing this would mean that networking might not be as performant as it could, as access to file would block the operations.
Many:
Having to expose the NodeTrait
just to be able to use the methods on the Node
type feels leaky. We should create a "sealed" and "unsealed" Node
type, where one acts as a front for the other.
We can do this by creating a facade using https://github.com/chancancode/rust-delegate, which should allow us to seal the trait
requirements internally without leaking it.
We should probably name one SealedNode
and the other Node. Using
Node` exclusively throughout our code as to prevent the sealed version from leaking.
Software | Version(s) |
---|---|
hypercore | 0.9.0 |
Rustc | rustc 1.35.0-nightly (237bf3244 2019-03-28) |
Operating System | Ubuntu 18.04 |
Program prints
hello
world
Program prints
Ok(Some([104, 101, 108, 108, 111]))
Ok(Some([119, 111, 114, 108, 100]))
extern crate hypercore;
use hypercore::Feed;
use std::path::PathBuf;
let path = PathBuf::from("./my-first-dataset");
let mut feed = Feed::new(&path).unwrap();
feed.append(b"hello").unwrap();
feed.append(b"world").unwrap();
println!("{:?}", feed.get(0)); // prints "hello"
println!("{:?}", feed.get(1)); // prints "world"
Hi, I was reading the code and stumble onto the comment that said "@todo Read key pair from disk". It doesn't look too hard to implement but I had a few questions:
Storage
, not sure!Maybe that it's too early in the development to implement this though :).
Cheers.
Hi,
I've been thinking about whether it would make sense to remove the generic Storage<T>
field on the Feed
struct and instead have a Box<dyn DynStorage>
object on the Feed. DynStorage
would be a trait with all public methods of Storage<T>
. Thus, Feed<T>
would just be Feed
.
Benefits:
Feed
.Drawbacks:
I would guess that compiler optimizations might oftenly reduce the cost of dynamic dispatch if you'd only use one implementation in your code paths, but I'm not sure about it.
Opinions?
$ rustup toolchain list
stable-x86_64-unknown-linux-gnu (default)
1.47.0-x86_64-unknown-linux-gnu
And
$ rustc --test -O benches/bench.rs
error[E0670]: `async fn` is not permitted in the 2015 edition
--> benches/bench.rs:10:1
|
10 | async fn create_feed(page_size: usize) -> Result<Feed<RandomAccessMemory>, Error> {
| ^^^^^ to use `async fn`, switch to Rust 2018
|
= help: set `edition = "2018"` in `Cargo.toml`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found keyword `move`
--> benches/bench.rs:12:28
|
12 | |_| Box::pin(async move { Ok(RandomAccessMemory::new(page_size)) }),
| ^^^^ expected one of 8 possible tokens
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0670`.
But in the toml file there's already
edition = "2018"
why is it being ignored?
Dependabot can't resolve your Rust dependency files.
As a result, Dependabot couldn't update your dependencies.
The error Dependabot encountered was:
Updating crates.io index
error: failed to select a version for the requirement `curve25519-dalek = "^0.20"`
candidate versions found which didn't match: 1.2.1, 1.1.4, 1.1.3, ...
location searched: crates.io index
required by package `ed25519-dalek v0.8.1`
... which is depended on by `hypercore v0.9.0 (/home/dependabot/dependabot-updater/dependabot_tmp_dir
If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.
You can mention @dependabot in the comments below to contact the Dependabot team.
In some places usize
is being used in situations where it would be better to explicitly define what bit size we want to use. One example can be found here:
Lines 53 to 54 in c7c8757
The crate is currently built with a 64 bit word size in mind, this will cause issues when run on a 32-bit system
Review all uses of usize
, evaluate if u64
would be more appropriate, change the types, fix any compiler errors that occour. (optional: build and run on a 32 bit system to check compatability)
Is this something that should be done now? are there valid reasons to postpone this work? Are there any other relevant issues that have not been described in this ticket
Hi there (not sure if the appropriate repo to do this)
Thanks for the project, it seems to be moving quite well. The idea of a dat component in Rust is quite nice as it could reach many devices.
One platform that interests me is Android. I've been looking at staltz/dat-installer and this is quite a nice example of possible app on Android that would benefit a lot of having datrs available as a lib. I would like to help with providing such capabilities for Android, but I'm not sure how to help.
I have no experience on bindings and Android NDK's FFI, but I'm interested to be able to use dat on mobile applications. A bonus point would be to provide a Flutter plugin which would allow cross-platform development as well.
What would be the next steps for this?
Software | Version(s) |
---|---|
hypercore | Master Branch |
Rustc | N/A |
Operating System | N/A |
If I understand correctly the sign function in hypercore/crypto should be using the secret/private key to sign the data rather than the public key.
Currently using the public key rather than private key from what I can tell.
https://github.com/datrs/hypercore/blob/master/src/crypto/key_pair.rs#L15-L22
For a working Dat2 / hypercore 8 implementation in Rust, we'll have to implement the NOISE handshaking and transport encryption.
I'll document what I found out while looking into this.
I don't think there's any "official" documentation about the NOISE handshake and transport encryption in hypercore yet. Looking into the code reveals:
Noise_XX_25519_XChaChaPoly_BLAKE2
(see noise-protocol/handshake-state and simple-hypercore-protocol/handshake). The handshake uses a state machine module called simple-handshake, which then uses noise-protocol, a Javascript implementation of some parts of the NOISE spec that uses sodium-native for the actual crypto.payload
being transmitted from each side is a protocol buffers encoded message with a 24 byte nonce (random bytes), created in simple-hypercore-protocol/index.jssodium.crypto_stream_xor
(see simple-hypercore-protocol/lib/xor.js and the sodium docs), with instances for receiving and transmitting, where for each the keys are coming from the split
result of the NOISE handshake and the nonces are the payloads that were transmitted during the handshake. sodium.crypto_stream_xor
resolves to crypto_stream_xsalsa20_xor
which, in sodium-native, uses crypto_stream_xsalsa20I tried to connect to a nodejs hypercore-protocol stream from Rust, however I hit a few roadblocks. I started with snow as it seems to be the most complete NOISE impl in rust. Following are, I think, what's missing to make connecting to a hypercore-protocol stream:
XChaChaPoly
cipher. I created an issue for that. There's a rust impl of XChaChaPoly in chacha20poly1305.split
results directlyA declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.