github.com/ethereum-optimism/optimism@v1.7.2/op-bootnode/bootnode/entrypoint.go (about) 1 package bootnode 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "github.com/libp2p/go-libp2p/core/peer" 9 "github.com/urfave/cli/v2" 10 11 "github.com/ethereum/go-ethereum/common" 12 "github.com/ethereum/go-ethereum/log" 13 "github.com/ethereum/go-ethereum/rpc" 14 15 opnode "github.com/ethereum-optimism/optimism/op-node" 16 "github.com/ethereum-optimism/optimism/op-node/metrics" 17 "github.com/ethereum-optimism/optimism/op-node/p2p" 18 p2pcli "github.com/ethereum-optimism/optimism/op-node/p2p/cli" 19 "github.com/ethereum-optimism/optimism/op-node/rollup" 20 "github.com/ethereum-optimism/optimism/op-service/eth" 21 oplog "github.com/ethereum-optimism/optimism/op-service/log" 22 opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" 23 "github.com/ethereum-optimism/optimism/op-service/opio" 24 oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" 25 ) 26 27 type gossipNoop struct{} 28 29 func (g *gossipNoop) OnUnsafeL2Payload(_ context.Context, _ peer.ID, _ *eth.ExecutionPayloadEnvelope) error { 30 return nil 31 } 32 33 type gossipConfig struct{} 34 35 func (g *gossipConfig) P2PSequencerAddress() common.Address { 36 return common.Address{} 37 } 38 39 type l2Chain struct{} 40 41 func (l *l2Chain) PayloadByNumber(_ context.Context, _ uint64) (*eth.ExecutionPayloadEnvelope, error) { 42 return nil, errors.New("P2P req/resp is not supported in bootnodes") 43 } 44 45 func Main(cliCtx *cli.Context) error { 46 log.Info("Initializing bootnode") 47 logCfg := oplog.ReadCLIConfig(cliCtx) 48 logger := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) 49 oplog.SetGlobalLogHandler(logger.Handler()) 50 m := metrics.NewMetrics("default") 51 ctx := context.Background() 52 53 config, err := opnode.NewRollupConfigFromCLI(logger, cliCtx) 54 if err != nil { 55 return err 56 } 57 if err = validateConfig(config); err != nil { 58 return err 59 } 60 61 p2pConfig, err := p2pcli.NewConfig(cliCtx, config) 62 if err != nil { 63 return fmt.Errorf("failed to load p2p config: %w", err) 64 } 65 if p2pConfig.EnableReqRespSync { 66 logger.Warn("req-resp sync is enabled, bootnode does not support this feature") 67 p2pConfig.EnableReqRespSync = false 68 } 69 70 p2pNode, err := p2p.NewNodeP2P(ctx, config, logger, p2pConfig, &gossipNoop{}, &l2Chain{}, &gossipConfig{}, m, false) 71 if err != nil || p2pNode == nil { 72 return err 73 } 74 if p2pNode.Dv5Udp() == nil { 75 return fmt.Errorf("uninitialized discovery service") 76 } 77 78 rpcCfg := oprpc.ReadCLIConfig(cliCtx) 79 if err := rpcCfg.Check(); err != nil { 80 return fmt.Errorf("failed to validate RPC config") 81 } 82 rpcServer := oprpc.NewServer(rpcCfg.ListenAddr, rpcCfg.ListenPort, "", oprpc.WithLogger(logger)) 83 if rpcCfg.EnableAdmin { 84 logger.Info("Admin RPC enabled but does nothing for the bootnode") 85 } 86 rpcServer.AddAPI(rpc.API{ 87 Namespace: p2p.NamespaceRPC, 88 Version: "", 89 Service: p2p.NewP2PAPIBackend(p2pNode, logger, m), 90 Authenticated: false, 91 }) 92 if err := rpcServer.Start(); err != nil { 93 return fmt.Errorf("failed to start the RPC server") 94 } 95 defer func() { 96 if err := rpcServer.Stop(); err != nil { 97 log.Error("failed to stop RPC server", "err", err) 98 } 99 }() 100 101 go p2pNode.DiscoveryProcess(ctx, logger, config, p2pConfig.TargetPeers()) 102 103 metricsCfg := opmetrics.ReadCLIConfig(cliCtx) 104 if metricsCfg.Enabled { 105 log.Debug("starting metrics server", "addr", metricsCfg.ListenAddr, "port", metricsCfg.ListenPort) 106 metricsSrv, err := m.StartServer(metricsCfg.ListenAddr, metricsCfg.ListenPort) 107 if err != nil { 108 return fmt.Errorf("failed to start metrics server: %w", err) 109 } 110 defer func() { 111 if err := metricsSrv.Stop(context.Background()); err != nil { 112 log.Error("failed to stop metrics server", "err", err) 113 } 114 }() 115 log.Info("started metrics server", "addr", metricsSrv.Addr()) 116 m.RecordUp() 117 } 118 119 opio.BlockOnInterrupts() 120 121 return nil 122 } 123 124 // validateConfig ensures the minimal config required to run a bootnode 125 func validateConfig(config *rollup.Config) error { 126 if config.L2ChainID == nil || config.L2ChainID.Uint64() == 0 { 127 return errors.New("chain ID is not set") 128 } 129 if config.Genesis.L2Time <= 0 { 130 return errors.New("genesis timestamp is not set") 131 } 132 if config.BlockTime <= 0 { 133 return errors.New("block time is not set") 134 } 135 return nil 136 }