feat(nu-p2p): initial Faz 0 scaffold
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
9cd556a439
9 changed files with 178 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
target/
|
||||
*.rs.bk
|
||||
.env
|
||||
35
CLAUDE.md
Normal file
35
CLAUDE.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# nu-p2p — CLAUDE.md
|
||||
|
||||
P2P ağ katmanı. `nu-node`'dan ayrı tutulur — test ederken network mock'lanabilir.
|
||||
|
||||
## Stack
|
||||
|
||||
- `libp2p 0.54` — Gossipsub, Kademlia DHT, Identify, Ping
|
||||
- Tokio async runtime
|
||||
|
||||
## Modüller
|
||||
|
||||
| Dosya | Sorumluluk |
|
||||
|-------|-----------|
|
||||
| `behaviour.rs` | libp2p `NetworkBehaviour` kompozisyonu |
|
||||
| `messages.rs` | Gossip topic sabitleri + mesaj tipleri |
|
||||
| `peer.rs` | PeerRegistry (max 50 bağlantı) |
|
||||
| `config.rs` | Listen addr, bootstrap peers, max peers |
|
||||
|
||||
## Gossip Topics
|
||||
|
||||
```
|
||||
nu/blocks/1 → BlockAnnounce, BlockRequest, BlockResponse
|
||||
nu/txs/1 → TxGossip
|
||||
nu/votes/1 → VoteAnnounce
|
||||
nu/validators/1 → ValidatorHeartbeat
|
||||
```
|
||||
|
||||
## Geliştirme
|
||||
|
||||
```bash
|
||||
cargo run --bin nu-p2p
|
||||
|
||||
# Faz 1: iki node arası gossip testi
|
||||
RUST_LOG=debug cargo run --bin nu-p2p -- --bootstrap /ip4/127.0.0.1/tcp/30333
|
||||
```
|
||||
28
Cargo.toml
Normal file
28
Cargo.toml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
[package]
|
||||
name = "nu-p2p"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "nu-p2p"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
libp2p = { version = "0.54", features = [
|
||||
"tokio",
|
||||
"tcp",
|
||||
"noise",
|
||||
"yamux",
|
||||
"gossipsub",
|
||||
"kad",
|
||||
"identify",
|
||||
"ping",
|
||||
] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
anyhow = "1"
|
||||
thiserror = "1"
|
||||
tracing = "1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
futures = "0.3"
|
||||
13
src/behaviour.rs
Normal file
13
src/behaviour.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// libp2p combined behaviour: Gossipsub + Kademlia DHT + Identify + Ping
|
||||
// Full implementation in Faz 1; scaffold defines the composited behaviour struct.
|
||||
|
||||
use libp2p::{gossipsub, identify, kad, ping};
|
||||
use libp2p::swarm::NetworkBehaviour;
|
||||
|
||||
#[derive(NetworkBehaviour)]
|
||||
pub struct NuBehaviour {
|
||||
pub gossipsub: gossipsub::Behaviour,
|
||||
pub kademlia: kad::Behaviour<kad::store::MemoryStore>,
|
||||
pub identify: identify::Behaviour,
|
||||
pub ping: ping::Behaviour,
|
||||
}
|
||||
20
src/config.rs
Normal file
20
src/config.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const MAX_PEERS: usize = 50;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct P2pConfig {
|
||||
pub listen_addr: String, // e.g. "/ip4/0.0.0.0/tcp/30333"
|
||||
pub bootstrap_peers: Vec<String>, // multiaddrs from genesis.toml
|
||||
pub max_peers: usize,
|
||||
}
|
||||
|
||||
impl Default for P2pConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
listen_addr: "/ip4/0.0.0.0/tcp/30333".into(),
|
||||
bootstrap_peers: vec![],
|
||||
max_peers: MAX_PEERS,
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/lib.rs
Normal file
4
src/lib.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
pub mod behaviour;
|
||||
pub mod messages;
|
||||
pub mod peer;
|
||||
pub mod config;
|
||||
14
src/main.rs
Normal file
14
src/main.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use anyhow::Result;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(EnvFilter::from_default_env())
|
||||
.init();
|
||||
|
||||
tracing::info!("nu-p2p starting...");
|
||||
|
||||
// TODO Faz 1: build libp2p swarm with NuBehaviour, connect bootstrap peers, run event loop
|
||||
Ok(())
|
||||
}
|
||||
19
src/messages.rs
Normal file
19
src/messages.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// All gossip topics on the network.
|
||||
pub const TOPIC_BLOCKS: &str = "nu/blocks/1";
|
||||
pub const TOPIC_TXS: &str = "nu/txs/1";
|
||||
pub const TOPIC_VOTES: &str = "nu/votes/1";
|
||||
pub const TOPIC_VALIDATORS: &str = "nu/validators/1";
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", content = "data")]
|
||||
pub enum NetworkMessage {
|
||||
BlockAnnounce { height: u64, hash: String },
|
||||
BlockRequest { height: u64 },
|
||||
BlockResponse { raw_block: Vec<u8> },
|
||||
TxGossip { raw_tx: Vec<u8> },
|
||||
PeerExchange { peers: Vec<String> }, // multiaddrs
|
||||
ValidatorHeartbeat { address: String, slot: u32 },
|
||||
VoteAnnounce { node_id: String, voter: String, approve: bool },
|
||||
}
|
||||
42
src/peer.rs
Normal file
42
src/peer.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PeerInfo {
|
||||
pub peer_id: String,
|
||||
pub addr: String,
|
||||
pub is_validator: bool,
|
||||
}
|
||||
|
||||
pub struct PeerRegistry {
|
||||
peers: Vec<PeerInfo>,
|
||||
max: usize,
|
||||
}
|
||||
|
||||
impl PeerRegistry {
|
||||
pub fn new(max: usize) -> Self {
|
||||
Self { peers: vec![], max }
|
||||
}
|
||||
|
||||
pub fn add(&mut self, peer: PeerInfo) -> bool {
|
||||
if self.peers.len() >= self.max {
|
||||
return false;
|
||||
}
|
||||
if !self.peers.iter().any(|p| p.peer_id == peer.peer_id) {
|
||||
self.peers.push(peer);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, peer_id: &str) {
|
||||
self.peers.retain(|p| p.peer_id != peer_id);
|
||||
}
|
||||
|
||||
pub fn count(&self) -> usize {
|
||||
self.peers.len()
|
||||
}
|
||||
|
||||
pub fn validator_peers(&self) -> Vec<&PeerInfo> {
|
||||
self.peers.iter().filter(|p| p.is_validator).collect()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue