Skip to content

ETCEngine.verifyHeader

Source (upstream pre-purge) Current
File consensus/ethash/consensus.go engine.go
Symbol Ethash.verifyHeader ETCEngine.verifyHeader
Ref dde2da0ef~1 etc/v1.17.3-full-node

Internal header validation. Adapted for ETC: BaseFee always nil (no EIP-1559), rejects post-merge fields unconditionally, uses ETC difficulty calculation. Includes future block time check (allowedFutureBlockTimeSeconds=15) and unixNow parameter for consistent batch verification.

3-way merge — purge → getc ← upstream

pre-purgeupstreamcommoncore-geth≈ adapted (origin inferred by similarity)fork-only
// verifyHeader performs ETC-specific header verification.
func (e *ETCEngine) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header, seal bool, unixNow int64) error {
// Ensure that the header's extra-data section is of a reasonable size
if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize)
}
// Verify the header's timestamp: reject future blocks
if header.Time > uint64(unixNow+allowedFutureBlockTimeSeconds) {
return consensus.ErrFutureBlock
}
if header.Time <= parent.Time {
return errOlderBlockTime
}
// Verify the block's difficulty based on its timestamp and parent's difficulty
expected := e.CalcDifficulty(chain, header.Time, parent)
if expected.Cmp(header.Difficulty) != 0 {
return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected)
}
// Verify that the gas limit is <= 2^63-1
if header.GasLimit > params.MaxGasLimit {
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
}
// Verify that the gasUsed is <= gasLimit
if header.GasUsed > header.GasLimit {
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
}
// ETC-specific: London (Mystique) does NOT include EIP-1559
// BaseFee should always be nil for ETC chains
if header.BaseFee != nil {
return fmt.Errorf("invalid baseFee: ETC does not support EIP-1559, have %d, expected nil", header.BaseFee)
}
// Verify gas limit follows the standard rules (no EIP-1559 gas elasticity)
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
return err
}
// Verify that the block number is parent's +1
if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
return consensus.ErrInvalidNumber
}
// Verify the non-existence of post-merge fields (ETC is perpetual PoW)
if header.WithdrawalsHash != nil {
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
}
if header.ExcessBlobGas != nil {
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
}
if header.BlobGasUsed != nil {
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
}
if header.ParentBeaconRoot != nil {
return fmt.Errorf("invalid parentBeaconRoot: have %x, expected nil", header.ParentBeaconRoot)
}
// Verify the PoW seal if requested
if seal {
if err := e.inner.VerifySeal(header); err != nil {
return err
}
}
return nil
}
core-geth validation — +25 -74 | | | |---|---| | File | [`consensus.go`](https://github.com/etclabscore/core-geth/blob/v1.12.20/consensus/ethash/consensus.go) | | Symbol | `Ethash.verifyHeader` | | Ref | `v1.12.20` |
--- a/core-geth/consensus/ethash/consensus.go
+++ b/etc/consensus/etc/engine.go
@@ -1,109 +1,60 @@
-// verifyHeader checks whether a header conforms to the consensus rules of the
-// stock Ethereum ethash engine.
-// See YP section 4.3.4. "Block Header Validity"
-func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header, uncle bool, seal bool, unixNow int64) error {
-   // Ensure that the header's extra-data section is of a reasonable size (32)
-   if uint64(len(header.Extra)) > vars.MaximumExtraDataSize {
-       return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), vars.MaximumExtraDataSize)
-   }
-   // Verify the header's timestamp
-   if !uncle {
-       if header.Time > uint64(unixNow+int64(allowedFutureBlockTime.Seconds())) {
-           return consensus.ErrFutureBlock
+// verifyHeader performs ETC-specific header verification.
+func (e *ETCEngine) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header, seal bool, unixNow int64) error {
+   // Ensure that the header's extra-data section is of a reasonable size
+   if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
+       return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize)
        }
+   // Verify the header's timestamp: reject future blocks
+   if header.Time > uint64(unixNow+allowedFutureBlockTimeSeconds) {
+       return consensus.ErrFutureBlock
    }
-   // Verify the timestamp
    if header.Time <= parent.Time {
        return errOlderBlockTime
    }
    // Verify the block's difficulty based on its timestamp and parent's difficulty
