forked from cerc-io/plugeth
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:
parent
46f701ca93
commit
93f196c4b0
@ -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))
|
||||||
|
|
||||||
|
@ -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]
|
||||||
}
|
}
|
||||||
return api.setHead(params.HeadBlockHash)
|
|
||||||
|
func (api *ConsensusAPI) invalid() ExecutePayloadResponse {
|
||||||
|
if api.light {
|
||||||
|
return ExecutePayloadResponse{Status: INVALID.Status, LatestValidHash: api.les.BlockChain().CurrentHeader().Hash()}
|
||||||
}
|
}
|
||||||
return nil
|
return ExecutePayloadResponse{Status: INVALID.Status, LatestValidHash: api.eth.BlockChain().CurrentHeader().Hash()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
@ -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, ¶ms)
|
||||||
|
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(), ¶ms)
|
||||||
|
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 {
|
||||||
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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:]
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user