Skip to content

Commit

Permalink
Merge branch 'main' into fix-partial-download-raw
Browse files Browse the repository at this point in the history
  • Loading branch information
rklaehn committed Dec 19, 2023
2 parents df87f96 + c8784a4 commit 0297f3f
Show file tree
Hide file tree
Showing 21 changed files with 476 additions and 246 deletions.
18 changes: 11 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,18 @@ jobs:
RUST_LOG: ${{ runner.debug && 'DEBUG' || 'INFO'}}

- name: tests
run: cargo nextest run --workspace ${{ env.FEATURES }} --lib --bins --tests
run: |
cargo nextest run --workspace ${{ env.FEATURES }} --lib --bins --tests
env:
RUST_LOG: ${{ runner.debug && 'DEBUG' || 'INFO'}}
RUST_LOG: "TRACE"

- name: doctests
if: ${{ matrix.features == 'all' }}
run: cargo test --workspace --all-features --doc
env:
RUST_LOG: ${{ runner.debug && 'DEBUG' || 'INFO'}}
run: |
if [ -n "${{ runner.debug }}" ]; then
export RUST_LOG=DEBUG
fi
cargo test --workspace --all-features --doc
build_and_test_windows:
timeout-minutes: 30
Expand Down Expand Up @@ -168,9 +171,10 @@ jobs:
- uses: msys2/setup-msys2@v2

- name: tests
run: cargo nextest run --workspace ${{ env.FEATURES }} --lib --bins --tests --target ${{ matrix.target }}
run: |
cargo nextest run --workspace ${{ env.FEATURES }} --lib --bins --tests --target ${{ matrix.target }}
env:
RUST_LOG: ${{ runner.debug && 'DEBUG' || 'INFO'}}
RUST_LOG: "TRACE"

cross:
timeout-minutes: 30
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 5 additions & 42 deletions iroh-base/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ use std::str::FromStr;

use bao_tree::blake3;
use postcard::experimental::max_size::MaxSize;
use serde::{
de::{self, SeqAccess},
ser::SerializeTuple,
Deserialize, Deserializer, Serialize, Serializer,
};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

/// Hash type used throughout.
#[derive(PartialEq, Eq, Copy, Clone, Hash)]
Expand All @@ -36,7 +32,7 @@ impl Hash {
201, 173, 193, 18, 183, 204, 154, 147, 202, 228, 31, 50, 98,
]);

/// Calculate the hash of the provide bytes.
/// Calculate the hash of the provided bytes.
pub fn new(buf: impl AsRef<[u8]>) -> Self {
let val = blake3::hash(buf.as_ref());
Hash(val)
Expand Down Expand Up @@ -159,13 +155,7 @@ impl Serialize for Hash {
if serializer.is_human_readable() {
serializer.serialize_str(self.to_string().as_str())
} else {
// Fixed-length structures, including arrays, are supported in Serde as tuples
// See: https://serde.rs/impl-serialize.html#serializing-a-tuple
let mut s = serializer.serialize_tuple(32)?;
for item in self.0.as_bytes() {
s.serialize_element(item)?;
}
s.end()
self.0.as_bytes().serialize(serializer)
}
}
}
Expand All @@ -179,39 +169,12 @@ impl<'de> Deserialize<'de> for Hash {
let s = String::deserialize(deserializer)?;
s.parse().map_err(de::Error::custom)
} else {
deserializer.deserialize_tuple(32, HashVisitor)
let data: [u8; 32] = Deserialize::deserialize(deserializer)?;
Ok(Self(blake3::Hash::from(data)))
}
}
}

struct HashVisitor;

impl<'de> de::Visitor<'de> for HashVisitor {
type Value = Hash;

fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "an array of 32 bytes containing hash data")
}

/// Process a sequence into an array
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut arr = [0u8; 32];
let mut i = 0;
while let Some(val) = seq.next_element()? {
arr[i] = val;
i += 1;
if i > 32 {
return Err(de::Error::invalid_length(i, &self));
}
}

Ok(Hash::from(arr))
}
}

impl MaxSize for Hash {
const POSTCARD_MAX_SIZE: usize = 32;
}
Expand Down
2 changes: 2 additions & 0 deletions iroh-base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ pub mod base32;
#[cfg(feature = "hash")]
pub mod hash;
pub mod rpc;
#[cfg(feature = "base32")]
pub mod ticket;
63 changes: 63 additions & 0 deletions iroh-base/src/ticket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use crate::base32;

