Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DSN client to subspace-gateway binary #3137

Merged
merged 5 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions crates/subspace-gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
anyhow = "1.0.89"
async-trait = "0.1.83"
clap = { version = "4.5.18", features = ["derive"] }
fdlimit = "0.3.0"
futures = "0.3.31"
hex = "0.4.3"
jsonrpsee = { version = "0.24.5", features = ["server"] }
mimalloc = "0.1.43"
parking_lot = "0.12.2"
subspace-core-primitives = { version = "0.1.0", path = "../subspace-core-primitives" }
subspace-networking = { version = "0.1.0", path = "../subspace-networking" }
subspace-rpc-primitives = { version = "0.1.0", path = "../subspace-rpc-primitives" }
supports-color = "3.0.1"
Expand Down
13 changes: 9 additions & 4 deletions crates/subspace-gateway/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub(super) struct GatewayOptions {
dev: bool,

#[clap(flatten)]
dsn: NetworkArgs,
dsn_options: NetworkArgs,
}

/// Default run command for gateway
Expand All @@ -38,21 +38,26 @@ pub async fn run(run_options: RunOptions) -> anyhow::Result<()> {
let signal = shutdown_signal();

let RunOptions {
gateway: GatewayOptions { dev, mut dsn },
gateway: GatewayOptions {
dev,
mut dsn_options,
},
} = run_options;

// Development mode handling is limited to this section
{
if dev {
dsn.allow_private_ips = true;
dsn_options.allow_private_ips = true;
}
}

info!("Subspace Gateway");
info!("✌️ version {}", env!("CARGO_PKG_VERSION"));
info!("❤️ by {}", env!("CARGO_PKG_AUTHORS"));

let (_dsn_node, mut dsn_node_runner) = dsn::configure_network(dsn)?;
// TODO: move this service code into its own function, in a new library part of this crate
#[expect(unused_variables, reason = "implementation is incomplete")]
let (dsn_node, mut dsn_node_runner, node_client) = dsn::configure_network(dsn_options).await?;
let dsn_fut = dsn_node_runner.run();

let rpc_fut = future::pending::<()>();
Expand Down
63 changes: 50 additions & 13 deletions crates/subspace-gateway/src/commands/run/dsn.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
//! DSN config and implementation for the gateway.

use clap::Parser;
use crate::node_client::{NodeClient, RpcNodeClient};
use anyhow::anyhow;
use clap::{Parser, ValueHint};
use subspace_networking::libp2p::kad::Mode;
use subspace_networking::libp2p::Multiaddr;
use subspace_networking::{construct, Config, KademliaMode, Node, NodeRunner};
use tracing::{debug, info};

/// Configuration for network stack
#[derive(Debug, Parser)]
pub(crate) struct NetworkArgs {
/// Multiaddrs of DSN bootstrap nodes to connect to on startup, multiple are supported
/// WebSocket RPC URL of the Subspace node to connect to.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listen-on is always helpful for local debugging as well as for setting up some cloud infrastructure. I'd add this parameter.

///
/// This node provides the DSN protocol version, default bootstrap nodes, and piece validation
/// metadata.
#[arg(long, value_hint = ValueHint::Url, default_value = "ws://127.0.0.1:9944")]
node_rpc_url: String,

/// Multiaddrs of DSN bootstrap nodes to connect to on startup, multiple are supported.
///
/// The default bootstrap nodes are fetched from the node RPC connection.
#[arg(long)]
pub(crate) dsn_bootstrap_nodes: Vec<Multiaddr>,
teor2345 marked this conversation as resolved.
Show resolved Hide resolved

/// Multiaddrs of DSN reserved nodes to maintain a connection to, multiple are supported.
#[arg(long)]
dsn_reserved_peers: Vec<Multiaddr>,

/// Enable non-global (private, shared, loopback..) addresses in the Kademlia DHT.
/// By default these addresses are excluded from the DHT.
#[arg(long, default_value_t = false)]
pub(crate) allow_private_ips: bool,
teor2345 marked this conversation as resolved.
Show resolved Hide resolved

/// Multiaddrs of DSN reserved nodes to maintain a connection to, multiple are supported
#[arg(long)]
pub(crate) dsn_reserved_peers: Vec<Multiaddr>,

/// Maximum established outgoing swarm connection limit.
#[arg(long, default_value_t = 100)]
pub(crate) out_connections: u32,
Expand All @@ -31,32 +43,57 @@ pub(crate) struct NetworkArgs {
}

/// Create a DSN network client with the supplied configuration.
pub(crate) fn configure_network(
// TODO:
// - move this DSN code into a new library part of this crate
// - change NetworkArgs to a struct that's independent of clap
pub async fn configure_network(
NetworkArgs {
dsn_bootstrap_nodes,
allow_private_ips,
node_rpc_url,
mut dsn_bootstrap_nodes,
dsn_reserved_peers,
allow_private_ips,
out_connections,
pending_out_connections,
}: NetworkArgs,
) -> anyhow::Result<(Node, NodeRunner<()>)> {
) -> anyhow::Result<(Node, NodeRunner<()>, RpcNodeClient)> {
// TODO:
// - store keypair on disk and allow CLI override
// - cache known peers on disk
// - get default dsnBootstrapNodes from chainspec?
// - prometheus telemetry
let default_config = Config::<()>::default();

info!(url = %node_rpc_url, "Connecting to node RPC");
let node_client = RpcNodeClient::new(&node_rpc_url)
.await
.map_err(|error| anyhow!("Failed to connect to node RPC: {error}"))?;

// The gateway only needs the first part of the farmer info.
let farmer_app_info = node_client
.farmer_app_info()
.await
.map_err(|error| anyhow!("Failed to get farmer app info: {error}"))?;

// Fall back to the node's bootstrap nodes.
if dsn_bootstrap_nodes.is_empty() {
debug!(dsn_bootstrap_nodes = ?farmer_app_info.dsn_bootstrap_nodes, "Setting DSN bootstrap nodes...");
dsn_bootstrap_nodes.clone_from(&farmer_app_info.dsn_bootstrap_nodes);
}

let dsn_protocol_version = hex::encode(farmer_app_info.genesis_hash);
debug!(?dsn_protocol_version, "Setting DSN protocol version...");

let config = Config {
protocol_version: dsn_protocol_version,
bootstrap_addresses: dsn_bootstrap_nodes,
reserved_peers: dsn_reserved_peers,
allow_non_global_addresses_in_dht: allow_private_ips,
max_established_outgoing_connections: out_connections,
max_pending_outgoing_connections: pending_out_connections,
bootstrap_addresses: dsn_bootstrap_nodes,
kademlia_mode: KademliaMode::Static(Mode::Client),
..default_config
};

let (node, node_runner) = construct(config)?;

Ok((node, node_runner))
Ok((node, node_runner, node_client))
}
Loading