-
Notifications
You must be signed in to change notification settings - Fork 322
/
config.go
437 lines (396 loc) · 15.8 KB
/
config.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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
// Copyright (c) 2019 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.
package config
import (
"os"
"strings"
"time"
"github.com/pkg/errors"
uconfig "go.uber.org/config"
"github.com/iotexproject/iotex-core/actpool"
"github.com/iotexproject/iotex-core/blockchain"
"github.com/iotexproject/iotex-core/blockchain/genesis"
"github.com/iotexproject/iotex-core/blockindex"
"github.com/iotexproject/iotex-core/db"
"github.com/iotexproject/iotex-core/dispatcher"
"github.com/iotexproject/iotex-core/p2p"
"github.com/iotexproject/iotex-core/pkg/log"
"github.com/iotexproject/iotex-core/pkg/tracer"
"github.com/iotexproject/iotex-core/pkg/unit"
)
// IMPORTANT: to define a config, add a field or a new config type to the existing config types. In addition, provide
// the default value in Default var.
const (
// RollDPoSScheme means randomized delegated proof of stake
RollDPoSScheme = "ROLLDPOS"
// StandaloneScheme means that the node creates a block periodically regardless of others (if there is any)
StandaloneScheme = "STANDALONE"
// NOOPScheme means that the node does not create only block
NOOPScheme = "NOOP"
)
const (
// GatewayPlugin is the plugin of accepting user API requests and serving blockchain data to users
GatewayPlugin = iota
)
type strs []string
func (ss *strs) String() string {
return strings.Join(*ss, ",")
}
func (ss *strs) Set(str string) error {
*ss = append(*ss, str)
return nil
}
// Dardanelles consensus config
var (
// Default is the default config
Default = Config{
Plugins: make(map[int]interface{}),
SubLogs: make(map[string]log.GlobalConfig),
Network: p2p.DefaultConfig,
Chain: blockchain.DefaultConfig,
ActPool: actpool.DefaultConfig,
Consensus: Consensus{
Scheme: StandaloneScheme,
RollDPoS: RollDPoS{
FSM: ConsensusTiming{
UnmatchedEventTTL: 3 * time.Second,
UnmatchedEventInterval: 100 * time.Millisecond,
AcceptBlockTTL: 4 * time.Second,
AcceptProposalEndorsementTTL: 2 * time.Second,
AcceptLockEndorsementTTL: 2 * time.Second,
CommitTTL: 2 * time.Second,
EventChanSize: 10000,
},
ToleratedOvertime: 2 * time.Second,
Delay: 5 * time.Second,
ConsensusDBPath: "/var/data/consensus.db",
},
},
DardanellesUpgrade: DardanellesUpgrade{
UnmatchedEventTTL: 2 * time.Second,
UnmatchedEventInterval: 100 * time.Millisecond,
AcceptBlockTTL: 2 * time.Second,
AcceptProposalEndorsementTTL: time.Second,
AcceptLockEndorsementTTL: time.Second,
CommitTTL: time.Second,
BlockInterval: 5 * time.Second,
Delay: 2 * time.Second,
},
BlockSync: BlockSync{
Interval: 30 * time.Second,
ProcessSyncRequestTTL: 10 * time.Second,
BufferSize: 200,
IntervalSize: 20,
MaxRepeat: 3,
RepeatDecayStep: 1,
},
Dispatcher: dispatcher.DefaultConfig,
API: API{
UseRDS: false,
GRPCPort: 14014,
HTTPPort: 15014,
WebSocketPort: 16014,
TpsWindow: 10,
GasStation: GasStation{
SuggestBlockWindow: 20,
DefaultGas: uint64(unit.Qev),
Percentile: 60,
},
RangeQueryLimit: 1000,
},
System: System{
Active: true,
HeartbeatInterval: 10 * time.Second,
HTTPStatsPort: 8080,
HTTPAdminPort: 0,
StartSubChainInterval: 10 * time.Second,
SystemLogDBPath: "/var/log",
},
DB: db.DefaultConfig,
Indexer: blockindex.DefaultConfig,
Genesis: genesis.Default,
}
// ErrInvalidCfg indicates the invalid config value
ErrInvalidCfg = errors.New("invalid config value")
// Validates is the collection config validation functions
Validates = []Validate{
ValidateRollDPoS,
ValidateArchiveMode,
ValidateDispatcher,
ValidateAPI,
ValidateActPool,
ValidateForkHeights,
}
)
// Network is the config struct for network package
type (
// Consensus is the config struct for consensus package
Consensus struct {
// There are three schemes that are supported
Scheme string `yaml:"scheme"`
RollDPoS RollDPoS `yaml:"rollDPoS"`
}
// BlockSync is the config struct for the BlockSync
BlockSync struct {
Interval time.Duration `yaml:"interval"` // update duration
ProcessSyncRequestTTL time.Duration `yaml:"processSyncRequestTTL"`
BufferSize uint64 `yaml:"bufferSize"`
IntervalSize uint64 `yaml:"intervalSize"`
// MaxRepeat is the maximal number of repeat of a block sync request
MaxRepeat int `yaml:"maxRepeat"`
// RepeatDecayStep is the step for repeat number decreasing by 1
RepeatDecayStep int `yaml:"repeatDecayStep"`
}
// DardanellesUpgrade is the config for dardanelles upgrade
DardanellesUpgrade struct {
UnmatchedEventTTL time.Duration `yaml:"unmatchedEventTTL"`
UnmatchedEventInterval time.Duration `yaml:"unmatchedEventInterval"`
AcceptBlockTTL time.Duration `yaml:"acceptBlockTTL"`
AcceptProposalEndorsementTTL time.Duration `yaml:"acceptProposalEndorsementTTL"`
AcceptLockEndorsementTTL time.Duration `yaml:"acceptLockEndorsementTTL"`
CommitTTL time.Duration `yaml:"commitTTL"`
BlockInterval time.Duration `yaml:"blockInterval"`
Delay time.Duration `yaml:"delay"`
}
// RollDPoS is the config struct for RollDPoS consensus package
RollDPoS struct {
FSM ConsensusTiming `yaml:"fsm"`
ToleratedOvertime time.Duration `yaml:"toleratedOvertime"`
Delay time.Duration `yaml:"delay"`
ConsensusDBPath string `yaml:"consensusDBPath"`
}
// ConsensusTiming defines a set of time durations used in fsm and event queue size
ConsensusTiming struct {
EventChanSize uint `yaml:"eventChanSize"`
UnmatchedEventTTL time.Duration `yaml:"unmatchedEventTTL"`
UnmatchedEventInterval time.Duration `yaml:"unmatchedEventInterval"`
AcceptBlockTTL time.Duration `yaml:"acceptBlockTTL"`
AcceptProposalEndorsementTTL time.Duration `yaml:"acceptProposalEndorsementTTL"`
AcceptLockEndorsementTTL time.Duration `yaml:"acceptLockEndorsementTTL"`
CommitTTL time.Duration `yaml:"commitTTL"`
}
// API is the api service config
API struct {
UseRDS bool `yaml:"useRDS"`
GRPCPort int `yaml:"port"`
HTTPPort int `yaml:"web3port"`
WebSocketPort int `yaml:"webSocketPort"`
RedisCacheURL string `yaml:"redisCacheURL"`
TpsWindow int `yaml:"tpsWindow"`
GasStation GasStation `yaml:"gasStation"`
RangeQueryLimit uint64 `yaml:"rangeQueryLimit"`
Tracer tracer.Config `yaml:"tracer"`
}
// GasStation is the gas station config
GasStation struct {
SuggestBlockWindow int `yaml:"suggestBlockWindow"`
DefaultGas uint64 `yaml:"defaultGas"`
Percentile int `yaml:"Percentile"`
}
// System is the system config
System struct {
// Active is the status of the node. True means active and false means stand-by
Active bool `yaml:"active"`
HeartbeatInterval time.Duration `yaml:"heartbeatInterval"`
// HTTPProfilingPort is the port number to access golang performance profiling data of a blockchain node. It is
// 0 by default, meaning performance profiling has been disabled
HTTPAdminPort int `yaml:"httpAdminPort"`
HTTPStatsPort int `yaml:"httpStatsPort"`
StartSubChainInterval time.Duration `yaml:"startSubChainInterval"`
SystemLogDBPath string `yaml:"systemLogDBPath"`
}
// Config is the root config struct, each package's config should be put as its sub struct
Config struct {
Plugins map[int]interface{} `ymal:"plugins"`
Network p2p.Config `yaml:"network"`
Chain blockchain.Config `yaml:"chain"`
ActPool actpool.Config `yaml:"actPool"`
Consensus Consensus `yaml:"consensus"`
DardanellesUpgrade DardanellesUpgrade `yaml:"dardanellesUpgrade"`
BlockSync BlockSync `yaml:"blockSync"`
Dispatcher dispatcher.Config `yaml:"dispatcher"`
API API `yaml:"api"`
System System `yaml:"system"`
DB db.Config `yaml:"db"`
Indexer blockindex.Config `yaml:"indexer"`
Log log.GlobalConfig `yaml:"log"`
SubLogs map[string]log.GlobalConfig `yaml:"subLogs"`
Genesis genesis.Genesis `yaml:"genesis"`
}
// Validate is the interface of validating the config
Validate func(Config) error
)
// New creates a config instance. It first loads the default configs. If the config path is not empty, it will read from
// the file and override the default configs. By default, it will apply all validation functions. To bypass validation,
// use DoNotValidate instead.
func New(configPaths []string, _plugins []string, validates ...Validate) (Config, error) {
opts := make([]uconfig.YAMLOption, 0)
opts = append(opts, uconfig.Static(Default))
opts = append(opts, uconfig.Expand(os.LookupEnv))
for _, path := range configPaths {
if path != "" {
opts = append(opts, uconfig.File(path))
}
}
yaml, err := uconfig.NewYAML(opts...)
if err != nil {
return Config{}, errors.Wrap(err, "failed to init config")
}
var cfg Config
if err := yaml.Get(uconfig.Root).Populate(&cfg); err != nil {
return Config{}, errors.Wrap(err, "failed to unmarshal YAML config to struct")
}
if err := cfg.Chain.SetProducerPrivKey(); err != nil {
return Config{}, errors.Wrap(err, "failed to set producer private key")
}
// set network master key to private key
if cfg.Network.MasterKey == "" {
cfg.Network.MasterKey = cfg.Chain.ProducerPrivKey
}
// set plugins
for _, plugin := range _plugins {
switch strings.ToLower(plugin) {
case "gateway":
cfg.Plugins[GatewayPlugin] = nil
default:
return Config{}, errors.Errorf("Plugin %s is not supported", plugin)
}
}
// By default, the config needs to pass all the validation
if len(validates) == 0 {
validates = Validates
}
for _, validate := range validates {
if err := validate(cfg); err != nil {
return Config{}, errors.Wrap(err, "failed to validate config")
}
}
return cfg, nil
}
// NewSub create config for sub chain.
func NewSub(configPaths []string, validates ...Validate) (Config, error) {
opts := make([]uconfig.YAMLOption, 0)
opts = append(opts, uconfig.Static(Default))
opts = append(opts, uconfig.Expand(os.LookupEnv))
for _, path := range configPaths {
if path != "" {
opts = append(opts, uconfig.File(path))
}
}
yaml, err := uconfig.NewYAML(opts...)
if err != nil {
return Config{}, errors.Wrap(err, "failed to init config")
}
var cfg Config
if err := yaml.Get(uconfig.Root).Populate(&cfg); err != nil {
return Config{}, errors.Wrap(err, "failed to unmarshal YAML config to struct")
}
// By default, the config needs to pass all the validation
if len(validates) == 0 {
validates = Validates
}
for _, validate := range validates {
if err := validate(cfg); err != nil {
return Config{}, errors.Wrap(err, "failed to validate config")
}
}
return cfg, nil
}
// ValidateDispatcher validates the dispatcher configs
func ValidateDispatcher(cfg Config) error {
if cfg.Dispatcher.ActionChanSize <= 0 || cfg.Dispatcher.BlockChanSize <= 0 || cfg.Dispatcher.BlockSyncChanSize <= 0 {
return errors.Wrap(ErrInvalidCfg, "dispatcher chan size should be greater than 0")
}
if cfg.Dispatcher.ProcessSyncRequestInterval < 0 {
return errors.Wrap(ErrInvalidCfg, "dispatcher processSyncRequestInterval should not be less than 0")
}
return nil
}
// ValidateRollDPoS validates the roll-DPoS configs
func ValidateRollDPoS(cfg Config) error {
if cfg.Consensus.Scheme != RollDPoSScheme {
return nil
}
rollDPoS := cfg.Consensus.RollDPoS
fsm := rollDPoS.FSM
if fsm.EventChanSize <= 0 {
return errors.Wrap(ErrInvalidCfg, "roll-DPoS event chan size should be greater than 0")
}
return nil
}
// ValidateArchiveMode validates the state factory setting
func ValidateArchiveMode(cfg Config) error {
if !cfg.Chain.EnableArchiveMode || !cfg.Chain.EnableTrielessStateDB {
return nil
}
return errors.Wrap(ErrInvalidCfg, "Archive mode is incompatible with trieless state DB")
}
// ValidateAPI validates the api configs
func ValidateAPI(cfg Config) error {
if cfg.API.TpsWindow <= 0 {
return errors.Wrap(ErrInvalidCfg, "tps window is not a positive integer when the api is enabled")
}
return nil
}
// ValidateActPool validates the given config
func ValidateActPool(cfg Config) error {
maxNumActPerPool := cfg.ActPool.MaxNumActsPerPool
maxNumActPerAcct := cfg.ActPool.MaxNumActsPerAcct
if maxNumActPerPool <= 0 || maxNumActPerAcct <= 0 {
return errors.Wrap(
ErrInvalidCfg,
"maximum number of actions per pool or per account cannot be zero or negative",
)
}
if maxNumActPerPool < maxNumActPerAcct {
return errors.Wrap(
ErrInvalidCfg,
"maximum number of actions per pool cannot be less than maximum number of actions per account",
)
}
return nil
}
// ValidateForkHeights validates the forked heights
func ValidateForkHeights(cfg Config) error {
hu := cfg.Genesis
switch {
case hu.PacificBlockHeight > hu.AleutianBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Pacific is heigher than Aleutian")
case hu.AleutianBlockHeight > hu.BeringBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Aleutian is heigher than Bering")
case hu.BeringBlockHeight > hu.CookBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Bering is heigher than Cook")
case hu.CookBlockHeight > hu.DardanellesBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Cook is heigher than Dardanelles")
case hu.DardanellesBlockHeight > hu.DaytonaBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Dardanelles is heigher than Daytona")
case hu.DaytonaBlockHeight > hu.EasterBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Daytona is heigher than Easter")
case hu.EasterBlockHeight > hu.FbkMigrationBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Easter is heigher than FairbankMigration")
case hu.FbkMigrationBlockHeight > hu.FairbankBlockHeight:
return errors.Wrap(ErrInvalidCfg, "FairbankMigration is heigher than Fairbank")
case hu.FairbankBlockHeight > hu.GreenlandBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Fairbank is heigher than Greenland")
case hu.GreenlandBlockHeight > hu.IcelandBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Greenland is heigher than Iceland")
case hu.IcelandBlockHeight > hu.JutlandBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Iceland is heigher than Jutland")
case hu.JutlandBlockHeight > hu.KamchatkaBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Jutland is heigher than Kamchatka")
case hu.KamchatkaBlockHeight > hu.LordHoweBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Kamchatka is heigher than LordHowe")
case hu.LordHoweBlockHeight > hu.MidwayBlockHeight:
return errors.Wrap(ErrInvalidCfg, "LordHowe is heigher than Midway")
case hu.MidwayBlockHeight > hu.NewfoundlandBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Midway is heigher than Newfoundland")
case hu.NewfoundlandBlockHeight > hu.OkhotskBlockHeight:
return errors.Wrap(ErrInvalidCfg, "Newfoundland is heigher than Okhotsk")
}
return nil
}
// DoNotValidate validates the given config
func DoNotValidate(cfg Config) error { return nil }