Skip to content

Commit

Permalink
Support engine_forkchoiceUpdatedV3 with ParentBeaconBlockRoot (EIP-47…
Browse files Browse the repository at this point in the history
  • Loading branch information
yperbasis authored and AskAlexSharov committed Sep 6, 2023
1 parent 77958c7 commit c0a32a4
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 21 deletions.
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

0 comments on commit c0a32a4

Please sign in to comment.