-
Notifications
You must be signed in to change notification settings - Fork 175
/
node_builder.go
311 lines (270 loc) · 12.2 KB
/
node_builder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
package cmd
import (
"context"
"os"
"path/filepath"
"runtime"
"time"
"github.com/dgraph-io/badger/v2"
madns "github.com/multiformats/go-multiaddr-dns"
"github.com/prometheus/client_golang/prometheus"
"github.com/rs/zerolog"
"github.com/spf13/pflag"
"github.com/onflow/flow-go/admin/commands"
"github.com/onflow/flow-go/crypto"
"github.com/onflow/flow-go/fvm"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module"
"github.com/onflow/flow-go/module/chainsync"
"github.com/onflow/flow-go/module/compliance"
"github.com/onflow/flow-go/module/component"
"github.com/onflow/flow-go/module/updatable_configs"
"github.com/onflow/flow-go/network"
"github.com/onflow/flow-go/network/codec/cbor"
"github.com/onflow/flow-go/network/p2p"
"github.com/onflow/flow-go/network/p2p/connection"
"github.com/onflow/flow-go/network/p2p/dns"
"github.com/onflow/flow-go/network/p2p/middleware"
"github.com/onflow/flow-go/network/p2p/p2pnode"
"github.com/onflow/flow-go/network/p2p/scoring"
"github.com/onflow/flow-go/state/protocol"
"github.com/onflow/flow-go/state/protocol/events"
bstorage "github.com/onflow/flow-go/storage/badger"
"github.com/onflow/flow-go/utils/grpcutils"
)
const NotSet = "not set"
type BuilderFunc func(nodeConfig *NodeConfig) error
type ReadyDoneFactory func(node *NodeConfig) (module.ReadyDoneAware, error)
// NodeBuilder declares the initialization methods needed to bootstrap up a Flow node
type NodeBuilder interface {
// BaseFlags reads the command line arguments common to all nodes
BaseFlags()
// ExtraFlags reads the node specific command line arguments and adds it to the FlagSet
ExtraFlags(f func(*pflag.FlagSet)) NodeBuilder
// ParseAndPrintFlags parses and validates all the command line arguments
ParseAndPrintFlags() error
// Initialize performs all the initialization needed at the very start of a node
Initialize() error
// PrintBuildVersionDetails prints the node software build version
PrintBuildVersionDetails()
// InitIDProviders initializes the ID providers needed by various components
InitIDProviders()
// EnqueueNetworkInit enqueues the default networking layer.
EnqueueNetworkInit()
// EnqueueMetricsServerInit enqueues the metrics component.
EnqueueMetricsServerInit()
// EnqueueTracer enqueues the Tracer component.
EnqueueTracer()
// Module enables setting up dependencies of the engine with the builder context
Module(name string, f BuilderFunc) NodeBuilder
// Component adds a new component to the node that conforms to the ReadyDoneAware
// interface, and throws a Fatal() when an irrecoverable error is encountered.
//
// The ReadyDoneFactory may return either a `Component` or `ReadyDoneAware` instance.
// In both cases, the object is started according to its interface when the node is run,
// and the node will wait for the component to exit gracefully.
Component(name string, f ReadyDoneFactory) NodeBuilder
// DependableComponent adds a new component to the node that conforms to the ReadyDoneAware
// interface. The builder will wait until all of the components in the dependencies list are ready
// before constructing the component.
//
// The ReadyDoneFactory may return either a `Component` or `ReadyDoneAware` instance.
// In both cases, the object is started when the node is run, and the node will wait for the
// component to exit gracefully.
//
// IMPORTANT: Dependable components are started in parallel with no guaranteed run order, so all
// dependencies must be initialized outside of the ReadyDoneFactory, and their `Ready()` method
// MUST be idempotent.
DependableComponent(name string, f ReadyDoneFactory, dependencies *DependencyList) NodeBuilder
// RestartableComponent adds a new component to the node that conforms to the ReadyDoneAware
// interface, and calls the provided error handler when an irrecoverable error is encountered.
// Use RestartableComponent if the component is not critical to the node's safe operation and
// can/should be independently restarted when an irrecoverable error is encountered.
//
// Any irrecoverable errors thrown by the component will be passed to the provided error handler.
RestartableComponent(name string, f ReadyDoneFactory, errorHandler component.OnError) NodeBuilder
// ShutdownFunc adds a callback function that is called after all components have exited.
// All shutdown functions are called regardless of errors returned by previous callbacks. Any
// errors returned are captured and passed to the caller.
ShutdownFunc(fn func() error) NodeBuilder
// AdminCommand registers a new admin command with the admin server
AdminCommand(command string, f func(config *NodeConfig) commands.AdminCommand) NodeBuilder
// MustNot asserts that the given error must not occur.
// If the error is nil, returns a nil log event (which acts as a no-op).
// If the error is not nil, returns a fatal log event containing the error.
MustNot(err error) *zerolog.Event
// Build finalizes the node configuration in preparation for start and returns a Node
// object that can be run
Build() (Node, error)
// PreInit registers a new PreInit function.
// PreInit functions run before the protocol state is initialized or any other modules or components are initialized
PreInit(f BuilderFunc) NodeBuilder
// PostInit registers a new PreInit function.
// PostInit functions run after the protocol state has been initialized but before any other modules or components
// are initialized
PostInit(f BuilderFunc) NodeBuilder
// RegisterBadgerMetrics registers all badger related metrics
RegisterBadgerMetrics() error
// ValidateFlags sets any custom validation rules for the command line flags,
// for example where certain combinations aren't allowed
ValidateFlags(func() error) NodeBuilder
}
// BaseConfig is the general config for the NodeBuilder and the command line params
// For a node running as a standalone process, the config fields will be populated from the command line params,
// while for a node running as a library, the config fields are expected to be initialized by the caller.
type BaseConfig struct {
NetworkConfig
nodeIDHex string
AdminAddr string
AdminCert string
AdminKey string
AdminClientCAs string
AdminMaxMsgSize uint
BindAddr string
NodeRole string
DynamicStartupANAddress string
DynamicStartupANPubkey string
DynamicStartupEpochPhase string
DynamicStartupEpoch string
DynamicStartupSleepInterval time.Duration
datadir string
secretsdir string
secretsDBEnabled bool
InsecureSecretsDB bool
level string
metricsPort uint
BootstrapDir string
profilerEnabled bool
uploaderEnabled bool
profilerDir string
profilerInterval time.Duration
profilerDuration time.Duration
profilerMemProfileRate int
tracerEnabled bool
tracerSensitivity uint
MetricsEnabled bool
guaranteesCacheSize uint
receiptsCacheSize uint
db *badger.DB
HeroCacheMetricsEnable bool
SyncCoreConfig chainsync.Config
CodecFactory func() network.Codec
LibP2PNode *p2pnode.Node
// ComplianceConfig configures either the compliance engine (consensus nodes)
// or the follower engine (all other node roles)
ComplianceConfig compliance.Config
}
type NetworkConfig struct {
// NetworkConnectionPruning determines whether connections to nodes
// that are not part of protocol state should be trimmed
// TODO: solely a fallback mechanism, can be removed upon reliable behavior in production.
NetworkConnectionPruning bool
PeerScoringEnabled bool // enables peer scoring on pubsub
PreferredUnicastProtocols []string
NetworkReceivedMessageCacheSize uint32
PeerUpdateInterval time.Duration
UnicastMessageTimeout time.Duration
DNSCacheTTL time.Duration
}
// NodeConfig contains all the derived parameters such the NodeID, private keys etc. and initialized instances of
// structs such as DB, Network etc. The NodeConfig is composed of the BaseConfig and is updated in the
// NodeBuilder functions as a node is bootstrapped.
type NodeConfig struct {
Cancel context.CancelFunc // cancel function for the context that is passed to the networking layer
BaseConfig
Logger zerolog.Logger
NodeID flow.Identifier
Me module.Local
Tracer module.Tracer
ConfigManager *updatable_configs.Manager
MetricsRegisterer prometheus.Registerer
Metrics Metrics
DB *badger.DB
SecretsDB *badger.DB
Storage Storage
ProtocolEvents *events.Distributor
State protocol.State
Resolver madns.BasicResolver
Middleware network.Middleware
Network network.Network
PingService network.PingService
MsgValidators []network.MessageValidator
FvmOptions []fvm.Option
StakingKey crypto.PrivateKey
NetworkKey crypto.PrivateKey
// list of dependencies for network peer manager startup
PeerManagerDependencies *DependencyList
// ReadyDoneAware implementation of the network middleware for DependableComponents
middlewareDependable *module.ProxiedReadyDoneAware
// ID providers
IdentityProvider module.IdentityProvider
IDTranslator p2p.IDTranslator
SyncEngineIdentifierProvider module.IdentifierProvider
// root state information
RootSnapshot protocol.Snapshot
// cached properties of RootSnapshot for convenience
RootBlock *flow.Block
RootQC *flow.QuorumCertificate
RootResult *flow.ExecutionResult
RootSeal *flow.Seal
RootChainID flow.ChainID
SporkID flow.Identifier
// bootstrapping options
SkipNwAddressBasedValidations bool
}
func DefaultBaseConfig() *BaseConfig {
homedir, _ := os.UserHomeDir()
datadir := filepath.Join(homedir, ".flow", "database")
// NOTE: if the codec used in the network component is ever changed any code relying on
// the message format specific to the codec must be updated. i.e: the AuthorizedSenderValidator.
codecFactory := func() network.Codec { return cbor.NewCodec() }
return &BaseConfig{
NetworkConfig: NetworkConfig{
PeerUpdateInterval: connection.DefaultPeerUpdateInterval,
UnicastMessageTimeout: middleware.DefaultUnicastTimeout,
NetworkReceivedMessageCacheSize: p2p.DefaultReceiveCacheSize,
// By default we let networking layer trim connections to all nodes that
// are no longer part of protocol state.
NetworkConnectionPruning: connection.ConnectionPruningEnabled,
PeerScoringEnabled: scoring.DefaultPeerScoringEnabled,
DNSCacheTTL: dns.DefaultTimeToLive,
},
nodeIDHex: NotSet,
AdminAddr: NotSet,
AdminCert: NotSet,
AdminKey: NotSet,
AdminClientCAs: NotSet,
AdminMaxMsgSize: grpcutils.DefaultMaxMsgSize,
BindAddr: NotSet,
BootstrapDir: "bootstrap",
datadir: datadir,
secretsdir: NotSet,
secretsDBEnabled: true,
level: "info",
metricsPort: 8080,
profilerEnabled: false,
uploaderEnabled: false,
profilerDir: "profiler",
profilerInterval: 15 * time.Minute,
profilerDuration: 10 * time.Second,
profilerMemProfileRate: runtime.MemProfileRate,
tracerEnabled: false,
tracerSensitivity: 4,
MetricsEnabled: true,
receiptsCacheSize: bstorage.DefaultCacheSize,
guaranteesCacheSize: bstorage.DefaultCacheSize,
HeroCacheMetricsEnable: false,
SyncCoreConfig: chainsync.DefaultConfig(),
CodecFactory: codecFactory,
ComplianceConfig: compliance.DefaultConfig(),
}
}
// DependencyList is a slice of ReadyDoneAware implementations that are used by DependableComponent
// to define the list of depenencies that must be ready before starting the component.
type DependencyList struct {
components []module.ReadyDoneAware
}
// Add adds a new ReadyDoneAware implementation to the list of dependencies.
func (d *DependencyList) Add(component module.ReadyDoneAware) {
d.components = append(d.components, component)
}