github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/consensus/ethash/consensus.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package ethash 26 27 import ( 28 "bytes" 29 "errors" 30 "fmt" 31 "math/big" 32 "runtime" 33 "time" 34 35 mapset "github.com/deckarep/golang-set" 36 "github.com/ethereum/go-ethereum/common" 37 "github.com/ethereum/go-ethereum/common/math" 38 "github.com/ethereum/go-ethereum/consensus" 39 "github.com/ethereum/go-ethereum/consensus/misc" 40 "github.com/ethereum/go-ethereum/core/state" 41 "github.com/ethereum/go-ethereum/core/types" 42 "github.com/ethereum/go-ethereum/params" 43 ) 44 45 // 46 var ( 47 FrontierBlockReward *big.Int = big.NewInt(5e+18) //在魏块奖励成功开采块 48 ByzantiumBlockReward *big.Int = big.NewInt(3e+18) //从拜占庭向上成功开采一个区块,在魏城获得区块奖励 49 maxUncles = 2 //单个块中允许的最大叔叔数 50 allowedFutureBlockTime = 15 * time.Second //从当前时间算起的最大时间,在考虑将来的块之前 51 ) 52 53 //将块标记为无效的各种错误消息。这些应该是私人的 54 //防止在 55 //代码库,如果引擎被换出,则固有的中断。请把普通 56 //共识包中的错误类型。 57 var ( 58 errLargeBlockTime = errors.New("timestamp too big") 59 errZeroBlockTime = errors.New("timestamp equals parent's") 60 errTooManyUncles = errors.New("too many uncles") 61 errDuplicateUncle = errors.New("duplicate uncle") 62 errUncleIsAncestor = errors.New("uncle is ancestor") 63 errDanglingUncle = errors.New("uncle's parent is not ancestor") 64 errInvalidDifficulty = errors.New("non-positive difficulty") 65 errInvalidMixDigest = errors.New("invalid mix digest") 66 errInvalidPoW = errors.New("invalid proof-of-work") 67 ) 68 69 //作者实现共识引擎,返回头部的coinbase作为 70 // 71 func (ethash *Ethash) Author(header *types.Header) (common.Address, error) { 72 return header.Coinbase, nil 73 } 74 75 //验证标题检查标题是否符合 76 //库存以太坊Ethash发动机。 77 func (ethash *Ethash) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { 78 //如果我们正在运行一个完整的引擎伪造,接受任何有效的输入。 79 if ethash.config.PowMode == ModeFullFake { 80 return nil 81 } 82 //如果知道收割台,或其父项不知道,则短路 83 number := header.Number.Uint64() 84 if chain.GetHeader(header.Hash(), number) != nil { 85 return nil 86 } 87 parent := chain.GetHeader(header.ParentHash, number-1) 88 if parent == nil { 89 return consensus.ErrUnknownAncestor 90 } 91 //通过健康检查,进行适当的验证 92 return ethash.verifyHeader(chain, header, parent, false, seal) 93 } 94 95 //VerifyHeaders类似于VerifyHeader,但会验证一批头 96 //同时地。该方法返回退出通道以中止操作,并且 97 //用于检索异步验证的结果通道。 98 func (ethash *Ethash) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 99 //如果我们正在运行一个完整的引擎伪造,接受任何有效的输入。 100 if ethash.config.PowMode == ModeFullFake || len(headers) == 0 { 101 abort, results := make(chan struct{}), make(chan error, len(headers)) 102 for i := 0; i < len(headers); i++ { 103 results <- nil 104 } 105 return abort, results 106 } 107 108 // 109 workers := runtime.GOMAXPROCS(0) 110 if len(headers) < workers { 111 workers = len(headers) 112 } 113 114 //创建任务通道并生成验证程序 115 var ( 116 inputs = make(chan int) 117 done = make(chan int, workers) 118 errors = make([]error, len(headers)) 119 abort = make(chan struct{}) 120 ) 121 for i := 0; i < workers; i++ { 122 go func() { 123 for index := range inputs { 124 errors[index] = ethash.verifyHeaderWorker(chain, headers, seals, index) 125 done <- index 126 } 127 }() 128 } 129 130 errorsOut := make(chan error, len(headers)) 131 go func() { 132 defer close(inputs) 133 var ( 134 in, out = 0, 0 135 checked = make([]bool, len(headers)) 136 inputs = inputs 137 ) 138 for { 139 select { 140 case inputs <- in: 141 if in++; in == len(headers) { 142 //已到达邮件头的结尾。停止向工人发送。 143 inputs = nil 144 } 145 case index := <-done: 146 for checked[index] = true; checked[out]; out++ { 147 errorsOut <- errors[out] 148 if out == len(headers)-1 { 149 return 150 } 151 } 152 case <-abort: 153 return 154 } 155 } 156 }() 157 return abort, errorsOut 158 } 159 160 func (ethash *Ethash) verifyHeaderWorker(chain consensus.ChainReader, headers []*types.Header, seals []bool, index int) error { 161 var parent *types.Header 162 if index == 0 { 163 parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) 164 } else if headers[index-1].Hash() == headers[index].ParentHash { 165 parent = headers[index-1] 166 } 167 if parent == nil { 168 return consensus.ErrUnknownAncestor 169 } 170 if chain.GetHeader(headers[index].Hash(), headers[index].Number.Uint64()) != nil { 171 return nil //已知块体 172 } 173 return ethash.verifyHeader(chain, headers[index], parent, false, seals[index]) 174 } 175 176 //验证叔父验证给定区块的叔父是否符合共识 177 //股票以太坊的规则。 178 func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 179 //如果我们正在运行一个完整的引擎伪造,接受任何有效的输入。 180 if ethash.config.PowMode == ModeFullFake { 181 return nil 182 } 183 //验证此块中最多包含2个叔叔 184 if len(block.Uncles()) > maxUncles { 185 return errTooManyUncles 186 } 187 //收集过去的叔叔和祖先 188 uncles, ancestors := mapset.NewSet(), make(map[common.Hash]*types.Header) 189 190 number, parent := block.NumberU64()-1, block.ParentHash() 191 for i := 0; i < 7; i++ { 192 ancestor := chain.GetBlock(parent, number) 193 if ancestor == nil { 194 break 195 } 196 ancestors[ancestor.Hash()] = ancestor.Header() 197 for _, uncle := range ancestor.Uncles() { 198 uncles.Add(uncle.Hash()) 199 } 200 parent, number = ancestor.ParentHash(), number-1 201 } 202 ancestors[block.Hash()] = block.Header() 203 uncles.Add(block.Hash()) 204 205 //确认每个叔叔都是最近的,但不是祖先 206 for _, uncle := range block.Uncles() { 207 //确保每个叔叔只奖励一次 208 hash := uncle.Hash() 209 if uncles.Contains(hash) { 210 return errDuplicateUncle 211 } 212 uncles.Add(hash) 213 214 //确保叔叔有一个有效的祖先 215 if ancestors[hash] != nil { 216 return errUncleIsAncestor 217 } 218 if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == block.ParentHash() { 219 return errDanglingUncle 220 } 221 if err := ethash.verifyHeader(chain, uncle, ancestors[uncle.ParentHash], true, true); err != nil { 222 return err 223 } 224 } 225 return nil 226 } 227 228 //验证标题检查标题是否符合 229 //库存以太坊Ethash发动机。 230 //见YP第4.3.4节。”块头有效期” 231 func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *types.Header, uncle bool, seal bool) error { 232 // 233 if uint64(len(header.Extra)) > params.MaximumExtraDataSize { 234 return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize) 235 } 236 //验证头的时间戳 237 if uncle { 238 if header.Time.Cmp(math.MaxBig256) > 0 { 239 return errLargeBlockTime 240 } 241 } else { 242 if header.Time.Cmp(big.NewInt(time.Now().Add(allowedFutureBlockTime).Unix())) > 0 { 243 return consensus.ErrFutureBlock 244 } 245 } 246 if header.Time.Cmp(parent.Time) <= 0 { 247 return errZeroBlockTime 248 } 249 //根据时间戳和父块的难度验证块的难度 250 expected := ethash.CalcDifficulty(chain, header.Time.Uint64(), parent) 251 252 if expected.Cmp(header.Difficulty) != 0 { 253 return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected) 254 } 255 //确认气体限值<=2^63-1 256 cap := uint64(0x7fffffffffffffff) 257 if header.GasLimit > cap { 258 return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) 259 } 260 //确认所用气体<=气体限值 261 if header.GasUsed > header.GasLimit { 262 return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) 263 } 264 265 //确认气体限值保持在允许范围内 266 diff := int64(parent.GasLimit) - int64(header.GasLimit) 267 if diff < 0 { 268 diff *= -1 269 } 270 limit := parent.GasLimit / params.GasLimitBoundDivisor 271 272 if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { 273 return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) 274 } 275 //验证块号是否为父块的+1 276 if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { 277 return consensus.ErrInvalidNumber 278 } 279 //确认固定气缸体的发动机专用密封件 280 if seal { 281 if err := ethash.VerifySeal(chain, header); err != nil { 282 return err 283 } 284 } 285 //如果所有检查都通过,则验证硬分叉的任何特殊字段 286 if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil { 287 return err 288 } 289 if err := misc.VerifyForkHashes(chain.Config(), header, uncle); err != nil { 290 return err 291 } 292 return nil 293 } 294 295 //计算难度是难度调整算法。它返回 296 //新块在创建时应该具有的困难 297 // 298 func (ethash *Ethash) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 299 return CalcDifficulty(chain.Config(), time, parent) 300 } 301 302 //计算难度是难度调整算法。它返回 303 //新块在创建时应该具有的困难 304 //考虑到父块的时间和难度。 305 func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int { 306 next := new(big.Int).Add(parent.Number, big1) 307 switch { 308 case config.IsByzantium(next): 309 return calcDifficultyByzantium(time, parent) 310 case config.IsHomestead(next): 311 return calcDifficultyHomestead(time, parent) 312 default: 313 return calcDifficultyFrontier(time, parent) 314 } 315 } 316 317 //一些奇怪的常量,以避免为它们分配常量内存。 318 var ( 319 expDiffPeriod = big.NewInt(100000) 320 big1 = big.NewInt(1) 321 big2 = big.NewInt(2) 322 big9 = big.NewInt(9) 323 big10 = big.NewInt(10) 324 bigMinus99 = big.NewInt(-99) 325 big2999999 = big.NewInt(2999999) 326 ) 327 328 //拜占庭算法是一种难度调整算法。它返回 329 //在给定 330 //父块的时间和难度。计算使用拜占庭规则。 331 func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int { 332 //https://github.com/ethereum/eips/issues/100。 333 //算法: 334 //diff=(父级diff+ 335 //(父级差异/2048*最大值((如果len(parent.uncles)为2,否则为1)-((timestamp-parent.timestamp)//9),-99)) 336 //)+2^(周期计数-2) 337 338 bigTime := new(big.Int).SetUint64(time) 339 bigParentTime := new(big.Int).Set(parent.Time) 340 341 //保持中间值以使算法更易于读取和审计 342 x := new(big.Int) 343 y := new(big.Int) 344 345 // 346 x.Sub(bigTime, bigParentTime) 347 x.Div(x, big9) 348 if parent.UncleHash == types.EmptyUncleHash { 349 x.Sub(big1, x) 350 } else { 351 x.Sub(big2, x) 352 } 353 //max((如果len(parent_uncles)为2,否则为1)-(block_timestamp-parent_timestamp)//9,-99) 354 if x.Cmp(bigMinus99) < 0 { 355 x.Set(bigMinus99) 356 } 357 // 358 y.Div(parent.Difficulty, params.DifficultyBoundDivisor) 359 x.Mul(y, x) 360 x.Add(parent.Difficulty, x) 361 362 //最小难度可以是(指数因子之前) 363 if x.Cmp(params.MinimumDifficulty) < 0 { 364 x.Set(params.MinimumDifficulty) 365 } 366 //计算冰期延迟的假块数: 367 //https://github.com/ethereum/eips/pull/669 368 //假块编号=最大值(0,块编号-3) 369 fakeBlockNumber := new(big.Int) 370 if parent.Number.Cmp(big2999999) >= 0 { 371 fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, big2999999) //注意,父级比实际块号小1 372 } 373 //对于指数因子 374 periodCount := fakeBlockNumber 375 periodCount.Div(periodCount, expDiffPeriod) 376 377 //指数因子,通常称为“炸弹” 378 //diff=diff+2^(周期计数-2) 379 if periodCount.Cmp(big1) > 0 { 380 y.Sub(periodCount, big2) 381 y.Exp(big2, y, nil) 382 x.Add(x, y) 383 } 384 return x 385 } 386 387 //CalcDifficultyHomeStead是难度调整算法。它返回 388 //在给定 389 // 390 func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int { 391 //https://github.com/ethereum/eips/blob/master/eips/eip-2.md网站 392 //算法: 393 //diff=(父级diff+ 394 //(parent_diff/2048*最大值(1-(block_timestamp-parent_timestamp)//10,-99)) 395 //)+2^(周期计数-2) 396 397 bigTime := new(big.Int).SetUint64(time) 398 bigParentTime := new(big.Int).Set(parent.Time) 399 400 //保持中间值以使算法更易于读取和审计 401 x := new(big.Int) 402 y := new(big.Int) 403 404 //1-(block_timestamp-parent_timestamp)//10 405 x.Sub(bigTime, bigParentTime) 406 x.Div(x, big10) 407 x.Sub(big1, x) 408 409 //max(1-(block_timestamp-parent_timestamp)//10,-99) 410 if x.Cmp(bigMinus99) < 0 { 411 x.Set(bigMinus99) 412 } 413 //(parent_diff+parent_diff//2048*最大值(1-(block_timestamp-parent_timestamp)//10,-99)) 414 y.Div(parent.Difficulty, params.DifficultyBoundDivisor) 415 x.Mul(y, x) 416 x.Add(parent.Difficulty, x) 417 418 //最小难度可以是(指数因子之前) 419 if x.Cmp(params.MinimumDifficulty) < 0 { 420 x.Set(params.MinimumDifficulty) 421 } 422 //对于指数因子 423 periodCount := new(big.Int).Add(parent.Number, big1) 424 periodCount.Div(periodCount, expDiffPeriod) 425 426 //指数因子,通常称为“炸弹” 427 //diff=diff+2^(周期计数-2) 428 if periodCount.Cmp(big1) > 0 { 429 y.Sub(periodCount, big2) 430 y.Exp(big2, y, nil) 431 x.Add(x, y) 432 } 433 return x 434 } 435 436 //计算难度边界是难度调整算法。它返回 437 //在给定父级的情况下创建新块时应具有的困难 438 //布洛克的时间和难度。计算使用边界规则。 439 func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int { 440 diff := new(big.Int) 441 adjust := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) 442 bigTime := new(big.Int) 443 bigParentTime := new(big.Int) 444 445 bigTime.SetUint64(time) 446 bigParentTime.Set(parent.Time) 447 448 if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 { 449 diff.Add(parent.Difficulty, adjust) 450 } else { 451 diff.Sub(parent.Difficulty, adjust) 452 } 453 if diff.Cmp(params.MinimumDifficulty) < 0 { 454 diff.Set(params.MinimumDifficulty) 455 } 456 457 periodCount := new(big.Int).Add(parent.Number, big1) 458 periodCount.Div(periodCount, expDiffPeriod) 459 if periodCount.Cmp(big1) > 0 { 460 //diff=diff+2^(周期计数-2) 461 expDiff := periodCount.Sub(periodCount, big2) 462 expDiff.Exp(big2, expDiff, nil) 463 diff.Add(diff, expDiff) 464 diff = math.BigMax(diff, params.MinimumDifficulty) 465 } 466 return diff 467 } 468 469 //验证seal是否执行共识引擎,检查给定的块是否满足 470 //POW难度要求。 471 func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Header) error { 472 return ethash.verifySeal(chain, header, false) 473 } 474 475 //验证Seal检查块是否满足POW难度要求, 476 //或者使用通常的ethash缓存,或者使用完整的DAG 477 //以加快远程挖掘。 478 func (ethash *Ethash) verifySeal(chain consensus.ChainReader, header *types.Header, fulldag bool) error { 479 // 480 if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake { 481 time.Sleep(ethash.fakeDelay) 482 if ethash.fakeFail == header.Number.Uint64() { 483 return errInvalidPoW 484 } 485 return nil 486 } 487 //如果我们正在运行一个共享的POW,请将验证委托给它。 488 if ethash.shared != nil { 489 return ethash.shared.verifySeal(chain, header, fulldag) 490 } 491 //确保我们有一个有效的障碍。 492 if header.Difficulty.Sign() <= 0 { 493 return errInvalidDifficulty 494 } 495 //重新计算摘要值和POW值 496 number := header.Number.Uint64() 497 498 var ( 499 digest []byte 500 result []byte 501 ) 502 //如果请求快速但繁重的POW验证,请使用ethash数据集 503 if fulldag { 504 dataset := ethash.dataset(number, true) 505 if dataset.generated() { 506 digest, result = hashimotoFull(dataset.dataset, header.HashNoNonce().Bytes(), header.Nonce.Uint64()) 507 508 //数据集在终结器中未映射。确保数据集保持活动状态 509 //直到调用后桥本满,所以在使用时不会取消映射。 510 runtime.KeepAlive(dataset) 511 } else { 512 //数据集尚未生成,请不要挂起,改用缓存 513 fulldag = false 514 } 515 } 516 //如果请求缓慢但轻微的POW验证(或DAG尚未就绪),请使用ethash缓存 517 if !fulldag { 518 cache := ethash.cache(number) 519 520 size := datasetSize(number) 521 if ethash.config.PowMode == ModeTest { 522 size = 32 * 1024 523 } 524 digest, result = hashimotoLight(size, cache.cache, header.HashNoNonce().Bytes(), header.Nonce.Uint64()) 525 526 //在终结器中取消映射缓存。确保缓存保持活动状态 527 // 528 runtime.KeepAlive(cache) 529 } 530 //对照标题中提供的值验证计算值 531 if !bytes.Equal(header.MixDigest[:], digest) { 532 return errInvalidMixDigest 533 } 534 target := new(big.Int).Div(two256, header.Difficulty) 535 if new(big.Int).SetBytes(result).Cmp(target) > 0 { 536 return errInvalidPoW 537 } 538 return nil 539 } 540 541 //准备执行共识。引擎,初始化 542 //头符合ethash协议。更改是以内联方式完成的。 543 func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header) error { 544 parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) 545 if parent == nil { 546 return consensus.ErrUnknownAncestor 547 } 548 header.Difficulty = ethash.CalcDifficulty(chain, header.Time.Uint64(), parent) 549 return nil 550 } 551 552 // 553 //设置最终状态并组装块。 554 func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { 555 //累积任何块和叔叔奖励并提交最终状态根 556 accumulateRewards(chain.Config(), state, header, uncles) 557 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 558 559 //收割台似乎已完成,组装成一个块并返回 560 return types.NewBlock(header, txs, uncles, receipts), nil 561 } 562 563 //一些奇怪的常量,以避免为它们分配常量内存。 564 var ( 565 big8 = big.NewInt(8) 566 big32 = big.NewInt(32) 567 ) 568 569 //累加后,将给定块的coinbase用于采矿。 570 //奖赏。总奖励包括静态块奖励和 571 //包括叔叔。每个叔叔街区的硬币库也会得到奖励。 572 func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) { 573 //根据链进程选择正确的区块奖励 574 blockReward := FrontierBlockReward 575 if config.IsByzantium(header.Number) { 576 blockReward = ByzantiumBlockReward 577 } 578 //为矿工和任何包括叔叔的人累积奖励 579 reward := new(big.Int).Set(blockReward) 580 r := new(big.Int) 581 for _, uncle := range uncles { 582 r.Add(uncle.Number, big8) 583 r.Sub(r, header.Number) 584 r.Mul(r, blockReward) 585 r.Div(r, big8) 586 state.AddBalance(uncle.Coinbase, r) 587 588 r.Div(blockReward, big32) 589 reward.Add(reward, r) 590 } 591 state.AddBalance(header.Coinbase, reward) 592 }