Skip to content

Commit 8f6d601

Browse files
authored
feat: full node (#302)
1 parent a17d6e6 commit 8f6d601

File tree

35 files changed

+1920
-190
lines changed

35 files changed

+1920
-190
lines changed

Cargo.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/chain-spec/src/full_node.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use katana_genesis::Genesis;
2+
use katana_primitives::chain::ChainId;
3+
use lazy_static::lazy_static;
4+
5+
use crate::{FeeContracts, SettlementLayer};
6+
7+
/// The full node chain specification.
8+
#[derive(Debug, Clone, PartialEq, Eq)]
9+
pub struct ChainSpec {
10+
/// The network chain id.
11+
pub id: ChainId,
12+
13+
/// The chain's genesis states.
14+
pub genesis: Genesis,
15+
16+
/// The chain fee token contract.
17+
pub fee_contracts: FeeContracts,
18+
19+
/// The chain's settlement layer configurations (if any).
20+
pub settlement: Option<SettlementLayer>,
21+
}
22+
23+
//////////////////////////////////////////////////////////////
24+
// ChainSpec implementations
25+
//////////////////////////////////////////////////////////////
26+
27+
impl ChainSpec {
28+
/// Creates a new [`ChainSpec`] for Starknet mainnet.
29+
pub fn mainnet() -> Self {
30+
MAINNET.clone()
31+
}
32+
33+
/// Creates a new [`ChainSpec`] for Starknet sepolia testnet.
34+
pub fn sepolia() -> Self {
35+
SEPOLIA.clone()
36+
}
37+
}
38+
39+
//////////////////////////////////////////////////////////////
40+
// Predefined ChainSpec instances
41+
//////////////////////////////////////////////////////////////
42+
43+
lazy_static! {
44+
/// Starknet mainnet chain specification.
45+
pub static ref MAINNET: ChainSpec = ChainSpec {
46+
id: ChainId::MAINNET,
47+
genesis: Genesis::default(),
48+
fee_contracts: FeeContracts {
49+
eth: katana_genesis::constant::DEFAULT_ETH_FEE_TOKEN_ADDRESS,
50+
strk: katana_genesis::constant::DEFAULT_STRK_FEE_TOKEN_ADDRESS,
51+
},
52+
settlement: None,
53+
};
54+
55+
/// Starknet sepolia testnet chain specification.
56+
pub static ref SEPOLIA: ChainSpec = ChainSpec {
57+
id: ChainId::SEPOLIA,
58+
genesis: Genesis::default(),
59+
fee_contracts: FeeContracts {
60+
eth: katana_genesis::constant::DEFAULT_ETH_FEE_TOKEN_ADDRESS,
61+
strk: katana_genesis::constant::DEFAULT_STRK_FEE_TOKEN_ADDRESS,
62+
},
63+
settlement: None,
64+
};
65+
}

crates/chain-spec/src/lib.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ use serde::{Deserialize, Serialize};
66
use url::Url;
77

88
pub mod dev;
9+
pub mod full_node;
910
pub mod rollup;
1011

1112
#[derive(Debug, Clone, PartialEq, Eq)]
1213
pub enum ChainSpec {
1314
Dev(dev::ChainSpec),
1415
Rollup(rollup::ChainSpec),
16+
FullNode(full_node::ChainSpec),
1517
}
1618

1719
//////////////////////////////////////////////////////////////
@@ -24,31 +26,45 @@ impl ChainSpec {
2426
Self::Dev(dev::DEV.clone())
2527
}
2628

29+
/// Creates a new [`ChainSpec`] for Starknet mainnet.
30+
pub fn mainnet() -> Self {
31+
Self::FullNode(full_node::ChainSpec::mainnet())
32+
}
33+
34+
/// Creates a new [`ChainSpec`] for Starknet sepolia testnet.
35+
pub fn sepolia() -> Self {
36+
Self::FullNode(full_node::ChainSpec::sepolia())
37+
}
38+
2739
pub fn id(&self) -> ChainId {
2840
match self {
2941
Self::Dev(spec) => spec.id,
3042
Self::Rollup(spec) => spec.id,
43+
Self::FullNode(spec) => spec.id,
3144
}
3245
}
3346

3447
pub fn genesis(&self) -> &Genesis {
3548
match self {
3649
Self::Dev(spec) => &spec.genesis,
3750
Self::Rollup(spec) => &spec.genesis,
51+
Self::FullNode(spec) => &spec.genesis,
3852
}
3953
}
4054

4155
pub fn settlement(&self) -> Option<&SettlementLayer> {
4256
match self {
4357
Self::Dev(spec) => spec.settlement.as_ref(),
4458
Self::Rollup(spec) => Some(&spec.settlement),
59+
Self::FullNode(spec) => spec.settlement.as_ref(),
4560
}
4661
}
4762

4863
pub fn fee_contracts(&self) -> &FeeContracts {
4964
match self {
5065
Self::Dev(spec) => &spec.fee_contracts,
5166
Self::Rollup(spec) => &spec.fee_contracts,
67+
Self::FullNode(spec) => &spec.fee_contracts,
5268
}
5369
}
5470
}
@@ -65,6 +81,12 @@ impl From<rollup::ChainSpec> for ChainSpec {
6581
}
6682
}
6783

