Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support engine_forkchoiceUpdatedV3 with ParentBeaconBlockRoot (EIP-4788) #7969

Merged
merged 7 commits into from
Aug 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ Erigon can be used as an Execution Layer (EL) for Consensus Layer clients (CL).
If your CL client is on a different device, add `--authrpc.addr 0.0.0.0` ([Engine API] listens on localhost by default)
as well as `--authrpc.vhosts <CL host>` where `<CL host>` is your source host or `any`.

[Engine API]: https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md
[Engine API]: https://github.com/ethereum/execution-apis/blob/main/src/engine

In order to establish a secure connection between the Consensus Layer and the Execution Layer, a JWT secret key is
automatically generated.
Expand Down
1 change: 1 addition & 0 deletions cl/phase1/execution_client/rpc_helper/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ const EngineNewPayloadV3 = "engine_newPayloadV3"

const ForkChoiceUpdatedV1 = "engine_forkchoiceUpdatedV1"
const ForkChoiceUpdatedV2 = "engine_forkchoiceUpdatedV2"
const ForkChoiceUpdatedV3 = "engine_forkchoiceUpdatedV3"
1 change: 1 addition & 0 deletions cmd/rpcdaemon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ The following table shows the current implementation status of Erigon's RPC daem
| engine_newPayloadV3 | Yes | |
| engine_forkchoiceUpdatedV1 | Yes | |
| engine_forkchoiceUpdatedV2 | Yes | |
| engine_forkchoiceUpdatedV3 | Yes | |
| engine_getPayloadV1 | Yes | |
| engine_getPayloadV2 | Yes | |
| engine_getPayloadV3 | Yes | |
Expand Down
7 changes: 4 additions & 3 deletions core/block_builder_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
)

