diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go
index 5743387f6c7f90f5bddf9d686d748f232a45e9cc..6ad9fc22be03900d8253bc0a53671bc152ac1a37 100644
--- a/consensus/ethash/consensus.go
+++ b/consensus/ethash/consensus.go
@@ -330,8 +330,6 @@ func (ethash *Ethash) CalcDifficulty(chain consensus.ChainHeaderReader, time uin
 func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
 	next := new(big.Int).Add(parent.Number, big1)
 	switch {
-	case config.IsCatalyst(next):
-		return big.NewInt(1)
 	case config.IsLondon(next):
 		return calcDifficultyEip3554(time, parent)
 	case config.IsMuirGlacier(next):
@@ -639,10 +637,6 @@ var (
 // reward. The total reward consists of the static block reward and rewards for
 // included uncles. The coinbase of each uncle block is also rewarded.
 func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
-	// Skip block reward in catalyst mode
-	if config.IsCatalyst(header.Number) {
-		return
-	}
 	// Select the correct block reward based on chain progression
 	blockReward := FrontierBlockReward
 	if config.IsByzantium(header.Number) {
diff --git a/consensus/misc/eip1559_test.go b/consensus/misc/eip1559_test.go
index fd400b6881d1abe301bfeb8f5e83de48189d542d..23cd9023de24ada97baa47b530d4f14bf8a43b16 100644
--- a/consensus/misc/eip1559_test.go
+++ b/consensus/misc/eip1559_test.go
@@ -29,24 +29,24 @@ import (
 // do not use e.g. SetInt() on the numbers. For testing only
 func copyConfig(original *params.ChainConfig) *params.ChainConfig {
 	return &params.ChainConfig{
-		ChainID:             original.ChainID,
-		HomesteadBlock:      original.HomesteadBlock,
-		DAOForkBlock:        original.DAOForkBlock,
-		DAOForkSupport:      original.DAOForkSupport,
-		EIP150Block:         original.EIP150Block,
-		EIP150Hash:          original.EIP150Hash,
-		EIP155Block:         original.EIP155Block,
-		EIP158Block:         original.EIP158Block,
-		ByzantiumBlock:      original.ByzantiumBlock,
-		ConstantinopleBlock: original.ConstantinopleBlock,
-		PetersburgBlock:     original.PetersburgBlock,
-		IstanbulBlock:       original.IstanbulBlock,
-		MuirGlacierBlock:    original.MuirGlacierBlock,
-		BerlinBlock:         original.BerlinBlock,
-		LondonBlock:         original.LondonBlock,
-		CatalystBlock:       original.CatalystBlock,
-		Ethash:              original.Ethash,
-		Clique:              original.Clique,
+		ChainID:                 original.ChainID,
+		HomesteadBlock:          original.HomesteadBlock,
+		DAOForkBlock:            original.DAOForkBlock,
+		DAOForkSupport:          original.DAOForkSupport,
+		EIP150Block:             original.EIP150Block,
+		EIP150Hash:              original.EIP150Hash,
+		EIP155Block:             original.EIP155Block,
+		EIP158Block:             original.EIP158Block,
+		ByzantiumBlock:          original.ByzantiumBlock,
+		ConstantinopleBlock:     original.ConstantinopleBlock,
+		PetersburgBlock:         original.PetersburgBlock,
+		IstanbulBlock:           original.IstanbulBlock,
+		MuirGlacierBlock:        original.MuirGlacierBlock,
+		BerlinBlock:             original.BerlinBlock,
+		LondonBlock:             original.LondonBlock,
+		TerminalTotalDifficulty: original.TerminalTotalDifficulty,
+		Ethash:                  original.Ethash,
+		Clique:                  original.Clique,
 	}
 }
 
diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go
index 2622c4a148f6bd18da05db4ed0fd3399f7303cb2..ea5414bd4c8a7c1e038e99590c04ea37d42fcb79 100644
--- a/eth/catalyst/api.go
+++ b/eth/catalyst/api.go
@@ -39,10 +39,8 @@ import (
 // Register adds catalyst APIs to the node.
 func Register(stack *node.Node, backend *eth.Ethereum) error {
 	chainconfig := backend.BlockChain().Config()
-	if chainconfig.CatalystBlock == nil {
-		return errors.New("catalystBlock is not set in genesis config")
-	} else if chainconfig.CatalystBlock.Sign() != 0 {
-		return errors.New("catalystBlock of genesis config must be zero")
+	if chainconfig.TerminalTotalDifficulty == nil {
+		return errors.New("catalyst started without valid total difficulty")
 	}
 
 	log.Warn("Catalyst mode enabled")
diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go
index f8550fa59b7c2a25997b8c77e384eb0f319f9320..11042086305d403228d8b31299e038652031da2e 100644
--- a/eth/catalyst/api_test.go
+++ b/eth/catalyst/api_test.go
@@ -62,26 +62,28 @@ func generateTestChain() (*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 := &params.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),
-		CatalystBlock:       big.NewInt(0),
-		Ethash:              new(params.EthashConfig),
+		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),
+		TerminalTotalDifficulty: big.NewInt(0),
+		Ethash:                  new(params.EthashConfig),
 	}
 	genesis := &core.Genesis{
 		Config:    config,
@@ -105,6 +107,7 @@ func generateTestChainWithFork(n int, fork int) (*core.Genesis, []*types.Block,
 	forkedBlocks, _ := core.GenerateChain(config, blocks[fork], engine, db, n-fork, generateFork)
 	return genesis, blocks, forkedBlocks
 }
+*/
 
 func TestEth2AssembleBlock(t *testing.T) {
 	genesis, blocks := generateTestChain()
@@ -156,6 +159,8 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
 	}
 }
 
+// TODO (MariusVanDerWijden) reenable once engine api is updated to the latest spec
+/*
 func TestEth2NewBlock(t *testing.T) {
 	genesis, blocks, forkedBlocks := generateTestChainWithFork(10, 4)
 	n, ethservice := startEthService(t, genesis, blocks[1:5])
@@ -216,6 +221,7 @@ func TestEth2NewBlock(t *testing.T) {
 		t.Fatalf("Wrong head after inserting fork %x != %x", exp, ethservice.BlockChain().CurrentBlock().Hash())
 	}
 }
+*/
 
 // startEthService creates a full node instance for testing.
 func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) (*node.Node, *eth.Ethereum) {
diff --git a/eth/tracers/tracer_test.go b/eth/tracers/tracer_test.go
index 3decca225d7a1dfacbf9b975e7cb292d4e073258..63b09bdc6f396ae9732df888b6efcf2ebd529c16 100644
--- a/eth/tracers/tracer_test.go
+++ b/eth/tracers/tracer_test.go
@@ -207,7 +207,7 @@ func TestNoStepExec(t *testing.T) {
 }
 
 func TestIsPrecompile(t *testing.T) {
-	chaincfg := &params.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), CatalystBlock: nil, Ethash: new(params.EthashConfig), Clique: nil}
+	chaincfg := &params.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), TerminalTotalDifficulty: nil, Ethash: new(params.EthashConfig), Clique: nil}
 	chaincfg.ByzantiumBlock = big.NewInt(100)
 	chaincfg.IstanbulBlock = big.NewInt(200)
 	chaincfg.BerlinBlock = big.NewInt(300)
diff --git a/params/config.go b/params/config.go
index 16c8018257768505c7ab9bb144fd454c5704a81d..fdbff930240bd1f05252804bbe07b46347c7f070 100644
--- a/params/config.go
+++ b/params/config.go
@@ -314,7 +314,9 @@ type ChainConfig struct {
 	BerlinBlock         *big.Int `json:"berlinBlock,omitempty"`         // Berlin switch block (nil = no fork, 0 = already on berlin)
 	LondonBlock         *big.Int `json:"londonBlock,omitempty"`         // London switch block (nil = no fork, 0 = already on london)
 
-	CatalystBlock *big.Int `json:"catalystBlock,omitempty"` // Catalyst switch block (nil = no fork, 0 = already on catalyst)
+	// TerminalTotalDifficulty is the amount of total difficulty reached by
+	// the network that triggers the consensus upgrade.
+	TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"`
 
 	// Various consensus engines
 	Ethash *EthashConfig `json:"ethash,omitempty"`
@@ -432,9 +434,12 @@ func (c *ChainConfig) IsLondon(num *big.Int) bool {
 	return isForked(c.LondonBlock, num)
 }
 
-// IsCatalyst returns whether num is either equal to the Merge fork block or greater.
-func (c *ChainConfig) IsCatalyst(num *big.Int) bool {
-	return isForked(c.CatalystBlock, num)
+// IsTerminalPoWBlock returns whether the given block is the last block of PoW stage.
+func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool {
+	if c.TerminalTotalDifficulty == nil {
+		return false
+	}
+	return parentTotalDiff.Cmp(c.TerminalTotalDifficulty) < 0 && totalDiff.Cmp(c.TerminalTotalDifficulty) >= 0
 }
 
 // CheckCompatible checks whether scheduled fork transitions have been imported
@@ -613,7 +618,7 @@ type Rules struct {
 	ChainID                                                 *big.Int
 	IsHomestead, IsEIP150, IsEIP155, IsEIP158               bool
 	IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
-	IsBerlin, IsLondon, IsCatalyst                          bool
+	IsBerlin, IsLondon                                      bool
 }
 
 // Rules ensures c's ChainID is not nil.
@@ -634,6 +639,5 @@ func (c *ChainConfig) Rules(num *big.Int) Rules {
 		IsIstanbul:       c.IsIstanbul(num),
 		IsBerlin:         c.IsBerlin(num),
 		IsLondon:         c.IsLondon(num),
-		IsCatalyst:       c.IsCatalyst(num),
 	}
 }