github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/cmd/access/node_builder/access_node_builder.go (about)

     1  package node_builder
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"math"
     8  	"os"
     9  	"path"
    10  	"path/filepath"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/ipfs/boxo/bitswap"
    15  	badger "github.com/ipfs/go-ds-badger2"
    16  	"github.com/libp2p/go-libp2p/core/host"
    17  	"github.com/libp2p/go-libp2p/core/routing"
    18  	"github.com/onflow/crypto"
    19  	"github.com/onflow/flow/protobuf/go/flow/access"
    20  	"github.com/rs/zerolog"
    21  	"github.com/spf13/pflag"
    22  	"google.golang.org/grpc"
    23  	"google.golang.org/grpc/credentials"
    24  	"google.golang.org/grpc/credentials/insecure"
    25  
    26  	"github.com/onflow/flow-go/admin/commands"
    27  	stateSyncCommands "github.com/onflow/flow-go/admin/commands/state_synchronization"
    28  	storageCommands "github.com/onflow/flow-go/admin/commands/storage"
    29  	"github.com/onflow/flow-go/cmd"
    30  	"github.com/onflow/flow-go/consensus"
    31  	"github.com/onflow/flow-go/consensus/hotstuff"
    32  	"github.com/onflow/flow-go/consensus/hotstuff/committees"
    33  	"github.com/onflow/flow-go/consensus/hotstuff/notifications"
    34  	consensuspubsub "github.com/onflow/flow-go/consensus/hotstuff/notifications/pubsub"
    35  	"github.com/onflow/flow-go/consensus/hotstuff/signature"
    36  	hotstuffvalidator "github.com/onflow/flow-go/consensus/hotstuff/validator"
    37  	"github.com/onflow/flow-go/consensus/hotstuff/verification"
    38  	recovery "github.com/onflow/flow-go/consensus/recovery/protocol"
    39  	"github.com/onflow/flow-go/engine"
    40  	"github.com/onflow/flow-go/engine/access/index"
    41  	"github.com/onflow/flow-go/engine/access/ingestion"
    42  	pingeng "github.com/onflow/flow-go/engine/access/ping"
    43  	"github.com/onflow/flow-go/engine/access/rest"
    44  	"github.com/onflow/flow-go/engine/access/rest/routes"
    45  	"github.com/onflow/flow-go/engine/access/rpc"
    46  	"github.com/onflow/flow-go/engine/access/rpc/backend"
    47  	rpcConnection "github.com/onflow/flow-go/engine/access/rpc/connection"
    48  	"github.com/onflow/flow-go/engine/access/state_stream"
    49  	statestreambackend "github.com/onflow/flow-go/engine/access/state_stream/backend"
    50  	"github.com/onflow/flow-go/engine/access/subscription"
    51  	followereng "github.com/onflow/flow-go/engine/common/follower"
    52  	"github.com/onflow/flow-go/engine/common/requester"
    53  	synceng "github.com/onflow/flow-go/engine/common/synchronization"
    54  	"github.com/onflow/flow-go/engine/execution/computation/query"
    55  	"github.com/onflow/flow-go/fvm/storage/derived"
    56  	"github.com/onflow/flow-go/ledger"
    57  	"github.com/onflow/flow-go/ledger/complete/wal"
    58  	"github.com/onflow/flow-go/model/bootstrap"
    59  	"github.com/onflow/flow-go/model/flow"
    60  	"github.com/onflow/flow-go/model/flow/filter"
    61  	"github.com/onflow/flow-go/module"
    62  	"github.com/onflow/flow-go/module/blobs"
    63  	"github.com/onflow/flow-go/module/chainsync"
    64  	"github.com/onflow/flow-go/module/counters"
    65  	"github.com/onflow/flow-go/module/execution"
    66  	"github.com/onflow/flow-go/module/executiondatasync/execution_data"
    67  	execdatacache "github.com/onflow/flow-go/module/executiondatasync/execution_data/cache"
    68  	finalizer "github.com/onflow/flow-go/module/finalizer/consensus"
    69  	"github.com/onflow/flow-go/module/grpcserver"
    70  	"github.com/onflow/flow-go/module/id"
    71  	"github.com/onflow/flow-go/module/mempool/herocache"
    72  	"github.com/onflow/flow-go/module/mempool/stdmap"
    73  	"github.com/onflow/flow-go/module/metrics"
    74  	"github.com/onflow/flow-go/module/metrics/unstaked"
    75  	"github.com/onflow/flow-go/module/state_synchronization"
    76  	"github.com/onflow/flow-go/module/state_synchronization/indexer"
    77  	edrequester "github.com/onflow/flow-go/module/state_synchronization/requester"
    78  	"github.com/onflow/flow-go/network"
    79  	alspmgr "github.com/onflow/flow-go/network/alsp/manager"
    80  	netcache "github.com/onflow/flow-go/network/cache"
    81  	"github.com/onflow/flow-go/network/channels"
    82  	cborcodec "github.com/onflow/flow-go/network/codec/cbor"
    83  	"github.com/onflow/flow-go/network/p2p"
    84  	"github.com/onflow/flow-go/network/p2p/blob"
    85  	p2pbuilder "github.com/onflow/flow-go/network/p2p/builder"
    86  	p2pbuilderconfig "github.com/onflow/flow-go/network/p2p/builder/config"
    87  	"github.com/onflow/flow-go/network/p2p/cache"
    88  	"github.com/onflow/flow-go/network/p2p/conduit"
    89  	"github.com/onflow/flow-go/network/p2p/connection"
    90  	"github.com/onflow/flow-go/network/p2p/dht"
    91  	networkingsubscription "github.com/onflow/flow-go/network/p2p/subscription"
    92  	"github.com/onflow/flow-go/network/p2p/translator"
    93  	"github.com/onflow/flow-go/network/p2p/unicast/protocols"
    94  	relaynet "github.com/onflow/flow-go/network/relay"
    95  	"github.com/onflow/flow-go/network/slashing"
    96  	"github.com/onflow/flow-go/network/topology"
    97  	"github.com/onflow/flow-go/network/underlay"
    98  	"github.com/onflow/flow-go/network/validator"
    99  	"github.com/onflow/flow-go/state/protocol"
   100  	badgerState "github.com/onflow/flow-go/state/protocol/badger"
   101  	"github.com/onflow/flow-go/state/protocol/blocktimer"
   102  	"github.com/onflow/flow-go/storage"
   103  	bstorage "github.com/onflow/flow-go/storage/badger"
   104  	pStorage "github.com/onflow/flow-go/storage/pebble"
   105  	"github.com/onflow/flow-go/utils/grpcutils"
   106  )
   107  
   108  // AccessNodeBuilder extends cmd.NodeBuilder and declares additional functions needed to bootstrap an Access node.
   109  // The private network allows the staked 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 |<----------------------->| Staked Access Node |<--------------->| All other staked Nodes |
   118  //  +------------------------+                         +--------------------+                 +------------------------+
   119  //  +------------------------+                           ^
   120  //  | Observer             3 |<--------------------------|
   121  //  +------------------------+
   122  
   123  // AccessNodeConfig 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 AccessNodeConfig struct {
   127  	supportsObserver                  bool // True if this is an Access node that supports observers and consensus follower engines
   128  	collectionGRPCPort                uint
   129  	executionGRPCPort                 uint
   130  	pingEnabled                       bool
   131  	nodeInfoFile                      string
   132  	apiRatelimits                     map[string]int
   133  	apiBurstlimits                    map[string]int
   134  	rpcConf                           rpc.Config
   135  	stateStreamConf                   statestreambackend.Config
   136  	stateStreamFilterConf             map[string]int
   137  	ExecutionNodeAddress              string // deprecated
   138  	HistoricalAccessRPCs              []access.AccessAPIClient
   139  	logTxTimeToFinalized              bool
   140  	logTxTimeToExecuted               bool
   141  	logTxTimeToFinalizedExecuted      bool
   142  	retryEnabled                      bool
   143  	rpcMetricsEnabled                 bool
   144  	executionDataSyncEnabled          bool
   145  	publicNetworkExecutionDataEnabled bool
   146  	executionDataDir                  string
   147  	executionDataStartHeight          uint64
   148  	executionDataConfig               edrequester.ExecutionDataConfig
   149  	PublicNetworkConfig               PublicNetworkConfig
   150  	TxResultCacheSize                 uint
   151  	TxErrorMessagesCacheSize          uint
   152  	executionDataIndexingEnabled      bool
   153  	registersDBPath                   string
   154  	checkpointFile                    string
   155  	scriptExecutorConfig              query.QueryConfig
   156  	scriptExecMinBlock                uint64
   157  	scriptExecMaxBlock                uint64
   158  	registerCacheType                 string
   159  	registerCacheSize                 uint
   160  	programCacheSize                  uint
   161  }
   162  
   163  type PublicNetworkConfig struct {
   164  	// NetworkKey crypto.PublicKey // TODO: do we need a different key for the public network?
   165  	BindAddress string
   166  	Network     network.EngineRegistry
   167  	Metrics     module.NetworkMetrics
   168  }
   169  
   170  // DefaultAccessNodeConfig defines all the default values for the AccessNodeConfig
   171  func DefaultAccessNodeConfig() *AccessNodeConfig {
   172  	homedir, _ := os.UserHomeDir()
   173  	return &AccessNodeConfig{
   174  		supportsObserver:   false,
   175  		collectionGRPCPort: 9000,
   176  		executionGRPCPort:  9000,
   177  		rpcConf: rpc.Config{
   178  			UnsecureGRPCListenAddr: "0.0.0.0:9000",
   179  			SecureGRPCListenAddr:   "0.0.0.0:9001",
   180  			HTTPListenAddr:         "0.0.0.0:8000",
   181  			CollectionAddr:         "",
   182  			HistoricalAccessAddrs:  "",
   183  			BackendConfig: backend.Config{
   184  				CollectionClientTimeout:   3 * time.Second,
   185  				ExecutionClientTimeout:    3 * time.Second,
   186  				ConnectionPoolSize:        backend.DefaultConnectionPoolSize,
   187  				MaxHeightRange:            backend.DefaultMaxHeightRange,
   188  				PreferredExecutionNodeIDs: nil,
   189  				FixedExecutionNodeIDs:     nil,
   190  				CircuitBreakerConfig: rpcConnection.CircuitBreakerConfig{
   191  					Enabled:        false,
   192  					RestoreTimeout: 60 * time.Second,
   193  					MaxFailures:    5,
   194  					MaxRequests:    1,
   195  				},
   196  				ScriptExecutionMode: backend.IndexQueryModeExecutionNodesOnly.String(), // default to ENs only for now
   197  				EventQueryMode:      backend.IndexQueryModeExecutionNodesOnly.String(), // default to ENs only for now
   198  				TxResultQueryMode:   backend.IndexQueryModeExecutionNodesOnly.String(), // default to ENs only for now
   199  			},
   200  			RestConfig: rest.Config{
   201  				ListenAddress: "",
   202  				WriteTimeout:  rest.DefaultWriteTimeout,
   203  				ReadTimeout:   rest.DefaultReadTimeout,
   204  				IdleTimeout:   rest.DefaultIdleTimeout,
   205  			},
   206  			MaxMsgSize:     grpcutils.DefaultMaxMsgSize,
   207  			CompressorName: grpcutils.NoCompressor,
   208  		},
   209  		stateStreamConf: statestreambackend.Config{
   210  			MaxExecutionDataMsgSize: grpcutils.DefaultMaxMsgSize,
   211  			ExecutionDataCacheSize:  subscription.DefaultCacheSize,
   212  			ClientSendTimeout:       subscription.DefaultSendTimeout,
   213  			ClientSendBufferSize:    subscription.DefaultSendBufferSize,
   214  			MaxGlobalStreams:        subscription.DefaultMaxGlobalStreams,
   215  			EventFilterConfig:       state_stream.DefaultEventFilterConfig,
   216  			RegisterIDsRequestLimit: state_stream.DefaultRegisterIDsRequestLimit,
   217  			ResponseLimit:           subscription.DefaultResponseLimit,
   218  			HeartbeatInterval:       subscription.DefaultHeartbeatInterval,
   219  		},
   220  		stateStreamFilterConf:        nil,
   221  		ExecutionNodeAddress:         "localhost:9000",
   222  		logTxTimeToFinalized:         false,
   223  		logTxTimeToExecuted:          false,
   224  		logTxTimeToFinalizedExecuted: false,
   225  		pingEnabled:                  false,
   226  		retryEnabled:                 false,
   227  		rpcMetricsEnabled:            false,
   228  		nodeInfoFile:                 "",
   229  		apiRatelimits:                nil,
   230  		apiBurstlimits:               nil,
   231  		TxResultCacheSize:            0,
   232  		TxErrorMessagesCacheSize:     1000,
   233  		PublicNetworkConfig: PublicNetworkConfig{
   234  			BindAddress: cmd.NotSet,
   235  			Metrics:     metrics.NewNoopCollector(),
   236  		},
   237  		executionDataSyncEnabled:          true,
   238  		publicNetworkExecutionDataEnabled: false,
   239  		executionDataDir:                  filepath.Join(homedir, ".flow", "execution_data"),
   240  		executionDataStartHeight:          0,
   241  		executionDataConfig: edrequester.ExecutionDataConfig{
   242  			InitialBlockHeight: 0,
   243  			MaxSearchAhead:     edrequester.DefaultMaxSearchAhead,
   244  			FetchTimeout:       edrequester.DefaultFetchTimeout,
   245  			MaxFetchTimeout:    edrequester.DefaultMaxFetchTimeout,
   246  			RetryDelay:         edrequester.DefaultRetryDelay,
   247  			MaxRetryDelay:      edrequester.DefaultMaxRetryDelay,
   248  		},
   249  		executionDataIndexingEnabled: false,
   250  		registersDBPath:              filepath.Join(homedir, ".flow", "execution_state"),
   251  		checkpointFile:               cmd.NotSet,
   252  		scriptExecutorConfig:         query.NewDefaultConfig(),
   253  		scriptExecMinBlock:           0,
   254  		scriptExecMaxBlock:           math.MaxUint64,
   255  		registerCacheType:            pStorage.CacheTypeTwoQueue.String(),
   256  		registerCacheSize:            0,
   257  		programCacheSize:             0,
   258  	}
   259  }
   260  
   261  // FlowAccessNodeBuilder provides the common functionality needed to bootstrap a Flow access node
   262  // It is composed of the FlowNodeBuilder, the AccessNodeConfig and contains all the components and modules needed for the
   263  // access nodes
   264  type FlowAccessNodeBuilder struct {
   265  	*cmd.FlowNodeBuilder
   266  	*AccessNodeConfig
   267  
   268  	// components
   269  	FollowerState              protocol.FollowerState
   270  	SyncCore                   *chainsync.Core
   271  	RpcEng                     *rpc.Engine
   272  	FollowerDistributor        *consensuspubsub.FollowerDistributor
   273  	CollectionRPC              access.AccessAPIClient
   274  	TransactionTimings         *stdmap.TransactionTimings
   275  	CollectionsToMarkFinalized *stdmap.Times
   276  	CollectionsToMarkExecuted  *stdmap.Times
   277  	BlocksToMarkExecuted       *stdmap.Times
   278  	TransactionMetrics         *metrics.TransactionCollector
   279  	RestMetrics                *metrics.RestCollector
   280  	AccessMetrics              module.AccessMetrics
   281  	PingMetrics                module.PingMetrics
   282  	Committee                  hotstuff.DynamicCommittee
   283  	Finalized                  *flow.Header // latest finalized block that the node knows of at startup time
   284  	Pending                    []*flow.Header
   285  	FollowerCore               module.HotStuffFollower
   286  	Validator                  hotstuff.Validator
   287  	ExecutionDataDownloader    execution_data.Downloader
   288  	PublicBlobService          network.BlobService
   289  	ExecutionDataRequester     state_synchronization.ExecutionDataRequester
   290  	ExecutionDataStore         execution_data.ExecutionDataStore
   291  	ExecutionDataCache         *execdatacache.ExecutionDataCache
   292  	ExecutionIndexer           *indexer.Indexer
   293  	ExecutionIndexerCore       *indexer.IndexerCore
   294  	ScriptExecutor             *backend.ScriptExecutor
   295  	RegistersAsyncStore        *execution.RegistersAsyncStore
   296  	EventsIndex                *index.EventsIndex
   297  	TxResultsIndex             *index.TransactionResultsIndex
   298  	IndexerDependencies        *cmd.DependencyList
   299  	collectionExecutedMetric   module.CollectionExecutedMetric
   300  
   301  	// The sync engine participants provider is the libp2p peer store for the access node
   302  	// which is not available until after the network has started.
   303  	// Hence, a factory function that needs to be called just before creating the sync engine
   304  	SyncEngineParticipantsProviderFactory func() module.IdentifierProvider
   305  
   306  	// engines
   307  	IngestEng      *ingestion.Engine
   308  	RequestEng     *requester.Engine
   309  	FollowerEng    *followereng.ComplianceEngine
   310  	SyncEng        *synceng.Engine
   311  	StateStreamEng *statestreambackend.Engine
   312  
   313  	// grpc servers
   314  	secureGrpcServer      *grpcserver.GrpcServer
   315  	unsecureGrpcServer    *grpcserver.GrpcServer
   316  	stateStreamGrpcServer *grpcserver.GrpcServer
   317  
   318  	stateStreamBackend *statestreambackend.StateStreamBackend
   319  }
   320  
   321  func (builder *FlowAccessNodeBuilder) buildFollowerState() *FlowAccessNodeBuilder {
   322  	builder.Module("mutable follower state", func(node *cmd.NodeConfig) error {
   323  		// For now, we only support state implementations from package badger.
   324  		// If we ever support different implementations, the following can be replaced by a type-aware factory
   325  		state, ok := node.State.(*badgerState.State)
   326  		if !ok {
   327  			return fmt.Errorf("only implementations of type badger.State are currently supported but read-only state has type %T", node.State)
   328  		}
   329  
   330  		followerState, err := badgerState.NewFollowerState(
   331  			node.Logger,
   332  			node.Tracer,
   333  			node.ProtocolEvents,
   334  			state,
   335  			node.Storage.Index,
   336  			node.Storage.Payloads,
   337  			blocktimer.DefaultBlockTimer,
   338  		)
   339  		builder.FollowerState = followerState
   340  
   341  		return err
   342  	})
   343  
   344  	return builder
   345  }
   346  
   347  func (builder *FlowAccessNodeBuilder) buildSyncCore() *FlowAccessNodeBuilder {
   348  	builder.Module("sync core", func(node *cmd.NodeConfig) error {
   349  		syncCore, err := chainsync.New(node.Logger, node.SyncCoreConfig, metrics.NewChainSyncCollector(node.RootChainID), node.RootChainID)
   350  		builder.SyncCore = syncCore
   351  
   352  		return err
   353  	})
   354  
   355  	return builder
   356  }
   357  
   358  func (builder *FlowAccessNodeBuilder) buildCommittee() *FlowAccessNodeBuilder {
   359  	builder.Component("committee", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   360  		// initialize consensus committee's membership state
   361  		// This committee state is for the HotStuff follower, which follows the MAIN CONSENSUS committee
   362  		// Note: node.Me.NodeID() is not part of the consensus committee
   363  		committee, err := committees.NewConsensusCommittee(node.State, node.Me.NodeID())
   364  		node.ProtocolEvents.AddConsumer(committee)
   365  		builder.Committee = committee
   366  
   367  		return committee, err
   368  	})
   369  
   370  	return builder
   371  }
   372  
   373  func (builder *FlowAccessNodeBuilder) buildLatestHeader() *FlowAccessNodeBuilder {
   374  	builder.Module("latest header", func(node *cmd.NodeConfig) error {
   375  		finalized, pending, err := recovery.FindLatest(node.State, node.Storage.Headers)
   376  		builder.Finalized, builder.Pending = finalized, pending
   377  
   378  		return err
   379  	})
   380  
   381  	return builder
   382  }
   383  
   384  func (builder *FlowAccessNodeBuilder) buildFollowerCore() *FlowAccessNodeBuilder {
   385  	builder.Component("follower core", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   386  		// create a finalizer that will handle updating the protocol
   387  		// state when the follower detects newly finalized blocks
   388  		final := finalizer.NewFinalizer(node.DB, node.Storage.Headers, builder.FollowerState, node.Tracer)
   389  
   390  		packer := signature.NewConsensusSigDataPacker(builder.Committee)
   391  		// initialize the verifier for the protocol consensus
   392  		verifier := verification.NewCombinedVerifier(builder.Committee, packer)
   393  		builder.Validator = hotstuffvalidator.New(builder.Committee, verifier)
   394  
   395  		followerCore, err := consensus.NewFollower(
   396  			node.Logger,
   397  			node.Metrics.Mempool,
   398  			node.Storage.Headers,
   399  			final,
   400  			builder.FollowerDistributor,
   401  			node.FinalizedRootBlock.Header,
   402  			node.RootQC,
   403  			builder.Finalized,
   404  			builder.Pending,
   405  		)
   406  		if err != nil {
   407  			return nil, fmt.Errorf("could not initialize follower core: %w", err)
   408  		}
   409  		builder.FollowerCore = followerCore
   410  
   411  		return builder.FollowerCore, nil
   412  	})
   413  
   414  	return builder
   415  }
   416  
   417  func (builder *FlowAccessNodeBuilder) buildFollowerEngine() *FlowAccessNodeBuilder {
   418  	builder.Component("follower engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   419  		var heroCacheCollector module.HeroCacheMetrics = metrics.NewNoopCollector()
   420  		if node.HeroCacheMetricsEnable {
   421  			heroCacheCollector = metrics.FollowerCacheMetrics(node.MetricsRegisterer)
   422  		}
   423  
   424  		core, err := followereng.NewComplianceCore(
   425  			node.Logger,
   426  			node.Metrics.Mempool,
   427  			heroCacheCollector,
   428  			builder.FollowerDistributor,
   429  			builder.FollowerState,
   430  			builder.FollowerCore,
   431  			builder.Validator,
   432  			builder.SyncCore,
   433  			node.Tracer,
   434  		)
   435  		if err != nil {
   436  			return nil, fmt.Errorf("could not create follower core: %w", err)
   437  		}
   438  
   439  		builder.FollowerEng, err = followereng.NewComplianceLayer(
   440  			node.Logger,
   441  			node.EngineRegistry,
   442  			node.Me,
   443  			node.Metrics.Engine,
   444  			node.Storage.Headers,
   445  			builder.Finalized,
   446  			core,
   447  			node.ComplianceConfig,
   448  		)
   449  		if err != nil {
   450  			return nil, fmt.Errorf("could not create follower engine: %w", err)
   451  		}
   452  		builder.FollowerDistributor.AddOnBlockFinalizedConsumer(builder.FollowerEng.OnFinalizedBlock)
   453  
   454  		return builder.FollowerEng, nil
   455  	})
   456  
   457  	return builder
   458  }
   459  
   460  func (builder *FlowAccessNodeBuilder) buildSyncEngine() *FlowAccessNodeBuilder {
   461  	builder.Component("sync engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   462  		spamConfig, err := synceng.NewSpamDetectionConfig()
   463  		if err != nil {
   464  			return nil, fmt.Errorf("could not initialize spam detection config: %w", err)
   465  		}
   466  		sync, err := synceng.New(
   467  			node.Logger,
   468  			node.Metrics.Engine,
   469  			node.EngineRegistry,
   470  			node.Me,
   471  			node.State,
   472  			node.Storage.Blocks,
   473  			builder.FollowerEng,
   474  			builder.SyncCore,
   475  			builder.SyncEngineParticipantsProviderFactory(),
   476  			spamConfig,
   477  		)
   478  		if err != nil {
   479  			return nil, fmt.Errorf("could not create synchronization engine: %w", err)
   480  		}
   481  		builder.SyncEng = sync
   482  		builder.FollowerDistributor.AddFinalizationConsumer(sync)
   483  
   484  		return builder.SyncEng, nil
   485  	})
   486  
   487  	return builder
   488  }
   489  
   490  func (builder *FlowAccessNodeBuilder) BuildConsensusFollower() *FlowAccessNodeBuilder {
   491  	builder.
   492  		buildFollowerState().
   493  		buildSyncCore().
   494  		buildCommittee().
   495  		buildLatestHeader().
   496  		buildFollowerCore().
   497  		buildFollowerEngine().
   498  		buildSyncEngine()
   499  
   500  	return builder
   501  }
   502  
   503  func (builder *FlowAccessNodeBuilder) BuildExecutionSyncComponents() *FlowAccessNodeBuilder {
   504  	var ds *badger.Datastore
   505  	var bs network.BlobService
   506  	var processedBlockHeight storage.ConsumerProgress
   507  	var processedNotifications storage.ConsumerProgress
   508  	var bsDependable *module.ProxiedReadyDoneAware
   509  	var execDataDistributor *edrequester.ExecutionDataDistributor
   510  	var execDataCacheBackend *herocache.BlockExecutionData
   511  	var executionDataStoreCache *execdatacache.ExecutionDataCache
   512  
   513  	// setup dependency chain to ensure indexer starts after the requester
   514  	requesterDependable := module.NewProxiedReadyDoneAware()
   515  	builder.IndexerDependencies.Add(requesterDependable)
   516  
   517  	builder.
   518  		AdminCommand("read-execution-data", func(config *cmd.NodeConfig) commands.AdminCommand {
   519  			return stateSyncCommands.NewReadExecutionDataCommand(builder.ExecutionDataStore)
   520  		}).
   521  		Module("execution data datastore and blobstore", func(node *cmd.NodeConfig) error {
   522  			datastoreDir := filepath.Join(builder.executionDataDir, "blobstore")
   523  			err := os.MkdirAll(datastoreDir, 0700)
   524  			if err != nil {
   525  				return err
   526  			}
   527  
   528  			ds, err = badger.NewDatastore(datastoreDir, &badger.DefaultOptions)
   529  			if err != nil {
   530  				return err
   531  			}
   532  
   533  			builder.ShutdownFunc(func() error {
   534  				if err := ds.Close(); err != nil {
   535  					return fmt.Errorf("could not close execution data datastore: %w", err)
   536  				}
   537  				return nil
   538  			})
   539  
   540  			return nil
   541  		}).
   542  		Module("processed block height consumer progress", func(node *cmd.NodeConfig) error {
   543  			// Note: progress is stored in the datastore's DB since that is where the jobqueue
   544  			// writes execution data to.
   545  			processedBlockHeight = bstorage.NewConsumerProgress(ds.DB, module.ConsumeProgressExecutionDataRequesterBlockHeight)
   546  			return nil
   547  		}).
   548  		Module("processed notifications consumer progress", func(node *cmd.NodeConfig) error {
   549  			// Note: progress is stored in the datastore's DB since that is where the jobqueue
   550  			// writes execution data to.
   551  			processedNotifications = bstorage.NewConsumerProgress(ds.DB, module.ConsumeProgressExecutionDataRequesterNotification)
   552  			return nil
   553  		}).
   554  		Module("blobservice peer manager dependencies", func(node *cmd.NodeConfig) error {
   555  			bsDependable = module.NewProxiedReadyDoneAware()
   556  			builder.PeerManagerDependencies.Add(bsDependable)
   557  			return nil
   558  		}).
   559  		Module("execution datastore", func(node *cmd.NodeConfig) error {
   560  			blobstore := blobs.NewBlobstore(ds)
   561  			builder.ExecutionDataStore = execution_data.NewExecutionDataStore(blobstore, execution_data.DefaultSerializer)
   562  			return nil
   563  		}).
   564  		Module("execution data cache", func(node *cmd.NodeConfig) error {
   565  			var heroCacheCollector module.HeroCacheMetrics = metrics.NewNoopCollector()
   566  			if builder.HeroCacheMetricsEnable {
   567  				heroCacheCollector = metrics.AccessNodeExecutionDataCacheMetrics(builder.MetricsRegisterer)
   568  			}
   569  
   570  			execDataCacheBackend = herocache.NewBlockExecutionData(builder.stateStreamConf.ExecutionDataCacheSize, builder.Logger, heroCacheCollector)
   571  
   572  			// Execution Data cache that uses a blobstore as the backend (instead of a downloader)
   573  			// This ensures that it simply returns a not found error if the blob doesn't exist
   574  			// instead of attempting to download it from the network.
   575  			executionDataStoreCache = execdatacache.NewExecutionDataCache(
   576  				builder.ExecutionDataStore,
   577  				builder.Storage.Headers,
   578  				builder.Storage.Seals,
   579  				builder.Storage.Results,
   580  				execDataCacheBackend,
   581  			)
   582  
   583  			return nil
   584  		}).
   585  		Component("execution data service", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   586  			opts := []network.BlobServiceOption{
   587  				blob.WithBitswapOptions(
   588  					// Only allow block requests from staked ENs and ANs
   589  					bitswap.WithPeerBlockRequestFilter(
   590  						blob.AuthorizedRequester(nil, builder.IdentityProvider, builder.Logger),
   591  					),
   592  					bitswap.WithTracer(
   593  						blob.NewTracer(node.Logger.With().Str("blob_service", channels.ExecutionDataService.String()).Logger()),
   594  					),
   595  				),
   596  			}
   597  
   598  			if !builder.BitswapReprovideEnabled {
   599  				opts = append(opts, blob.WithReprovideInterval(-1))
   600  			}
   601  
   602  			var err error
   603  			bs, err = node.EngineRegistry.RegisterBlobService(channels.ExecutionDataService, ds, opts...)
   604  			if err != nil {
   605  				return nil, fmt.Errorf("could not register blob service: %w", err)
   606  			}
   607  
   608  			// add blobservice into ReadyDoneAware dependency passed to peer manager
   609  			// this starts the blob service and configures peer manager to wait for the blobservice
   610  			// to be ready before starting
   611  			bsDependable.Init(bs)
   612  
   613  			builder.ExecutionDataDownloader = execution_data.NewDownloader(bs)
   614  
   615  			return builder.ExecutionDataDownloader, nil
   616  		}).
   617  		Component("execution data requester", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   618  			// Validation of the start block height needs to be done after loading state
   619  			if builder.executionDataStartHeight > 0 {
   620  				if builder.executionDataStartHeight <= builder.FinalizedRootBlock.Header.Height {
   621  					return nil, fmt.Errorf(
   622  						"execution data start block height (%d) must be greater than the root block height (%d)",
   623  						builder.executionDataStartHeight, builder.FinalizedRootBlock.Header.Height)
   624  				}
   625  
   626  				latestSeal, err := builder.State.Sealed().Head()
   627  				if err != nil {
   628  					return nil, fmt.Errorf("failed to get latest sealed height")
   629  				}
   630  
   631  				// Note: since the root block of a spork is also sealed in the root protocol state, the
   632  				// latest sealed height is always equal to the root block height. That means that at the
   633  				// very beginning of a spork, this check will always fail. Operators should not specify
   634  				// an InitialBlockHeight when starting from the beginning of a spork.
   635  				if builder.executionDataStartHeight > latestSeal.Height {
   636  					return nil, fmt.Errorf(
   637  						"execution data start block height (%d) must be less than or equal to the latest sealed block height (%d)",
   638  						builder.executionDataStartHeight, latestSeal.Height)
   639  				}
   640  
   641  				// executionDataStartHeight is provided as the first block to sync, but the
   642  				// requester expects the initial last processed height, which is the first height - 1
   643  				builder.executionDataConfig.InitialBlockHeight = builder.executionDataStartHeight - 1
   644  			} else {
   645  				builder.executionDataConfig.InitialBlockHeight = builder.SealedRootBlock.Header.Height
   646  			}
   647  
   648  			execDataDistributor = edrequester.NewExecutionDataDistributor()
   649  
   650  			// Execution Data cache with a downloader as the backend. This is used by the requester
   651  			// to download and cache execution data for each block. It shares a cache backend instance
   652  			// with the datastore implementation.
   653  			executionDataCache := execdatacache.NewExecutionDataCache(
   654  				builder.ExecutionDataDownloader,
   655  				builder.Storage.Headers,
   656  				builder.Storage.Seals,
   657  				builder.Storage.Results,
   658  				execDataCacheBackend,
   659  			)
   660  
   661  			r, err := edrequester.New(
   662  				builder.Logger,
   663  				metrics.NewExecutionDataRequesterCollector(),
   664  				builder.ExecutionDataDownloader,
   665  				executionDataCache,
   666  				processedBlockHeight,
   667  				processedNotifications,
   668  				builder.State,
   669  				builder.Storage.Headers,
   670  				builder.executionDataConfig,
   671  				execDataDistributor,
   672  			)
   673  			if err != nil {
   674  				return nil, fmt.Errorf("failed to create execution data requester: %w", err)
   675  			}
   676  			builder.ExecutionDataRequester = r
   677  
   678  			builder.FollowerDistributor.AddOnBlockFinalizedConsumer(builder.ExecutionDataRequester.OnBlockFinalized)
   679  
   680  			// add requester into ReadyDoneAware dependency passed to indexer. This allows the indexer
   681  			// to wait for the requester to be ready before starting.
   682  			requesterDependable.Init(builder.ExecutionDataRequester)
   683  
   684  			return builder.ExecutionDataRequester, nil
   685  		})
   686  
   687  	if builder.publicNetworkExecutionDataEnabled {
   688  		var publicBsDependable *module.ProxiedReadyDoneAware
   689  
   690  		builder.Module("public blobservice peer manager dependencies", func(node *cmd.NodeConfig) error {
   691  			publicBsDependable = module.NewProxiedReadyDoneAware()
   692  			builder.PeerManagerDependencies.Add(publicBsDependable)
   693  			return nil
   694  		})
   695  		builder.Component("public network execution data service", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   696  			opts := []network.BlobServiceOption{
   697  				blob.WithBitswapOptions(
   698  					bitswap.WithTracer(
   699  						blob.NewTracer(node.Logger.With().Str("public_blob_service", channels.PublicExecutionDataService.String()).Logger()),
   700  					),
   701  				),
   702  				blob.WithParentBlobService(bs),
   703  			}
   704  
   705  			net := builder.AccessNodeConfig.PublicNetworkConfig.Network
   706  
   707  			var err error
   708  			builder.PublicBlobService, err = net.RegisterBlobService(channels.PublicExecutionDataService, ds, opts...)
   709  			if err != nil {
   710  				return nil, fmt.Errorf("could not register blob service: %w", err)
   711  			}
   712  
   713  			// add blobservice into ReadyDoneAware dependency passed to peer manager
   714  			// this starts the blob service and configures peer manager to wait for the blobservice
   715  			// to be ready before starting
   716  			publicBsDependable.Init(builder.PublicBlobService)
   717  			return &module.NoopReadyDoneAware{}, nil
   718  		})
   719  	}
   720  
   721  	if builder.executionDataIndexingEnabled {
   722  		var indexedBlockHeight storage.ConsumerProgress
   723  
   724  		builder.
   725  			AdminCommand("execute-script", func(config *cmd.NodeConfig) commands.AdminCommand {
   726  				return stateSyncCommands.NewExecuteScriptCommand(builder.ScriptExecutor)
   727  			}).
   728  			Module("indexed block height consumer progress", func(node *cmd.NodeConfig) error {
   729  				// Note: progress is stored in the MAIN db since that is where indexed execution data is stored.
   730  				indexedBlockHeight = bstorage.NewConsumerProgress(builder.DB, module.ConsumeProgressExecutionDataIndexerBlockHeight)
   731  				return nil
   732  			}).
   733  			Module("transaction results storage", func(node *cmd.NodeConfig) error {
   734  				builder.Storage.LightTransactionResults = bstorage.NewLightTransactionResults(node.Metrics.Cache, node.DB, bstorage.DefaultCacheSize)
   735  				return nil
   736  			}).
   737  			DependableComponent("execution data indexer", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   738  				// Note: using a DependableComponent here to ensure that the indexer does not block
   739  				// other components from starting while bootstrapping the register db since it may
   740  				// take hours to complete.
   741  
   742  				pdb, err := pStorage.OpenRegisterPebbleDB(builder.registersDBPath)
   743  				if err != nil {
   744  					return nil, fmt.Errorf("could not open registers db: %w", err)
   745  				}
   746  				builder.ShutdownFunc(func() error {
   747  					return pdb.Close()
   748  				})
   749  
   750  				bootstrapped, err := pStorage.IsBootstrapped(pdb)
   751  				if err != nil {
   752  					return nil, fmt.Errorf("could not check if registers db is bootstrapped: %w", err)
   753  				}
   754  
   755  				if !bootstrapped {
   756  					checkpointFile := builder.checkpointFile
   757  					if checkpointFile == cmd.NotSet {
   758  						checkpointFile = path.Join(builder.BootstrapDir, bootstrap.PathRootCheckpoint)
   759  					}
   760  
   761  					// currently, the checkpoint must be from the root block.
   762  					// read the root hash from the provided checkpoint and verify it matches the
   763  					// state commitment from the root snapshot.
   764  					err := wal.CheckpointHasRootHash(
   765  						node.Logger,
   766  						"", // checkpoint file already full path
   767  						checkpointFile,
   768  						ledger.RootHash(node.RootSeal.FinalState),
   769  					)
   770  					if err != nil {
   771  						return nil, fmt.Errorf("could not verify checkpoint file: %w", err)
   772  					}
   773  
   774  					checkpointHeight := builder.SealedRootBlock.Header.Height
   775  
   776  					if builder.SealedRootBlock.ID() != builder.RootSeal.BlockID {
   777  						return nil, fmt.Errorf("mismatching sealed root block and root seal: %v != %v",
   778  							builder.SealedRootBlock.ID(), builder.RootSeal.BlockID)
   779  					}
   780  
   781  					rootHash := ledger.RootHash(builder.RootSeal.FinalState)
   782  					bootstrap, err := pStorage.NewRegisterBootstrap(pdb, checkpointFile, checkpointHeight, rootHash, builder.Logger)
   783  					if err != nil {
   784  						return nil, fmt.Errorf("could not create registers bootstrap: %w", err)
   785  					}
   786  
   787  					// TODO: find a way to hook a context up to this to allow a graceful shutdown
   788  					workerCount := 10
   789  					err = bootstrap.IndexCheckpointFile(context.Background(), workerCount)
   790  					if err != nil {
   791  						return nil, fmt.Errorf("could not load checkpoint file: %w", err)
   792  					}
   793  				}
   794  
   795  				registers, err := pStorage.NewRegisters(pdb)
   796  				if err != nil {
   797  					return nil, fmt.Errorf("could not create registers storage: %w", err)
   798  				}
   799  
   800  				if builder.registerCacheSize > 0 {
   801  					cacheType, err := pStorage.ParseCacheType(builder.registerCacheType)
   802  					if err != nil {
   803  						return nil, fmt.Errorf("could not parse register cache type: %w", err)
   804  					}
   805  					cacheMetrics := metrics.NewCacheCollector(builder.RootChainID)
   806  					registersCache, err := pStorage.NewRegistersCache(registers, cacheType, builder.registerCacheSize, cacheMetrics)
   807  					if err != nil {
   808  						return nil, fmt.Errorf("could not create registers cache: %w", err)
   809  					}
   810  					builder.Storage.RegisterIndex = registersCache
   811  				} else {
   812  					builder.Storage.RegisterIndex = registers
   813  				}
   814  
   815  				indexerDerivedChainData, queryDerivedChainData, err := builder.buildDerivedChainData()
   816  				if err != nil {
   817  					return nil, fmt.Errorf("could not create derived chain data: %w", err)
   818  				}
   819  
   820  				indexerCore, err := indexer.New(
   821  					builder.Logger,
   822  					metrics.NewExecutionStateIndexerCollector(),
   823  					builder.DB,
   824  					builder.Storage.RegisterIndex,
   825  					builder.Storage.Headers,
   826  					builder.Storage.Events,
   827  					builder.Storage.Collections,
   828  					builder.Storage.Transactions,
   829  					builder.Storage.LightTransactionResults,
   830  					builder.RootChainID.Chain(),
   831  					indexerDerivedChainData,
   832  					builder.collectionExecutedMetric,
   833  				)
   834  				if err != nil {
   835  					return nil, err
   836  				}
   837  				builder.ExecutionIndexerCore = indexerCore
   838  
   839  				// execution state worker uses a jobqueue to process new execution data and indexes it by using the indexer.
   840  				builder.ExecutionIndexer, err = indexer.NewIndexer(
   841  					builder.Logger,
   842  					registers.FirstHeight(),
   843  					registers,
   844  					indexerCore,
   845  					executionDataStoreCache,
   846  					builder.ExecutionDataRequester.HighestConsecutiveHeight,
   847  					indexedBlockHeight,
   848  				)
   849  				if err != nil {
   850  					return nil, err
   851  				}
   852  
   853  				// setup requester to notify indexer when new execution data is received
   854  				execDataDistributor.AddOnExecutionDataReceivedConsumer(builder.ExecutionIndexer.OnExecutionData)
   855  
   856  				// create script execution module, this depends on the indexer being initialized and the
   857  				// having the register storage bootstrapped
   858  				scripts := execution.NewScripts(
   859  					builder.Logger,
   860  					metrics.NewExecutionCollector(builder.Tracer),
   861  					builder.RootChainID,
   862  					query.NewProtocolStateWrapper(builder.State),
   863  					builder.Storage.Headers,
   864  					builder.ExecutionIndexerCore.RegisterValue,
   865  					builder.scriptExecutorConfig,
   866  					queryDerivedChainData,
   867  					builder.programCacheSize > 0,
   868  				)
   869  
   870  				err = builder.ScriptExecutor.Initialize(builder.ExecutionIndexer, scripts)
   871  				if err != nil {
   872  					return nil, err
   873  				}
   874  
   875  				err = builder.EventsIndex.Initialize(builder.ExecutionIndexer)
   876  				if err != nil {
   877  					return nil, err
   878  				}
   879  
   880  				err = builder.TxResultsIndex.Initialize(builder.ExecutionIndexer)
   881  				if err != nil {
   882  					return nil, err
   883  				}
   884  
   885  				err = builder.RegistersAsyncStore.Initialize(registers)
   886  				if err != nil {
   887  					return nil, err
   888  				}
   889  
   890  				return builder.ExecutionIndexer, nil
   891  			}, builder.IndexerDependencies)
   892  	}
   893  
   894  	if builder.stateStreamConf.ListenAddr != "" {
   895  		builder.Component("exec state stream engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
   896  			for key, value := range builder.stateStreamFilterConf {
   897  				switch key {
   898  				case "EventTypes":
   899  					builder.stateStreamConf.MaxEventTypes = value
   900  				case "Addresses":
   901  					builder.stateStreamConf.MaxAddresses = value
   902  				case "Contracts":
   903  					builder.stateStreamConf.MaxContracts = value
   904  				case "AccountAddresses":
   905  					builder.stateStreamConf.MaxAccountAddress = value
   906  				}
   907  			}
   908  			builder.stateStreamConf.RpcMetricsEnabled = builder.rpcMetricsEnabled
   909  
   910  			highestAvailableHeight, err := builder.ExecutionDataRequester.HighestConsecutiveHeight()
   911  			if err != nil {
   912  				return nil, fmt.Errorf("could not get highest consecutive height: %w", err)
   913  			}
   914  			broadcaster := engine.NewBroadcaster()
   915  
   916  			eventQueryMode, err := backend.ParseIndexQueryMode(builder.rpcConf.BackendConfig.EventQueryMode)
   917  			if err != nil {
   918  				return nil, fmt.Errorf("could not parse event query mode: %w", err)
   919  			}
   920  
   921  			// use the events index for events if enabled and the node is configured to use it for
   922  			// regular event queries
   923  			useIndex := builder.executionDataIndexingEnabled &&
   924  				eventQueryMode != backend.IndexQueryModeExecutionNodesOnly
   925  
   926  			executionDataTracker := subscription.NewExecutionDataTracker(
   927  				builder.Logger,
   928  				node.State,
   929  				builder.executionDataConfig.InitialBlockHeight,
   930  				node.Storage.Headers,
   931  				broadcaster,
   932  				highestAvailableHeight,
   933  				builder.EventsIndex,
   934  				useIndex,
   935  			)
   936  
   937  			builder.stateStreamBackend, err = statestreambackend.New(
   938  				node.Logger,
   939  				node.State,
   940  				node.Storage.Headers,
   941  				node.Storage.Seals,
   942  				node.Storage.Results,
   943  				builder.ExecutionDataStore,
   944  				executionDataStoreCache,
   945  				builder.RegistersAsyncStore,
   946  				builder.EventsIndex,
   947  				useIndex,
   948  				int(builder.stateStreamConf.RegisterIDsRequestLimit),
   949  				subscription.NewSubscriptionHandler(
   950  					builder.Logger,
   951  					broadcaster,
   952  					builder.stateStreamConf.ClientSendTimeout,
   953  					builder.stateStreamConf.ResponseLimit,
   954  					builder.stateStreamConf.ClientSendBufferSize,
   955  				),
   956  				executionDataTracker,
   957  			)
   958  			if err != nil {
   959  				return nil, fmt.Errorf("could not create state stream backend: %w", err)
   960  			}
   961  
   962  			stateStreamEng, err := statestreambackend.NewEng(
   963  				node.Logger,
   964  				builder.stateStreamConf,
   965  				executionDataStoreCache,
   966  				node.Storage.Headers,
   967  				node.RootChainID,
   968  				builder.stateStreamGrpcServer,
   969  				builder.stateStreamBackend,
   970  			)
   971  			if err != nil {
   972  				return nil, fmt.Errorf("could not create state stream engine: %w", err)
   973  			}
   974  			builder.StateStreamEng = stateStreamEng
   975  
   976  			// setup requester to notify ExecutionDataTracker when new execution data is received
   977  			execDataDistributor.AddOnExecutionDataReceivedConsumer(builder.stateStreamBackend.OnExecutionData)
   978  
   979  			return builder.StateStreamEng, nil
   980  		})
   981  	}
   982  
   983  	return builder
   984  }
   985  
   986  // buildDerivedChainData creates the derived chain data for the indexer and the query engine
   987  // If program caching is disabled, the function will return nil for the indexer cache, and a
   988  // derived chain data object for the query engine cache.
   989  func (builder *FlowAccessNodeBuilder) buildDerivedChainData() (
   990  	indexerCache *derived.DerivedChainData,
   991  	queryCache *derived.DerivedChainData,
   992  	err error,
   993  ) {
   994  	cacheSize := builder.programCacheSize
   995  
   996  	// the underlying cache requires size > 0. no data will be written so 1 is fine.
   997  	if cacheSize == 0 {
   998  		cacheSize = 1
   999  	}
  1000  
  1001  	derivedChainData, err := derived.NewDerivedChainData(cacheSize)
  1002  	if err != nil {
  1003  		return nil, nil, err
  1004  	}
  1005  
  1006  	// writes are done by the indexer. using a nil value effectively disables writes to the cache.
  1007  	if builder.programCacheSize == 0 {
  1008  		return nil, derivedChainData, nil
  1009  	}
  1010  
  1011  	return derivedChainData, derivedChainData, nil
  1012  }
  1013  
  1014  func FlowAccessNode(nodeBuilder *cmd.FlowNodeBuilder) *FlowAccessNodeBuilder {
  1015  	dist := consensuspubsub.NewFollowerDistributor()
  1016  	dist.AddProposalViolationConsumer(notifications.NewSlashingViolationsConsumer(nodeBuilder.Logger))
  1017  	return &FlowAccessNodeBuilder{
  1018  		AccessNodeConfig:    DefaultAccessNodeConfig(),
  1019  		FlowNodeBuilder:     nodeBuilder,
  1020  		FollowerDistributor: dist,
  1021  		IndexerDependencies: cmd.NewDependencyList(),
  1022  	}
  1023  }
  1024  
  1025  func (builder *FlowAccessNodeBuilder) ParseFlags() error {
  1026  	builder.BaseFlags()
  1027  
  1028  	builder.extraFlags()
  1029  
  1030  	return builder.ParseAndPrintFlags()
  1031  }
  1032  
  1033  func (builder *FlowAccessNodeBuilder) extraFlags() {
  1034  	builder.ExtraFlags(func(flags *pflag.FlagSet) {
  1035  		defaultConfig := DefaultAccessNodeConfig()
  1036  
  1037  		flags.UintVar(&builder.collectionGRPCPort, "collection-ingress-port", defaultConfig.collectionGRPCPort, "the grpc ingress port for all collection nodes")
  1038  		flags.UintVar(&builder.executionGRPCPort, "execution-ingress-port", defaultConfig.executionGRPCPort, "the grpc ingress port for all execution nodes")
  1039  		flags.StringVarP(&builder.rpcConf.UnsecureGRPCListenAddr,
  1040  			"rpc-addr",
  1041  			"r",
  1042  			defaultConfig.rpcConf.UnsecureGRPCListenAddr,
  1043  			"the address the unsecured gRPC server listens on")
  1044  		flags.StringVar(&builder.rpcConf.SecureGRPCListenAddr,
  1045  			"secure-rpc-addr",
  1046  			defaultConfig.rpcConf.SecureGRPCListenAddr,
  1047  			"the address the secure gRPC server listens on")
  1048  		flags.StringVar(&builder.stateStreamConf.ListenAddr,
  1049  			"state-stream-addr",
  1050  			defaultConfig.stateStreamConf.ListenAddr,
  1051  			"the address the state stream server listens on (if empty the server will not be started)")
  1052  		flags.StringVarP(&builder.rpcConf.HTTPListenAddr, "http-addr", "h", defaultConfig.rpcConf.HTTPListenAddr, "the address the http proxy server listens on")
  1053  		flags.StringVar(&builder.rpcConf.RestConfig.ListenAddress,
  1054  			"rest-addr",
  1055  			defaultConfig.rpcConf.RestConfig.ListenAddress,
  1056  			"the address the REST server listens on (if empty the REST server will not be started)")
  1057  		flags.DurationVar(&builder.rpcConf.RestConfig.WriteTimeout,
  1058  			"rest-write-timeout",
  1059  			defaultConfig.rpcConf.RestConfig.WriteTimeout,
  1060  			"timeout to use when writing REST response")
  1061  		flags.DurationVar(&builder.rpcConf.RestConfig.ReadTimeout,
  1062  			"rest-read-timeout",
  1063  			defaultConfig.rpcConf.RestConfig.ReadTimeout,
  1064  			"timeout to use when reading REST request headers")
  1065  		flags.DurationVar(&builder.rpcConf.RestConfig.IdleTimeout, "rest-idle-timeout", defaultConfig.rpcConf.RestConfig.IdleTimeout, "idle timeout for REST connections")
  1066  		flags.StringVarP(&builder.rpcConf.CollectionAddr,
  1067  			"static-collection-ingress-addr",
  1068  			"",
  1069  			defaultConfig.rpcConf.CollectionAddr,
  1070  			"the address (of the collection node) to send transactions to")
  1071  		flags.StringVarP(&builder.ExecutionNodeAddress,
  1072  			"script-addr",
  1073  			"s",
  1074  			defaultConfig.ExecutionNodeAddress,
  1075  			"the address (of the execution node) forward the script to")
  1076  		flags.StringVarP(&builder.rpcConf.HistoricalAccessAddrs,
  1077  			"historical-access-addr",
  1078  			"",
  1079  			defaultConfig.rpcConf.HistoricalAccessAddrs,
  1080  			"comma separated rpc addresses for historical access nodes")
  1081  		flags.DurationVar(&builder.rpcConf.BackendConfig.CollectionClientTimeout,
  1082  			"collection-client-timeout",
  1083  			defaultConfig.rpcConf.BackendConfig.CollectionClientTimeout,
  1084  			"grpc client timeout for a collection node")
  1085  		flags.DurationVar(&builder.rpcConf.BackendConfig.ExecutionClientTimeout,
  1086  			"execution-client-timeout",
  1087  			defaultConfig.rpcConf.BackendConfig.ExecutionClientTimeout,
  1088  			"grpc client timeout for an execution node")
  1089  		flags.UintVar(&builder.rpcConf.BackendConfig.ConnectionPoolSize,
  1090  			"connection-pool-size",
  1091  			defaultConfig.rpcConf.BackendConfig.ConnectionPoolSize,
  1092  			"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")
  1093  		flags.UintVar(&builder.rpcConf.MaxMsgSize,
  1094  			"rpc-max-message-size",
  1095  			grpcutils.DefaultMaxMsgSize,
  1096  			"the maximum message size in bytes for messages sent or received over grpc")
  1097  		flags.UintVar(&builder.rpcConf.BackendConfig.MaxHeightRange,
  1098  			"rpc-max-height-range",
  1099  			defaultConfig.rpcConf.BackendConfig.MaxHeightRange,
  1100  			"maximum size for height range requests")
  1101  		flags.StringSliceVar(&builder.rpcConf.BackendConfig.PreferredExecutionNodeIDs,
  1102  			"preferred-execution-node-ids",
  1103  			defaultConfig.rpcConf.BackendConfig.PreferredExecutionNodeIDs,
  1104  			"comma separated list of execution nodes ids to choose from when making an upstream call e.g. b4a4dbdcd443d...,fb386a6a... etc.")
  1105  		flags.StringSliceVar(&builder.rpcConf.BackendConfig.FixedExecutionNodeIDs,
  1106  			"fixed-execution-node-ids",
  1107  			defaultConfig.rpcConf.BackendConfig.FixedExecutionNodeIDs,
  1108  			"comma separated list of execution nodes ids to choose from when making an upstream call if no matching preferred execution id is found e.g. b4a4dbdcd443d...,fb386a6a... etc.")
  1109  		flags.StringVar(&builder.rpcConf.CompressorName,
  1110  			"grpc-compressor",
  1111  			defaultConfig.rpcConf.CompressorName,
  1112  			"name of grpc compressor that will be used for requests to other nodes. One of (gzip, snappy, deflate)")
  1113  		flags.BoolVar(&builder.logTxTimeToFinalized, "log-tx-time-to-finalized", defaultConfig.logTxTimeToFinalized, "log transaction time to finalized")
  1114  		flags.BoolVar(&builder.logTxTimeToExecuted, "log-tx-time-to-executed", defaultConfig.logTxTimeToExecuted, "log transaction time to executed")
  1115  		flags.BoolVar(&builder.logTxTimeToFinalizedExecuted,
  1116  			"log-tx-time-to-finalized-executed",
  1117  			defaultConfig.logTxTimeToFinalizedExecuted,
  1118  			"log transaction time to finalized and executed")
  1119  		flags.BoolVar(&builder.pingEnabled,
  1120  			"ping-enabled",
  1121  			defaultConfig.pingEnabled,
  1122  			"whether to enable the ping process that pings all other peers and report the connectivity to metrics")
  1123  		flags.BoolVar(&builder.retryEnabled, "retry-enabled", defaultConfig.retryEnabled, "whether to enable the retry mechanism at the access node level")
  1124  		flags.BoolVar(&builder.rpcMetricsEnabled, "rpc-metrics-enabled", defaultConfig.rpcMetricsEnabled, "whether to enable the rpc metrics")
  1125  		flags.UintVar(&builder.TxResultCacheSize, "transaction-result-cache-size", defaultConfig.TxResultCacheSize, "transaction result cache size.(Disabled by default i.e 0)")
  1126  		flags.UintVar(&builder.TxErrorMessagesCacheSize, "transaction-error-messages-cache-size", defaultConfig.TxErrorMessagesCacheSize, "transaction error messages cache size.(By default 1000)")
  1127  		flags.StringVarP(&builder.nodeInfoFile,
  1128  			"node-info-file",
  1129  			"",
  1130  			defaultConfig.nodeInfoFile,
  1131  			"full path to a json file which provides more details about nodes when reporting its reachability metrics")
  1132  		flags.StringToIntVar(&builder.apiRatelimits, "api-rate-limits", defaultConfig.apiRatelimits, "per second rate limits for Access API methods e.g. Ping=300,GetTransaction=500 etc.")
  1133  		flags.StringToIntVar(&builder.apiBurstlimits, "api-burst-limits", defaultConfig.apiBurstlimits, "burst limits for Access API methods e.g. Ping=100,GetTransaction=100 etc.")
  1134  		flags.BoolVar(&builder.supportsObserver, "supports-observer", defaultConfig.supportsObserver, "true if this staked access node supports observer or follower connections")
  1135  		flags.StringVar(&builder.PublicNetworkConfig.BindAddress, "public-network-address", defaultConfig.PublicNetworkConfig.BindAddress, "staked access node's public network bind address")
  1136  		flags.BoolVar(&builder.rpcConf.BackendConfig.CircuitBreakerConfig.Enabled,
  1137  			"circuit-breaker-enabled",
  1138  			defaultConfig.rpcConf.BackendConfig.CircuitBreakerConfig.Enabled,
  1139  			"specifies whether the circuit breaker is enabled for collection and execution API clients.")
  1140  		flags.DurationVar(&builder.rpcConf.BackendConfig.CircuitBreakerConfig.RestoreTimeout,
  1141  			"circuit-breaker-restore-timeout",
  1142  			defaultConfig.rpcConf.BackendConfig.CircuitBreakerConfig.RestoreTimeout,
  1143  			"duration after which the circuit breaker will restore the connection to the client after closing it due to failures. Default value is 60s")
  1144  		flags.Uint32Var(&builder.rpcConf.BackendConfig.CircuitBreakerConfig.MaxFailures,
  1145  			"circuit-breaker-max-failures",
  1146  			defaultConfig.rpcConf.BackendConfig.CircuitBreakerConfig.MaxFailures,
  1147  			"maximum number of failed calls to the client that will cause the circuit breaker to close the connection. Default value is 5")
  1148  		flags.Uint32Var(&builder.rpcConf.BackendConfig.CircuitBreakerConfig.MaxRequests,
  1149  			"circuit-breaker-max-requests",
  1150  			defaultConfig.rpcConf.BackendConfig.CircuitBreakerConfig.MaxRequests,
  1151  			"maximum number of requests to check if connection restored after timeout. Default value is 1")
  1152  		// ExecutionDataRequester config
  1153  		flags.BoolVar(&builder.executionDataSyncEnabled,
  1154  			"execution-data-sync-enabled",
  1155  			defaultConfig.executionDataSyncEnabled,
  1156  			"whether to enable the execution data sync protocol")
  1157  		flags.BoolVar(&builder.publicNetworkExecutionDataEnabled,
  1158  			"public-network-execution-data-sync-enabled",
  1159  			defaultConfig.publicNetworkExecutionDataEnabled,
  1160  			"[experimental] whether to enable the execution data sync protocol on public network")
  1161  		flags.StringVar(&builder.executionDataDir, "execution-data-dir", defaultConfig.executionDataDir, "directory to use for Execution Data database")
  1162  		flags.Uint64Var(&builder.executionDataStartHeight,
  1163  			"execution-data-start-height",
  1164  			defaultConfig.executionDataStartHeight,
  1165  			"height of first block to sync execution data from when starting with an empty Execution Data database")
  1166  		flags.Uint64Var(&builder.executionDataConfig.MaxSearchAhead,
  1167  			"execution-data-max-search-ahead",
  1168  			defaultConfig.executionDataConfig.MaxSearchAhead,
  1169  			"max number of heights to search ahead of the lowest outstanding execution data height")
  1170  		flags.DurationVar(&builder.executionDataConfig.FetchTimeout,
  1171  			"execution-data-fetch-timeout",
  1172  			defaultConfig.executionDataConfig.FetchTimeout,
  1173  			"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")
  1174  		flags.DurationVar(&builder.executionDataConfig.MaxFetchTimeout,
  1175  			"execution-data-max-fetch-timeout",
  1176  			defaultConfig.executionDataConfig.MaxFetchTimeout,
  1177  			"maximum timeout to use when fetching execution data from the network e.g. 300s")
  1178  		flags.DurationVar(&builder.executionDataConfig.RetryDelay,
  1179  			"execution-data-retry-delay",
  1180  			defaultConfig.executionDataConfig.RetryDelay,
  1181  			"initial delay for exponential backoff when fetching execution data fails e.g. 10s")
  1182  		flags.DurationVar(&builder.executionDataConfig.MaxRetryDelay,
  1183  			"execution-data-max-retry-delay",
  1184  			defaultConfig.executionDataConfig.MaxRetryDelay,
  1185  			"maximum delay for exponential backoff when fetching execution data fails e.g. 5m")
  1186  
  1187  		// Execution State Streaming API
  1188  		flags.Uint32Var(&builder.stateStreamConf.ExecutionDataCacheSize, "execution-data-cache-size", defaultConfig.stateStreamConf.ExecutionDataCacheSize, "block execution data cache size")
  1189  		flags.Uint32Var(&builder.stateStreamConf.MaxGlobalStreams, "state-stream-global-max-streams", defaultConfig.stateStreamConf.MaxGlobalStreams, "global maximum number of concurrent streams")
  1190  		flags.UintVar(&builder.stateStreamConf.MaxExecutionDataMsgSize,
  1191  			"state-stream-max-message-size",
  1192  			defaultConfig.stateStreamConf.MaxExecutionDataMsgSize,
  1193  			"maximum size for a gRPC message containing block execution data")
  1194  		flags.StringToIntVar(&builder.stateStreamFilterConf,
  1195  			"state-stream-event-filter-limits",
  1196  			defaultConfig.stateStreamFilterConf,
  1197  			"event filter limits for ExecutionData SubscribeEvents API e.g. EventTypes=100,Addresses=100,Contracts=100 etc.")
  1198  		flags.DurationVar(&builder.stateStreamConf.ClientSendTimeout,
  1199  			"state-stream-send-timeout",
  1200  			defaultConfig.stateStreamConf.ClientSendTimeout,
  1201  			"maximum wait before timing out while sending a response to a streaming client e.g. 30s")
  1202  		flags.UintVar(&builder.stateStreamConf.ClientSendBufferSize,
  1203  			"state-stream-send-buffer-size",
  1204  			defaultConfig.stateStreamConf.ClientSendBufferSize,
  1205  			"maximum number of responses to buffer within a stream")
  1206  		flags.Float64Var(&builder.stateStreamConf.ResponseLimit,
  1207  			"state-stream-response-limit",
  1208  			defaultConfig.stateStreamConf.ResponseLimit,
  1209  			"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")
  1210  		flags.Uint64Var(&builder.stateStreamConf.HeartbeatInterval,
  1211  			"state-stream-heartbeat-interval",
  1212  			defaultConfig.stateStreamConf.HeartbeatInterval,
  1213  			"default interval in blocks at which heartbeat messages should be sent. applied when client did not specify a value.")
  1214  		flags.Uint32Var(&builder.stateStreamConf.RegisterIDsRequestLimit,
  1215  			"state-stream-max-register-values",
  1216  			defaultConfig.stateStreamConf.RegisterIDsRequestLimit,
  1217  			"maximum number of register ids to include in a single request to the GetRegisters endpoint")
  1218  
  1219  		// Execution Data Indexer
  1220  		flags.BoolVar(&builder.executionDataIndexingEnabled,
  1221  			"execution-data-indexing-enabled",
  1222  			defaultConfig.executionDataIndexingEnabled,
  1223  			"whether to enable the execution data indexing")
  1224  		flags.StringVar(&builder.registersDBPath, "execution-state-dir", defaultConfig.registersDBPath, "directory to use for execution-state database")
  1225  		flags.StringVar(&builder.checkpointFile, "execution-state-checkpoint", defaultConfig.checkpointFile, "execution-state checkpoint file")
  1226  
  1227  		flags.StringVar(&builder.rpcConf.BackendConfig.EventQueryMode,
  1228  			"event-query-mode",
  1229  			defaultConfig.rpcConf.BackendConfig.EventQueryMode,
  1230  			"mode to use when querying events. one of [local-only, execution-nodes-only(default), failover]")
  1231  
  1232  		flags.StringVar(&builder.rpcConf.BackendConfig.TxResultQueryMode,
  1233  			"tx-result-query-mode",
  1234  			defaultConfig.rpcConf.BackendConfig.TxResultQueryMode,
  1235  			"mode to use when querying transaction results. one of [local-only, execution-nodes-only(default), failover]")
  1236  
  1237  		// Script Execution
  1238  		flags.StringVar(&builder.rpcConf.BackendConfig.ScriptExecutionMode,
  1239  			"script-execution-mode",
  1240  			defaultConfig.rpcConf.BackendConfig.ScriptExecutionMode,
  1241  			"mode to use when executing scripts. one of (local-only, execution-nodes-only, failover, compare)")
  1242  		flags.Uint64Var(&builder.scriptExecutorConfig.ComputationLimit,
  1243  			"script-execution-computation-limit",
  1244  			defaultConfig.scriptExecutorConfig.ComputationLimit,
  1245  			"maximum number of computation units a locally executed script can use. default: 100000")
  1246  		flags.IntVar(&builder.scriptExecutorConfig.MaxErrorMessageSize,
  1247  			"script-execution-max-error-length",
  1248  			defaultConfig.scriptExecutorConfig.MaxErrorMessageSize,
  1249  			"maximum number characters to include in error message strings. additional characters are truncated. default: 1000")
  1250  		flags.DurationVar(&builder.scriptExecutorConfig.LogTimeThreshold,
  1251  			"script-execution-log-time-threshold",
  1252  			defaultConfig.scriptExecutorConfig.LogTimeThreshold,
  1253  			"emit a log for any scripts that take over this threshold. default: 1s")
  1254  		flags.DurationVar(&builder.scriptExecutorConfig.ExecutionTimeLimit,
  1255  			"script-execution-timeout",
  1256  			defaultConfig.scriptExecutorConfig.ExecutionTimeLimit,
  1257  			"timeout value for locally executed scripts. default: 10s")
  1258  		flags.Uint64Var(&builder.scriptExecMinBlock,
  1259  			"script-execution-min-height",
  1260  			defaultConfig.scriptExecMinBlock,
  1261  			"lowest block height to allow for script execution. default: no limit")
  1262  		flags.Uint64Var(&builder.scriptExecMaxBlock,
  1263  			"script-execution-max-height",
  1264  			defaultConfig.scriptExecMaxBlock,
  1265  			"highest block height to allow for script execution. default: no limit")
  1266  		flags.StringVar(&builder.registerCacheType,
  1267  			"register-cache-type",
  1268  			defaultConfig.registerCacheType,
  1269  			"type of backend cache to use for registers (lru, arc, 2q)")
  1270  		flags.UintVar(&builder.registerCacheSize,
  1271  			"register-cache-size",
  1272  			defaultConfig.registerCacheSize,
  1273  			"number of registers to cache for script execution. default: 0 (no cache)")
  1274  		flags.UintVar(&builder.programCacheSize,
  1275  			"program-cache-size",
  1276  			defaultConfig.programCacheSize,
  1277  			"[experimental] number of blocks to cache for cadence programs. use 0 to disable cache. default: 0. Note: this is an experimental feature and may cause nodes to become unstable under certain workloads. Use with caution.")
  1278  	}).ValidateFlags(func() error {
  1279  		if builder.supportsObserver && (builder.PublicNetworkConfig.BindAddress == cmd.NotSet || builder.PublicNetworkConfig.BindAddress == "") {
  1280  			return errors.New("public-network-address must be set if supports-observer is true")
  1281  		}
  1282  		if builder.executionDataSyncEnabled {
  1283  			if builder.executionDataConfig.FetchTimeout <= 0 {
  1284  				return errors.New("execution-data-fetch-timeout must be greater than 0")
  1285  			}
  1286  			if builder.executionDataConfig.MaxFetchTimeout < builder.executionDataConfig.FetchTimeout {
  1287  				return errors.New("execution-data-max-fetch-timeout must be greater than execution-data-fetch-timeout")
  1288  			}
  1289  			if builder.executionDataConfig.RetryDelay <= 0 {
  1290  				return errors.New("execution-data-retry-delay must be greater than 0")
  1291  			}
  1292  			if builder.executionDataConfig.MaxRetryDelay < builder.executionDataConfig.RetryDelay {
  1293  				return errors.New("execution-data-max-retry-delay must be greater than or equal to execution-data-retry-delay")
  1294  			}
  1295  			if builder.executionDataConfig.MaxSearchAhead == 0 {
  1296  				return errors.New("execution-data-max-search-ahead must be greater than 0")
  1297  			}
  1298  		}
  1299  		if builder.stateStreamConf.ListenAddr != "" {
  1300  			if builder.stateStreamConf.ExecutionDataCacheSize == 0 {
  1301  				return errors.New("execution-data-cache-size must be greater than 0")
  1302  			}
  1303  			if builder.stateStreamConf.ClientSendBufferSize == 0 {
  1304  				return errors.New("state-stream-send-buffer-size must be greater than 0")
  1305  			}
  1306  			if len(builder.stateStreamFilterConf) > 4 {
  1307  				return errors.New("state-stream-event-filter-limits must have at most 3 keys (EventTypes, Addresses, Contracts, AccountAddresses)")
  1308  			}
  1309  			for key, value := range builder.stateStreamFilterConf {
  1310  				switch key {
  1311  				case "EventTypes", "Addresses", "Contracts", "AccountAddresses":
  1312  					if value <= 0 {
  1313  						return fmt.Errorf("state-stream-event-filter-limits %s must be greater than 0", key)
  1314  					}
  1315  				default:
  1316  					return errors.New("state-stream-event-filter-limits may only contain the keys EventTypes, Addresses, Contracts, AccountAddresses")
  1317  				}
  1318  			}
  1319  			if builder.stateStreamConf.ResponseLimit < 0 {
  1320  				return errors.New("state-stream-response-limit must be greater than or equal to 0")
  1321  			}
  1322  			if builder.stateStreamConf.RegisterIDsRequestLimit <= 0 {
  1323  				return errors.New("state-stream-max-register-values must be greater than 0")
  1324  			}
  1325  		}
  1326  		if builder.rpcConf.BackendConfig.CircuitBreakerConfig.Enabled {
  1327  			if builder.rpcConf.BackendConfig.CircuitBreakerConfig.MaxFailures == 0 {
  1328  				return errors.New("circuit-breaker-max-failures must be greater than 0")
  1329  			}
  1330  			if builder.rpcConf.BackendConfig.CircuitBreakerConfig.MaxRequests == 0 {
  1331  				return errors.New("circuit-breaker-max-requests must be greater than 0")
  1332  			}
  1333  			if builder.rpcConf.BackendConfig.CircuitBreakerConfig.RestoreTimeout <= 0 {
  1334  				return errors.New("circuit-breaker-restore-timeout must be greater than 0")
  1335  			}
  1336  		}
  1337  		if builder.TxErrorMessagesCacheSize == 0 {
  1338  			return errors.New("transaction-error-messages-cache-size must be greater than 0")
  1339  		}
  1340  
  1341  		return nil
  1342  	})
  1343  }
  1344  
  1345  func publicNetworkMsgValidators(log zerolog.Logger, idProvider module.IdentityProvider, selfID flow.Identifier) []network.MessageValidator {
  1346  	return []network.MessageValidator{
  1347  		// filter out messages sent by this node itself
  1348  		validator.ValidateNotSender(selfID),
  1349  		validator.NewAnyValidator(
  1350  			// message should be either from a valid staked node
  1351  			validator.NewOriginValidator(
  1352  				id.NewIdentityFilterIdentifierProvider(filter.IsValidCurrentEpochParticipant, idProvider),
  1353  			),
  1354  			// or the message should be specifically targeted for this node
  1355  			validator.ValidateTarget(log, selfID),
  1356  		),
  1357  	}
  1358  }
  1359  
  1360  func (builder *FlowAccessNodeBuilder) InitIDProviders() {
  1361  	builder.Module("id providers", func(node *cmd.NodeConfig) error {
  1362  		idCache, err := cache.NewProtocolStateIDCache(node.Logger, node.State, node.ProtocolEvents)
  1363  		if err != nil {
  1364  			return fmt.Errorf("could not initialize ProtocolStateIDCache: %w", err)
  1365  		}
  1366  		builder.IDTranslator = translator.NewHierarchicalIDTranslator(idCache, translator.NewPublicNetworkIDTranslator())
  1367  
  1368  		// The following wrapper allows to disallow-list byzantine nodes via an admin command:
  1369  		// the wrapper overrides the 'Ejected' flag of disallow-listed nodes to true
  1370  		disallowListWrapper, err := cache.NewNodeDisallowListWrapper(idCache, node.DB, func() network.DisallowListNotificationConsumer {
  1371  			return builder.NetworkUnderlay
  1372  		})
  1373  		if err != nil {
  1374  			return fmt.Errorf("could not initialize NodeBlockListWrapper: %w", err)
  1375  		}
  1376  		builder.IdentityProvider = disallowListWrapper
  1377  
  1378  		// register the wrapper for dynamic configuration via admin command
  1379  		err = node.ConfigManager.RegisterIdentifierListConfig("network-id-provider-blocklist",
  1380  			disallowListWrapper.GetDisallowList, disallowListWrapper.Update)
  1381  		if err != nil {
  1382  			return fmt.Errorf("failed to register disallow-list wrapper with config manager: %w", err)
  1383  		}
  1384  
  1385  		builder.SyncEngineParticipantsProviderFactory = func() module.IdentifierProvider {
  1386  			return id.NewIdentityFilterIdentifierProvider(
  1387  				filter.And(
  1388  					filter.HasRole[flow.Identity](flow.RoleConsensus),
  1389  					filter.Not(filter.HasNodeID[flow.Identity](node.Me.NodeID())),
  1390  					filter.NotEjectedFilter,
  1391  				),
  1392  				builder.IdentityProvider,
  1393  			)
  1394  		}
  1395  		return nil
  1396  	})
  1397  }
  1398  
  1399  func (builder *FlowAccessNodeBuilder) Initialize() error {
  1400  	builder.InitIDProviders()
  1401  
  1402  	builder.EnqueueResolver()
  1403  
  1404  	// enqueue the regular network
  1405  	builder.EnqueueNetworkInit()
  1406  
  1407  	builder.AdminCommand("get-transactions", func(conf *cmd.NodeConfig) commands.AdminCommand {
  1408  		return storageCommands.NewGetTransactionsCommand(conf.State, conf.Storage.Payloads, conf.Storage.Collections)
  1409  	})
  1410  
  1411  	// if this is an access node that supports public followers, enqueue the public network
  1412  	if builder.supportsObserver {
  1413  		builder.enqueuePublicNetworkInit()
  1414  		builder.enqueueRelayNetwork()
  1415  	}
  1416  
  1417  	builder.EnqueuePingService()
  1418  
  1419  	builder.EnqueueMetricsServerInit()
  1420  
  1421  	if err := builder.RegisterBadgerMetrics(); err != nil {
  1422  		return err
  1423  	}
  1424  
  1425  	builder.EnqueueTracer()
  1426  	builder.PreInit(cmd.DynamicStartPreInit)
  1427  	builder.ValidateRootSnapshot(badgerState.ValidRootSnapshotContainsEntityExpiryRange)
  1428  
  1429  	return nil
  1430  }
  1431  
  1432  func (builder *FlowAccessNodeBuilder) enqueueRelayNetwork() {
  1433  	builder.Component("relay network", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1434  		relayNet := relaynet.NewRelayNetwork(
  1435  			node.EngineRegistry,
  1436  			builder.AccessNodeConfig.PublicNetworkConfig.Network,
  1437  			node.Logger,
  1438  			map[channels.Channel]channels.Channel{
  1439  				channels.ReceiveBlocks: channels.PublicReceiveBlocks,
  1440  			},
  1441  		)
  1442  		node.EngineRegistry = relayNet
  1443  		return relayNet, nil
  1444  	})
  1445  }
  1446  
  1447  func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) {
  1448  	var processedBlockHeight storage.ConsumerProgress
  1449  
  1450  	if builder.executionDataSyncEnabled {
  1451  		builder.BuildExecutionSyncComponents()
  1452  	}
  1453  
  1454  	ingestionDependable := module.NewProxiedReadyDoneAware()
  1455  	builder.IndexerDependencies.Add(ingestionDependable)
  1456  	var lastFullBlockHeight *counters.PersistentStrictMonotonicCounter
  1457  
  1458  	builder.
  1459  		BuildConsensusFollower().
  1460  		Module("collection node client", func(node *cmd.NodeConfig) error {
  1461  			// collection node address is optional (if not specified, collection nodes will be chosen at random)
  1462  			if strings.TrimSpace(builder.rpcConf.CollectionAddr) == "" {
  1463  				node.Logger.Info().Msg("using a dynamic collection node address")
  1464  				return nil
  1465  			}
  1466  
  1467  			node.Logger.Info().
  1468  				Str("collection_node", builder.rpcConf.CollectionAddr).
  1469  				Msg("using the static collection node address")
  1470  
  1471  			collectionRPCConn, err := grpc.Dial(
  1472  				builder.rpcConf.CollectionAddr,
  1473  				grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(int(builder.rpcConf.MaxMsgSize))),
  1474  				grpc.WithTransportCredentials(insecure.NewCredentials()),
  1475  				rpcConnection.WithClientTimeoutOption(builder.rpcConf.BackendConfig.CollectionClientTimeout))
  1476  			if err != nil {
  1477  				return err
  1478  			}
  1479  			builder.CollectionRPC = access.NewAccessAPIClient(collectionRPCConn)
  1480  			return nil
  1481  		}).
  1482  		Module("historical access node clients", func(node *cmd.NodeConfig) error {
  1483  			addrs := strings.Split(builder.rpcConf.HistoricalAccessAddrs, ",")
  1484  			for _, addr := range addrs {
  1485  				if strings.TrimSpace(addr) == "" {
  1486  					continue
  1487  				}
  1488  				node.Logger.Info().Str("access_nodes", addr).Msg("historical access node addresses")
  1489  
  1490  				historicalAccessRPCConn, err := grpc.Dial(
  1491  					addr,
  1492  					grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(int(builder.rpcConf.MaxMsgSize))),
  1493  					grpc.WithTransportCredentials(insecure.NewCredentials()))
  1494  				if err != nil {
  1495  					return err
  1496  				}
  1497  				builder.HistoricalAccessRPCs = append(builder.HistoricalAccessRPCs, access.NewAccessAPIClient(historicalAccessRPCConn))
  1498  			}
  1499  			return nil
  1500  		}).
  1501  		Module("transaction timing mempools", func(node *cmd.NodeConfig) error {
  1502  			var err error
  1503  			builder.TransactionTimings, err = stdmap.NewTransactionTimings(1500 * 300) // assume 1500 TPS * 300 seconds
  1504  			if err != nil {
  1505  				return err
  1506  			}
  1507  
  1508  			builder.CollectionsToMarkFinalized, err = stdmap.NewTimes(50 * 300) // assume 50 collection nodes * 300 seconds
  1509  			if err != nil {
  1510  				return err
  1511  			}
  1512  
  1513  			builder.CollectionsToMarkExecuted, err = stdmap.NewTimes(50 * 300) // assume 50 collection nodes * 300 seconds
  1514  			if err != nil {
  1515  				return err
  1516  			}
  1517  
  1518  			builder.BlocksToMarkExecuted, err = stdmap.NewTimes(1 * 300) // assume 1 block per second * 300 seconds
  1519  
  1520  			return err
  1521  		}).
  1522  		Module("transaction metrics", func(node *cmd.NodeConfig) error {
  1523  			builder.TransactionMetrics = metrics.NewTransactionCollector(
  1524  				node.Logger,
  1525  				builder.TransactionTimings,
  1526  				builder.logTxTimeToFinalized,
  1527  				builder.logTxTimeToExecuted,
  1528  				builder.logTxTimeToFinalizedExecuted,
  1529  			)
  1530  			return nil
  1531  		}).
  1532  		Module("rest metrics", func(node *cmd.NodeConfig) error {
  1533  			m, err := metrics.NewRestCollector(routes.URLToRoute, node.MetricsRegisterer)
  1534  			if err != nil {
  1535  				return err
  1536  			}
  1537  			builder.RestMetrics = m
  1538  			return nil
  1539  		}).
  1540  		Module("access metrics", func(node *cmd.NodeConfig) error {
  1541  			builder.AccessMetrics = metrics.NewAccessCollector(
  1542  				metrics.WithTransactionMetrics(builder.TransactionMetrics),
  1543  				metrics.WithBackendScriptsMetrics(builder.TransactionMetrics),
  1544  				metrics.WithRestMetrics(builder.RestMetrics),
  1545  			)
  1546  			return nil
  1547  		}).
  1548  		Module("collection metrics", func(node *cmd.NodeConfig) error {
  1549  			var err error
  1550  			builder.collectionExecutedMetric, err = indexer.NewCollectionExecutedMetricImpl(
  1551  				builder.Logger,
  1552  				builder.AccessMetrics,
  1553  				builder.CollectionsToMarkFinalized,
  1554  				builder.CollectionsToMarkExecuted,
  1555  				builder.BlocksToMarkExecuted,
  1556  				builder.Storage.Collections,
  1557  				builder.Storage.Blocks,
  1558  			)
  1559  			if err != nil {
  1560  				return err
  1561  			}
  1562  
  1563  			return nil
  1564  		}).
  1565  		Module("ping metrics", func(node *cmd.NodeConfig) error {
  1566  			builder.PingMetrics = metrics.NewPingCollector()
  1567  			return nil
  1568  		}).
  1569  		Module("server certificate", func(node *cmd.NodeConfig) error {
  1570  			// generate the server certificate that will be served by the GRPC server
  1571  			x509Certificate, err := grpcutils.X509Certificate(node.NetworkKey)
  1572  			if err != nil {
  1573  				return err
  1574  			}
  1575  			tlsConfig := grpcutils.DefaultServerTLSConfig(x509Certificate)
  1576  			builder.rpcConf.TransportCredentials = credentials.NewTLS(tlsConfig)
  1577  			return nil
  1578  		}).
  1579  		Module("creating grpc servers", func(node *cmd.NodeConfig) error {
  1580  			builder.secureGrpcServer = grpcserver.NewGrpcServerBuilder(
  1581  				node.Logger,
  1582  				builder.rpcConf.SecureGRPCListenAddr,
  1583  				builder.rpcConf.MaxMsgSize,
  1584  				builder.rpcMetricsEnabled,
  1585  				builder.apiRatelimits,
  1586  				builder.apiBurstlimits,
  1587  				grpcserver.WithTransportCredentials(builder.rpcConf.TransportCredentials)).Build()
  1588  
  1589  			builder.stateStreamGrpcServer = grpcserver.NewGrpcServerBuilder(
  1590  				node.Logger,
  1591  				builder.stateStreamConf.ListenAddr,
  1592  				builder.stateStreamConf.MaxExecutionDataMsgSize,
  1593  				builder.rpcMetricsEnabled,
  1594  				builder.apiRatelimits,
  1595  				builder.apiBurstlimits,
  1596  				grpcserver.WithStreamInterceptor()).Build()
  1597  
  1598  			if builder.rpcConf.UnsecureGRPCListenAddr != builder.stateStreamConf.ListenAddr {
  1599  				builder.unsecureGrpcServer = grpcserver.NewGrpcServerBuilder(node.Logger,
  1600  					builder.rpcConf.UnsecureGRPCListenAddr,
  1601  					builder.rpcConf.MaxMsgSize,
  1602  					builder.rpcMetricsEnabled,
  1603  					builder.apiRatelimits,
  1604  					builder.apiBurstlimits).Build()
  1605  			} else {
  1606  				builder.unsecureGrpcServer = builder.stateStreamGrpcServer
  1607  			}
  1608  
  1609  			return nil
  1610  		}).
  1611  		Module("backend script executor", func(node *cmd.NodeConfig) error {
  1612  			builder.ScriptExecutor = backend.NewScriptExecutor(builder.Logger, builder.scriptExecMinBlock, builder.scriptExecMaxBlock)
  1613  			return nil
  1614  		}).
  1615  		Module("async register store", func(node *cmd.NodeConfig) error {
  1616  			builder.RegistersAsyncStore = execution.NewRegistersAsyncStore()
  1617  			return nil
  1618  		}).
  1619  		Module("events storage", func(node *cmd.NodeConfig) error {
  1620  			builder.Storage.Events = bstorage.NewEvents(node.Metrics.Cache, node.DB)
  1621  			return nil
  1622  		}).
  1623  		Module("events index", func(node *cmd.NodeConfig) error {
  1624  			builder.EventsIndex = index.NewEventsIndex(builder.Storage.Events)
  1625  			return nil
  1626  		}).
  1627  		Module("transaction result index", func(node *cmd.NodeConfig) error {
  1628  			builder.TxResultsIndex = index.NewTransactionResultsIndex(builder.Storage.LightTransactionResults)
  1629  			return nil
  1630  		}).
  1631  		Module("processed block height consumer progress", func(node *cmd.NodeConfig) error {
  1632  			processedBlockHeight = bstorage.NewConsumerProgress(builder.DB, module.ConsumeProgressIngestionEngineBlockHeight)
  1633  			return nil
  1634  		}).
  1635  		Module("processed last full block height monotonic consumer progress", func(node *cmd.NodeConfig) error {
  1636  			rootBlockHeight := node.State.Params().FinalizedRoot().Height
  1637  
  1638  			var err error
  1639  			lastFullBlockHeight, err = counters.NewPersistentStrictMonotonicCounter(
  1640  				bstorage.NewConsumerProgress(builder.DB, module.ConsumeProgressLastFullBlockHeight),
  1641  				rootBlockHeight,
  1642  			)
  1643  			if err != nil {
  1644  				return fmt.Errorf("failed to initialize monotonic consumer progress: %w", err)
  1645  			}
  1646  
  1647  			return nil
  1648  		}).
  1649  		Component("RPC engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1650  			config := builder.rpcConf
  1651  			backendConfig := config.BackendConfig
  1652  			accessMetrics := builder.AccessMetrics
  1653  			cacheSize := int(backendConfig.ConnectionPoolSize)
  1654  
  1655  			var connBackendCache *rpcConnection.Cache
  1656  			var err error
  1657  			if cacheSize > 0 {
  1658  				connBackendCache, err = rpcConnection.NewCache(node.Logger, accessMetrics, cacheSize)
  1659  				if err != nil {
  1660  					return nil, fmt.Errorf("could not initialize connection cache: %w", err)
  1661  				}
  1662  			}
  1663  
  1664  			connFactory := &rpcConnection.ConnectionFactoryImpl{
  1665  				CollectionGRPCPort:        builder.collectionGRPCPort,
  1666  				ExecutionGRPCPort:         builder.executionGRPCPort,
  1667  				CollectionNodeGRPCTimeout: backendConfig.CollectionClientTimeout,
  1668  				ExecutionNodeGRPCTimeout:  backendConfig.ExecutionClientTimeout,
  1669  				AccessMetrics:             accessMetrics,
  1670  				Log:                       node.Logger,
  1671  				Manager: rpcConnection.NewManager(
  1672  					node.Logger,
  1673  					accessMetrics,
  1674  					connBackendCache,
  1675  					config.MaxMsgSize,
  1676  					backendConfig.CircuitBreakerConfig,
  1677  					config.CompressorName,
  1678  				),
  1679  			}
  1680  
  1681  			scriptExecMode, err := backend.ParseIndexQueryMode(config.BackendConfig.ScriptExecutionMode)
  1682  			if err != nil {
  1683  				return nil, fmt.Errorf("could not parse script execution mode: %w", err)
  1684  			}
  1685  
  1686  			eventQueryMode, err := backend.ParseIndexQueryMode(config.BackendConfig.EventQueryMode)
  1687  			if err != nil {
  1688  				return nil, fmt.Errorf("could not parse event query mode: %w", err)
  1689  			}
  1690  			if eventQueryMode == backend.IndexQueryModeCompare {
  1691  				return nil, fmt.Errorf("event query mode 'compare' is not supported")
  1692  			}
  1693  
  1694  			broadcaster := engine.NewBroadcaster()
  1695  			// create BlockTracker that will track for new blocks (finalized and sealed) and
  1696  			// handles block-related operations.
  1697  			blockTracker, err := subscription.NewBlockTracker(
  1698  				node.State,
  1699  				builder.FinalizedRootBlock.Header.Height,
  1700  				node.Storage.Headers,
  1701  				broadcaster,
  1702  			)
  1703  			if err != nil {
  1704  				return nil, fmt.Errorf("failed to initialize block tracker: %w", err)
  1705  			}
  1706  			txResultQueryMode, err := backend.ParseIndexQueryMode(config.BackendConfig.TxResultQueryMode)
  1707  			if err != nil {
  1708  				return nil, fmt.Errorf("could not parse transaction result query mode: %w", err)
  1709  			}
  1710  			if txResultQueryMode == backend.IndexQueryModeCompare {
  1711  				return nil, fmt.Errorf("transaction result query mode 'compare' is not supported")
  1712  			}
  1713  
  1714  			nodeBackend, err := backend.New(backend.Params{
  1715  				State:                     node.State,
  1716  				CollectionRPC:             builder.CollectionRPC,
  1717  				HistoricalAccessNodes:     builder.HistoricalAccessRPCs,
  1718  				Blocks:                    node.Storage.Blocks,
  1719  				Headers:                   node.Storage.Headers,
  1720  				Collections:               node.Storage.Collections,
  1721  				Transactions:              node.Storage.Transactions,
  1722  				ExecutionReceipts:         node.Storage.Receipts,
  1723  				ExecutionResults:          node.Storage.Results,
  1724  				ChainID:                   node.RootChainID,
  1725  				AccessMetrics:             builder.AccessMetrics,
  1726  				ConnFactory:               connFactory,
  1727  				RetryEnabled:              builder.retryEnabled,
  1728  				MaxHeightRange:            backendConfig.MaxHeightRange,
  1729  				PreferredExecutionNodeIDs: backendConfig.PreferredExecutionNodeIDs,
  1730  				FixedExecutionNodeIDs:     backendConfig.FixedExecutionNodeIDs,
  1731  				Log:                       node.Logger,
  1732  				SnapshotHistoryLimit:      backend.DefaultSnapshotHistoryLimit,
  1733  				Communicator:              backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled),
  1734  				TxResultCacheSize:         builder.TxResultCacheSize,
  1735  				TxErrorMessagesCacheSize:  builder.TxErrorMessagesCacheSize,
  1736  				ScriptExecutor:            builder.ScriptExecutor,
  1737  				ScriptExecutionMode:       scriptExecMode,
  1738  				EventQueryMode:            eventQueryMode,
  1739  				BlockTracker:              blockTracker,
  1740  				SubscriptionHandler: subscription.NewSubscriptionHandler(
  1741  					builder.Logger,
  1742  					broadcaster,
  1743  					builder.stateStreamConf.ClientSendTimeout,
  1744  					builder.stateStreamConf.ResponseLimit,
  1745  					builder.stateStreamConf.ClientSendBufferSize,
  1746  				),
  1747  				EventsIndex:         builder.EventsIndex,
  1748  				TxResultQueryMode:   txResultQueryMode,
  1749  				TxResultsIndex:      builder.TxResultsIndex,
  1750  				LastFullBlockHeight: lastFullBlockHeight,
  1751  			})
  1752  			if err != nil {
  1753  				return nil, fmt.Errorf("could not initialize backend: %w", err)
  1754  			}
  1755  
  1756  			engineBuilder, err := rpc.NewBuilder(
  1757  				node.Logger,
  1758  				node.State,
  1759  				config,
  1760  				node.RootChainID,
  1761  				builder.AccessMetrics,
  1762  				builder.rpcMetricsEnabled,
  1763  				builder.Me,
  1764  				nodeBackend,
  1765  				nodeBackend,
  1766  				builder.secureGrpcServer,
  1767  				builder.unsecureGrpcServer,
  1768  				builder.stateStreamBackend,
  1769  				builder.stateStreamConf,
  1770  			)
  1771  			if err != nil {
  1772  				return nil, err
  1773  			}
  1774  
  1775  			builder.RpcEng, err = engineBuilder.
  1776  				WithLegacy().
  1777  				WithBlockSignerDecoder(signature.NewBlockSignerDecoder(builder.Committee)).
  1778  				Build()
  1779  			if err != nil {
  1780  				return nil, err
  1781  			}
  1782  			builder.FollowerDistributor.AddOnBlockFinalizedConsumer(builder.RpcEng.OnFinalizedBlock)
  1783  
  1784  			return builder.RpcEng, nil
  1785  		}).
  1786  		Component("ingestion engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1787  			var err error
  1788  
  1789  			builder.RequestEng, err = requester.New(
  1790  				node.Logger,
  1791  				node.Metrics.Engine,
  1792  				node.EngineRegistry,
  1793  				node.Me,
  1794  				node.State,
  1795  				channels.RequestCollections,
  1796  				filter.HasRole[flow.Identity](flow.RoleCollection),
  1797  				func() flow.Entity { return &flow.Collection{} },
  1798  			)
  1799  			if err != nil {
  1800  				return nil, fmt.Errorf("could not create requester engine: %w", err)
  1801  			}
  1802  
  1803  			builder.IngestEng, err = ingestion.New(
  1804  				node.Logger,
  1805  				node.EngineRegistry,
  1806  				node.State,
  1807  				node.Me,
  1808  				builder.RequestEng,
  1809  				node.Storage.Blocks,
  1810  				node.Storage.Headers,
  1811  				node.Storage.Collections,
  1812  				node.Storage.Transactions,
  1813  				node.Storage.Results,
  1814  				node.Storage.Receipts,
  1815  				builder.collectionExecutedMetric,
  1816  				processedBlockHeight,
  1817  				lastFullBlockHeight,
  1818  			)
  1819  			if err != nil {
  1820  				return nil, err
  1821  			}
  1822  			ingestionDependable.Init(builder.IngestEng)
  1823  			builder.RequestEng.WithHandle(builder.IngestEng.OnCollection)
  1824  			builder.FollowerDistributor.AddOnBlockFinalizedConsumer(builder.IngestEng.OnFinalizedBlock)
  1825  
  1826  			return builder.IngestEng, nil
  1827  		}).
  1828  		Component("requester engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1829  			// We initialize the requester engine inside the ingestion engine due to the mutual dependency. However, in
  1830  			// order for it to properly start and shut down, we should still return it as its own engine here, so it can
  1831  			// be handled by the scaffold.
  1832  			return builder.RequestEng, nil
  1833  		})
  1834  
  1835  	if builder.supportsObserver {
  1836  		builder.Component("public sync request handler", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1837  			syncRequestHandler, err := synceng.NewRequestHandlerEngine(
  1838  				node.Logger.With().Bool("public", true).Logger(),
  1839  				unstaked.NewUnstakedEngineCollector(node.Metrics.Engine),
  1840  				builder.AccessNodeConfig.PublicNetworkConfig.Network,
  1841  				node.Me,
  1842  				node.State,
  1843  				node.Storage.Blocks,
  1844  				builder.SyncCore,
  1845  			)
  1846  			if err != nil {
  1847  				return nil, fmt.Errorf("could not create public sync request handler: %w", err)
  1848  			}
  1849  			builder.FollowerDistributor.AddFinalizationConsumer(syncRequestHandler)
  1850  
  1851  			return syncRequestHandler, nil
  1852  		})
  1853  	}
  1854  
  1855  	builder.Component("secure grpc server", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1856  		return builder.secureGrpcServer, nil
  1857  	})
  1858  
  1859  	builder.Component("state stream unsecure grpc server", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1860  		return builder.stateStreamGrpcServer, nil
  1861  	})
  1862  
  1863  	if builder.rpcConf.UnsecureGRPCListenAddr != builder.stateStreamConf.ListenAddr {
  1864  		builder.Component("unsecure grpc server", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1865  			return builder.unsecureGrpcServer, nil
  1866  		})
  1867  	}
  1868  
  1869  	if builder.pingEnabled {
  1870  		builder.Component("ping engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1871  			ping, err := pingeng.New(
  1872  				node.Logger,
  1873  				node.IdentityProvider,
  1874  				node.IDTranslator,
  1875  				node.Me,
  1876  				builder.PingMetrics,
  1877  				builder.nodeInfoFile,
  1878  				node.PingService,
  1879  			)
  1880  			if err != nil {
  1881  				return nil, fmt.Errorf("could not create ping engine: %w", err)
  1882  			}
  1883  
  1884  			return ping, nil
  1885  		})
  1886  	}
  1887  
  1888  	return builder.FlowNodeBuilder.Build()
  1889  }
  1890  
  1891  // enqueuePublicNetworkInit enqueues the public network component initialized for the staked node
  1892  func (builder *FlowAccessNodeBuilder) enqueuePublicNetworkInit() {
  1893  	var publicLibp2pNode p2p.LibP2PNode
  1894  	builder.
  1895  		Module("public network metrics", func(node *cmd.NodeConfig) error {
  1896  			builder.PublicNetworkConfig.Metrics = metrics.NewNetworkCollector(builder.Logger, metrics.WithNetworkPrefix("public"))
  1897  			return nil
  1898  		}).
  1899  		Component("public libp2p node", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1900  			var err error
  1901  			publicLibp2pNode, err = builder.initPublicLibp2pNode(
  1902  				builder.NodeConfig.NetworkKey,
  1903  				builder.PublicNetworkConfig.BindAddress,
  1904  				builder.PublicNetworkConfig.Metrics)
  1905  			if err != nil {
  1906  				return nil, fmt.Errorf("could not create public libp2p node: %w", err)
  1907  			}
  1908  
  1909  			return publicLibp2pNode, nil
  1910  		}).
  1911  		Component("public network", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1912  			msgValidators := publicNetworkMsgValidators(node.Logger.With().Bool("public", true).Logger(), node.IdentityProvider, builder.NodeID)
  1913  			receiveCache := netcache.NewHeroReceiveCache(builder.FlowConfig.NetworkConfig.NetworkReceivedMessageCacheSize,
  1914  				builder.Logger,
  1915  				metrics.NetworkReceiveCacheMetricsFactory(builder.HeroCacheMetricsFactory(), network.PublicNetwork))
  1916  
  1917  			err := node.Metrics.Mempool.Register(metrics.PrependPublicPrefix(metrics.ResourceNetworkingReceiveCache), receiveCache.Size)
  1918  			if err != nil {
  1919  				return nil, fmt.Errorf("could not register networking receive cache metric: %w", err)
  1920  			}
  1921  
  1922  			net, err := underlay.NewNetwork(&underlay.NetworkConfig{
  1923  				Logger:                builder.Logger.With().Str("module", "public-network").Logger(),
  1924  				Libp2pNode:            publicLibp2pNode,
  1925  				Codec:                 cborcodec.NewCodec(),
  1926  				Me:                    builder.Me,
  1927  				Topology:              topology.EmptyTopology{}, // topology returns empty list since peers are not known upfront
  1928  				Metrics:               builder.PublicNetworkConfig.Metrics,
  1929  				BitSwapMetrics:        builder.Metrics.Bitswap,
  1930  				IdentityProvider:      builder.IdentityProvider,
  1931  				ReceiveCache:          receiveCache,
  1932  				ConduitFactory:        conduit.NewDefaultConduitFactory(),
  1933  				SporkId:               builder.SporkID,
  1934  				UnicastMessageTimeout: underlay.DefaultUnicastTimeout,
  1935  				IdentityTranslator:    builder.IDTranslator,
  1936  				AlspCfg: &alspmgr.MisbehaviorReportManagerConfig{
  1937  					Logger:                  builder.Logger,
  1938  					SpamRecordCacheSize:     builder.FlowConfig.NetworkConfig.AlspConfig.SpamRecordCacheSize,
  1939  					SpamReportQueueSize:     builder.FlowConfig.NetworkConfig.AlspConfig.SpamReportQueueSize,
  1940  					DisablePenalty:          builder.FlowConfig.NetworkConfig.AlspConfig.DisablePenalty,
  1941  					HeartBeatInterval:       builder.FlowConfig.NetworkConfig.AlspConfig.HearBeatInterval,
  1942  					AlspMetrics:             builder.Metrics.Network,
  1943  					NetworkType:             network.PublicNetwork,
  1944  					HeroCacheMetricsFactory: builder.HeroCacheMetricsFactory(),
  1945  				},
  1946  				SlashingViolationConsumerFactory: func(adapter network.ConduitAdapter) network.ViolationsConsumer {
  1947  					return slashing.NewSlashingViolationsConsumer(builder.Logger, builder.Metrics.Network, adapter)
  1948  				},
  1949  			}, underlay.WithMessageValidators(msgValidators...))
  1950  			if err != nil {
  1951  				return nil, fmt.Errorf("could not initialize network: %w", err)
  1952  			}
  1953  
  1954  			builder.NetworkUnderlay = net
  1955  			builder.AccessNodeConfig.PublicNetworkConfig.Network = net
  1956  
  1957  			node.Logger.Info().Msgf("network will run on address: %s", builder.PublicNetworkConfig.BindAddress)
  1958  			return net, nil
  1959  		}).
  1960  		Component("public peer manager", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
  1961  			return publicLibp2pNode.PeerManagerComponent(), nil
  1962  		})
  1963  }
  1964  
  1965  // initPublicLibp2pNode initializes the public libp2p node for the public (unstaked) network.
  1966  // The LibP2P host is created with the following options:
  1967  //   - DHT as server
  1968  //   - The address from the node config or the specified bind address as the listen address
  1969  //   - The passed in private key as the libp2p key
  1970  //   - No connection gater
  1971  //   - Default Flow libp2p pubsub options
  1972  //
  1973  // Args:
  1974  //   - networkKey: The private key to use for the libp2p node
  1975  //
  1976  // - bindAddress: The address to bind the libp2p node to.
  1977  // - networkMetrics: The metrics collector for the network
  1978  // Returns:
  1979  // - The libp2p node instance for the public network.
  1980  // - Any error encountered during initialization. Any error should be considered fatal.
  1981  func (builder *FlowAccessNodeBuilder) initPublicLibp2pNode(networkKey crypto.PrivateKey, bindAddress string, networkMetrics module.LibP2PMetrics) (p2p.LibP2PNode,
  1982  	error,
  1983  ) {
  1984  	connManager, err := connection.NewConnManager(builder.Logger, networkMetrics, &builder.FlowConfig.NetworkConfig.ConnectionManager)
  1985  	if err != nil {
  1986  		return nil, fmt.Errorf("could not create connection manager: %w", err)
  1987  	}
  1988  	libp2pNode, err := p2pbuilder.NewNodeBuilder(builder.Logger, &builder.FlowConfig.NetworkConfig.GossipSub, &p2pbuilderconfig.MetricsConfig{
  1989  		HeroCacheFactory: builder.HeroCacheMetricsFactory(),
  1990  		Metrics:          networkMetrics,
  1991  	},
  1992  		network.PublicNetwork,
  1993  		bindAddress,
  1994  		networkKey,
  1995  		builder.SporkID,
  1996  		builder.IdentityProvider,
  1997  		&builder.FlowConfig.NetworkConfig.ResourceManager,
  1998  		&p2pbuilderconfig.PeerManagerConfig{
  1999  			// TODO: eventually, we need pruning enabled even on public network. However, it needs a modified version of
  2000  			// the peer manager that also operate on the public identities.
  2001  			ConnectionPruning: connection.PruningDisabled,
  2002  			UpdateInterval:    builder.FlowConfig.NetworkConfig.PeerUpdateInterval,
  2003  			ConnectorFactory:  connection.DefaultLibp2pBackoffConnectorFactory(),
  2004  		},
  2005  		&p2p.DisallowListCacheConfig{
  2006  			MaxSize: builder.FlowConfig.NetworkConfig.DisallowListNotificationCacheSize,
  2007  			Metrics: metrics.DisallowListCacheMetricsFactory(builder.HeroCacheMetricsFactory(), network.PublicNetwork),
  2008  		},
  2009  		&p2pbuilderconfig.UnicastConfig{
  2010  			Unicast: builder.FlowConfig.NetworkConfig.Unicast,
  2011  		}).
  2012  		SetBasicResolver(builder.Resolver).
  2013  		SetSubscriptionFilter(networkingsubscription.NewRoleBasedFilter(flow.RoleAccess, builder.IdentityProvider)).
  2014  		SetConnectionManager(connManager).
  2015  		SetRoutingSystem(func(ctx context.Context, h host.Host) (routing.Routing, error) {
  2016  			return dht.NewDHT(ctx, h, protocols.FlowPublicDHTProtocolID(builder.SporkID), builder.Logger, networkMetrics, dht.AsServer())
  2017  		}).
  2018  		Build()
  2019  	if err != nil {
  2020  		return nil, fmt.Errorf("could not build libp2p node for staked access node: %w", err)
  2021  	}
  2022  
  2023  	return libp2pNode, nil
  2024  }