forked from yinchengtsinghua/golang-bitcoin-chinese
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbtcd.go
341 lines (299 loc) · 8.67 KB
/
btcd.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
//此源码被清华学神尹成大魔王专业翻译分析并修改
//尹成QQ77025077
//尹成微信18510341407
//尹成所在QQ群721929980
//尹成邮箱 [email protected]
//尹成毕业于清华大学,微软区块链领域全球最有价值专家
//https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
//版权所有(c)2013-2016 BTCSuite开发者
//此源代码的使用由ISC控制
//可以在许可文件中找到的许可证。
package main
import (
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"os"
"path/filepath"
"runtime"
"runtime/debug"
"runtime/pprof"
"github.com/btcsuite/btcd/blockchain/indexers"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/limits"
)
const (
//BlockDBNamePrefix是块数据库名称的前缀。这个
//数据库类型附加到此值后形成完整的块
//数据库名称。
blockDbNamePrefix = "blocks"
)
var (
cfg *config
)
//仅在Windows上调用WinServiceMain。它检测BTCD何时运行
//作为一种服务,并做出相应的反应。
var winServiceMain func() (bool, error)
//BTCDMAIN是BTCD真正的主要功能。有必要四处工作
//当调用os.exit()时,延迟函数不运行。这个
//可选的serverchan参数主要用于
//在服务器设置后通知它,以便它可以在
//从服务控制管理器请求。
func btcdMain(serverChan chan<- *server) error {
//加载配置并分析命令行。此功能也
//初始化日志并进行相应的配置。
tcfg, _, err := loadConfig()
if err != nil {
return err
}
cfg = tcfg
defer func() {
if logRotator != nil {
logRotator.Close()
}
}()
//获取关闭信号时将关闭的通道
//从操作系统信号(如sigint(ctrl+c))或从
//
interrupt := interruptListener()
defer btcdLog.Info("Shutdown complete")
//启动时显示版本。
btcdLog.Infof("Version %s", version())
//如果请求,启用HTTP分析服务器。
if cfg.Profile != "" {
go func() {
listenAddr := net.JoinHostPort("", cfg.Profile)
btcdLog.Infof("Profile server listening on %s", listenAddr)
profileRedirect := http.RedirectHandler("/debug/pprof",
http.StatusSeeOther)
http.Handle("/", profileRedirect)
btcdLog.Errorf("%v", http.ListenAndServe(listenAddr, nil))
}()
}
//如果需要,写入CPU配置文件。
if cfg.CPUProfile != "" {
f, err := os.Create(cfg.CPUProfile)
if err != nil {
btcdLog.Errorf("Unable to create cpu profile: %v", err)
return err
}
pprof.StartCPUProfile(f)
defer f.Close()
defer pprof.StopCPUProfile()
}
//根据新版本的需要升级到BTCD。
if err := doUpgrades(); err != nil {
btcdLog.Errorf("%v", err)
return err
}
//如果触发了中断信号,立即返回。
if interruptRequested(interrupt) {
return nil
}
//加载块数据库。
db, err := loadBlockDB()
if err != nil {
btcdLog.Errorf("%v", err)
return err
}
defer func() {
//确保数据库已同步并在关闭时关闭。
btcdLog.Infof("Gracefully shutting down the database...")
db.Close()
}()
//如果触发了中断信号,立即返回。
if interruptRequested(interrupt) {
return nil
}
//删除索引并在请求时退出。
//
//注意:这里的顺序很重要,因为删除tx索引也很重要
//删除地址索引,因为它依赖于它。
if cfg.DropAddrIndex {
if err := indexers.DropAddrIndex(db, interrupt); err != nil {
btcdLog.Errorf("%v", err)
return err
}
return nil
}
if cfg.DropTxIndex {
if err := indexers.DropTxIndex(db, interrupt); err != nil {
btcdLog.Errorf("%v", err)
return err
}
return nil
}
if cfg.DropCfIndex {
if err := indexers.DropCfIndex(db, interrupt); err != nil {
btcdLog.Errorf("%v", err)
return err
}
return nil
}
//
server, err := newServer(cfg.Listeners, db, activeNetParams.Params,
interrupt)
if err != nil {
//托多:这种伐木可以美化环境。
btcdLog.Errorf("Unable to start server on %v: %v",
cfg.Listeners, err)
return err
}
defer func() {
btcdLog.Infof("Gracefully shutting down the server...")
server.Stop()
server.WaitForShutdown()
srvrLog.Infof("Server shutdown complete")
}()
server.Start()
if serverChan != nil {
serverChan <- server
}
//等待直到从操作系统信号接收到中断信号或
//通过一个子系统(如rpc)请求关闭
//服务器。
<-interrupt
return nil
}
//如果正在运行,则removeexcessiondb将删除现有的回归测试数据库
//在回归测试模式中,它已经存在。
func removeRegressionDB(dbPath string) error {
//如果不处于回归测试模式,则不要执行任何操作。
if !cfg.RegressionTest {
return nil
}
//删除旧的回归测试数据库(如果它已经存在)。
fi, err := os.Stat(dbPath)
if err == nil {
btcdLog.Infof("Removing regression test database from '%s'", dbPath)
if fi.IsDir() {
err := os.RemoveAll(dbPath)
if err != nil {
return err
}
} else {
err := os.Remove(dbPath)
if err != nil {
return err
}
}
}
return nil
}
//dbpath返回给定数据库类型的块数据库的路径。
func blockDbPath(dbType string) string {
//数据库名称基于数据库类型。
dbName := blockDbNamePrefix + "_" + dbType
if dbType == "sqlite" {
dbName = dbName + ".db"
}
dbPath := filepath.Join(cfg.DataDir, dbName)
return dbPath
}
//如果检测到多个块数据库类型,warnmultipledbs将显示警告。
//
//支持多个并行数据库。
func warnMultipleDBs() {
//这是故意不使用已知的数据库类型
//关于编译成二进制文件的数据库类型,因为我们希望
//同时检测旧数据库类型。
dbTypes := []string{"ffldb", "leveldb", "sqlite"}
duplicateDbPaths := make([]string, 0, len(dbTypes)-1)
for _, dbType := range dbTypes {
if dbType == cfg.DbType {
continue
}
//如果数据库路径存在,则将其存储为重复的数据库。
dbPath := blockDbPath(dbType)
if fileExists(dbPath) {
duplicateDbPaths = append(duplicateDbPaths, dbPath)
}
}
//如果有额外的数据库,则发出警告。
if len(duplicateDbPaths) > 0 {
selectedDbPath := blockDbPath(cfg.DbType)
btcdLog.Warnf("WARNING: There are multiple block chain databases "+
"using different database types.\nYou probably don't "+
"want to waste disk space by having more than one.\n"+
"Your current database is located at [%v].\nThe "+
"additional database is located at %v", selectedDbPath,
duplicateDbPaths)
}
}
//loadblockdb加载(或在需要时创建)块数据库
//帐户选定的数据库后端并返回其句柄。它也
//包含其他逻辑,如警告用户存在多个
//消耗文件系统空间并确保回归的数据库
//在回归测试模式下,测试数据库是干净的。
func loadBlockDB() (database.DB, error) {
//memdb后端没有与其关联的文件路径,因此
//独特处理。我们也不想担心多重性
//使用内存数据库运行时出现数据库类型警告。
if cfg.DbType == "memdb" {
btcdLog.Infof("Creating block database in memory.")
db, err := database.Create(cfg.DbType)
if err != nil {
return nil, err
}
return db, nil
}
warnMultipleDBs()
//数据库名称基于数据库类型。
dbPath := blockDbPath(cfg.DbType)
//回归测试的特殊之处在于它需要一个干净的数据库
//每次运行,如果它已经存在,现在就删除它。
removeRegressionDB(dbPath)
btcdLog.Infof("Loading block database from '%s'", dbPath)
db, err := database.Open(cfg.DbType, dbPath, activeNetParams.Net)
if err != nil {
//如果不是因为数据库没有
//存在。
if dbErr, ok := err.(database.Error); !ok || dbErr.ErrorCode !=
database.ErrDbDoesNotExist {
return nil, err
}
//如果数据库不存在,则创建它。
err = os.MkdirAll(cfg.DataDir, 0700)
if err != nil {
return nil, err
}
db, err = database.Create(cfg.DbType, dbPath, activeNetParams.Net)
if err != nil {
return nil, err
}
}
btcdLog.Info("Block database loaded")
return db, nil
}
func main() {
//使用所有处理器核心。
runtime.GOMAXPROCS(runtime.NumCPU())
//块和事务处理可能会导致激烈的分配。这个
//限制垃圾收集器在
//爆发。此值是在分析Live的帮助下获得的
//用法。
debug.SetGCPercent(10)
//有一些限制。
if err := limits.SetLimits(); err != nil {
fmt.Fprintf(os.Stderr, "failed to set limits: %v\n", err)
os.Exit(1)
}
//调用Windows上的ServiceMain以处理作为服务运行的情况。什么时候?
//返回IsService标志为true,现在退出,因为我们作为
//服务。否则,就只能正常运行。
if runtime.GOOS == "windows" {
isService, err := winServiceMain()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if isService {
os.Exit(0)
}
}
//解决OS.exit()之后延迟不工作的问题
if err := btcdMain(nil); err != nil {
os.Exit(1)
}
}