github.com/onflow/flow-go@v0.33.17/cmd/observer/node_builder/observer_builder.go (about)

     1  package node_builder
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"os"
    10  	"path"
    11  	"path/filepath"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/ipfs/boxo/bitswap"
    16  	badger "github.com/ipfs/go-ds-badger2"
    17  	dht "github.com/libp2p/go-libp2p-kad-dht"
    18  	"github.com/libp2p/go-libp2p/core/host"
    19  	"github.com/libp2p/go-libp2p/core/peer"
    20  	"github.com/libp2p/go-libp2p/core/routing"
    21  	"github.com/rs/zerolog"
    22  	"github.com/spf13/pflag"
    23  
    24  	"google.golang.org/grpc/credentials"
    25  
    26  	"github.com/onflow/flow-go/admin/commands"
    27  	stateSyncCommands "github.com/onflow/flow-go/admin/commands/state_synchronization"
    28  	"github.com/onflow/flow-go/cmd"
    29  	"github.com/onflow/flow-go/consensus"
    30  	"github.com/onflow/flow-go/consensus/hotstuff"
    31  	"github.com/onflow/flow-go/consensus/hotstuff/committees"
    32  	"github.com/onflow/flow-go/consensus/hotstuff/notifications"
    33  	"github.com/onflow/flow-go/consensus/hotstuff/notifications/pubsub"
    34  	hotsignature "github.com/onflow/flow-go/consensus/hotstuff/signature"
    35  	hotstuffvalidator "github.com/onflow/flow-go/consensus/hotstuff/validator"
    36  	"github.com/onflow/flow-go/consensus/hotstuff/verification"
    37  	recovery "github.com/onflow/flow-go/consensus/recovery/protocol"
    38  	"github.com/onflow/flow-go/crypto"
    39  	"github.com/onflow/flow-go/engine"
    40  	"github.com/onflow/flow-go/engine/access/apiproxy"
    41  	"github.com/onflow/flow-go/engine/access/rest"
    42  	restapiproxy "github.com/onflow/flow-go/engine/access/rest/apiproxy"
    43  	"github.com/onflow/flow-go/engine/access/rest/routes"
    44  	"github.com/onflow/flow-go/engine/access/rpc"
    45  	"github.com/onflow/flow-go/engine/access/rpc/backend"
    46  	rpcConnection "github.com/onflow/flow-go/engine/access/rpc/connection"
    47  	"github.com/onflow/flow-go/engine/access/state_stream"
    48  	statestreambackend "github.com/onflow/flow-go/engine/access/state_stream/backend"
    49  	"github.com/onflow/flow-go/engine/common/follower"
    50  	synceng "github.com/onflow/flow-go/engine/common/synchronization"
    51  	"github.com/onflow/flow-go/engine/execution/computation/query"
    52  	"github.com/onflow/flow-go/engine/protocol"
    53  	"github.com/onflow/flow-go/ledger"
    54  	"github.com/onflow/flow-go/ledger/complete/wal"
    55  	"github.com/onflow/flow-go/model/bootstrap"
    56  	"github.com/onflow/flow-go/model/encodable"
    57  	"github.com/onflow/flow-go/model/flow"
    58  	"github.com/onflow/flow-go/model/flow/filter"
    59  	"github.com/onflow/flow-go/module"
    60  	"github.com/onflow/flow-go/module/blobs"
    61  	"github.com/onflow/flow-go/module/chainsync"
    62  	"github.com/onflow/flow-go/module/execution"
    63  	"github.com/onflow/flow-go/module/executiondatasync/execution_data"
    64  	execdatacache "github.com/onflow/flow-go/module/executiondatasync/execution_data/cache"
    65  	finalizer "github.com/onflow/flow-go/module/finalizer/consensus"
    66  	"github.com/onflow/flow-go/module/grpcserver"
    67  	"github.com/onflow/flow-go/module/id"
    68  	"github.com/onflow/flow-go/module/local"
    69  	"github.com/onflow/flow-go/module/mempool/herocache"
    70  	"github.com/onflow/flow-go/module/metrics"
    71  	"github.com/onflow/flow-go/module/state_synchronization"
    72  	"github.com/onflow/flow-go/module/state_synchronization/indexer"
    73  	edrequester "github.com/onflow/flow-go/module/state_synchronization/requester"
    74  	consensus_follower "github.com/onflow/flow-go/module/upstream"
    75  	"github.com/onflow/flow-go/network"
    76  	alspmgr "github.com/onflow/flow-go/network/alsp/manager"
    77  	netcache "github.com/onflow/flow-go/network/cache"
    78  	"github.com/onflow/flow-go/network/channels"
    79  	"github.com/onflow/flow-go/network/converter"
    80  	"github.com/onflow/flow-go/network/p2p"
    81  	"github.com/onflow/flow-go/network/p2p/blob"
    82  	p2pbuilder "github.com/onflow/flow-go/network/p2p/builder"
    83  	p2pbuilderconfig "github.com/onflow/flow-go/network/p2p/builder/config"
    84  	"github.com/onflow/flow-go/network/p2p/cache"
    85  	"github.com/onflow/flow-go/network/p2p/conduit"
    86  	p2pdht "github.com/onflow/flow-go/network/p2p/dht"
    87  	"github.com/onflow/flow-go/network/p2p/keyutils"
    88  	p2plogging "github.com/onflow/flow-go/network/p2p/logging"
    89  	"github.com/onflow/flow-go/network/p2p/subscription"
    90  	"github.com/onflow/flow-go/network/p2p/translator"
    91  	"github.com/onflow/flow-go/network/p2p/unicast/protocols"
    92  	"github.com/onflow/flow-go/network/p2p/utils"
    93  	"github.com/onflow/flow-go/network/slashing"
    94  	"github.com/onflow/flow-go/network/underlay"
    95  	"github.com/onflow/flow-go/network/validator"
    96  	stateprotocol "github.com/onflow/flow-go/state/protocol"
    97  	badgerState "github.com/onflow/flow-go/state/protocol/badger"
    98  	"github.com/onflow/flow-go/state/protocol/blocktimer"
    99  	"github.com/onflow/flow-go/state/protocol/events/gadgets"
   100  	"github.com/onflow/flow-go/storage"
   101  	bstorage "github.com/onflow/flow-go/storage/badger"
   102  	pStorage "github.com/onflow/flow-go/storage/pebble"
   103  	"github.com/onflow/flow-go/utils/grpcutils"
   104  	"github.com/onflow/flow-go/utils/io"
   105  )
   106  
   107  // ObserverBuilder extends cmd.NodeBuilder and declares additional functions needed to bootstrap an Access node
   108  // These functions are shared by observer builders.
   109  // The Staked network allows the access nodes to communicate among themselves, while the public network allows the
   110  // observers and an Access node to communicate.
   111  //
   112  //                                 public network                           private network
   113  //  +------------------------+
   114  //  | observer 1             |<--------------------------|
   115  //  +------------------------+                           v
   116  //  +------------------------+                         +----------------------+              +------------------------+
   117  //  | observer 2             |<----------------------->| Access Node (staked) |<------------>| All other staked Nodes |
   118  //  +------------------------+                         +----------------------+              +------------------------+
   119  //  +------------------------+                           ^
   120  //  | observer 3             |<--------------------------|
   121  //  +------------------------+
   122  
   123  // ObserverServiceConfig defines all the user defined parameters required to bootstrap an access node
   124  // For a node running as a standalone process, the config fields will be populated from the command line params,
   125  // while for a node running as a library, the config fields are expected to be initialized by the caller.
   126  type ObserverServiceConfig struct {
   127  	bootstrapNodeAddresses       []string
   128  	bootstrapNodePublicKeys      []string
   129  	observerNetworkingKeyPath    string
   130  	bootstrapIdentities          flow.IdentityList // the identity list of bootstrap peers the node uses to discover other nodes
   131  	apiRatelimits                map[string]int
   132  	apiBurstlimits               map[string]int
   133  	rpcConf                      rpc.Config
   134  	rpcMetricsEnabled            bool
   135  	registersDBPath              string
   136  	checkpointFile               string
   137  	apiTimeout                   time.Duration
   138  	stateStreamConf              statestreambackend.Config
   139  	stateStreamFilterConf        map[string]int
   140  	upstreamNodeAddresses        []string
   141  	upstreamNodePublicKeys       []string
   142  	upstreamIdentities           flow.IdentityList // the identity list of upstream peers the node uses to forward API requests to
   143  	scriptExecutorConfig         query.QueryConfig
   144  	executionDataSyncEnabled     bool
   145  	executionDataIndexingEnabled bool
   146  	executionDataDir             string
   147  	executionDataStartHeight     uint64
   148  	executionDataConfig          edrequester.ExecutionDataConfig
   149  }
   150  
   151  // DefaultObserverServiceConfig defines all the default values for the ObserverServiceConfig
   152  func DefaultObserverServiceConfig() *ObserverServiceConfig {
   153  	homedir, _ := os.UserHomeDir()
   154  	return &ObserverServiceConfig{
   155  		rpcConf: rpc.Config{
   156  			UnsecureGRPCListenAddr: "0.0.0.0:9000",
   157  			SecureGRPCListenAddr:   "0.0.0.0:9001",
   158  			HTTPListenAddr:         "0.0.0.0:8000",
   159  			CollectionAddr:         "",
   160  			HistoricalAccessAddrs:  "",
   161  			BackendConfig: backend.Config{
   162  				CollectionClientTimeout:   3 * time.Second,
   163  				ExecutionClientTimeout:    3 * time.Second,
   164  				ConnectionPoolSize:        backend.DefaultConnectionPoolSize,
   165  				MaxHeightRange:            backend.DefaultMaxHeightRange,
   166  				PreferredExecutionNodeIDs: nil,
   167  				FixedExecutionNodeIDs:     nil,
   168  			},
   169  			RestConfig: rest.Config{
   170  				ListenAddress: "",
   171  				WriteTimeout:  rest.DefaultWriteTimeout,
   172  				ReadTimeout:   rest.DefaultReadTimeout,
   173  				IdleTimeout:   rest.DefaultIdleTimeout,
   174  			},
   175  			MaxMsgSize:     grpcutils.DefaultMaxMsgSize,
   176  			CompressorName: grpcutils.NoCompressor,
   177  		},
   178  		stateStreamConf: statestreambackend.Config{
   179  			MaxExecutionDataMsgSize: grpcutils.DefaultMaxMsgSize,
   180  			ExecutionDataCacheSize:  state_stream.DefaultCacheSize,
   181  			ClientSendTimeout:       state_stream.DefaultSendTimeout,
   182  			ClientSendBufferSize:    state_stream.DefaultSendBufferSize,
   183  			MaxGlobalStreams:        state_stream.DefaultMaxGlobalStreams,
   184  			EventFilterConfig:       state_stream.DefaultEventFilterConfig,
   185  			ResponseLimit:           state_stream.DefaultResponseLimit,
   186  			HeartbeatInterval:       state_stream.DefaultHeartbeatInterval,
   187  			RegisterIDsRequestLimit: state_stream.DefaultRegisterIDsRequestLimit,
   188  		},
   189  		stateStreamFilterConf:        nil,
   190  		rpcMetricsEnabled:            false,
   191  		apiRatelimits:                nil,
   192  		apiBurstlimits:               nil,
   193  		bootstrapNodeAddresses:       []string{},
   194  		bootstrapNodePublicKeys:      []string{},
   195  		observerNetworkingKeyPath:    cmd.NotSet,
   196  		apiTimeout:                   3 * time.Second,
   197  		upstreamNodeAddresses:        []string{},
   198  		upstreamNodePublicKeys:       []string{},
   199  		registersDBPath:              filepath.Join(homedir, ".flow", "execution_state"),
   200  		checkpointFile:               cmd.NotSet,
   201  		scriptExecutorConfig:         query.NewDefaultConfig(),
   202  		executionDataSyncEnabled:     false,
   203  		executionDataIndexingEnabled: false,
   204  		executionDataDir:             filepath.Join(homedir, ".flow", "execution_data"),
   205  		executionDataStartHeight:     0,
   206  		executionDataConfig: edrequester.ExecutionDataConfig{
   207  			InitialBlockHeight: 0,
   208  			MaxSearchAhead:     edrequester.DefaultMaxSearchAhead,
   209  			FetchTimeout:       edrequester.DefaultFetchTimeout,
   210  			MaxFetchTimeout:    edrequester.DefaultMaxFetchTimeout,
   211  			RetryDelay:         edrequester.DefaultRetryDelay,
   212  			MaxRetryDelay:      edrequester.DefaultMaxRetryDelay,
   213  		},
   214  	}
   215  }
   216  
   217  // ObserverServiceBuilder provides the common functionality needed to bootstrap a Flow observer service
   218  // It is composed of the FlowNodeBuilder, the ObserverServiceConfig and contains all the components and modules needed for the observers
   219  type ObserverServiceBuilder struct {
   220  	*cmd.FlowNodeBuilder
   221  	*ObserverServiceConfig
   222  
   223  	// components
   224  
   225  	LibP2PNode           p2p.LibP2PNode
   226  	FollowerState        stateprotocol.FollowerState
   227  	SyncCore             *chainsync.Core
   228  	RpcEng               *rpc.Engine
   229  	FollowerDistributor  *pubsub.FollowerDistributor
   230  	Committee            hotstuff.DynamicCommittee
   231  	Finalized            *flow.Header
   232  	Pending              []*flow.Header
   233  	FollowerCore         module.HotStuffFollower
   234  	ExecutionIndexer     *indexer.Indexer
   235  	ExecutionIndexerCore *indexer.IndexerCore
   236  	IndexerDependencies  *cmd.DependencyList
   237  
   238  	ExecutionDataDownloader execution_data.Downloader
   239  	ExecutionDataRequester  state_synchronization.ExecutionDataRequester
   240  	ExecutionDataStore      execution_data.ExecutionDataStore
   241  
   242  	RegistersAsyncStore *execution.RegistersAsyncStore
   243  	EventsIndex         *backend.EventsIndex
   244  
   245  	// available until after the network has started. Hence, a factory function that needs to be called just before
   246  	// creating the sync engine
   247  	SyncEngineParticipantsProviderFactory func() module.IdentifierProvider
   248  
   249  	// engines
   250  	FollowerEng    *follower.ComplianceEngine
   251  	SyncEng        *synceng.Engine
   252  	StateStreamEng *statestreambackend.Engine
   253  
   254  	// Public network
   255  	peerID peer.ID
   256  
   257  	RestMetrics   *metrics.RestCollector
   258  	AccessMetrics module.AccessMetrics
   259  
   260  	// grpc servers
   261  	secureGrpcServer      *grpcserver.GrpcServer
   262  	unsecureGrpcServer    *grpcserver.GrpcServer
   263  	stateStreamGrpcServer *grpcserver.GrpcServer
   264  
   265  	stateStreamBackend *statestreambackend.StateStreamBackend
   266  }
   267  
   268  // deriveBootstrapPeerIdentities derives the Flow Identity of the bootstrap peers from the parameters.
   269  // These are the identities of the observers also acting as the DHT bootstrap server
   270  func (builder *ObserverServiceBuilder) deriveBootstrapPeerIdentities() error {
   271  	// if bootstrap identities already provided (as part of alternate initialization as a library the skip reading command
   272  	// line params)
   273  	if builder.bootstrapIdentities != nil {
   274  		return nil
   275  	}
   276  
   277  	ids, err := cmd.BootstrapIdentities(builder.bootstrapNodeAddresses, builder.bootstrapNodePublicKeys)
   278  	if err != nil {
   279  		return fmt.Errorf("failed to derive bootstrap peer identities: %w", err)
   280  	}
   281  
   282  	builder.bootstrapIdentities = ids
   283  
   284  	return nil
   285  }
   286  
   287  // deriveBootstrapPeerIdentities derives the Flow Identity of the bootstrap peers from the parameters.
   288  // These are the identities of the observers also acting as the DHT bootstrap server
   289  func (builder *ObserverServiceBuilder) deriveUpstreamIdentities() error {
   290  	// if bootstrap identities already provided (as part of alternate initialization as a library the skip reading command
   291  	// line params)
   292  	if builder.upstreamIdentities != nil {
   293  		return nil
   294  	}
   295  
   296  	// BootstrapIdentities converts the bootstrap node addresses and keys to a Flow Identity list where
   297  	// each Flow Identity is initialized with the passed address, the networking key
   298  	// and the Node ID set to ZeroID, role set to Access, 0 stake and no staking key.
   299  	addresses := builder.upstreamNodeAddresses
   300  	keys := builder.upstreamNodePublicKeys
   301  	if len(addresses) != len(keys) {
   302  		return fmt.Errorf("number of addresses and keys provided for the boostrap nodes don't match")
   303  	}
   304  
   305  	ids := make([]*flow.Identity, len(addresses))
   306  	for i, address := range addresses {
   307  		key := keys[i]
   308  
   309  		// json unmarshaller needs a quotes before and after the string
   310  		// the pflags.StringSliceVar does not retain quotes for the command line arg even if escaped with \"
   311  		// hence this additional check to ensure the key is indeed quoted
   312  		if !strings.HasPrefix(key, "\"") {
   313  			key = fmt.Sprintf("\"%s\"", key)
   314  		}
   315  
   316  		// create the identity of the peer by setting only the relevant fields
   317  		ids[i] = &flow.Identity{
   318  			NodeID:        flow.ZeroID, // the NodeID is the hash of the staking key and for the public network it does not apply
   319  			Address:       address,
   320  			Role:          flow.RoleAccess, // the upstream node has to be an access node
   321  			NetworkPubKey: nil,
   322  		}
   323  
   324  		// networking public key
   325  		var networkKey encodable.NetworkPubKey
   326  		err := json.Unmarshal([]byte(key), &networkKey)
   327  		if err == nil {
   328  			ids[i].NetworkPubKey = networkKey
   329  		}
   330  	}
   331  
   332  	builder.upstreamIdentities = ids
   333  
   334  	return nil
   335  }
   336  
   337  func (builder *ObserverServiceBuilder) buildFollowerState() *ObserverServiceBuilder {
   338  	builder.Module("mutable follower state", func(node *cmd.NodeConfig) error {
   339  		// For now, we only support state implementations from package badger.
   340  		// If we ever support different implementations, the following can be replaced by a type-aware factory
   341  		state, ok := node.State.(*badgerState.State)
   342  		if !ok {
   343  			return fmt.Errorf("only implementations of type badger.State are currently supported but read-only state has type %T", node.State)
   344  		}
   345  
   346  		followerState, err := badgerState.NewFollowerState(
   347  			node.Logger,
   348  			node.Tracer,
   349  			node.ProtocolEvents,
   350  			state,
   351  			node.Storage.Index,
   352  			node.Storage.Payloads,
   353  			blocktimer.DefaultBlockTimer,
   354  		)
   355  		builder.FollowerState = followerState
   356  
   357  		return err
   358  	})
   359  
   360  	return builder
   361  }
   362  
   363  func (builder *ObserverServiceBuilder) buildSyncCore() *ObserverServiceBuilder {
   364  	builder.Module("sync core", func(node *cmd.NodeConfig) error {
   365  		syncCore, err := chainsync.New(node.Logger, node.SyncCoreConfig, metrics.NewChainSyncCollector(node.RootChainID), node.RootChainID)
   366  		builder.SyncCore = syncCore
   367  
   368  		return err
   369  	})
   370  
   371  	return builder
   372  }
   373  
   374  func (builder *ObserverServiceBuilder) buildCommittee() *ObserverServiceBuilder {
   375  	builder.Component("committee", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   376  		// initialize consensus committee's membership state
   377  		// This committee state is for the HotStuff follower, which follows the MAIN CONSENSUS committee
   378  		// Note: node.Me.NodeID() is not part of the consensus committee
   379  		committee, err := committees.NewConsensusCommittee(node.State, node.Me.NodeID())
   380  		node.ProtocolEvents.AddConsumer(committee)
   381  		builder.Committee = committee
   382  
   383  		return committee, err
   384  	})
   385  
   386  	return builder
   387  }
   388  
   389  func (builder *ObserverServiceBuilder) buildLatestHeader() *ObserverServiceBuilder {
   390  	builder.Module("latest header", func(node *cmd.NodeConfig) error {
   391  		finalized, pending, err := recovery.FindLatest(node.State, node.Storage.Headers)
   392  		builder.Finalized, builder.Pending = finalized, pending
   393  
   394  		return err
   395  	})
   396  
   397  	return builder
   398  }
   399  
   400  func (builder *ObserverServiceBuilder) buildFollowerCore() *ObserverServiceBuilder {
   401  	builder.Component("follower core", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   402  		// create a finalizer that will handle updating the protocol
   403  		// state when the follower detects newly finalized blocks
   404  		final := finalizer.NewFinalizer(node.DB, node.Storage.Headers, builder.FollowerState, node.Tracer)
   405  
   406  		followerCore, err := consensus.NewFollower(
   407  			node.Logger,
   408  			node.Metrics.Mempool,
   409  			node.Storage.Headers,
   410  			final,
   411  			builder.FollowerDistributor,
   412  			node.FinalizedRootBlock.Header,
   413  			node.RootQC,
   414  			builder.Finalized,
   415  			builder.Pending,
   416  		)
   417  		if err != nil {
   418  			return nil, fmt.Errorf("could not initialize follower core: %w", err)
   419  		}
   420  		builder.FollowerCore = followerCore
   421  
   422  		return builder.FollowerCore, nil
   423  	})
   424  
   425  	return builder
   426  }
   427  
   428  func (builder *ObserverServiceBuilder) buildFollowerEngine() *ObserverServiceBuilder {
   429  	builder.Component("follower engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   430  		var heroCacheCollector module.HeroCacheMetrics = metrics.NewNoopCollector()
   431  		if node.HeroCacheMetricsEnable {
   432  			heroCacheCollector = metrics.FollowerCacheMetrics(node.MetricsRegisterer)
   433  		}
   434  		packer := hotsignature.NewConsensusSigDataPacker(builder.Committee)
   435  		verifier := verification.NewCombinedVerifier(builder.Committee, packer) // verifier for HotStuff signature constructs (QCs, TCs, votes)
   436  		val := hotstuffvalidator.New(builder.Committee, verifier)
   437  
   438  		core, err := follower.NewComplianceCore(
   439  			node.Logger,
   440  			node.Metrics.Mempool,
   441  			heroCacheCollector,
   442  			builder.FollowerDistributor,
   443  			builder.FollowerState,
   444  			builder.FollowerCore,
   445  			val,
   446  			builder.SyncCore,
   447  			node.Tracer,
   448  		)
   449  		if err != nil {
   450  			return nil, fmt.Errorf("could not create follower core: %w", err)
   451  		}
   452  
   453  		builder.FollowerEng, err = follower.NewComplianceLayer(
   454  			node.Logger,
   455  			node.EngineRegistry,
   456  			node.Me,
   457  			node.Metrics.Engine,
   458  			node.Storage.Headers,
   459  			builder.Finalized,
   460  			core,
   461  			builder.ComplianceConfig,
   462  			follower.WithChannel(channels.PublicReceiveBlocks),
   463  		)
   464  		if err != nil {
   465  			return nil, fmt.Errorf("could not create follower engine: %w", err)
   466  		}
   467  		builder.FollowerDistributor.AddOnBlockFinalizedConsumer(builder.FollowerEng.OnFinalizedBlock)
   468  
   469  		return builder.FollowerEng, nil
   470  	})
   471  
   472  	return builder
   473  }
   474  
   475  func (builder *ObserverServiceBuilder) buildSyncEngine() *ObserverServiceBuilder {
   476  	builder.Component("sync engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   477  		spamConfig, err := synceng.NewSpamDetectionConfig()
   478  		if err != nil {
   479  			return nil, fmt.Errorf("could not initialize spam detection config: %w", err)
   480  		}
   481  
   482  		sync, err := synceng.New(
   483  			node.Logger,
   484  			node.Metrics.Engine,
   485  			node.EngineRegistry,
   486  			node.Me,
   487  			node.State,
   488  			node.Storage.Blocks,
   489  			builder.FollowerEng,
   490  			builder.SyncCore,
   491  			builder.SyncEngineParticipantsProviderFactory(),
   492  			spamConfig,
   493  		)
   494  		if err != nil {
   495  			return nil, fmt.Errorf("could not create synchronization engine: %w", err)
   496  		}
   497  		builder.SyncEng = sync
   498  		builder.FollowerDistributor.AddFinalizationConsumer(sync)
   499  
   500  		return builder.SyncEng, nil
   501  	})
   502  
   503  	return builder
   504  }
   505  
   506  func (builder *ObserverServiceBuilder) BuildConsensusFollower() cmd.NodeBuilder {
   507  	builder.
   508  		buildFollowerState().
   509  		buildSyncCore().
   510  		buildCommittee().
   511  		buildLatestHeader().
   512  		buildFollowerCore().
   513  		buildFollowerEngine().
   514  		buildSyncEngine()
   515  
   516  	return builder
   517  }
   518  
   519  type Option func(*ObserverServiceConfig)
   520  
   521  func NewFlowObserverServiceBuilder(opts ...Option) *ObserverServiceBuilder {
   522  	config := DefaultObserverServiceConfig()
   523  	for _, opt := range opts {
   524  		opt(config)
   525  	}
   526  	anb := &ObserverServiceBuilder{
   527  		ObserverServiceConfig: config,
   528  		FlowNodeBuilder:       cmd.FlowNode("observer"),
   529  		FollowerDistributor:   pubsub.NewFollowerDistributor(),
   530  		IndexerDependencies:   cmd.NewDependencyList(),
   531  	}
   532  	anb.FollowerDistributor.AddProposalViolationConsumer(notifications.NewSlashingViolationsConsumer(anb.Logger))
   533  	// the observer gets a version of the root snapshot file that does not contain any node addresses
   534  	// hence skip all the root snapshot validations that involved an identity address
   535  	anb.FlowNodeBuilder.SkipNwAddressBasedValidations = true
   536  	return anb
   537  }
   538  
   539  func (builder *ObserverServiceBuilder) ParseFlags() error {
   540  
   541  	builder.BaseFlags()
   542  
   543  	builder.extraFlags()
   544  
   545  	return builder.ParseAndPrintFlags()
   546  }
   547  
   548  func (builder *ObserverServiceBuilder) extraFlags() {
   549  	builder.ExtraFlags(func(flags *pflag.FlagSet) {
   550  		defaultConfig := DefaultObserverServiceConfig()
   551  
   552  		flags.StringVarP(&builder.rpcConf.UnsecureGRPCListenAddr,
   553  			"rpc-addr",
   554  			"r",
   555  			defaultConfig.rpcConf.UnsecureGRPCListenAddr,
   556  			"the address the unsecured gRPC server listens on")
   557  		flags.StringVar(&builder.rpcConf.SecureGRPCListenAddr,
   558  			"secure-rpc-addr",
   559  			defaultConfig.rpcConf.SecureGRPCListenAddr,
   560  			"the address the secure gRPC server listens on")
   561  		flags.StringVarP(&builder.rpcConf.HTTPListenAddr, "http-addr", "h", defaultConfig.rpcConf.HTTPListenAddr, "the address the http proxy server listens on")
   562  		flags.StringVar(&builder.rpcConf.RestConfig.ListenAddress,
   563  			"rest-addr",
   564  			defaultConfig.rpcConf.RestConfig.ListenAddress,
   565  			"the address the REST server listens on (if empty the REST server will not be started)")
   566  		flags.DurationVar(&builder.rpcConf.RestConfig.WriteTimeout,
   567  			"rest-write-timeout",
   568  			defaultConfig.rpcConf.RestConfig.WriteTimeout,
   569  			"timeout to use when writing REST response")
   570  		flags.DurationVar(&builder.rpcConf.RestConfig.ReadTimeout,
   571  			"rest-read-timeout",
   572  			defaultConfig.rpcConf.RestConfig.ReadTimeout,
   573  			"timeout to use when reading REST request headers")
   574  		flags.DurationVar(&builder.rpcConf.RestConfig.IdleTimeout, "rest-idle-timeout", defaultConfig.rpcConf.RestConfig.IdleTimeout, "idle timeout for REST connections")
   575  		flags.UintVar(&builder.rpcConf.MaxMsgSize,
   576  			"rpc-max-message-size",
   577  			defaultConfig.rpcConf.MaxMsgSize,
   578  			"the maximum message size in bytes for messages sent or received over grpc")
   579  		flags.UintVar(&builder.rpcConf.BackendConfig.ConnectionPoolSize,
   580  			"connection-pool-size",
   581  			defaultConfig.rpcConf.BackendConfig.ConnectionPoolSize,
   582  			"maximum number of connections allowed in the connection pool, size of 0 disables the connection pooling, and anything less than the default size will be overridden to use the default size")
   583  		flags.UintVar(&builder.rpcConf.BackendConfig.MaxHeightRange,
   584  			"rpc-max-height-range",
   585  			defaultConfig.rpcConf.BackendConfig.MaxHeightRange,
   586  			"maximum size for height range requests")
   587  		flags.StringToIntVar(&builder.apiRatelimits,
   588  			"api-rate-limits",
   589  			defaultConfig.apiRatelimits,
   590  			"per second rate limits for Access API methods e.g. Ping=300,GetTransaction=500 etc.")
   591  		flags.StringToIntVar(&builder.apiBurstlimits,
   592  			"api-burst-limits",
   593  			defaultConfig.apiBurstlimits,
   594  			"burst limits for Access API methods e.g. Ping=100,GetTransaction=100 etc.")
   595  		flags.StringVar(&builder.observerNetworkingKeyPath,
   596  			"observer-networking-key-path",
   597  			defaultConfig.observerNetworkingKeyPath,
   598  			"path to the networking key for observer")
   599  		flags.StringSliceVar(&builder.bootstrapNodeAddresses,
   600  			"bootstrap-node-addresses",
   601  			defaultConfig.bootstrapNodeAddresses,
   602  			"the network addresses of the bootstrap access node if this is an observer e.g. access-001.mainnet.flow.org:9653,access-002.mainnet.flow.org:9653")
   603  		flags.StringSliceVar(&builder.bootstrapNodePublicKeys,
   604  			"bootstrap-node-public-keys",
   605  			defaultConfig.bootstrapNodePublicKeys,
   606  			"the networking public key of the bootstrap access node if this is an observer (in the same order as the bootstrap node addresses) e.g. \"d57a5e9c5.....\",\"44ded42d....\"")
   607  		flags.DurationVar(&builder.apiTimeout, "upstream-api-timeout", defaultConfig.apiTimeout, "tcp timeout for Flow API gRPC sockets to upstrem nodes")
   608  		flags.StringSliceVar(&builder.upstreamNodeAddresses,
   609  			"upstream-node-addresses",
   610  			defaultConfig.upstreamNodeAddresses,
   611  			"the gRPC network addresses of the upstream access node. e.g. access-001.mainnet.flow.org:9000,access-002.mainnet.flow.org:9000")
   612  		flags.StringSliceVar(&builder.upstreamNodePublicKeys,
   613  			"upstream-node-public-keys",
   614  			defaultConfig.upstreamNodePublicKeys,
   615  			"the networking public key of the upstream access node (in the same order as the upstream node addresses) e.g. \"d57a5e9c5.....\",\"44ded42d....\"")
   616  		flags.BoolVar(&builder.rpcMetricsEnabled, "rpc-metrics-enabled", defaultConfig.rpcMetricsEnabled, "whether to enable the rpc metrics")
   617  		flags.BoolVar(&builder.executionDataIndexingEnabled,
   618  			"execution-data-indexing-enabled",
   619  			defaultConfig.executionDataIndexingEnabled,
   620  			"whether to enable the execution data indexing")
   621  		flags.StringVar(&builder.registersDBPath, "execution-state-dir", defaultConfig.registersDBPath, "directory to use for execution-state database")
   622  		flags.StringVar(&builder.checkpointFile, "execution-state-checkpoint", defaultConfig.checkpointFile, "execution-state checkpoint file")
   623  
   624  		// ExecutionDataRequester config
   625  		flags.BoolVar(&builder.executionDataSyncEnabled,
   626  			"execution-data-sync-enabled",
   627  			defaultConfig.executionDataSyncEnabled,
   628  			"whether to enable the execution data sync protocol")
   629  		flags.StringVar(&builder.executionDataDir,
   630  			"execution-data-dir",
   631  			defaultConfig.executionDataDir,
   632  			"directory to use for Execution Data database")
   633  		flags.Uint64Var(&builder.executionDataStartHeight,
   634  			"execution-data-start-height",
   635  			defaultConfig.executionDataStartHeight,
   636  			"height of first block to sync execution data from when starting with an empty Execution Data database")
   637  		flags.Uint64Var(&builder.executionDataConfig.MaxSearchAhead,
   638  			"execution-data-max-search-ahead",
   639  			defaultConfig.executionDataConfig.MaxSearchAhead,
   640  			"max number of heights to search ahead of the lowest outstanding execution data height")
   641  		flags.DurationVar(&builder.executionDataConfig.FetchTimeout,
   642  			"execution-data-fetch-timeout",
   643  			defaultConfig.executionDataConfig.FetchTimeout,
   644  			"initial timeout to use when fetching execution data from the network. timeout increases using an incremental backoff until execution-data-max-fetch-timeout. e.g. 30s")
   645  		flags.DurationVar(&builder.executionDataConfig.MaxFetchTimeout,
   646  			"execution-data-max-fetch-timeout",
   647  			defaultConfig.executionDataConfig.MaxFetchTimeout,
   648  			"maximum timeout to use when fetching execution data from the network e.g. 300s")
   649  		flags.DurationVar(&builder.executionDataConfig.RetryDelay,
   650  			"execution-data-retry-delay",
   651  			defaultConfig.executionDataConfig.RetryDelay,
   652  			"initial delay for exponential backoff when fetching execution data fails e.g. 10s")
   653  		flags.DurationVar(&builder.executionDataConfig.MaxRetryDelay,
   654  			"execution-data-max-retry-delay",
   655  			defaultConfig.executionDataConfig.MaxRetryDelay,
   656  			"maximum delay for exponential backoff when fetching execution data fails e.g. 5m")
   657  
   658  		// Streaming API
   659  		flags.StringVar(&builder.stateStreamConf.ListenAddr,
   660  			"state-stream-addr",
   661  			defaultConfig.stateStreamConf.ListenAddr,
   662  			"the address the state stream server listens on (if empty the server will not be started)")
   663  		flags.Uint32Var(&builder.stateStreamConf.ExecutionDataCacheSize,
   664  			"execution-data-cache-size",
   665  			defaultConfig.stateStreamConf.ExecutionDataCacheSize,
   666  			"block execution data cache size")
   667  		flags.Uint32Var(&builder.stateStreamConf.MaxGlobalStreams,
   668  			"state-stream-global-max-streams", defaultConfig.stateStreamConf.MaxGlobalStreams,
   669  			"global maximum number of concurrent streams")
   670  		flags.UintVar(&builder.stateStreamConf.MaxExecutionDataMsgSize,
   671  			"state-stream-max-message-size",
   672  			defaultConfig.stateStreamConf.MaxExecutionDataMsgSize,
   673  			"maximum size for a gRPC message containing block execution data")
   674  		flags.StringToIntVar(&builder.stateStreamFilterConf,
   675  			"state-stream-event-filter-limits",
   676  			defaultConfig.stateStreamFilterConf,
   677  			"event filter limits for ExecutionData SubscribeEvents API e.g. EventTypes=100,Addresses=100,Contracts=100 etc.")
   678  		flags.DurationVar(&builder.stateStreamConf.ClientSendTimeout,
   679  			"state-stream-send-timeout",
   680  			defaultConfig.stateStreamConf.ClientSendTimeout,
   681  			"maximum wait before timing out while sending a response to a streaming client e.g. 30s")
   682  		flags.UintVar(&builder.stateStreamConf.ClientSendBufferSize,
   683  			"state-stream-send-buffer-size",
   684  			defaultConfig.stateStreamConf.ClientSendBufferSize,
   685  			"maximum number of responses to buffer within a stream")
   686  		flags.Float64Var(&builder.stateStreamConf.ResponseLimit,
   687  			"state-stream-response-limit",
   688  			defaultConfig.stateStreamConf.ResponseLimit,
   689  			"max number of responses per second to send over streaming endpoints. this helps manage resources consumed by each client querying data not in the cache e.g. 3 or 0.5. 0 means no limit")
   690  		flags.Uint64Var(&builder.stateStreamConf.HeartbeatInterval,
   691  			"state-stream-heartbeat-interval",
   692  			defaultConfig.stateStreamConf.HeartbeatInterval,
   693  			"default interval in blocks at which heartbeat messages should be sent. applied when client did not specify a value.")
   694  		flags.Uint32Var(&builder.stateStreamConf.RegisterIDsRequestLimit,
   695  			"state-stream-max-register-values",
   696  			defaultConfig.stateStreamConf.RegisterIDsRequestLimit,
   697  			"maximum number of register ids to include in a single request to the GetRegisters endpoint")
   698  
   699  		flags.StringVar(&builder.rpcConf.BackendConfig.EventQueryMode,
   700  			"event-query-mode",
   701  			defaultConfig.rpcConf.BackendConfig.EventQueryMode,
   702  			"mode to use when querying events. one of [local-only, execution-nodes-only(default), failover]")
   703  
   704  	}).ValidateFlags(func() error {
   705  		if builder.executionDataSyncEnabled {
   706  			if builder.executionDataConfig.FetchTimeout <= 0 {
   707  				return errors.New("execution-data-fetch-timeout must be greater than 0")
   708  			}
   709  			if builder.executionDataConfig.MaxFetchTimeout < builder.executionDataConfig.FetchTimeout {
   710  				return errors.New("execution-data-max-fetch-timeout must be greater than execution-data-fetch-timeout")
   711  			}
   712  			if builder.executionDataConfig.RetryDelay <= 0 {
   713  				return errors.New("execution-data-retry-delay must be greater than 0")
   714  			}
   715  			if builder.executionDataConfig.MaxRetryDelay < builder.executionDataConfig.RetryDelay {
   716  				return errors.New("execution-data-max-retry-delay must be greater than or equal to execution-data-retry-delay")
   717  			}
   718  			if builder.executionDataConfig.MaxSearchAhead == 0 {
   719  				return errors.New("execution-data-max-search-ahead must be greater than 0")
   720  			}
   721  		}
   722  		if builder.stateStreamConf.ListenAddr != "" {
   723  			if builder.stateStreamConf.ExecutionDataCacheSize == 0 {
   724  				return errors.New("execution-data-cache-size must be greater than 0")
   725  			}
   726  			if builder.stateStreamConf.ClientSendBufferSize == 0 {
   727  				return errors.New("state-stream-send-buffer-size must be greater than 0")
   728  			}
   729  			if len(builder.stateStreamFilterConf) > 3 {
   730  				return errors.New("state-stream-event-filter-limits must have at most 3 keys (EventTypes, Addresses, Contracts)")
   731  			}
   732  			for key, value := range builder.stateStreamFilterConf {
   733  				switch key {
   734  				case "EventTypes", "Addresses", "Contracts":
   735  					if value <= 0 {
   736  						return fmt.Errorf("state-stream-event-filter-limits %s must be greater than 0", key)
   737  					}
   738  				default:
   739  					return errors.New("state-stream-event-filter-limits may only contain the keys EventTypes, Addresses, Contracts")
   740  				}
   741  			}
   742  			if builder.stateStreamConf.ResponseLimit < 0 {
   743  				return errors.New("state-stream-response-limit must be greater than or equal to 0")
   744  			}
   745  			if builder.stateStreamConf.RegisterIDsRequestLimit <= 0 {
   746  				return errors.New("state-stream-max-register-values must be greater than 0")
   747  			}
   748  		}
   749  
   750  		return nil
   751  	})
   752  }
   753  
   754  func publicNetworkMsgValidators(log zerolog.Logger, idProvider module.IdentityProvider, selfID flow.Identifier) []network.MessageValidator {
   755  	return []network.MessageValidator{
   756  		// filter out messages sent by this node itself
   757  		validator.ValidateNotSender(selfID),
   758  		validator.NewAnyValidator(
   759  			// message should be either from a valid staked node
   760  			validator.NewOriginValidator(
   761  				id.NewIdentityFilterIdentifierProvider(filter.IsValidCurrentEpochParticipant, idProvider),
   762  			),
   763  			// or the message should be specifically targeted for this node
   764  			validator.ValidateTarget(log, selfID),
   765  		),
   766  	}
   767  }
   768  
   769  func (builder *ObserverServiceBuilder) initNodeInfo() error {
   770  	// use the networking key that was loaded from the configured file
   771  	networkingKey, err := loadNetworkingKey(builder.observerNetworkingKeyPath)
   772  	if err != nil {
   773  		return fmt.Errorf("could not load networking private key: %w", err)
   774  	}
   775  
   776  	pubKey, err := keyutils.LibP2PPublicKeyFromFlow(networkingKey.PublicKey())
   777  	if err != nil {
   778  		return fmt.Errorf("could not load networking public key: %w", err)
   779  	}
   780  
   781  	builder.peerID, err = peer.IDFromPublicKey(pubKey)
   782  	if err != nil {
   783  		return fmt.Errorf("could not get peer ID from public key: %w", err)
   784  	}
   785  
   786  	builder.NodeID, err = translator.NewPublicNetworkIDTranslator().GetFlowID(builder.peerID)
   787  	if err != nil {
   788  		return fmt.Errorf("could not get flow node ID: %w", err)
   789  	}
   790  
   791  	builder.NodeConfig.NetworkKey = networkingKey // copy the key to NodeConfig
   792  	builder.NodeConfig.StakingKey = nil           // no staking key for the observer
   793  
   794  	return nil
   795  }
   796  
   797  func (builder *ObserverServiceBuilder) InitIDProviders() {
   798  	builder.Module("id providers", func(node *cmd.NodeConfig) error {
   799  		idCache, err := cache.NewProtocolStateIDCache(node.Logger, node.State, builder.ProtocolEvents)
   800  		if err != nil {
   801  			return fmt.Errorf("could not initialize ProtocolStateIDCache: %w", err)
   802  		}
   803  		builder.IDTranslator = translator.NewHierarchicalIDTranslator(idCache, translator.NewPublicNetworkIDTranslator())
   804  
   805  		// The following wrapper allows to black-list byzantine nodes via an admin command:
   806  		// the wrapper overrides the 'Ejected' flag of disallow-listed nodes to true
   807  		builder.IdentityProvider, err = cache.NewNodeDisallowListWrapper(idCache, node.DB, func() network.DisallowListNotificationConsumer {
   808  			return builder.NetworkUnderlay
   809  		})
   810  		if err != nil {
   811  			return fmt.Errorf("could not initialize NodeBlockListWrapper: %w", err)
   812  		}
   813  
   814  		// use the default identifier provider
   815  		builder.SyncEngineParticipantsProviderFactory = func() module.IdentifierProvider {
   816  			return id.NewCustomIdentifierProvider(func() flow.IdentifierList {
   817  				pids := builder.LibP2PNode.GetPeersForProtocol(protocols.FlowProtocolID(builder.SporkID))
   818  				result := make(flow.IdentifierList, 0, len(pids))
   819  
   820  				for _, pid := range pids {
   821  					// exclude own Identifier
   822  					if pid == builder.peerID {
   823  						continue
   824  					}
   825  
   826  					if flowID, err := builder.IDTranslator.GetFlowID(pid); err != nil {
   827  						// TODO: this is an instance of "log error and continue with best effort" anti-pattern
   828  						builder.Logger.Err(err).Str("peer", p2plogging.PeerId(pid)).Msg("failed to translate to Flow ID")
   829  					} else {
   830  						result = append(result, flowID)
   831  					}
   832  				}
   833  
   834  				return result
   835  			})
   836  		}
   837  
   838  		return nil
   839  	})
   840  }
   841  
   842  func (builder *ObserverServiceBuilder) Initialize() error {
   843  	if err := builder.deriveBootstrapPeerIdentities(); err != nil {
   844  		return err
   845  	}
   846  
   847  	if err := builder.deriveUpstreamIdentities(); err != nil {
   848  		return err
   849  	}
   850  
   851  	if err := builder.validateParams(); err != nil {
   852  		return err
   853  	}
   854  
   855  	if err := builder.initNodeInfo(); err != nil {
   856  		return err
   857  	}
   858  
   859  	builder.InitIDProviders()
   860  
   861  	builder.enqueuePublicNetworkInit()
   862  
   863  	builder.enqueueConnectWithStakedAN()
   864  
   865  	if builder.executionDataSyncEnabled {
   866  		builder.BuildExecutionSyncComponents()
   867  	}
   868  
   869  	builder.enqueueRPCServer()
   870  
   871  	if builder.BaseConfig.MetricsEnabled {
   872  		builder.EnqueueMetricsServerInit()
   873  		if err := builder.RegisterBadgerMetrics(); err != nil {
   874  			return err
   875  		}
   876  	}
   877  
   878  	builder.PreInit(builder.initObserverLocal())
   879  
   880  	return nil
   881  }
   882  
   883  func (builder *ObserverServiceBuilder) validateParams() error {
   884  	if builder.BaseConfig.BindAddr == cmd.NotSet || builder.BaseConfig.BindAddr == "" {
   885  		return errors.New("bind address not specified")
   886  	}
   887  	if builder.ObserverServiceConfig.observerNetworkingKeyPath == cmd.NotSet {
   888  		return errors.New("networking key not provided")
   889  	}
   890  	if len(builder.bootstrapIdentities) > 0 {
   891  		return nil
   892  	}
   893  	if len(builder.bootstrapNodeAddresses) == 0 {
   894  		return errors.New("no bootstrap node address provided")
   895  	}
   896  	if len(builder.bootstrapNodeAddresses) != len(builder.bootstrapNodePublicKeys) {
   897  		return errors.New("number of bootstrap node addresses and public keys should match")
   898  	}
   899  	if len(builder.upstreamNodePublicKeys) > 0 && len(builder.upstreamNodeAddresses) != len(builder.upstreamNodePublicKeys) {
   900  		return errors.New("number of upstream node addresses and public keys must match if public keys given")
   901  	}
   902  	return nil
   903  }
   904  
   905  // initPublicLibp2pNode creates a libp2p node for the observer service in the public (unstaked) network.
   906  // The factory function is later passed into the initMiddleware function to eventually instantiate the p2p.LibP2PNode instance
   907  // The LibP2P host is created with the following options:
   908  // * DHT as client and seeded with the given bootstrap peers
   909  // * The specified bind address as the listen address
   910  // * The passed in private key as the libp2p key
   911  // * No connection gater
   912  // * No connection manager
   913  // * No peer manager
   914  // * Default libp2p pubsub options.
   915  // Args:
   916  // - networkKey: the private key to use for the libp2p node
   917  // Returns:
   918  // - p2p.LibP2PNode: the libp2p node
   919  // - error: if any error occurs. Any error returned is considered irrecoverable.
   920  func (builder *ObserverServiceBuilder) initPublicLibp2pNode(networkKey crypto.PrivateKey) (p2p.LibP2PNode, error) {
   921  	var pis []peer.AddrInfo
   922  
   923  	for _, b := range builder.bootstrapIdentities {
   924  		pi, err := utils.PeerAddressInfo(*b)
   925  		if err != nil {
   926  			return nil, fmt.Errorf("could not extract peer address info from bootstrap identity %v: %w", b, err)
   927  		}
   928  
   929  		pis = append(pis, pi)
   930  	}
   931  
   932  	node, err := p2pbuilder.NewNodeBuilder(
   933  		builder.Logger,
   934  		&builder.FlowConfig.NetworkConfig.GossipSub,
   935  		&p2pbuilderconfig.MetricsConfig{
   936  			HeroCacheFactory: builder.HeroCacheMetricsFactory(),
   937  			Metrics:          builder.Metrics.Network,
   938  		},
   939  		network.PublicNetwork,
   940  		builder.BaseConfig.BindAddr,
   941  		networkKey,
   942  		builder.SporkID,
   943  		builder.IdentityProvider,
   944  		&builder.FlowConfig.NetworkConfig.ResourceManager,
   945  		p2pbuilderconfig.PeerManagerDisableConfig(), // disable peer manager for observer node.
   946  		&p2p.DisallowListCacheConfig{
   947  			MaxSize: builder.FlowConfig.NetworkConfig.DisallowListNotificationCacheSize,
   948  			Metrics: metrics.DisallowListCacheMetricsFactory(builder.HeroCacheMetricsFactory(), network.PublicNetwork),
   949  		},
   950  		&p2pbuilderconfig.UnicastConfig{
   951  			Unicast: builder.FlowConfig.NetworkConfig.Unicast,
   952  		}).
   953  		SetSubscriptionFilter(
   954  			subscription.NewRoleBasedFilter(
   955  				subscription.UnstakedRole, builder.IdentityProvider,
   956  			),
   957  		).
   958  		SetRoutingSystem(func(ctx context.Context, h host.Host) (routing.Routing, error) {
   959  			return p2pdht.NewDHT(ctx, h, protocols.FlowPublicDHTProtocolID(builder.SporkID),
   960  				builder.Logger,
   961  				builder.Metrics.Network,
   962  				p2pdht.AsClient(),
   963  				dht.BootstrapPeers(pis...),
   964  			)
   965  		}).
   966  		Build()
   967  
   968  	if err != nil {
   969  		return nil, fmt.Errorf("could not initialize libp2p node for observer: %w", err)
   970  	}
   971  
   972  	builder.LibP2PNode = node
   973  
   974  	return builder.LibP2PNode, nil
   975  }
   976  
   977  // initObserverLocal initializes the observer's ID, network key and network address
   978  // Currently, it reads a node-info.priv.json like any other node.
   979  // TODO: read the node ID from the special bootstrap files
   980  func (builder *ObserverServiceBuilder) initObserverLocal() func(node *cmd.NodeConfig) error {
   981  	return func(node *cmd.NodeConfig) error {
   982  		// for an observer, set the identity here explicitly since it will not be found in the protocol state
   983  		self := &flow.Identity{
   984  			NodeID:        node.NodeID,
   985  			NetworkPubKey: node.NetworkKey.PublicKey(),
   986  			StakingPubKey: nil,             // no staking key needed for the observer
   987  			Role:          flow.RoleAccess, // observer can only run as an access node
   988  			Address:       builder.BindAddr,
   989  		}
   990  
   991  		var err error
   992  		node.Me, err = local.NewNoKey(self)
   993  		if err != nil {
   994  			return fmt.Errorf("could not initialize local: %w", err)
   995  		}
   996  		return nil
   997  	}
   998  }
   999  
  1000  // Build enqueues the sync engine and the follower engine for the observer.
  1001  // Currently, the observer only runs the follower engine.
  1002  func (builder *ObserverServiceBuilder) Build() (cmd.Node, error) {
  1003  	builder.BuildConsensusFollower()
  1004  	return builder.FlowNodeBuilder.Build()
  1005  }
  1006  
  1007  func (builder *ObserverServiceBuilder) BuildExecutionSyncComponents() *ObserverServiceBuilder {
  1008  	var ds *badger.Datastore
  1009  	var bs network.BlobService
  1010  	var processedBlockHeight storage.ConsumerProgress
  1011  	var processedNotifications storage.ConsumerProgress
  1012  	var publicBsDependable *module.ProxiedReadyDoneAware
  1013  	var execDataDistributor *edrequester.ExecutionDataDistributor
  1014  	var execDataCacheBackend *herocache.BlockExecutionData
  1015  	var executionDataStoreCache *execdatacache.ExecutionDataCache
  1016  
  1017  	// setup dependency chain to ensure indexer starts after the requester
  1018  	requesterDependable := module.NewProxiedReadyDoneAware()
  1019  	builder.IndexerDependencies.Add(requesterDependable)
  1020  
  1021  	builder.
  1022  		AdminCommand("read-execution-data", func(config *cmd.NodeConfig) commands.AdminCommand {
  1023  			return stateSyncCommands.NewReadExecutionDataCommand(builder.ExecutionDataStore)
  1024  		}).
  1025  		Module("execution data datastore and blobstore", func(node *cmd.NodeConfig) error {
  1026  			datastoreDir := filepath.Join(builder.executionDataDir, "blobstore")
  1027  			err := os.MkdirAll(datastoreDir, 0700)
  1028  			if err != nil {
  1029  				return err
  1030  			}
  1031  
  1032  			ds, err = badger.NewDatastore(datastoreDir, &badger.DefaultOptions)
  1033  			if err != nil {
  1034  				return err
  1035  			}
  1036  
  1037  			builder.ShutdownFunc(func() error {
  1038  				if err := ds.Close(); err != nil {
  1039  					return fmt.Errorf("could not close execution data datastore: %w", err)
  1040  				}
  1041  				return nil
  1042  			})
  1043  
  1044  			return nil
  1045  		}).
  1046  		Module("processed block height consumer progress", func(node *cmd.NodeConfig) error {
  1047  			// Note: progress is stored in the datastore's DB since that is where the jobqueue
  1048  			// writes execution data to.
  1049  			processedBlockHeight = bstorage.NewConsumerProgress(ds.DB, module.ConsumeProgressExecutionDataRequesterBlockHeight)
  1050  			return nil
  1051  		}).
  1052  		Module("processed notifications consumer progress", func(node *cmd.NodeConfig) error {
  1053  			// Note: progress is stored in the datastore's DB since that is where the jobqueue
  1054  			// writes execution data to.
  1055  			processedNotifications = bstorage.NewConsumerProgress(ds.DB, module.ConsumeProgressExecutionDataRequesterNotification)
  1056  			return nil
  1057  		}).
  1058  		Module("blobservice peer manager dependencies", func(node *cmd.NodeConfig) error {
  1059  			publicBsDependable = module.NewProxiedReadyDoneAware()
  1060  			builder.PeerManagerDependencies.Add(publicBsDependable)
  1061  			return nil
  1062  		}).
  1063  		Module("execution datastore", func(node *cmd.NodeConfig) error {
  1064  			blobstore := blobs.NewBlobstore(ds)
  1065  			builder.ExecutionDataStore = execution_data.NewExecutionDataStore(blobstore, execution_data.DefaultSerializer)
  1066  			return nil
  1067  		}).
  1068  		Module("execution data cache", func(node *cmd.NodeConfig) error {
  1069  			var heroCacheCollector module.HeroCacheMetrics = metrics.NewNoopCollector()
  1070  			if builder.HeroCacheMetricsEnable {
  1071  				heroCacheCollector = metrics.AccessNodeExecutionDataCacheMetrics(builder.MetricsRegisterer)
  1072  			}
  1073  
  1074  			execDataCacheBackend = herocache.NewBlockExecutionData(builder.stateStreamConf.ExecutionDataCacheSize, builder.Logger, heroCacheCollector)
  1075  
  1076  			// Execution Data cache that uses a blobstore as the backend (instead of a downloader)
  1077  			// This ensures that it simply returns a not found error if the blob doesn't exist
  1078  			// instead of attempting to download it from the network.
  1079  			executionDataStoreCache = execdatacache.NewExecutionDataCache(
  1080  				builder.ExecutionDataStore,
  1081  				builder.Storage.Headers,
  1082  				builder.Storage.Seals,
  1083  				builder.Storage.Results,
  1084  				execDataCacheBackend,
  1085  			)
  1086  
  1087  			return nil
  1088  		}).
  1089  		Component("public execution data service", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1090  			opts := []network.BlobServiceOption{
  1091  				blob.WithBitswapOptions(
  1092  					bitswap.WithTracer(
  1093  						blob.NewTracer(node.Logger.With().Str("public_blob_service", channels.PublicExecutionDataService.String()).Logger()),
  1094  					),
  1095  				),
  1096  			}
  1097  
  1098  			var err error
  1099  			bs, err = node.EngineRegistry.RegisterBlobService(channels.PublicExecutionDataService, ds, opts...)
  1100  			if err != nil {
  1101  				return nil, fmt.Errorf("could not register blob service: %w", err)
  1102  			}
  1103  
  1104  			// add blobservice into ReadyDoneAware dependency passed to peer manager
  1105  			// this starts the blob service and configures peer manager to wait for the blobservice
  1106  			// to be ready before starting
  1107  			publicBsDependable.Init(bs)
  1108  
  1109  			builder.ExecutionDataDownloader = execution_data.NewDownloader(bs)
  1110  
  1111  			return builder.ExecutionDataDownloader, nil
  1112  		}).
  1113  		Component("execution data requester", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1114  			// Validation of the start block height needs to be done after loading state
  1115  			if builder.executionDataStartHeight > 0 {
  1116  				if builder.executionDataStartHeight <= builder.FinalizedRootBlock.Header.Height {
  1117  					return nil, fmt.Errorf(
  1118  						"execution data start block height (%d) must be greater than the root block height (%d)",
  1119  						builder.executionDataStartHeight, builder.FinalizedRootBlock.Header.Height)
  1120  				}
  1121  
  1122  				latestSeal, err := builder.State.Sealed().Head()
  1123  				if err != nil {
  1124  					return nil, fmt.Errorf("failed to get latest sealed height")
  1125  				}
  1126  
  1127  				// Note: since the root block of a spork is also sealed in the root protocol state, the
  1128  				// latest sealed height is always equal to the root block height. That means that at the
  1129  				// very beginning of a spork, this check will always fail. Operators should not specify
  1130  				// an InitialBlockHeight when starting from the beginning of a spork.
  1131  				if builder.executionDataStartHeight > latestSeal.Height {
  1132  					return nil, fmt.Errorf(
  1133  						"execution data start block height (%d) must be less than or equal to the latest sealed block height (%d)",
  1134  						builder.executionDataStartHeight, latestSeal.Height)
  1135  				}
  1136  
  1137  				// executionDataStartHeight is provided as the first block to sync, but the
  1138  				// requester expects the initial last processed height, which is the first height - 1
  1139  				builder.executionDataConfig.InitialBlockHeight = builder.executionDataStartHeight - 1
  1140  			} else {
  1141  				builder.executionDataConfig.InitialBlockHeight = builder.FinalizedRootBlock.Header.Height
  1142  			}
  1143  
  1144  			execDataDistributor = edrequester.NewExecutionDataDistributor()
  1145  
  1146  			// Execution Data cache with a downloader as the backend. This is used by the requester
  1147  			// to download and cache execution data for each block. It shares a cache backend instance
  1148  			// with the datastore implementation.
  1149  			executionDataCache := execdatacache.NewExecutionDataCache(
  1150  				builder.ExecutionDataDownloader,
  1151  				builder.Storage.Headers,
  1152  				builder.Storage.Seals,
  1153  				builder.Storage.Results,
  1154  				execDataCacheBackend,
  1155  			)
  1156  
  1157  			r, err := edrequester.New(
  1158  				builder.Logger,
  1159  				metrics.NewExecutionDataRequesterCollector(),
  1160  				builder.ExecutionDataDownloader,
  1161  				executionDataCache,
  1162  				processedBlockHeight,
  1163  				processedNotifications,
  1164  				builder.State,
  1165  				builder.Storage.Headers,
  1166  				builder.executionDataConfig,
  1167  				execDataDistributor,
  1168  			)
  1169  			if err != nil {
  1170  				return nil, fmt.Errorf("failed to create execution data requester: %w", err)
  1171  			}
  1172  			builder.ExecutionDataRequester = r
  1173  
  1174  			builder.FollowerDistributor.AddOnBlockFinalizedConsumer(builder.ExecutionDataRequester.OnBlockFinalized)
  1175  
  1176  			// add requester into ReadyDoneAware dependency passed to indexer. This allows the indexer
  1177  			// to wait for the requester to be ready before starting.
  1178  			requesterDependable.Init(builder.ExecutionDataRequester)
  1179  
  1180  			return builder.ExecutionDataRequester, nil
  1181  		})
  1182  
  1183  	if builder.executionDataIndexingEnabled {
  1184  		var indexedBlockHeight storage.ConsumerProgress
  1185  
  1186  		builder.Module("indexed block height consumer progress", func(node *cmd.NodeConfig) error {
  1187  			// Note: progress is stored in the MAIN db since that is where indexed execution data is stored.
  1188  			indexedBlockHeight = bstorage.NewConsumerProgress(builder.DB, module.ConsumeProgressExecutionDataIndexerBlockHeight)
  1189  			return nil
  1190  		}).Module("transaction results storage", func(node *cmd.NodeConfig) error {
  1191  			builder.Storage.LightTransactionResults = bstorage.NewLightTransactionResults(node.Metrics.Cache, node.DB, bstorage.DefaultCacheSize)
  1192  			return nil
  1193  		}).DependableComponent("execution data indexer", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1194  			// Note: using a DependableComponent here to ensure that the indexer does not block
  1195  			// other components from starting while bootstrapping the register db since it may
  1196  			// take hours to complete.
  1197  
  1198  			pdb, err := pStorage.OpenRegisterPebbleDB(builder.registersDBPath)
  1199  			if err != nil {
  1200  				return nil, fmt.Errorf("could not open registers db: %w", err)
  1201  			}
  1202  			builder.ShutdownFunc(func() error {
  1203  				return pdb.Close()
  1204  			})
  1205  
  1206  			bootstrapped, err := pStorage.IsBootstrapped(pdb)
  1207  			if err != nil {
  1208  				return nil, fmt.Errorf("could not check if registers db is bootstrapped: %w", err)
  1209  			}
  1210  
  1211  			if !bootstrapped {
  1212  				checkpointFile := builder.checkpointFile
  1213  				if checkpointFile == cmd.NotSet {
  1214  					checkpointFile = path.Join(builder.BootstrapDir, bootstrap.PathRootCheckpoint)
  1215  				}
  1216  
  1217  				// currently, the checkpoint must be from the root block.
  1218  				// read the root hash from the provided checkpoint and verify it matches the
  1219  				// state commitment from the root snapshot.
  1220  				err := wal.CheckpointHasRootHash(
  1221  					node.Logger,
  1222  					"", // checkpoint file already full path
  1223  					checkpointFile,
  1224  					ledger.RootHash(node.RootSeal.FinalState),
  1225  				)
  1226  				if err != nil {
  1227  					return nil, fmt.Errorf("could not verify checkpoint file: %w", err)
  1228  				}
  1229  
  1230  				checkpointHeight := builder.SealedRootBlock.Header.Height
  1231  
  1232  				if builder.SealedRootBlock.ID() != builder.RootSeal.BlockID {
  1233  					return nil, fmt.Errorf("mismatching sealed root block and root seal: %v != %v",
  1234  						builder.SealedRootBlock.ID(), builder.RootSeal.BlockID)
  1235  				}
  1236  
  1237  				rootHash := ledger.RootHash(builder.RootSeal.FinalState)
  1238  				bootstrap, err := pStorage.NewRegisterBootstrap(pdb, checkpointFile, checkpointHeight, rootHash, builder.Logger)
  1239  				if err != nil {
  1240  					return nil, fmt.Errorf("could not create registers bootstrap: %w", err)
  1241  				}
  1242  
  1243  				// TODO: find a way to hook a context up to this to allow a graceful shutdown
  1244  				workerCount := 10
  1245  				err = bootstrap.IndexCheckpointFile(context.Background(), workerCount)
  1246  				if err != nil {
  1247  					return nil, fmt.Errorf("could not load checkpoint file: %w", err)
  1248  				}
  1249  			}
  1250  
  1251  			registers, err := pStorage.NewRegisters(pdb)
  1252  			if err != nil {
  1253  				return nil, fmt.Errorf("could not create registers storage: %w", err)
  1254  			}
  1255  
  1256  			builder.Storage.RegisterIndex = registers
  1257  
  1258  			var collectionExecutedMetric module.CollectionExecutedMetric = metrics.NewNoopCollector()
  1259  			indexerCore, err := indexer.New(
  1260  				builder.Logger,
  1261  				metrics.NewExecutionStateIndexerCollector(),
  1262  				builder.DB,
  1263  				builder.Storage.RegisterIndex,
  1264  				builder.Storage.Headers,
  1265  				builder.Storage.Events,
  1266  				builder.Storage.Collections,
  1267  				builder.Storage.Transactions,
  1268  				builder.Storage.LightTransactionResults,
  1269  				collectionExecutedMetric,
  1270  			)
  1271  			if err != nil {
  1272  				return nil, err
  1273  			}
  1274  			builder.ExecutionIndexerCore = indexerCore
  1275  
  1276  			// execution state worker uses a jobqueue to process new execution data and indexes it by using the indexer.
  1277  			builder.ExecutionIndexer, err = indexer.NewIndexer(
  1278  				builder.Logger,
  1279  				registers.FirstHeight(),
  1280  				registers,
  1281  				indexerCore,
  1282  				executionDataStoreCache,
  1283  				builder.ExecutionDataRequester.HighestConsecutiveHeight,
  1284  				indexedBlockHeight,
  1285  			)
  1286  			if err != nil {
  1287  				return nil, err
  1288  			}
  1289  
  1290  			// setup requester to notify indexer when new execution data is received
  1291  			execDataDistributor.AddOnExecutionDataReceivedConsumer(builder.ExecutionIndexer.OnExecutionData)
  1292  
  1293  			err = builder.EventsIndex.Initialize(builder.ExecutionIndexer)
  1294  			if err != nil {
  1295  				return nil, err
  1296  			}
  1297  
  1298  			err = builder.RegistersAsyncStore.Initialize(registers)
  1299  			if err != nil {
  1300  				return nil, err
  1301  			}
  1302  
  1303  			return builder.ExecutionIndexer, nil
  1304  		}, builder.IndexerDependencies)
  1305  	}
  1306  
  1307  	if builder.stateStreamConf.ListenAddr != "" {
  1308  		builder.Component("exec state stream engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1309  			for key, value := range builder.stateStreamFilterConf {
  1310  				switch key {
  1311  				case "EventTypes":
  1312  					builder.stateStreamConf.MaxEventTypes = value
  1313  				case "Addresses":
  1314  					builder.stateStreamConf.MaxAddresses = value
  1315  				case "Contracts":
  1316  					builder.stateStreamConf.MaxContracts = value
  1317  				}
  1318  			}
  1319  			builder.stateStreamConf.RpcMetricsEnabled = builder.rpcMetricsEnabled
  1320  
  1321  			highestAvailableHeight, err := builder.ExecutionDataRequester.HighestConsecutiveHeight()
  1322  			if err != nil {
  1323  				return nil, fmt.Errorf("could not get highest consecutive height: %w", err)
  1324  			}
  1325  			broadcaster := engine.NewBroadcaster()
  1326  
  1327  			eventQueryMode, err := backend.ParseIndexQueryMode(builder.rpcConf.BackendConfig.EventQueryMode)
  1328  			if err != nil {
  1329  				return nil, fmt.Errorf("could not parse event query mode: %w", err)
  1330  			}
  1331  
  1332  			// use the events index for events if enabled and the node is configured to use it for
  1333  			// regular event queries
  1334  			useIndex := builder.executionDataIndexingEnabled &&
  1335  				eventQueryMode != backend.IndexQueryModeExecutionNodesOnly
  1336  
  1337  			builder.stateStreamBackend, err = statestreambackend.New(
  1338  				node.Logger,
  1339  				builder.stateStreamConf,
  1340  				node.State,
  1341  				node.Storage.Headers,
  1342  				node.Storage.Seals,
  1343  				node.Storage.Results,
  1344  				builder.ExecutionDataStore,
  1345  				executionDataStoreCache,
  1346  				broadcaster,
  1347  				builder.executionDataConfig.InitialBlockHeight,
  1348  				highestAvailableHeight,
  1349  				builder.RegistersAsyncStore,
  1350  				builder.EventsIndex,
  1351  				useIndex,
  1352  			)
  1353  			if err != nil {
  1354  				return nil, fmt.Errorf("could not create state stream backend: %w", err)
  1355  			}
  1356  
  1357  			stateStreamEng, err := statestreambackend.NewEng(
  1358  				node.Logger,
  1359  				builder.stateStreamConf,
  1360  				executionDataStoreCache,
  1361  				node.Storage.Headers,
  1362  				node.RootChainID,
  1363  				builder.stateStreamGrpcServer,
  1364  				builder.stateStreamBackend,
  1365  				broadcaster,
  1366  			)
  1367  			if err != nil {
  1368  				return nil, fmt.Errorf("could not create state stream engine: %w", err)
  1369  			}
  1370  			builder.StateStreamEng = stateStreamEng
  1371  
  1372  			execDataDistributor.AddOnExecutionDataReceivedConsumer(builder.StateStreamEng.OnExecutionData)
  1373  
  1374  			return builder.StateStreamEng, nil
  1375  		})
  1376  	}
  1377  	return builder
  1378  }
  1379  
  1380  // enqueuePublicNetworkInit enqueues the observer network component initialized for the observer
  1381  func (builder *ObserverServiceBuilder) enqueuePublicNetworkInit() {
  1382  	var publicLibp2pNode p2p.LibP2PNode
  1383  	builder.
  1384  		Component("public libp2p node", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1385  			var err error
  1386  			publicLibp2pNode, err = builder.initPublicLibp2pNode(node.NetworkKey)
  1387  			if err != nil {
  1388  				return nil, fmt.Errorf("could not create public libp2p node: %w", err)
  1389  			}
  1390  
  1391  			return publicLibp2pNode, nil
  1392  		}).
  1393  		Component("public network", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1394  			receiveCache := netcache.NewHeroReceiveCache(builder.FlowConfig.NetworkConfig.NetworkReceivedMessageCacheSize,
  1395  				builder.Logger,
  1396  				metrics.NetworkReceiveCacheMetricsFactory(builder.HeroCacheMetricsFactory(), network.PublicNetwork))
  1397  
  1398  			err := node.Metrics.Mempool.Register(metrics.PrependPublicPrefix(metrics.ResourceNetworkingReceiveCache), receiveCache.Size)
  1399  			if err != nil {
  1400  				return nil, fmt.Errorf("could not register networking receive cache metric: %w", err)
  1401  			}
  1402  
  1403  			net, err := underlay.NewNetwork(&underlay.NetworkConfig{
  1404  				Logger:                builder.Logger.With().Str("component", "public-network").Logger(),
  1405  				Codec:                 builder.CodecFactory(),
  1406  				Me:                    builder.Me,
  1407  				Topology:              nil, // topology is nil since it is managed by libp2p; //TODO: can we set empty topology?
  1408  				Libp2pNode:            publicLibp2pNode,
  1409  				Metrics:               builder.Metrics.Network,
  1410  				BitSwapMetrics:        builder.Metrics.Bitswap,
  1411  				IdentityProvider:      builder.IdentityProvider,
  1412  				ReceiveCache:          receiveCache,
  1413  				ConduitFactory:        conduit.NewDefaultConduitFactory(),
  1414  				SporkId:               builder.SporkID,
  1415  				UnicastMessageTimeout: underlay.DefaultUnicastTimeout,
  1416  				IdentityTranslator:    builder.IDTranslator,
  1417  				AlspCfg: &alspmgr.MisbehaviorReportManagerConfig{
  1418  					Logger:                  builder.Logger,
  1419  					SpamRecordCacheSize:     builder.FlowConfig.NetworkConfig.AlspConfig.SpamRecordCacheSize,
  1420  					SpamReportQueueSize:     builder.FlowConfig.NetworkConfig.AlspConfig.SpamReportQueueSize,
  1421  					DisablePenalty:          builder.FlowConfig.NetworkConfig.AlspConfig.DisablePenalty,
  1422  					HeartBeatInterval:       builder.FlowConfig.NetworkConfig.AlspConfig.HearBeatInterval,
  1423  					AlspMetrics:             builder.Metrics.Network,
  1424  					HeroCacheMetricsFactory: builder.HeroCacheMetricsFactory(),
  1425  					NetworkType:             network.PublicNetwork,
  1426  				},
  1427  				SlashingViolationConsumerFactory: func(adapter network.ConduitAdapter) network.ViolationsConsumer {
  1428  					return slashing.NewSlashingViolationsConsumer(builder.Logger, builder.Metrics.Network, adapter)
  1429  				},
  1430  			}, underlay.WithMessageValidators(publicNetworkMsgValidators(node.Logger, node.IdentityProvider, node.NodeID)...))
  1431  			if err != nil {
  1432  				return nil, fmt.Errorf("could not initialize network: %w", err)
  1433  			}
  1434  
  1435  			builder.NetworkUnderlay = net
  1436  			builder.EngineRegistry = converter.NewNetwork(net, channels.SyncCommittee, channels.PublicSyncCommittee)
  1437  
  1438  			builder.Logger.Info().Msgf("network will run on address: %s", builder.BindAddr)
  1439  
  1440  			idEvents := gadgets.NewIdentityDeltas(builder.NetworkUnderlay.UpdateNodeAddresses)
  1441  			builder.ProtocolEvents.AddConsumer(idEvents)
  1442  
  1443  			return builder.EngineRegistry, nil
  1444  		})
  1445  }
  1446  
  1447  // enqueueConnectWithStakedAN enqueues the upstream connector component which connects the libp2p host of the observer
  1448  // service with the AN.
  1449  // Currently, there is an issue with LibP2P stopping advertisements of subscribed topics if no peers are connected
  1450  // (https://github.com/libp2p/go-libp2p-pubsub/issues/442). This means that an observer could end up not being
  1451  // discovered by other observers if it subscribes to a topic before connecting to the AN. Hence, the need
  1452  // of an explicit connect to the AN before the node attempts to subscribe to topics.
  1453  func (builder *ObserverServiceBuilder) enqueueConnectWithStakedAN() {
  1454  	builder.Component("upstream connector", func(_ *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1455  		return consensus_follower.NewUpstreamConnector(builder.bootstrapIdentities, builder.LibP2PNode, builder.Logger), nil
  1456  	})
  1457  }
  1458  
  1459  func (builder *ObserverServiceBuilder) enqueueRPCServer() {
  1460  	builder.Module("rest metrics", func(node *cmd.NodeConfig) error {
  1461  		m, err := metrics.NewRestCollector(routes.URLToRoute, node.MetricsRegisterer)
  1462  		if err != nil {
  1463  			return err
  1464  		}
  1465  		builder.RestMetrics = m
  1466  		return nil
  1467  	})
  1468  	builder.Module("access metrics", func(node *cmd.NodeConfig) error {
  1469  		builder.AccessMetrics = metrics.NewAccessCollector(
  1470  			metrics.WithRestMetrics(builder.RestMetrics),
  1471  		)
  1472  		return nil
  1473  	})
  1474  	builder.Module("server certificate", func(node *cmd.NodeConfig) error {
  1475  		// generate the server certificate that will be served by the GRPC server
  1476  		x509Certificate, err := grpcutils.X509Certificate(node.NetworkKey)
  1477  		if err != nil {
  1478  			return err
  1479  		}
  1480  		tlsConfig := grpcutils.DefaultServerTLSConfig(x509Certificate)
  1481  		builder.rpcConf.TransportCredentials = credentials.NewTLS(tlsConfig)
  1482  		return nil
  1483  	})
  1484  	builder.Module("creating grpc servers", func(node *cmd.NodeConfig) error {
  1485  		builder.secureGrpcServer = grpcserver.NewGrpcServerBuilder(node.Logger,
  1486  			builder.rpcConf.SecureGRPCListenAddr,
  1487  			builder.rpcConf.MaxMsgSize,
  1488  			builder.rpcMetricsEnabled,
  1489  			builder.apiRatelimits,
  1490  			builder.apiBurstlimits,
  1491  			grpcserver.WithTransportCredentials(builder.rpcConf.TransportCredentials)).Build()
  1492  
  1493  		builder.stateStreamGrpcServer = grpcserver.NewGrpcServerBuilder(
  1494  			node.Logger,
  1495  			builder.stateStreamConf.ListenAddr,
  1496  			builder.stateStreamConf.MaxExecutionDataMsgSize,
  1497  			builder.rpcMetricsEnabled,
  1498  			builder.apiRatelimits,
  1499  			builder.apiBurstlimits,
  1500  			grpcserver.WithStreamInterceptor()).Build()
  1501  
  1502  		if builder.rpcConf.UnsecureGRPCListenAddr != builder.stateStreamConf.ListenAddr {
  1503  			builder.unsecureGrpcServer = grpcserver.NewGrpcServerBuilder(node.Logger,
  1504  				builder.rpcConf.UnsecureGRPCListenAddr,
  1505  				builder.rpcConf.MaxMsgSize,
  1506  				builder.rpcMetricsEnabled,
  1507  				builder.apiRatelimits,
  1508  				builder.apiBurstlimits).Build()
  1509  		} else {
  1510  			builder.unsecureGrpcServer = builder.stateStreamGrpcServer
  1511  		}
  1512  
  1513  		return nil
  1514  	})
  1515  	builder.Module("async register store", func(node *cmd.NodeConfig) error {
  1516  		builder.RegistersAsyncStore = execution.NewRegistersAsyncStore()
  1517  		return nil
  1518  	})
  1519  	builder.Module("events storage", func(node *cmd.NodeConfig) error {
  1520  		builder.Storage.Events = bstorage.NewEvents(node.Metrics.Cache, node.DB)
  1521  		return nil
  1522  	})
  1523  	builder.Module("events index", func(node *cmd.NodeConfig) error {
  1524  		builder.EventsIndex = backend.NewEventsIndex(builder.Storage.Events)
  1525  		return nil
  1526  	})
  1527  	builder.Component("RPC engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1528  		accessMetrics := builder.AccessMetrics
  1529  		config := builder.rpcConf
  1530  		backendConfig := config.BackendConfig
  1531  		cacheSize := int(backendConfig.ConnectionPoolSize)
  1532  
  1533  		var connBackendCache *rpcConnection.Cache
  1534  		var err error
  1535  		if cacheSize > 0 {
  1536  			connBackendCache, err = rpcConnection.NewCache(node.Logger, accessMetrics, cacheSize)
  1537  			if err != nil {
  1538  				return nil, fmt.Errorf("could not initialize connection cache: %w", err)
  1539  			}
  1540  		}
  1541  
  1542  		connFactory := &rpcConnection.ConnectionFactoryImpl{
  1543  			CollectionGRPCPort:        0,
  1544  			ExecutionGRPCPort:         0,
  1545  			CollectionNodeGRPCTimeout: builder.apiTimeout,
  1546  			ExecutionNodeGRPCTimeout:  builder.apiTimeout,
  1547  			AccessMetrics:             accessMetrics,
  1548  			Log:                       node.Logger,
  1549  			Manager: rpcConnection.NewManager(
  1550  				node.Logger,
  1551  				accessMetrics,
  1552  				connBackendCache,
  1553  				config.MaxMsgSize,
  1554  				backendConfig.CircuitBreakerConfig,
  1555  				config.CompressorName,
  1556  			),
  1557  		}
  1558  
  1559  		accessBackend, err := backend.New(backend.Params{
  1560  			State:                     node.State,
  1561  			Blocks:                    node.Storage.Blocks,
  1562  			Headers:                   node.Storage.Headers,
  1563  			Collections:               node.Storage.Collections,
  1564  			Transactions:              node.Storage.Transactions,
  1565  			ExecutionReceipts:         node.Storage.Receipts,
  1566  			ExecutionResults:          node.Storage.Results,
  1567  			ChainID:                   node.RootChainID,
  1568  			AccessMetrics:             accessMetrics,
  1569  			ConnFactory:               connFactory,
  1570  			RetryEnabled:              false,
  1571  			MaxHeightRange:            backendConfig.MaxHeightRange,
  1572  			PreferredExecutionNodeIDs: backendConfig.PreferredExecutionNodeIDs,
  1573  			FixedExecutionNodeIDs:     backendConfig.FixedExecutionNodeIDs,
  1574  			Log:                       node.Logger,
  1575  			SnapshotHistoryLimit:      backend.DefaultSnapshotHistoryLimit,
  1576  			Communicator:              backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled),
  1577  		})
  1578  		if err != nil {
  1579  			return nil, fmt.Errorf("could not initialize backend: %w", err)
  1580  		}
  1581  
  1582  		observerCollector := metrics.NewObserverCollector()
  1583  		restHandler, err := restapiproxy.NewRestProxyHandler(
  1584  			accessBackend,
  1585  			builder.upstreamIdentities,
  1586  			connFactory,
  1587  			builder.Logger,
  1588  			observerCollector,
  1589  			node.RootChainID.Chain())
  1590  		if err != nil {
  1591  			return nil, err
  1592  		}
  1593  
  1594  		engineBuilder, err := rpc.NewBuilder(
  1595  			node.Logger,
  1596  			node.State,
  1597  			config,
  1598  			node.RootChainID,
  1599  			accessMetrics,
  1600  			builder.rpcMetricsEnabled,
  1601  			builder.Me,
  1602  			accessBackend,
  1603  			restHandler,
  1604  			builder.secureGrpcServer,
  1605  			builder.unsecureGrpcServer,
  1606  			builder.stateStreamBackend,
  1607  			builder.stateStreamConf,
  1608  		)
  1609  		if err != nil {
  1610  			return nil, err
  1611  		}
  1612  
  1613  		// upstream access node forwarder
  1614  		forwarder, err := apiproxy.NewFlowAccessAPIForwarder(builder.upstreamIdentities, connFactory)
  1615  		if err != nil {
  1616  			return nil, err
  1617  		}
  1618  
  1619  		rpcHandler := &apiproxy.FlowAccessAPIRouter{
  1620  			Logger:   builder.Logger,
  1621  			Metrics:  observerCollector,
  1622  			Upstream: forwarder,
  1623  			Observer: protocol.NewHandler(protocol.New(
  1624  				node.State,
  1625  				node.Storage.Blocks,
  1626  				node.Storage.Headers,
  1627  				backend.NewNetworkAPI(
  1628  					node.State,
  1629  					node.RootChainID,
  1630  					node.Storage.Headers,
  1631  					backend.DefaultSnapshotHistoryLimit,
  1632  				),
  1633  			)),
  1634  		}
  1635  
  1636  		// build the rpc engine
  1637  		builder.RpcEng, err = engineBuilder.
  1638  			WithRpcHandler(rpcHandler).
  1639  			WithLegacy().
  1640  			Build()
  1641  		if err != nil {
  1642  			return nil, err
  1643  		}
  1644  		builder.FollowerDistributor.AddOnBlockFinalizedConsumer(builder.RpcEng.OnFinalizedBlock)
  1645  		return builder.RpcEng, nil
  1646  	})
  1647  
  1648  	// build secure grpc server
  1649  	builder.Component("secure grpc server", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1650  		return builder.secureGrpcServer, nil
  1651  	})
  1652  
  1653  	builder.Component("state stream unsecure grpc server", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1654  		return builder.stateStreamGrpcServer, nil
  1655  	})
  1656  
  1657  	if builder.rpcConf.UnsecureGRPCListenAddr != builder.stateStreamConf.ListenAddr {
  1658  		builder.Component("unsecure grpc server", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1659  			return builder.unsecureGrpcServer, nil
  1660  		})
  1661  	}
  1662  }
  1663  
  1664  func loadNetworkingKey(path string) (crypto.PrivateKey, error) {
  1665  	data, err := io.ReadFile(path)
  1666  	if err != nil {
  1667  		return nil, fmt.Errorf("could not read networking key (path=%s): %w", path, err)
  1668  	}
  1669  
  1670  	keyBytes, err := hex.DecodeString(strings.Trim(string(data), "\n "))
  1671  	if err != nil {
  1672  		return nil, fmt.Errorf("could not hex decode networking key (path=%s): %w", path, err)
  1673  	}
  1674  
  1675  	networkingKey, err := crypto.DecodePrivateKey(crypto.ECDSASecp256k1, keyBytes)
  1676  	if err != nil {
  1677  		return nil, fmt.Errorf("could not decode networking key (path=%s): %w", path, err)
  1678  	}
  1679  
  1680  	return networkingKey, nil
  1681  }