Skip to content

Commit

Permalink
chore(network): Port Types to Alloy (#239)
Browse files Browse the repository at this point in the history
* chore(network): port types to alloy

* chore(network): port types to alloy

* chore(network): fix enr encoding/decoding
  • Loading branch information
refcell authored Apr 30, 2024
1 parent 3fa1617 commit 88610fc
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 41 deletions.
42 changes: 3 additions & 39 deletions src/network/service/discovery.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
//! Module handles Discv5 discovery
use std::{str::FromStr, time::Duration};

use super::enr::OpStackEnrData;
use discv5::{
enr::{CombinedKey, Enr, EnrBuilder, NodeId},
Discv5, Discv5Config,
};
use ethers::utils::rlp;
use eyre::Result;
use tokio::{
sync::mpsc::{self, Receiver},
time::sleep,
};
use unsigned_varint::{decode, encode};

use super::types::{NetworkAddress, Peer};

Expand Down Expand Up @@ -81,43 +82,6 @@ fn create_disc(chain_id: u64) -> Result<Discv5> {
Discv5::new(enr, key, config).map_err(|_| eyre::eyre!("could not create disc service"))
}

/// The unique L2 network identifier
#[derive(Debug)]
struct OpStackEnrData {
/// Chain ID
chain_id: u64,
/// The version. Always set to 0.
version: u64,
}

impl TryFrom<&[u8]> for OpStackEnrData {
type Error = eyre::Report;

/// Converts a slice of RLP encoded bytes to [OpStackEnrData]
fn try_from(value: &[u8]) -> Result<Self> {
let bytes: Vec<u8> = rlp::decode(value)?;
let (chain_id, rest) = decode::u64(&bytes)?;
let (version, _) = decode::u64(rest)?;

Ok(Self { chain_id, version })
}
}

impl From<OpStackEnrData> for Vec<u8> {
/// Converts [OpStackEnrData] to a vector of bytes.
fn from(value: OpStackEnrData) -> Vec<u8> {
let mut chain_id_buf = encode::u128_buffer();
let chain_id_slice = encode::u128(value.chain_id as u128, &mut chain_id_buf);

let mut version_buf = encode::u128_buffer();
let version_slice = encode::u128(value.version as u128, &mut version_buf);

let opstack = [chain_id_slice, version_slice].concat();

rlp::encode(&opstack).to_vec()
}
}

/// Default bootnodes to use. Currently consists of 2 Base bootnodes & 1 Optimism bootnode.
fn bootnodes() -> Vec<Enr<CombinedKey>> {
let bootnodes = [
Expand Down
93 changes: 93 additions & 0 deletions src/network/service/enr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//! Contains the [OpStackEnrData] struct.
use alloy_rlp::{Buf, Decodable, Encodable, Error};
use eyre::Result;

#[derive(Debug, Copy, Default, PartialEq, Clone)]
pub struct OpStackEnrData {
/// Chain ID
pub chain_id: u64,
/// The version. Always set to 0.
pub version: u64,
}

impl Decodable for OpStackEnrData {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
buf.advance(1); // Advance past the string rlp type
let (chain_id, rest) =
unsigned_varint::decode::u64(buf).map_err(|_| Error::Custom("Invalid chain id"))?;
let (version, _) =
unsigned_varint::decode::u64(rest).map_err(|_| Error::Custom("Invalid version"))?;
Ok(OpStackEnrData { chain_id, version })
}
}

impl Encodable for OpStackEnrData {
fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
out.put_u8(0x87); // RLP string type
let encoded: &mut [u8; 10] = &mut [0; 10];
let chain_id = unsigned_varint::encode::u64(self.chain_id, encoded);
out.put_slice(chain_id);
let version = unsigned_varint::encode::u64(self.version, encoded);
out.put_slice(version);
}
}

impl TryFrom<&[u8]> for OpStackEnrData {
type Error = eyre::Report;

/// Converts a slice of RLP encoded bytes to [OpStackEnrData]
fn try_from(mut value: &[u8]) -> Result<Self> {
Ok(OpStackEnrData::decode(&mut value)?)
}
}

impl From<OpStackEnrData> for Vec<u8> {
/// Converts [OpStackEnrData] to a vector of bytes.
fn from(value: OpStackEnrData) -> Vec<u8> {
let mut bytes = Vec::new();
value.encode(&mut bytes);
bytes
}
}

#[cfg(test)]
mod tests {
use super::*;
use alloy_rlp::BytesMut;

#[test]
fn test_decode_encode_raw() {
let raw = &[0x87, 0x7b, 0x01];
let decoded = OpStackEnrData::try_from(&raw[..]).unwrap();
assert_eq!(decoded.chain_id, 123);
assert_eq!(decoded.version, 1);
let mut buf = BytesMut::new();
decoded.encode(&mut buf);
assert_eq!(&buf[..], raw);
}

#[test]
fn test_empty_round_trip() {
let data = OpStackEnrData {
chain_id: 0,
version: 0,
};
let bytes: Vec<u8> = data.into();
let decoded = OpStackEnrData::try_from(bytes.as_slice()).unwrap();
assert_eq!(decoded.chain_id, 0);
assert_eq!(decoded.version, 0);
}

#[test]
fn test_round_trip_large() {
let data = OpStackEnrData {
chain_id: u64::MAX / 2,
version: u64::MAX / 3,
};
let bytes: Vec<u8> = data.into();
let decoded = OpStackEnrData::try_from(bytes.as_slice()).unwrap();
assert_eq!(decoded.chain_id, data.chain_id);
assert_eq!(decoded.version, data.version);
}
}
3 changes: 1 addition & 2 deletions src/network/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ use openssl::sha::sha256;

use super::{handlers::Handler, service::types::NetworkAddress};

/// A module to handle peer discovery
mod discovery;
/// A module to handle commonly used types in the p2p system.
mod enr;
mod types;

/// Responsible for management of the `Discv5` & `libp2p` services.
Expand Down
1 change: 1 addition & 0 deletions src/network/service/types.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// Module contains commonly used types in the p2p system.
use std::net::{IpAddr, Ipv4Addr, SocketAddr};

use discv5::enr::{CombinedKey, Enr};
Expand Down

0 comments on commit 88610fc

Please sign in to comment.