forkchoice.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // Copyright 2021 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package core
  17. import (
  18. crand "crypto/rand"
  19. "errors"
  20. "math/big"
  21. mrand "math/rand"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/common/math"
  24. "github.com/ethereum/go-ethereum/core/types"
  25. "github.com/ethereum/go-ethereum/log"
  26. "github.com/ethereum/go-ethereum/params"
  27. )
  28. // ChainReader defines a small collection of methods needed to access the local
  29. // blockchain during header verification. It's implemented by both blockchain
  30. // and lightchain.
  31. type ChainReader interface {
  32. // Config retrieves the header chain's chain configuration.
  33. Config() *params.ChainConfig
  34. // GetTd returns the total difficulty of a local block.
  35. GetTd(common.Hash, uint64) *big.Int
  36. }
  37. // ForkChoice is the fork chooser based on the highest total difficulty of the
  38. // chain(the fork choice used in the eth1) and the external fork choice (the fork
  39. // choice used in the eth2). This main goal of this ForkChoice is not only for
  40. // offering fork choice during the eth1/2 merge phase, but also keep the compatibility
  41. // for all other proof-of-work networks.
  42. type ForkChoice struct {
  43. chain ChainReader
  44. rand *mrand.Rand
  45. // preserve is a helper function used in td fork choice.
  46. // Miners will prefer to choose the local mined block if the
  47. // local td is equal to the extern one. It can be nil for light
  48. // client
  49. preserve func(header *types.Header) bool
  50. }
  51. func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool) *ForkChoice {
  52. // Seed a fast but crypto originating random generator
  53. seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
  54. if err != nil {
  55. log.Crit("Failed to initialize random seed", "err", err)
  56. }
  57. return &ForkChoice{
  58. chain: chainReader,
  59. rand: mrand.New(mrand.NewSource(seed.Int64())),
  60. preserve: preserve,
  61. }
  62. }
  63. // ReorgNeeded returns whether the reorg should be applied
  64. // based on the given external header and local canonical chain.
  65. // In the td mode, the new head is chosen if the corresponding
  66. // total difficulty is higher. In the extern mode, the trusted
  67. // header is always selected as the head.
  68. func (f *ForkChoice) ReorgNeeded(current *types.Header, header *types.Header) (bool, error) {
  69. var (
  70. localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64())
  71. externTd = f.chain.GetTd(header.Hash(), header.Number.Uint64())
  72. )
  73. if localTD == nil || externTd == nil {
  74. return false, errors.New("missing td")
  75. }
  76. // Accept the new header as the chain head if the transition
  77. // is already triggered. We assume all the headers after the
  78. // transition come from the trusted consensus layer.
  79. if ttd := f.chain.Config().TerminalTotalDifficulty; ttd != nil && ttd.Cmp(externTd) <= 0 {
  80. return true, nil
  81. }
  82. // If the total difficulty is higher than our known, add it to the canonical chain
  83. // Second clause in the if statement reduces the vulnerability to selfish mining.
  84. // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
  85. reorg := externTd.Cmp(localTD) > 0
  86. if !reorg && externTd.Cmp(localTD) == 0 {
  87. number, headNumber := header.Number.Uint64(), current.Number.Uint64()
  88. if number < headNumber {
  89. reorg = true
  90. } else if number == headNumber {
  91. var currentPreserve, externPreserve bool
  92. if f.preserve != nil {
  93. currentPreserve, externPreserve = f.preserve(current), f.preserve(header)
  94. }
  95. reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
  96. }
  97. }
  98. return reorg, nil
  99. }