diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index c8e49341074f..043c53463d5c 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -24,9 +24,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" ) @@ -55,12 +55,12 @@ var ( // // The beacon here is a half-functional consensus engine with partial functions which // is only used for necessary consensus checks. The legacy consensus engine can be any -// engine implements the consensus interface(except the beacon itself). +// engine implements the consensus interface (except the beacon itself). type Beacon struct { ethone consensus.Engine // Classic consensus engine used in eth1, e.g. ethash or clique // transitioned is the flag whether the transition has been triggered. - // It's triggered by receiving the first "POS_CHAINHEAD_SET" message + // It's triggered by receiving the first "ENGINE_FORKCHOICEUPDATED" message // from the external consensus engine. transitioned bool lock sync.RWMutex @@ -107,6 +107,7 @@ func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *ty // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers // concurrently. The method returns a quit channel to abort the operations and // a results channel to retrieve the async verifications. +// VerifyHeaders expect the headers to be ordered (not necessary continuous). func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { if !beacon.IsPoSHeader(headers[len(headers)-1]) { return beacon.ethone.VerifyHeaders(chain, headers, seals) @@ -181,9 +182,10 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo // verifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum consensus engine. The difference between the beacon and classic is -// (a) the difficulty, mixhash, nonce, extradata and unclehash are expected +// (a) the difficulty, mixhash, nonce and unclehash are expected // to be the desired constants // (b) the timestamp is not verified anymore +// (c) the extradata is limited to 32 bytes func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { // Ensure that the header's extra-data section is of a reasonable size if len(header.Extra) > 32 { @@ -203,13 +205,17 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa 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 !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 err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { + return err + } + } else if err := misc.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 { diff --git a/core/blockchain.go b/core/blockchain.go index 5ef19a3c1fc1..851ffbeee9c2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -928,7 +928,10 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ // Rewind may have occurred, skip in that case. if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 { reorg, err := bc.forker.Reorg(bc.CurrentFastBlock().Header(), head.Header()) - if err != nil || !reorg { + if err != nil { + log.Warn("Reorg failed", "err", err) + return false + } else if !reorg { return false } rawdb.WriteHeadFastBlockHash(bc.db, head.Hash()) @@ -1184,9 +1187,6 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error { // writeBlockWithState writes block, metadata and corresponding state data to the // database. func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB) error { - bc.wg.Add(1) - defer bc.wg.Done() - // Calculate the total difficulty of the block ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1) if ptd == nil { @@ -1436,7 +1436,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er if reorg { // Switch to import mode if the forker says the reorg is necessary // and also the block is not on the canonical chain. - // In eth2 the forker always returns True for reorg desision(blindly trust + // In eth2 the forker always returns true for reorg decision (blindly trusting // the external consensus engine), but in order to prevent the unnecessary // reorgs when importing known blocks, the special case is handled here. if bc.GetCanonicalHash(block.NumberU64()) != block.Hash() || block.NumberU64() > current.NumberU64() { diff --git a/core/forkchoice.go b/core/forkchoice.go index e3b8e591201f..a7b75a91386f 100644 --- a/core/forkchoice.go +++ b/core/forkchoice.go @@ -53,7 +53,7 @@ type ForkChoice struct { // preserve is a helper function used in td fork choice. // Miners will prefer to choose the local mined block if the - // local td is equal to the extern one. It can nil for light + // local td is equal to the extern one. It can be nil for light // client preserve func(header *types.Header) bool } diff --git a/core/merger.go b/core/merger.go index c6e2f0eceb89..6734167d7486 100644 --- a/core/merger.go +++ b/core/merger.go @@ -39,7 +39,6 @@ type Merger struct { db ethdb.KeyValueStore status transitionStatus leavePoWCalls []func() - enterPoSCalls []func() lock sync.Mutex } @@ -66,15 +65,6 @@ func (m *Merger) SubscribeLeavePoW(callback func()) { m.leavePoWCalls = append(m.leavePoWCalls, callback) } -// SubscribeEnterPoS registers callback so that if the chain leaves -// from the 'transition' stage and enters the PoS stage it can be invoked. -func (m *Merger) SubscribeEnterPoS(callback func()) { - m.lock.Lock() - defer m.lock.Unlock() - - m.enterPoSCalls = append(m.enterPoSCalls, callback) -} - // LeavePoW is called whenever the first NewHead message received // from the consensus-layer. func (m *Merger) LeavePoW() { @@ -111,9 +101,6 @@ func (m *Merger) EnterPoS() { log.Crit("Failed to encode the transition status", "err", err) } rawdb.WriteTransitionStatus(m.db, blob) - for _, call := range m.enterPoSCalls { - call() - } log.Info("Entered PoS stage") } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 9925dea5f332..a60fb599fce8 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -22,7 +22,6 @@ import ( "errors" "fmt" "math/big" - "os" "time" "github.com/ethereum/go-ethereum/common" @@ -38,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" chainParams "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" ) @@ -196,15 +194,7 @@ func (api *ConsensusAPI) GetPayload(PayloadID hexutil.Uint64) (*ExecutableData, func (api *ConsensusAPI) ConsensusValidated(params ConsensusValidatedParams) error { switch params.Status { case VALID.Status: - // Finalize the transition if it's the first `FinalisedBlock` event. - merger := api.merger() - if !merger.EnteredPoS() { - if err := api.checkTerminalTotalDifficulty(params.BlockHash); err != nil { - return err - } - merger.EnterPoS() - } - return nil //api.setHead(params.BlockHash) + return nil case INVALID.Status: // TODO (MariusVanDerWijden) delete the block from the bc return nil @@ -258,6 +248,10 @@ func (api *ConsensusAPI) ExecutePayload(params ExecutableData) (GenericStringRes if err := api.eth.BlockChain().InsertBlock(block); err != nil { return INVALID, err } + merger := api.merger() + if !merger.LeftPoW() { + merger.LeavePoW() + } return VALID, nil } @@ -277,7 +271,7 @@ func (api *ConsensusAPI) assembleBlock(params AssembleBlockParams) (*ExecutableD } if params.Timestamp < parent.Time() { - return nil, fmt.Errorf("child timestamp lower than parent's: %d >= %d", parent.Time(), params.Timestamp) + return nil, fmt.Errorf("child timestamp lower than parent's: %d < %d", params.Timestamp, parent.Time()) } if now := uint64(time.Now().Unix()); params.Timestamp > now+1 { diff := time.Duration(params.Timestamp-now) * time.Second @@ -468,8 +462,8 @@ func (api *ConsensusAPI) checkTerminalTotalDifficulty(head common.Hash) error { func (api *ConsensusAPI) setHead(newHead common.Hash) error { // Trigger the transition if it's the first `NewHead` event. merger := api.merger() - if !merger.LeftPoW() { - merger.LeavePoW() + if !merger.EnteredPoS() { + merger.EnterPoS() } log.Info("Setting head", "head", newHead) if api.light { @@ -508,63 +502,3 @@ func (api *ConsensusAPI) merger() *core.Merger { } return api.eth.Merger() } - -// Helper API for the merge f2f - -func (api *ConsensusAPI) ExportChain(path string) error { - if api.light { - return errors.New("cannot export chain in light mode") - } - f, err := os.Create(path) - if err != nil { - return err - } - return api.eth.BlockChain().Export(f) -} - -func (api *ConsensusAPI) ImportChain(path string) error { - if api.light { - return errors.New("cannot import chain in light mode") - } - f, err := os.Open(path) - if err != nil { - return err - } - for { - var block types.Block - if err := block.DecodeRLP(rlp.NewStream(f, 0)); err != nil { - break - } - if err := api.eth.BlockChain().InsertBlock(&block); err != nil { - return err - } - } - return nil -} - -func (api *ConsensusAPI) ExportExecutableData(path string) error { - if api.light { - return errors.New("cannot export chain in light mode") - } - f, err := os.Create(path) - if err != nil { - return err - } - for i := uint64(0); i < api.eth.BlockChain().CurrentBlock().NumberU64(); i++ { - block := api.eth.BlockChain().GetBlockByNumber(i) - exec := BlockToExecutableData(block, common.Hash{}) - b, err := exec.MarshalJSON() - if err != nil { - return err - } - if _, err := f.Write(b); err != nil { - return err - } - f.Write([]byte("\n")) - } - return nil -} - -func (api *ConsensusAPI) GetHead() (common.Hash, error) { - return api.eth.BlockChain().CurrentBlock().Hash(), nil -} diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index c3871b45617a..ca53cec8ffcc 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -73,52 +73,6 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) { return genesis, blocks } -// TODO (MariusVanDerWijden) reenable once engine api is updated to the latest spec -/* -func generateTestChainWithFork(n int, fork int) (*core.Genesis, []*types.Block, []*types.Block) { - if fork >= n { - fork = n - 1 - } - db := rawdb.NewMemoryDatabase() - config := ¶ms.ChainConfig{ - ChainID: big.NewInt(1337), - HomesteadBlock: big.NewInt(0), - 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(params.EthashConfig), - } - genesis := &core.Genesis{ - Config: config, - Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, - ExtraData: []byte("test genesis"), - Timestamp: 9000, - BaseFee: big.NewInt(params.InitialBaseFee), - } - generate := func(i int, g *core.BlockGen) { - g.OffsetTime(5) - g.SetExtra([]byte("test")) - } - generateFork := func(i int, g *core.BlockGen) { - g.OffsetTime(5) - g.SetExtra([]byte("testF")) - } - gblock := genesis.ToBlock(db) - engine := ethash.NewFaker() - blocks, _ := core.GenerateChain(config, gblock, engine, db, n, generate) - blocks = append([]*types.Block{gblock}, blocks...) - forkedBlocks, _ := core.GenerateChain(config, blocks[fork], engine, db, n-fork, generateFork) - return genesis, blocks, forkedBlocks -} -*/ - func TestEth2AssembleBlock(t *testing.T) { genesis, blocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, blocks) @@ -172,9 +126,6 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) { defer n.Close() api := NewConsensusAPI(ethservice, nil) - if err := api.ConsensusValidated(ConsensusValidatedParams{BlockHash: blocks[5].Hash(), Status: VALID.Status}); err == nil { - t.Errorf("consensus validated before total terminal difficulty should fail") - } if err := api.ForkchoiceUpdated(ForkChoiceParams{HeadBlockHash: blocks[5].Hash()}); err == nil { t.Errorf("fork choice updated before total terminal difficulty should fail")