// Parameters for PoS block building
// See also https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#payloadattributesv2
// See also https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#payloadattributesv3
type BlockBuilderParameters struct {
PayloadId uint64
ParentHash libcommon.Hash
Timestamp uint64
PrevRandao libcommon.Hash
SuggestedFeeRecipient libcommon.Address
Withdrawals []*types.Withdrawal
PayloadId uint64
Withdrawals []*types.Withdrawal // added in Shapella (EIP-4895)
ParentBeaconBlockRoot *libcommon.Hash // added in Dencun (EIP-4788)
}
1 change: 1 addition & 0 deletions eth/stagedsync/stage_mining_create_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ func SpawnMiningCreateBlockStage(s *StageState, tx kv.RwTx, cfg MiningCreateBloc

if cfg.blockBuilderParameters != nil {
header.MixDigest = cfg.blockBuilderParameters.PrevRandao
header.ParentBeaconBlockRoot = cfg.blockBuilderParameters.ParentBeaconBlockRoot

current.Header = header
current.Uncles = nil
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/ledgerwatch/erigon
go 1.19

require (
github.com/ledgerwatch/erigon-lib v0.0.0-20230806000623-e9a42e443c30
github.com/ledgerwatch/erigon-lib v0.0.0-20230806094003-563a68124b44
github.com/ledgerwatch/erigon-snapshot v1.2.1-0.20230622075030-1d69651854c2
github.com/ledgerwatch/log/v3 v3.8.0
github.com/ledgerwatch/secp256k1 v1.0.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758 h1:0D5M2HQSGD3PYPwICLl+/9oulQauOuETfgFvhBDffs0=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/ledgerwatch/erigon-lib v0.0.0-20230806000623-e9a42e443c30 h1:FdZJ/lz6Uv936nQe/n7tTVc/VXcdXgipC5oPi31TEXk=
github.com/ledgerwatch/erigon-lib v0.0.0-20230806000623-e9a42e443c30/go.mod h1:g8v1BUhWTrK1mDMLLzFYMmLfqmfrqQmXyCPxRiBJ7iA=
github.com/ledgerwatch/erigon-lib v0.0.0-20230806094003-563a68124b44 h1:5tmiUuLlj94snkO1Ljq12dmqBDG+ncO2IQNPe9fU0HA=
github.com/ledgerwatch/erigon-lib v0.0.0-20230806094003-563a68124b44/go.mod h1:vMETmlckriMRtrg81+YGcmA4/V3XFmjScMqjCojPr3g=
github.com/ledgerwatch/erigon-snapshot v1.2.1-0.20230622075030-1d69651854c2 h1:Ls2itRGHMOr2PbHRDA4g1HH8HQdwfJhRVfMPEaLQe94=
github.com/ledgerwatch/erigon-snapshot v1.2.1-0.20230622075030-1d69651854c2/go.mod h1:3AuPxZc85jkehh/HA9h8gabv5MSi3kb/ddtzBsTVJFo=
github.com/ledgerwatch/log/v3 v3.8.0 h1:gCpp7uGtIerEz1jKVPeDnbIopFPud9ZnCpBLlLBGqPU=
Expand Down
7 changes: 7 additions & 0 deletions rpc/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ func (e *InvalidParamsError) ErrorCode() int { return -32602 }

func (e *InvalidParamsError) Error() string { return e.Message }

// mismatch between the Engine API method version and the fork
type UnsupportedForkError struct{ Message string }

func (e *UnsupportedForkError) ErrorCode() int { return -38005 }

func (e *UnsupportedForkError) Error() string { return e.Message }

type CustomError struct {
Code int
Message string
Expand Down
40 changes: 28 additions & 12 deletions turbo/engineapi/engine_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (s *EngineServer) checkWithdrawalsPresence(time uint64, withdrawals []*type

// EngineNewPayload validates and possibly executes payload
func (s *EngineServer) newPayload(ctx context.Context, req *engine_types.ExecutionPayload,
expectedBlobHashes []libcommon.Hash, version clparams.StateVersion,
expectedBlobHashes []libcommon.Hash, parentBeaconBlockRoot *libcommon.Hash, version clparams.StateVersion,
) (*engine_types.PayloadStatus, error) {
var bloom types.Bloom
copy(bloom[:], req.LogsBloom)
Expand Down Expand Up @@ -160,16 +160,22 @@ func (s *EngineServer) newPayload(ctx context.Context, req *engine_types.Executi
if version >= clparams.DenebVersion {
header.BlobGasUsed = (*uint64)(req.BlobGasUsed)
header.ExcessBlobGas = (*uint64)(req.ExcessBlobGas)
header.ParentBeaconBlockRoot = parentBeaconBlockRoot
}

if !s.config.IsCancun(header.Time) && (header.BlobGasUsed != nil || header.ExcessBlobGas != nil) {
return nil, &rpc.InvalidParamsError{Message: "blobGasUsed/excessBlobGas present before Cancun"}
if (!s.config.IsCancun(header.Time) && version >= clparams.DenebVersion) ||
(s.config.IsCancun(header.Time) && version < clparams.DenebVersion) {
return nil, &rpc.UnsupportedForkError{Message: "Unsupported fork"}
}

if s.config.IsCancun(header.Time) && (header.BlobGasUsed == nil || header.ExcessBlobGas == nil) {
return nil, &rpc.InvalidParamsError{Message: "blobGasUsed/excessBlobGas missing"}
}

if s.config.IsCancun(header.Time) && header.ParentBeaconBlockRoot == nil {
return nil, &rpc.InvalidParamsError{Message: "parentBeaconBlockRoot missing"}
}

blockHash := req.BlockHash
if header.Hash() != blockHash {
s.logger.Error("[NewPayload] invalid block hash", "stated", blockHash, "actual", header.Hash())
Expand Down Expand Up @@ -428,6 +434,12 @@ func (s *EngineServer) forkchoiceUpdated(ctx context.Context, forkchoiceState *e
return nil, fmt.Errorf("execution layer not running as a proposer. enable proposer by taking out the --proposer.disable flag on startup")
}

timestamp := uint64(payloadAttributes.Timestamp)
if (!s.config.IsCancun(timestamp) && version >= clparams.DenebVersion) ||
(s.config.IsCancun(timestamp) && version < clparams.DenebVersion) {
return nil, &rpc.UnsupportedForkError{Message: "Unsupported fork"}
}

headHeader := s.chainRW.GetHeaderByHash(forkchoiceState.HeadHash)

if headHeader.Hash() != forkchoiceState.HeadHash {
Expand All @@ -443,21 +455,25 @@ func (s *EngineServer) forkchoiceUpdated(ctx context.Context, forkchoiceState *e
return &engine_types.ForkChoiceUpdatedResponse{PayloadStatus: status}, nil
}

if headHeader.Time >= uint64(payloadAttributes.Timestamp) {
if headHeader.Time >= timestamp {
return nil, &engine_helpers.InvalidPayloadAttributesErr
}

req := &execution.AssembleBlockRequest{
ParentHash: gointerfaces.ConvertHashToH256(forkchoiceState.HeadHash),
Timestamp: uint64(payloadAttributes.Timestamp),
MixDigest: gointerfaces.ConvertHashToH256(payloadAttributes.PrevRandao),
SuggestedFeeRecipent: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient),
ParentHash: gointerfaces.ConvertHashToH256(forkchoiceState.HeadHash),
Timestamp: timestamp,
PrevRandao: gointerfaces.ConvertHashToH256(payloadAttributes.PrevRandao),
SuggestedFeeRecipient: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient),
}

if version >= clparams.CapellaVersion {
req.Withdrawals = engine_types.ConvertWithdrawalsToRpc(payloadAttributes.Withdrawals)
}

if version >= clparams.DenebVersion {
req.ParentBeaconBlockRoot = gointerfaces.ConvertHashToH256(payloadAttributes.ParentBeaconBlockRoot)
}

resp, err := s.executionService.AssembleBlock(ctx, req)
if err != nil {
return nil, err
Expand Down Expand Up @@ -564,26 +580,26 @@ func (e *EngineServer) ForkchoiceUpdatedV2(ctx context.Context, forkChoiceState
}

func (e *EngineServer) ForkchoiceUpdatedV3(ctx context.Context, forkChoiceState *engine_types.ForkChoiceState, payloadAttributes *engine_types.PayloadAttributes) (*engine_types.ForkChoiceUpdatedResponse, error) {
return e.forkchoiceUpdated(ctx, forkChoiceState, payloadAttributes, clparams.CapellaVersion)
return e.forkchoiceUpdated(ctx, forkChoiceState, payloadAttributes, clparams.DenebVersion)
}

// NewPayloadV1 processes new payloads (blocks) from the beacon chain without withdrawals.
// See https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#engine_newpayloadv1
func (e *EngineServer) NewPayloadV1(ctx context.Context, payload *engine_types.ExecutionPayload) (*engine_types.PayloadStatus, error) {
return e.newPayload(ctx, payload, nil, clparams.BellatrixVersion)
return e.newPayload(ctx, payload, nil, nil, clparams.BellatrixVersion)
}

// NewPayloadV2 processes new payloads (blocks) from the beacon chain with withdrawals.
// See https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#engine_newpayloadv2
func (e *EngineServer) NewPayloadV2(ctx context.Context, payload *engine_types.ExecutionPayload) (*engine_types.PayloadStatus, error) {
return e.newPayload(ctx, payload, nil, clparams.CapellaVersion)
return e.newPayload(ctx, payload, nil, nil, clparams.CapellaVersion)
}

// NewPayloadV3 processes new payloads (blocks) from the beacon chain with withdrawals & blob gas.
// See https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_newpayloadv3
func (e *EngineServer) NewPayloadV3(ctx context.Context, payload *engine_types.ExecutionPayload,
expectedBlobHashes []libcommon.Hash, parentBeaconBlockRoot *libcommon.Hash) (*engine_types.PayloadStatus, error) {
return e.newPayload(ctx, payload, expectedBlobHashes, clparams.DenebVersion)
return e.newPayload(ctx, payload, expectedBlobHashes, parentBeaconBlockRoot, clparams.DenebVersion)
}

// Receives consensus layer's transition configuration and checks if the execution layer has the correct configuration.
Expand Down
12 changes: 10 additions & 2 deletions turbo/execution/eth1/block_building.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import (
"reflect"

"github.com/holiman/uint256"

libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/gointerfaces"
"github.com/ledgerwatch/erigon-lib/gointerfaces/execution"
types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types"

"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/types"
Expand Down Expand Up @@ -49,15 +52,20 @@ func (e *EthereumExecutionModule) AssembleBlock(ctx context.Context, req *execut
param := core.BlockBuilderParameters{
ParentHash: gointerfaces.ConvertH256ToHash(req.ParentHash),
Timestamp: req.Timestamp,
PrevRandao: gointerfaces.ConvertH256ToHash(req.MixDigest),
SuggestedFeeRecipient: gointerfaces.ConvertH160toAddress(req.SuggestedFeeRecipent),
PrevRandao: gointerfaces.ConvertH256ToHash(req.PrevRandao),
SuggestedFeeRecipient: gointerfaces.ConvertH160toAddress(req.SuggestedFeeRecipient),
Withdrawals: eth1_utils.ConvertWithdrawalsFromRpc(req.Withdrawals),
}

if err := e.checkWithdrawalsPresence(param.Timestamp, param.Withdrawals); err != nil {
return nil, err
}

if req.ParentBeaconBlockRoot != nil {
pbbr := libcommon.Hash(gointerfaces.ConvertH256ToHash(req.ParentBeaconBlockRoot))
param.ParentBeaconBlockRoot = &pbbr
}

// First check if we're already building a block with the requested parameters
if reflect.DeepEqual(e.lastParameters, &param) {
e.logger.Info("[ForkChoiceUpdated] duplicate build request")
Expand Down
Loading