ForkChoice.ReorgNeeded¶
| Source (upstream pre-purge) | Current | |
|---|---|---|
| File | core/forkchoice.go |
forkchoice_pow.go |
| Symbol | ForkChoice.ReorgNeeded |
ForkChoice.ReorgNeeded |
| Ref | f4d53133f~1 |
etc/v1.17.3-full-node |
TTD merge logic removed (ETC is perpetual PoW). All reorg paths now go through reorgAllowed() — extension point for MESS artificial finality.
3-way merge — purge → getc ← upstream¶
pre-purgecore-geth≈ adapted (origin inferred by similarity)fork-only
↗// ReorgNeeded returns whether the reorg should be applied
// based on the given external header and local canonical chain.
// In the td mode, the new head is chosen if the corresponding
// total difficulty is higher. In the extern mode, the trusted
// header is always selected as the head.
func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (needed bool, err error) {
// When the external header is not adopted as the new canonical head it is a
// side block — an uncle candidate for the PoW miner. Notify subscribers.
defer func() {
≈ if err == nil && !needed {
f.sideBlockFeed.Send(ChainSideEvent{Header: extern})
}
}()
↗ var (
localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64())
externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64())
)
if localTD == nil || externTd == nil {
return false, errors.New("missing td")
}
↗ // If the total difficulty is higher than our known, add it to the canonical chain
if diff := externTd.Cmp(localTD); diff > 0 {
return f.reorgAllowed(current, extern)
↗ } 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.
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
reorg := false
externNum, localNum := extern.Number.Uint64(), current.Number.Uint64()
if externNum < localNum {
reorg = true
} else if externNum == localNum {
var currentPreserve, externPreserve bool
if f.preserve != nil {
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
}
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
}
↗ if !reorg {
≈ return false, nil
↗ }
return f.reorgAllowed(current, extern)
↗}
core-geth validation — +17 -66
| | | |---|---| | File | [`forkchoice.go`](https://github.com/etclabscore/core-geth/blob/v1.12.20/core/forkchoice.go) | | Symbol | `ForkChoice.ReorgNeeded` | | Ref | `v1.12.20` |--- a/core-geth/core/forkchoice.go
+++ b/etc/core/forkchoice_pow.go
@@ -3,7 +3,14 @@
// In the td mode, the new head is chosen if the corresponding
// total difficulty is higher. In the extern mode, the trusted
// header is always selected as the head.
-func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (bool, error) {
+func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (needed bool, err error) {
+ // When the external header is not adopted as the new canonical head it is a
+ // side block — an uncle candidate for the PoW miner. Notify subscribers.
+ defer func() {
+ if err == nil && !needed {
+ f.sideBlockFeed.Send(ChainSideEvent{Header: extern})
+ }
+ }()
var (
localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64())
externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64())
@@ -11,35 +18,16 @@
if localTD == nil || externTd == nil {
return false, errors.New("missing td")
}
- // Accept the new header as the chain head if the transition
- // is already triggered. We assume all the headers after the
- // transition come from the trusted consensus layer.
- if ttd := f.chain.Config().GetEthashTerminalTotalDifficulty(); ttd != nil && ttd.Cmp(externTd) <= 0 {
- return true, nil
- }
-
- // // 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
- // }
- /*
- This is chunk was added with the following commit, citing it to be logically inoperative.
- etclabscore/core-geth omits it because of subsequent Artificial Finality checks on the reorg var.
-
- core: clarify code in forkchoice (#26257)
-
- refactoring without logic change
- 0dc9b01c github.com/setunapo 20221128
- */
-
+ // If the total difficulty is higher than our known, add it to the canonical chain
+ if diff := externTd.Cmp(localTD); diff > 0 {
+ return f.reorgAllowed(current, extern)
+ } 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.
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
- reorg := externTd.Cmp(localTD) > 0
- tie := externTd.Cmp(localTD) == 0
- if tie {
+ reorg := false
externNum, localNum := extern.Number.Uint64(), current.Number.Uint64()
if externNum < localNum {
reorg = true
@@ -50,45 +38,8 @@
}
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
}
- }
-
- // If reorg is not needed (false), then we can just return.
- // The following logic adds a condition only in the case where a reorg would
- // otherwise be indicated.
if !reorg {
- return reorg, nil
- }
-
- if bc, ok := f.chain.(*BlockChain); ok {
- // Short circuit if not configured for Artificial Finality.
- if !bc.IsArtificialFinalityEnabled() {
- return reorg, nil
- }
- }
- if !f.chain.Config().IsEnabled(f.chain.Config().GetECBP1100Transition, current.Number) {
- return reorg, nil
- }
-
- commonHeader, err := f.CommonAncestor(current, extern)
- if err != nil {
- return reorg, err
- }
-
- if err := ecbp1100(commonHeader, current, extern, f.chain.GetTd); err != nil {
- reorg = false
- log.Warn("Reorg disallowed", "error", err)
- } else if current.Number.Uint64()-commonHeader.Number.Uint64() > 2 {
- // Reorg is allowed, only log the MESS line if old chain is longer than normal.
- log.Info("ECBP1100-MESS 🔓",
- "status", "accepted",
- "age", common.PrettyAge(time.Unix(int64(commonHeader.Time), 0)),
- "current.span", common.PrettyDuration(time.Duration(current.Time-commonHeader.Time)*time.Second),
- "proposed.span", common.PrettyDuration(time.Duration(extern.Time-commonHeader.Time)*time.Second),
- "common.bno", commonHeader.Number.Uint64(), "common.hash", commonHeader.Hash(),
- "current.bno", current.Number.Uint64(), "current.hash", current.Hash(),
- "proposed.bno", extern.Number.Uint64(), "proposed.hash", extern.Hash(),
- )
+ return false, nil
}
-
- return reorg, nil
+ return f.reorgAllowed(current, extern)
}