Skip to content

HeaderChain.writeHeadersAndSetHead (fork choice)

Source (upstream v1.17.4) Current
File core/headerchain.go headerchain.go
Symbol HeaderChain.writeHeadersAndSetHead HeaderChain.writeHeadersAndSetHead
Ref v1.17.4 etc/v1.17.4-full-node

Modified in-place: takes a *ForkChoice and consults forker.ReorgNeeded before adopting the incoming headers, so TD fork choice (and MESS via the reorgFilter) applies at the header-insertion path too, not only at block insertion. Upstream v1.17.4 dropped the forker here (post-merge the CL drives the head); getc re-threads it, matching core-geth (which passes the forker into writeHeadersAndSetHead / InsertHeaderChain). The block is a near-verbatim port of core-geth's, guarded by if forker != nil since getc's forker is nil on non-PoW chains. Threaded through InsertHeaderChain -> BlockChain.InsertHeaderChain (which passes bc.forker). Guarded by TestHeaderInsertionForkChoiceTD.

Diff — vs upstream v1.17.4 (modified in-place)

--- a/core/headerchain.go
+++ b/core/headerchain.go
@@ -6,7 +6,7 @@
 // without the real blocks. Hence, writing headers directly should only be done
 // in two scenarios: pure-header mode of operation (light clients), or properly
 // separated header/block phases (non-archive clients).
-func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header) (*headerWriteResult, error) {
+func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *ForkChoice) (*headerWriteResult, error) {
    inserted, err := hc.WriteHeaders(headers)
    if err != nil {
        return nil, err
@@ -22,6 +22,17 @@
            lastHeader: lastHeader,
        }
    )
+   // Ask the fork choicer if the reorg is necessary
+   if forker != nil {
+       if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil {
+           return nil, err
+       } else if !reorg {
+           if inserted != 0 {
+               result.status = SideStatTy
+           }
+           return result, nil
+       }
+   }
    // Special case, all the inserted headers are already on the canonical
    // header chain, skip the reorg operation.
    if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() {
core-geth validation — +4 -1 | | | |---|---| | File | [`headerchain.go`](https://github.com/etclabscore/core-geth/blob/v1.12.20/core/headerchain.go) | | Symbol | `HeaderChain.writeHeadersAndSetHead` | | Ref | `v1.12.20` |
--- a/core-geth/core/headerchain.go
+++ b/etc/core/headerchain.go
@@ -1,5 +1,6 @@
 // writeHeadersAndSetHead writes a batch of block headers and applies the last
-// header as the chain head if the fork choicer says it's ok to update the chain.
+// header as the chain head.
+//
 // Note: This method is not concurrent-safe with inserting blocks simultaneously
 // into the chain, as side effects caused by reorganisations cannot be emulated
 // without the real blocks. Hence, writing headers directly should only be done
@@ -22,6 +23,7 @@
        }
    )
    // Ask the fork choicer if the reorg is necessary
+   if forker != nil {
    if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil {
        return nil, err
    } else if !reorg {
@@ -30,6 +32,7 @@
        }
        return result, nil
    }
+   }
    // Special case, all the inserted headers are already on the canonical
    // header chain, skip the reorg operation.
    if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() {

← Total Difficulty (TD)