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

Feat/node builder #226

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion Cargo.lock

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

1 change: 0 additions & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ lumina-node = { workspace = true }
anyhow = "1.0.71"
axum = "0.6.20"
clap = { version = "4.4.4", features = ["derive"] }
directories = "5.0.1"
dotenvy = "0.15.7"
mime_guess = "2.0"
rust-embed = { version = "8.0.0", features = ["interpolate-folder-path"] }
Expand Down
91 changes: 29 additions & 62 deletions cli/src/native.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
use std::env;
use std::path::Path;
use std::path::PathBuf;
use std::time::Duration;

use anyhow::{bail, Context, Result};
use celestia_rpc::prelude::*;
use celestia_rpc::Client;
use clap::Parser;
use directories::ProjectDirs;
use libp2p::{identity, multiaddr::Protocol, Multiaddr};
use libp2p::{multiaddr::Protocol, Multiaddr};
use lumina_node::blockstore::SledBlockstore;
use lumina_node::network::{canonical_network_bootnodes, network_genesis, network_id, Network};
use lumina_node::node::{Node, NodeConfig};
use lumina_node::store::{SledStore, Store};
use lumina_node::network::Network;
use lumina_node::node::Node;
use lumina_node::store::SledStore;
use sled::Db;
use tokio::fs;
use tokio::task::spawn_blocking;
use tokio::time::sleep;
use tracing::info;
use tracing::warn;

use crate::common::ArgNetwork;

