Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaka committed Oct 10, 2023
1 parent 94aaf36 commit 1bb23bc
Show file tree
Hide file tree
Showing 6 changed files with 3,437 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/src/libp2p/connection/established/substream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,7 @@ pub enum InboundTy {
/// Maximum allowed size of the request.
/// If `None`, then no data is expected on the substream, not even the length of the
/// request.
// TODO: use a proper enum
request_max_size: Option<usize>,
},
Notifications {
Expand Down
1 change: 1 addition & 0 deletions lib/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
pub mod kademlia;
pub mod protocol;
pub mod service;
pub mod service2;
237 changes: 237 additions & 0 deletions lib/src/network/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
// TODO: expand docs

use alloc::borrow::Cow;
use core::iter;

// Implementation note: each protocol goes into a different sub-module whose content is
// re-exported here.

Expand All @@ -44,3 +47,237 @@ pub use self::identify::*;
pub use self::kademlia::*;
pub use self::state_request::*;
pub use self::storage_call_proof::*;

pub enum ProtocolName<'a> {
Identify,
Ping,
BlockAnnounces {
genesis_hash: [u8; 32],
fork_id: Option<&'a str>,
},
Transactions {
genesis_hash: [u8; 32],
fork_id: Option<&'a str>,
},
Grandpa {
genesis_hash: [u8; 32],
fork_id: Option<&'a str>,
},
Sync {
genesis_hash: [u8; 32],
fork_id: Option<&'a str>,
},
Light {
genesis_hash: [u8; 32],
fork_id: Option<&'a str>,
},
Kad {
genesis_hash: [u8; 32],
fork_id: Option<&'a str>,
},
SyncWarp {
genesis_hash: [u8; 32],
fork_id: Option<&'a str>,
},
State {
genesis_hash: [u8; 32],
fork_id: Option<&'a str>,
},
}

pub fn encode_protocol_name(
protocol: ProtocolName<'_>,
) -> impl Iterator<Item = impl AsRef<str> + '_> + '_ {
let (genesis_hash, fork_id, base_protocol_name) = match protocol {
ProtocolName::Identify => return either::Left(iter::once(Cow::Borrowed("/ipfs/id/1.0.0"))),
ProtocolName::Ping => return either::Left(iter::once(Cow::Borrowed("/ipfs/ping/1.0.0"))),
ProtocolName::BlockAnnounces {
genesis_hash,
fork_id,
} => (genesis_hash, fork_id, "block-announces/1"),
ProtocolName::Transactions {
genesis_hash,
fork_id,
} => (genesis_hash, fork_id, "transactions/1"),
ProtocolName::Grandpa {
genesis_hash,
fork_id,
} => (genesis_hash, fork_id, "grandpa/1"),
ProtocolName::Sync {
genesis_hash,
fork_id,
} => (genesis_hash, fork_id, "sync/2"),
ProtocolName::Light {
genesis_hash,
fork_id,
} => (genesis_hash, fork_id, "light/2"),
ProtocolName::Kad {
genesis_hash,
fork_id,
} => (genesis_hash, fork_id, "kad"),
ProtocolName::SyncWarp {
genesis_hash,
fork_id,
} => (genesis_hash, fork_id, "sync/warp"),
ProtocolName::State {
genesis_hash,
fork_id,
} => (genesis_hash, fork_id, "state/2"),
};

let genesis_hash = hex::encode(&genesis_hash);

if let Some(fork_id) = fork_id {
either::Right(either::Right(
[
Cow::Borrowed("/"),
Cow::Owned(genesis_hash),
Cow::Borrowed("/"),
Cow::Borrowed(fork_id),
Cow::Borrowed("/"),
Cow::Borrowed(base_protocol_name),
]
.into_iter(),
))
} else {
either::Right(either::Left(
[
Cow::Borrowed("/"),
Cow::Owned(genesis_hash),
Cow::Borrowed("/"),
Cow::Borrowed(base_protocol_name),
]
.into_iter(),
))
}
}

pub fn encode_protocol_name_string(protocol: ProtocolName<'_>) -> String {
encode_protocol_name(protocol).fold(String::with_capacity(128), |mut a, b| {
a.push_str(b.as_ref());
a
})
}

