Skip to main content

Overview

Ubu-Block uses peer-to-peer (P2P) networking to create a distributed, resilient network of nodes. Each node can connect to multiple peers to share blocks and synchronize the blockchain.

Node Types

Ubu-Block supports three types of nodes:
  • Submission Nodes: Accept result submissions from authorized users
  • Observer Nodes: Provide public, read-only access for transparency
  • Verification Nodes: Cross-reference results with official sources

Starting a P2P Server

Start your node as a P2P server to accept incoming connections:
ubu-block --config config.toml serve --port 8333
Output:
🚀 P2P server started on 127.0.0.1:8333 with id 550e8400-e29b-41d4-a716-446655440000
Each node generates a unique UUID for identification.

P2P Configuration

Configure P2P settings in your config.toml:
[peer_config]
max_peers = 50                    # Maximum number of peer connections
connection_timeout = "30s"        # Timeout for connecting to peers
ping_interval = "60s"            # How often to ping peers
sync_batch_size = 100            # Number of blocks to request during sync
max_message_size = 10485760      # 10MB max message size

Configuration Options

OptionDescriptionDefault
max_peersMaximum simultaneous peer connections50
connection_timeoutTCP connection timeout30s
ping_intervalPeer health check interval60s
sync_batch_sizeBlocks per sync request100
max_message_sizeMaximum P2P message size10MB

Connecting to Peers

Manual Connection

Connect to a specific peer:
let addr = "157.230.45.123:8333".parse()?;
blockchain.connect_to_peer(addr).await?;
Connection process:
1

TCP connection

Establishes TCP connection to peer address
2

Handshake

Exchanges Hello message:
P2PMessage::Hello {
    node_id: "550e8400-e29b-41d4-a716-446655440000",
    version: 1,
    chain_height: 1234
}
3

Synchronization

If peer has higher chain height, requests missing blocks
4

Active connection

Maintains persistent connection for block announcements and messages

Automatic Peer Discovery

Request peer list from connected peers:
// Request peers
let message = P2PMessage::GetPeers;
blockchain.send_message(&mut stream, &message).await?;

// Receive peer addresses
// P2PMessage::PeersResponse { peers: Vec<SocketAddr> }
The node automatically connects to discovered peers (up to max_peers limit).

P2P Message Types

Nodes communicate using various message types:

Connection Messages

P2PMessage::Hello {
    node_id: String,
    version: u32,
    chain_height: i64
}

Block Messages

P2PMessage::BlockAnnouncement(Block)

Synchronization Messages

P2PMessage::GetBlocks {
    start_height: i64,
    count: u32
}

Maintenance Messages

P2PMessage::Ping

Chain Synchronization

When connecting to a peer with more blocks:
1

Detect height difference

During handshake, compare chain heights:
if peer_height > our_height {
    request_chain_sync(peer_addr).await?;
}
2

Request missing blocks

Request blocks in batches:
P2PMessage::GetBlocks {
    start_height: our_height,
    count: sync_batch_size
}
3

Receive and validate

Process received blocks:
for block in blocks {
    self.add_block_to_chain(block).await?;
    // Validation happens automatically
}
4

Continue until synced

Repeat until chain heights match
Node A (height: 100)
    ↓ GetBlocks(100, 100)
Node B (height: 250)
    ↓ BlocksResponse([blocks 100-199])
Node A (height: 200)
    ↓ GetBlocks(200, 100)
Node B
    ↓ BlocksResponse([blocks 200-249])
Node A (height: 250) ✓ Synced

Broadcasting Blocks

When you create a new block, announce it to all peers:
pub async fn announce_block(&self, block: Block) -> Result<(), ChainError> {
    log::info!("📢 Announcing new block: {} (height: {})", 
               block.hash, block.height);
    
    self.broadcast_message(P2PMessage::BlockAnnouncement(block)).await
}
The block propagates through the network:
Your Node → [Peer 1, Peer 2, Peer 3]
              ↓       ↓       ↓
         [More peers propagate]
Blocks are only broadcasted once per peer to prevent network flooding. The broadcast channel handles deduplication.

Peer Management

Peer Connection Structure

pub struct PeerConnection {
    pub addr: SocketAddr,
    pub node_id: Option<String>,
    pub chain_height: i64,
    pub last_seen: Instant,
    pub last_ping: Option<Instant>,
    pub is_syncing: bool,
}

