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
}