Inline noise into OnlyValidators

libp2p does support (noise, OnlyValidators) but it'll interpret it as either,
not a chain. This will act as the desired chain.
This commit is contained in:
Luke Parker
2025-01-05 00:55:25 -05:00
parent 96518500b1
commit c6d0fb477c
5 changed files with 35 additions and 26 deletions

1
Cargo.lock generated
View File

@@ -8327,6 +8327,7 @@ dependencies = [
"parity-scale-codec", "parity-scale-codec",
"rand_core", "rand_core",
"schnorr-signatures", "schnorr-signatures",
"schnorrkel",
"serai-client", "serai-client",
"serai-cosign", "serai-cosign",
"serai-db", "serai-db",

View File

@@ -29,7 +29,7 @@ pub use delay::BROADCAST_FREQUENCY;
use delay::LatestCosignedBlockNumber; use delay::LatestCosignedBlockNumber;
/// The schnorrkel context to used when signing a cosign. /// The schnorrkel context to used when signing a cosign.
pub const COSIGN_CONTEXT: &[u8] = b"serai-cosign"; pub const COSIGN_CONTEXT: &[u8] = b"/serai/coordinator/cosign";
/// A 'global session', defined as all validator sets used for cosigning at a given moment. /// A 'global session', defined as all validator sets used for cosigning at a given moment.
/// ///

View File

@@ -12,7 +12,12 @@ use serai_client::primitives::PublicKey as Public;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use futures_util::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use futures_util::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use libp2p::{core::UpgradeInfo, InboundUpgrade, OutboundUpgrade, identity::PeerId, noise}; use libp2p::{
core::UpgradeInfo,
InboundUpgrade, OutboundUpgrade,
identity::{self, PeerId},
noise,
};
use crate::p2p::{validators::Validators, peer_id_from_public}; use crate::p2p::{validators::Validators, peer_id_from_public};
@@ -21,7 +26,7 @@ const PROTOCOL: &str = "/serai/coordinator/validators";
struct OnlyValidators { struct OnlyValidators {
validators: Arc<RwLock<Validators>>, validators: Arc<RwLock<Validators>>,
serai_key: Zeroizing<Keypair>, serai_key: Zeroizing<Keypair>,
our_peer_id: PeerId, noise_keypair: identity::Keypair,
} }
impl OnlyValidators { impl OnlyValidators {
@@ -112,33 +117,35 @@ impl OnlyValidators {
} }
impl UpgradeInfo for OnlyValidators { impl UpgradeInfo for OnlyValidators {
type Info = &'static str; type Info = <noise::Config as UpgradeInfo>::Info;
type InfoIter = [&'static str; 1]; type InfoIter = <noise::Config as UpgradeInfo>::InfoIter;
fn protocol_info(&self) -> [&'static str; 1] { fn protocol_info(&self) -> Self::InfoIter {
[PROTOCOL] // A keypair only causes an error if its sign operation fails, which is only possible with RSA,
// which isn't used within this codebase
noise::Config::new(&self.noise_keypair).unwrap().protocol_info()
} }
} }
impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundUpgrade<(PeerId, noise::Output<S>)> impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundUpgrade<S> for OnlyValidators {
for OnlyValidators
{
type Output = (PeerId, noise::Output<S>); type Output = (PeerId, noise::Output<S>);
type Error = io::Error; type Error = io::Error;
type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>; type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>;
fn upgrade_inbound( fn upgrade_inbound(self, socket: S, info: Self::Info) -> Self::Future {
self,
(dialer_noise_peer_id, mut socket): (PeerId, noise::Output<S>),
_: Self::Info,
) -> Self::Future {
Box::pin(async move { Box::pin(async move {
let (dialer_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair)
.unwrap()
.upgrade_inbound(socket, info)
.await
.map_err(io::Error::other)?;
let (our_challenge, dialer_challenge) = OnlyValidators::challenges(&mut socket).await?; let (our_challenge, dialer_challenge) = OnlyValidators::challenges(&mut socket).await?;
let dialer_serai_validator = self let dialer_serai_validator = self
.authenticate( .authenticate(
&mut socket, &mut socket,
dialer_noise_peer_id, dialer_noise_peer_id,
dialer_challenge, dialer_challenge,
self.our_peer_id, PeerId::from_public_key(&self.noise_keypair.public()),
our_challenge, our_challenge,
) )
.await?; .await?;
@@ -147,24 +154,24 @@ impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundUpgrade<(PeerId,
} }
} }
impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> OutboundUpgrade<(PeerId, noise::Output<S>)> impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> OutboundUpgrade<S> for OnlyValidators {
for OnlyValidators
{
type Output = (PeerId, noise::Output<S>); type Output = (PeerId, noise::Output<S>);
type Error = io::Error; type Error = io::Error;
type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>; type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>;
fn upgrade_outbound( fn upgrade_outbound(self, socket: S, info: Self::Info) -> Self::Future {
self,
(listener_noise_peer_id, mut socket): (PeerId, noise::Output<S>),
_: Self::Info,
) -> Self::Future {
Box::pin(async move { Box::pin(async move {
let (listener_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair)
.unwrap()
.upgrade_outbound(socket, info)
.await
.map_err(io::Error::other)?;
let (our_challenge, listener_challenge) = OnlyValidators::challenges(&mut socket).await?; let (our_challenge, listener_challenge) = OnlyValidators::challenges(&mut socket).await?;
let listener_serai_validator = self let listener_serai_validator = self
.authenticate( .authenticate(
&mut socket, &mut socket,
self.our_peer_id, PeerId::from_public_key(&self.noise_keypair.public()),
our_challenge, our_challenge,
listener_noise_peer_id, listener_noise_peer_id,
listener_challenge, listener_challenge,

View File

@@ -100,6 +100,7 @@ impl SwarmTask {
biased; biased;
// Refresh the instance of validators we use to track peers/share with authenticate // Refresh the instance of validators we use to track peers/share with authenticate
// TODO: Move this to a task
() = tokio::time::sleep(time_till_refresh_validators) => { () = tokio::time::sleep(time_till_refresh_validators) => {
const TIME_BETWEEN_REFRESH_VALIDATORS: Duration = Duration::from_secs(60); const TIME_BETWEEN_REFRESH_VALIDATORS: Duration = Duration::from_secs(60);
const MAX_TIME_BETWEEN_REFRESH_VALIDATORS: Duration = Duration::from_secs(5 * 60); const MAX_TIME_BETWEEN_REFRESH_VALIDATORS: Duration = Duration::from_secs(5 * 60);

View File

@@ -65,7 +65,7 @@ where
let validators = client.runtime_api().validators(latest_block, network).map_err(|_| { let validators = client.runtime_api().validators(latest_block, network).map_err(|_| {
jsonrpsee::core::Error::to_call_error(std::io::Error::other(format!( jsonrpsee::core::Error::to_call_error(std::io::Error::other(format!(
"couldn't get validators from the latest block, which is likely a fatal bug. {}", "couldn't get validators from the latest block, which is likely a fatal bug. {}",
"please report this at https://github.com/serai-dex/serai", "please report this at https://github.com/serai-dex/serai/issues",
))) )))
})?; })?;
// Always return the protocol's bootnodes // Always return the protocol's bootnodes