github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/network/node/node.go (about) 1 package node 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "os" 8 "path/filepath" 9 "reflect" 10 "strings" 11 "sync" 12 13 "github.com/neatlab/neatio/chain/core/rawdb" 14 15 "github.com/neatlab/neatio/chain/accounts" 16 "github.com/neatlab/neatio/chain/log" 17 "github.com/neatlab/neatio/internal/debug" 18 "github.com/neatlab/neatio/neatdb" 19 "github.com/neatlab/neatio/network/p2p" 20 "github.com/neatlab/neatio/network/rpc" 21 "github.com/neatlab/neatio/utilities/event" 22 flock "github.com/neatlib/flock-go" 23 ) 24 25 type Node struct { 26 eventmux *event.TypeMux 27 config *Config 28 accman *accounts.Manager 29 30 ephemeralKeystore string 31 instanceDirLock flock.Releaser 32 33 serverConfig p2p.Config 34 server *p2p.Server 35 36 serviceFuncs []ServiceConstructor 37 services map[reflect.Type]Service 38 39 rpcAPIs []rpc.API 40 inprocHandler *rpc.Server 41 42 ipcEndpoint string 43 ipcListener net.Listener 44 ipcHandler *rpc.Server 45 46 httpEndpoint string 47 httpWhitelist []string 48 httpListener net.Listener 49 httpHandler *rpc.Server 50 51 wsEndpoint string 52 wsListener net.Listener 53 wsHandler *rpc.Server 54 55 stop chan struct{} 56 lock sync.RWMutex 57 58 log log.Logger 59 } 60 61 func New(conf *Config) (*Node, error) { 62 confCopy := *conf 63 conf = &confCopy 64 if conf.DataDir != "" { 65 absdatadir, err := filepath.Abs(conf.DataDir) 66 if err != nil { 67 return nil, err 68 } 69 conf.DataDir = absdatadir 70 } 71 if strings.ContainsAny(conf.Name, `/\`) { 72 return nil, errors.New(`Config.Name must not contain '/' or '\'`) 73 } 74 if conf.Name == datadirDefaultKeyStore { 75 return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`) 76 } 77 if strings.HasSuffix(conf.Name, ".ipc") { 78 return nil, errors.New(`Config.Name cannot end in ".ipc"`) 79 } 80 am, ephemeralKeystore, err := makeAccountManager(conf) 81 if err != nil { 82 return nil, err 83 } 84 if conf.Logger == nil { 85 conf.Logger = log.New() 86 } 87 return &Node{ 88 accman: am, 89 ephemeralKeystore: ephemeralKeystore, 90 config: conf, 91 serviceFuncs: []ServiceConstructor{}, 92 ipcEndpoint: conf.IPCEndpoint(), 93 httpEndpoint: conf.HTTPEndpoint(), 94 wsEndpoint: conf.WSEndpoint(), 95 eventmux: new(event.TypeMux), 96 log: conf.Logger, 97 }, nil 98 } 99 100 func (n *Node) Close() error { 101 var errs []error 102 103 if err := n.Stop(); err != nil && err != ErrNodeStopped { 104 errs = append(errs, err) 105 } 106 if err := n.accman.Close(); err != nil { 107 errs = append(errs, err) 108 } 109 switch len(errs) { 110 case 0: 111 return nil 112 case 1: 113 return errs[0] 114 default: 115 return fmt.Errorf("%v", errs) 116 } 117 } 118 119 func (n *Node) Register(constructor ServiceConstructor) error { 120 n.lock.Lock() 121 defer n.lock.Unlock() 122 123 if n.server != nil { 124 return ErrNodeRunning 125 } 126 n.serviceFuncs = append(n.serviceFuncs, constructor) 127 return nil 128 } 129 130 func (n *Node) Start() error { 131 n.lock.Lock() 132 defer n.lock.Unlock() 133 134 if n.server != nil { 135 return ErrNodeRunning 136 } 137 if err := n.openDataDir(); err != nil { 138 return err 139 } 140 141 n.serverConfig = n.config.P2P 142 n.serverConfig.PrivateKey = n.config.NodeKey() 143 n.serverConfig.Name = n.config.NodeName() 144 n.serverConfig.Logger = n.log 145 if n.serverConfig.StaticNodes == nil { 146 n.serverConfig.StaticNodes = n.config.StaticNodes() 147 } 148 if n.serverConfig.TrustedNodes == nil { 149 n.serverConfig.TrustedNodes = n.config.TrustedNodes() 150 } 151 if n.serverConfig.NodeDatabase == "" { 152 n.serverConfig.NodeDatabase = n.config.NodeDB() 153 } 154 running := &p2p.Server{Config: n.serverConfig} 155 n.log.Info("Starting peer-to-peer node", "instance", n.serverConfig.Name) 156 157 services := make(map[reflect.Type]Service) 158 for _, constructor := range n.serviceFuncs { 159 ctx := &ServiceContext{ 160 config: n.config, 161 services: make(map[reflect.Type]Service), 162 EventMux: n.eventmux, 163 AccountManager: n.accman, 164 } 165 for kind, s := range services { 166 ctx.services[kind] = s 167 } 168 service, err := constructor(ctx) 169 if err != nil { 170 return err 171 } 172 kind := reflect.TypeOf(service) 173 if _, exists := services[kind]; exists { 174 return &DuplicateServiceError{Kind: kind} 175 } 176 services[kind] = service 177 } 178 for _, service := range services { 179 running.Protocols = append(running.Protocols, service.Protocols()...) 180 } 181 if err := running.Start(); err != nil { 182 return convertFileLockError(err) 183 } 184 started := []reflect.Type{} 185 for kind, service := range services { 186 if err := service.Start(running); err != nil { 187 for _, kind := range started { 188 services[kind].Stop() 189 } 190 running.Stop() 191 192 return err 193 } 194 started = append(started, kind) 195 } 196 if err := n.startRPC(services); err != nil { 197 for _, service := range services { 198 service.Stop() 199 } 200 running.Stop() 201 return err 202 } 203 n.services = services 204 n.server = running 205 n.stop = make(chan struct{}) 206 207 return nil 208 } 209 210 func (n *Node) openDataDir() error { 211 if n.config.DataDir == "" { 212 return nil 213 } 214 215 instdir := filepath.Join(n.config.DataDir, n.config.name()) 216 if err := os.MkdirAll(instdir, 0700); err != nil { 217 return err 218 } 219 release, _, err := flock.New(filepath.Join(instdir, "LOCK")) 220 if err != nil { 221 return convertFileLockError(err) 222 } 223 n.instanceDirLock = release 224 return nil 225 } 226 227 func (n *Node) startRPC(services map[reflect.Type]Service) error { 228 apis := n.apis() 229 for _, service := range services { 230 apis = append(apis, service.APIs()...) 231 } 232 if err := n.startInProc(apis); err != nil { 233 return err 234 } 235 if err := n.startIPC(apis); err != nil { 236 n.stopInProc() 237 return err 238 } 239 if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts); err != nil { 240 n.stopIPC() 241 n.stopInProc() 242 return err 243 } 244 if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil { 245 n.stopHTTP() 246 n.stopIPC() 247 n.stopInProc() 248 return err 249 } 250 n.rpcAPIs = apis 251 return nil 252 } 253 254 func (n *Node) startInProc(apis []rpc.API) error { 255 handler := rpc.NewServer() 256 for _, api := range apis { 257 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 258 return err 259 } 260 n.log.Debug("InProc registered", "service", api.Service, "namespace", api.Namespace) 261 } 262 n.inprocHandler = handler 263 return nil 264 } 265 266 func (n *Node) stopInProc() { 267 if n.inprocHandler != nil { 268 n.inprocHandler.Stop() 269 n.inprocHandler = nil 270 } 271 } 272 273 func (n *Node) startIPC(apis []rpc.API) error { 274 if n.ipcEndpoint == "" { 275 return nil 276 } 277 listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis) 278 if err != nil { 279 return err 280 } 281 n.ipcListener = listener 282 n.ipcHandler = handler 283 return nil 284 } 285 286 func (n *Node) stopIPC() { 287 if n.ipcListener != nil { 288 n.ipcListener.Close() 289 n.ipcListener = nil 290 291 n.log.Info("IPC endpoint closed", "endpoint", n.ipcEndpoint) 292 } 293 if n.ipcHandler != nil { 294 n.ipcHandler.Stop() 295 n.ipcHandler = nil 296 } 297 } 298 299 func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error { 300 if endpoint == "" { 301 return nil 302 } 303 listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, timeouts) 304 if err != nil { 305 return err 306 } 307 n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ",")) 308 n.httpEndpoint = endpoint 309 n.httpListener = listener 310 n.httpHandler = handler 311 312 return nil 313 } 314 315 func (n *Node) stopHTTP() { 316 if n.httpListener != nil { 317 n.httpListener.Close() 318 n.httpListener = nil 319 320 n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint)) 321 } 322 if n.httpHandler != nil { 323 n.httpHandler.Stop() 324 n.httpHandler = nil 325 } 326 } 327 328 func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error { 329 if endpoint == "" { 330 return nil 331 } 332 listener, handler, err := rpc.StartWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll) 333 if err != nil { 334 return err 335 } 336 n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr())) 337 n.wsEndpoint = endpoint 338 n.wsListener = listener 339 n.wsHandler = handler 340 341 return nil 342 } 343 344 func (n *Node) stopWS() { 345 if n.wsListener != nil { 346 n.wsListener.Close() 347 n.wsListener = nil 348 349 n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint)) 350 } 351 if n.wsHandler != nil { 352 n.wsHandler.Stop() 353 n.wsHandler = nil 354 } 355 } 356 357 func (n *Node) Stop() error { 358 n.lock.Lock() 359 defer n.lock.Unlock() 360 361 if n.server == nil { 362 return ErrNodeStopped 363 } 364 365 n.stopWS() 366 n.stopHTTP() 367 n.stopIPC() 368 n.rpcAPIs = nil 369 failure := &StopError{ 370 Services: make(map[reflect.Type]error), 371 } 372 for kind, service := range n.services { 373 if err := service.Stop(); err != nil { 374 failure.Services[kind] = err 375 } 376 } 377 n.server.Stop() 378 n.services = nil 379 n.server = nil 380 381 if n.instanceDirLock != nil { 382 if err := n.instanceDirLock.Release(); err != nil { 383 n.log.Error("Can't release datadir lock", "err", err) 384 } 385 n.instanceDirLock = nil 386 } 387 388 close(n.stop) 389 390 var keystoreErr error 391 if n.ephemeralKeystore != "" { 392 keystoreErr = os.RemoveAll(n.ephemeralKeystore) 393 } 394 395 if len(failure.Services) > 0 { 396 return failure 397 } 398 if keystoreErr != nil { 399 return keystoreErr 400 } 401 return nil 402 } 403 404 func (n *Node) Wait() { 405 n.lock.RLock() 406 if n.server == nil { 407 n.lock.RUnlock() 408 return 409 } 410 stop := n.stop 411 n.lock.RUnlock() 412 413 <-stop 414 } 415 416 func (n *Node) Restart() error { 417 if err := n.Stop(); err != nil { 418 return err 419 } 420 if err := n.Start(); err != nil { 421 return err 422 } 423 return nil 424 } 425 426 func (n *Node) Attach() (*rpc.Client, error) { 427 n.lock.RLock() 428 defer n.lock.RUnlock() 429 430 if n.server == nil { 431 return nil, ErrNodeStopped 432 } 433 return rpc.DialInProc(n.inprocHandler), nil 434 } 435 436 func (n *Node) RPCHandler() (*rpc.Server, error) { 437 n.lock.RLock() 438 defer n.lock.RUnlock() 439 440 if n.inprocHandler == nil { 441 return nil, ErrNodeStopped 442 } 443 return n.inprocHandler, nil 444 } 445 446 func (n *Node) Server() *p2p.Server { 447 n.lock.RLock() 448 defer n.lock.RUnlock() 449 450 return n.server 451 } 452 453 func (n *Node) Service(service interface{}) error { 454 n.lock.RLock() 455 defer n.lock.RUnlock() 456 457 if n.server == nil { 458 return ErrNodeStopped 459 } 460 element := reflect.ValueOf(service).Elem() 461 if running, ok := n.services[element.Type()]; ok { 462 element.Set(reflect.ValueOf(running)) 463 return nil 464 } 465 return ErrServiceUnknown 466 } 467 468 func (n *Node) DataDir() string { 469 return n.config.DataDir 470 } 471 472 func (n *Node) InstanceDir() string { 473 return n.config.instanceDir() 474 } 475 476 func (n *Node) AccountManager() *accounts.Manager { 477 return n.accman 478 } 479 480 func (n *Node) IPCEndpoint() string { 481 return n.ipcEndpoint 482 } 483 484 func (n *Node) HTTPEndpoint() string { 485 return n.httpEndpoint 486 } 487 488 func (n *Node) WSEndpoint() string { 489 return n.wsEndpoint 490 } 491 492 func (n *Node) EventMux() *event.TypeMux { 493 return n.eventmux 494 } 495 496 func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (neatdb.Database, error) { 497 if n.config.DataDir == "" { 498 return rawdb.NewMemoryDatabase(), nil 499 } 500 return rawdb.NewLevelDBDatabase(n.config.ResolvePath(name), cache, handles, namespace) 501 } 502 503 func (n *Node) ResolvePath(x string) string { 504 return n.config.ResolvePath(x) 505 } 506 507 func (n *Node) SetP2PServer(p2pServer *p2p.Server) { 508 n.server = p2pServer 509 } 510 511 func (n *Node) StopChan() <-chan struct{} { 512 return n.stop 513 } 514 515 func (n *Node) apis() []rpc.API { 516 return []rpc.API{ 517 { 518 Namespace: "admin", 519 Version: "1.0", 520 Service: NewPrivateAdminAPI(n), 521 }, { 522 Namespace: "admin", 523 Version: "1.0", 524 Service: NewPublicAdminAPI(n), 525 Public: true, 526 }, { 527 Namespace: "debug", 528 Version: "1.0", 529 Service: debug.Handler, 530 }, { 531 Namespace: "debug", 532 Version: "1.0", 533 Service: NewPublicDebugAPI(n), 534 Public: true, 535 }, { 536 Namespace: "web3", 537 Version: "1.0", 538 Service: NewPublicWeb3API(n), 539 Public: true, 540 }, 541 } 542 }