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  }