From ff956c98da5b71dc8fbc901cb36c73248b138657 Mon Sep 17 00:00:00 2001 From: geoffsee <> Date: Sun, 15 Jun 2025 16:01:06 -0400 Subject: [PATCH 1/2] builds a network of nodes --- .dockerignore | 28 +++++++++++++++ Dockerfile | 73 +++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e8e8768 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,28 @@ +# Rust build artifacts +/target/ +**/*.rs.bk + +# Git directory +.git/ +.github/ +.gitignore + +# Editor files +.vscode/ +.idea/ +*.swp +*.swo + +# Node.js files (from packages directory) +node_modules/ +npm-debug.log + +# Other unnecessary files +*.md +LICENSE +*.log +.DS_Store + +# Keep necessary files +!Cargo.toml +!Cargo.lock diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c7b0c02 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,73 @@ +# Multistage Dockerfile for gsio-node + +# Build stage +FROM rust:slim as builder + +# Install build dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + pkg-config \ + libssl-dev \ + build-essential \ + git \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Create a new empty project +WORKDIR /app + +COPY Cargo.toml Cargo.lock ./ +COPY crates/gsio-node/Cargo.toml ./crates/gsio-node/ +COPY crates/gsio-relay/Cargo.toml ./crates/gsio-relay/ +COPY crates/gsio-client/Cargo.toml ./crates/gsio-client/ +COPY crates/gsio-wallet/Cargo.toml ./crates/gsio-wallet/ + +# Create dummy source files to build dependencies +RUN mkdir -p crates/gsio-node/src && \ + echo 'fn main() { println!("Dummy!"); }' > crates/gsio-node/src/main.rs && \ + mkdir -p crates/gsio-relay/src && \ + echo 'fn main() { println!("Dummy!"); }' > crates/gsio-relay/src/lib.rs && \ + mkdir -p crates/gsio-client/src && \ + echo 'fn main() { println!("Dummy!"); }' > crates/gsio-client/src/main.rs && \ + mkdir -p crates/gsio-wallet/src && \ + echo 'pub fn dummy() {}' > crates/gsio-wallet/src/lib.rs + +# Create dummy source files to build dependencies + + +# Build dependencies - this will be cached if dependencies don't change +RUN cargo build --release --bin gsio-node + +# Remove the dummy source files +RUN rm -rf crates/*/src + +# Copy the actual source code +COPY crates ./crates + +# Build the application +RUN cargo build --release --bin gsio-node + +# Runtime stage +FROM debian:bookworm-slim + +# Install runtime dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + libssl3 \ + wget \ + && rm -rf /var/lib/apt/lists/* + +# Create a non-root user to run the application +RUN useradd -m appuser +USER appuser +WORKDIR /home/appuser + +# Copy the binary from the builder stage +COPY --from=builder --chown=appuser:appuser /app/target/release/gsio-node . + +# Expose the port the app runs on +EXPOSE 3000 + +# Command to run the application +CMD ["./gsio-node"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..99bbac7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,86 @@ +version: '3.8' +# GSIO-Net Docker Compose Configuration +# +# This file defines a network of GSIO-Net nodes that can communicate with each other. +# It creates three nodes, each exposing the API on a different host port: +# - node1: http://localhost:3001 +# - node2: http://localhost:3002 +# - node3: http://localhost:3003 +# +# Usage: +# - Start the network: docker-compose up -d +# - View logs: docker-compose logs -f +# - Stop the network: docker-compose down +# - Stop and remove volumes: docker-compose down -v + +services: + # Node 1 + node1: + build: + context: . + dockerfile: Dockerfile + container_name: gsio-node1 + ports: + - "3001:3000" # Map to different host ports to avoid conflicts + volumes: + - node1-data:/home/appuser/data + networks: + - gsio-network + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + + # Node 2 + node2: + build: + context: . + dockerfile: Dockerfile + container_name: gsio-node2 + ports: + - "3002:3000" + volumes: + - node2-data:/home/appuser/data + networks: + - gsio-network + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + + # Node 3 + node3: + build: + context: . + dockerfile: Dockerfile + container_name: gsio-node3 + ports: + - "3003:3000" + volumes: + - node3-data:/home/appuser/data + networks: + - gsio-network + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + +# Define volumes for persistent storage +volumes: + node1-data: + node2-data: + node3-data: + +# Define a custom network for the nodes to communicate +networks: + gsio-network: + driver: bridge From 9dfea97e1841272e727dfa5423be306344b9eaeb Mon Sep 17 00:00:00 2001 From: geoffsee <> Date: Sun, 15 Jun 2025 16:12:35 -0400 Subject: [PATCH 2/2] Add logging to peer connection and synchronization processes --- README.md | 8 ++++++++ crates/gsio-node/src/main.rs | 7 +++++++ crates/gsio-node/src/p2p.rs | 5 +++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d644da0..b1f4775 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,14 @@ [![Tests](https://github.com/seemueller-io/gsio-net/actions/workflows/main.yml/badge.svg)](https://github.com/seemueller-io/gsio-net/actions/workflows/main.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) +Warning: This API is unstable. + +## run a network +```yaml +docker compose build +docker compose up +``` + ## License This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/crates/gsio-node/src/main.rs b/crates/gsio-node/src/main.rs index 62e302a..6e511ed 100644 --- a/crates/gsio-node/src/main.rs +++ b/crates/gsio-node/src/main.rs @@ -195,6 +195,7 @@ async fn on_peer_message( /// ---- Individual peer-message helpers ---- async fn handle_peer_discovered(socket: SocketRef, p2p: Arc, data: &JsonValue) { if let Some(peer_id) = data.get("peer_id").and_then(|id| id.as_str()) { + info!(peer_id = peer_id, "Peer discovered, initiating peering"); p2p.ledger.add_known_node(peer_id.to_owned()); socket .emit( @@ -207,10 +208,12 @@ async fn handle_peer_discovered(socket: SocketRef, p2p: Arc, data: & async fn handle_advertise(socket: SocketRef, p2p: Arc, data: &JsonValue) { if let Some(peer_id) = data.get("peer_id").and_then(|id| id.as_str()) { + info!(peer_id = peer_id, "Received peer advertisement, establishing connection"); p2p.ledger.add_known_node(peer_id.to_owned()); socket .emit("peer_ack", &json!({ "type": "ack", "peer_id": p2p.node_id() })) .ok(); + info!(peer_id = peer_id, "Sent acknowledgment to peer, connection established"); socket .emit( "peer_sync_request", @@ -235,6 +238,10 @@ async fn handle_sync_request(socket: SocketRef, p2p: Arc, _data: &Js } async fn handle_sync_response(_socket: SocketRef, p2p: Arc, data: &JsonValue) { + if let Some(peer_id) = data.get("peer_id").and_then(|id| id.as_str()) { + info!(peer_id = peer_id, "Received sync response from peer, peering active"); + } + if let Some(entries_val) = data.get("entries") { if let Ok(entries) = serde_json::from_value::>(entries_val.clone()) { for e in entries { diff --git a/crates/gsio-node/src/p2p.rs b/crates/gsio-node/src/p2p.rs index 2aaba18..33bc667 100644 --- a/crates/gsio-node/src/p2p.rs +++ b/crates/gsio-node/src/p2p.rs @@ -123,18 +123,19 @@ impl P2PManager { /// Handle a new connection from another node pub fn handle_connection(&self, socket: SocketRef, data: JsonValue) { - info!(ns = socket.ns(), ?socket.id, "P2P node connected"); - // Extract the node ID from the connection data let node_id = match data.get("node_id") { Some(id) => id.as_str().unwrap_or("unknown").to_string(), None => "unknown".to_string(), }; + info!(ns = socket.ns(), ?socket.id, node_id = node_id, "P2P node connected, establishing peering"); + // Add the node to the connected nodes { let mut connected_nodes = self.connected_nodes.lock().unwrap(); connected_nodes.insert(node_id.clone(), socket.clone()); + info!(peer_id = node_id, "Successfully peered with node"); } // Add the node to the known nodes in the ledger