84+
impl From<full_node::ChainSpec> for ChainSpec {
85+
fn from(spec: full_node::ChainSpec) -> Self {
86+
Self::FullNode(spec)
87+
}
88+
}
89+
6890
impl Default for ChainSpec {
6991
fn default() -> Self {
7092
Self::dev()

crates/cli/src/full.rs

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
use std::path::PathBuf;
22

3-
use anyhow::{anyhow, Result};
3+
use anyhow::{Context, Result};
44
pub use clap::Parser;
5+
use katana_node::config::db::DbConfig;
6+
use katana_node::config::metrics::MetricsConfig;
7+
use katana_node::config::rpc::RpcConfig;
8+
use katana_node::full;
9+
use katana_node::full::Network;
510
use serde::{Deserialize, Serialize};
11+
use tracing::info;
612

713
use crate::options::*;
814

15+
pub(crate) const LOG_TARGET: &str = "katana::cli::full";
16+
917
#[derive(Parser, Debug, Serialize, Deserialize, Default, Clone, PartialEq)]
1018
#[command(next_help_heading = "Full node options")]
1119
pub struct FullNodeArgs {
@@ -19,7 +27,19 @@ pub struct FullNodeArgs {
1927
/// previously initialized Katana database.
2028
#[arg(long)]
2129
#[arg(value_name = "PATH")]
22-
pub db_dir: Option<PathBuf>,
30+
pub db_dir: PathBuf,
31+
32+
#[arg(long = "eth.rpc")]
33+
#[arg(value_name = "PATH")]
34+
pub eth_rpc_url: String,
35+
36+
#[arg(long)]
37+
pub network: Network,
38+
39+
/// Gateway API key for accessing the sequencer gateway.
40+
#[arg(long)]
41+
#[arg(value_name = "KEY")]
42+
pub gateway_api_key: Option<String>,
2343

2444
#[command(flatten)]
2545
pub logging: LoggingOptions,
@@ -42,6 +62,102 @@ pub struct FullNodeArgs {
4262

4363
impl FullNodeArgs {
4464
pub async fn execute(&self) -> Result<()> {
45-
Err(anyhow!("Full node is not implemented yet!"))
65+
// Initialize logging with tracer
66+
let tracer_config = self.tracer_config();
67+
katana_tracing::init(self.logging.log_format, tracer_config).await?;
68+
self.start_node().await
69+
}
70+
71+
async fn start_node(&self) -> Result<()> {
72+
// Build the node
73+
let config = self.config()?;
74+
let node = full::Node::build(config).context("failed to build full node")?;
75+
76+
if !self.silent {
77+
info!(target: LOG_TARGET, "Starting full node");
78+
}
79+
80+
// Launch the node
81+
let handle = node.launch().await.context("failed to launch full node")?;
82+
83+
// Wait until an OS signal (ie SIGINT, SIGTERM) is received or the node is shutdown.
84+
tokio::select! {
85+
_ = katana_utils::wait_shutdown_signals() => {
86+
// Gracefully shutdown the node before exiting
87+
handle.stop().await?;
88+
},
89+
90+
_ = handle.stopped() => { }
91+
}
92+
93+
info!("Shutting down.");
94+
95+
Ok(())
96+
}
97+
98+
fn config(&self) -> Result<full::Config> {
99+
let db = self.db_config();
100+
let rpc = self.rpc_config()?;
101+
let metrics = self.metrics_config();
102+
103+
Ok(full::Config {
104+
db,
105+
rpc,
106+
metrics,
107+
network: self.network,
108+
eth_rpc_url: self.eth_rpc_url.clone(),
109+
gateway_api_key: self.gateway_api_key.clone(),
110+
})
111+
}
112+
113+
fn db_config(&self) -> DbConfig {
114+
DbConfig { dir: Some(self.db_dir.clone()) }
115+
}
116+
117+
fn rpc_config(&self) -> Result<RpcConfig> {
118+
#[cfg(feature = "server")]
119+
{
120+
use std::time::Duration;
121+
122+
let cors_origins = self.server.http_cors_origins.clone();
123+
124+
Ok(RpcConfig {
125+
apis: Default::default(),
126+
port: self.server.http_port,
127+
addr: self.server.http_addr,
128+
max_connections: self.server.max_connections,
129+
max_concurrent_estimate_fee_requests: None,
130+
max_request_body_size: None,
131+
max_response_body_size: None,
132+
timeout: self.server.timeout.map(Duration::from_secs),
133+
cors_origins,
134+
#[cfg(feature = "explorer")]
135+
explorer: self.explorer.explorer,
136+
max_event_page_size: Some(self.server.max_event_page_size),
137+
max_proof_keys: Some(self.server.max_proof_keys),
138+
max_call_gas: Some(self.server.max_call_gas),
139+
})
140+
}
141+
142+
#[cfg(not(feature = "server"))]
143+
{
144+
Ok(RpcConfig::default())
145+
}
146+
}
147+
148+
fn metrics_config(&self) -> Option<MetricsConfig> {
149+
#[cfg(feature = "server")]
150+
if self.metrics.metrics {
151+
Some(MetricsConfig { addr: self.metrics.metrics_addr, port: self.metrics.metrics_port })
152+
} else {
153+
None
154+
}
155+
156+
#[cfg(not(feature = "server"))]
157+
None
158+
}
159+
160+
fn tracer_config(&self) -> Option<katana_tracing::TracerConfig> {
161+
self.tracer.config()
46162
}
47163
}

crates/cli/src/utils.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ PREDEPLOYED CONTRACTS
130130
cs.fee_contracts.strk, DEFAULT_LEGACY_ERC20_CLASS_HASH,
131131
);
132132
}
133+
134+
ChainSpec::FullNode(..) => {}
133135
}
134136

135137
println!(

crates/core/src/backend/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ impl<EF: ExecutorFactory> Backend<EF> {
7676
match self.chain_spec.as_ref() {
7777
ChainSpec::Dev(cs) => self.init_dev_genesis(cs),
7878
ChainSpec::Rollup(cs) => self.init_rollup_genesis(cs),
79+
ChainSpec::FullNode(_) => {
80+
// Full nodes sync from the network, so we skip genesis initialization
81+
info!("Full node mode: genesis initialization skipped, will sync from network");
82+
Ok(())
83+
}
7984
}
8085
}
8186

crates/gateway/gateway-server/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ version.workspace = true
77

88
[dependencies]
99
katana-gateway-types.workspace = true
10+
katana-primitives.workspace = true
1011
katana-executor.workspace = true
1112
katana-core.workspace = true
12-
katana-primitives.workspace = true
1313
katana-metrics.workspace = true
1414
katana-pool.workspace = true
1515
katana-rpc-server.workspace = true
16+
katana-pool-api.workspace = true
1617
katana-rpc-api.workspace = true
1718
katana-provider-api.workspace = true
1819
serde-utils.workspace = true

0 commit comments

Comments
 (0)