-   expected := ethash.CalcDifficulty(chain, header.Time, parent)
+   expected := e.CalcDifficulty(chain, header.Time, parent)
    if expected.Cmp(header.Difficulty) != 0 {
        return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected)
    }
    // Verify that the gas limit is <= 2^63-1
-   if header.GasLimit > vars.MaxGasLimit {
-       return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, vars.MaxGasLimit)
+   if header.GasLimit > params.MaxGasLimit {
+       return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
    }
    // Verify that the gasUsed is <= gasLimit
    if header.GasUsed > header.GasLimit {
        return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
    }
-   // Verify that the block number is parent's +1
-   if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
-       return consensus.ErrInvalidNumber
-   }
-   // Verify the block's gas usage and (if applicable) verify the base fee.
-   if !chain.Config().IsEnabled(chain.Config().GetEIP1559Transition, header.Number) {
-       // Verify BaseFee not present before EIP-1559 fork.
+   // ETC-specific: London (Mystique) does NOT include EIP-1559
+   // BaseFee should always be nil for ETC chains
        if header.BaseFee != nil {
-           return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee)
+       return fmt.Errorf("invalid baseFee: ETC does not support EIP-1559, have %d, expected nil", header.BaseFee)
        }
+   // Verify gas limit follows the standard rules (no EIP-1559 gas elasticity)
        if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
            return err
        }
-   } else if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
-       // Verify the header's EIP-1559 attributes.
-       return err
+   // Verify that the block number is parent's +1
+   if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
+       return consensus.ErrInvalidNumber
    }
-
-   // Shanghai
-   // EIP-4895: Beacon chain push withdrawals as operations
-   // Verify the non-existence of withdrawalsHash (EIP-4895: Beacon chain push withdrawals as operations).
-   eip4895Enabled := chain.Config().IsEnabledByTime(chain.Config().GetEIP4895TransitionTime, &header.Time) || chain.Config().IsEnabled(chain.Config().GetEIP4895Transition, header.Number)
-   if !eip4895Enabled {
+   // Verify the non-existence of post-merge fields (ETC is perpetual PoW)
        if header.WithdrawalsHash != nil {
            return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
        }
-   } else {
-       if header.WithdrawalsHash == nil {
-           return errors.New("header is missing withdrawalsHash")
-       }
-   }
-
-   // Cancun
-   // EIP-4844: Shard Blob Txes
-   // EIP-4788: Beacon block root in the EVM
-   eip4844Enabled := chain.Config().IsEnabledByTime(chain.Config().GetEIP4844TransitionTime, &header.Time) || chain.Config().IsEnabled(chain.Config().GetEIP4844Transition, header.Number)
-   if !eip4844Enabled {
-       switch {
-       case header.ExcessBlobGas != nil:
+   if header.ExcessBlobGas != nil {
            return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
-       case header.BlobGasUsed != nil:
-           return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
-       }
-   } else {
-       if err := eip4844.VerifyEIP4844Header(parent, header); err != nil {
-           return err
        }
+   if header.BlobGasUsed != nil {
+       return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
    }
-
-   // EIP-4788: Beacon block root in the EVM
-   eip4788Enabled := chain.Config().IsEnabledByTime(chain.Config().GetEIP4788TransitionTime, &header.Time) || chain.Config().IsEnabled(chain.Config().GetEIP4788Transition, header.Number)
-   if !eip4788Enabled {
        if header.ParentBeaconRoot != nil {
-           return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
-       }
-   } else {
-       if header.ParentBeaconRoot == nil {
-           return errors.New("header is missing beaconRoot")
-       }
+       return fmt.Errorf("invalid parentBeaconRoot: have %x, expected nil", header.ParentBeaconRoot)
    }
-
-   // // Add some fake checks for tests
-   // if ethash.fakeDelay != nil {
-   //  time.Sleep(*ethash.fakeDelay)
-   // }
-
-   // Verify the engine specific seal securing the block
+   // Verify the PoW seal if requested
    if seal {
-       if err := ethash.verifySeal(chain, header, false); err != nil {
+       if err := e.inner.VerifySeal(header); err != nil {
            return err
        }
    }
-   // If all checks passed, validate any special fields for hard forks
-   if err := mutations.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil {
-       return err
-   }
    return nil
 }

← Consensus & Ethash