11/*
2- Neutrino server main entry point.
3-
4- This server wraps the lightninglabs/neutrino BIP157/BIP158 light client
5- with a REST API for use by JoinMarket maker/taker clients.
2+ neutrinod is a standalone REST API server for neutrino, a privacy-preserving
3+ Bitcoin light client using BIP157/BIP158 compact block filters.
64*/
75package main
86
97import (
8+ "context"
109 "flag"
1110 "fmt"
1211 "net/http"
@@ -23,65 +22,49 @@ import (
2322)
2423
2524var (
26- // Build-time variables (set via -ldflags)
27- version = "dev"
28- buildTime = "unknown"
29- commit = "unknown"
30-
31- // Upstream neutrino version
32- neutrinoVersion = "v0.16.0"
33-
34- // Command-line flags
35- network = flag .String ("network" , "mainnet" , "Bitcoin network (mainnet, testnet, regtest, signet)" )
36- dataDir = flag .String ("datadir" , "/data/neutrino" , "Data directory for headers and filters" )
37- listenAddr = flag .String ("listen" , "0.0.0.0:8334" , "REST API listen address" )
38- torProxy = flag .String ("proxy" , "" , "Tor SOCKS5 proxy address (e.g., 127.0.0.1:9050)" )
39- connectPeers = flag .String ("connect" , "" , "Comma-separated list of peers to connect to" )
40- logLevel = flag .String ("loglevel" , "info" , "Log level (trace, debug, info, warn, error)" )
41- maxPeers = flag .Int ("maxpeers" , 8 , "Maximum number of peers to connect to" )
42- banDuration = flag .Duration ("banduration" , 24 * time .Hour , "Duration to ban misbehaving peers" )
43- filterCacheSize = flag .Int ("filtercache" , 4096 , "Size of filter cache (number of filters)" )
44- showVersion = flag .Bool ("version" , false , "Show version information and exit" )
25+ // Version is set at build time via ldflags
26+ version = "dev"
4527)
4628
4729func main () {
30+ // Parse command line flags
31+ network := flag .String ("network" , getEnv ("NETWORK" , "mainnet" ), "Bitcoin network (mainnet, testnet, regtest, signet)" )
32+ listen := flag .String ("listen" , getEnv ("LISTEN_ADDR" , "0.0.0.0:8334" ), "REST API listen address" )
33+ dataDir := flag .String ("datadir" , getEnv ("DATA_DIR" , "/data/neutrino" ), "Data directory for headers and filters" )
34+ logLevel := flag .String ("loglevel" , getEnv ("LOG_LEVEL" , "info" ), "Log level (trace, debug, info, warn, error)" )
35+ connectPeers := flag .String ("connect" , getEnv ("CONNECT_PEERS" , "" ), "Comma-separated list of peers to connect to" )
36+ showVersion := flag .Bool ("version" , false , "Show version and exit" )
4837 flag .Parse ()
4938
50- // Show version if requested
5139 if * showVersion {
52- fmt .Printf ("Neutrino API Server\n " )
53- fmt .Printf (" Version: %s\n " , version )
54- fmt .Printf (" Neutrino: %s\n " , neutrinoVersion )
55- fmt .Printf (" Build time: %s\n " , buildTime )
56- fmt .Printf (" Commit: %s\n " , commit )
57- fmt .Printf (" Go version: %s\n " , "go1.21" )
40+ fmt .Printf ("neutrinod %s\n " , version )
5841 os .Exit (0 )
5942 }
6043
61- // Setup logging
44+ // Set up logging
6245 backend := btclog .NewBackend (os .Stdout )
6346 logger := backend .Logger ("MAIN" )
6447 level , _ := btclog .LevelFromString (* logLevel )
6548 logger .SetLevel (level )
6649
67- logger .Infof ("Starting Neutrino API Server %s (neutrino %s)" , version , neutrinoVersion )
68- logger .Infof ("Listening on %s for %s network" , * listenAddr , * network )
50+ logger .Infof ("Starting neutrinod %s" , version )
51+ logger .Infof ("Network: %s" , * network )
52+ logger .Infof ("Listen address: %s" , * listen )
53+ logger .Infof ("Data directory: %s" , * dataDir )
6954
70- // Create data directory
55+ // Ensure data directory exists
7156 if err := os .MkdirAll (* dataDir , 0750 ); err != nil {
7257 logger .Errorf ("Failed to create data directory: %v" , err )
7358 os .Exit (1 )
7459 }
7560
76- // Initialize neutrino node
61+ // Create neutrino node
7762 nodeConfig := & neutrino.Config {
7863 Network : * network ,
7964 DataDir : * dataDir ,
80- TorProxy : * torProxy ,
8165 ConnectPeers : * connectPeers ,
82- MaxPeers : * maxPeers ,
83- BanDuration : * banDuration ,
84- FilterCacheSize : * filterCacheSize ,
66+ MaxPeers : 8 ,
67+ FilterCacheSize : 5000 ,
8568 Logger : backend ,
8669 LogLevel : * logLevel ,
8770 }
@@ -98,43 +81,58 @@ func main() {
9881 os .Exit (1 )
9982 }
10083
101- // Setup REST API
84+ // Create API handler
85+ apiLogger := backend .Logger ("API" )
86+ apiLogger .SetLevel (level )
87+ handler := api .NewHandler (node , apiLogger )
88+
89+ // Set up router
10290 router := mux .NewRouter ()
103- apiHandler := api .NewHandler (node , logger )
104- apiHandler .RegisterRoutes (router )
91+ handler .RegisterRoutes (router )
10592
10693 // Create HTTP server
10794 server := & http.Server {
108- Addr : * listenAddr ,
95+ Addr : * listen ,
10996 Handler : router ,
11097 ReadTimeout : 30 * time .Second ,
111- WriteTimeout : 60 * time .Second ,
112- IdleTimeout : 120 * time .Second ,
98+ WriteTimeout : 30 * time .Second ,
99+ IdleTimeout : 60 * time .Second ,
113100 }
114101
115- // Start HTTP server in goroutine
102+ // Start HTTP server in background
116103 go func () {
117- logger .Infof ("REST API listening on %s" , * listenAddr )
118- if err := server .ListenAndServe (); err != http .ErrServerClosed {
104+ logger .Infof ("HTTP server listening on %s" , * listen )
105+ if err := server .ListenAndServe (); err != nil && err != http .ErrServerClosed {
119106 logger .Errorf ("HTTP server error: %v" , err )
120107 }
121108 }()
122109
123110 // Wait for shutdown signal
124- sigChan := make (chan os.Signal , 1 )
125- signal .Notify (sigChan , syscall .SIGINT , syscall .SIGTERM )
126- <- sigChan
111+ quit := make (chan os.Signal , 1 )
112+ signal .Notify (quit , syscall .SIGINT , syscall .SIGTERM )
113+ <- quit
127114
128115 logger .Info ("Shutting down..." )
129116
130- // Graceful shutdown
131- if err := server .Close (); err != nil {
132- logger .Warnf ("HTTP server shutdown error: %v" , err )
117+ // Graceful shutdown with timeout
118+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
119+ defer cancel ()
120+
121+ if err := server .Shutdown (ctx ); err != nil {
122+ logger .Errorf ("HTTP server shutdown error: %v" , err )
133123 }
134124
135125 if err := node .Stop (); err != nil {
136- logger .Warnf ("Neutrino node shutdown error: %v" , err )
126+ logger .Errorf ("Neutrino node shutdown error: %v" , err )
137127 }
138128
139129 logger .Info ("Shutdown complete" )
140130}
131+
132+ // getEnv returns the value of an environment variable or a default value.
133+ func getEnv (key , defaultValue string ) string {
134+ if value := os .Getenv (key ); value != "" {
135+ return value
136+ }
137+ return defaultValue
138+ }
0 commit comments