mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-24 12:37:16 +00:00
d82c778ab3
This PR partially implements [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895): Beacon chain push withdrawals as operations. The new Engine API methods (https://github.com/ethereum/execution-apis/pull/195) are implemented. _Body downloader and saving withdrawals into DB are not implemented yet!_
470 lines
20 KiB
Go
470 lines
20 KiB
Go
package commands
|
|
|
|
import (
|
|
"context"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/holiman/uint256"
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces"
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
|
|
types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types"
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
|
"github.com/ledgerwatch/erigon/common"
|
|
"github.com/ledgerwatch/erigon/common/hexutil"
|
|
"github.com/ledgerwatch/erigon/core/rawdb"
|
|
"github.com/ledgerwatch/erigon/core/types"
|
|
"github.com/ledgerwatch/erigon/ethdb/privateapi"
|
|
"github.com/ledgerwatch/erigon/turbo/rpchelper"
|
|
"github.com/ledgerwatch/log/v3"
|
|
)
|
|
|
|
// ExecutionPayloadV1 represents an execution payload (aka block) without withdrawals
|
|
type ExecutionPayloadV1 struct {
|
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
|
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
|
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
|
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
|
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
|
PrevRandao common.Hash `json:"prevRandao" gencodec:"required"`
|
|
BlockNumber hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
|
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
|
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
|
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
|
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
|
|
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
|
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
|
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
|
}
|
|
|
|
// ExecutionPayloadV2 represents an execution payload (aka block) with withdrawals
|
|
type ExecutionPayloadV2 struct {
|
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
|
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
|
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
|
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
|
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
|
PrevRandao common.Hash `json:"prevRandao" gencodec:"required"`
|
|
BlockNumber hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
|
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
|
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
|
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
|
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
|
|
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
|
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
|
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
|
Withdrawals []*types.Withdrawal `json:"withdrawals" gencodec:"required"`
|
|
}
|
|
|
|
// PayloadAttributes represent the attributes required to start assembling a payload
|
|
type ForkChoiceState struct {
|
|
HeadHash common.Hash `json:"headBlockHash" gencodec:"required"`
|
|
SafeBlockHash common.Hash `json:"safeBlockHash" gencodec:"required"`
|
|
FinalizedBlockHash common.Hash `json:"finalizedBlockHash" gencodec:"required"`
|
|
}
|
|
|
|
// PayloadAttributesV1 represent the attributes required to start assembling a payload without withdrawals
|
|
type PayloadAttributesV1 struct {
|
|
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
|
PrevRandao common.Hash `json:"prevRandao" gencodec:"required"`
|
|
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
|
}
|
|
|
|
// PayloadAttributesV2 represent the attributes required to start assembling a payload with withdrawals
|
|
type PayloadAttributesV2 struct {
|
|
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
|
PrevRandao common.Hash `json:"prevRandao" gencodec:"required"`
|
|
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
|
Withdrawals []*types.Withdrawal `json:"withdrawals" gencodec:"required"`
|
|
}
|
|
|
|
// TransitionConfiguration represents the correct configurations of the CL and the EL
|
|
type TransitionConfiguration struct {
|
|
TerminalTotalDifficulty *hexutil.Big `json:"terminalTotalDifficulty" gencodec:"required"`
|
|
TerminalBlockHash common.Hash `json:"terminalBlockHash" gencodec:"required"`
|
|
TerminalBlockNumber *hexutil.Big `json:"terminalBlockNumber" gencodec:"required"`
|
|
}
|
|
|
|
// EngineAPI Beacon chain communication endpoint
|
|
type EngineAPI interface {
|
|
NewPayloadV1(context.Context, *ExecutionPayloadV1) (map[string]interface{}, error)
|
|
NewPayloadV2(context.Context, *ExecutionPayloadV2) (map[string]interface{}, error)
|
|
ForkchoiceUpdatedV1(ctx context.Context, forkChoiceState *ForkChoiceState, payloadAttributes *PayloadAttributesV1) (map[string]interface{}, error)
|
|
ForkchoiceUpdatedV2(ctx context.Context, forkChoiceState *ForkChoiceState, payloadAttributes *PayloadAttributesV2) (map[string]interface{}, error)
|
|
GetPayloadV1(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayloadV1, error)
|
|
GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayloadV2, error)
|
|
ExchangeTransitionConfigurationV1(ctx context.Context, transitionConfiguration *TransitionConfiguration) (*TransitionConfiguration, error)
|
|
}
|
|
|
|
// EngineImpl is implementation of the EngineAPI interface
|
|
type EngineImpl struct {
|
|
*BaseAPI
|
|
db kv.RoDB
|
|
api rpchelper.ApiBackend
|
|
internalCL bool
|
|
}
|
|
|
|
func convertPayloadStatus(ctx context.Context, db kv.RoDB, x *remote.EnginePayloadStatus) (map[string]interface{}, error) {
|
|
json := map[string]interface{}{
|
|
"status": x.Status.String(),
|
|
}
|
|
if x.ValidationError != "" {
|
|
json["validationError"] = x.ValidationError
|
|
}
|
|
if x.LatestValidHash == nil || (x.Status != remote.EngineStatus_VALID && x.Status != remote.EngineStatus_INVALID) {
|
|
return json, nil
|
|
}
|
|
|
|
latestValidHash := common.Hash(gointerfaces.ConvertH256ToHash(x.LatestValidHash))
|
|
if latestValidHash == (common.Hash{}) || x.Status == remote.EngineStatus_VALID {
|
|
json["latestValidHash"] = latestValidHash
|
|
return json, nil
|
|
}
|
|
|
|
// Per the Engine API spec latestValidHash should be set to 0x0000000000000000000000000000000000000000000000000000000000000000
|
|
// if it refers to a PoW block.
|
|
tx, err := db.BeginRo(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
isValidHashPos, err := rawdb.IsPosBlock(tx, latestValidHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if isValidHashPos {
|
|
json["latestValidHash"] = latestValidHash
|
|
} else {
|
|
json["latestValidHash"] = common.Hash{}
|
|
}
|
|
return json, nil
|
|
}
|
|
|
|
// Engine API specifies that payloadId is 8 bytes
|
|
func addPayloadId(json map[string]interface{}, payloadId uint64) {
|
|
if payloadId != 0 {
|
|
encodedPayloadId := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(encodedPayloadId, payloadId)
|
|
json["payloadId"] = hexutil.Bytes(encodedPayloadId)
|
|
}
|
|
}
|
|
|
|
func (e *EngineImpl) ForkchoiceUpdatedV1(ctx context.Context, forkChoiceState *ForkChoiceState, payloadAttributes *PayloadAttributesV1) (map[string]interface{}, error) {
|
|
if e.internalCL {
|
|
log.Error("EXTERNAL CONSENSUS LAYER IS NOT ENABLED, PLEASE RESTART WITH FLAG --externalcl")
|
|
return nil, fmt.Errorf("engine api should not be used, restart with --externalcl")
|
|
}
|
|
log.Debug("Received ForkchoiceUpdatedV1", "head", forkChoiceState.HeadHash, "safe", forkChoiceState.HeadHash, "finalized", forkChoiceState.FinalizedBlockHash,
|
|
"build", payloadAttributes != nil)
|
|
|
|
var attributes *remote.EnginePayloadAttributes
|
|
if payloadAttributes != nil {
|
|
attributes = &remote.EnginePayloadAttributes{
|
|
Timestamp: uint64(payloadAttributes.Timestamp),
|
|
PrevRandao: gointerfaces.ConvertHashToH256(payloadAttributes.PrevRandao),
|
|
SuggestedFeeRecipient: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient),
|
|
}
|
|
}
|
|
reply, err := e.api.EngineForkchoiceUpdatedV1(ctx, &remote.EngineForkChoiceUpdatedRequest{
|
|
ForkchoiceState: &remote.EngineForkChoiceState{
|
|
HeadBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.HeadHash),
|
|
SafeBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.SafeBlockHash),
|
|
FinalizedBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.FinalizedBlockHash),
|
|
},
|
|
PayloadAttributes: attributes,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
payloadStatus, err := convertPayloadStatus(ctx, e.db, reply.PayloadStatus)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
json := map[string]interface{}{
|
|
"payloadStatus": payloadStatus,
|
|
}
|
|
addPayloadId(json, reply.PayloadId)
|
|
|
|
return json, nil
|
|
}
|
|
|
|
func (e *EngineImpl) ForkchoiceUpdatedV2(ctx context.Context, forkChoiceState *ForkChoiceState, payloadAttributes *PayloadAttributesV2) (map[string]interface{}, error) {
|
|
if e.internalCL {
|
|
log.Error("EXTERNAL CONSENSUS LAYER IS NOT ENABLED, PLEASE RESTART WITH FLAG --externalcl")
|
|
return nil, fmt.Errorf("engine api should not be used, restart with --externalcl")
|
|
}
|
|
log.Debug("Received ForkchoiceUpdatedV2", "head", forkChoiceState.HeadHash, "safe", forkChoiceState.HeadHash, "finalized", forkChoiceState.FinalizedBlockHash,
|
|
"build", payloadAttributes != nil)
|
|
|
|
var attributesV2 *remote.EnginePayloadAttributesV2
|
|
if payloadAttributes != nil {
|
|
attributes := &remote.EnginePayloadAttributes{
|
|
Timestamp: uint64(payloadAttributes.Timestamp),
|
|
PrevRandao: gointerfaces.ConvertHashToH256(payloadAttributes.PrevRandao),
|
|
SuggestedFeeRecipient: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient),
|
|
}
|
|
withdrawals := privateapi.ConvertWithdrawalsToRpc(payloadAttributes.Withdrawals)
|
|
attributesV2 = &remote.EnginePayloadAttributesV2{Attributes: attributes, Withdrawals: withdrawals}
|
|
}
|
|
reply, err := e.api.EngineForkchoiceUpdatedV2(ctx, &remote.EngineForkChoiceUpdatedRequestV2{
|
|
ForkchoiceState: &remote.EngineForkChoiceState{
|
|
HeadBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.HeadHash),
|
|
SafeBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.SafeBlockHash),
|
|
FinalizedBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.FinalizedBlockHash),
|
|
},
|
|
PayloadAttributes: attributesV2,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
payloadStatus, err := convertPayloadStatus(ctx, e.db, reply.PayloadStatus)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
json := map[string]interface{}{
|
|
"payloadStatus": payloadStatus,
|
|
}
|
|
addPayloadId(json, reply.PayloadId)
|
|
|
|
return json, nil
|
|
}
|
|
|
|
// NewPayloadV1 processes new payloads (blocks) from the beacon chain without withdrawals.
|
|
// See https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_newpayloadv1
|
|
func (e *EngineImpl) NewPayloadV1(ctx context.Context, payload *ExecutionPayloadV1) (map[string]interface{}, error) {
|
|
if e.internalCL {
|
|
log.Error("EXTERNAL CONSENSUS LAYER IS NOT ENABLED, PLEASE RESTART WITH FLAG --externalcl")
|
|
return nil, fmt.Errorf("engine api should not be used, restart with --externalcl")
|
|
}
|
|
log.Debug("Received NewPayloadV1", "height", uint64(payload.BlockNumber), "hash", payload.BlockHash)
|
|
|
|
var baseFee *uint256.Int
|
|
if payload.BaseFeePerGas != nil {
|
|
var overflow bool
|
|
baseFee, overflow = uint256.FromBig((*big.Int)(payload.BaseFeePerGas))
|
|
if overflow {
|
|
log.Warn("NewPayload BaseFeePerGas overflow")
|
|
return nil, fmt.Errorf("invalid request")
|
|
}
|
|
}
|
|
|
|
// Convert slice of hexutil.Bytes to a slice of slice of bytes
|
|
transactions := make([][]byte, len(payload.Transactions))
|
|
for i, transaction := range payload.Transactions {
|
|
transactions[i] = transaction
|
|
}
|
|
res, err := e.api.EngineNewPayloadV1(ctx, &types2.ExecutionPayload{
|
|
ParentHash: gointerfaces.ConvertHashToH256(payload.ParentHash),
|
|
Coinbase: gointerfaces.ConvertAddressToH160(payload.FeeRecipient),
|
|
StateRoot: gointerfaces.ConvertHashToH256(payload.StateRoot),
|
|
ReceiptRoot: gointerfaces.ConvertHashToH256(payload.ReceiptsRoot),
|
|
LogsBloom: gointerfaces.ConvertBytesToH2048(payload.LogsBloom),
|
|
PrevRandao: gointerfaces.ConvertHashToH256(payload.PrevRandao),
|
|
BlockNumber: uint64(payload.BlockNumber),
|
|
GasLimit: uint64(payload.GasLimit),
|
|
GasUsed: uint64(payload.GasUsed),
|
|
Timestamp: uint64(payload.Timestamp),
|
|
ExtraData: payload.ExtraData,
|
|
BaseFeePerGas: gointerfaces.ConvertUint256IntToH256(baseFee),
|
|
BlockHash: gointerfaces.ConvertHashToH256(payload.BlockHash),
|
|
Transactions: transactions,
|
|
})
|
|
if err != nil {
|
|
log.Warn("NewPayloadV1", "err", err)
|
|
return nil, err
|
|
}
|
|
return convertPayloadStatus(ctx, e.db, res)
|
|
}
|
|
|
|
// NewPayloadV2 processes new payloads (blocks) from the beacon chain with withdrawals.
|
|
// See https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_newpayloadv2
|
|
func (e *EngineImpl) NewPayloadV2(ctx context.Context, payload *ExecutionPayloadV2) (map[string]interface{}, error) {
|
|
if e.internalCL {
|
|
log.Error("EXTERNAL CONSENSUS LAYER IS NOT ENABLED, PLEASE RESTART WITH FLAG --externalcl")
|
|
return nil, fmt.Errorf("engine api should not be used, restart with --externalcl")
|
|
}
|
|
log.Debug("Received NewPayloadV2", "height", uint64(payload.BlockNumber), "hash", payload.BlockHash)
|
|
|
|
var baseFee *uint256.Int
|
|
if payload.BaseFeePerGas != nil {
|
|
var overflow bool
|
|
baseFee, overflow = uint256.FromBig((*big.Int)(payload.BaseFeePerGas))
|
|
if overflow {
|
|
log.Warn("NewPayload BaseFeePerGas overflow")
|
|
return nil, fmt.Errorf("invalid request")
|
|
}
|
|
}
|
|
|
|
// Convert slice of hexutil.Bytes to a slice of slice of bytes
|
|
transactions := make([][]byte, len(payload.Transactions))
|
|
for i, transaction := range payload.Transactions {
|
|
transactions[i] = transaction
|
|
}
|
|
ep := &types2.ExecutionPayload{
|
|
ParentHash: gointerfaces.ConvertHashToH256(payload.ParentHash),
|
|
Coinbase: gointerfaces.ConvertAddressToH160(payload.FeeRecipient),
|
|
StateRoot: gointerfaces.ConvertHashToH256(payload.StateRoot),
|
|
ReceiptRoot: gointerfaces.ConvertHashToH256(payload.ReceiptsRoot),
|
|
LogsBloom: gointerfaces.ConvertBytesToH2048(payload.LogsBloom),
|
|
PrevRandao: gointerfaces.ConvertHashToH256(payload.PrevRandao),
|
|
BlockNumber: uint64(payload.BlockNumber),
|
|
GasLimit: uint64(payload.GasLimit),
|
|
GasUsed: uint64(payload.GasUsed),
|
|
Timestamp: uint64(payload.Timestamp),
|
|
ExtraData: payload.ExtraData,
|
|
BaseFeePerGas: gointerfaces.ConvertUint256IntToH256(baseFee),
|
|
BlockHash: gointerfaces.ConvertHashToH256(payload.BlockHash),
|
|
Transactions: transactions,
|
|
}
|
|
withdrawals := privateapi.ConvertWithdrawalsToRpc(payload.Withdrawals)
|
|
res, err := e.api.EngineNewPayloadV2(ctx, &types2.ExecutionPayloadV2{Payload: ep, Withdrawals: withdrawals})
|
|
if err != nil {
|
|
log.Warn("NewPayloadV2", "err", err)
|
|
return nil, err
|
|
}
|
|
return convertPayloadStatus(ctx, e.db, res)
|
|
}
|
|
|
|
func (e *EngineImpl) GetPayloadV1(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayloadV1, error) {
|
|
if e.internalCL {
|
|
log.Error("EXTERNAL CONSENSUS LAYER IS NOT ENABLED, PLEASE RESTART WITH FLAG --externalcl")
|
|
return nil, fmt.Errorf("engine api should not be used, restart with --externalcl")
|
|
}
|
|
|
|
decodedPayloadId := binary.BigEndian.Uint64(payloadID)
|
|
log.Info("Received GetPayloadV1", "payloadId", decodedPayloadId)
|
|
|
|
payload, err := e.api.EngineGetPayloadV1(ctx, decodedPayloadId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var bloom types.Bloom = gointerfaces.ConvertH2048ToBloom(payload.LogsBloom)
|
|
|
|
var baseFee *big.Int
|
|
if payload.BaseFeePerGas != nil {
|
|
baseFee = gointerfaces.ConvertH256ToUint256Int(payload.BaseFeePerGas).ToBig()
|
|
}
|
|
|
|
// Convert slice of hexutil.Bytes to a slice of slice of bytes
|
|
transactions := make([]hexutil.Bytes, len(payload.Transactions))
|
|
for i, transaction := range payload.Transactions {
|
|
transactions[i] = transaction
|
|
}
|
|
return &ExecutionPayloadV1{
|
|
ParentHash: gointerfaces.ConvertH256ToHash(payload.ParentHash),
|
|
FeeRecipient: gointerfaces.ConvertH160toAddress(payload.Coinbase),
|
|
StateRoot: gointerfaces.ConvertH256ToHash(payload.StateRoot),
|
|
ReceiptsRoot: gointerfaces.ConvertH256ToHash(payload.ReceiptRoot),
|
|
LogsBloom: bloom[:],
|
|
PrevRandao: gointerfaces.ConvertH256ToHash(payload.PrevRandao),
|
|
BlockNumber: hexutil.Uint64(payload.BlockNumber),
|
|
GasLimit: hexutil.Uint64(payload.GasLimit),
|
|
GasUsed: hexutil.Uint64(payload.GasUsed),
|
|
Timestamp: hexutil.Uint64(payload.Timestamp),
|
|
ExtraData: payload.ExtraData,
|
|
BaseFeePerGas: (*hexutil.Big)(baseFee),
|
|
BlockHash: gointerfaces.ConvertH256ToHash(payload.BlockHash),
|
|
Transactions: transactions,
|
|
}, nil
|
|
}
|
|
|
|
func (e *EngineImpl) GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayloadV2, error) {
|
|
if e.internalCL {
|
|
log.Error("EXTERNAL CONSENSUS LAYER IS NOT ENABLED, PLEASE RESTART WITH FLAG --externalcl")
|
|
return nil, fmt.Errorf("engine api should not be used, restart with --externalcl")
|
|
}
|
|
|
|
decodedPayloadId := binary.BigEndian.Uint64(payloadID)
|
|
log.Info("Received GetPayloadV2", "payloadId", decodedPayloadId)
|
|
|
|
ep, err := e.api.EngineGetPayloadV2(ctx, decodedPayloadId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
payload := ep.Payload
|
|
var bloom types.Bloom = gointerfaces.ConvertH2048ToBloom(payload.LogsBloom)
|
|
|
|
var baseFee *big.Int
|
|
if payload.BaseFeePerGas != nil {
|
|
baseFee = gointerfaces.ConvertH256ToUint256Int(payload.BaseFeePerGas).ToBig()
|
|
}
|
|
|
|
// Convert slice of hexutil.Bytes to a slice of slice of bytes
|
|
transactions := make([]hexutil.Bytes, len(payload.Transactions))
|
|
for i, transaction := range payload.Transactions {
|
|
transactions[i] = transaction
|
|
}
|
|
return &ExecutionPayloadV2{
|
|
ParentHash: gointerfaces.ConvertH256ToHash(payload.ParentHash),
|
|
FeeRecipient: gointerfaces.ConvertH160toAddress(payload.Coinbase),
|
|
StateRoot: gointerfaces.ConvertH256ToHash(payload.StateRoot),
|
|
ReceiptsRoot: gointerfaces.ConvertH256ToHash(payload.ReceiptRoot),
|
|
LogsBloom: bloom[:],
|
|
PrevRandao: gointerfaces.ConvertH256ToHash(payload.PrevRandao),
|
|
BlockNumber: hexutil.Uint64(payload.BlockNumber),
|
|
GasLimit: hexutil.Uint64(payload.GasLimit),
|
|
GasUsed: hexutil.Uint64(payload.GasUsed),
|
|
Timestamp: hexutil.Uint64(payload.Timestamp),
|
|
ExtraData: payload.ExtraData,
|
|
BaseFeePerGas: (*hexutil.Big)(baseFee),
|
|
BlockHash: gointerfaces.ConvertH256ToHash(payload.BlockHash),
|
|
Transactions: transactions,
|
|
Withdrawals: privateapi.ConvertWithdrawalsFromRpc(ep.Withdrawals),
|
|
}, nil
|
|
}
|
|
|
|
// Receives consensus layer's transition configuration and checks if the execution layer has the correct configuration.
|
|
// Can also be used to ping the execution layer (heartbeats).
|
|
// See https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.1/src/engine/specification.md#engine_exchangetransitionconfigurationv1
|
|
func (e *EngineImpl) ExchangeTransitionConfigurationV1(ctx context.Context, beaconConfig *TransitionConfiguration) (*TransitionConfiguration, error) {
|
|
if e.internalCL {
|
|
log.Error("EXTERNAL CONSENSUS LAYER IS NOT ENABLED, PLEASE RESTART WITH FLAG --externalcl")
|
|
return nil, fmt.Errorf("engine api should not be used, restart with --externalcl")
|
|
}
|
|
|
|
tx, err := e.db.BeginRo(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
chainConfig, err := e.BaseAPI.chainConfig(tx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
terminalTotalDifficulty := chainConfig.TerminalTotalDifficulty
|
|
|
|
if terminalTotalDifficulty == nil {
|
|
return nil, fmt.Errorf("the execution layer doesn't have a terminal total difficulty. expected: %v", beaconConfig.TerminalTotalDifficulty)
|
|
}
|
|
|
|
if terminalTotalDifficulty.Cmp((*big.Int)(beaconConfig.TerminalTotalDifficulty)) != 0 {
|
|
return nil, fmt.Errorf("the execution layer has a wrong terminal total difficulty. expected %v, but instead got: %d", beaconConfig.TerminalTotalDifficulty, terminalTotalDifficulty)
|
|
}
|
|
|
|
return &TransitionConfiguration{
|
|
TerminalTotalDifficulty: (*hexutil.Big)(terminalTotalDifficulty),
|
|
TerminalBlockHash: common.Hash{},
|
|
TerminalBlockNumber: (*hexutil.Big)(common.Big0),
|
|
}, nil
|
|
}
|
|
|
|
// NewEngineAPI returns EngineImpl instance
|
|
func NewEngineAPI(base *BaseAPI, db kv.RoDB, api rpchelper.ApiBackend, internalCL bool) *EngineImpl {
|
|
return &EngineImpl{
|
|
BaseAPI: base,
|
|
db: db,
|
|
api: api,
|
|
internalCL: internalCL,
|
|
}
|
|
}
|