eth/catalyst: implement kintsugi spec v1.0.0-alpha.4 (#23984)

This PR implements the new kintsugi specification which can be found here: https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.4/src/engine/specification.md
This commit is contained in:
Marius van der Wijden 2021-12-03 16:26:28 +01:00 committed by GitHub
parent 46f701ca93
commit 93f196c4b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 259 additions and 180 deletions

View File

@ -159,7 +159,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
cfg.Eth.OverrideArrowGlacier = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideArrowGlacierFlag.Name)) cfg.Eth.OverrideArrowGlacier = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideArrowGlacierFlag.Name))
} }
if ctx.GlobalIsSet(utils.OverrideTerminalTotalDifficulty.Name) { if ctx.GlobalIsSet(utils.OverrideTerminalTotalDifficulty.Name) {
cfg.Eth.Genesis.Config.TerminalTotalDifficulty = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideTerminalTotalDifficulty.Name)) cfg.Eth.OverrideTerminalTotalDifficulty = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideTerminalTotalDifficulty.Name))
} }
backend, _ := utils.RegisterEthService(stack, &cfg.Eth, ctx.GlobalBool(utils.CatalystFlag.Name)) backend, _ := utils.RegisterEthService(stack, &cfg.Eth, ctx.GlobalBool(utils.CatalystFlag.Name))

View File

