Skip to content

Commit

Permalink
eth/catalyst: prefix payload id with version (#28246)
Browse files Browse the repository at this point in the history
GetPayloadVX should only return payloads which match its version. GetPayloadV2 is a special snowflake that supports v1 and v2 payloads. This change uses a a version-specific prefix within in the payload id, basically a namespace for the version number.
  • Loading branch information
lightclient authored Jan 24, 2024
1 parent 6b0de79 commit a8a8758
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 13 deletions.
25 changes: 25 additions & 0 deletions beacon/engine/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ import (
"github.com/ethereum/go-ethereum/trie"
)

// PayloadVersion denotes the version of PayloadAttributes used to request the
// building of the payload to commence.
type PayloadVersion byte

var (
PayloadV1 PayloadVersion = 0x1
PayloadV2 PayloadVersion = 0x2
PayloadV3 PayloadVersion = 0x3
)

//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go

// PayloadAttributes describes the environment context in which a block should
Expand Down Expand Up @@ -115,6 +125,21 @@ type TransitionConfigurationV1 struct {
// PayloadID is an identifier of the payload build process
type PayloadID [8]byte

// Version returns the payload version associated with the identifier.
func (b PayloadID) Version() PayloadVersion {
return PayloadVersion(b[0])
}

// Is returns whether the identifier matches any of provided payload versions.
func (b PayloadID) Is(versions ...PayloadVersion) bool {
for _, v := range versions {
if v == b.Version() {
return true
}
}
return false
}

func (b PayloadID) String() string {
return hexutil.Encode(b[:])
}
Expand Down
18 changes: 14 additions & 4 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai"))
}
}
return api.forkchoiceUpdated(update, payloadAttributes, false)
return api.forkchoiceUpdated(update, payloadAttributes, engine.PayloadV1, false)
}

// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes.
Expand All @@ -196,7 +196,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa
return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV2 must only be called for shanghai payloads"))
}
}
return api.forkchoiceUpdated(update, params, false)
return api.forkchoiceUpdated(update, params, engine.PayloadV2, false)
}

// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root in the payload attributes.
Expand All @@ -220,10 +220,10 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa
// hash, even if params are wrong. To do this we need to split up
// forkchoiceUpdate into a function that only updates the head and then a
// function that kicks off block construction.
return api.forkchoiceUpdated(update, params, false)
return api.forkchoiceUpdated(update, params, engine.PayloadV3, false)
}

func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, simulatorMode bool) (engine.ForkChoiceResponse, error) {
func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, payloadVersion engine.PayloadVersion, simulatorMode bool) (engine.ForkChoiceResponse, error) {
api.forkchoiceLock.Lock()
defer api.forkchoiceLock.Unlock()

Expand Down Expand Up @@ -367,6 +367,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
Random: payloadAttributes.Random,
Withdrawals: payloadAttributes.Withdrawals,
BeaconRoot: payloadAttributes.BeaconRoot,
Version: payloadVersion,
}
id := args.Id()
// If we already are busy generating this work, then we do not need
Expand Down Expand Up @@ -430,6 +431,9 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config engine.Transit

// GetPayloadV1 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.ExecutableData, error) {
if !payloadID.Is(engine.PayloadV1) {
return nil, engine.UnsupportedFork
}
data, err := api.getPayload(payloadID, false)
if err != nil {
return nil, err
Expand All @@ -439,11 +443,17 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.Execu

// GetPayloadV2 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV2(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
if !payloadID.Is(engine.PayloadV1, engine.PayloadV2) {
return nil, engine.UnsupportedFork
}
return api.getPayload(payloadID, false)
}

// GetPayloadV3 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
if !payloadID.Is(engine.PayloadV3) {
return nil, engine.UnsupportedFork
}
return api.getPayload(payloadID, false)
}

