diff --git a/.gitignore b/.gitignore index 4200858..4eff86c 100644 --- a/.gitignore +++ b/.gitignore @@ -70,4 +70,6 @@ data/* ./node data/bootstrap/rqlite/ -.env.* \ No newline at end of file +.env.* + +configs/ diff --git a/Makefile b/Makefile index 80ba2a7..b271031 100644 --- a/Makefile +++ b/Makefile @@ -30,22 +30,20 @@ test: # Run bootstrap node (auto-selects identity and data dir) run-node: - @echo "Starting bootstrap node..." - go run ./cmd/node --data ./data/bootstrap --p2p-port $${P2P:-4001} --rqlite-http-port $${HTTP:-5001} --rqlite-raft-port $${RAFT:-7001} --adv-addr $${ADV_ADDR:-127.0.0.1} --disable-anonrc + @echo "Starting bootstrap node with config..." + go run ./cmd/node --config configs/bootstrap.yaml # Run second node (regular) - requires join address of bootstrap node # Usage: make run-node2 JOINADDR=/ip4/127.0.0.1/tcp/5001 HTTP=5002 RAFT=7002 P2P=4002 run-node2: - @echo "Starting regular node2..." - @if [ -z "$(JOINADDR)" ]; then echo "ERROR: Provide join address: make run-node2 JOINADDR=/ip4/127.0.0.1/tcp/5001 [HTTP=5002 RAFT=7002 P2P=4002]"; exit 1; fi - go run ./cmd/node --id node2 --data ./data/node2 --p2p-port $${P2P:-4002} --rqlite-http-port $${HTTP:-5002} --rqlite-raft-port $${RAFT:-7002} --rqlite-join-address $(JOINADDR) + @echo "Starting regular node2 with config..." + go run ./cmd/node --config configs/node.yaml # Run third node (regular) - requires join address of bootstrap node # Usage: make run-node3 JOINADDR=/ip4/127.0.0.1/tcp/5001 HTTP=5003 RAFT=7003 P2P=4003 run-node3: - @echo "Starting regular node3..." - @if [ -z "$(JOINADDR)" ]; then echo "ERROR: Provide join address: make run-node3 JOINADDR=/ip4/127.0.0.1/tcp/5001 [HTTP=5003 RAFT=7003 P2P=4003]"; exit 1; fi - go run ./cmd/node --id node3 --data ./data/node3 --p2p-port $${P2P:-4003} --rqlite-http-port $${HTTP:-5003} --rqlite-raft-port $${RAFT:-7003} --rqlite-join-address $(JOINADDR) + @echo "Starting regular node3 with config..." + go run ./cmd/node --config configs/node.yaml # Run basic usage example run-example: @@ -150,9 +148,9 @@ test-consensus: build # Start development cluster (requires multiple terminals) dev-cluster: @echo "To start a development cluster, run these commands in separate terminals:" - @echo "1. make run-node # Start bootstrap node" - @echo "2. make run-node2 JOINADDR=/ip4/127.0.0.1/tcp/5001 HTTP=5002 RAFT=7002 P2P=4002" - @echo "3. make run-node3 JOINADDR=/ip4/127.0.0.1/tcp/5001 HTTP=5003 RAFT=7003 P2P=4003" + @echo "1. make run-node # Start bootstrap node (uses configs/bootstrap.yaml)" + @echo "2. make run-node2 # Start second node (uses configs/node.yaml)" + @echo "3. make run-node3 # Start third node (uses configs/node.yaml)" @echo "4. make run-example # Test basic functionality" @echo "5. make cli-health # Check network health" @echo "6. make cli-peers # List peers" diff --git a/README.md b/README.md index 74eba6c..8e1a20a 100644 --- a/README.md +++ b/README.md @@ -109,13 +109,15 @@ make build ```bash make run-node # Or manually: -go run ./cmd/node -data ./data/bootstrap -p2p-port 4001 -rqlite-http-port 5001 -rqlite-raft-port 7001 +go run ./cmd/node --config configs/bootstrap.yaml ``` ### 4. Start Additional Nodes ```bash -go run ./cmd/node -id node2 -data ./data/node2 -rqlite-http-port 5002 -rqlite-raft-port 7002 -p2p-port 4002 --disable-anonrc +make run-node2 +# Or manually: +go run ./cmd/node --config configs/node.yaml ``` ### 5. Test with CLI @@ -174,23 +176,87 @@ sudo journalctl -u debros-node.service -f ## Configuration -### YAML Config Example (`/opt/debros/configs/node.yaml`) +### Example Configuration Files + +#### `configs/bootstrap.yaml` ```yaml node: - data_dir: "/opt/debros/data/node" - key_file: "/opt/debros/keys/node/identity.key" + id: "" listen_addresses: - "/ip4/0.0.0.0/tcp/4001" - solana_wallet: "YOUR_WALLET_ADDRESS" + data_dir: "./data/bootstrap" + max_connections: 100 + disable_anonrc: true database: + data_dir: "./data/db" + replication_factor: 3 + shard_count: 16 + max_database_size: 1073741824 + backup_interval: 24h rqlite_port: 5001 rqlite_raft_port: 7001 + rqlite_join_address: "" # Bootstrap node does not join + +discovery: + bootstrap_peers: [] + discovery_interval: 15s + bootstrap_port: 4001 + http_adv_address: "127.0.0.1" + raft_adv_address: "" + +security: + enable_tls: false + private_key_file: "" + certificate_file: "" + auth_enabled: false logging: level: "info" - file: "/opt/debros/logs/node.log" + format: "console" + output_file: "" +``` + +#### `configs/node.yaml` + +```yaml +node: + id: "node2" + listen_addresses: + - "/ip4/0.0.0.0/tcp/4002" + data_dir: "./data/node2" + max_connections: 50 + disable_anonrc: true + +database: + data_dir: "./data/db" + replication_factor: 3 + shard_count: 16 + max_database_size: 1073741824 + backup_interval: 24h + rqlite_port: 5002 + rqlite_raft_port: 7002 + rqlite_join_address: "http://127.0.0.1:5001" + +discovery: + bootstrap_peers: + - "/ip4/127.0.0.1/tcp/4001/p2p/" + discovery_interval: 15s + bootstrap_port: 4002 + http_adv_address: "127.0.0.1" + raft_adv_address: "" + +security: + enable_tls: false + private_key_file: "" + certificate_file: "" + auth_enabled: false + +logging: + level: "info" + format: "console" + output_file: "" ``` ### Flags & Environment Variables diff --git a/WHITEPAPER.md b/WHITEPAPER.md index d144fab..5fd1ebf 100644 --- a/WHITEPAPER.md +++ b/WHITEPAPER.md @@ -1,19 +1,19 @@ -# DeBros Network: A Peer-to-Peer Decentralized Database Ecosystem +# DeBros Network: A Peer-to-Peer Decentralized Development Ecosystem -**DeBros** -info@debros.io -https://debros.io -August 2, 2025 +**DeBros** +info@debros.io +https://debros.io +August 14, 2025 ## Abstract -We propose a decentralized ecosystem, the DeBros Network, enabling peer-to-peer application deployment and operation across a global network of nodes, free from centralized control. Built with Go and LibP2P for robust networking, RQLite for distributed consensus, and integrated with the Solana blockchain for identity and governance, the network provides a resilient, privacy-first platform for decentralized applications. Participation is governed by NFT ownership and token staking, with demonstrated applications like Anchat showcasing real-world messaging capabilities. The architecture eliminates single points of failure while maintaining developer simplicity and end-user accessibility. +We propose a decentralized development ecosystem, the DeBros Network, enabling peer-to-peer application deployment and operation across a global network of nodes, free from centralized control. Built LibP2P for robust networking, RQLite for distributed consensus, and integrated with the blochains like Etherium or Solana for identity and governance, the network provides a resilient, privacy-first platform for decentralized development. Participation is governed by NFT ownership and token staking, with demonstrated applications like Anchat showcasing real-world messaging capabilities. The architecture eliminates single points of failure while maintaining developer simplicity and end-user accessibility. ## 1. Introduction Centralized systems dominate modern technology, imposing control over data, access, and development through single points of failure and intermediaries. These structures compromise privacy, resilience, innovation, and freedom, while existing decentralized solutions often lack the simplicity or scalability needed for widespread adoption. -The DeBros Network resolves these issues by establishing a peer-to-peer platform where nodes form a decentralized backbone for applications. Built on Go's performance and LibP2P's proven networking stack, it empowers a global community of developers and users to collaborate as equals, delivering scalable, privacy-first solutions without centralized oversight. +The DeBros Network resolves these issues by establishing a peer-to-peer platform where nodes form a decentralized backbone for applications. Built on LibP2P's proven networking stack and Rqlite as a database, it empowers a global community of developers and users to collaborate as equals, delivering scalable, privacy-first solutions without centralized oversight. ## 2. Problem Statement @@ -361,11 +361,11 @@ Built on proven technologies including Go, LibP2P, and RQLite, with Solana block ## References -[1] **Go Programming Language** - https://golang.org -[2] **LibP2P Networking Stack** - https://libp2p.io -[3] **RQLite Distributed Database** - https://rqlite.io -[4] **Solana Blockchain** - https://solana.com -[5] **Raft Consensus Algorithm** - https://raft.github.io +[1] **Go Programming Language** - https://golang.org +[2] **LibP2P Networking Stack** - https://libp2p.io +[3] **RQLite Distributed Database** - https://rqlite.io +[4] **Solana Blockchain** - https://solana.com +[5] **Raft Consensus Algorithm** - https://raft.github.io [6] **DeBros Network Repository** - https://git.debros.io/DeBros/network-cluster --- diff --git a/cmd/node/main.go b/cmd/node/main.go index 85ade17..4cdf4c6 100644 --- a/cmd/node/main.go +++ b/cmd/node/main.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "io/ioutil" "log" "os" "os/signal" @@ -15,6 +16,7 @@ import ( "git.debros.io/DeBros/network/pkg/logging" "git.debros.io/DeBros/network/pkg/node" "go.uber.org/zap" + "gopkg.in/yaml.v3" ) func setup_logger(component logging.Component) (logger *logging.ColoredLogger) { @@ -28,9 +30,10 @@ func setup_logger(component logging.Component) (logger *logging.ColoredLogger) { return logger } -func parse_and_return_network_flags() (dataDir, nodeID *string, p2pPort, rqlHTTP, rqlRaft *int, disableAnon *bool, rqlJoinAddr *string, advAddr *string, help *bool) { +func parse_and_return_network_flags() (configPath *string, dataDir, nodeID *string, p2pPort, rqlHTTP, rqlRaft *int, disableAnon *bool, rqlJoinAddr *string, advAddr *string, help *bool) { logger := setup_logger(logging.ComponentNode) + configPath = flag.String("config", "", "Path to config YAML file (overrides defaults)") dataDir = flag.String("data", "", "Data directory (auto-detected if not provided)") nodeID = flag.String("id", "", "Node identifier (for running multiple local nodes)") p2pPort = flag.Int("p2p-port", 4001, "LibP2P listen port") @@ -38,15 +41,63 @@ func parse_and_return_network_flags() (dataDir, nodeID *string, p2pPort, rqlHTTP rqlRaft = flag.Int("rqlite-raft-port", 7001, "RQLite Raft port") disableAnon = flag.Bool("disable-anonrc", false, "Disable Anyone proxy routing (defaults to enabled on 127.0.0.1:9050)") rqlJoinAddr = flag.String("rqlite-join-address", "", "RQLite address to join (e.g., /ip4/)") - advAddr = flag.String("adv-addr", "127.0.0.1", "Default Addvertise address for rqlite and rafts") + advAddr = flag.String("adv-addr", "127.0.0.1", "Default Advertise address for rqlite and rafts") help = flag.Bool("help", false, "Show help") flag.Parse() logger.Info("Successfully parsed all flags and arguments.") + if *configPath != "" { + cfg, err := LoadConfigFromYAML(*configPath) + if err != nil { + logger.Error("Failed to load config from YAML", zap.Error(err)) + os.Exit(1) + } + logger.ComponentInfo(logging.ComponentNode, "Configuration loaded from YAML file", zap.String("path", *configPath)) + + // Instead of returning flag values, return config values + // For ListenAddresses, extract port from multiaddr string if possible, else use default + var p2pPortVal int + if len(cfg.Node.ListenAddresses) > 0 { + // Try to parse port from multiaddr string + var port int + _, err := fmt.Sscanf(cfg.Node.ListenAddresses[0], "/ip4/0.0.0.0/tcp/%d", &port) + if err == nil { + p2pPortVal = port + } else { + p2pPortVal = 4001 + } + } else { + p2pPortVal = 4001 + } + return configPath, + &cfg.Node.DataDir, + &cfg.Node.ID, + &p2pPortVal, + &cfg.Database.RQLitePort, + &cfg.Database.RQLiteRaftPort, + &cfg.Node.DisableAnonRC, + &cfg.Database.RQLiteJoinAddress, + &cfg.Discovery.HttpAdvAddress, + help + } + return } +// LoadConfigFromYAML loads a config from a YAML file +func LoadConfigFromYAML(path string) (*config.Config, error) { + data, err := ioutil.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("failed to read config file: %w", err) + } + var cfg config.Config + if err := yaml.Unmarshal(data, &cfg); err != nil { + return nil, fmt.Errorf("failed to unmarshal YAML: %w", err) + } + return &cfg, nil +} + func disable_anon_proxy(disableAnon *bool) bool { anyoneproxy.SetDisabled(*disableAnon) logger := setup_logger(logging.ComponentAnyone) @@ -152,7 +203,7 @@ func load_args_into_config(cfg *config.Config, p2pPort, rqlHTTP, rqlRaft *int, r func main() { logger := setup_logger(logging.ComponentNode) - dataDir, nodeID, p2pPort, rqlHTTP, rqlRaft, disableAnon, rqlJoinAddr, advAddr, help := parse_and_return_network_flags() + _, dataDir, nodeID, p2pPort, rqlHTTP, rqlRaft, disableAnon, rqlJoinAddr, advAddr, help := parse_and_return_network_flags() disable_anon_proxy(disableAnon) check_if_should_open_help(help) diff --git a/go.mod b/go.mod index c25edd9..7e8c295 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/rqlite/gorqlite v0.0.0-20250609141355-ac86a4a1c9a8 go.uber.org/zap v1.27.0 golang.org/x/net v0.42.0 + gopkg.in/yaml.v3 v3.0.1 ) require ( diff --git a/pkg/config/config.go b/pkg/config/config.go index 6f5aefe..7f6b4e4 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -22,9 +22,7 @@ type NodeConfig struct { ListenAddresses []string `yaml:"listen_addresses"` // LibP2P listen addresses DataDir string `yaml:"data_dir"` // Data directory MaxConnections int `yaml:"max_connections"` // Maximum peer connections - - // Bootstrap configuration (only for bootstrap nodes) - IsBootstrap bool `yaml:"is_bootstrap"` + DisableAnonRC bool `yaml:"disable_anon_rc"` // Disable Anyone proxy/SOCKS5 } // DatabaseConfig contains database-related configuration @@ -97,7 +95,6 @@ func DefaultConfig() *Config { }, DataDir: "./data", MaxConnections: 50, - IsBootstrap: false, }, Database: DatabaseConfig{ DataDir: "./data/db",