/// A ticket is a serializable object that combines all information required
/// for an operation. E.g. an iroh blob ticket would contain the hash of the
/// data as well as information about how to reach the provider.
///
/// Tickets support serialization to a string using base32 encoding. The kind of
/// ticket will be prepended to the string to make it somewhat self describing.
///
/// Versioning is left to the implementer. Some kinds of tickets might need
/// versioning, others might not.
///
/// The serialization format for converting the ticket from and to bytes is left
/// to the implementer. We recommend using [postcard] for serialization.
///
/// [postcard]: https://docs.rs/postcard/latest/postcard/
pub trait Ticket: Sized {
/// String prefix describing the kind of iroh ticket.
///
/// This should be lower case ascii characters.
const KIND: &'static str;

/// Serialize to bytes used in the base32 string representation.
fn to_bytes(&self) -> Vec<u8>;

/// Deserialize from the base32 string representation bytes.
fn from_bytes(bytes: &[u8]) -> Result<Self, Error>;

/// Serialize to string.
fn serialize(&self) -> String {
let mut out = Self::KIND.to_string();
base32::fmt_append(&self.to_bytes(), &mut out);
out
}

/// Deserialize from a string.
fn deserialize(str: &str) -> Result<Self, Error> {
let expected = Self::KIND;
let Some(rest) = str.strip_prefix(expected) else {
return Err(Error::Kind { expected });
};
let bytes = base32::parse_vec(rest)?;
let ticket = Self::from_bytes(&bytes)?;
Ok(ticket)
}
}

/// An error deserializing an iroh ticket.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Found a ticket of with the wrong prefix, indicating the wrong kind.
#[error("wrong prefix, expected {expected}")]
Kind { expected: &'static str },
/// This looks like a ticket, but postcard deserialization failed.
#[error("deserialization failed: {_0}")]
Postcard(#[from] postcard::Error),
/// This looks like a ticket, but base32 decoding failed.
#[error("decoding failed: {_0}")]
Encoding(#[from] base32::DecodeError),
/// Verification of the deserialized bytes failed.
#[error("verification failed: {_0}")]
Verify(&'static str),
}
1 change: 1 addition & 0 deletions iroh-net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ serdect = "0.2.0"
smallvec = "1.11.1"
socket2 = "0.5.3"
ssh-key = { version = "0.6.0", features = ["ed25519", "std", "rand_core"] }
strum = { version = "0.25.0", features = ["derive"] }
stun-rs = "0.1.5"
surge-ping = "0.8.0"
thiserror = "1"
Expand Down
26 changes: 22 additions & 4 deletions iroh-net/src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl Serialize for PublicKey {
if serializer.is_human_readable() {
serializer.serialize_str(&self.to_string())
} else {
serializer.serialize_bytes(&self.0)
self.0.serialize(serializer)
}
}
}
Expand All @@ -120,8 +120,8 @@ impl<'de> Deserialize<'de> for PublicKey {
let s = String::deserialize(deserializer)?;
Self::from_str(&s).map_err(serde::de::Error::custom)
} else {
let bytes: &serde_bytes::Bytes = serde::Deserialize::deserialize(deserializer)?;
Self::try_from(bytes.as_ref()).map_err(serde::de::Error::custom)
let data: [u8; 32] = serde::Deserialize::deserialize(deserializer)?;
Self::try_from(data.as_ref()).map_err(serde::de::Error::custom)
}
}
}
Expand Down Expand Up @@ -396,8 +396,25 @@ impl TryFrom<&[u8]> for SecretKey {

#[cfg(test)]
mod tests {
use iroh_test::{assert_eq_hex, hexdump::parse_hexdump};

use super::*;

#[test]
fn test_public_key_postcard() {
let public_key = PublicKey::try_from(
hex::decode("ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
.unwrap()
.as_slice(),
)
.unwrap();
let bytes = postcard::to_stdvec(&public_key).unwrap();
let expected =
parse_hexdump("ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
.unwrap();
assert_eq_hex!(bytes, expected);
}

#[test]
fn test_secret_key_openssh_roundtrip() {
let kp = SecretKey::generate();
Expand Down Expand Up @@ -463,7 +480,8 @@ mod tests {

let k5 = random_verifying_key();
let bytes = postcard::to_stdvec(&k5).unwrap();
let _key: PublicKey = postcard::from_bytes(&bytes).unwrap();
// VerifyingKey serialises with a length prefix, PublicKey does not.
let _key: PublicKey = postcard::from_bytes(&bytes[1..]).unwrap();
assert!(lock_key_cache().contains_key(k5.as_bytes()));
}
}
1 change: 1 addition & 0 deletions iroh-net/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod netcheck;
pub mod ping;
pub mod portmapper;
pub mod stun;
pub mod ticket;
pub mod tls;
pub mod util;

Expand Down
6 changes: 6 additions & 0 deletions iroh-net/src/ticket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! Tickets supported by iroh-net
mod blob;
mod node;

pub use blob::BlobTicket;
pub use node::NodeTicket;
Loading

0 comments on commit 0297f3f

Please sign in to comment.