Skip to content

Commit a9a54a0

Browse files
Merge pull request #77 from inicio-labs/issue-38/bor-node-wiring
feat(bor-node): wire BorNode with all components and CLI binary
2 parents ed121fa + f7b1351 commit a9a54a0

7 files changed

Lines changed: 290 additions & 2 deletions

File tree

Cargo.lock

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

bin/boreth/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ edition.workspace = true
66
[[bin]]
77
name = "boreth"
88
path = "src/main.rs"
9+
10+
[dependencies]
11+
bor-node = { workspace = true }
12+
eyre = { workspace = true }

bin/boreth/src/main.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1-
fn main() {
2-
println!("boreth");
1+
use bor_node::{BorNode, BorNodeConfig};
2+
3+
fn main() -> eyre::Result<()> {
4+
let args: Vec<String> = std::env::args().collect();
5+
6+
let network = if args.iter().any(|a| a == "--amoy") {
7+
"amoy"
8+
} else {
9+
"mainnet"
10+
};
11+
12+
let config = match network {
13+
"amoy" => BorNodeConfig::amoy(),
14+
_ => BorNodeConfig::mainnet(),
15+
};
16+
17+
println!("boreth v{}", env!("CARGO_PKG_VERSION"));
18+
println!("Network: {:?}", config.network);
19+
println!("Chain ID: {}", config.chain_id());
20+
println!("Heimdall: {}", config.heimdall_url);
21+
println!("Data dir: {}", config.data_dir);
22+
23+
let node = BorNode::new(config)?;
24+
println!("Node initialized (chain_id={})", node.chain_id());
25+
26+
Ok(())
327
}

crates/bor-node/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,16 @@ version.workspace = true
44
edition.workspace = true
55

66
[dependencies]
7+
bor-chainspec = { workspace = true }
8+
bor-consensus = { workspace = true }
9+
bor-evm = { workspace = true }
10+
bor-payload = { workspace = true }
11+
bor-primitives = { workspace = true }
12+
bor-rpc = { workspace = true }
13+
bor-storage = { workspace = true }
14+
heimdall-client = { workspace = true }
15+
alloy-primitives = { workspace = true }
16+
serde = { workspace = true }
17+
serde_json = { workspace = true }
18+
eyre = { workspace = true }
19+
url = { workspace = true }

crates/bor-node/src/config.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//! Bor node configuration.
2+
3+
use url::Url;
4+
5+
/// Configuration for the Bor node.
6+
#[derive(Debug, Clone)]
7+
pub struct BorNodeConfig {
8+
/// The network to run on (mainnet or amoy).
9+
pub network: BorNetwork,
10+
/// Heimdall API endpoint URL.
11+
pub heimdall_url: Url,
12+
/// Data directory path.
13+
pub data_dir: String,
14+
/// RPC listen address.
15+
pub rpc_addr: String,
16+
/// RPC listen port.
17+
pub rpc_port: u16,
18+
/// P2P listen port.
19+
pub p2p_port: u16,
20+
}
21+
22+
/// Which Bor network to connect to.
23+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24+
pub enum BorNetwork {
25+
/// Polygon PoS mainnet (chain ID 137).
26+
Mainnet,
27+
/// Polygon Amoy testnet (chain ID 80002).
28+
Amoy,
29+
}
30+
31+
impl BorNodeConfig {
32+
/// Create a default config for mainnet.
33+
pub fn mainnet() -> Self {
34+
Self {
35+
network: BorNetwork::Mainnet,
36+
heimdall_url: Url::parse("https://heimdall-api.polygon.technology").unwrap(),
37+
data_dir: "~/.boreth".to_string(),
38+
rpc_addr: "127.0.0.1".to_string(),
39+
rpc_port: 8545,
40+
p2p_port: 30303,
41+
}
42+
}
43+
44+
/// Create a default config for Amoy testnet.
45+
pub fn amoy() -> Self {
46+
Self {
47+
network: BorNetwork::Amoy,
48+
heimdall_url: Url::parse("https://heimdall-api-amoy.polygon.technology").unwrap(),
49+
data_dir: "~/.boreth-amoy".to_string(),
50+
rpc_addr: "127.0.0.1".to_string(),
51+
rpc_port: 8545,
52+
p2p_port: 30303,
53+
}
54+
}
55+
56+
/// Get the chain ID for this network.
57+
pub fn chain_id(&self) -> u64 {
58+
match self.network {
59+
BorNetwork::Mainnet => bor_chainspec::constants::MAINNET_CHAIN_ID,
60+
BorNetwork::Amoy => bor_chainspec::constants::AMOY_CHAIN_ID,
61+
}
62+
}
63+
}
64+
65+
#[cfg(test)]
66+
mod tests {
67+
use super::*;
68+
69+
#[test]
70+
fn test_mainnet_config() {
71+
let config = BorNodeConfig::mainnet();
72+
assert_eq!(config.chain_id(), 137);
73+
assert_eq!(config.network, BorNetwork::Mainnet);
74+
}
75+
76+
#[test]
77+
fn test_amoy_config() {
78+
let config = BorNodeConfig::amoy();
79+
assert_eq!(config.chain_id(), 80002);
80+
assert_eq!(config.network, BorNetwork::Amoy);
81+
}
82+
}

crates/bor-node/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
11
//! Bor node builder and configuration.
2+
//!
3+
//! Wires together all Bor components: consensus, EVM, payload builder,
4+
//! RPC, storage, and Heimdall client into a complete node.
5+
6+
pub mod node;
7+
pub mod config;
8+
9+
pub use node::BorNode;
10+
pub use config::BorNodeConfig;

crates/bor-node/src/node.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! BorNode: wires all components together.
2+
3+
use alloy_primitives::{Address, B256};
4+
use bor_chainspec::BorChainSpec;
5+
use bor_consensus::BorSnapshot;
6+
use bor_storage::persistence::{InMemorySpanStore, InMemorySnapshotStore, SpanStore, SnapshotStore};
7+
use crate::config::{BorNodeConfig, BorNetwork};
8+
use std::sync::{Arc, RwLock};
9+
10+
/// The assembled Bor node with all components wired together.
11+
pub struct BorNode {
12+
/// Node configuration.
13+
pub config: BorNodeConfig,
14+
/// Chain specification.
15+
pub chain_spec: Arc<BorChainSpec>,
16+
/// Span store.
17+
pub span_store: Arc<RwLock<InMemorySpanStore>>,
18+
/// Snapshot store.
19+
pub snapshot_store: Arc<RwLock<InMemorySnapshotStore>>,
20+
}
21+
22+
impl BorNode {
23+
/// Create a new BorNode from configuration.
24+
pub fn new(config: BorNodeConfig) -> eyre::Result<Self> {
25+
let chain_spec = match config.network {
26+
BorNetwork::Mainnet => Arc::new(bor_chainspec::bor_mainnet_genesis()),
27+
BorNetwork::Amoy => Arc::new(bor_chainspec::bor_amoy_genesis()),
28+
};
29+
30+
let span_store = Arc::new(RwLock::new(InMemorySpanStore::new()));
31+
let snapshot_store = Arc::new(RwLock::new(InMemorySnapshotStore::new()));
32+
33+
Ok(Self {
34+
config,
35+
chain_spec,
36+
span_store,
37+
snapshot_store,
38+
})
39+
}
40+
41+
/// Get the chain ID.
42+
pub fn chain_id(&self) -> u64 {
43+
self.config.chain_id()
44+
}
45+
46+
/// Store a snapshot.
47+
pub fn put_snapshot(&self, block_hash: B256, snapshot: &BorSnapshot) -> eyre::Result<()> {
48+
let data = snapshot.encode();
49+
let mut store = self.snapshot_store.write().map_err(|e| eyre::eyre!("{e}"))?;
50+
store.put_snapshot(block_hash.0, data);
51+
Ok(())
52+
}
53+
54+
/// Get a snapshot by block hash.
55+
pub fn get_snapshot(&self, block_hash: &B256) -> eyre::Result<Option<BorSnapshot>> {
56+
let store = self.snapshot_store.read().map_err(|e| eyre::eyre!("{e}"))?;
57+
match store.get_snapshot(&block_hash.0) {
58+
Some(data) => {
59+
let snap = BorSnapshot::decode(&data)?;
60+
Ok(Some(snap))
61+
}
62+
None => Ok(None),
63+
}
64+
}
65+
}
66+
67+
#[cfg(test)]
68+
mod tests {
69+
use super::*;
70+
use bor_primitives::{Validator, ValidatorSet};
71+
72+
fn test_validator_set() -> ValidatorSet {
73+
ValidatorSet {
74+
validators: vec![Validator {
75+
id: 1,
76+
address: Address::new([0xaa; 20]),
77+
voting_power: 100,
78+
signer: Address::new([0xaa; 20]),
79+
proposer_priority: 0,
80+
}],
81+
proposer: None,
82+
}
83+
}
84+
85+
#[test]
86+
fn test_node_builder_compiles() {
87+
let config = BorNodeConfig::amoy();
88+
let node = BorNode::new(config).unwrap();
89+
assert_eq!(node.chain_id(), 80002);
90+
}
91+
92+
#[test]
93+
fn test_node_mainnet() {
94+
let config = BorNodeConfig::mainnet();
95+
let node = BorNode::new(config).unwrap();
96+
assert_eq!(node.chain_id(), 137);
97+
}
98+
99+
#[test]
100+
fn test_snapshot_roundtrip() {
101+
let config = BorNodeConfig::amoy();
102+
let node = BorNode::new(config).unwrap();
103+
104+
let hash = B256::from([0xab; 32]);
105+
let snapshot = BorSnapshot::new(100, hash, test_validator_set());
106+
107+
node.put_snapshot(hash, &snapshot).unwrap();
108+
109+
let retrieved = node.get_snapshot(&hash).unwrap().unwrap();
110+
assert_eq!(retrieved.number, 100);
111+
assert_eq!(retrieved.validator_set.validators.len(), 1);
112+
}
113+
114+
#[test]
115+
fn test_snapshot_not_found() {
116+
let config = BorNodeConfig::amoy();
117+
let node = BorNode::new(config).unwrap();
118+
let result = node.get_snapshot(&B256::ZERO).unwrap();
119+
assert!(result.is_none());
120+
}
121+
}

0 commit comments

Comments
 (0)