forked from yinchengtsinghua/golang-bitcoin-chinese
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.go
1190 lines (1070 loc) · 43.5 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
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//此源码被清华学神尹成大魔王专业翻译分析并修改
//尹成QQ77025077
//尹成微信18510341407
//尹成所在QQ群721929980
//尹成邮箱 [email protected]
//尹成毕业于清华大学,微软区块链领域全球最有价值专家
//https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
//版权所有(c)2013-2017 BTCSuite开发者
//此源代码的使用由ISC控制
//可以在许可文件中找到的许可证。
package main
import (
"bufio"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"net"
"os"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
"time"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/connmgr"
"github.com/btcsuite/btcd/database"
_ "github.com/btcsuite/btcd/database/ffldb"
"github.com/btcsuite/btcd/mempool"
"github.com/btcsuite/btcd/peer"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/go-socks/socks"
flags "github.com/jessevdk/go-flags"
)
const (
defaultConfigFilename = "btcd.conf"
defaultDataDirname = "data"
defaultLogLevel = "info"
defaultLogDirname = "logs"
defaultLogFilename = "btcd.log"
defaultMaxPeers = 125
defaultBanDuration = time.Hour * 24
defaultBanThreshold = 100
defaultConnectTimeout = time.Second * 30
defaultMaxRPCClients = 10
defaultMaxRPCWebsockets = 25
defaultMaxRPCConcurrentReqs = 20
defaultDbType = "ffldb"
defaultFreeTxRelayLimit = 15.0
defaultTrickleInterval = peer.DefaultTrickleInterval
defaultBlockMinSize = 0
defaultBlockMaxSize = 750000
defaultBlockMinWeight = 0
defaultBlockMaxWeight = 3000000
blockMaxSizeMin = 1000
blockMaxSizeMax = blockchain.MaxBlockBaseSize - 1000
blockMaxWeightMin = 4000
blockMaxWeightMax = blockchain.MaxBlockWeight - 4000
defaultGenerate = false
defaultMaxOrphanTransactions = 100
defaultMaxOrphanTxSize = 100000
defaultSigCacheMaxSize = 100000
sampleConfigFilename = "sample-btcd.conf"
defaultTxIndex = false
defaultAddrIndex = false
)
var (
defaultHomeDir = btcutil.AppDataDir("btcd", false)
defaultConfigFile = filepath.Join(defaultHomeDir, defaultConfigFilename)
defaultDataDir = filepath.Join(defaultHomeDir, defaultDataDirname)
knownDbTypes = database.SupportedDrivers()
defaultRPCKeyFile = filepath.Join(defaultHomeDir, "rpc.key")
defaultRPCCertFile = filepath.Join(defaultHomeDir, "rpc.cert")
defaultLogDir = filepath.Join(defaultHomeDir, defaultLogDirname)
)
//runservicecommand仅在Windows上设置为实函数。它被使用
//解析和执行通过-s标志指定的服务命令。
var runServiceCommand func(string) error
//minint32是一个帮助函数,返回至少两个uint32。
//这样就避免了数学导入和强制转换为浮点。
func minUint32(a, b uint32) uint32 {
if a < b {
return a
}
return b
}
//config定义btcd的配置选项。
//
//有关配置加载过程的详细信息,请参阅loadconfig。
type config struct {
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"`
DataDir string `short:"b" long:"datadir" description:"Directory to store data"`
LogDir string `long:"logdir" description:"Directory to log output."`
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"`
DisableListen bool `long:"nolisten" description:"Disable listening for incoming connections -- NOTE: Listening is automatically disabled if the --connect or --proxy options are used without also specifying listen interfaces via --listen"`
Listeners []string `long:"listen" description:"Add an interface/port to listen for connections (default all interfaces port: 8333, testnet: 18333)"`
MaxPeers int `long:"maxpeers" description:"Max number of inbound and outbound peers"`
DisableBanning bool `long:"nobanning" description:"Disable banning of misbehaving peers"`
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
Whitelists []string `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"`
RPCUser string `short:"u" long:"rpcuser" description:"Username for RPC connections"`
RPCPass string `short:"P" long:"rpcpass" default-mask:"-" description:"Password for RPC connections"`
RPCLimitUser string `long:"rpclimituser" description:"Username for limited RPC connections"`
RPCLimitPass string `long:"rpclimitpass" default-mask:"-" description:"Password for limited RPC connections"`
RPCListeners []string `long:"rpclisten" description:"Add an interface/port to listen for RPC connections (default port: 8334, testnet: 18334)"`
RPCCert string `long:"rpccert" description:"File containing the certificate file"`
RPCKey string `long:"rpckey" description:"File containing the certificate key"`
RPCMaxClients int `long:"rpcmaxclients" description:"Max number of RPC clients for standard connections"`
RPCMaxWebsockets int `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"`
RPCMaxConcurrentReqs int `long:"rpcmaxconcurrentreqs" description:"Max number of concurrent RPC requests that may be processed concurrently"`
RPCQuirks bool `long:"rpcquirks" description:"Mirror some JSON-RPC quirks of Bitcoin Core -- NOTE: Discouraged unless interoperability issues need to be worked around"`
DisableRPC bool `long:"norpc" description:"Disable built-in RPC server -- NOTE: The RPC server is disabled by default if no rpcuser/rpcpass or rpclimituser/rpclimitpass is specified"`
DisableTLS bool `long:"notls" description:"Disable TLS for the RPC server -- NOTE: This is only allowed if the RPC server is bound to localhost"`
DisableDNSSeed bool `long:"nodnsseed" description:"Disable DNS seeding for peers"`
ExternalIPs []string `long:"externalip" description:"Add an ip to the list of local addresses we claim to listen on to peers"`
Proxy string `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
ProxyUser string `long:"proxyuser" description:"Username for proxy server"`
ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"`
OnionProxy string `long:"onion" description:"Connect to tor hidden services via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
OnionProxyUser string `long:"onionuser" description:"Username for onion proxy server"`
OnionProxyPass string `long:"onionpass" default-mask:"-" description:"Password for onion proxy server"`
NoOnion bool `long:"noonion" description:"Disable connecting to tor hidden services"`
TorIsolation bool `long:"torisolation" description:"Enable Tor stream isolation by randomizing user credentials for each connection."`
TestNet3 bool `long:"testnet" description:"Use the test network"`
RegressionTest bool `long:"regtest" description:"Use the regression test network"`
SimNet bool `long:"simnet" description:"Use the simulation test network"`
AddCheckpoints []string `long:"addcheckpoint" description:"Add a custom checkpoint. Format: '<height>:<hash>'"`
DisableCheckpoints bool `long:"nocheckpoints" description:"Disable built-in checkpoints. Don't do this unless you know what you're doing."`
DbType string `long:"dbtype" description:"Database backend to use for the Block Chain"`
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
CPUProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"`
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"`
Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"`
MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in BTC/kB to be considered a non-zero fee."`
FreeTxRelayLimit float64 `long:"limitfreerelay" description:"Limit relay of transactions with no transaction fee to the given amount in thousands of bytes per minute"`
NoRelayPriority bool `long:"norelaypriority" description:"Do not require free or low-fee transactions to have high priority for relaying"`
TrickleInterval time.Duration `long:"trickleinterval" description:"Minimum time between attempts to send new inventory to a connected peer"`
MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"`
Generate bool `long:"generate" description:"Generate (mine) bitcoins using the CPU"`
MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"`
BlockMinSize uint32 `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"`
BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"`
BlockMinWeight uint32 `long:"blockminweight" description:"Mininum block weight to be used when creating a block"`
BlockMaxWeight uint32 `long:"blockmaxweight" description:"Maximum block weight to be used when creating a block"`
BlockPrioritySize uint32 `long:"blockprioritysize" description:"Size in bytes for high-priority/low-fee transactions when creating a block"`
UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
NoCFilters bool `long:"nocfilters" description:"Disable committed filtering (CF) support"`
DropCfIndex bool `long:"dropcfindex" description:"Deletes the index used for committed filtering (CF) support from the database on start up and then exits."`
SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"`
BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."`
TxIndex bool `long:"txindex" description:"Maintain a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"`
DropTxIndex bool `long:"droptxindex" description:"Deletes the hash-based transaction index from the database on start up and then exits."`
AddrIndex bool `long:"addrindex" description:"Maintain a full address-based transaction index which makes the searchrawtransactions RPC available"`
DropAddrIndex bool `long:"dropaddrindex" description:"Deletes the address-based transaction index from the database on start up and then exits."`
RelayNonStd bool `long:"relaynonstd" description:"Relay non-standard transactions regardless of the default settings for the active network."`
RejectNonStd bool `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."`
lookup func(string) ([]net.IP, error)
oniondial func(string, string, time.Duration) (net.Conn, error)
dial func(string, string, time.Duration) (net.Conn, error)
addCheckpoints []chaincfg.Checkpoint
miningAddrs []btcutil.Address
minRelayTxFee btcutil.Amount
whitelists []*net.IPNet
}
//service options将守护进程的配置选项定义为上的服务
//窗户。
type serviceOptions struct {
ServiceCommand string `short:"s" long:"service" description:"Service command {install, remove, start, stop}"`
}
//cleanandexpandpath扩展环境变量并在
//传递路径,清除结果并返回。
func cleanAndExpandPath(path string) string {
//将initial~扩展到操作系统特定的主目录。
if strings.HasPrefix(path, "~") {
homeDir := filepath.Dir(defaultHomeDir)
path = strings.Replace(path, "~", homeDir, 1)
}
//注意:os.expandenv不适用于Windows样式%variable%,
//但这些变量仍然可以通过posix样式的$variable进行扩展。
return filepath.Clean(os.ExpandEnv(path))
}
//validLogLevel返回logLevel是否为有效的调试日志级别。
func validLogLevel(logLevel string) bool {
switch logLevel {
case "trace":
fallthrough
case "debug":
fallthrough
case "info":
fallthrough
case "warn":
fallthrough
case "error":
fallthrough
case "critical":
return true
}
return false
}
//SupportedSubsystems返回受支持子系统的已排序切片
//日志记录目的。
func supportedSubsystems() []string {
//将子系统记录器映射键转换为切片。
subsystems := make([]string, 0, len(subsystemLoggers))
for subsysID := range subsystemLoggers {
subsystems = append(subsystems, subsysID)
}
//对子系统进行排序,以便稳定显示。
sort.Strings(subsystems)
return subsystems
}
//parsandsetdebuglevels尝试解析指定的调试级别并设置
//相应的水平。如果有任何错误
//无效。
func parseAndSetDebugLevels(debugLevel string) error {
//当指定的字符串没有任何delimter时,将其视为
//所有子系统的日志级别。
if !strings.Contains(debugLevel, ",") && !strings.Contains(debugLevel, "=") {
//验证调试日志级别。
if !validLogLevel(debugLevel) {
str := "The specified debug level [%v] is invalid"
return fmt.Errorf(str, debugLevel)
}
//更改所有子系统的日志记录级别。
setLogLevels(debugLevel)
return nil
}
//检测时将指定的字符串拆分为子系统/级别对
//发布并相应更新日志级别。
for _, logLevelPair := range strings.Split(debugLevel, ",") {
if !strings.Contains(logLevelPair, "=") {
str := "The specified debug level contains an invalid " +
"subsystem/level pair [%v]"
return fmt.Errorf(str, logLevelPair)
}
//提取指定的子系统和日志级别。
fields := strings.Split(logLevelPair, "=")
subsysID, logLevel := fields[0], fields[1]
//验证子系统。
if _, exists := subsystemLoggers[subsysID]; !exists {
str := "The specified subsystem [%v] is invalid -- " +
"supported subsytems %v"
return fmt.Errorf(str, subsysID, supportedSubsystems())
}
//验证日志级别。
if !validLogLevel(logLevel) {
str := "The specified debug level [%v] is invalid"
return fmt.Errorf(str, logLevel)
}
setLogLevel(subsysID, logLevel)
}
return nil
}
//validdbtype返回dbtype是否为受支持的数据库类型。
func validDbType(dbType string) bool {
for _, knownType := range knownDbTypes {
if dbType == knownType {
return true
}
}
return false
}
//removeduplicateAddresses返回一个新切片,其中包含所有重复项
//删除ADDR。
func removeDuplicateAddresses(addrs []string) []string {
result := make([]string, 0, len(addrs))
seen := map[string]struct{}{}
for _, val := range addrs {
if _, ok := seen[val]; !ok {
result = append(result, val)
seen[val] = struct{}{}
}
}
return result
}
//normalizedAddress返回addr,并附加传递的默认端口if
//尚未指定端口。
func normalizeAddress(addr, defaultPort string) string {
_, _, err := net.SplitHostPort(addr)
if err != nil {
return net.JoinHostPort(addr, defaultPort)
}
return addr
}
//normalizeadresss返回一个新切片,其中包含所有传递的对等地址
//使用给定的默认端口进行规范化,并删除所有重复项。
func normalizeAddresses(addrs []string, defaultPort string) []string {
for i, addr := range addrs {
addrs[i] = normalizeAddress(addr, defaultPort)
}
return removeDuplicateAddresses(addrs)
}
//newcheckpointfromstr以“<height>:<hash>”格式分析检查点。
func newCheckpointFromStr(checkpoint string) (chaincfg.Checkpoint, error) {
parts := strings.Split(checkpoint, ":")
if len(parts) != 2 {
return chaincfg.Checkpoint{}, fmt.Errorf("unable to parse "+
"checkpoint %q -- use the syntax <height>:<hash>",
checkpoint)
}
height, err := strconv.ParseInt(parts[0], 10, 32)
if err != nil {
return chaincfg.Checkpoint{}, fmt.Errorf("unable to parse "+
"checkpoint %q due to malformed height", checkpoint)
}
if len(parts[1]) == 0 {
return chaincfg.Checkpoint{}, fmt.Errorf("unable to parse "+
"checkpoint %q due to missing hash", checkpoint)
}
hash, err := chainhash.NewHashFromStr(parts[1])
if err != nil {
return chaincfg.Checkpoint{}, fmt.Errorf("unable to parse "+
"checkpoint %q due to malformed hash", checkpoint)
}
return chaincfg.Checkpoint{
Height: int32(height),
Hash: hash,
}, nil
}
//ParseCheckpoints检查检查点字符串的有效语法
//('<height>:<hash>')并将其解析为chaincfg.checkpoint实例。
func parseCheckpoints(checkpointStrings []string) ([]chaincfg.Checkpoint, error) {
if len(checkpointStrings) == 0 {
return nil, nil
}
checkpoints := make([]chaincfg.Checkpoint, len(checkpointStrings))
for i, cpString := range checkpointStrings {
checkpoint, err := newCheckpointFromStr(cpString)
if err != nil {
return nil, err
}
checkpoints[i] = checkpoint
}
return checkpoints, nil
}
//filesexists报告命名文件或目录是否存在。
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
//NewConfigParser返回新的命令行标志分析器。
func newConfigParser(cfg *config, so *serviceOptions, options flags.Options) *flags.Parser {
parser := flags.NewParser(cfg, options)
if runtime.GOOS == "windows" {
parser.AddGroup("Service Options", "Service Options", so)
}
return parser
}
//loadconfig使用配置文件和命令初始化并分析配置
//行选项。
//
//配置过程如下:
//1)从具有健全设置的默认配置开始
//2)预分析命令行以检查备用配置文件
//3)使用任何指定选项加载配置文件覆盖默认值
//4)解析cli选项并覆盖/添加任何指定选项
//
//以上结果导致btcd在没有任何配置设置的情况下正常工作。
//同时仍允许用户使用配置文件和
//命令行选项。命令行选项始终优先。
func loadConfig() (*config, []string, error) {
//默认配置。
cfg := config{
ConfigFile: defaultConfigFile,
DebugLevel: defaultLogLevel,
MaxPeers: defaultMaxPeers,
BanDuration: defaultBanDuration,
BanThreshold: defaultBanThreshold,
RPCMaxClients: defaultMaxRPCClients,
RPCMaxWebsockets: defaultMaxRPCWebsockets,
RPCMaxConcurrentReqs: defaultMaxRPCConcurrentReqs,
DataDir: defaultDataDir,
LogDir: defaultLogDir,
DbType: defaultDbType,
RPCKey: defaultRPCKeyFile,
RPCCert: defaultRPCCertFile,
MinRelayTxFee: mempool.DefaultMinRelayTxFee.ToBTC(),
FreeTxRelayLimit: defaultFreeTxRelayLimit,
TrickleInterval: defaultTrickleInterval,
BlockMinSize: defaultBlockMinSize,
BlockMaxSize: defaultBlockMaxSize,
BlockMinWeight: defaultBlockMinWeight,
BlockMaxWeight: defaultBlockMaxWeight,
BlockPrioritySize: mempool.DefaultBlockPrioritySize,
MaxOrphanTxs: defaultMaxOrphanTransactions,
SigCacheMaxSize: defaultSigCacheMaxSize,
Generate: defaultGenerate,
TxIndex: defaultTxIndex,
AddrIndex: defaultAddrIndex,
}
//仅在Windows上添加的服务选项。
serviceOpts := serviceOptions{}
//预分析命令行选项,以查看是否有其他配置
//指定了文件或版本标志。除了
//此处可以忽略帮助消息错误,因为它们将被
//下面的最终分析。
preCfg := cfg
preParser := newConfigParser(&preCfg, &serviceOpts, flags.HelpFlag)
_, err := preParser.Parse()
if err != nil {
if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
}
//显示版本,如果指定了版本标志,则退出。
appName := filepath.Base(os.Args[0])
appName = strings.TrimSuffix(appName, filepath.Ext(appName))
usageMessage := fmt.Sprintf("Use %s -h to show usage", appName)
if preCfg.ShowVersion {
fmt.Println(appName, "version", version())
os.Exit(0)
}
//执行服务命令并退出(如果指定)。无效服务
//命令显示适当的错误。仅在Windows上运行
//如果不在Windows上,runservicecommand函数将为nil。
if serviceOpts.ServiceCommand != "" && runServiceCommand != nil {
err := runServiceCommand(serviceOpts.ServiceCommand)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
os.Exit(0)
}
//从文件加载附加配置。
var configFileError error
parser := newConfigParser(&cfg, &serviceOpts, flags.Default)
if !(preCfg.RegressionTest || preCfg.SimNet) || preCfg.ConfigFile !=
defaultConfigFile {
if _, err := os.Stat(preCfg.ConfigFile); os.IsNotExist(err) {
err := createDefaultConfigFile(preCfg.ConfigFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating a "+
"default config file: %v\n", err)
}
}
err := flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile)
if err != nil {
if _, ok := err.(*os.PathError); !ok {
fmt.Fprintf(os.Stderr, "Error parsing config "+
"file: %v\n", err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
configFileError = err
}
}
//在回归测试模式下,不要从配置文件添加对等。
if preCfg.RegressionTest && len(cfg.AddPeers) > 0 {
cfg.AddPeers = nil
}
//再次分析命令行选项以确保它们优先。
remainingArgs, err := parser.Parse()
if err != nil {
if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
fmt.Fprintln(os.Stderr, usageMessage)
}
return nil, nil, err
}
//如果主目录不存在,则创建它。
funcName := "loadConfig"
err = os.MkdirAll(defaultHomeDir, 0700)
if err != nil {
//如果是因为符号链接
//链接到不存在的目录(可能是因为
//它没有安装)。
if e, ok := err.(*os.PathError); ok && os.IsExist(err) {
if link, lerr := os.Readlink(e.Path); lerr == nil {
str := "is symlink %s -> %s mounted?"
err = fmt.Errorf(str, e.Path, link)
}
}
str := "%s: Failed to create home directory: %v"
err := fmt.Errorf(str, funcName, err)
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
//无法同时选择多个网络。
numNets := 0
//计数传递的网络标志数;分配活动的网络参数
//当我们在那里的时候
if cfg.TestNet3 {
numNets++
activeNetParams = &testNet3Params
}
if cfg.RegressionTest {
numNets++
activeNetParams = ®ressionNetParams
}
if cfg.SimNet {
numNets++
//同时禁用模拟测试网络上的DNS种子设定。
activeNetParams = &simNetParams
cfg.DisableDNSSeed = true
}
if numNets > 1 {
str := "%s: The testnet, regtest, segnet, and simnet params " +
"can't be used together -- choose one of the four"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//设置中继非标准事务的默认策略
//根据活动网络的默认值。集合
//配置值优先于
//选定的网络。
relayNonStd := activeNetParams.RelayNonStdTxs
switch {
case cfg.RelayNonStd && cfg.RejectNonStd:
str := "%s: rejectnonstd and relaynonstd cannot be used " +
"together -- choose only one"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
case cfg.RejectNonStd:
relayNonStd = false
case cfg.RelayNonStd:
relayNonStd = true
}
cfg.RelayNonStd = relayNonStd
//将网络类型附加到数据目录中,使其具有“名称空间”
//每个网络。除了块数据库,还有其他
//保存到磁盘上的数据块,如地址管理器状态。
//所有数据都是特定于一个网络的,因此名称间隔数据目录
//意味着每个单独的序列化数据不必
//担心更改每个网络的名称等等。
cfg.DataDir = cleanAndExpandPath(cfg.DataDir)
cfg.DataDir = filepath.Join(cfg.DataDir, netName(activeNetParams))
//将网络类型附加到日志目录中,使其具有“名称空间”
//与数据目录的方式相同。
cfg.LogDir = cleanAndExpandPath(cfg.LogDir)
cfg.LogDir = filepath.Join(cfg.LogDir, netName(activeNetParams))
//列出支持的子系统并退出的特殊显示命令。
if cfg.DebugLevel == "show" {
fmt.Println("Supported subsystems", supportedSubsystems())
os.Exit(0)
}
//初始化日志旋转。日志旋转初始化后,
//可以使用记录器变量。
initLogRotator(filepath.Join(cfg.LogDir, defaultLogFilename))
//分析、验证和设置调试日志级别。
if err := parseAndSetDebugLevels(cfg.DebugLevel); err != nil {
err := fmt.Errorf("%s: %v", funcName, err.Error())
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//验证数据库类型。
if !validDbType(cfg.DbType) {
str := "%s: The specified database type [%v] is invalid -- " +
"supported types %v"
err := fmt.Errorf(str, funcName, cfg.DbType, knownDbTypes)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//验证配置文件端口号
if cfg.Profile != "" {
profilePort, err := strconv.Atoi(cfg.Profile)
if err != nil || profilePort < 1024 || profilePort > 65535 {
str := "%s: The profile port must be between 1024 and 65535"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
}
//禁止时间太短。
if cfg.BanDuration < time.Second {
str := "%s: The banduration option may not be less than 1s -- parsed [%v]"
err := fmt.Errorf(str, funcName, cfg.BanDuration)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//验证任何给定的白名单IP地址和网络。
if len(cfg.Whitelists) > 0 {
var ip net.IP
cfg.whitelists = make([]*net.IPNet, 0, len(cfg.Whitelists))
for _, addr := range cfg.Whitelists {
_, ipnet, err := net.ParseCIDR(addr)
if err != nil {
ip = net.ParseIP(addr)
if ip == nil {
str := "%s: The whitelist value of '%s' is invalid"
err = fmt.Errorf(str, funcName, addr)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
var bits int
if ip.To4() == nil {
//IPv6
bits = 128
} else {
bits = 32
}
ipnet = &net.IPNet{
IP: ip,
Mask: net.CIDRMask(bits, bits),
}
}
cfg.whitelists = append(cfg.whitelists, ipnet)
}
}
//--addpeer和--connect不要混合使用。
if len(cfg.AddPeers) > 0 && len(cfg.ConnectPeers) > 0 {
str := "%s: the --addpeer and --connect options can not be " +
"mixed"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//--proxy或--connect without--listen禁用侦听。
if (cfg.Proxy != "" || len(cfg.ConnectPeers) > 0) &&
len(cfg.Listeners) == 0 {
cfg.DisableListen = true
}
//连接意味着没有DNS种子设定。
if len(cfg.ConnectPeers) > 0 {
cfg.DisableDNSSeed = true
}
//如果未指定,则添加默认侦听器。默认值
//侦听器是网络侦听端口上的所有地址
//我们要接通。
if len(cfg.Listeners) == 0 {
cfg.Listeners = []string{
net.JoinHostPort("", activeNetParams.DefaultPort),
}
}
//检查以确保受限用户和管理员用户没有相同的用户名
if cfg.RPCUser == cfg.RPCLimitUser && cfg.RPCUser != "" {
str := "%s: --rpcuser and --rpclimituser must not specify the " +
"same username"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//检查以确保受限用户和管理员用户没有相同的密码
if cfg.RPCPass == cfg.RPCLimitPass && cfg.RPCPass != "" {
str := "%s: --rpcpass and --rpclimitpass must not specify the " +
"same password"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//如果未提供用户名或密码,则禁用RPC服务器。
if (cfg.RPCUser == "" || cfg.RPCPass == "") &&
(cfg.RPCLimitUser == "" || cfg.RPCLimitPass == "") {
cfg.DisableRPC = true
}
if cfg.DisableRPC {
btcdLog.Infof("RPC service is disabled")
}
//默认的RPC只在本地主机上侦听。
if !cfg.DisableRPC && len(cfg.RPCListeners) == 0 {
addrs, err := net.LookupHost("localhost")
if err != nil {
return nil, nil, err
}
cfg.RPCListeners = make([]string, 0, len(addrs))
for _, addr := range addrs {
addr = net.JoinHostPort(addr, activeNetParams.rpcPort)
cfg.RPCListeners = append(cfg.RPCListeners, addr)
}
}
if cfg.RPCMaxConcurrentReqs < 0 {
str := "%s: The rpcmaxwebsocketconcurrentrequests option may " +
"not be less than 0 -- parsed [%d]"
err := fmt.Errorf(str, funcName, cfg.RPCMaxConcurrentReqs)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//验证minrelaytxfee。
cfg.minRelayTxFee, err = btcutil.NewAmount(cfg.MinRelayTxFee)
if err != nil {
str := "%s: invalid minrelaytxfee: %v"
err := fmt.Errorf(str, funcName, err)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//将最大块大小限制为正常值。
if cfg.BlockMaxSize < blockMaxSizeMin || cfg.BlockMaxSize >
blockMaxSizeMax {
str := "%s: The blockmaxsize option must be in between %d " +
"and %d -- parsed [%d]"
err := fmt.Errorf(str, funcName, blockMaxSizeMin,
blockMaxSizeMax, cfg.BlockMaxSize)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//将最大块重量限制为正常值。
if cfg.BlockMaxWeight < blockMaxWeightMin ||
cfg.BlockMaxWeight > blockMaxWeightMax {
str := "%s: The blockmaxweight option must be in between %d " +
"and %d -- parsed [%d]"
err := fmt.Errorf(str, funcName, blockMaxWeightMin,
blockMaxWeightMax, cfg.BlockMaxWeight)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//将最大孤立计数限制为正常值。
if cfg.MaxOrphanTxs < 0 {
str := "%s: The maxorphantx option may not be less than 0 " +
"-- parsed [%d]"
err := fmt.Errorf(str, funcName, cfg.MaxOrphanTxs)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//将块优先级和最小块大小限制为最大块大小。
cfg.BlockPrioritySize = minUint32(cfg.BlockPrioritySize, cfg.BlockMaxSize)
cfg.BlockMinSize = minUint32(cfg.BlockMinSize, cfg.BlockMaxSize)
cfg.BlockMinWeight = minUint32(cfg.BlockMinWeight, cfg.BlockMaxWeight)
switch {
//如果未设置最大块大小,但最大权重为,则我们将
//将最大块大小的限制设置为安全限制,以便重量
//优先。
case cfg.BlockMaxSize == defaultBlockMaxSize &&
cfg.BlockMaxWeight != defaultBlockMaxWeight:
cfg.BlockMaxSize = blockchain.MaxBlockBaseSize - 1000
//如果未设置最大块重,但块大小为,则我们将
//根据最大块大小值相应缩放设定的权重。
case cfg.BlockMaxSize != defaultBlockMaxSize &&
cfg.BlockMaxWeight == defaultBlockMaxWeight:
cfg.BlockMaxWeight = cfg.BlockMaxSize * blockchain.WitnessScaleFactor
}
//在用户代理注释中查找非法字符。
for _, uaComment := range cfg.UserAgentComments {
if strings.ContainsAny(uaComment, "/:()") {
err := fmt.Errorf("%s: The following characters must not "+
"appear in user agent comments: '/', ':', '(', ')'",
funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
}
//--txtindex和--droptxindex不混合。
if cfg.TxIndex && cfg.DropTxIndex {
err := fmt.Errorf("%s: the --txindex and --droptxindex "+
"options may not be activated at the same time",
funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//--addrindex和--dropaddrindex不混合。
if cfg.AddrIndex && cfg.DropAddrIndex {
err := fmt.Errorf("%s: the --addrindex and --dropaddrindex "+
"options may not be activated at the same time",
funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//--addrindex和--droptxindex不混合。
if cfg.AddrIndex && cfg.DropTxIndex {
err := fmt.Errorf("%s: the --addrindex and --droptxindex "+
"options may not be activated at the same time "+
"because the address index relies on the transaction "+
"index",
funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//检查挖掘地址是否有效并保存已分析的版本。
cfg.miningAddrs = make([]btcutil.Address, 0, len(cfg.MiningAddrs))
for _, strAddr := range cfg.MiningAddrs {
addr, err := btcutil.DecodeAddress(strAddr, activeNetParams.Params)
if err != nil {
str := "%s: mining address '%s' failed to decode: %v"
err := fmt.Errorf(str, funcName, strAddr, err)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
if !addr.IsForNet(activeNetParams.Params) {
str := "%s: mining address '%s' is on the wrong network"
err := fmt.Errorf(str, funcName, strAddr)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
cfg.miningAddrs = append(cfg.miningAddrs, addr)
}
//当generate标志为
//集合。
if cfg.Generate && len(cfg.MiningAddrs) == 0 {
str := "%s: the generate flag is set, but there are no mining " +
"addresses specified "
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//如果需要,将默认端口添加到所有侦听器地址并删除
//重复地址。
cfg.Listeners = normalizeAddresses(cfg.Listeners,
activeNetParams.DefaultPort)
//如果需要,将默认端口添加到所有RPC侦听器地址,然后删除
//重复地址。
cfg.RPCListeners = normalizeAddresses(cfg.RPCListeners,
activeNetParams.rpcPort)
//Only allow TLS to be disabled if the RPC is bound to localhost
//地址。
if !cfg.DisableRPC && cfg.DisableTLS {
allowedTLSListeners := map[string]struct{}{
"localhost": {},
"127.0.0.1": {},
"::1": {},
}
for _, addr := range cfg.RPCListeners {
host, _, err := net.SplitHostPort(addr)
if err != nil {
str := "%s: RPC listen interface '%s' is " +
"invalid: %v"
err := fmt.Errorf(str, funcName, addr, err)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
if _, ok := allowedTLSListeners[host]; !ok {
str := "%s: the --notls option may not be used " +
"when binding RPC to non localhost " +
"addresses: %s"
err := fmt.Errorf(str, funcName, addr)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
}
}
//如果需要,将默认端口添加到所有添加的对等地址,然后删除
//重复地址。
cfg.AddPeers = normalizeAddresses(cfg.AddPeers,
activeNetParams.DefaultPort)
cfg.ConnectPeers = normalizeAddresses(cfg.ConnectPeers,
activeNetParams.DefaultPort)
//——诺尼翁和——洋葱不能混合。
if cfg.NoOnion && cfg.OnionProxy != "" {
err := fmt.Errorf("%s: the --noonion and --onion options may "+
"not be activated at the same time", funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//检查检查检查点是否有语法错误。
cfg.addCheckpoints, err = parseCheckpoints(cfg.AddCheckpoints)
if err != nil {
str := "%s: Error parsing checkpoints: %v"
err := fmt.Errorf(str, funcName, err)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//Tor stream isolation requires either proxy or onion proxy to be set.
if cfg.TorIsolation && cfg.Proxy == "" && cfg.OnionProxy == "" {
str := "%s: Tor stream isolation requires either proxy or " +
"onionproxy to be set"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
//根据设置拨号和DNS解析(查找)功能
//指定的选项。默认值是使用标准
//NET.DialTimeout函数以及系统DNS解析程序。当A
//已指定代理,拨号功能设置为特定于代理
//拨号功能和查找设置为使用TOR(除非-nooion是
//在这种情况下指定使用系统DNS解析程序)。
cfg.dial = net.DialTimeout
cfg.lookup = net.LookupIP
if cfg.Proxy != "" {
_, _, err := net.SplitHostPort(cfg.Proxy)
if err != nil {
str := "%s: Proxy address '%s' is invalid: %v"
err := fmt.Errorf(str, funcName, cfg.Proxy, err)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}