Expand All @@ -44,41 +42,35 @@ pub(crate) struct Params {

pub(crate) async fn run(args: Params) -> Result<()> {
let network = args.network.into();
let p2p_local_keypair = identity::Keypair::generate_ed25519();

let p2p_bootnodes = if args.bootnodes.is_empty() {
let bootnodes = if args.bootnodes.is_empty() {
match network {
Network::Private => fetch_bridge_multiaddrs(CELESTIA_LOCAL_BRIDGE_RPC_ADDR).await?,
network => canonical_network_bootnodes(network).collect(),
network => network.canonical_bootnodes().collect(),
}
} else {
args.bootnodes
};

let network_id = network_id(network).to_owned();
let genesis_hash = network_genesis(network);

info!("Initializing store");
let db = open_db(args.store, &network_id).await?;
let store = SledStore::new(db.clone()).await?;
let blockstore = SledBlockstore::new(db).await?;

match store.head_height().await {
Ok(height) => info!("Initialised store with head height: {height}"),
Err(_) => info!("Initialised new store"),
}

let node = Node::new(NodeConfig {
network_id,
genesis_hash,
p2p_local_keypair,
p2p_bootnodes,
p2p_listen_on: args.listen_addrs,
blockstore,
store,
})
.await
.context("Failed to start node")?;
let node = if let Some(path) = args.store {
let db = open_db(path).await?;
let store = SledStore::new(db.clone()).await?;
let blockstore = SledBlockstore::new(db).await?;
Node::from_network(network)
.with_bootnodes(bootnodes)
.with_store(store)
.with_blockstore(blockstore)
.build()
.await
.context("Failed to start node")?
} else {
Node::from_network(network)
.with_bootnodes(bootnodes)
.with_default_blockstore()
.build()
.await
.context("Failed to start node")?
};

node.wait_connected_trusted().await?;

Expand All @@ -88,34 +80,9 @@ pub(crate) async fn run(args: Params) -> Result<()> {
}
}

async fn open_db(path: Option<PathBuf>, network_id: &str) -> Result<Db> {
if let Some(path) = path {
let db = spawn_blocking(|| sled::open(path)).await??;
return Ok(db);
}

let cache_dir =
ProjectDirs::from("co", "eiger", "lumina").context("Couldn't find lumina's cache dir")?;
let mut cache_dir = cache_dir.cache_dir().to_owned();

// TODO: remove it in 2 months or after a few releases
// If we find an old ('celestia') cache dir, move it to the new one.
if let Some(old_cache_dir) = ProjectDirs::from("co", "eiger", "celestia") {
let old_cache_dir = old_cache_dir.cache_dir();
if old_cache_dir.exists() && !cache_dir.exists() {
warn!(
"Migrating old cache dir to a new location: {} -> {}",
old_cache_dir.display(),
cache_dir.display()
);
fs::rename(old_cache_dir, &cache_dir).await?;
}
}

cache_dir.push(network_id);
// TODO: should we create there also a subdirectory for the 'db'
// in case we want to put there some other stuff too?
let db = spawn_blocking(|| sled::open(cache_dir)).await??;
async fn open_db(path: impl AsRef<Path>) -> Result<Db> {
let path = path.as_ref().to_owned();
let db = spawn_blocking(|| sled::open(path)).await??;
Ok(db)
}

Expand Down
9 changes: 5 additions & 4 deletions cli/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use celestia_types::hash::Hash;
use clap::Args;
use libp2p::multiaddr::Protocol;
use libp2p::Multiaddr;
use lumina_node::network::{canonical_network_bootnodes, network_genesis};
use lumina_node::network::Network;
use rust_embed::RustEmbed;
use serde::Serialize;
use tracing::info;
Expand Down Expand Up @@ -50,10 +50,11 @@ pub(crate) struct Params {
}

pub(crate) async fn run(args: Params) -> Result<()> {
let network = args.network.into();
let genesis_hash = network_genesis(network);
let network = Network::from(args.network);
let genesis_hash = network.genesis();
let bootnodes = if args.bootnodes.is_empty() {
canonical_network_bootnodes(network)
network
.canonical_bootnodes()
.filter(|addr| addr.iter().any(|proto| proto == Protocol::WebTransport))
.collect()
} else {
Expand Down
1 change: 1 addition & 0 deletions node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ tracing = "0.1.37"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
backoff = { version = "0.4.0", features = ["tokio"] }
blockstore = { workspace = true, features = ["sled"] }
directories = "5.0.1"
# Upgrading this dependency invalidates existing persistent dbs.
# Those can be restored by migrating between versions:
# https://docs.rs/sled/latest/sled/struct.Db.html#examples-1
Expand Down
3 changes: 2 additions & 1 deletion node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ pub mod blockstore;
mod executor;
pub mod network;
pub mod node;
mod node_builder;
pub mod p2p;
pub mod peer_tracker;
pub mod store;
pub mod syncer;
#[cfg(any(test, feature = "test-utils"))]
#[cfg_attr(docs_rs, doc(cfg(feature = "test-utils")))]
pub mod test_utils;
mod utils;
pub mod utils;
68 changes: 35 additions & 33 deletions node/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,34 @@ impl FromStr for Network {
}

/// Get the string id of the given network.
pub fn network_id(network: Network) -> &'static str {
match network {
Network::Arabica => "arabica-10",
Network::Mocha => "mocha-4",
Network::Private => "private",
Network::Mainnet => "celestia",
impl Network {
pub fn id(&self) -> &'static str {
match self {
Network::Arabica => "arabica-10",
Network::Mocha => "mocha-4",
Network::Private => "private",
Network::Mainnet => "celestia",
}
}
}

/// Get the hash of a genesis block for the given network.
pub fn network_genesis(network: Network) -> Option<Hash> {
let hex = match network {
Network::Mainnet => "6BE39EFD10BA412A9DB5288488303F5DD32CF386707A5BEF33617F4C43301872",
Network::Arabica => "5904E55478BA4B3002EE885621E007A2A6A2399662841912219AECD5D5CBE393",
Network::Mocha => "B93BBE20A0FBFDF955811B6420F8433904664D45DB4BF51022BE4200C1A1680D",
Network::Private => return None,
};
/// Get the hash of a genesis block for the given network.
pub fn genesis(&self) -> Option<Hash> {
let hex = match self {
Network::Mainnet => "6BE39EFD10BA412A9DB5288488303F5DD32CF386707A5BEF33617F4C43301872",
Network::Arabica => "5904E55478BA4B3002EE885621E007A2A6A2399662841912219AECD5D5CBE393",
Network::Mocha => "B93BBE20A0FBFDF955811B6420F8433904664D45DB4BF51022BE4200C1A1680D",
Network::Private => return None,
};

let bytes = hex::decode(hex).expect("failed decoding genesis hash");
let array = bytes.try_into().expect("invalid genesis hash lenght");
let bytes = hex::decode(hex).expect("failed decoding genesis hash");
let array = bytes.try_into().expect("invalid genesis hash lenght");

Some(Hash::Sha256(array))
}
Some(Hash::Sha256(array))
}

/// Get official Celestia and Lumina bootnodes for the given network.
pub fn canonical_network_bootnodes(network: Network) -> impl Iterator<Item = Multiaddr> {
let peers: &[_] = match network {
/// Get official Celestia and Lumina bootnodes for the given network.
pub fn canonical_bootnodes(&self) -> impl Iterator<Item = Multiaddr> {
let peers: &[_] = match self {
Network::Mainnet => &[
"/dns4/lumina.eiger.co/tcp/2121/p2p/12D3KooW9z4jLqwodwNRcSa5qgcSgtJ13kN7CYLcwZQjPRYodqWx",
"/dns4/lumina.eiger.co/udp/2121/quic-v1/webtransport/p2p/12D3KooW9z4jLqwodwNRcSa5qgcSgtJ13kN7CYLcwZQjPRYodqWx",
Expand Down Expand Up @@ -94,9 +95,10 @@ pub fn canonical_network_bootnodes(network: Network) -> impl Iterator<Item = Mul
],
Network::Private => &[],
};
peers
.iter()
.map(|s| s.parse().expect("Invalid bootstrap address"))
peers
.iter()
.map(|s| s.parse().expect("Invalid bootstrap address"))
}
}

#[cfg(test)]
Expand All @@ -105,32 +107,32 @@ mod tests {

#[test]
fn test_network_genesis() {
let mainnet = network_genesis(Network::Mainnet);
let mainnet = Network::Mainnet.genesis();
assert!(mainnet.is_some());

let arabica = network_genesis(Network::Arabica);
let arabica = Network::Arabica.genesis();
assert!(arabica.is_some());

let mocha = network_genesis(Network::Mocha);
let mocha = Network::Mocha.genesis();
assert!(mocha.is_some());

let private = network_genesis(Network::Private);
let private = Network::Private.genesis();
assert!(private.is_none());
}

#[test]
fn test_canonical_network_bootnodes() {
// canonical_network_bootnodes works on const data, test it doesn't panic and the data is there
let mainnet = canonical_network_bootnodes(Network::Mainnet);
let mainnet = Network::Mainnet.canonical_bootnodes();
assert_ne!(mainnet.count(), 0);

let arabica = canonical_network_bootnodes(Network::Arabica);
let arabica = Network::Arabica.canonical_bootnodes();
assert_ne!(arabica.count(), 0);

let mocha = canonical_network_bootnodes(Network::Mocha);
let mocha = Network::Mocha.canonical_bootnodes();
assert_ne!(mocha.count(), 0);

let private = canonical_network_bootnodes(Network::Private);
let private = Network::Private.canonical_bootnodes();
assert_eq!(private.count(), 0);
}
}
Loading
Loading