Skip to content

Commit

Permalink
Merge pull request #18 from vulcanize/block_verification
Browse files Browse the repository at this point in the history
Block verification
  • Loading branch information
i-norden authored Dec 11, 2019
2 parents 0c8dcc0 + 783f706 commit 7842864
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 32 deletions.
96 changes: 64 additions & 32 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ var (
errInvalidDifficulty = errors.New("non-positive difficulty")
errInvalidMixDigest = errors.New("invalid mix digest")
errInvalidPoW = errors.New("invalid proof-of-work")
errGasLimitSet = errors.New("GasLimit should not be set after EIP1559 has finalized")
)

// Author implements consensus.Engine, returning the header's coinbase as the
Expand Down Expand Up @@ -258,26 +259,34 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, 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
cap := uint64(0x7fffffffffffffff)
if header.GasLimit > cap {
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
}
// 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 gas limit remains within allowed bounds
diff := int64(parent.GasLimit) - int64(header.GasLimit)
if diff < 0 {
diff *= -1
}
limit := parent.GasLimit / params.GasLimitBoundDivisor
// If we have not reached the EIP1559 finalization block we need to verify that the GasLimit field is valid
if !chain.Config().IsEIP1559Finalized(header.Number) {
// Verify that the gas limit is <= 2^63-1
cap := uint64(0x7fffffffffffffff)
if header.GasLimit > cap {
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
}
// 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 gas limit remains within allowed bounds
diff := int64(parent.GasLimit) - int64(header.GasLimit)
if diff < 0 {
diff *= -1
}
limit := parent.GasLimit / params.GasLimitBoundDivisor

if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
}
} else if header.GasLimit != 0 {
// If EIP1559 is finalized, GasLimit should be 0
return errGasLimitSet
}

// 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
Expand All @@ -289,6 +298,9 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
}
}
// If all checks passed, validate any special fields for hard forks
if err := misc.VerifyEIP1559BaseFee(chain.Config(), header, parent); err != nil {
return err
}
if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil {
return err
}
Expand Down Expand Up @@ -583,21 +595,41 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainReader, header *t
func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewLegacyKeccak256()

rlp.Encode(hasher, []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra,
})
if header.BaseFee == nil {
rlp.Encode(hasher, []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra,
})
} else {
rlp.Encode(hasher, []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra,
header.BaseFee,
})
}

hasher.Sum(hash[:0])
return hash
}
Expand Down
48 changes: 48 additions & 0 deletions consensus/misc/forks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,23 @@
package misc

import (
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)

var (
errInvalidInitialBaseFee = fmt.Errorf("initial BaseFee must equal %d", params.EIP1559InitialBaseFee)
errInvalidBaseFee = errors.New("invalid BaseFee")
errMissingParentBaseFee = errors.New("parent header is missing BaseFee")
errMissingBaseFee = errors.New("current header is missing BaseFee")
errHaveBaseFee = fmt.Errorf("BaseFee should not be set before block %d", params.EIP1559ForkBlockNumber)
)

// VerifyForkHashes verifies that blocks conforming to network hard-forks do have
// the correct hashes, to avoid clients going off on different chains. This is an
// optional feature.
Expand All @@ -41,3 +51,41 @@ func VerifyForkHashes(config *params.ChainConfig, header *types.Header, uncle bo
// All ok, return
return nil
}

// VerifyEIP1559BaseFee verifies that the EIP1559 BaseFee field is valid for the current block height
func VerifyEIP1559BaseFee(config *params.ChainConfig, header, parent *types.Header) error {
// If we are at the EIP1559 fork block the BaseFee needs to be equal to params.EIP1559InitialBaseFee
if config.EIP1559Block != nil && config.EIP1559Block.Cmp(header.Number) == 0 {
if header.BaseFee == nil || header.BaseFee.Cmp(new(big.Int).SetUint64(params.EIP1559InitialBaseFee)) != 0 {
return errInvalidInitialBaseFee
}
return nil
}
// Verify the BaseFee is valid if we are past the EIP1559 initialization block
if config.IsEIP1559(header.Number) {
// A valid BASEFEE is one such that abs(BASEFEE - PARENT_BASEFEE) <= max(1, PARENT_BASEFEE // BASEFEE_MAX_CHANGE_DENOMINATOR)
if parent.BaseFee == nil {
return errMissingParentBaseFee
}
if header.BaseFee == nil {
return errMissingBaseFee
}
diff := new(big.Int).Sub(header.BaseFee, parent.BaseFee)
if diff.Sign() < 0 {
diff.Neg(diff)
}
max := new(big.Int).Div(parent.BaseFee, new(big.Int).SetUint64(params.BaseFeeMaxChangeDenominator))
if max.Cmp(common.Big1) < 0 {
max = common.Big1
}
if diff.Cmp(max) > 0 {
return errInvalidBaseFee
}
return nil
}
// If we are before the EIP1559 initialization block the current and parent BaseFees should be nil
if header.BaseFee != nil || parent.BaseFee != nil {
return errHaveBaseFee
}
return nil
}

0 comments on commit 7842864

Please sign in to comment.