Expand Down
12 changes: 10 additions & 2 deletions eth/catalyst/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) {
FeeRecipient: blockParams.SuggestedFeeRecipient,
Random: blockParams.Random,
BeaconRoot: blockParams.BeaconRoot,
Version: engine.PayloadV1,
}).Id()
execData, err := api.GetPayloadV1(payloadID)
if err != nil {
Expand Down Expand Up @@ -1076,6 +1077,7 @@ func TestWithdrawals(t *testing.T) {
Random: blockParams.Random,
Withdrawals: blockParams.Withdrawals,
BeaconRoot: blockParams.BeaconRoot,
Version: engine.PayloadV2,
}).Id()
execData, err := api.GetPayloadV2(payloadID)
if err != nil {
Expand Down Expand Up @@ -1124,6 +1126,7 @@ func TestWithdrawals(t *testing.T) {
Random: blockParams.Random,
Withdrawals: blockParams.Withdrawals,
BeaconRoot: blockParams.BeaconRoot,
Version: engine.PayloadV2,
}).Id()
execData, err = api.GetPayloadV2(payloadID)
if err != nil {
Expand Down Expand Up @@ -1238,12 +1241,15 @@ func TestNilWithdrawals(t *testing.T) {

for _, test := range tests {
var (
err error
shanghai = genesis.Config.IsShanghai(genesis.Config.LondonBlock, test.blockParams.Timestamp)
err error
payloadVersion engine.PayloadVersion
shanghai = genesis.Config.IsShanghai(genesis.Config.LondonBlock, test.blockParams.Timestamp)
)
if !shanghai {
payloadVersion = engine.PayloadV1
_, err = api.ForkchoiceUpdatedV1(fcState, &test.blockParams)
} else {
payloadVersion = engine.PayloadV2
_, err = api.ForkchoiceUpdatedV2(fcState, &test.blockParams)
}
if test.wantErr {
Expand All @@ -1262,6 +1268,7 @@ func TestNilWithdrawals(t *testing.T) {
Timestamp: test.blockParams.Timestamp,
FeeRecipient: test.blockParams.SuggestedFeeRecipient,
Random: test.blockParams.Random,
Version: payloadVersion,
}).Id()
execData, err := api.GetPayloadV2(payloadID)
if err != nil {
Expand Down Expand Up @@ -1616,6 +1623,7 @@ func TestParentBeaconBlockRoot(t *testing.T) {
Random: blockParams.Random,
Withdrawals: blockParams.Withdrawals,
BeaconRoot: blockParams.BeaconRoot,
Version: engine.PayloadV3,
}).Id()
execData, err := api.GetPayloadV3(payloadID)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion eth/catalyst/simulated_beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
SuggestedFeeRecipient: feeRecipient,
Withdrawals: withdrawals,
Random: random,
}, true)
}, engine.PayloadV2, true)
if err != nil {
return err
}
Expand Down
14 changes: 8 additions & 6 deletions miner/payload_building.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ import (
// Check engine-api specification for more details.
// https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#payloadattributesv3
type BuildPayloadArgs struct {
Parent common.Hash // The parent block to build payload on top
Timestamp uint64 // The provided timestamp of generated payload
FeeRecipient common.Address // The provided recipient address for collecting transaction fee
Random common.Hash // The provided randomness value
Withdrawals types.Withdrawals // The provided withdrawals
BeaconRoot *common.Hash // The provided beaconRoot (Cancun)
Parent common.Hash // The parent block to build payload on top
Timestamp uint64 // The provided timestamp of generated payload
FeeRecipient common.Address // The provided recipient address for collecting transaction fee
Random common.Hash // The provided randomness value
Withdrawals types.Withdrawals // The provided withdrawals
BeaconRoot *common.Hash // The provided beaconRoot (Cancun)
Version engine.PayloadVersion // Versioning byte for payload id calculation.
}

// Id computes an 8-byte identifier by hashing the components of the payload arguments.
Expand All @@ -57,6 +58,7 @@ func (args *BuildPayloadArgs) Id() engine.PayloadID {
}
var out engine.PayloadID
copy(out[:], hasher.Sum(nil)[:8])
out[0] = byte(args.Version)
return out
}

Expand Down

0 comments on commit a8a8758

Please sign in to comment.