diff --git a/simulators/ethereum/engine/client/engine.go b/simulators/ethereum/engine/client/engine.go index 765e2ecad6..b4df3560ed 100644 --- a/simulators/ethereum/engine/client/engine.go +++ b/simulators/ethereum/engine/client/engine.go @@ -37,6 +37,7 @@ type Engine interface { GetPayloadV1(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, error) GetPayloadV2(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, *big.Int, error) GetPayloadV3(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, *big.Int, *typ.BlobsBundle, *bool, error) + GetPayload(ctx context.Context, version int, payloadId *api.PayloadID) (typ.ExecutableData, *big.Int, *typ.BlobsBundle, *bool, error) NewPayload(ctx context.Context, version int, payload interface{}, versionedHashes *[]common.Hash, beaconRoot *common.Hash) (api.PayloadStatusV1, error) NewPayloadV1(ctx context.Context, payload *typ.ExecutableDataV1) (api.PayloadStatusV1, error) @@ -85,6 +86,6 @@ var ( Pending = big.NewInt(-2) Finalized = big.NewInt(-3) Safe = big.NewInt(-4) - LatestForkchoiceUpdatedVersion = 2 + LatestForkchoiceUpdatedVersion = 3 LatestNewPayloadVersion = 3 ) diff --git a/simulators/ethereum/engine/client/node/node.go b/simulators/ethereum/engine/client/node/node.go index 4d891945a6..354af59079 100644 --- a/simulators/ethereum/engine/client/node/node.go +++ b/simulators/ethereum/engine/client/node/node.go @@ -569,6 +569,16 @@ func (n *GethNode) GetPayloadV3(ctx context.Context, payloadId *beacon.PayloadID return ed, p.BlockValue, nil, &p.Override, err } +func (n *GethNode) GetPayload(ctx context.Context, version int, payloadId *beacon.PayloadID) (typ.ExecutableData, *big.Int, *typ.BlobsBundle, *bool, error) { + p, err := n.api.GetPayloadV3(*payloadId) + if p == nil || err != nil { + return typ.ExecutableData{}, nil, nil, nil, err + } + ed, err := typ.FromBeaconExecutableData(p.ExecutionPayload) + // TODO: Convert and return the blobs bundle + return ed, p.BlockValue, nil, &p.Override, err +} + func (n *GethNode) GetPayloadBodiesByRangeV1(ctx context.Context, start uint64, count uint64) ([]*typ.ExecutionPayloadBodyV1, error) { return nil, fmt.Errorf("not implemented") } diff --git a/simulators/ethereum/engine/clmock/clmock.go b/simulators/ethereum/engine/clmock/clmock.go index 8a264efc05..3ebf135c44 100644 --- a/simulators/ethereum/engine/clmock/clmock.go +++ b/simulators/ethereum/engine/clmock/clmock.go @@ -5,7 +5,6 @@ import ( "crypto/sha256" "encoding/binary" "encoding/json" - "errors" "fmt" "math/big" "math/rand" @@ -23,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/hive/hivesim" + "github.com/pkg/errors" ) var ( @@ -89,6 +89,9 @@ type CLMocker struct { // Chain History HeaderHistory map[uint64]*types.Header + // Payload ID History + PayloadIDHistory map[api.PayloadID]interface{} + // PoS Chain History Information PrevRandaoHistory map[uint64]common.Hash ExecutedPayloadHistory ExecutableDataHistory @@ -147,6 +150,7 @@ func NewCLMocker(t *hivesim.T, genesis *core.Genesis, slotsToSafe, slotsToFinali SlotsToFinalized: slotsToFinalized, SafeSlotsToImportOptimistically: safeSlotsToImportOptimistically, PayloadProductionClientDelay: DefaultPayloadProductionClientDelay, + PayloadIDHistory: make(map[api.PayloadID]interface{}), LatestHeader: nil, FirstPoSBlockNumber: nil, LatestHeadNumber: nil, @@ -392,7 +396,7 @@ func TimestampToBeaconRoot(timestamp uint64) common.Hash { return beaconRoot } -func (cl *CLMocker) RequestNextPayload() { +func (cl *CLMocker) GeneratePayloadAttributes() { // Generate a random value for the PrevRandao field nextPrevRandao := common.Hash{} rand.Read(nextPrevRandao[:]) @@ -415,10 +419,23 @@ func (cl *CLMocker) RequestNextPayload() { // Save random value cl.PrevRandaoHistory[cl.LatestHeader.Number.Uint64()+1] = nextPrevRandao +} + +func (cl *CLMocker) AddPayloadID(newPayloadID *api.PayloadID) error { + if newPayloadID == nil { + return errors.New("nil payload ID") + } + if _, ok := cl.PayloadIDHistory[*newPayloadID]; ok { + return fmt.Errorf("Reused payload ID: %v", *newPayloadID) + } + cl.PayloadIDHistory[*newPayloadID] = nil + return nil +} +func (cl *CLMocker) RequestNextPayload() { ctx, cancel := context.WithTimeout(cl.TestContext, globals.RPCTimeout) defer cancel() - fcUVersion := cl.ForkchoiceUpdatedVersion(cl.LatestPayloadAttributes.Timestamp) + fcUVersion := cl.ForkchoiceUpdatedVersion(cl.LatestHeader.Time, &cl.LatestPayloadAttributes.Timestamp) resp, err := cl.NextBlockProducer.ForkchoiceUpdated(ctx, fcUVersion, &cl.LatestForkchoice, &cl.LatestPayloadAttributes) if err != nil { cl.Fatalf("CLMocker: Could not send forkchoiceUpdatedV%d (%v): %v", fcUVersion, cl.NextBlockProducer.ID(), err) @@ -429,6 +446,9 @@ func (cl *CLMocker) RequestNextPayload() { if resp.PayloadStatus.LatestValidHash == nil || *resp.PayloadStatus.LatestValidHash != cl.LatestForkchoice.HeadBlockHash { cl.Fatalf("CLMocker: Unexpected forkchoiceUpdated LatestValidHash Response from Payload builder: %v != %v", resp.PayloadStatus.LatestValidHash, cl.LatestForkchoice.HeadBlockHash) } + if err = cl.AddPayloadID(resp.PayloadID); err != nil { + cl.Fatalf("CLMocker: Payload ID failure: %v", err) + } cl.NextPayloadID = resp.PayloadID } @@ -436,16 +456,8 @@ func (cl *CLMocker) GetNextPayload() { var err error ctx, cancel := context.WithTimeout(cl.TestContext, globals.RPCTimeout) defer cancel() - if cl.IsCancun(cl.LatestPayloadAttributes.Timestamp) { - cl.LatestPayloadBuilt, cl.LatestBlockValue, cl.LatestBlobBundle, cl.LatestShouldOverrideBuilder, err = cl.NextBlockProducer.GetPayloadV3(ctx, cl.NextPayloadID) - } else if cl.IsShanghai(cl.LatestPayloadAttributes.Timestamp) { - cl.LatestPayloadBuilt, cl.LatestBlockValue, err = cl.NextBlockProducer.GetPayloadV2(ctx, cl.NextPayloadID) - cl.LatestBlobBundle = nil - } else { - cl.LatestPayloadBuilt, err = cl.NextBlockProducer.GetPayloadV1(ctx, cl.NextPayloadID) - cl.LatestBlockValue = nil - cl.LatestBlobBundle = nil - } + version := cl.ForkConfig.GetPayloadVersion(cl.LatestPayloadAttributes.Timestamp) + cl.LatestPayloadBuilt, cl.LatestBlockValue, cl.LatestBlobBundle, cl.LatestShouldOverrideBuilder, err = cl.NextBlockProducer.GetPayload(ctx, version, cl.NextPayloadID) if err != nil { cl.Fatalf("CLMocker: Could not getPayload (%v, %v): %v", cl.NextBlockProducer.ID(), cl.NextPayloadID, err) } @@ -519,7 +531,7 @@ func (cl *CLMocker) broadcastNextNewPayload() { } func (cl *CLMocker) broadcastLatestForkchoice() { - version := cl.ForkchoiceUpdatedVersion(cl.LatestExecutedPayload.Timestamp) + version := cl.ForkchoiceUpdatedVersion(cl.LatestExecutedPayload.Timestamp, nil) for _, resp := range cl.BroadcastForkchoiceUpdated(&cl.LatestForkchoice, nil, version) { if resp.Error != nil { cl.Logf("CLMocker: BroadcastForkchoiceUpdated Error (%v): %v\n", resp.Container, resp.Error) @@ -543,13 +555,14 @@ func (cl *CLMocker) broadcastLatestForkchoice() { } type BlockProcessCallbacks struct { - OnPayloadProducerSelected func() - OnRequestNextPayload func() - OnGetPayload func() - OnNewPayloadBroadcast func() - OnForkchoiceBroadcast func() - OnSafeBlockChange func() - OnFinalizedBlockChange func() + OnPayloadProducerSelected func() + OnPayloadAttributesGenerated func() + OnRequestNextPayload func() + OnGetPayload func() + OnNewPayloadBroadcast func() + OnForkchoiceBroadcast func() + OnSafeBlockChange func() + OnFinalizedBlockChange func() } func (cl *CLMocker) ProduceSingleBlock(callbacks BlockProcessCallbacks) { @@ -576,6 +589,12 @@ func (cl *CLMocker) ProduceSingleBlock(callbacks BlockProcessCallbacks) { callbacks.OnPayloadProducerSelected() } + cl.GeneratePayloadAttributes() + + if callbacks.OnPayloadAttributesGenerated != nil { + callbacks.OnPayloadAttributesGenerated() + } + cl.RequestNextPayload() cl.SetNextWithdrawals(nil) diff --git a/simulators/ethereum/engine/globals/globals.go b/simulators/ethereum/engine/globals/globals.go index ecd5fbdb4e..8a99c4e953 100644 --- a/simulators/ethereum/engine/globals/globals.go +++ b/simulators/ethereum/engine/globals/globals.go @@ -181,7 +181,14 @@ func (f *ForkConfig) IsCancun(blockTimestamp uint64) bool { return f.CancunTimestamp != nil && new(big.Int).SetUint64(blockTimestamp).Cmp(f.CancunTimestamp) >= 0 } -func (f *ForkConfig) ForkchoiceUpdatedVersion(timestamp uint64) int { +func (f *ForkConfig) ForkchoiceUpdatedVersion(headTimestamp uint64, payloadAttributesTimestamp *uint64) int { + // If the payload attributes timestamp is nil, use the head timestamp + // to calculate the FcU version. + timestamp := headTimestamp + if payloadAttributesTimestamp != nil { + timestamp = *payloadAttributesTimestamp + } + if f.IsCancun(timestamp) { return 3 } else if f.IsShanghai(timestamp) { diff --git a/simulators/ethereum/engine/helper/payload.go b/simulators/ethereum/engine/helper/customizer.go similarity index 54% rename from simulators/ethereum/engine/helper/payload.go rename to simulators/ethereum/engine/helper/customizer.go index 09d2048be1..1a200b316e 100644 --- a/simulators/ethereum/engine/helper/payload.go +++ b/simulators/ethereum/engine/helper/customizer.go @@ -6,6 +6,7 @@ import ( "math/rand" "strings" + api "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/core/types" @@ -14,8 +15,234 @@ import ( typ "github.com/ethereum/hive/simulators/ethereum/engine/types" ) +type GetPayloadCustomizer interface { + GetPayloadID(basePayloadID *api.PayloadID) (*api.PayloadID, error) + GetVersion(forkConfig *globals.ForkConfig, requestedTimestamp uint64) (int, error) + GetExpectedError() (*int, error) +} + +type BaseGetPayloadCustomizer struct { + CustomPayloadID *api.PayloadID + ExpectedError *int +} + +var _ GetPayloadCustomizer = (*BaseGetPayloadCustomizer)(nil) + +func (customizer *BaseGetPayloadCustomizer) GetPayloadID(basePayloadID *api.PayloadID) (*api.PayloadID, error) { + if customizer.CustomPayloadID != nil { + return customizer.CustomPayloadID, nil + } + return basePayloadID, nil +} + +func (customizer *BaseGetPayloadCustomizer) GetVersion(forkConfig *globals.ForkConfig, requestedTimestamp uint64) (int, error) { + return forkConfig.GetPayloadVersion(requestedTimestamp), nil +} + +func (customizer *BaseGetPayloadCustomizer) GetExpectedError() (*int, error) { + return customizer.ExpectedError, nil +} + +type UpgradeGetPayloadVersion struct { + GetPayloadCustomizer +} + +var _ GetPayloadCustomizer = (*UpgradeGetPayloadVersion)(nil) + +func (customizer *UpgradeGetPayloadVersion) GetVersion(forkConfig *globals.ForkConfig, requestedTimestamp uint64) (int, error) { + if customizer.GetPayloadCustomizer == nil { + return 0, fmt.Errorf("base customizer not set") + } + baseVersion, err := customizer.GetPayloadCustomizer.GetVersion(forkConfig, requestedTimestamp) + if err != nil { + return 0, err + } + return baseVersion + 1, nil +} + +type DowngradeGetPayloadVersion struct { + GetPayloadCustomizer +} + +var _ GetPayloadCustomizer = (*DowngradeGetPayloadVersion)(nil) + +func (customizer *DowngradeGetPayloadVersion) GetVersion(forkConfig *globals.ForkConfig, requestedTimestamp uint64) (int, error) { + if customizer.GetPayloadCustomizer == nil { + return 0, fmt.Errorf("base customizer not set") + } + baseVersion, err := customizer.GetPayloadCustomizer.GetVersion(forkConfig, requestedTimestamp) + if err != nil { + return 0, err + } + if baseVersion == 1 { + return 1, fmt.Errorf("cannot downgrade version 1") + } + return baseVersion - 1, nil +} + +type PayloadAttributesCustomizer interface { + GetPayloadAttributes(basePayloadAttributes *typ.PayloadAttributes) (*typ.PayloadAttributes, error) +} + +type ForkchoiceUpdatedCustomizer interface { + PayloadAttributesCustomizer + GetForkchoiceState(baseForkchoiceUpdate api.ForkchoiceStateV1) (api.ForkchoiceStateV1, error) + GetVersion(forkConfig *globals.ForkConfig, headTimestamp uint64, basePayloadAttributes *typ.PayloadAttributes) (int, error) + GetExpectedError() (*int, error) + GetExpectInvalidStatus() bool +} + +type BasePayloadAttributesCustomizer struct { + Timestamp *uint64 + Random *common.Hash + SuggestedFeeRecipient *common.Address + Withdrawals *[]*types.Withdrawal + RemoveWithdrawals bool + BeaconRoot *common.Hash + RemoveBeaconRoot bool +} + +var _ PayloadAttributesCustomizer = (*BasePayloadAttributesCustomizer)(nil) + +func (customData *BasePayloadAttributesCustomizer) GetPayloadAttributes(basePayloadAttributes *typ.PayloadAttributes) (*typ.PayloadAttributes, error) { + customPayloadAttributes := &typ.PayloadAttributes{ + Timestamp: basePayloadAttributes.Timestamp, + Random: basePayloadAttributes.Random, + SuggestedFeeRecipient: basePayloadAttributes.SuggestedFeeRecipient, + Withdrawals: basePayloadAttributes.Withdrawals, + BeaconRoot: basePayloadAttributes.BeaconRoot, + } + if customData.Timestamp != nil { + customPayloadAttributes.Timestamp = *customData.Timestamp + } + if customData.Random != nil { + customPayloadAttributes.Random = *customData.Random + } + if customData.SuggestedFeeRecipient != nil { + customPayloadAttributes.SuggestedFeeRecipient = *customData.SuggestedFeeRecipient + } + if customData.RemoveWithdrawals { + customPayloadAttributes.Withdrawals = nil + } else if customData.Withdrawals != nil { + customPayloadAttributes.Withdrawals = *customData.Withdrawals + } + if customData.RemoveBeaconRoot { + customPayloadAttributes.BeaconRoot = nil + } else if customData.BeaconRoot != nil { + customPayloadAttributes.BeaconRoot = customData.BeaconRoot + } + return customPayloadAttributes, nil +} + +type TimestampDeltaPayloadAttributesCustomizer struct { + PayloadAttributesCustomizer + TimestampDelta int64 +} + +var _ PayloadAttributesCustomizer = (*TimestampDeltaPayloadAttributesCustomizer)(nil) + +func (customData *TimestampDeltaPayloadAttributesCustomizer) GetPayloadAttributes(basePayloadAttributes *typ.PayloadAttributes) (*typ.PayloadAttributes, error) { + customPayloadAttributes, err := customData.PayloadAttributesCustomizer.GetPayloadAttributes(basePayloadAttributes) + if err != nil { + return nil, err + } + customPayloadAttributes.Timestamp = uint64(int64(customPayloadAttributes.Timestamp) + customData.TimestampDelta) + return customPayloadAttributes, nil +} + +// Customizer that makes no modifications to the forkchoice directive call. +// Used as base to other customizers. +type BaseForkchoiceUpdatedCustomizer struct { + PayloadAttributesCustomizer + ExpectedError *int + ExpectInvalidStatus bool +} + +func (customizer *BaseForkchoiceUpdatedCustomizer) GetPayloadAttributes(basePayloadAttributes *typ.PayloadAttributes) (*typ.PayloadAttributes, error) { + if customizer.PayloadAttributesCustomizer != nil { + return customizer.PayloadAttributesCustomizer.GetPayloadAttributes(basePayloadAttributes) + } + return basePayloadAttributes, nil +} + +func (customizer *BaseForkchoiceUpdatedCustomizer) GetForkchoiceState(baseForkchoiceUpdate api.ForkchoiceStateV1) (api.ForkchoiceStateV1, error) { + return baseForkchoiceUpdate, nil +} + +func (customizer *BaseForkchoiceUpdatedCustomizer) GetVersion(forkConfig *globals.ForkConfig, headTimestamp uint64, basePayloadAttributes *typ.PayloadAttributes) (int, error) { + // We use the version meant for the head block unless there are payload attributes + // in which case we use the version meant for the new payload requested. + var payloadAttributesTimestamp *uint64 + if basePayloadAttributes != nil { + payloadAttributesTimestamp = &basePayloadAttributes.Timestamp + } + return forkConfig.ForkchoiceUpdatedVersion(headTimestamp, payloadAttributesTimestamp), nil +} + +func (customizer *BaseForkchoiceUpdatedCustomizer) GetExpectedError() (*int, error) { + return customizer.ExpectedError, nil +} + +func (customizer *BaseForkchoiceUpdatedCustomizer) GetExpectInvalidStatus() bool { + return customizer.ExpectInvalidStatus +} + +var _ ForkchoiceUpdatedCustomizer = (*BaseForkchoiceUpdatedCustomizer)(nil) + +// Customizer that upgrades the version of the forkchoice directive call to the next version. +type UpgradeForkchoiceUpdatedVersion struct { + ForkchoiceUpdatedCustomizer +} + +var _ ForkchoiceUpdatedCustomizer = (*UpgradeForkchoiceUpdatedVersion)(nil) + +func (customizer *UpgradeForkchoiceUpdatedVersion) GetVersion(forkConfig *globals.ForkConfig, headTimestamp uint64, basePayloadAttributes *typ.PayloadAttributes) (int, error) { + if customizer.ForkchoiceUpdatedCustomizer == nil { + return 0, fmt.Errorf("base customizer not set") + } + baseVersion, err := customizer.ForkchoiceUpdatedCustomizer.GetVersion(forkConfig, headTimestamp, basePayloadAttributes) + if err != nil { + return 0, err + } + return baseVersion + 1, nil +} + +// Customizer that downgrades the version of the forkchoice directive call to the previous version. +type DowngradeForkchoiceUpdatedVersion struct { + ForkchoiceUpdatedCustomizer +} + +var _ ForkchoiceUpdatedCustomizer = (*DowngradeForkchoiceUpdatedVersion)(nil) + +func (customizer *DowngradeForkchoiceUpdatedVersion) GetVersion(forkConfig *globals.ForkConfig, headTimestamp uint64, basePayloadAttributes *typ.PayloadAttributes) (int, error) { + if customizer.ForkchoiceUpdatedCustomizer == nil { + return 0, fmt.Errorf("base customizer not set") + } + baseVersion, err := customizer.ForkchoiceUpdatedCustomizer.GetVersion(forkConfig, headTimestamp, basePayloadAttributes) + if err != nil { + return 0, err + } + if baseVersion == 1 { + return 1, fmt.Errorf("cannot downgrade version 1") + } + return baseVersion - 1, nil +} + type PayloadCustomizer interface { CustomizePayload(basePayload *typ.ExecutableData, baseBeaconRoot *common.Hash) (modifiedPayload *typ.ExecutableData, modifiedBeaconRoot *common.Hash, err error) + GetTimestamp(basePayload *typ.ExecutableData) (uint64, error) +} + +type VersionedHashesCustomizer interface { + GetVersionedHashes(baseVesionedHashes *[]common.Hash) (*[]common.Hash, error) +} + +type NewPayloadCustomizer interface { + PayloadCustomizer + VersionedHashesCustomizer + GetVersion(forkConfig *globals.ForkConfig, basePayload *typ.ExecutableData) (int, error) + GetExpectedError() (*int, error) + GetExpectInvalidStatus() bool } type CustomPayloadData struct { @@ -45,6 +272,13 @@ type CustomPayloadData struct { var _ PayloadCustomizer = (*CustomPayloadData)(nil) +func (customData *CustomPayloadData) GetTimestamp(basePayload *typ.ExecutableData) (uint64, error) { + if customData.Timestamp != nil { + return *customData.Timestamp, nil + } + return basePayload.Timestamp, nil +} + // Construct a customized payload by taking an existing payload as base and mixing it CustomPayloadData // BlockHash is calculated automatically. func (customData *CustomPayloadData) CustomizePayload(basePayload *typ.ExecutableData, baseBeaconRoot *common.Hash) (*typ.ExecutableData, *common.Hash, error) { @@ -173,6 +407,87 @@ func (customData *CustomPayloadData) CustomizePayload(basePayload *typ.Executabl return result, customPayloadHeader.ParentBeaconRoot, nil } +// Base new payload directive call customizer. +// Used as base to other customizers. +type BaseNewPayloadVersionCustomizer struct { + PayloadCustomizer + VersionedHashesCustomizer + ExpectedError *int + ExpectInvalidStatus bool +} + +var _ NewPayloadCustomizer = (*BaseNewPayloadVersionCustomizer)(nil) + +func (customNewPayload *BaseNewPayloadVersionCustomizer) CustomizePayload(basePayload *typ.ExecutableData, baseBeaconRoot *common.Hash) (*typ.ExecutableData, *common.Hash, error) { + if customNewPayload.PayloadCustomizer == nil { + return basePayload, baseBeaconRoot, nil + } + return customNewPayload.PayloadCustomizer.CustomizePayload(basePayload, baseBeaconRoot) +} + +func (customNewPayload *BaseNewPayloadVersionCustomizer) GetVersionedHashes(baseVersionedHashes *[]common.Hash) (*[]common.Hash, error) { + if customNewPayload.VersionedHashesCustomizer != nil { + return customNewPayload.VersionedHashesCustomizer.GetVersionedHashes(baseVersionedHashes) + } + return baseVersionedHashes, nil +} + +func (customNewPayload *BaseNewPayloadVersionCustomizer) GetVersion(forkConfig *globals.ForkConfig, basePayload *typ.ExecutableData) (int, error) { + var ( + timestamp = basePayload.Timestamp + err error + ) + if customNewPayload.PayloadCustomizer != nil { + timestamp, err = customNewPayload.PayloadCustomizer.GetTimestamp(basePayload) + if err != nil { + return 0, err + } + } + + return forkConfig.NewPayloadVersion(timestamp), nil +} + +func (customNewPayload *BaseNewPayloadVersionCustomizer) GetExpectedError() (*int, error) { + return customNewPayload.ExpectedError, nil +} + +func (customNewPayload *BaseNewPayloadVersionCustomizer) GetExpectInvalidStatus() bool { + return customNewPayload.ExpectInvalidStatus +} + +// Customizer that upgrades the version of the payload to the next version. +type UpgradeNewPayloadVersion struct { + NewPayloadCustomizer +} + +var _ NewPayloadCustomizer = (*UpgradeNewPayloadVersion)(nil) + +func (customNewPayload *UpgradeNewPayloadVersion) GetVersion(forkConfig *globals.ForkConfig, basePayload *typ.ExecutableData) (int, error) { + if customNewPayload.NewPayloadCustomizer == nil { + return 0, fmt.Errorf("base customizer not set") + } + version, err := customNewPayload.NewPayloadCustomizer.GetVersion(forkConfig, basePayload) + return version + 1, err +} + +// Customizer that downgrades the version of the payload to the previous version. +type DowngradeNewPayloadVersion struct { + NewPayloadCustomizer +} + +var _ NewPayloadCustomizer = (*DowngradeNewPayloadVersion)(nil) + +func (customNewPayload *DowngradeNewPayloadVersion) GetVersion(forkConfig *globals.ForkConfig, basePayload *typ.ExecutableData) (int, error) { + if customNewPayload.NewPayloadCustomizer == nil { + return 0, fmt.Errorf("base customizer not set") + } + version, err := customNewPayload.NewPayloadCustomizer.GetVersion(forkConfig, basePayload) + if version == 1 { + return 1, fmt.Errorf("cannot downgrade version 1") + } + return version - 1, err +} + func CustomizePayloadTransactions(basePayload *typ.ExecutableData, baseBeaconRoot *common.Hash, customTransactions types.Transactions) (*typ.ExecutableData, *common.Hash, error) { byteTxs := make([][]byte, 0) for _, tx := range customTransactions { diff --git a/simulators/ethereum/engine/suites/cancun/config.go b/simulators/ethereum/engine/suites/cancun/config.go index 02f34a83c9..6b7e993ae4 100644 --- a/simulators/ethereum/engine/suites/cancun/config.go +++ b/simulators/ethereum/engine/suites/cancun/config.go @@ -49,7 +49,10 @@ func (cs *CancunBaseSpec) GetForkConfig() globals.ForkConfig { // Get the per-block timestamp increments configured for this test func (cs *CancunBaseSpec) GetBlockTimeIncrements() uint64 { - return 1 + if cs.TimeIncrements == 0 { + return 1 + } + return cs.TimeIncrements } // Timestamp delta between genesis and the withdrawals fork diff --git a/simulators/ethereum/engine/suites/cancun/steps.go b/simulators/ethereum/engine/suites/cancun/steps.go index 30b0568e99..2951140ee9 100644 --- a/simulators/ethereum/engine/suites/cancun/steps.go +++ b/simulators/ethereum/engine/suites/cancun/steps.go @@ -8,6 +8,7 @@ import ( "sync" "time" + api "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/hive/simulators/ethereum/engine/client" @@ -124,16 +125,16 @@ type NewPayloads struct { ExpectedBlobs []helper.BlobID // Delay between FcU and GetPayload calls GetPayloadDelay uint64 - // Extra modifications on NewPayload to the versioned hashes - VersionedHashes *VersionedHashes + // GetPayload modifier when requesting the new Payload + GetPayloadCustomizer helper.GetPayloadCustomizer + // ForkchoiceUpdate modifier when requesting the new Payload + FcUOnPayloadRequest helper.ForkchoiceUpdatedCustomizer // Extra modifications on NewPayload to potentially generate an invalid payload - PayloadCustomizer helper.PayloadCustomizer - // Version to use to call NewPayload - Version int + NewPayloadCustomizer helper.NewPayloadCustomizer + // ForkchoiceUpdate modifier when setting the new payload as head + FcUOnHeadSet helper.ForkchoiceUpdatedCustomizer // Expected responses on the NewPayload call - ExpectedError *int ExpectationDescription string - ExpectedStatus test.PayloadStatus } type VersionedHashes struct { @@ -141,7 +142,7 @@ type VersionedHashes struct { HashVersions []byte } -func (v *VersionedHashes) VersionedHashes() (*[]common.Hash, error) { +func (v *VersionedHashes) GetVersionedHashes(*[]common.Hash) (*[]common.Hash, error) { if v.Blobs == nil { return nil, nil } @@ -403,6 +404,85 @@ func (step NewPayloads) Execute(t *CancunTestContext) error { ) for p := uint64(0); p < payloadCount; p++ { t.CLMock.ProduceSingleBlock(clmock.BlockProcessCallbacks{ + OnPayloadAttributesGenerated: func() { + if step.FcUOnPayloadRequest != nil { + var ( + payloadAttributes *typ.PayloadAttributes = &t.CLMock.LatestPayloadAttributes + forkchoiceState api.ForkchoiceStateV1 = t.CLMock.LatestForkchoice + version int + expectedError *int + expectedStatus test.PayloadStatus = test.Valid + err error + ) + payloadAttributes, err = step.FcUOnPayloadRequest.GetPayloadAttributes(payloadAttributes) + if err != nil { + t.Fatalf("FAIL: Error getting custom payload attributes (payload %d/%d): %v", p+1, payloadCount, err) + } + version, err = step.FcUOnPayloadRequest.GetVersion(t.Env.ForkConfig, t.CLMock.LatestHeader.Time, payloadAttributes) + if err != nil { + t.Fatalf("FAIL: Error getting custom fcU version (payload %d/%d): %v", p+1, payloadCount, err) + } + expectedError, err = step.FcUOnPayloadRequest.GetExpectedError() + if err != nil { + t.Fatalf("FAIL: Error getting custom expected error (payload %d/%d): %v", p+1, payloadCount, err) + } + if step.FcUOnPayloadRequest.GetExpectInvalidStatus() { + expectedStatus = test.Invalid + } + + r := t.TestEngine.TestEngineForkchoiceUpdated(&forkchoiceState, payloadAttributes, version) + r.ExpectationDescription = step.ExpectationDescription + if expectedError != nil { + r.ExpectErrorCode(*expectedError) + } else { + r.ExpectNoError() + r.ExpectPayloadStatus(expectedStatus) + } + if r.Response.PayloadID != nil { + t.CLMock.AddPayloadID(r.Response.PayloadID) + } + } + }, + OnRequestNextPayload: func() { + // Get the next payload + if step.GetPayloadCustomizer != nil { + var ( + payloadAttributes = &t.CLMock.LatestPayloadAttributes + payloadID = t.CLMock.NextPayloadID + version int + r *test.GetPayloadResponseExpectObject + expectedError *int + err error + ) + + // We are going to sleep twice because there is no way to skip the CL Mock's sleep + time.Sleep(time.Duration(step.GetPayloadDelay) * time.Second) + + payloadID, err = step.GetPayloadCustomizer.GetPayloadID(payloadID) + if err != nil { + t.Fatalf("FAIL: Error getting custom payload ID (payload %d/%d): %v", p+1, payloadCount, err) + } + + version, err = step.GetPayloadCustomizer.GetVersion(t.Env.ForkConfig, payloadAttributes.Timestamp) + if err != nil { + t.Fatalf("FAIL: Error getting custom get-payload version (payload %d/%d): %v", p+1, payloadCount, err) + } + + expectedError, err = step.GetPayloadCustomizer.GetExpectedError() + if err != nil { + t.Fatalf("FAIL: Error getting custom expected error (payload %d/%d): %v", p+1, payloadCount, err) + } + + r = t.TestEngine.TestEngineGetPayload(payloadID, version) + r.ExpectationDescription = step.ExpectationDescription + if expectedError != nil { + r.ExpectErrorCode(*expectedError) + } else { + r.ExpectNoError() + } + } + + }, OnGetPayload: func() { // Get the latest blob bundle var ( @@ -428,52 +508,92 @@ func (step NewPayloads) Execute(t *CancunTestContext) error { } }, OnNewPayloadBroadcast: func() { - // Send a test NewPayload directive with either a modified payload or modifed versioned hashes - var ( - payload = &t.CLMock.LatestPayloadBuilt - versionedHashes *[]common.Hash = nil - beaconRoot *common.Hash = t.CLMock.LatestPayloadAttributes.BeaconRoot - r *test.NewPayloadResponseExpectObject - err error - ) - if step.VersionedHashes != nil { - // Send a new payload with the modified versioned hashes - versionedHashes, err = step.VersionedHashes.VersionedHashes() - if err != nil { - t.Fatalf("FAIL: Error getting modified versioned hashes (payload %d/%d): %v", p+1, payloadCount, err) - } - } else { + if step.NewPayloadCustomizer != nil { + // Send a test NewPayload directive with either a modified payload or modifed versioned hashes + var ( + payload = &t.CLMock.LatestPayloadBuilt + version = t.Env.ForkConfig.NewPayloadVersion(payload.Timestamp) + versionedHashes *[]common.Hash = nil + beaconRoot *common.Hash = t.CLMock.LatestPayloadAttributes.BeaconRoot + r *test.NewPayloadResponseExpectObject + expectedError *int + expectedStatus test.PayloadStatus = test.Valid + err error + ) + if t.CLMock.LatestBlobBundle != nil { versionedHashes, err = t.CLMock.LatestBlobBundle.VersionedHashes(BLOB_COMMITMENT_VERSION_KZG) if err != nil { t.Fatalf("FAIL: Error getting versioned hashes (payload %d/%d): %v", p+1, payloadCount, err) } } - } - if step.PayloadCustomizer != nil { // Send a custom new payload - payload, beaconRoot, err = step.PayloadCustomizer.CustomizePayload(payload, beaconRoot) + version, err = step.NewPayloadCustomizer.GetVersion(t.Env.ForkConfig, payload) + if err != nil { + t.Fatalf("FAIL: Error getting custom payload version (payload %d/%d): %v", p+1, payloadCount, err) + } + payload, beaconRoot, err = step.NewPayloadCustomizer.CustomizePayload(payload, beaconRoot) if err != nil { t.Fatalf("FAIL: Error customizing payload (payload %d/%d): %v", p+1, payloadCount, err) } + versionedHashes, err = step.NewPayloadCustomizer.GetVersionedHashes(versionedHashes) + if err != nil { + t.Fatalf("FAIL: Error getting custom versioned hashes (payload %d/%d): %v", p+1, payloadCount, err) + } + expectedError, err = step.NewPayloadCustomizer.GetExpectedError() + if err != nil { + t.Fatalf("FAIL: Error getting custom expected error (payload %d/%d): %v", p+1, payloadCount, err) + } + if step.NewPayloadCustomizer.GetExpectInvalidStatus() { + expectedStatus = test.Invalid + } + r = t.TestEngine.TestEngineNewPayload(payload, versionedHashes, beaconRoot, version) + r.ExpectationDescription = step.ExpectationDescription + if expectedError != nil { + r.ExpectErrorCode(*expectedError) + } else { + r.ExpectNoError() + r.ExpectStatus(expectedStatus) + } } - version := step.Version - if version == 0 { - version = t.Env.ForkConfig.NewPayloadVersion(payload.Timestamp) - } - r = t.TestEngine.TestEngineNewPayload(payload, versionedHashes, beaconRoot, version) - r.ExpectationDescription = step.ExpectationDescription - if step.ExpectedError != nil { - r.ExpectErrorCode(*step.ExpectedError) - } else { - r.ExpectNoError() - if step.ExpectedStatus != "" { - r.ExpectStatus(step.ExpectedStatus) + if step.FcUOnHeadSet != nil { + var ( + payloadAttributes *typ.PayloadAttributes = nil + forkchoiceState api.ForkchoiceStateV1 = t.CLMock.LatestForkchoice + version int + expectedError *int + expectedStatus test.PayloadStatus = test.Valid + err error + ) + payloadAttributes, err = step.FcUOnHeadSet.GetPayloadAttributes(payloadAttributes) + if err != nil { + t.Fatalf("FAIL: Error getting custom payload attributes (payload %d/%d): %v", p+1, payloadCount, err) + } + version, err = step.FcUOnHeadSet.GetVersion(t.Env.ForkConfig, t.CLMock.LatestHeader.Time, payloadAttributes) + if err != nil { + t.Fatalf("FAIL: Error getting custom fcU version (payload %d/%d): %v", p+1, payloadCount, err) + } + expectedError, err = step.FcUOnHeadSet.GetExpectedError() + if err != nil { + t.Fatalf("FAIL: Error getting custom expected error (payload %d/%d): %v", p+1, payloadCount, err) + } + if step.FcUOnHeadSet.GetExpectInvalidStatus() { + expectedStatus = test.Invalid + } + + r := t.TestEngine.TestEngineForkchoiceUpdated(&forkchoiceState, payloadAttributes, version) + r.ExpectationDescription = step.ExpectationDescription + if expectedError != nil { + r.ExpectErrorCode(*expectedError) + } else { + r.ExpectNoError() + r.ExpectPayloadStatus(expectedStatus) } } + }, OnForkchoiceBroadcast: func() { // Verify the transaction receipts on incorporated transactions @@ -499,9 +619,12 @@ func (step NewPayloads) Execute(t *CancunTestContext) error { } func (step NewPayloads) Description() string { - if step.VersionedHashes != nil { - return fmt.Sprintf("NewPayloads: %d payloads, %d blobs expected, %s", step.GetPayloadCount(), step.ExpectedIncludedBlobCount, step.VersionedHashes.Description()) - } + /* + TODO: Figure out if we need this. + if step.VersionedHashes != nil { + return fmt.Sprintf("NewPayloads: %d payloads, %d blobs expected, %s", step.GetPayloadCount(), step.ExpectedIncludedBlobCount, step.VersionedHashes.Description()) + } + */ return fmt.Sprintf("NewPayloads: %d payloads, %d blobs expected", step.GetPayloadCount(), step.ExpectedIncludedBlobCount) } @@ -598,56 +721,74 @@ func (step SendBlobTransactions) Description() string { // Send a modified version of the latest payload produced using NewPayloadV3 type SendModifiedLatestPayload struct { - ClientID uint64 - // Versioned hashes modification - VersionedHashes *VersionedHashes - // Other modifications - PayloadCustomizer helper.PayloadCustomizer - // Expected responses on the NewPayload call - ExpectedError *int - ExpectedStatus test.PayloadStatus + ClientID uint64 + NewPayloadCustomizer helper.NewPayloadCustomizer } func (step SendModifiedLatestPayload) Execute(t *CancunTestContext) error { // Get the latest payload var ( - payload = &t.CLMock.LatestPayloadBuilt - beaconRoot = t.CLMock.LatestPayloadAttributes.BeaconRoot + payload = &t.CLMock.LatestPayloadBuilt + beaconRoot = t.CLMock.LatestPayloadAttributes.BeaconRoot + version int = t.Env.ForkConfig.NewPayloadVersion(payload.Timestamp) + versionedHashes *[]common.Hash = nil + expectedError *int = nil + expectedStatus test.PayloadStatus = test.Valid + err error = nil ) if payload == nil { - return fmt.Errorf("no payload available") + return fmt.Errorf("TEST-FAIL: no payload available") + } + if t.CLMock.LatestBlobBundle == nil { + return fmt.Errorf("TEST-FAIL: no blob bundle available") + } + if step.NewPayloadCustomizer == nil { + return fmt.Errorf("TEST-FAIL: no payload customizer available") } - // Modify the versioned hashes - versionedHashes, err := step.VersionedHashes.VersionedHashes() + + // Send a custom new payload + version, err = step.NewPayloadCustomizer.GetVersion(t.Env.ForkConfig, payload) if err != nil { - return fmt.Errorf("error getting modified versioned hashes: %v", err) + t.Fatalf("FAIL: Error getting custom payload version: %v", err) } - // Modify the payload - if step.PayloadCustomizer != nil { - payload, beaconRoot, err = step.PayloadCustomizer.CustomizePayload(payload, beaconRoot) - if err != nil { - return fmt.Errorf("error modifying payload: %v", err) - } + payload, beaconRoot, err = step.NewPayloadCustomizer.CustomizePayload(payload, beaconRoot) + if err != nil { + t.Fatalf("FAIL: Error customizing payload: %v", err) } + versionedHashes, err = step.NewPayloadCustomizer.GetVersionedHashes(versionedHashes) + if err != nil { + t.Fatalf("FAIL: Error getting custom versioned hashes: %v", err) + } + expectedError, err = step.NewPayloadCustomizer.GetExpectedError() + if err != nil { + t.Fatalf("FAIL: Error getting custom expected error: %v", err) + } + if step.NewPayloadCustomizer.GetExpectInvalidStatus() { + expectedStatus = test.Invalid + } + // Send the payload if step.ClientID >= uint64(len(t.TestEngines)) { return fmt.Errorf("invalid client index %d", step.ClientID) } testEngine := t.TestEngines[step.ClientID] - r := testEngine.TestEngineNewPayloadV3(payload, versionedHashes, beaconRoot) - if step.ExpectedError != nil { - r.ExpectErrorCode(*step.ExpectedError) + r := testEngine.TestEngineNewPayload(payload, versionedHashes, beaconRoot, version) + if expectedError != nil { + r.ExpectErrorCode(*expectedError) } else { - r.ExpectStatus(step.ExpectedStatus) + r.ExpectStatus(expectedStatus) } return nil } func (step SendModifiedLatestPayload) Description() string { - desc := fmt.Sprintf("SendModifiedLatestPayload: client %d, expected status %s, ", step.ClientID, step.ExpectedStatus) - if step.VersionedHashes != nil { - desc += step.VersionedHashes.Description() - } + desc := fmt.Sprintf("SendModifiedLatestPayload: client %d, expected invalid=%T, ", step.ClientID, step.NewPayloadCustomizer.GetExpectInvalidStatus()) + /* + TODO: Figure out if we need this. + if step.VersionedHashes != nil { + desc += step.VersionedHashes.Description() + } + */ return desc } diff --git a/simulators/ethereum/engine/suites/cancun/tests.go b/simulators/ethereum/engine/suites/cancun/tests.go index eb3e679ef2..87f79eb38c 100644 --- a/simulators/ethereum/engine/suites/cancun/tests.go +++ b/simulators/ethereum/engine/suites/cancun/tests.go @@ -537,6 +537,278 @@ var Tests = []test.SpecInterface{ }, }, + // ForkchoiceUpdatedV3 before cancun + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "ForkchoiceUpdatedV3 Set Head to Shanghai Payload, Nil Payload Attributes", + About: ` + Test sending ForkchoiceUpdatedV3 to set the head of the chain to a Shanghai payload: + - Send NewPayloadV2 with Shanghai payload on block 1 + - Use ForkchoiceUpdatedV3 to set the head to the payload, with nil payload attributes + + Verify that client returns no error. + `, + }, + + CancunForkHeight: 2, + + TestSequence: TestSequence{ + NewPayloads{ + FcUOnHeadSet: &helper.UpgradeForkchoiceUpdatedVersion{ + ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{}, + }, + ExpectationDescription: ` + ForkchoiceUpdatedV3 before Cancun returns no error without payload attributes + `, + }, + }, + }, + + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "ForkchoiceUpdatedV3 To Request Shanghai Payload, Nil Beacon Root", + About: ` + Test sending ForkchoiceUpdatedV3 to request a Shanghai payload: + - Payload Attributes uses Shanghai timestamp + - Payload Attributes' Beacon Root is nil + + Verify that client returns INVALID_PARAMS_ERROR. + `, + }, + + CancunForkHeight: 2, + + TestSequence: TestSequence{ + NewPayloads{ + FcUOnPayloadRequest: &helper.UpgradeForkchoiceUpdatedVersion{ + ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ + ExpectedError: INVALID_PARAMS_ERROR, + }, + }, + ExpectationDescription: fmt.Sprintf(` + ForkchoiceUpdatedV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) + `, *INVALID_PARAMS_ERROR), + }, + }, + }, + + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "ForkchoiceUpdatedV3 To Request Shanghai Payload, Zero Beacon Root", + About: ` + Test sending ForkchoiceUpdatedV3 to request a Shanghai payload: + - Payload Attributes uses Shanghai timestamp + - Payload Attributes' Beacon Root zero + + Verify that client returns UNSUPPORTED_FORK_ERROR. + `, + }, + + CancunForkHeight: 2, + + TestSequence: TestSequence{ + NewPayloads{ + FcUOnPayloadRequest: &helper.UpgradeForkchoiceUpdatedVersion{ + ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ + PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ + BeaconRoot: &(common.Hash{}), + }, + ExpectedError: UNSUPPORTED_FORK_ERROR, + }, + }, + ExpectationDescription: fmt.Sprintf(` + ForkchoiceUpdatedV3 before Cancun with beacon root must return UNSUPPORTED_FORK_ERROR (code %d) + `, *UNSUPPORTED_FORK_ERROR), + }, + }, + }, + + // ForkchoiceUpdatedV2 before cancun with beacon root + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "ForkchoiceUpdatedV2 To Request Shanghai Payload, Zero Beacon Root", + About: ` + Test sending ForkchoiceUpdatedV2 to request a Cancun payload: + - Payload Attributes uses Shanghai timestamp + - Payload Attributes' Beacon Root zero + + Verify that client returns INVALID_PARAMS_ERROR. + `, + }, + + CancunForkHeight: 1, + + TestSequence: TestSequence{ + NewPayloads{ + FcUOnPayloadRequest: &helper.DowngradeForkchoiceUpdatedVersion{ + ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ + PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ + BeaconRoot: &(common.Hash{}), + }, + ExpectedError: INVALID_PARAMS_ERROR, + }, + }, + ExpectationDescription: fmt.Sprintf(` + ForkchoiceUpdatedV2 before Cancun with beacon root field must return INVALID_PARAMS_ERROR (code %d) + `, *INVALID_PARAMS_ERROR), + }, + }, + }, + + // ForkchoiceUpdatedV2 after cancun + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "ForkchoiceUpdatedV2 To Request Cancun Payload, Zero Beacon Root", + About: ` + Test sending ForkchoiceUpdatedV2 to request a Cancun payload: + - Payload Attributes uses Cancun timestamp + - Payload Attributes' Beacon Root zero + + Verify that client returns INVALID_PARAMS_ERROR. + `, + }, + + CancunForkHeight: 1, + + TestSequence: TestSequence{ + NewPayloads{ + FcUOnPayloadRequest: &helper.DowngradeForkchoiceUpdatedVersion{ + ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ + ExpectedError: INVALID_PARAMS_ERROR, + }, + }, + ExpectationDescription: fmt.Sprintf(` + ForkchoiceUpdatedV2 after Cancun with beacon root field must return INVALID_PARAMS_ERROR (code %d) + `, *INVALID_PARAMS_ERROR), + }, + }, + }, + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "ForkchoiceUpdatedV2 To Request Cancun Payload, Nil Beacon Root", + About: ` + Test sending ForkchoiceUpdatedV2 to request a Cancun payload: + - Payload Attributes uses Cancun timestamp + - Payload Attributes' Beacon Root nil (not provided) + + Verify that client returns UNSUPPORTED_FORK_ERROR. + `, + }, + + CancunForkHeight: 1, + + TestSequence: TestSequence{ + NewPayloads{ + FcUOnPayloadRequest: &helper.DowngradeForkchoiceUpdatedVersion{ + ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ + PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ + RemoveBeaconRoot: true, + }, + ExpectedError: UNSUPPORTED_FORK_ERROR, + }, + }, + ExpectationDescription: fmt.Sprintf(` + ForkchoiceUpdatedV2 after Cancun must return UNSUPPORTED_FORK_ERROR (code %d) + `, *UNSUPPORTED_FORK_ERROR), + }, + }, + }, + + // ForkchoiceUpdatedV3 with modified BeaconRoot Attribute + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "ForkchoiceUpdatedV3 Modifies Payload ID on Different Beacon Root", + About: ` + Test requesting a Cancun Payload using ForkchoiceUpdatedV3 twice with the beacon root + payload attribute as the only change between requests and verify that the payload ID is + different. + `, + }, + + CancunForkHeight: 0, + + TestSequence: TestSequence{ + SendBlobTransactions{ + TransactionCount: 1, + BlobsPerTransaction: MAX_BLOBS_PER_BLOCK, + BlobTransactionMaxBlobGasCost: big.NewInt(100), + }, + NewPayloads{ + ExpectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + FcUOnPayloadRequest: &helper.BaseForkchoiceUpdatedCustomizer{ + PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ + BeaconRoot: &(common.Hash{}), + }, + }, + }, + SendBlobTransactions{ + TransactionCount: 1, + BlobsPerTransaction: MAX_BLOBS_PER_BLOCK, + BlobTransactionMaxBlobGasCost: big.NewInt(100), + }, + NewPayloads{ + ExpectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + FcUOnPayloadRequest: &helper.BaseForkchoiceUpdatedCustomizer{ + PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ + BeaconRoot: &(common.Hash{1}), + }, + }, + }, + }, + }, + + // GetPayloadV3 Before Cancun, Negative Tests + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "GetPayloadV3 To Request Shanghai Payload", + About: ` + Test requesting a Shanghai PayloadID using GetPayloadV3. + Verify that client returns UNSUPPORTED_FORK_ERROR. + `, + }, + + CancunForkHeight: 2, + + TestSequence: TestSequence{ + NewPayloads{ + GetPayloadCustomizer: &helper.UpgradeGetPayloadVersion{ + GetPayloadCustomizer: &helper.BaseGetPayloadCustomizer{ + ExpectedError: UNSUPPORTED_FORK_ERROR, + }, + }, + ExpectationDescription: fmt.Sprintf(` + GetPayloadV3 To Request Shanghai Payload must return UNSUPPORTED_FORK_ERROR (code %d) + `, *UNSUPPORTED_FORK_ERROR), + }, + }, + }, + + // GetPayloadV2 After Cancun, Negative Tests + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "GetPayloadV2 To Request Cancun Payload", + About: ` + Test requesting a Cancun PayloadID using GetPayloadV2. + Verify that client returns UNSUPPORTED_FORK_ERROR. + `, + }, + + CancunForkHeight: 1, + + TestSequence: TestSequence{ + NewPayloads{ + GetPayloadCustomizer: &helper.DowngradeGetPayloadVersion{ + GetPayloadCustomizer: &helper.BaseGetPayloadCustomizer{ + ExpectedError: UNSUPPORTED_FORK_ERROR, + }, + }, + ExpectationDescription: fmt.Sprintf(` + GetPayloadV2 To Request Cancun Payload must return UNSUPPORTED_FORK_ERROR (code %d) + `, *UNSUPPORTED_FORK_ERROR), + }, + }, + }, + // NewPayloadV3 Before Cancun, Negative Tests &CancunBaseSpec{ Spec: test.Spec{ @@ -556,15 +828,17 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - VersionedHashes: &VersionedHashes{ - Blobs: nil, + NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: nil, + }, + ExpectedError: INVALID_PARAMS_ERROR, + }, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - `, INVALID_PARAMS_ERROR), + `, *INVALID_PARAMS_ERROR), }, }, }, @@ -584,15 +858,17 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - PayloadCustomizer: &helper.CustomPayloadData{ - BlobGasUsed: pUint64(0), + NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + BlobGasUsed: pUint64(0), + }, + ExpectedError: INVALID_PARAMS_ERROR, + }, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - `, INVALID_PARAMS_ERROR), + `, *INVALID_PARAMS_ERROR), }, }, }, @@ -612,15 +888,17 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - PayloadCustomizer: &helper.CustomPayloadData{ - ExcessBlobGas: pUint64(0), + NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + ExcessBlobGas: pUint64(0), + }, + ExpectedError: INVALID_PARAMS_ERROR, + }, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - `, INVALID_PARAMS_ERROR), + `, *INVALID_PARAMS_ERROR), }, }, }, @@ -640,15 +918,17 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - VersionedHashes: &VersionedHashes{ - Blobs: []helper.BlobID{}, + NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: []helper.BlobID{}, + }, + ExpectedError: INVALID_PARAMS_ERROR, + }, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - `, INVALID_PARAMS_ERROR), + `, *INVALID_PARAMS_ERROR), }, }, }, @@ -668,15 +948,17 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - PayloadCustomizer: &helper.CustomPayloadData{ - ParentBeaconRoot: &(common.Hash{}), + NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + ParentBeaconRoot: &(common.Hash{}), + }, + ExpectedError: INVALID_PARAMS_ERROR, + }, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - `, INVALID_PARAMS_ERROR), + `, *INVALID_PARAMS_ERROR), }, }, }, @@ -696,20 +978,22 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - VersionedHashes: &VersionedHashes{ - Blobs: []helper.BlobID{}, - }, - PayloadCustomizer: &helper.CustomPayloadData{ - ExcessBlobGas: pUint64(0), - BlobGasUsed: pUint64(0), - ParentBeaconRoot: &(common.Hash{}), + NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + ExcessBlobGas: pUint64(0), + BlobGasUsed: pUint64(0), + ParentBeaconRoot: &(common.Hash{}), + }, + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: []helper.BlobID{}, + }, + ExpectedError: UNSUPPORTED_FORK_ERROR, + }, }, - ExpectedError: UNSUPPORTED_FORK_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 before Cancun with no nil fields must return UNSUPPORTED_FORK_ERROR (code %d) - `, UNSUPPORTED_FORK_ERROR), + `, *UNSUPPORTED_FORK_ERROR), }, }, }, @@ -731,15 +1015,15 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - PayloadCustomizer: &helper.CustomPayloadData{ - RemoveExcessBlobGas: true, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + RemoveExcessBlobGas: true, + }, + ExpectedError: INVALID_PARAMS_ERROR, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 after Cancun with nil ExcessBlobGas must return INVALID_PARAMS_ERROR (code %d) - `, INVALID_PARAMS_ERROR), + `, *INVALID_PARAMS_ERROR), }, }, }, @@ -758,15 +1042,15 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - PayloadCustomizer: &helper.CustomPayloadData{ - RemoveBlobGasUsed: true, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + RemoveBlobGasUsed: true, + }, + ExpectedError: INVALID_PARAMS_ERROR, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 after Cancun with nil BlobGasUsed must return INVALID_PARAMS_ERROR (code %d) - `, INVALID_PARAMS_ERROR), + `, *INVALID_PARAMS_ERROR), }, }, }, @@ -785,15 +1069,57 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - Version: 3, - PayloadCustomizer: &helper.CustomPayloadData{ - RemoveParentBeaconRoot: true, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + RemoveParentBeaconRoot: true, + }, + ExpectedError: INVALID_PARAMS_ERROR, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: fmt.Sprintf(` NewPayloadV3 after Cancun with nil parentBeaconBlockRoot must return INVALID_PARAMS_ERROR (code %d) - `, INVALID_PARAMS_ERROR), + `, *INVALID_PARAMS_ERROR), + }, + }, + }, + + // Fork time tests + &CancunBaseSpec{ + Spec: test.Spec{ + Name: "ForkchoiceUpdatedV2 then ForkchoiceUpdatedV3 Valid Payload Building Requests", + About: ` + Test requesting a Shanghai ForkchoiceUpdatedV2 payload followed by a Cancun ForkchoiceUpdatedV3 request. + Verify that client correctly returns the Cancun payload. + `, + }, + + // We request two blocks from the client, first on shanghai and then on cancun, both with + // the same parent. + // Client must respond correctly to later request. + CancunForkHeight: 1, + TimeIncrements: 2, + + TestSequence: TestSequence{ + // First, we send a couple of blob transactions on genesis, + // with enough data gas cost to make sure they are included in the first block. + SendBlobTransactions{ + TransactionCount: TARGET_BLOBS_PER_BLOCK, + BlobTransactionMaxBlobGasCost: big.NewInt(1), + }, + NewPayloads{ + ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + // This customizer only simulates requesting a Shanghai payload 1 second before cancun. + // CL Mock will still request the Cancun payload afterwards + FcUOnPayloadRequest: &helper.BaseForkchoiceUpdatedCustomizer{ + PayloadAttributesCustomizer: &helper.TimestampDeltaPayloadAttributesCustomizer{ + PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ + RemoveBeaconRoot: true, + }, + TimestampDelta: -1, + }, + }, + ExpectationDescription: ` + ForkchoiceUpdatedV3 must construct transaction with blob payloads even if a ForkchoiceUpdatedV2 was previously requested + `, }, }, }, @@ -816,10 +1142,12 @@ var Tests = []test.SpecInterface{ NewPayloads{ ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, ExpectedBlobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - VersionedHashes: &VersionedHashes{ - Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK-1), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK-1), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, ExpectationDescription: ` NewPayloadV3 with incorrect list of versioned hashes must return INVALID status `, @@ -845,10 +1173,12 @@ var Tests = []test.SpecInterface{ NewPayloads{ ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, ExpectedBlobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - VersionedHashes: &VersionedHashes{ - Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK+1), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK+1), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, ExpectationDescription: ` NewPayloadV3 with incorrect list of versioned hashes must return INVALID status `, @@ -872,10 +1202,12 @@ var Tests = []test.SpecInterface{ NewPayloads{ ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, ExpectedBlobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - VersionedHashes: &VersionedHashes{ - Blobs: helper.GetBlobListByIndex(helper.BlobID(TARGET_BLOBS_PER_BLOCK-1), 0), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: helper.GetBlobListByIndex(helper.BlobID(TARGET_BLOBS_PER_BLOCK-1), 0), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, ExpectationDescription: ` NewPayloadV3 with incorrect list of versioned hashes must return INVALID status `, @@ -899,10 +1231,12 @@ var Tests = []test.SpecInterface{ NewPayloads{ ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, ExpectedBlobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - VersionedHashes: &VersionedHashes{ - Blobs: append(helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), helper.BlobID(TARGET_BLOBS_PER_BLOCK-1)), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: append(helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), helper.BlobID(TARGET_BLOBS_PER_BLOCK-1)), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, ExpectationDescription: ` NewPayloadV3 with incorrect list of versioned hashes must return INVALID status `, @@ -926,10 +1260,12 @@ var Tests = []test.SpecInterface{ NewPayloads{ ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, ExpectedBlobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - VersionedHashes: &VersionedHashes{ - Blobs: append(helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK-1), helper.BlobID(TARGET_BLOBS_PER_BLOCK)), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: append(helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK-1), helper.BlobID(TARGET_BLOBS_PER_BLOCK)), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, ExpectationDescription: ` NewPayloadV3 with incorrect hash in list of versioned hashes must return INVALID status `, @@ -952,11 +1288,13 @@ var Tests = []test.SpecInterface{ NewPayloads{ ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, ExpectedBlobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - VersionedHashes: &VersionedHashes{ - Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - HashVersions: []byte{BLOB_COMMITMENT_VERSION_KZG, BLOB_COMMITMENT_VERSION_KZG + 1}, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), + HashVersions: []byte{BLOB_COMMITMENT_VERSION_KZG, BLOB_COMMITMENT_VERSION_KZG + 1}, + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, ExpectationDescription: ` NewPayloadV3 with incorrect version in list of versioned hashes must return INVALID status `, @@ -980,10 +1318,12 @@ var Tests = []test.SpecInterface{ NewPayloads{ ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, ExpectedBlobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - VersionedHashes: &VersionedHashes{ - Blobs: nil, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: nil, + }, + ExpectedError: INVALID_PARAMS_ERROR, }, - ExpectedError: INVALID_PARAMS_ERROR, ExpectationDescription: ` NewPayloadV3 after Cancun with nil VersionedHashes must return INVALID_PARAMS_ERROR (code -32602) `, @@ -1007,10 +1347,12 @@ var Tests = []test.SpecInterface{ NewPayloads{ ExpectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, ExpectedBlobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - VersionedHashes: &VersionedHashes{ - Blobs: []helper.BlobID{}, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: []helper.BlobID{}, + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, ExpectationDescription: ` NewPayloadV3 with incorrect list of versioned hashes must return INVALID status `, @@ -1028,12 +1370,13 @@ var Tests = []test.SpecInterface{ }, TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - ExpectedBlobs: []helper.BlobID{}, - VersionedHashes: &VersionedHashes{ - Blobs: []helper.BlobID{0}, + ExpectedBlobs: []helper.BlobID{}, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: []helper.BlobID{0}, + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, ExpectationDescription: ` NewPayloadV3 with incorrect list of versioned hashes must return INVALID status `, @@ -1069,10 +1412,12 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK-1), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK-1), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, }, }, }, @@ -1105,10 +1450,12 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK+1), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK+1), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, }, }, }, @@ -1138,10 +1485,12 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: helper.GetBlobListByIndex(helper.BlobID(TARGET_BLOBS_PER_BLOCK-1), 0), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: helper.GetBlobListByIndex(helper.BlobID(TARGET_BLOBS_PER_BLOCK-1), 0), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, }, }, }, @@ -1172,10 +1521,12 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: append(helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), helper.BlobID(TARGET_BLOBS_PER_BLOCK-1)), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: append(helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), helper.BlobID(TARGET_BLOBS_PER_BLOCK-1)), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, }, }, }, @@ -1206,10 +1557,12 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: append(helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK-1), helper.BlobID(TARGET_BLOBS_PER_BLOCK)), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: append(helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK-1), helper.BlobID(TARGET_BLOBS_PER_BLOCK)), + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, }, }, }, @@ -1239,11 +1592,13 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), - HashVersions: []byte{BLOB_COMMITMENT_VERSION_KZG, BLOB_COMMITMENT_VERSION_KZG + 1}, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: helper.GetBlobList(0, TARGET_BLOBS_PER_BLOCK), + HashVersions: []byte{BLOB_COMMITMENT_VERSION_KZG, BLOB_COMMITMENT_VERSION_KZG + 1}, + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, }, }, }, @@ -1274,10 +1629,12 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: nil, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: nil, + }, + ExpectedError: INVALID_PARAMS_ERROR, }, - ExpectedError: INVALID_PARAMS_ERROR, }, }, }, @@ -1308,10 +1665,12 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: []helper.BlobID{}, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: []helper.BlobID{}, + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, }, }, }, @@ -1327,8 +1686,7 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ NewPayloads{}, // Send new payload so the parent is unknown to the secondary client NewPayloads{ - ExpectedIncludedBlobCount: 0, - ExpectedBlobs: []helper.BlobID{}, + ExpectedBlobs: []helper.BlobID{}, }, LaunchClients{ @@ -1338,10 +1696,12 @@ var Tests = []test.SpecInterface{ }, SendModifiedLatestPayload{ ClientID: 1, - VersionedHashes: &VersionedHashes{ - Blobs: []helper.BlobID{0}, + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + VersionedHashesCustomizer: &VersionedHashes{ + Blobs: []helper.BlobID{0}, + }, + ExpectInvalidStatus: true, }, - ExpectedStatus: test.Invalid, }, }, }, @@ -1359,9 +1719,11 @@ var Tests = []test.SpecInterface{ }, TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - PayloadCustomizer: &helper.CustomPayloadData{ - BlobGasUsed: pUint64(1), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + BlobGasUsed: pUint64(1), + }, + ExpectInvalidStatus: true, }, }, }, @@ -1376,9 +1738,11 @@ var Tests = []test.SpecInterface{ }, TestSequence: TestSequence{ NewPayloads{ - ExpectedIncludedBlobCount: 0, - PayloadCustomizer: &helper.CustomPayloadData{ - BlobGasUsed: pUint64(GAS_PER_BLOB), + NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + PayloadCustomizer: &helper.CustomPayloadData{ + BlobGasUsed: pUint64(GAS_PER_BLOB), + }, + ExpectInvalidStatus: true, }, }, }, @@ -1521,7 +1885,7 @@ var Tests = []test.SpecInterface{ TestSequence: TestSequence{ // Get past the genesis NewPayloads{ - ExpectedIncludedBlobCount: 0, + PayloadCount: 1, }, // Send multiple transactions with multiple blobs each SendBlobTransactions{ diff --git a/simulators/ethereum/engine/test/expect.go b/simulators/ethereum/engine/test/expect.go index 3131713644..fe1de650a8 100644 --- a/simulators/ethereum/engine/test/expect.go +++ b/simulators/ethereum/engine/test/expect.go @@ -125,10 +125,19 @@ func (tec *TestEngineClient) TestEngineForkchoiceUpdated(fcState *api.Forkchoice if version == -1 { version = client.LatestForkchoiceUpdatedVersion } - if version == 2 { - return tec.TestEngineForkchoiceUpdatedV2(fcState, pAttributes) + ctx, cancel := context.WithTimeout(tec.TestContext, globals.RPCTimeout) + defer cancel() + resp, err := tec.Engine.ForkchoiceUpdated(ctx, version, fcState, pAttributes) + ret := &ForkchoiceResponseExpectObject{ + ExpectEnv: &ExpectEnv{Env: tec.Env}, + Response: resp, + Version: version, + Error: err, + } + if err, ok := err.(rpc.Error); ok { + ret.ErrorCode = err.ErrorCode() } - return tec.TestEngineForkchoiceUpdatedV1(fcState, pAttributes) + return ret } func (exp *ForkchoiceResponseExpectObject) ExpectNoError() { @@ -338,11 +347,13 @@ func (exp *NewPayloadResponseExpectObject) ExpectLatestValidHash(lvh *common.Has // GetPayload type GetPayloadResponseExpectObject struct { *ExpectEnv - Payload typ.ExecutableData - BlockValue *big.Int - Version int - Error error - ErrorCode int + Payload typ.ExecutableData + BlockValue *big.Int + BlobsBundle *typ.BlobsBundle + ShouldOverrideBuilder *bool + Version int + Error error + ErrorCode int } func (tec *TestEngineClient) TestEngineGetPayloadV1(payloadID *api.PayloadID) *GetPayloadResponseExpectObject { @@ -380,10 +391,22 @@ func (tec *TestEngineClient) TestEngineGetPayloadV2(payloadID *api.PayloadID) *G } func (tec *TestEngineClient) TestEngineGetPayload(payloadID *api.PayloadID, version int) *GetPayloadResponseExpectObject { - if version == 2 { - return tec.TestEngineGetPayloadV2(payloadID) + ctx, cancel := context.WithTimeout(tec.TestContext, globals.RPCTimeout) + defer cancel() + payload, blockValue, blobBundle, shouldOverride, err := tec.Engine.GetPayload(ctx, version, payloadID) + ret := &GetPayloadResponseExpectObject{ + ExpectEnv: &ExpectEnv{Env: tec.Env}, + Payload: payload, + Version: version, + BlockValue: blockValue, + BlobsBundle: blobBundle, + ShouldOverrideBuilder: shouldOverride, + Error: err, } - return tec.TestEngineGetPayloadV1(payloadID) + if err, ok := err.(rpc.Error); ok { + ret.ErrorCode = err.ErrorCode() + } + return ret } func (exp *GetPayloadResponseExpectObject) ExpectNoError() {