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: add iroh-sync and integrate into iroh node #1333

Merged
merged 144 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from 113 commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
3340613
feat: initial prototype of integrating iroh-sync
Frando Jul 26, 2023
867d741
sync: start impl of multikey
dignifiedquire Jul 3, 2023
f5c51c0
feat: integrate iroh-sync and iroh-gossip, add example
Frando Jul 6, 2023
230a362
feat: make the live sync handler work with many docs
Frando Jul 7, 2023
350a486
chore: cleanup and clippy
Frando Jul 7, 2023
e8e9158
chore: remove old code and add docs
Frando Jul 12, 2023
9a9266e
feat: WIP integration of sync and bytes
Frando Jul 12, 2023
b1868ad
feat: proper REPL for sync example, and docs store
Frando Jul 13, 2023
607fd81
feat(example-sync): add ticket command
Frando Jul 13, 2023
a0f96db
fix: adapt to changes on main after rebase
Frando Jul 26, 2023
e0e062c
example(sync): add watch command
dignifiedquire Jul 26, 2023
6347541
fixup
dignifiedquire Jul 26, 2023
82d4589
chore: unused variables
Frando Jul 26, 2023
94163c7
fix tests and warnings
dignifiedquire Jul 27, 2023
7240fc5
clippy cleanups
dignifiedquire Jul 27, 2023
069a53b
feat(iroh): metrics for iroh-sync
Frando Jul 27, 2023
ce9d809
fix: remove usage of unbounded channels
dignifiedquire Jul 27, 2023
2c9aa58
add todo
dignifiedquire Jul 27, 2023
5a627b9
sync: implement more extensive fetch methods
dignifiedquire Jul 27, 2023
5899d0e
add prefix methods
dignifiedquire Jul 27, 2023
43eff25
feat: enable metrics server on sync (#1308)
Arqu Jul 27, 2023
33883f8
chore: update deny.toml
dignifiedquire Jul 27, 2023
b487671
fix clippy and feature selection
dignifiedquire Jul 27, 2023
e56e7aa
doc: more docs fixes
dignifiedquire Jul 27, 2023
b4358dd
feat: file system export/import in sync repl
Frando Jul 27, 2023
c700721
feat: hammer sync example
Arqu Jul 27, 2023
6bdfaf6
chore: fmt
Frando Jul 27, 2023
27e0923
allow specifying number of threads and print out some basic stats
Arqu Jul 27, 2023
6745dfa
mad clippy is mad
Arqu Jul 27, 2023
aeda868
extend hammer with get/set modes
Arqu Jul 27, 2023
4de81b6
refactor: use clap::ValueEnum
Frando Jul 28, 2023
494748b
refactor: check results, and clearer variable names
Frando Jul 28, 2023
193a33a
refactor: count actual rows, and make mode an argument
Frando Jul 28, 2023
b0a7ab0
fix: rebase fix
Frando Jul 28, 2023
fb693b1
feat(iroh-sync): implement file system backed for documents (#1315)
dignifiedquire Aug 3, 2023
56fb90c
adapt after rebase on main
Frando Aug 7, 2023
e4fca32
chore: fmt
Frando Aug 7, 2023
b33d3ef
feat: download from peer that informed us about a change
Frando Jul 28, 2023
cd17db8
refactor: move downloader out of sync module
Frando Aug 7, 2023
722df34
fix: rebase
Frando Aug 7, 2023
f0d9ef2
fix imports
Frando Aug 7, 2023
111b117
chore: fmt
Frando Aug 7, 2023
59077b1
fix: metrics
Frando Aug 7, 2023
437c031
fix: feature flags
Frando Aug 7, 2023
481b771
chore: fmt
Frando Aug 7, 2023
8da512f
rework abstractions for integration in iroh node
Frando Aug 10, 2023
c76a1da
wip: integrate iroh sync and gossip
Frando Aug 4, 2023
7784510
add ticket for doc share, and concrete type for node client/controller
Frando Aug 9, 2023
d1caf19
add minimal client example
Frando Aug 9, 2023
f80617a
add util methods to obtain an iroh client
Frando Aug 9, 2023
134477a
fix: return DocTicket from share
Frando Aug 9, 2023
5880f50
feat: expose metrics over rpc
Frando Aug 9, 2023
e911696
expose stats in rpc client
Frando Aug 9, 2023
d021455
fix sync example after rebase
Frando Aug 10, 2023
c78fb5b
feat: reimplement download
Frando Aug 10, 2023
c039f72
feat(cli): support printing document content
Frando Aug 10, 2023
910fd87
remove unneeded todo comment
Frando Aug 10, 2023
f03b061
fix tests
Frando Aug 10, 2023
1f864b5
fix downloader and sync test
Frando Aug 10, 2023
961bd3d
fix: feature flags, and more docs
Frando Aug 10, 2023
67dd342
remove sync feature
Frando Aug 10, 2023
cb24396
chore: fmt & clippy fix
Frando Aug 10, 2023
75679db
fix: feature flags
Frando Aug 10, 2023
69951d2
fix: feature flags
Frando Aug 10, 2023
4d87cd3
docs: fixes
Frando Aug 10, 2023
14ce536
chore: clippy fix
Frando Aug 10, 2023
610d09f
refactor: better modules for client
Frando Aug 10, 2023
a16ec9a
fix: clippy
Frando Aug 10, 2023
ac5240e
fix: clippy
Frando Aug 10, 2023
3bc1483
fix: feature flags
Frando Aug 11, 2023
9d5d06a
fix: cleanup imports
Frando Aug 11, 2023
23d138b
fix: gossip endpoint init
Frando Aug 11, 2023
cc4c5a9
fix: less arguments for clippy
Frando Aug 11, 2023
d05e32c
increase logging in cli tests
Frando Aug 11, 2023
ef0892d
chore: remove obsolete file
Frando Aug 11, 2023
a285c6d
chore: clippy
Frando Aug 11, 2023
96c9a43
feat: implement minimal subscription for sync (#1346)
dignifiedquire Aug 14, 2023
fbfdd27
fix: unused code
Frando Aug 14, 2023
6daef61
test: use events in sync test
Frando Aug 14, 2023
e596d7b
chore: fmt
Frando Aug 14, 2023
ec4e619
refactor: simplify iroh-sync store trait
Frando Aug 14, 2023
35f3218
fix: debug for client
Frando Aug 14, 2023
4429435
fix: sync example
Frando Aug 14, 2023
d15b61d
refactor: improve subscription model for sync events
dignifiedquire Aug 14, 2023
4c649c1
docs and clippy
dignifiedquire Aug 14, 2023
ac2bd41
feat: content ready events
Frando Aug 14, 2023
07653ca
chore: clippy
Frando Aug 14, 2023
925ff83
fix: sync example
Frando Aug 14, 2023
f5c0dd9
fix
Frando Aug 15, 2023
c08fef8
refactor: make from peer id required
Frando Aug 15, 2023
0287d4d
Merge branch 'main' into sync-integration
Frando Aug 17, 2023
a8e8093
fix: content status for partial entries
Frando Aug 17, 2023
839a855
docs: fix
Frando Aug 17, 2023
cde53c3
chore: clippy
Frando Aug 17, 2023
fc91c5e
docs,refactor: add docs in iroh-sync and reduce public API surface
Frando Aug 16, 2023
ff90fe6
refactor: move keys into module
Frando Aug 16, 2023
1fb6f8f
chore: fmt
Frando Aug 16, 2023
b666f87
refactor: align variable names with rust crypto
Frando Aug 16, 2023
4b50b64
docs: improve docs further
Frando Aug 16, 2023
337fc1d
fix: item visibility in iroh-sync
Frando Aug 16, 2023
4df7796
remove obsolete comments
Frando Aug 16, 2023
b103077
refactor: make list_authors and list_namespaces return an interator
Frando Aug 17, 2023
036c168
fix: doc links
Frando Aug 17, 2023
b990a72
chore: clippy
Frando Aug 17, 2023
a3bd92e
doc: fixes
Frando Aug 17, 2023
b2a92f1
Merge branch 'main' into sync-integration
Frando Aug 22, 2023
5bf0e9e
fixes after merging main
Frando Aug 22, 2023
05035e3
chore: clippy
Frando Aug 22, 2023
e655828
more docs clean up
ramfox Aug 18, 2023
6615092
fix: sync example
Frando Aug 22, 2023
6fa839d
deps: be less specific in required versions
Frando Aug 22, 2023
ab2d2db
fix: do not require features for metrics
Frando Aug 22, 2023
629289b
docs(iroh-sync): copy prose from lib.rs to README.md
Frando Aug 22, 2023
3779d27
fix: idbytes macro
Frando Aug 22, 2023
f6f9f9c
Merge branch 'main' into sync-integration
Frando Aug 22, 2023
0968384
refactor: use base32 for Author and Namespace encoding
Frando Aug 23, 2023
452059b
Merge branch 'main' into sync-integration
Frando Aug 23, 2023
bbdf7bf
chore: clippy
Frando Aug 23, 2023
f571631
fix: docs for client, add stop_sync rpc call
Frando Aug 23, 2023
f065781
remove unimplemented PeerAdd and PeerList commands for now
Frando Aug 23, 2023
f00db58
docs and cleanup of RPC interface
Frando Aug 23, 2023
5e12659
cleanup
Frando Aug 23, 2023
2c540be
fix: log errors for incoming connections
Frando Aug 23, 2023
136a994
Merge branch 'main' into sync-integration
Frando Aug 23, 2023
23911fc
chore: remove leftover code
Frando Aug 23, 2023
e44fb83
chore: disable cross tests for armv7 and aarch64
Frando Aug 23, 2023
0d432da
feat: filter by author on
Frando Aug 23, 2023
502da40
cleanup naming
Frando Aug 23, 2023
a63fbf8
chore: fix CI skip statement
Frando Aug 23, 2023
3339add
fix: check if doc exists in client
Frando Aug 23, 2023
b4d2164
cleanup
Frando Aug 23, 2023
fe781be
chore: fmt
Frando Aug 23, 2023
264dadf
fix: last commit was broken
Frando Aug 23, 2023
503ff23
fix: clarify metrics initialization
Frando Aug 23, 2023
0e3f169
fix(sync): properly drop rpc subscriptions, add doc status (#1396)
Frando Aug 24, 2023
c50bf53
Merge branch 'main' into sync-integration
Frando Aug 24, 2023
d206252
refactor(iroh): simplify and cleanup the sync algorithm (#1401)
dignifiedquire Aug 24, 2023
8d803b0
refactor: move sync net code into iroh_sync
Frando Aug 24, 2023
248f6b3
Merge remote-tracking branch 'origin/main' into sync-integration
Frando Aug 24, 2023
3921eac
fix: doc links
Frando Aug 24, 2023
39fda80
fix: imports in tests
Frando Aug 24, 2023
7690287
fix: visibility
Frando Aug 24, 2023
0bc1efb
fix: sync example
Frando Aug 24, 2023
b7c7623
chore: make clippy happy
Frando Aug 24, 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
413 changes: 320 additions & 93 deletions Cargo.lock

Large diffs are not rendered by default.

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 = [
"iroh-bytes",
"iroh-gossip",
"iroh-metrics",
"iroh-sync",
]

[profile.release]
Expand Down
2 changes: 2 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ multiple-versions = "allow"
[licenses]
allow = [
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"BSL-1.0", # BOSL license
"ISC",
"MIT",
"OpenSSL",
Expand Down
4 changes: 2 additions & 2 deletions iroh-bytes/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl GetRequest {
}

/// Write the given data to the provider sink, with a unsigned varint length prefix.
pub(crate) async fn write_lp<W: AsyncWrite + Unpin>(writer: &mut W, data: &[u8]) -> Result<()> {
pub async fn write_lp<W: AsyncWrite + Unpin>(writer: &mut W, data: &[u8]) -> Result<()> {
ensure!(
data.len() < MAX_MESSAGE_SIZE,
"sending message is too large"
Expand All @@ -193,7 +193,7 @@ pub(crate) async fn write_lp<W: AsyncWrite + Unpin>(writer: &mut W, data: &[u8])
///
/// The message as raw bytes. If the end of the stream is reached and there is no partial
/// message, returns `None`.
pub(crate) async fn read_lp(
pub async fn read_lp(
mut reader: impl AsyncRead + Unpin,
buffer: &mut BytesMut,
) -> Result<Option<Bytes>> {
Expand Down
18 changes: 18 additions & 0 deletions iroh-bytes/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ impl From<[u8; 32]> for Hash {
}
}

impl From<Hash> for [u8; 32] {
fn from(value: Hash) -> Self {
*value.as_bytes()
}
}

impl From<&[u8; 32]> for Hash {
fn from(value: &[u8; 32]) -> Self {
Hash(blake3::Hash::from(*value))
}
}

impl PartialOrd for Hash {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.0.as_bytes().cmp(other.0.as_bytes()))
Expand Down Expand Up @@ -202,6 +214,12 @@ impl From<anyhow::Error> for RpcError {
}
}

impl From<std::io::Error> for RpcError {
fn from(e: std::io::Error) -> Self {
RpcError(serde_error::Error::new(&e))
}
}

/// A serializable result type for use in RPC responses.
#[allow(dead_code)]
pub type RpcResult<T> = result::Result<T, RpcError>;
Expand Down
4 changes: 2 additions & 2 deletions iroh-gossip/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "iroh-gossip"
version = "0.4.1"
version = "0.5.1"
edition = "2021"
readme = "README.md"
description = "gossip messages over broadcast trees"
Expand All @@ -14,7 +14,7 @@ rust-version = "1.67"
[dependencies]
# proto dependencies (required)
anyhow = { version = "1", features = ["backtrace"] }
blake3 = "1.3.3"
blake3 = { package = "iroh-blake3", version = "1.4.3"}
bytes = { version = "1.4.0", features = ["serde"] }
data-encoding = "2.4.0"
derive_more = { version = "1.0.0-beta.1", features = ["add", "debug", "display", "from", "try_into"] }
Expand Down
46 changes: 34 additions & 12 deletions iroh-gossip/src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ use tokio::{
sync::{broadcast, mpsc, oneshot, watch},
task::JoinHandle,
};
use tracing::{debug, warn};
use tracing::{debug, trace, warn};

use self::util::{read_message, write_message, Dialer, Timers};
use crate::proto::{self, TopicId};

pub mod util;

/// ALPN protocol name
pub const GOSSIP_ALPN: &[u8] = b"n0/iroh-gossip/0";
pub const GOSSIP_ALPN: &[u8] = b"/iroh-gossip/0";
/// Maximum message size is limited to 1024 bytes.
pub const MAX_MESSAGE_SIZE: usize = 1024;

Expand Down Expand Up @@ -265,6 +265,20 @@ struct IrohInfo {
derp_region: Option<u16>,
}

impl IrohInfo {
async fn from_endpoint(endpoint: &MagicEndpoint) -> anyhow::Result<Self> {
Ok(Self {
addrs: endpoint
.local_endpoints()
.await?
.iter()
.map(|ep| ep.addr)
.collect(),
derp_region: endpoint.my_derp().await,
})
}
}

/// Whether a connection is initiated by us (Dial) or by the remote peer (Accept)
#[derive(Debug)]
enum ConnOrigin {
Expand Down Expand Up @@ -356,11 +370,7 @@ impl Actor {
}
},
_ = self.on_endpoints_rx.changed() => {
let endpoints = self.on_endpoints_rx.borrow().clone();
let info = IrohInfo {
addrs: endpoints.iter().map(|ep| ep.addr).collect(),
derp_region: self.endpoint.my_derp().await
};
let info = IrohInfo::from_endpoint(&self.endpoint).await?;
let peer_data = postcard::to_stdvec(&info)?;
self.handle_in_event(InEvent::UpdatePeerData(peer_data.into()), Instant::now()).await?;
}
Expand Down Expand Up @@ -469,13 +479,21 @@ impl Actor {

async fn handle_in_event(&mut self, event: InEvent, now: Instant) -> anyhow::Result<()> {
let me = *self.state.me();
debug!(me = ?me, "handle in_event {event:?}");
if matches!(event, InEvent::TimerExpired(_)) {
trace!(me = ?me, "handle in_event {event:?}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The choice to use a field for me but put the event in the message is odd. why not make both of them fields? (applies for all added logging calls here)

Also:

Suggested change
trace!(me = ?me, "handle in_event {event:?}");
trace!(?me, "handle in_event {event:?}");

is an equivalent shorthand and should probably be preferred if the field name is the same as the variable name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those were not added in this PR but in #1149. me is a field because it is a simple type (32 byte peer id) whereas event is a complex type (enum with tuple variantes and potentially a lot of data in them) so I thought debug-printing makes more sense. But also I'm not really sure when to use fields vs debug logging in tracing. I created a separate PR for this as its unrelated to this PR: #1390

} else {
debug!(me = ?me, "handle in_event {event:?}");
};
if let InEvent::PeerDisconnected(peer) = &event {
self.conn_send_tx.remove(peer);
}
let out = self.state.handle(event, now);
for event in out {
debug!(me = ?me, "handle out_event {event:?}");
if matches!(event, OutEvent::ScheduleTimer(_, _)) {
trace!(me = ?me, "handle out_event {event:?}");
} else {
debug!(me = ?me, "handle out_event {event:?}");
};
match event {
OutEvent::SendMessage(peer_id, message) => {
if let Some(send) = self.conn_send_tx.get(&peer_id) {
Expand Down Expand Up @@ -518,10 +536,14 @@ impl Actor {
OutEvent::PeerData(peer, data) => match postcard::from_bytes::<IrohInfo>(&data) {
Err(err) => warn!("Failed to decode PeerData from {peer}: {err}"),
Ok(info) => {
debug!("add known addrs for {peer}: {info:?}...");
self.endpoint
debug!(me = ?self.endpoint.peer_id(), peer = ?peer, "add known addrs: {info:?}");
if let Err(err) = self
.endpoint
.add_known_addrs(peer, info.derp_region, &info.addrs)
.await?;
.await
{
debug!(me = ?self.endpoint.peer_id(), peer = ?peer, "add known failed: {err:?}");
}
}
},
}
Expand Down
2 changes: 1 addition & 1 deletion iroh-gossip/src/proto/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ macro_rules! idbytes_impls {
}
}

impl<T: Into<[u8; 32]>> From<T> for $ty {
impl<T: Into<[u8; 32]>> std::convert::From<T> for $ty {
Frando marked this conversation as resolved.
Show resolved Hide resolved
fn from(value: T) -> Self {
Self::from_bytes(value.into())
}
Expand Down
30 changes: 28 additions & 2 deletions iroh-net/src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ impl PublicKey {
self.public.as_bytes()
}

/// Construct a `PublicKey` from a slice of bytes.
///
/// # Warning
///
/// This will return a [`SignatureError`] if the bytes passed into this method do not represent
/// a valid `ed25519_dalek` curve point. Will never fail for bytes return from [`Self::as_bytes`].
/// See [`VerifyingKey::from_bytes`] for details.
pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, SignatureError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed when we have TryFrom<&[u8>?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me having a from_bytes method seems convenient. Eg all the ed22591_dalek types have it as well. I can also remove it though..

let public = VerifyingKey::from_bytes(bytes)?;
Ok(public.into())
}

fn public_crypto_box(&self) -> crypto_box::PublicKey {
crypto_box::PublicKey::from_bytes(self.public_crypto_box)
}
Expand All @@ -74,6 +86,15 @@ impl TryFrom<&[u8]> for PublicKey {
}
}

impl TryFrom<&[u8; 32]> for PublicKey {
type Error = SignatureError;

#[inline]
fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error> {
Self::from_bytes(bytes)
}
}

impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
Expand Down Expand Up @@ -233,6 +254,12 @@ impl SecretKey {
self.secret.to_bytes()
}

/// Create a secret key from its byte representation.
pub fn from_bytes(bytes: &[u8; 32]) -> Self {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

let secret = SigningKey::from_bytes(bytes);
secret.into()
}

fn secret_crypto_box(&self) -> &crypto_box::SecretKey {
self.secret_crypto_box
.get_or_init(|| secret_ed_box(&self.secret))
Expand All @@ -250,8 +277,7 @@ impl From<SigningKey> for SecretKey {

impl From<[u8; 32]> for SecretKey {
fn from(value: [u8; 32]) -> Self {
let secret = SigningKey::from(value);
secret.into()
Self::from_bytes(&value)
}
}

Expand Down
41 changes: 41 additions & 0 deletions iroh-sync/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
name = "iroh-sync"
version = "0.5.1"
edition = "2021"
readme = "README.md"
description = "Iroh sync"
license = "MIT/Apache-2.0"
authors = ["n0 team"]
repository = "https://github.com/n0-computer/iroh"

Frando marked this conversation as resolved.
Show resolved Hide resolved
[dependencies]
anyhow = "1"
blake3 = { package = "iroh-blake3", version = "1.4.3"}
crossbeam = "0.8.2"
derive_more = { version = "1.0.0-beta.1", features = ["debug", "display", "from", "try_into"] }
ed25519-dalek = { version = "2.0.0", features = ["serde", "rand_core"] }
flume = "0.10"
iroh-bytes = { version = "0.5.0", path = "../iroh-bytes" }
iroh-metrics = { version = "0.5.0", path = "../iroh-metrics", optional = true }
flub marked this conversation as resolved.
Show resolved Hide resolved
once_cell = "1.18.0"
postcard = { version = "1", default-features = false, features = ["alloc", "use-std", "experimental-derive"] }
rand = "0.8.5"
rand_core = "0.6.4"
serde = { version = "1.0.164", features = ["derive"] }
url = "2.4"
bytes = "1"
parking_lot = "0.12.1"
hex = "0.4"

# fs-store
redb = { version = "1.0.5", optional = true }
ouroboros = { version = "0.17", optional = true }

[dev-dependencies]
tokio = { version = "1", features = ["sync", "macros"] }
tempfile = "3.4"

[features]
default = ["fs-store", "metrics"]
fs-store = ["redb", "ouroboros"]
metrics = ["iroh-metrics"]
Loading
Loading