Peer Maintenance Loop

The node automatically maintains peer health:
async fn peer_maintenance_loop(&self) {
    let mut interval = tokio::time::interval(ping_interval);
    
    loop {
        interval.tick().await;
        
        // Check peer health
        for peer_addr in peers {
            if peer.last_seen.elapsed() > ping_interval * 3 {
                // Remove inactive peer
                self.peers.remove(&peer_addr);
            }
        }
        
        // Broadcast ping
        self.broadcast_message(P2PMessage::Ping).await;
    }
}
Maintenance tasks:
  • Send periodic pings (every ping_interval)
  • Remove peers that don’t respond (3x ping_interval)
  • Log peer count and status
  • Attempt to maintain max_peers connections

Viewing Connected Peers

// Get peer information
let peers = blockchain.get_peers_info().await;
for peer in peers {
    println!("Peer: {:?} (height: {})", peer.addr, peer.chain_height);
}

// Get peer count
let count = blockchain.peer_count().await;
println!("Connected to {} peers", count);

Network Topology

Ubu-Block uses an unstructured P2P network:
        [Node A] ←→ [Node B]
           ↕            ↕
        [Node C] ←→ [Node D] ←→ [Node E]

                     [Node F]
Characteristics:
  • Each node maintains up to max_peers connections
  • No central coordinator
  • Peer discovery through existing connections
  • Gossip-style block propagation
  • Automatic peer replacement on disconnect

Security Considerations

Connection Limits

if self.peers.read().await.len() >= self.config.max_peers {
    log::warn!("Max peers reached, rejecting connection");
    return;
}
Prevents resource exhaustion from too many connections.

Message Size Limits

if message_len > self.config.max_message_size {
    return Err(ChainError::Other("Message too large"));
}
Prevents memory exhaustion from malicious messages.

Signature Verification

All blocks are verified before acceptance:
async fn handle_new_block(&mut self, block: Block) -> Result<i64, ChainError> {
    // Signature verification happens in add_block
    self.add_block_to_chain(block).await
}

Future Enhancements

Upcoming security features:
  • End-to-end encryption: Encrypted P2P communication
  • Peer reputation: Track peer reliability
  • BFT consensus: Byzantine fault tolerance (up to 1/3 malicious nodes)
  • Rate limiting: Prevent spam attacks

Public Servers

Connect to public Ubu-Block nodes:
LocationIPPort
Frankfurt (Digital Ocean)157... ***8333
Public servers are provided for free. Performance may vary based on your geographic location and network conditions.

Monitoring and Debugging

Enable Logging

Set log level for P2P debugging:
RUST_LOG=debug ubu-block serve --port 8333

Common Log Messages

🚀 P2P server started on 127.0.0.1:8333 with id <uuid>
🔗 Connecting to peer: 157.230.45.123:8333
📢 Received block announcement: <hash> (height: 42)
🏓 Received ping from 157.230.45.123:8333
🔄 Starting chain sync from height 100
🔍 Peer maintenance: 5 peers connected
👋 Peer disconnecting: Connection closed

Troubleshooting

Cannot connect to peer
Error: Connection refused
  • Verify peer address and port
  • Check firewall rules
  • Ensure peer node is running
Sync not completing
🔄 Starting chain sync from height 100
// No progress...
  • Check peer has higher chain height
  • Verify network connectivity
  • Increase connection_timeout
Max peers reached
⚠️  Max peers reached, rejecting connection
  • Increase max_peers in config
  • Some peers may be inactive (will be cleaned up)

Best Practices

Maintain connections to diverse peers for resilience:
  • Geographic diversity
  • Different node operators
  • Mix of observer and submission nodes
Track peer reliability:
let peers = blockchain.get_peers_info().await;
for peer in peers {
    let latency = peer.last_ping?.elapsed();
    if latency > Duration::from_secs(5) {
        log::warn!("Slow peer: {:?}", peer.addr);
    }
}
  • Run behind firewall
  • Use VPN for sensitive deployments
  • Monitor for unusual traffic patterns
  • Keep software updated
Balance connectivity and resources:
  • More peers = better redundancy, more bandwidth
  • Fewer peers = less resource usage, simpler
  • Typical: 8-50 peers depending on role

Next Steps

Build docs developers (and LLMs) love