github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/headerchain.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:35</date> 10 //</624450079075340288> 11 12 13 package core 14 15 import ( 16 crand "crypto/rand" 17 "errors" 18 "fmt" 19 "math" 20 "math/big" 21 mrand "math/rand" 22 "sync/atomic" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/consensus" 27 "github.com/ethereum/go-ethereum/core/rawdb" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/ethdb" 30 "github.com/ethereum/go-ethereum/log" 31 "github.com/ethereum/go-ethereum/params" 32 "github.com/hashicorp/golang-lru" 33 ) 34 35 const ( 36 headerCacheLimit = 512 37 tdCacheLimit = 1024 38 numberCacheLimit = 2048 39 ) 40 41 //HeaderChain实现由共享的基本块头链逻辑 42 //core.blockback和light.lightchain。它本身不可用,只是 43 //两种结构的一部分。 44 //它也不是线程安全的,封装链结构应该这样做 45 //必要的互斥锁/解锁。 46 type HeaderChain struct { 47 config *params.ChainConfig 48 49 chainDb ethdb.Database 50 genesisHeader *types.Header 51 52 currentHeader atomic.Value //收割台链条的当前收割台(可能位于区块链上方!) 53 currentHeaderHash common.Hash //头链当前头的哈希(禁止随时重新计算) 54 55 headerCache *lru.Cache //缓存最新的块头 56 tdCache *lru.Cache //缓存最近的块总困难 57 numberCache *lru.Cache //缓存最新的块号 58 59 procInterrupt func() bool 60 61 rand *mrand.Rand 62 engine consensus.Engine 63 } 64 65 //新的headerchain创建新的headerchain结构。 66 //GetValidator应返回父级的验证程序 67 //procInterrupt指向父级的中断信号量 68 //wg指向父级的关闭等待组 69 func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) { 70 headerCache, _ := lru.New(headerCacheLimit) 71 tdCache, _ := lru.New(tdCacheLimit) 72 numberCache, _ := lru.New(numberCacheLimit) 73 74 //设定一个快速但加密的随机生成器 75 seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) 76 if err != nil { 77 return nil, err 78 } 79 80 hc := &HeaderChain{ 81 config: config, 82 chainDb: chainDb, 83 headerCache: headerCache, 84 tdCache: tdCache, 85 numberCache: numberCache, 86 procInterrupt: procInterrupt, 87 rand: mrand.New(mrand.NewSource(seed.Int64())), 88 engine: engine, 89 } 90 91 hc.genesisHeader = hc.GetHeaderByNumber(0) 92 if hc.genesisHeader == nil { 93 return nil, ErrNoGenesis 94 } 95 96 hc.currentHeader.Store(hc.genesisHeader) 97 if head := rawdb.ReadHeadBlockHash(chainDb); head != (common.Hash{}) { 98 if chead := hc.GetHeaderByHash(head); chead != nil { 99 hc.currentHeader.Store(chead) 100 } 101 } 102 hc.currentHeaderHash = hc.CurrentHeader().Hash() 103 104 return hc, nil 105 } 106 107 //GetBlockNumber检索属于给定哈希的块号 108 //从缓存或数据库 109 func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 { 110 if cached, ok := hc.numberCache.Get(hash); ok { 111 number := cached.(uint64) 112 return &number 113 } 114 number := rawdb.ReadHeaderNumber(hc.chainDb, hash) 115 if number != nil { 116 hc.numberCache.Add(hash, *number) 117 } 118 return number 119 } 120 121 //WRITEHEADER将头写入本地链,因为它的父级是 122 //已经知道了。如果新插入的标题的总难度变为 123 //大于当前已知的td,则重新路由规范链。 124 // 125 //注意:此方法与同时插入块不同时安全 126 //在链中,由于无法模拟由重组引起的副作用 127 //没有真正的街区。因此,只应直接编写头文件 128 //在两种情况下:纯头段操作模式(轻客户端),或正确 129 //单独的头段/块阶段(非存档客户端)。 130 func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, err error) { 131 //缓存一些值以防止常量重新计算 132 var ( 133 hash = header.Hash() 134 number = header.Number.Uint64() 135 ) 136 //计算收割台的总难度 137 ptd := hc.GetTd(header.ParentHash, number-1) 138 if ptd == nil { 139 return NonStatTy, consensus.ErrUnknownAncestor 140 } 141 localTd := hc.GetTd(hc.currentHeaderHash, hc.CurrentHeader().Number.Uint64()) 142 externTd := new(big.Int).Add(header.Difficulty, ptd) 143 144 //与规范状态无关,将td和header写入数据库 145 if err := hc.WriteTd(hash, number, externTd); err != nil { 146 log.Crit("Failed to write header total difficulty", "err", err) 147 } 148 rawdb.WriteHeader(hc.chainDb, header) 149 150 //如果总的困难比我们已知的要高,就把它加到规范链中去。 151 //if语句中的第二个子句减少了自私挖掘的脆弱性。 152 //请参阅http://www.cs.cornell.edu/~ie53/publications/btcrpocfc.pdf 153 if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) { 154 //删除新标题上方的所有规范编号分配 155 batch := hc.chainDb.NewBatch() 156 for i := number + 1; ; i++ { 157 hash := rawdb.ReadCanonicalHash(hc.chainDb, i) 158 if hash == (common.Hash{}) { 159 break 160 } 161 rawdb.DeleteCanonicalHash(batch, i) 162 } 163 batch.Write() 164 165 //覆盖任何过时的规范编号分配 166 var ( 167 headHash = header.ParentHash 168 headNumber = header.Number.Uint64() - 1 169 headHeader = hc.GetHeader(headHash, headNumber) 170 ) 171 for rawdb.ReadCanonicalHash(hc.chainDb, headNumber) != headHash { 172 rawdb.WriteCanonicalHash(hc.chainDb, headHash, headNumber) 173 174 headHash = headHeader.ParentHash 175 headNumber = headHeader.Number.Uint64() - 1 176 headHeader = hc.GetHeader(headHash, headNumber) 177 } 178 //用新的头扩展规范链 179 rawdb.WriteCanonicalHash(hc.chainDb, hash, number) 180 rawdb.WriteHeadHeaderHash(hc.chainDb, hash) 181 182 hc.currentHeaderHash = hash 183 hc.currentHeader.Store(types.CopyHeader(header)) 184 185 status = CanonStatTy 186 } else { 187 status = SideStatTy 188 } 189 190 hc.headerCache.Add(hash, header) 191 hc.numberCache.Add(hash, number) 192 193 return 194 } 195 196 //whcallback是用于插入单个头的回调函数。 197 //回调有两个原因:第一,在LightChain中,状态应为 198 //处理并发送轻链事件,而在区块链中,这不是 199 //这是必需的,因为在插入块后发送链事件。第二, 200 //头写入应该由父链互斥体单独保护。 201 type WhCallback func(*types.Header) error 202 203 func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) { 204 //做一个健全的检查,确保提供的链实际上是有序的和链接的 205 for i := 1; i < len(chain); i++ { 206 if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() { 207 //断链祖先、记录消息(编程错误)和跳过插入 208 log.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(), 209 "parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", chain[i-1].Hash()) 210 211 return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].Number, 212 chain[i-1].Hash().Bytes()[:4], i, chain[i].Number, chain[i].Hash().Bytes()[:4], chain[i].ParentHash[:4]) 213 } 214 } 215 216 //生成密封验证请求列表,并启动并行验证程序 217 seals := make([]bool, len(chain)) 218 for i := 0; i < len(seals)/checkFreq; i++ { 219 index := i*checkFreq + hc.rand.Intn(checkFreq) 220 if index >= len(seals) { 221 index = len(seals) - 1 222 } 223 seals[index] = true 224 } 225 seals[len(seals)-1] = true //应始终验证最后一个以避免垃圾 226 227 abort, results := hc.engine.VerifyHeaders(hc, chain, seals) 228 defer close(abort) 229 230 //遍历头并确保它们都签出 231 for i, header := range chain { 232 //如果链终止,则停止处理块 233 if hc.procInterrupt() { 234 log.Debug("Premature abort during headers verification") 235 return 0, errors.New("aborted") 236 } 237 //如果标题是禁止的,直接中止 238 if BadHashes[header.Hash()] { 239 return i, ErrBlacklistedHash 240 } 241 //否则,等待头检查并确保它们通过 242 if err := <-results; err != nil { 243 return i, err 244 } 245 } 246 247 return 0, nil 248 } 249 250 //insert header chain尝试将给定的头链插入本地 251 //链,可能创建REORG。如果返回错误,它将返回 252 //失败头的索引号以及描述出错原因的错误。 253 // 254 //verify参数可用于微调非ce验证 255 //是否应该做。可选检查背后的原因是 256 //其中的头检索机制已经需要验证nonce,以及 257 //因为nonce可以被稀疏地验证,不需要检查每一个。 258 func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCallback, start time.Time) (int, error) { 259 //收集一些要报告的进口统计数据 260 stats := struct{ processed, ignored int }{} 261 //所有头都通过了验证,将它们导入数据库 262 for i, header := range chain { 263 //关闭时短路插入 264 if hc.procInterrupt() { 265 log.Debug("Premature abort during headers import") 266 return i, errors.New("aborted") 267 } 268 //如果头已经知道,跳过它,否则存储 269 if hc.HasHeader(header.Hash(), header.Number.Uint64()) { 270 stats.ignored++ 271 continue 272 } 273 if err := writeHeader(header); err != nil { 274 return i, err 275 } 276 stats.processed++ 277 } 278 //报告一些公共统计数据,这样用户就可以知道发生了什么。 279 last := chain[len(chain)-1] 280 281 context := []interface{}{ 282 "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), 283 "number", last.Number, "hash", last.Hash(), 284 } 285 if timestamp := time.Unix(last.Time.Int64(), 0); time.Since(timestamp) > time.Minute { 286 context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) 287 } 288 if stats.ignored > 0 { 289 context = append(context, []interface{}{"ignored", stats.ignored}...) 290 } 291 log.Info("Imported new block headers", context...) 292 293 return 0, nil 294 } 295 296 //GetBlockHashesFromHash从给定的 297 //哈什,向创世纪街区走去。 298 func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash { 299 //获取要从中获取的源标题 300 header := hc.GetHeaderByHash(hash) 301 if header == nil { 302 return nil 303 } 304 //重复这些头文件,直到收集到足够的文件或达到创世标准。 305 chain := make([]common.Hash, 0, max) 306 for i := uint64(0); i < max; i++ { 307 next := header.ParentHash 308 if header = hc.GetHeader(next, header.Number.Uint64()-1); header == nil { 309 break 310 } 311 chain = append(chain, next) 312 if header.Number.Sign() == 0 { 313 break 314 } 315 } 316 return chain 317 } 318 319 //getAncestor检索给定块的第n个祖先。它假定给定的块或 320 //它的近亲是典型的。maxnoncanonical指向向下计数器,限制 321 //到达规范链之前要单独检查的块数。 322 // 323 //注意:ancestor==0返回相同的块,1返回其父块,依此类推。 324 func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { 325 if ancestor > number { 326 return common.Hash{}, 0 327 } 328 if ancestor == 1 { 329 //在这种情况下,只需读取标题就更便宜了 330 if header := hc.GetHeader(hash, number); header != nil { 331 return header.ParentHash, number - 1 332 } else { 333 return common.Hash{}, 0 334 } 335 } 336 for ancestor != 0 { 337 if rawdb.ReadCanonicalHash(hc.chainDb, number) == hash { 338 number -= ancestor 339 return rawdb.ReadCanonicalHash(hc.chainDb, number), number 340 } 341 if *maxNonCanonical == 0 { 342 return common.Hash{}, 0 343 } 344 *maxNonCanonical-- 345 ancestor-- 346 header := hc.GetHeader(hash, number) 347 if header == nil { 348 return common.Hash{}, 0 349 } 350 hash = header.ParentHash 351 number-- 352 } 353 return hash, number 354 } 355 356 //gettd从 357 //按哈希和数字排列的数据库,如果找到,则将其缓存。 358 func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { 359 //如果td已经在缓存中,则短路,否则检索 360 if cached, ok := hc.tdCache.Get(hash); ok { 361 return cached.(*big.Int) 362 } 363 td := rawdb.ReadTd(hc.chainDb, hash, number) 364 if td == nil { 365 return nil 366 } 367 //缓存下一次找到的正文并返回 368 hc.tdCache.Add(hash, td) 369 return td 370 } 371 372 //getDByHash从 373 //通过哈希对数据库进行缓存(如果找到)。 374 func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int { 375 number := hc.GetBlockNumber(hash) 376 if number == nil { 377 return nil 378 } 379 return hc.GetTd(hash, *number) 380 } 381 382 //writetd将一个块的总难度存储到数据库中,并对其进行缓存 383 //一路走来。 384 func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) error { 385 rawdb.WriteTd(hc.chainDb, hash, number, td) 386 hc.tdCache.Add(hash, new(big.Int).Set(td)) 387 return nil 388 } 389 390 //GetHeader按哈希和数字从数据库中检索块头, 391 //如果找到,则缓存它。 392 func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header { 393 //如果头已经在缓存中,则短路,否则检索 394 if header, ok := hc.headerCache.Get(hash); ok { 395 return header.(*types.Header) 396 } 397 header := rawdb.ReadHeader(hc.chainDb, hash, number) 398 if header == nil { 399 return nil 400 } 401 //下次缓存找到的头并返回 402 hc.headerCache.Add(hash, header) 403 return header 404 } 405 406 //GetHeaderByHash通过哈希从数据库中检索块头,如果 407 //找到了。 408 func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header { 409 number := hc.GetBlockNumber(hash) 410 if number == nil { 411 return nil 412 } 413 return hc.GetHeader(hash, *number) 414 } 415 416 //hasheader检查数据库中是否存在块头。 417 func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool { 418 if hc.numberCache.Contains(hash) || hc.headerCache.Contains(hash) { 419 return true 420 } 421 return rawdb.HasHeader(hc.chainDb, hash, number) 422 } 423 424 //GetHeaderByNumber按编号从数据库中检索块头, 425 //如果找到,则缓存它(与其哈希关联)。 426 func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { 427 hash := rawdb.ReadCanonicalHash(hc.chainDb, number) 428 if hash == (common.Hash{}) { 429 return nil 430 } 431 return hc.GetHeader(hash, number) 432 } 433 434 //当前头检索规范链的当前头。这个 435 //从HeaderChain的内部缓存中检索头。 436 func (hc *HeaderChain) CurrentHeader() *types.Header { 437 return hc.currentHeader.Load().(*types.Header) 438 } 439 440 //setcurrentheader设置规范链的当前头。 441 func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { 442 rawdb.WriteHeadHeaderHash(hc.chainDb, head.Hash()) 443 444 hc.currentHeader.Store(head) 445 hc.currentHeaderHash = head.Hash() 446 } 447 448 //deleteCallback是一个回调函数,由sethead在 449 //删除每个标题。 450 type DeleteCallback func(rawdb.DatabaseDeleter, common.Hash, uint64) 451 452 //sethead将本地链重绕到新的head。新脑袋上的一切 453 //将被删除和新的一组。 454 func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) { 455 height := uint64(0) 456 457 if hdr := hc.CurrentHeader(); hdr != nil { 458 height = hdr.Number.Uint64() 459 } 460 batch := hc.chainDb.NewBatch() 461 for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() { 462 hash := hdr.Hash() 463 num := hdr.Number.Uint64() 464 if delFn != nil { 465 delFn(batch, hash, num) 466 } 467 rawdb.DeleteHeader(batch, hash, num) 468 rawdb.DeleteTd(batch, hash, num) 469 470 hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash, hdr.Number.Uint64()-1)) 471 } 472 //回滚规范链编号 473 for i := height; i > head; i-- { 474 rawdb.DeleteCanonicalHash(batch, i) 475 } 476 batch.Write() 477 478 //从缓存中清除所有过时的内容 479 hc.headerCache.Purge() 480 hc.tdCache.Purge() 481 hc.numberCache.Purge() 482 483 if hc.CurrentHeader() == nil { 484 hc.currentHeader.Store(hc.genesisHeader) 485 } 486 hc.currentHeaderHash = hc.CurrentHeader().Hash() 487 488 rawdb.WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash) 489 } 490 491 //setGenesis为链设置新的Genesis块头 492 func (hc *HeaderChain) SetGenesis(head *types.Header) { 493 hc.genesisHeader = head 494 } 495 496 //config检索头链的链配置。 497 func (hc *HeaderChain) Config() *params.ChainConfig { return hc.config } 498 499 //引擎检索收割台链的共识引擎。 500 func (hc *HeaderChain) Engine() consensus.Engine { return hc.engine } 501 502 //getBlock实现consumeration.chainReader,并为每个输入返回nil作为 503 //标题链没有可供检索的块。 504 func (hc *HeaderChain) GetBlock(hash common.Hash, number uint64) *types.Block { 505 return nil 506 } 507