From b701eea355c312cdd015d2ab9e4c22c7774cc122 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Wed, 20 Nov 2019 14:18:06 -0600 Subject: [PATCH 1/2] modify verifyHeader() for ethash --- consensus/ethash/consensus.go | 46 ++++++++++++++++++++------------- consensus/misc/forks.go | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 3cff2d9fe5d4..4bb51bf4ec22 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -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 @@ -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) + } - if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { - return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) + // 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) + } + } 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 @@ -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 } diff --git a/consensus/misc/forks.go b/consensus/misc/forks.go index 4a5e7c37e03c..5d76db720768 100644 --- a/consensus/misc/forks.go +++ b/consensus/misc/forks.go @@ -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. @@ -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 +} From 783f7060ca6b7467f3ac5e9b83cb661deabb4506 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Wed, 20 Nov 2019 14:54:05 -0600 Subject: [PATCH 2/2] modify ethash.SealHash() --- consensus/ethash/consensus.go | 50 ++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 4bb51bf4ec22..1bdbf025dd1b 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -595,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 }