Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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.

8 changes: 4 additions & 4 deletions crates/espresso/node/src/api/unlock_schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use chrono::{Months, NaiveDate, NaiveDateTime, NaiveTime};
use espresso_types::{v0_1::ChainId, v0_3::RewardAmount};
use serde::Deserialize;

const SCHEDULE_TOML: &str = include_str!("../../../../../data/token-unlock-schedule.toml");
use crate::MAINNET_CHAIN_ID;

pub(crate) const MAINNET_CHAIN_ID: u64 = 1;
const SCHEDULE_TOML: &str = include_str!("../../../../../data/token-unlock-schedule.toml");

#[derive(Deserialize)]
struct UnlockEntry {
Expand Down Expand Up @@ -120,7 +120,7 @@ impl SupplyCalculator {
/// Tokens still locked on L1 per the unlock schedule.
/// Mainnet: `initial_supply - unlocked(now)`. Non-mainnet: `0`.
fn locked(&self) -> U256 {
if self.chain_id == U256::from(MAINNET_CHAIN_ID) {
if self.chain_id == MAINNET_CHAIN_ID.0 {
self.initial_supply
.saturating_sub(unlocked_amount_at(self.now_secs))
} else {
Expand Down Expand Up @@ -245,7 +245,7 @@ mod tests {
// --- SupplyCalculator tests ---

fn mainnet_id() -> ChainId {
ChainId(U256::from(MAINNET_CHAIN_ID))
MAINNET_CHAIN_ID
}

fn testnet_id() -> ChainId {
Expand Down
7 changes: 7 additions & 0 deletions crates/espresso/node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ use espresso_types::{
SeqTypes, ValidatedState,
traits::{EventConsumer, MembershipPersistence},
v0::traits::SequencerPersistence,
v0_1::ChainId,
v0_3::Fetcher,
};

pub(crate) const MAINNET_CHAIN_ID: ChainId = ChainId(U256::ONE);
pub use genesis::Genesis;
use genesis::L1Finalized;
use hotshot::{
Expand Down Expand Up @@ -758,6 +761,9 @@ where

let combined_network = {
info!("Initializing Libp2p network");
// Mainnet keeps today's libp2p protocol strings byte-identical.
let chain_id = genesis.chain_config.chain_id;
let network_discriminator = (chain_id != MAINNET_CHAIN_ID).then_some(chain_id.0);
let p2p_network = Libp2pNetwork::from_config(
network_config.clone(),
persistence.clone(),
Expand All @@ -770,6 +776,7 @@ where
// (using https://docs.rs/blake3/latest/blake3/fn.derive_key.html)
&validator_config.private_key,
hotshot::traits::implementations::Libp2pMetricsValue::new(&*metrics),
network_discriminator,
)
.await
.with_context(|| {
Expand Down
1 change: 1 addition & 0 deletions crates/hotshot/examples/src/infra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,7 @@ where
public_key,
private_key,
Libp2pMetricsValue::default(),
None,
)
.await
.expect("failed to create libp2p network");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use std::{
#[cfg(feature = "hotshot-testing")]
use std::{collections::HashMap, str::FromStr};

use alloy::primitives::U256;
use anyhow::{Context, anyhow};
use async_lock::RwLock;
use async_trait::async_trait;
Expand Down Expand Up @@ -407,6 +408,7 @@ impl<T: NodeType> Libp2pNetwork<T> {
pub_key: &T::SignatureKey,
priv_key: &<T::SignatureKey as SignatureKey>::PrivateKey,
metrics: Libp2pMetricsValue,
network_discriminator: Option<U256>,
) -> anyhow::Result<Self> {
// Try to take our Libp2p config from our broader network config
let libp2p_config = config
Expand Down Expand Up @@ -456,7 +458,8 @@ impl<T: NodeType> Libp2pNetwork<T> {
.keypair(keypair)
.replication_factor(replication_factor)
.bind_address(Some(bind_address.clone()))
.announce_addresses(announce_addresses);
.announce_addresses(announce_addresses)
.network_discriminator(network_discriminator);

// Connect to the provided bootstrap nodes
config_builder.to_connect_addrs(HashSet::from_iter(libp2p_config.bootstrap_nodes.clone()));
Expand Down
1 change: 1 addition & 0 deletions crates/hotshot/libp2p-networking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ tracing-subscriber = { workspace = true }

[dev-dependencies]
hotshot-example-types = { workspace = true }
insta = { workspace = true }
tracing-test = { workspace = true }

[lints]
Expand Down
85 changes: 82 additions & 3 deletions crates/hotshot/libp2p-networking/src/network/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use std::{
time::{Duration, Instant},
};

use alloy::primitives::U256;
use bimap::BiMap;
use futures::{SinkExt, StreamExt, channel::mpsc};
use hotshot_types::{
Expand Down Expand Up @@ -87,6 +88,53 @@ pub const ESTABLISHED_LIMIT: NonZeroU32 = NonZeroU32::new(ESTABLISHED_LIMIT_UNWR
/// Number of connections to a single peer before logging an error
pub const ESTABLISHED_LIMIT_UNWR: u32 = 10;

/// Mainnet libp2p protocol identifiers. The snapshot tests below lock these down so a
/// change that would partition mainnet (e.g. a stray `protocol_id_prefix` call) is caught.
/// `None` for gossipsub means "do not call `protocol_id_prefix`" — libp2p's defaults
/// (`/meshsub/1.1.0` and `/meshsub/1.0.0`) are then used.
pub(crate) fn mainnet_gossipsub_prefix() -> Option<&'static str> {
None
}

pub(crate) fn mainnet_kad_protocol() -> StreamProtocol {
StreamProtocol::new("/ipfs/kad/1.0.0")
}

pub(crate) fn mainnet_direct_message_protocol() -> StreamProtocol {
StreamProtocol::new("/HotShot/direct_message/1.0")
}

/// Resolve the gossipsub `protocol_id_prefix` for the given network discriminator.
/// `None` returns the mainnet value (the libp2p default).
pub(crate) fn gossipsub_prefix(discriminator: Option<U256>) -> Option<String> {
match discriminator {
None => mainnet_gossipsub_prefix().map(String::from),
Some(d) => Some(format!("/HotShot/gossipsub/1.0/{d:#x}")),
}
}

/// Resolve the kademlia stream protocol for the given network discriminator.
pub(crate) fn kad_protocol(discriminator: Option<U256>) -> Result<StreamProtocol, NetworkError> {
match discriminator {
None => Ok(mainnet_kad_protocol()),
Some(d) => StreamProtocol::try_from_owned(format!("/ipfs/kad/1.0.0/{d:#x}"))
.map_err(|err| NetworkError::ConfigError(format!("invalid kademlia protocol: {err}"))),
}
}

/// Resolve the direct-message stream protocol for the given network discriminator.
pub(crate) fn direct_message_protocol(
discriminator: Option<U256>,
) -> Result<StreamProtocol, NetworkError> {
match discriminator {
None => Ok(mainnet_direct_message_protocol()),
Some(d) => StreamProtocol::try_from_owned(format!("/HotShot/direct_message/1.0/{d:#x}"))
.map_err(|err| {
NetworkError::ConfigError(format!("invalid direct_message protocol: {err}"))
}),
}
}

/// Network definition
#[derive(derive_more::Debug)]
pub struct NetworkNode<T: NodeType, D: DhtPersistentStorage> {
Expand Down Expand Up @@ -215,7 +263,11 @@ impl<T: NodeType, D: DhtPersistentStorage> NetworkNode<T, D> {
};

// Derive a `Gossipsub` config from our gossip config
let gossipsub_config = GossipsubConfigBuilder::default()
let mut gossipsub_builder = GossipsubConfigBuilder::default();
if let Some(prefix) = gossipsub_prefix(config.network_discriminator) {
gossipsub_builder.protocol_id_prefix(prefix);
}
let gossipsub_config = gossipsub_builder
.message_id_fn(message_id_fn) // Use the (blake3) hash of a message as its ID
.validation_mode(ValidationMode::Strict) // Force all messages to have valid signatures
.heartbeat_interval(config.gossip_config.heartbeat_interval) // Time between gossip heartbeats
Expand Down Expand Up @@ -263,7 +315,7 @@ impl<T: NodeType, D: DhtPersistentStorage> NetworkNode<T, D> {
let identify = IdentifyBehaviour::new(identify_cfg);

// - Build DHT needed for peer discovery
let mut kconfig = Config::new(StreamProtocol::new("/ipfs/kad/1.0.0"));
let mut kconfig = Config::new(kad_protocol(config.network_discriminator)?);
kconfig
.set_parallelism(NonZeroUsize::new(5).unwrap())
.set_provider_publication_interval(Some(kademlia_record_republication_interval))
Expand Down Expand Up @@ -303,7 +355,7 @@ impl<T: NodeType, D: DhtPersistentStorage> NetworkNode<T, D> {
RequestResponse::with_codec(
cbor,
[(
StreamProtocol::new("/HotShot/direct_message/1.0"),
direct_message_protocol(config.network_discriminator)?,
ProtocolSupport::Full,
)],
rrconfig.clone(),
Expand Down Expand Up @@ -817,3 +869,30 @@ impl<T: NodeType, D: DhtPersistentStorage> NetworkNode<T, D> {
self.peer_id
}
}

#[cfg(test)]
mod tests {
use super::{U256, direct_message_protocol, gossipsub_prefix, kad_protocol};

fn snapshot_for(discriminator: Option<U256>) -> String {
format!(
"gossipsub_prefix: {:?}\nkad: {}\ndirect_message: {}",
gossipsub_prefix(discriminator),
kad_protocol(discriminator).unwrap(),
direct_message_protocol(discriminator).unwrap(),
)
}

#[test]
fn mainnet_libp2p_protocol_identifiers() {
insta::assert_snapshot!("mainnet_libp2p_protocol_identifiers", snapshot_for(None));
}

#[test]
fn decaf_libp2p_protocol_identifiers() {
insta::assert_snapshot!(
"decaf_libp2p_protocol_identifiers",
snapshot_for(Some(U256::from(0xdecafu64)))
);
}
}
6 changes: 6 additions & 0 deletions crates/hotshot/libp2p-networking/src/network/node/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use std::{collections::HashSet, num::NonZeroUsize, time::Duration};

use alloy::primitives::U256;
use libp2p::{Multiaddr, identity::Keypair};
use libp2p_identity::PeerId;

Expand Down Expand Up @@ -70,6 +71,10 @@ pub struct NetworkNodeConfig {
#[builder(default)]
/// The timeout for DHT lookups.
pub dht_timeout: Option<Duration>,

/// `None` is the legacy value, used for mainnet.
#[builder(default)]
pub network_discriminator: Option<U256>,
}

impl Clone for NetworkNodeConfig {
Expand All @@ -87,6 +92,7 @@ impl Clone for NetworkNodeConfig {
dht_file_path: self.dht_file_path.clone(),
auth_message: self.auth_message.clone(),
dht_timeout: self.dht_timeout,
network_discriminator: self.network_discriminator,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
source: crates/hotshot/libp2p-networking/src/network/node.rs
expression: "snapshot_for(Some(U256::from(0xdecafu64)))"
---
gossipsub_prefix: Some("/HotShot/gossipsub/1.0/0xdecaf")
kad: /ipfs/kad/1.0.0/0xdecaf
direct_message: /HotShot/direct_message/1.0/0xdecaf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
source: crates/hotshot/libp2p-networking/src/network/node.rs
expression: snapshot_for(None)
---
gossipsub_prefix: None
kad: /ipfs/kad/1.0.0
direct_message: /HotShot/direct_message/1.0
Loading