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