@ -18,7 +18,8 @@
package catalyst package catalyst
import ( import (
"bytes" "crypto/sha256"
"encoding/binary"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
@ -43,10 +44,12 @@ import (
var ( var (
VALID = GenericStringResponse{"VALID"} VALID = GenericStringResponse{"VALID"}
INVALID = GenericStringResponse{"INVALID"} SUCCESS = GenericStringResponse{"SUCCESS"}
SYNCING = GenericStringResponse{"SYNCING"} INVALID = ForkChoiceResponse{Status: "INVALID", PayloadID: nil}
SYNCING = ForkChoiceResponse{Status: "INVALID", PayloadID: nil}
UnknownHeader = rpc.CustomError{Code: -32000, Message: "unknown header"} UnknownHeader = rpc.CustomError{Code: -32000, Message: "unknown header"}
UnknownPayload = rpc.CustomError{Code: -32001, Message: "unknown payload"} UnknownPayload = rpc.CustomError{Code: -32001, Message: "unknown payload"}
InvalidPayloadID = rpc.CustomError{Code: 1, Message: "invalid payload id"}
) )
// Register adds catalyst APIs to the full node. // Register adds catalyst APIs to the full node.
@ -82,7 +85,7 @@ type ConsensusAPI struct {
eth *eth.Ethereum eth *eth.Ethereum
les *les.LightEthereum les *les.LightEthereum
engine consensus.Engine // engine is the post-merge consensus engine, only for block creation engine consensus.Engine // engine is the post-merge consensus engine, only for block creation
preparedBlocks map[int]*ExecutableData preparedBlocks map[uint64]*ExecutableDataV1
} }
func NewConsensusAPI(eth *eth.Ethereum, les *les.LightEthereum) *ConsensusAPI { func NewConsensusAPI(eth *eth.Ethereum, les *les.LightEthereum) *ConsensusAPI {
@ -111,7 +114,7 @@ func NewConsensusAPI(eth *eth.Ethereum, les *les.LightEthereum) *ConsensusAPI {
eth: eth, eth: eth,
les: les, les: les,
engine: engine, engine: engine,
preparedBlocks: make(map[int]*ExecutableData), preparedBlocks: make(map[uint64]*ExecutableDataV1),
} }
} }
@ -171,64 +174,90 @@ func (api *ConsensusAPI) makeEnv(parent *types.Block, header *types.Header) (*bl
return env, nil return env, nil
} }
func (api *ConsensusAPI) PreparePayload(params AssembleBlockParams) (*PayloadResponse, error) { func (api *ConsensusAPI) GetPayloadV1(payloadID hexutil.Bytes) (*ExecutableDataV1, error) {
data, err := api.assembleBlock(params) hash := []byte(payloadID)
if err != nil { if len(hash) < 8 {
return nil, err return nil, &InvalidPayloadID
} }
id := len(api.preparedBlocks) id := binary.BigEndian.Uint64(hash[:8])
api.preparedBlocks[id] = data data, ok := api.preparedBlocks[id]
return &PayloadResponse{PayloadID: uint64(id)}, nil
}
func (api *ConsensusAPI) GetPayload(PayloadID hexutil.Uint64) (*ExecutableData, error) {
data, ok := api.preparedBlocks[int(PayloadID)]
if !ok { if !ok {
return nil, &UnknownPayload return nil, &UnknownPayload
} }
return data, nil return data, nil
} }
// ConsensusValidated is called to mark a block as valid, so func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads ForkchoiceStateV1, PayloadAttributes *PayloadAttributesV1) (ForkChoiceResponse, error) {
// that data that is no longer needed can be removed. if heads.HeadBlockHash == (common.Hash{}) {
func (api *ConsensusAPI) ConsensusValidated(params ConsensusValidatedParams) error { return ForkChoiceResponse{Status: SUCCESS.Status, PayloadID: nil}, nil
switch params.Status {
case VALID.Status:
return nil
case INVALID.Status:
// TODO (MariusVanDerWijden) delete the block from the bc
return nil
default:
return errors.New("invalid params.status")
} }
if err := api.checkTerminalTotalDifficulty(heads.HeadBlockHash); err != nil {
if block := api.eth.BlockChain().GetBlockByHash(heads.HeadBlockHash); block == nil {
// TODO (MariusVanDerWijden) trigger sync
return SYNCING, nil
}
return INVALID, err
}
// If the finalized block is set, check if it is in our blockchain
if heads.FinalizedBlockHash != (common.Hash{}) {
if block := api.eth.BlockChain().GetBlockByHash(heads.FinalizedBlockHash); block == nil {
// TODO (MariusVanDerWijden) trigger sync
return SYNCING, nil
}
}
// SetHead
if err := api.setHead(heads.HeadBlockHash); err != nil {
return INVALID, err
}
// Assemble block (if needed)
if PayloadAttributes != nil {
data, err := api.assembleBlock(heads.HeadBlockHash, PayloadAttributes)
if err != nil {
return INVALID, err
}
hash := computePayloadId(heads.HeadBlockHash, PayloadAttributes)
id := binary.BigEndian.Uint64(hash)
api.preparedBlocks[id] = data
log.Info("Created payload", "payloadid", id)
// TODO (MariusVanDerWijden) do something with the payloadID?
hex := hexutil.Bytes(hash)
return ForkChoiceResponse{Status: SUCCESS.Status, PayloadID: &hex}, nil
}
return ForkChoiceResponse{Status: SUCCESS.Status, PayloadID: nil}, nil
} }
func (api *ConsensusAPI) ForkchoiceUpdated(params ForkChoiceParams) error { func computePayloadId(headBlockHash common.Hash, params *PayloadAttributesV1) []byte {
var emptyHash = common.Hash{} // Hash
if !bytes.Equal(params.HeadBlockHash[:], emptyHash[:]) { hasher := sha256.New()
if err := api.checkTerminalTotalDifficulty(params.HeadBlockHash); err != nil { hasher.Write(headBlockHash[:])
return err binary.Write(hasher, binary.BigEndian, params.Timestamp)
hasher.Write(params.Random[:])
hasher.Write(params.FeeRecipient[:])
return hasher.Sum([]byte{})[:8]
}
func (api *ConsensusAPI) invalid() ExecutePayloadResponse {
if api.light {
return ExecutePayloadResponse{Status: INVALID.Status, LatestValidHash: api.les.BlockChain().CurrentHeader().Hash()}
} }
return api.setHead(params.HeadBlockHash) return ExecutePayloadResponse{Status: INVALID.Status, LatestValidHash: api.eth.BlockChain().CurrentHeader().Hash()}
}
return nil
} }
// ExecutePayload creates an Eth1 block, inserts it in the chain, and returns the status of the chain. // ExecutePayload creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
func (api *ConsensusAPI) ExecutePayload(params ExecutableData) (GenericStringResponse, error) { func (api *ConsensusAPI) ExecutePayloadV1(params ExecutableDataV1) (ExecutePayloadResponse, error) {
block, err := ExecutableDataToBlock(params) block, err := ExecutableDataToBlock(params)
if err != nil { if err != nil {
return INVALID, err return api.invalid(), err
} }
if api.light { if api.light {
parent := api.les.BlockChain().GetHeaderByHash(params.ParentHash) parent := api.les.BlockChain().GetHeaderByHash(params.ParentHash)
if parent == nil { if parent == nil {
return INVALID, fmt.Errorf("could not find parent %x", params.ParentHash) return api.invalid(), fmt.Errorf("could not find parent %x", params.ParentHash)
} }
if err = api.les.BlockChain().InsertHeader(block.Header()); err != nil { if err = api.les.BlockChain().InsertHeader(block.Header()); err != nil {
return INVALID, err return api.invalid(), err
} }
return VALID, nil return ExecutePayloadResponse{Status: VALID.Status, LatestValidHash: block.Hash()}, nil
} }
if !api.eth.BlockChain().HasBlock(block.ParentHash(), block.NumberU64()-1) { if !api.eth.BlockChain().HasBlock(block.ParentHash(), block.NumberU64()-1) {
/* /*
@ -237,37 +266,38 @@ func (api *ConsensusAPI) ExecutePayload(params ExecutableData) (GenericStringRes
return SYNCING, err return SYNCING, err
} }
*/ */
return SYNCING, nil // TODO (MariusVanDerWijden) we should return nil here not empty hash
return ExecutePayloadResponse{Status: SYNCING.Status, LatestValidHash: common.Hash{}}, nil
} }
parent := api.eth.BlockChain().GetBlockByHash(params.ParentHash) parent := api.eth.BlockChain().GetBlockByHash(params.ParentHash)
td := api.eth.BlockChain().GetTd(parent.Hash(), block.NumberU64()-1) td := api.eth.BlockChain().GetTd(parent.Hash(), block.NumberU64()-1)
ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty
if td.Cmp(ttd) < 0 { if td.Cmp(ttd) < 0 {
return INVALID, fmt.Errorf("can not execute payload on top of block with low td got: %v threshold %v", td, ttd) return api.invalid(), fmt.Errorf("can not execute payload on top of block with low td got: %v threshold %v", td, ttd)
} }
if err := api.eth.BlockChain().InsertBlockWithoutSetHead(block); err != nil { if err := api.eth.BlockChain().InsertBlockWithoutSetHead(block); err != nil {
return INVALID, err return api.invalid(), err
} }
merger := api.merger()
if !merger.TDDReached() { if merger := api.merger(); !merger.TDDReached() {
merger.ReachTTD() merger.ReachTTD()
} }
return VALID, nil return ExecutePayloadResponse{Status: VALID.Status, LatestValidHash: block.Hash()}, nil
} }
// AssembleBlock creates a new block, inserts it into the chain, and returns the "execution // AssembleBlock creates a new block, inserts it into the chain, and returns the "execution
// data" required for eth2 clients to process the new block. // data" required for eth2 clients to process the new block.
func (api *ConsensusAPI) assembleBlock(params AssembleBlockParams) (*ExecutableData, error) { func (api *ConsensusAPI) assembleBlock(parentHash common.Hash, params *PayloadAttributesV1) (*ExecutableDataV1, error) {
if api.light { if api.light {
return nil, errors.New("not supported") return nil, errors.New("not supported")
} }
log.Info("Producing block", "parentHash", params.ParentHash) log.Info("Producing block", "parentHash", parentHash)
bc := api.eth.BlockChain() bc := api.eth.BlockChain()
parent := bc.GetBlockByHash(params.ParentHash) parent := bc.GetBlockByHash(parentHash)
if parent == nil { if parent == nil {
log.Warn("Cannot assemble block with parent hash to unknown block", "parentHash", params.ParentHash) log.Warn("Cannot assemble block with parent hash to unknown block", "parentHash", parentHash)
return nil, fmt.Errorf("cannot assemble block with unknown parent %s", params.ParentHash) return nil, fmt.Errorf("cannot assemble block with unknown parent %s", parentHash)
} }
if params.Timestamp < parent.Time() { if params.Timestamp < parent.Time() {
@ -376,7 +406,7 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
return txs, nil return txs, nil
} }
func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) { func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) {
txs, err := decodeTransactions(params.Transactions) txs, err := decodeTransactions(params.Transactions)
if err != nil { if err != nil {
return nil, err return nil, err
@ -410,8 +440,8 @@ func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) {
return block, nil return block, nil
} }
func BlockToExecutableData(block *types.Block, random common.Hash) *ExecutableData { func BlockToExecutableData(block *types.Block, random common.Hash) *ExecutableDataV1 {
return &ExecutableData{ return &ExecutableDataV1{
BlockHash: block.Hash(), BlockHash: block.Hash(),
ParentHash: block.ParentHash(), ParentHash: block.ParentHash(),
Coinbase: block.Coinbase(), Coinbase: block.Coinbase(),
@ -447,11 +477,7 @@ func (api *ConsensusAPI) checkTerminalTotalDifficulty(head common.Hash) error {
if newHeadBlock == nil { if newHeadBlock == nil {
return &UnknownHeader return &UnknownHeader
} }
parent := api.eth.BlockChain().GetBlockByHash(newHeadBlock.ParentHash()) td := api.eth.BlockChain().GetTd(newHeadBlock.Hash(), newHeadBlock.NumberU64())
if parent == nil {
return fmt.Errorf("parent unavailable: %v", newHeadBlock.ParentHash())
}
td := api.eth.BlockChain().GetTd(parent.Hash(), parent.NumberU64())
if td != nil && td.Cmp(api.eth.BlockChain().Config().TerminalTotalDifficulty) < 0 { if td != nil && td.Cmp(api.eth.BlockChain().Config().TerminalTotalDifficulty) < 0 {
return errors.New("total difficulty not reached yet") return errors.New("total difficulty not reached yet")
} }
@ -460,11 +486,6 @@ func (api *ConsensusAPI) checkTerminalTotalDifficulty(head common.Hash) error {
// setHead is called to perform a force choice. // setHead is called to perform a force choice.
func (api *ConsensusAPI) setHead(newHead 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.PoSFinalized() {
merger.FinalizePoS()
}
log.Info("Setting head", "head", newHead) log.Info("Setting head", "head", newHead)
if api.light { if api.light {
headHeader := api.les.BlockChain().CurrentHeader() headHeader := api.les.BlockChain().CurrentHeader()
@ -478,10 +499,19 @@ func (api *ConsensusAPI) setHead(newHead common.Hash) error {
if err := api.les.BlockChain().SetChainHead(newHeadHeader); err != nil { if err := api.les.BlockChain().SetChainHead(newHeadHeader); err != nil {
return err return err
} }
// Trigger the transition if it's the first `NewHead` event.
merger := api.merger()
if !merger.PoSFinalized() {
merger.FinalizePoS()
}
return nil return nil
} }
headBlock := api.eth.BlockChain().CurrentBlock() headBlock := api.eth.BlockChain().CurrentBlock()
if headBlock.Hash() == newHead { if headBlock.Hash() == newHead {
// Trigger the transition if it's the first `NewHead` event.
if merger := api.merger(); !merger.PoSFinalized() {
merger.FinalizePoS()
}
return nil return nil
} }
newHeadBlock := api.eth.BlockChain().GetBlockByHash(newHead) newHeadBlock := api.eth.BlockChain().GetBlockByHash(newHead)
@ -491,6 +521,11 @@ func (api *ConsensusAPI) setHead(newHead common.Hash) error {
if err := api.eth.BlockChain().SetChainHead(newHeadBlock); err != nil { if err := api.eth.BlockChain().SetChainHead(newHeadBlock); err != nil {
return err return err
} }
// Trigger the transition if it's the first `NewHead` event.
if merger := api.merger(); !merger.PoSFinalized() {
merger.FinalizePoS()
}
// TODO (MariusVanDerWijden) are we really synced now?
api.eth.SetSynced() api.eth.SetSynced()
return nil return nil
} }

View File

@ -85,11 +85,10 @@ func TestEth2AssembleBlock(t *testing.T) {
t.Fatalf("error signing transaction, err=%v", err) t.Fatalf("error signing transaction, err=%v", err)
} }
ethservice.TxPool().AddLocal(tx) ethservice.TxPool().AddLocal(tx)
blockParams := AssembleBlockParams{ blockParams := PayloadAttributesV1{
ParentHash: blocks[9].Hash(),
Timestamp: blocks[9].Time() + 5, Timestamp: blocks[9].Time() + 5,
} }
execData, err := api.assembleBlock(blockParams) execData, err := api.assembleBlock(blocks[9].Hash(), &blockParams)
if err != nil { if err != nil {
t.Fatalf("error producing block, err=%v", err) t.Fatalf("error producing block, err=%v", err)
} }
@ -107,11 +106,10 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
// Put the 10th block's tx in the pool and produce a new block // Put the 10th block's tx in the pool and produce a new block
api.insertTransactions(blocks[9].Transactions()) api.insertTransactions(blocks[9].Transactions())
blockParams := AssembleBlockParams{ blockParams := PayloadAttributesV1{
ParentHash: blocks[8].Hash(),
Timestamp: blocks[8].Time() + 5, Timestamp: blocks[8].Time() + 5,
} }
execData, err := api.assembleBlock(blockParams) execData, err := api.assembleBlock(blocks[8].Hash(), &blockParams)
if err != nil { if err != nil {
t.Fatalf("error producing block, err=%v", err) t.Fatalf("error producing block, err=%v", err)
} }
@ -126,14 +124,20 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
defer n.Close() defer n.Close()
api := NewConsensusAPI(ethservice, nil) api := NewConsensusAPI(ethservice, nil)
fcState := ForkchoiceStateV1{
if err := api.ForkchoiceUpdated(ForkChoiceParams{HeadBlockHash: blocks[5].Hash()}); err == nil { HeadBlockHash: blocks[5].Hash(),
SafeBlockHash: common.Hash{},
FinalizedBlockHash: common.Hash{},
}
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err == nil {
t.Errorf("fork choice updated before total terminal difficulty should fail") t.Errorf("fork choice updated before total terminal difficulty should fail")
} }
} }
func TestEth2PrepareAndGetPayload(t *testing.T) { func TestEth2PrepareAndGetPayload(t *testing.T) {
genesis, blocks := generatePreMergeChain(10) genesis, blocks := generatePreMergeChain(10)
// We need to properly set the terminal total difficulty
genesis.Config.TerminalTotalDifficulty.Sub(genesis.Config.TerminalTotalDifficulty, blocks[9].Difficulty())
n, ethservice := startEthService(t, genesis, blocks[:9]) n, ethservice := startEthService(t, genesis, blocks[:9])
defer n.Close() defer n.Close()
@ -141,15 +145,20 @@ func TestEth2PrepareAndGetPayload(t *testing.T) {
// Put the 10th block's tx in the pool and produce a new block // Put the 10th block's tx in the pool and produce a new block
api.insertTransactions(blocks[9].Transactions()) api.insertTransactions(blocks[9].Transactions())
blockParams := AssembleBlockParams{ blockParams := PayloadAttributesV1{
ParentHash: blocks[8].Hash(),
Timestamp: blocks[8].Time() + 5, Timestamp: blocks[8].Time() + 5,
} }
respID, err := api.PreparePayload(blockParams) fcState := ForkchoiceStateV1{
HeadBlockHash: blocks[8].Hash(),
SafeBlockHash: common.Hash{},
FinalizedBlockHash: common.Hash{},
}
_, err := api.ForkchoiceUpdatedV1(fcState, &blockParams)
if err != nil { if err != nil {
t.Fatalf("error preparing payload, err=%v", err) t.Fatalf("error preparing payload, err=%v", err)
} }
execData, err := api.GetPayload(hexutil.Uint64(respID.PayloadID)) payloadID := computePayloadId(fcState.HeadBlockHash, &blockParams)
execData, err := api.GetPayloadV1(hexutil.Bytes(payloadID))
if err != nil { if err != nil {
t.Fatalf("error getting payload, err=%v", err) t.Fatalf("error getting payload, err=%v", err)
} }
@ -201,8 +210,7 @@ func TestEth2NewBlock(t *testing.T) {
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().AddLocal(tx) ethservice.TxPool().AddLocal(tx)
execData, err := api.assembleBlock(AssembleBlockParams{ execData, err := api.assembleBlock(parent.Hash(), &PayloadAttributesV1{
ParentHash: parent.Hash(),
Timestamp: parent.Time() + 5, Timestamp: parent.Time() + 5,
}) })
if err != nil { if err != nil {
@ -212,7 +220,7 @@ func TestEth2NewBlock(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to convert executable data to block %v", err) t.Fatalf("Failed to convert executable data to block %v", err)
} }
newResp, err := api.ExecutePayload(*execData) newResp, err := api.ExecutePayloadV1(*execData)
if err != nil || newResp.Status != "VALID" { if err != nil || newResp.Status != "VALID" {
t.Fatalf("Failed to insert block: %v", err) t.Fatalf("Failed to insert block: %v", err)
} }
@ -220,8 +228,12 @@ func TestEth2NewBlock(t *testing.T) {
t.Fatalf("Chain head shouldn't be updated") t.Fatalf("Chain head shouldn't be updated")
} }
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
fcState := ForkchoiceStateV1{
if err := api.ForkchoiceUpdated(ForkChoiceParams{HeadBlockHash: block.Hash(), FinalizedBlockHash: block.Hash()}); err != nil { HeadBlockHash: block.Hash(),
SafeBlockHash: block.Hash(),
FinalizedBlockHash: block.Hash(),
}
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
t.Fatalf("Failed to insert block: %v", err) t.Fatalf("Failed to insert block: %v", err)
} }
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() { if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
@ -238,8 +250,7 @@ func TestEth2NewBlock(t *testing.T) {
) )
parent = preMergeBlocks[len(preMergeBlocks)-1] parent = preMergeBlocks[len(preMergeBlocks)-1]
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
execData, err := api.assembleBlock(AssembleBlockParams{ execData, err := api.assembleBlock(parent.Hash(), &PayloadAttributesV1{
ParentHash: parent.Hash(),
Timestamp: parent.Time() + 6, Timestamp: parent.Time() + 6,
}) })
if err != nil { if err != nil {
@ -249,7 +260,7 @@ func TestEth2NewBlock(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to convert executable data to block %v", err) t.Fatalf("Failed to convert executable data to block %v", err)
} }
newResp, err := api.ExecutePayload(*execData) newResp, err := api.ExecutePayloadV1(*execData)
if err != nil || newResp.Status != "VALID" { if err != nil || newResp.Status != "VALID" {
t.Fatalf("Failed to insert block: %v", err) t.Fatalf("Failed to insert block: %v", err)
} }
@ -257,10 +268,12 @@ func TestEth2NewBlock(t *testing.T) {
t.Fatalf("Chain head shouldn't be updated") t.Fatalf("Chain head shouldn't be updated")
} }
if err := api.ConsensusValidated(ConsensusValidatedParams{BlockHash: block.Hash(), Status: "VALID"}); err != nil { fcState := ForkchoiceStateV1{
t.Fatalf("Failed to insert block: %v", err) HeadBlockHash: block.Hash(),
SafeBlockHash: block.Hash(),
FinalizedBlockHash: block.Hash(),
} }
if err := api.ForkchoiceUpdated(ForkChoiceParams{FinalizedBlockHash: block.Hash(), HeadBlockHash: block.Hash()}); err != nil { if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
t.Fatalf("Failed to insert block: %v", err) t.Fatalf("Failed to insert block: %v", err)
} }
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() { if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
@ -360,33 +373,41 @@ func TestFullAPI(t *testing.T) {
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().AddLocal(tx) ethservice.TxPool().AddLocal(tx)
params := AssembleBlockParams{ params := PayloadAttributesV1{
ParentHash: parent.Hash(),
Timestamp: parent.Time() + 1, Timestamp: parent.Time() + 1,
Random: crypto.Keccak256Hash([]byte{byte(i)}), Random: crypto.Keccak256Hash([]byte{byte(i)}),
FeeRecipient: parent.Coinbase(), FeeRecipient: parent.Coinbase(),
} }
resp, err := api.PreparePayload(params) fcState := ForkchoiceStateV1{
if err != nil { HeadBlockHash: parent.Hash(),
t.Fatalf("can't prepare payload: %v", err) SafeBlockHash: common.Hash{},
FinalizedBlockHash: common.Hash{},
} }
payload, err := api.GetPayload(hexutil.Uint64(resp.PayloadID)) resp, err := api.ForkchoiceUpdatedV1(fcState, &params)
if err != nil {
t.Fatalf("error preparing payload, err=%v", err)
}
if resp.Status != SUCCESS.Status {
t.Fatalf("error preparing payload, invalid status: %v", resp.Status)
}
payloadID := computePayloadId(parent.Hash(), &params)
payload, err := api.GetPayloadV1(hexutil.Bytes(payloadID))
if err != nil { if err != nil {
t.Fatalf("can't get payload: %v", err) t.Fatalf("can't get payload: %v", err)
} }
execResp, err := api.ExecutePayload(*payload) execResp, err := api.ExecutePayloadV1(*payload)
if err != nil { if err != nil {
t.Fatalf("can't execute payload: %v", err) t.Fatalf("can't execute payload: %v", err)
} }
if execResp.Status != VALID.Status { if execResp.Status != VALID.Status {
t.Fatalf("invalid status: %v", execResp.Status) t.Fatalf("invalid status: %v", execResp.Status)
} }
fcState = ForkchoiceStateV1{
if err := api.ConsensusValidated(ConsensusValidatedParams{BlockHash: payload.BlockHash, Status: VALID.Status}); err != nil { HeadBlockHash: payload.BlockHash,
t.Fatalf("failed to validate consensus: %v", err) SafeBlockHash: payload.ParentHash,
FinalizedBlockHash: payload.ParentHash,
} }
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
if err := api.ForkchoiceUpdated(ForkChoiceParams{HeadBlockHash: payload.BlockHash, FinalizedBlockHash: payload.BlockHash}); err != nil {
t.Fatalf("Failed to insert block: %v", err) t.Fatalf("Failed to insert block: %v", err)
} }
if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number { if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number {

View File

@ -23,26 +23,24 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
) )
//go:generate go run github.com/fjl/gencodec -type AssembleBlockParams -field-override assembleBlockParamsMarshaling -out gen_blockparams.go //go:generate go run github.com/fjl/gencodec -type PayloadAttributesV1 -field-override payloadAttributesMarshaling -out gen_blockparams.go
// Structure described at https://github.com/ethereum/execution-apis/pull/74 // Structure described at https://github.com/ethereum/execution-apis/pull/74
type AssembleBlockParams struct { type PayloadAttributesV1 struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
Timestamp uint64 `json:"timestamp" gencodec:"required"` Timestamp uint64 `json:"timestamp" gencodec:"required"`
Random common.Hash `json:"random" gencodec:"required"` Random common.Hash `json:"random" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
} }
// JSON type overrides for assembleBlockParams. // JSON type overrides for PayloadAttributesV1.
type assembleBlockParamsMarshaling struct { type payloadAttributesMarshaling struct {
Timestamp hexutil.Uint64 Timestamp hexutil.Uint64
} }
//go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go //go:generate go run github.com/fjl/gencodec -type ExecutableDataV1 -field-override executableDataMarshaling -out gen_ed.go
// Structure described at https://github.com/ethereum/execution-apis/pull/74/files // Structure described at https://github.com/ethereum/execution-apis/src/engine/specification.md
type ExecutableData struct { type ExecutableDataV1 struct {
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
ParentHash common.Hash `json:"parentHash" gencodec:"required"` ParentHash common.Hash `json:"parentHash" gencodec:"required"`
Coinbase common.Address `json:"coinbase" gencodec:"required"` Coinbase common.Address `json:"coinbase" gencodec:"required"`
StateRoot common.Hash `json:"stateRoot" gencodec:"required"` StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
@ -55,6 +53,7 @@ type ExecutableData struct {
Timestamp uint64 `json:"timestamp" gencodec:"required"` Timestamp uint64 `json:"timestamp" gencodec:"required"`
ExtraData []byte `json:"extraData" gencodec:"required"` ExtraData []byte `json:"extraData" gencodec:"required"`
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"` BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
Transactions [][]byte `json:"transactions" gencodec:"required"` Transactions [][]byte `json:"transactions" gencodec:"required"`
} }
@ -93,12 +92,23 @@ type GenericStringResponse struct {
Status string `json:"status"` Status string `json:"status"`
} }
type ExecutePayloadResponse struct {
Status string `json:"status"`
LatestValidHash common.Hash `json:"latestValidHash"`
}
type ConsensusValidatedParams struct { type ConsensusValidatedParams struct {
BlockHash common.Hash `json:"blockHash"` BlockHash common.Hash `json:"blockHash"`
Status string `json:"status"` Status string `json:"status"`
} }
type ForkChoiceParams struct { type ForkChoiceResponse struct {
Status string `json:"status"`
PayloadID *hexutil.Bytes `json:"payloadId"`
}
type ForkchoiceStateV1 struct {
HeadBlockHash common.Hash `json:"headBlockHash"` HeadBlockHash common.Hash `json:"headBlockHash"`
SafeBlockHash common.Hash `json:"safeBlockHash"`
FinalizedBlockHash common.Hash `json:"finalizedBlockHash"` FinalizedBlockHash common.Hash `json:"finalizedBlockHash"`
} }

View File

@ -10,51 +10,44 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
) )
var _ = (*assembleBlockParamsMarshaling)(nil) var _ = (*payloadAttributesMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (a AssembleBlockParams) MarshalJSON() ([]byte, error) { func (p PayloadAttributesV1) MarshalJSON() ([]byte, error) {
type AssembleBlockParams struct { type PayloadAttributesV1 struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
Random common.Hash `json:"random" gencodec:"required"` Random common.Hash `json:"random" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
} }
var enc AssembleBlockParams var enc PayloadAttributesV1
enc.ParentHash = a.ParentHash enc.Timestamp = hexutil.Uint64(p.Timestamp)
enc.Timestamp = hexutil.Uint64(a.Timestamp) enc.Random = p.Random
enc.Random = a.Random enc.FeeRecipient = p.FeeRecipient
enc.FeeRecipient = a.FeeRecipient
return json.Marshal(&enc) return json.Marshal(&enc)
} }
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (a *AssembleBlockParams) UnmarshalJSON(input []byte) error { func (p *PayloadAttributesV1) UnmarshalJSON(input []byte) error {
type AssembleBlockParams struct { type PayloadAttributesV1 struct {
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
Random *common.Hash `json:"random" gencodec:"required"` Random *common.Hash `json:"random" gencodec:"required"`
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"` FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
} }
var dec AssembleBlockParams var dec PayloadAttributesV1
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
return err return err
} }
if dec.ParentHash == nil {
return errors.New("missing required field 'parentHash' for AssembleBlockParams")
}
a.ParentHash = *dec.ParentHash
if dec.Timestamp == nil { if dec.Timestamp == nil {
return errors.New("missing required field 'timestamp' for AssembleBlockParams") return errors.New("missing required field 'timestamp' for PayloadAttributesV1")
} }
a.Timestamp = uint64(*dec.Timestamp) p.Timestamp = uint64(*dec.Timestamp)
if dec.Random == nil { if dec.Random == nil {
return errors.New("missing required field 'random' for AssembleBlockParams") return errors.New("missing required field 'random' for PayloadAttributesV1")
} }
a.Random = *dec.Random p.Random = *dec.Random
if dec.FeeRecipient == nil { if dec.FeeRecipient == nil {
return errors.New("missing required field 'feeRecipient' for AssembleBlockParams") return errors.New("missing required field 'feeRecipient' for PayloadAttributesV1")
} }
a.FeeRecipient = *dec.FeeRecipient p.FeeRecipient = *dec.FeeRecipient
return nil return nil
} }

View File

@ -14,9 +14,8 @@ import (
var _ = (*executableDataMarshaling)(nil) var _ = (*executableDataMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (e ExecutableData) MarshalJSON() ([]byte, error) { func (e ExecutableDataV1) MarshalJSON() ([]byte, error) {
type ExecutableData struct { type ExecutableDataV1 struct {
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
ParentHash common.Hash `json:"parentHash" gencodec:"required"` ParentHash common.Hash `json:"parentHash" gencodec:"required"`
Coinbase common.Address `json:"coinbase" gencodec:"required"` Coinbase common.Address `json:"coinbase" gencodec:"required"`
StateRoot common.Hash `json:"stateRoot" gencodec:"required"` StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
@ -29,10 +28,10 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"` ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
} }
var enc ExecutableData var enc ExecutableDataV1
enc.BlockHash = e.BlockHash
enc.ParentHash = e.ParentHash enc.ParentHash = e.ParentHash
enc.Coinbase = e.Coinbase enc.Coinbase = e.Coinbase
enc.StateRoot = e.StateRoot enc.StateRoot = e.StateRoot
@ -45,6 +44,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
enc.Timestamp = hexutil.Uint64(e.Timestamp) enc.Timestamp = hexutil.Uint64(e.Timestamp)
enc.ExtraData = e.ExtraData enc.ExtraData = e.ExtraData
enc.BaseFeePerGas = (*hexutil.Big)(e.BaseFeePerGas) enc.BaseFeePerGas = (*hexutil.Big)(e.BaseFeePerGas)
enc.BlockHash = e.BlockHash
if e.Transactions != nil { if e.Transactions != nil {
enc.Transactions = make([]hexutil.Bytes, len(e.Transactions)) enc.Transactions = make([]hexutil.Bytes, len(e.Transactions))
for k, v := range e.Transactions { for k, v := range e.Transactions {
@ -55,9 +55,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
} }
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (e *ExecutableData) UnmarshalJSON(input []byte) error { func (e *ExecutableDataV1) UnmarshalJSON(input []byte) error {
type ExecutableData struct { type ExecutableDataV1 struct {
BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
ParentHash *common.Hash `json:"parentHash" gencodec:"required"` ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
Coinbase *common.Address `json:"coinbase" gencodec:"required"` Coinbase *common.Address `json:"coinbase" gencodec:"required"`
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
@ -70,66 +69,67 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"` ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
} }
var dec ExecutableData var dec ExecutableDataV1
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
return err return err
} }
if dec.BlockHash == nil {
return errors.New("missing required field 'blockHash' for ExecutableData")
}
e.BlockHash = *dec.BlockHash
if dec.ParentHash == nil { if dec.ParentHash == nil {
return errors.New("missing required field 'parentHash' for ExecutableData") return errors.New("missing required field 'parentHash' for ExecutableDataV1")
} }
e.ParentHash = *dec.ParentHash e.ParentHash = *dec.ParentHash
if dec.Coinbase == nil { if dec.Coinbase == nil {
return errors.New("missing required field 'coinbase' for ExecutableData") return errors.New("missing required field 'coinbase' for ExecutableDataV1")
} }
e.Coinbase = *dec.Coinbase e.Coinbase = *dec.Coinbase
if dec.StateRoot == nil { if dec.StateRoot == nil {
return errors.New("missing required field 'stateRoot' for ExecutableData") return errors.New("missing required field 'stateRoot' for ExecutableDataV1")
} }
e.StateRoot = *dec.StateRoot e.StateRoot = *dec.StateRoot
if dec.ReceiptRoot == nil { if dec.ReceiptRoot == nil {
return errors.New("missing required field 'receiptRoot' for ExecutableData") return errors.New("missing required field 'receiptRoot' for ExecutableDataV1")
} }
e.ReceiptRoot = *dec.ReceiptRoot e.ReceiptRoot = *dec.ReceiptRoot
if dec.LogsBloom == nil { if dec.LogsBloom == nil {
return errors.New("missing required field 'logsBloom' for ExecutableData") return errors.New("missing required field 'logsBloom' for ExecutableDataV1")
} }
e.LogsBloom = *dec.LogsBloom e.LogsBloom = *dec.LogsBloom
if dec.Random == nil { if dec.Random == nil {
return errors.New("missing required field 'random' for ExecutableData") return errors.New("missing required field 'random' for ExecutableDataV1")
} }
e.Random = *dec.Random e.Random = *dec.Random
if dec.Number == nil { if dec.Number == nil {
return errors.New("missing required field 'blockNumber' for ExecutableData") return errors.New("missing required field 'blockNumber' for ExecutableDataV1")
} }
e.Number = uint64(*dec.Number) e.Number = uint64(*dec.Number)
if dec.GasLimit == nil { if dec.GasLimit == nil {
return errors.New("missing required field 'gasLimit' for ExecutableData") return errors.New("missing required field 'gasLimit' for ExecutableDataV1")
} }
e.GasLimit = uint64(*dec.GasLimit) e.GasLimit = uint64(*dec.GasLimit)
if dec.GasUsed == nil { if dec.GasUsed == nil {
return errors.New("missing required field 'gasUsed' for ExecutableData") return errors.New("missing required field 'gasUsed' for ExecutableDataV1")
} }
e.GasUsed = uint64(*dec.GasUsed) e.GasUsed = uint64(*dec.GasUsed)
if dec.Timestamp == nil { if dec.Timestamp == nil {
return errors.New("missing required field 'timestamp' for ExecutableData") return errors.New("missing required field 'timestamp' for ExecutableDataV1")
} }
e.Timestamp = uint64(*dec.Timestamp) e.Timestamp = uint64(*dec.Timestamp)
if dec.ExtraData == nil { if dec.ExtraData == nil {
return errors.New("missing required field 'extraData' for ExecutableData") return errors.New("missing required field 'extraData' for ExecutableDataV1")
} }
e.ExtraData = *dec.ExtraData e.ExtraData = *dec.ExtraData
if dec.BaseFeePerGas == nil { if dec.BaseFeePerGas == nil {
return errors.New("missing required field 'baseFeePerGas' for ExecutableData") return errors.New("missing required field 'baseFeePerGas' for ExecutableDataV1")
} }
e.BaseFeePerGas = (*big.Int)(dec.BaseFeePerGas) e.BaseFeePerGas = (*big.Int)(dec.BaseFeePerGas)
if dec.BlockHash == nil {
return errors.New("missing required field 'blockHash' for ExecutableDataV1")
}
e.BlockHash = *dec.BlockHash
if dec.Transactions == nil { if dec.Transactions == nil {
return errors.New("missing required field 'transactions' for ExecutableData") return errors.New("missing required field 'transactions' for ExecutableDataV1")
} }
e.Transactions = make([][]byte, len(dec.Transactions)) e.Transactions = make([][]byte, len(dec.Transactions))
for k, v := range dec.Transactions { for k, v := range dec.Transactions {

View File

@ -30,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -138,25 +137,30 @@ func newNode(typ nodetype, genesis *core.Genesis, enodes []*enode.Node) *ethNode
} }
} }
func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*catalyst.ExecutableData, error) { func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*catalyst.ExecutableDataV1, error) {
if n.typ != eth2MiningNode { if n.typ != eth2MiningNode {
return nil, errors.New("invalid node type") return nil, errors.New("invalid node type")
} }
payload, err := n.api.PreparePayload(catalyst.AssembleBlockParams{ payloadAttribute := catalyst.PayloadAttributesV1{
ParentHash: parentHash,
Timestamp: uint64(time.Now().Unix()), Timestamp: uint64(time.Now().Unix()),
}) }
fcState := catalyst.ForkchoiceStateV1{
HeadBlockHash: parentHash,
SafeBlockHash: common.Hash{},
FinalizedBlockHash: common.Hash{},
}
payload, err := n.api.ForkchoiceUpdatedV1(fcState, &payloadAttribute)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return n.api.GetPayload(hexutil.Uint64(payload.PayloadID)) return n.api.GetPayloadV1(*payload.PayloadID)
} }
func (n *ethNode) insertBlock(eb catalyst.ExecutableData) error { func (n *ethNode) insertBlock(eb catalyst.ExecutableDataV1) error {
if !eth2types(n.typ) { if !eth2types(n.typ) {
return errors.New("invalid node type") return errors.New("invalid node type")
} }
newResp, err := n.api.ExecutePayload(eb) newResp, err := n.api.ExecutePayloadV1(eb)
if err != nil { if err != nil {
return err return err
} else if newResp.Status != "VALID" { } else if newResp.Status != "VALID" {
@ -165,7 +169,7 @@ func (n *ethNode) insertBlock(eb catalyst.ExecutableData) error {
return nil return nil
} }
func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed catalyst.ExecutableData) error { func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed catalyst.ExecutableDataV1) error {
if !eth2types(n.typ) { if !eth2types(n.typ) {
return errors.New("invalid node type") return errors.New("invalid node type")
} }
@ -176,7 +180,12 @@ func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed catalyst.Execut
if err != nil { if err != nil {
return err return err
} }
if err := n.api.ConsensusValidated(catalyst.ConsensusValidatedParams{BlockHash: block.Hash(), Status: "VALID"}); err != nil { fcState := catalyst.ForkchoiceStateV1{
HeadBlockHash: block.ParentHash(),
SafeBlockHash: common.Hash{},
FinalizedBlockHash: common.Hash{},
}
if _, err := n.api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
return err return err
} }
return nil return nil
@ -275,7 +284,12 @@ func (mgr *nodeManager) run() {
nodes = append(nodes, mgr.getNodes(eth2NormalNode)...) nodes = append(nodes, mgr.getNodes(eth2NormalNode)...)
nodes = append(nodes, mgr.getNodes(eth2LightClient)...) nodes = append(nodes, mgr.getNodes(eth2LightClient)...)
for _, node := range append(nodes) { for _, node := range append(nodes) {
node.api.ConsensusValidated(catalyst.ConsensusValidatedParams{BlockHash: oldest.Hash(), Status: catalyst.VALID.Status}) fcState := catalyst.ForkchoiceStateV1{
HeadBlockHash: oldest.Hash(),
SafeBlockHash: common.Hash{},
FinalizedBlockHash: common.Hash{},
}
node.api.ForkchoiceUpdatedV1(fcState, nil)
} }
log.Info("Finalised eth2 block", "number", oldest.NumberU64(), "hash", oldest.Hash()) log.Info("Finalised eth2 block", "number", oldest.NumberU64(), "hash", oldest.Hash())
waitFinalise = waitFinalise[1:] waitFinalise = waitFinalise[1:]

View File

@ -1040,7 +1040,13 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st
return err return err
} }
if w.isRunning() && !w.merger.TDDReached() { // If we're post merge, just ignore
td, ttd := w.chain.GetTd(block.ParentHash(), block.NumberU64()-1), w.chain.Config().TerminalTotalDifficulty
if td != nil && ttd != nil && td.Cmp(ttd) >= 0 {
return nil
}
if w.isRunning() {
if interval != nil { if interval != nil {
interval() interval()
} }