|
|
@ -74,10 +74,10 @@ func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) |
|
|
|
// In the td mode, the new head is chosen if the corresponding
|
|
|
|
// In the td mode, the new head is chosen if the corresponding
|
|
|
|
// total difficulty is higher. In the extern mode, the trusted
|
|
|
|
// total difficulty is higher. In the extern mode, the trusted
|
|
|
|
// header is always selected as the head.
|
|
|
|
// header is always selected as the head.
|
|
|
|
func (f *ForkChoice) ReorgNeeded(current *types.Header, header *types.Header) (bool, error) { |
|
|
|
func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (bool, error) { |
|
|
|
var ( |
|
|
|
var ( |
|
|
|
localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64()) |
|
|
|
localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64()) |
|
|
|
externTd = f.chain.GetTd(header.Hash(), header.Number.Uint64()) |
|
|
|
externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64()) |
|
|
|
) |
|
|
|
) |
|
|
|
if localTD == nil || externTd == nil { |
|
|
|
if localTD == nil || externTd == nil { |
|
|
|
return false, errors.New("missing td") |
|
|
|
return false, errors.New("missing td") |
|
|
@ -88,21 +88,26 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, header *types.Header) (b |
|
|
|
if ttd := f.chain.Config().TerminalTotalDifficulty; ttd != nil && ttd.Cmp(externTd) <= 0 { |
|
|
|
if ttd := f.chain.Config().TerminalTotalDifficulty; ttd != nil && ttd.Cmp(externTd) <= 0 { |
|
|
|
return true, nil |
|
|
|
return true, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// If the total difficulty is higher than our known, add it to the canonical chain
|
|
|
|
// If the total difficulty is higher than our known, add it to the canonical chain
|
|
|
|
|
|
|
|
if diff := externTd.Cmp(localTD); diff > 0 { |
|
|
|
|
|
|
|
return true, nil |
|
|
|
|
|
|
|
} else if diff < 0 { |
|
|
|
|
|
|
|
return false, nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Local and external difficulty is identical.
|
|
|
|
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
|
|
|
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
|
|
|
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
|
|
|
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
|
|
|
reorg := externTd.Cmp(localTD) > 0 |
|
|
|
reorg := false |
|
|
|
if !reorg && externTd.Cmp(localTD) == 0 { |
|
|
|
externNum, localNum := extern.Number.Uint64(), current.Number.Uint64() |
|
|
|
number, headNumber := header.Number.Uint64(), current.Number.Uint64() |
|
|
|
if externNum < localNum { |
|
|
|
if number < headNumber { |
|
|
|
|
|
|
|
reorg = true |
|
|
|
reorg = true |
|
|
|
} else if number == headNumber { |
|
|
|
} else if externNum == localNum { |
|
|
|
var currentPreserve, externPreserve bool |
|
|
|
var currentPreserve, externPreserve bool |
|
|
|
if f.preserve != nil { |
|
|
|
if f.preserve != nil { |
|
|
|
currentPreserve, externPreserve = f.preserve(current), f.preserve(header) |
|
|
|
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern) |
|
|
|
} |
|
|
|
} |
|
|
|
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5) |
|
|
|
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return reorg, nil |
|
|
|
return reorg, nil |
|
|
|
} |
|
|
|
} |
|
|
|