/// Decodes a protocol name into its components.
///
/// Returns an error if the protocol name isn't recognized.
pub fn decode_protocol_name(name: &str) -> Result<ProtocolName, ()> {
nom::combinator::all_consuming(nom::branch::alt((
nom::combinator::map(nom::bytes::complete::tag("/ipfs/id/1.0.0"), |_| {
ProtocolName::Identify
}),
nom::combinator::map(nom::bytes::complete::tag("/ipfs/ping/1.0.0"), |_| {
ProtocolName::Ping
}),
nom::combinator::map(
nom::sequence::tuple((
nom::bytes::complete::tag("/"),
genesis_hash,
nom::bytes::complete::tag("/"),
protocol_ty,
)),
|(_, genesis_hash, _, protocol_ty)| {
protocol_ty_to_real_protocol(protocol_ty, genesis_hash, None)
},
),
nom::combinator::map(
nom::sequence::tuple((
nom::bytes::complete::tag("/"),
genesis_hash,
nom::bytes::complete::tag("/"),
nom::bytes::complete::take_until("/"),
nom::bytes::complete::tag("/"),
protocol_ty,
)),
|(_, genesis_hash, _, fork_id, _, protocol_ty)| {
protocol_ty_to_real_protocol(protocol_ty, genesis_hash, Some(fork_id))
},
),
)))(name)
.map(|(_, parse_result)| parse_result)
.map_err(|_| ())
}

fn genesis_hash(name: &str) -> nom::IResult<&str, [u8; 32]> {
nom::combinator::map_opt(nom::bytes::complete::take(64u32), |hash| {
hex::decode(&hash)
.ok()
.map(|hash| <[u8; 32]>::try_from(hash).unwrap_or_else(|_| unreachable!()))
})(name)
}

enum ProtocolTy {
BlockAnnounces,
Transactions,
Grandpa,
Sync,
Light,
Kad,
SyncWarp,
State,
}

fn protocol_ty(name: &str) -> nom::IResult<&str, ProtocolTy> {
nom::branch::alt((
nom::combinator::map(nom::bytes::complete::tag("block-announces/1"), |_| {
ProtocolTy::BlockAnnounces
}),
nom::combinator::map(nom::bytes::complete::tag("transactions/1"), |_| {
ProtocolTy::Transactions
}),
nom::combinator::map(nom::bytes::complete::tag("grandpa/1"), |_| {
ProtocolTy::Grandpa
}),
nom::combinator::map(nom::bytes::complete::tag("sync/2"), |_| ProtocolTy::Sync),
nom::combinator::map(nom::bytes::complete::tag("light/2"), |_| ProtocolTy::Light),
nom::combinator::map(nom::bytes::complete::tag("kad"), |_| ProtocolTy::Kad),
nom::combinator::map(nom::bytes::complete::tag("sync/warp"), |_| {
ProtocolTy::SyncWarp
}),
nom::combinator::map(nom::bytes::complete::tag("state/2"), |_| ProtocolTy::State),
))(name)
}

fn protocol_ty_to_real_protocol(
ty: ProtocolTy,
genesis_hash: [u8; 32],
fork_id: Option<&str>,
) -> ProtocolName {
match ty {
ProtocolTy::BlockAnnounces => ProtocolName::BlockAnnounces {
genesis_hash,
fork_id,
},
ProtocolTy::Transactions => ProtocolName::Transactions {
genesis_hash,
fork_id,
},
ProtocolTy::Grandpa => ProtocolName::Grandpa {
genesis_hash,
fork_id,
},
ProtocolTy::Sync => ProtocolName::Sync {
genesis_hash,
fork_id,
},
ProtocolTy::Light => ProtocolName::Light {
genesis_hash,
fork_id,
},
ProtocolTy::Kad => ProtocolName::Kad {
genesis_hash,
fork_id,
},
ProtocolTy::SyncWarp => ProtocolName::SyncWarp {
genesis_hash,
fork_id,
},
ProtocolTy::State => ProtocolName::State {
genesis_hash,
fork_id,
},
}
}

// TODO: tests for the protocol names
Loading

0 comments on commit 1bb23bc

Please sign in to comment.