A P2P network implementation using libp2p with DHT-based peer discovery and message routing.
The network supports four distinct node roles, each with specific capabilities and resource requirements:
- Maintain network connectivity
- Run DHT in server mode
- High connection limits (1000 max connections)
- Full DHT and gossip capabilities
- Large k-bucket size (200)
- No bootstrap requirement
- Frequent updates (30s DHT interval)
- Regular nodes with full capabilities
- Run DHT in client mode
- Moderate connection limits (50 max connections)
- Full DHT and gossip capabilities
- Standard k-bucket size (20)
- Requires bootstrap connection
- Regular updates (60s DHT interval)
- Message relay and storage
- Run DHT in client mode
- Higher connection limits (100 max connections)
- Full DHT and gossip capabilities
- Standard k-bucket size (20)
- Requires bootstrap connection
- Message relaying enabled
- Frequent updates (45s DHT interval)
- Minimal resource usage
- No DHT or gossip protocols
- Limited connections (10 max)
- Direct messaging only
- Requires bootstrap connection
- Infrequent updates (120s interval)
- Install dependencies:
pnpm install- Copy environment file:
cp .env.example .env.agent1- Configure your environment variables in
.env.agent1:
PRIVATE_KEY: Your Ethereum private keyREGISTRY_ADDRESS: The agent registry contract addressRPC_URL: Your Ethereum RPC URLNODE_TYPE: Node role (bootstrap, full, server, light)
# Start with specific role and port
pnpm start -- --role full --port 8000 --name mynode
# Start with env file
pnpm start -- --env .env.agent1# Install dependencies
pnpm install
# Build the node
pnpm build
# Start with default settings (FULL role)
pnpm start
# Start with specific configuration
pnpm start -- --role light --port 8000 --name lightnodeThe network uses Kademlia DHT for peer discovery and routing:
- Bootstrap nodes run in DHT server mode
- Full and Server nodes run in DHT client mode
- Light nodes don't participate in DHT
- Records naturally propagate through the network
The network uses gossipsub for real-time message propagation:
-
Topics:
agent-announcements: Node presence and network updatesagent-messages: Direct and broadcast messages between agentsnode-status: Health checks and metrics
-
Message Flow:
- DHT is used to find the target peer's ID (for direct messages)
- Messages are published to the appropriate gossipsub topic
- Gossipsub handles message propagation through the network
- Receiving nodes verify signatures and process messages
The network uses 4 bootstrap nodes for initial connectivity:
- US East (Virginia)
- US West (Oregon)
- EU West (Amsterdam)
- SEA (Singapore)
Regular nodes connect to bootstrap nodes first, then discover other peers through the DHT.
p2p.ts: Core P2P network implementationtypes/p2p.ts: Node role and configuration definitionsbin/p2p-node.ts: Executable wrapperconstants.ts: Bootstrap node configurationlogger.ts: Logging utilities
-
Role-based configuration:
- Each node type has specific resource limits
- Configuration automatically set based on role
- Light nodes minimize resource usage
- Bootstrap nodes optimize for network maintenance
-
DHT Strategy:
- Bootstrap nodes: Server mode, large routing tables
- Full/Server nodes: Client mode, standard routing
- Light nodes: No DHT participation
-
Connection Management:
- Role-specific connection limits
- Automatic peer discovery
- Bootstrap node requirement for non-bootstrap roles
sequenceDiagram
participant Agent1 as Agent 1
participant DHT as DHT Network
participant Bootstrap as Bootstrap Nodes
participant Agent2 as Agent 2
participant PubSub as GossipSub Network
Note over Agent1,PubSub: Initial Network Join
Agent1->>Bootstrap: Connect to bootstrap nodes
Agent1->>DHT: Publish presence (ETH addr -> PeerId)
Note over Agent1,PubSub: Message Flow
Agent1->>DHT: Query for Agent2's PeerId
DHT-->>Agent1: Return Agent2's PeerId
Note over Agent1,PubSub: Message Publishing
Agent1->>PubSub: Publish message to topic
PubSub->>Agent2: Propagate message through mesh
Note over Agent2,PubSub: Message Receipt
Agent2->>Agent2: Verify message signature
Agent2->>Agent2: Process message
To create a new release:
-
Make your changes and test them locally
-
Create a pull request (PR) with your changes:
# Create a feature branch git checkout -b feature/your-feature-name # Make your changes # ... # Commit your changes with conventional commit messages # Example: git commit -m "feat: add new feature" # Example: git commit -m "fix: resolve issue with X" # Push your branch and create a PR git push -u origin feature/your-feature-name
-
After PR review, merge your changes to master:
# Switch to master git checkout master # Pull latest changes git pull
-
Run the release script:
# For a patch version (0.1.0 -> 0.1.1) npm run release:patch # For a minor version (0.1.0 -> 0.2.0) npm run release:minor # For a major version (0.1.0 -> 1.0.0) npm run release:major
This will:
- Bump the version in package.json
- Update the CHANGELOG.md with all changes since the last release
- Create a git commit
- Create a git tag (e.g., v0.1.1)
- Push changes and tag to GitHub
The GitHub Actions workflow will automatically:
- Build the project
- Create a GitHub release
- Upload the release files:
p2p-node.js- The bundled node fileproto/p2p.proto- Protocol buffer definitionsproto/p2p.ts- Protocol buffer TypeScript definitionschecksums.txt- SHA256 checksums for verification
This project follows the Conventional Commits specification. Commit messages should be structured as follows:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Common types:
feat: A new featurefix: A bug fixdocs: Documentation changesstyle: Code style changes (formatting, semi-colons, etc)refactor: Code changes that neither fix bugs nor add featuresperf: Performance improvementstest: Adding or correcting testschore: Changes to the build process, tools, etc.
Examples:
feat: add user authenticationfix: resolve memory leak in connection handlingdocs: improve API documentationchore: update dependencies
Using conventional commits ensures your changes will be properly categorized in the changelog.
To use a specific release in another project:
{
"dependencies": {
"@openpond/node": "github:openpondai/node#v0.1.1"
}
}Replace v0.1.1 with the desired version tag.
- Create a new network in the
networks.tsfile - Update the
constants.tsfile with the new network's bootstrap nodes - Add a new folder to the
deployfolder - Deploy to railway
- select railway toml
- setup private key and bootstrap private key
- Setup dns hosting in railway, add to dns provider, and update
constants.ts
