Skip to content
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
39 changes: 14 additions & 25 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/stateless"
Expand Down Expand Up @@ -319,6 +318,14 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
log.Warn("Forkchoice requested update to zero hash")
return engine.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this?
}

// OP-Stack diff payload attributes validation:
if cfg := api.eth.BlockChain().Config(); cfg.IsOptimism() && payloadAttributes != nil {
if err := checkOptimismPayloadAttributes(payloadAttributes, cfg); err != nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(err)
}
}

// Stash away the last update to warn the user if the beacon client goes offline
api.lastForkchoiceLock.Lock()
api.lastForkchoiceUpdate = time.Now()
Expand Down Expand Up @@ -434,19 +441,9 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl

if payloadAttributes != nil {
var eip1559Params []byte
if api.eth.BlockChain().Config().Optimism != nil {
if payloadAttributes.GasLimit == nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("gasLimit parameter is required"))
}
if api.eth.BlockChain().Config().IsHolocene(payloadAttributes.Timestamp) {
if err := eip1559.ValidateHolocene1559Params(payloadAttributes.EIP1559Params); err != nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(err)
}
eip1559Params = bytes.Clone(payloadAttributes.EIP1559Params)
} else if len(payloadAttributes.EIP1559Params) != 0 {
return engine.STATUS_INVALID,
engine.InvalidPayloadAttributes.With(errors.New("eip155Params not supported prior to Holocene upgrade"))
}
if api.eth.BlockChain().Config().IsOptimismHolocene(payloadAttributes.Timestamp) {
// Validation performed above in checkOptimismPayloadAttributes
eip1559Params = bytes.Clone(payloadAttributes.EIP1559Params)
}
transactions := make(types.Transactions, 0, len(payloadAttributes.Transactions))
for i, otx := range payloadAttributes.Transactions {
Expand Down Expand Up @@ -663,10 +660,6 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV4 must only be called for prague payloads"))
}

if api.eth.BlockChain().Config().IsIsthmus(params.Timestamp) && params.WithdrawalsRoot == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawalsRoot post-isthmus"))
}

requests := convertRequests(executionRequests)
if err := validateRequests(requests); err != nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
Expand Down Expand Up @@ -870,15 +863,11 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
// Hence, we use a lock here, to be sure that the previous call has finished before we
// check whether we already have the block locally.

// OP-Stack diff: payload must have empty extraData before Holocene and hold eip-1559 params after Holocene.
if cfg := api.eth.BlockChain().Config(); cfg.IsHolocene(params.Timestamp) {
if err := eip1559.ValidateHoloceneExtraData(params.ExtraData); err != nil {
// OP-Stack diff payload validation:
if cfg := api.eth.BlockChain().Config(); cfg.IsOptimism() {
if err := checkOptimismPayload(params, cfg); err != nil {
return api.invalid(err, nil), nil
Comment thread
geoknee marked this conversation as resolved.
}
} else if cfg.IsOptimism() {
if len(params.ExtraData) > 0 {
return api.invalid(errors.New("extraData must be empty before Holocene"), nil), nil
}
}

api.newPayloadLock.Lock()
Expand Down
67 changes: 67 additions & 0 deletions eth/catalyst/api_optimism.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package catalyst

import (
"errors"

"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)

// checkOptimismPayload performs Optimism-specific checks on the payload data (called during [(*ConsensusAPI).newPayload]).
func checkOptimismPayload(params engine.ExecutableData, cfg *params.ChainConfig) error {
// Canyon
if cfg.IsCanyon(params.Timestamp) && !cfg.IsIsthmus(params.Timestamp) {
if params.WithdrawalsRoot == nil || *params.WithdrawalsRoot != types.EmptyWithdrawalsHash {
return errors.New("withdrawalsRoot not equal to MPT root of empty list post-Canyon and pre-Isthmus")
}
}

// Holocene
if cfg.IsHolocene(params.Timestamp) {
if err := eip1559.ValidateHoloceneExtraData(params.ExtraData); err != nil {
return err
}
} else {
if len(params.ExtraData) > 0 {
return errors.New("extraData must be empty before Holocene")
}
}

// Isthmus
if cfg.IsIsthmus(params.Timestamp) {
if params.Withdrawals == nil || len(params.Withdrawals) != 0 {
return errors.New("non-empty or nil withdrawals post-isthmus")
}
if params.WithdrawalsRoot == nil {
return errors.New("nil withdrawalsRoot post-isthmus")
}
}
Comment thread
sebastianst marked this conversation as resolved.

return nil
}

// checkOptimismPayloadAttributes performs Optimism-specific checks on the payload attributes (called during [(*ConsensusAPI).forkChoiceUpdated].
// Will panic if payloadAttributes is nil.
func checkOptimismPayloadAttributes(payloadAttributes *engine.PayloadAttributes, cfg *params.ChainConfig) error {
if payloadAttributes.GasLimit == nil {
return errors.New("gasLimit parameter is required")
}

// Holocene
if cfg.IsHolocene(payloadAttributes.Timestamp) {
if err := eip1559.ValidateHolocene1559Params(payloadAttributes.EIP1559Params); err != nil {
return err
}
} else if len(payloadAttributes.EIP1559Params) != 0 {
return errors.New("eip155Params not supported prior to Holocene upgrade")
}

// Isthmus
if cfg.IsIsthmus(payloadAttributes.Timestamp) && payloadAttributes.Withdrawals == nil || len(payloadAttributes.Withdrawals) != 0 {
return errors.New("non-empty or nil withdrawals post-isthmus")
}

return nil
}
Loading