From b76b9a197d1c6fd6ede64f06d5b9f727a28e1cf2 Mon Sep 17 00:00:00 2001 From: Jin Date: Tue, 27 Aug 2024 18:03:08 +0800 Subject: [PATCH] feat:Private network support shanghai cancun fork --- meerevm/meer/consensus/consensus.go | 142 ++++++++++++++++------------ meerevm/meer/genesis_hash.go | 2 +- meerevm/meer/meerchain.go | 29 +++++- meerevm/meer/utils.go | 15 +++ meerevm/params/config.go | 37 +++++--- 5 files changed, 146 insertions(+), 79 deletions(-) diff --git a/meerevm/meer/consensus/consensus.go b/meerevm/meer/consensus/consensus.go index 85e21515..082c73b4 100644 --- a/meerevm/meer/consensus/consensus.go +++ b/meerevm/meer/consensus/consensus.go @@ -7,24 +7,28 @@ package consensus import ( "errors" "fmt" + "github.com/Qitmeer/qng/consensus/forks" qtypes "github.com/Qitmeer/qng/core/types" qcommon "github.com/Qitmeer/qng/meerevm/common" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/consensus/misc/eip1559" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" "math/big" - "runtime" ) var ( errUnclesUnsupported = errors.New("uncles unsupported") + errOlderBlockTime = errors.New("timestamp older than parent") ) func (me *MeerEngine) Author(header *types.Header) (common.Address, error) { @@ -52,70 +56,31 @@ func (me *MeerEngine) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ } return abort, results } + abort := make(chan struct{}) + results := make(chan error, len(headers)) - // Spawn as many workers as allowed threads - workers := runtime.GOMAXPROCS(0) - if len(headers) < workers { - workers = len(headers) - } - - // Create a task channel and spawn the verifiers - var ( - inputs = make(chan int) - done = make(chan int, workers) - errors = make([]error, len(headers)) - abort = make(chan struct{}) - ) - for i := 0; i < workers; i++ { - go func() { - for index := range inputs { - errors[index] = me.verifyHeaderWorker(chain, headers, index) - done <- index - } - }() - } - - errorsOut := make(chan error, len(headers)) go func() { - defer close(inputs) - var ( - in, out = 0, 0 - checked = make([]bool, len(headers)) - inputs = inputs - ) - for { + for i, header := range headers { + var parent *types.Header + if i == 0 { + parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) + } else if headers[i-1].Hash() == headers[i].ParentHash { + parent = headers[i-1] + } + var err error + if parent == nil { + err = consensus.ErrUnknownAncestor + } else { + err = me.verifyHeader(chain, header, parent) + } select { - case inputs <- in: - if in++; in == len(headers) { - // Reached end of headers. Stop sending to workers. - inputs = nil - } - case index := <-done: - for checked[index] = true; checked[out]; out++ { - errorsOut <- errors[out] - if out == len(headers)-1 { - return - } - } case <-abort: return + case results <- err: } } }() - return abort, errorsOut -} - -func (me *MeerEngine) verifyHeaderWorker(chain consensus.ChainHeaderReader, headers []*types.Header, index int) error { - var parent *types.Header - if index == 0 { - parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) - } else if headers[index-1].Hash() == headers[index].ParentHash { - parent = headers[index-1] - } - if parent == nil { - return consensus.ErrUnknownAncestor - } - return me.verifyHeader(chain, headers[index], parent) + return abort, results } func (me *MeerEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { @@ -126,21 +91,32 @@ func (me *MeerEngine) VerifyUncles(chain consensus.ChainReader, block *types.Blo } func (me *MeerEngine) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { + if header.Time <= parent.Time { + return errOlderBlockTime + } // 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) + 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 the block's gas usage and (if applicable) verify the base fee. if !chain.Config().IsLondon(header.Number) { // Verify BaseFee not present before EIP-1559 fork. if header.BaseFee != nil { return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee) } + if !forks.NeedFixedGasLimit(parent.Number.Int64(), chain.Config().ChainID.Int64()) { + 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 { @@ -150,6 +126,34 @@ func (me *MeerEngine) verifyHeader(chain consensus.ChainHeaderReader, header, pa if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil { return err } + + // Verify existence / non-existence of withdrawalsHash. + shanghai := chain.Config().IsShanghai(header.Number, header.Time) + if shanghai && header.WithdrawalsHash == nil { + return errors.New("missing withdrawalsHash") + } + if !shanghai && header.WithdrawalsHash != nil { + return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) + } + // Verify the existence / non-existence of cancun-specific header fields + cancun := chain.Config().IsCancun(header.Number, header.Time) + if !cancun { + switch { + case 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) + case 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") + } + if err := eip4844.VerifyEIP4844Header(parent, header); err != nil { + return err + } + } return nil } @@ -167,13 +171,27 @@ func (me *MeerEngine) Finalize(chain consensus.ChainHeaderReader, header *types. if me.StateChange != nil { me.StateChange(header, state, body) } - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) } func (me *MeerEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) { + shanghai := chain.Config().IsShanghai(header.Number, header.Time) + if shanghai { + // All blocks after Shanghai must include a withdrawals root. + if body.Withdrawals == nil { + body.Withdrawals = make([]*types.Withdrawal, 0) + } + } else { + if len(body.Withdrawals) > 0 { + return nil, errors.New("withdrawals set before Shanghai activation") + } + } + // Finalize and assemble the block. me.Finalize(chain, header, state, body) - // Header seems complete, assemble into a block and return + // Assign the final state root to header. + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + + // Assemble and return the final block. return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil } diff --git a/meerevm/meer/genesis_hash.go b/meerevm/meer/genesis_hash.go index 841c111a..0941d4f8 100644 --- a/meerevm/meer/genesis_hash.go +++ b/meerevm/meer/genesis_hash.go @@ -6,5 +6,5 @@ package meer const MainNetGenesisHash = "0x6cff8746d87573e2667d0784ea8753c7ee1dfc67cdb24971fe5f34743b0208fc" const TestNetGenesisHash = "0x1c67a198c1a593b9f85bca881cbf5cbe047ab44d08a3571f66473adbe889f1f7" -const PrivNetGenesisHash = "0x528b2448923b0d08dc20c692eeb5f42d758e28804c6d341bfb3de9f452290db4" +const PrivNetGenesisHash = "0xf422ee34950d4a96701f83818360819643f6689c786a786f47816dc5b76f848d" const MixNetGenesisHash = "0x8e9755f323ddcdaf2bc1c010ddb895450d1a23eef67ed98287bcade4c8a0d959" \ No newline at end of file diff --git a/meerevm/meer/meerchain.go b/meerevm/meer/meerchain.go index d24cebaf..e07fc393 100644 --- a/meerevm/meer/meerchain.go +++ b/meerevm/meer/meerchain.go @@ -133,8 +133,35 @@ func (b *MeerChain) ConnectBlock(block *mmeer.Block) (uint64, error) { mbh := qcommon.ToEVMHash(block.ID()) // log.Debug(fmt.Sprintf("MeerEVM Block:number=%d hash=%s txs=%d => blockHash(%s) txs=%d", mblock.Number().Uint64(), mblock.Hash().String(), len(mblock.Transactions()), mbh.String(), len(block.Transactions()))) + return mblock.NumberU64(), b.finalized(mblock) +} + +func (b *MeerChain) finalized(block *types.Block) error { + number := block.Number().Uint64() + var finalizedNumber uint64 + epochLength := uint64(params.ActiveNetParams.CoinbaseMaturity) + var cnumber uint64 + if number <= epochLength { + cnumber = 0 + } else { + cnumber = number - epochLength + } + if cnumber <= 0 { + finalizedNumber = 0 + } else { + if cnumber%epochLength == 0 { + finalizedNumber = cnumber + } else { + finalizedNumber = (cnumber - 1) / epochLength * epochLength + } + } - return mblock.NumberU64(), nil + h := b.chain.Ether().BlockChain().GetHeaderByNumber(finalizedNumber) + if h == nil { + return nil + } + b.chain.Ether().BlockChain().SetFinalized(h) + return nil } func (b *MeerChain) buildBlock(parent *types.Header, qtxs []model.Tx, timestamp int64) (*types.Block, types.Receipts, *state.StateDB, error) { diff --git a/meerevm/meer/utils.go b/meerevm/meer/utils.go index 6e63c786..01fdc86a 100644 --- a/meerevm/meer/utils.go +++ b/meerevm/meer/utils.go @@ -6,6 +6,7 @@ import ( qtypes "github.com/Qitmeer/qng/core/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -36,6 +37,20 @@ func makeHeader(cfg *ethconfig.Config, parent *types.Block, state *state.StateDB header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit) } } + if cfg.Genesis.Config.IsCancun(header.Number, header.Time) { + var ( + parentExcessBlobGas uint64 + parentBlobGasUsed uint64 + ) + if parent.ExcessBlobGas() != nil { + parentExcessBlobGas = *parent.ExcessBlobGas() + parentBlobGasUsed = *parent.BlobGasUsed() + } + excessBlobGas := eip4844.CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed) + header.ExcessBlobGas = &excessBlobGas + header.BlobGasUsed = new(uint64) + header.ParentBeaconRoot = new(common.Hash) + } return header } diff --git a/meerevm/params/config.go b/meerevm/params/config.go index f2eecb37..64715402 100644 --- a/meerevm/params/config.go +++ b/meerevm/params/config.go @@ -5,6 +5,8 @@ import ( "math/big" ) +func newUint64(val uint64) *uint64 { return &val } + var ( // QNG QngMainnetChainConfig = &eparams.ChainConfig{ @@ -62,21 +64,26 @@ var ( } QngPrivnetChainConfig = &eparams.ChainConfig{ - ChainID: eparams.QngPrivnetChainConfig.ChainID, - HomesteadBlock: big.NewInt(0), - DAOForkBlock: big.NewInt(0), - DAOForkSupport: false, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - Ethash: new(eparams.EthashConfig), + ChainID: eparams.QngPrivnetChainConfig.ChainID, + HomesteadBlock: big.NewInt(0), + DAOForkBlock: big.NewInt(0), + DAOForkSupport: false, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + TerminalTotalDifficultyPassed: true, + ShanghaiTime: newUint64(0), + CancunTime: newUint64(0), } // Amana