Skip to content

Commit 29b3cc3

Browse files
committed
Working commit
1 parent 24fe2b5 commit 29b3cc3

File tree

10 files changed

+357
-327
lines changed

10 files changed

+357
-327
lines changed

simulators/ethereum/engine/client/node/node.go

+22-8
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ func (n *GethNode) NewPayloadV3(ctx context.Context, pl *typ.ExecutableData) (be
472472
if err != nil {
473473
return beacon.PayloadStatusV1{}, err
474474
}
475+
if pl.VersionedHashes == nil {
476+
return beacon.PayloadStatusV1{}, fmt.Errorf("versioned hashes are nil")
477+
}
475478
resp, err := n.api.NewPayloadV3(ed, *pl.VersionedHashes, pl.ParentBeaconBlockRoot)
476479
n.latestPayloadStatusReponse = &resp
477480
return resp, err
@@ -483,6 +486,8 @@ func (n *GethNode) ForkchoiceUpdated(ctx context.Context, version int, fcs *beac
483486
return n.ForkchoiceUpdatedV1(ctx, fcs, payload)
484487
case 2:
485488
return n.ForkchoiceUpdatedV2(ctx, fcs, payload)
489+
case 3:
490+
return n.ForkchoiceUpdatedV3(ctx, fcs, payload)
486491
default:
487492
return beacon.ForkChoiceResponse{}, fmt.Errorf("unknown version %d", version)
488493
}
@@ -548,18 +553,27 @@ func (n *GethNode) GetPayloadV3(ctx context.Context, payloadId *beacon.PayloadID
548553
return typ.ExecutableData{}, nil, nil, nil, err
549554
}
550555
ed, err := typ.FromBeaconExecutableData(p.ExecutionPayload)
551-
// TODO: Convert and return the blobs bundle
552-
return ed, p.BlockValue, nil, &p.Override, err
556+
blobsBundle := &typ.BlobsBundle{}
557+
if err := blobsBundle.FromBeaconBlobsBundle(p.BlobsBundle); err != nil {
558+
return typ.ExecutableData{}, nil, nil, nil, err
559+
}
560+
return ed, p.BlockValue, blobsBundle, &p.Override, err
553561
}
554562

555563
func (n *GethNode) GetPayload(ctx context.Context, version int, payloadId *beacon.PayloadID) (typ.ExecutableData, *big.Int, *typ.BlobsBundle, *bool, error) {
556-
p, err := n.api.GetPayloadV3(*payloadId)
557-
if p == nil || err != nil {
558-
return typ.ExecutableData{}, nil, nil, nil, err
564+
565+
switch version {
566+
case 1:
567+
ed, err := n.GetPayloadV1(ctx, payloadId)
568+
return ed, nil, nil, nil, err
569+
case 2:
570+
ed, value, err := n.GetPayloadV2(ctx, payloadId)
571+
return ed, value, nil, nil, err
572+
case 3:
573+
return n.GetPayloadV3(ctx, payloadId)
574+
default:
575+
return typ.ExecutableData{}, nil, nil, nil, fmt.Errorf("unknown version %d", version)
559576
}
560-
ed, err := typ.FromBeaconExecutableData(p.ExecutionPayload)
561-
// TODO: Convert and return the blobs bundle
562-
return ed, p.BlockValue, nil, &p.Override, err
563577
}
564578

565579
func (n *GethNode) GetPayloadBodiesByRangeV1(ctx context.Context, start uint64, count uint64) ([]*typ.ExecutionPayloadBodyV1, error) {

simulators/ethereum/engine/clmock/clmock.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -695,9 +695,11 @@ func (cl *CLMocker) ProduceSingleBlock(callbacks BlockProcessCallbacks) {
695695
defer cancel()
696696
newHeader, err := ec.HeaderByNumber(ctx, cl.LatestHeadNumber)
697697
if err != nil {
698+
cl.Logf("CLMocker: Client %v did not accept the new payload: %v", ec.ID(), err)
698699
continue
699700
}
700701
if newHeader.Hash() != cl.LatestPayloadBuilt.BlockHash {
702+
cl.Logf("CLMocker: Client %v produced a new header with incorrect hash: %v != %v", ec.ID(), newHeader.Hash(), cl.LatestPayloadBuilt.BlockHash)
701703
continue
702704
}
703705
// Check that the new finalized header has the correct properties
@@ -726,6 +728,7 @@ func (cl *CLMocker) ProduceSingleBlock(callbacks BlockProcessCallbacks) {
726728
cl.Fatalf("CLMocker: None of the clients accepted the newly constructed payload")
727729
}
728730
cl.HeaderHistory[cl.LatestHeadNumber.Uint64()] = cl.LatestHeader
731+
cl.Logf("CLMocker: New block produced: number=%d, hash=%x", cl.LatestHeader.Number, cl.LatestHeader.Hash())
729732
}
730733

731734
// Loop produce PoS blocks by using the Engine API
@@ -776,7 +779,7 @@ func (cl *CLMocker) BroadcastForkchoiceUpdated(fcstate *api.ForkchoiceStateV1, p
776779
defer cancel()
777780
fcUpdatedResp, err := ec.ForkchoiceUpdated(ctx, version, fcstate, payloadAttr)
778781
if err != nil {
779-
cl.Errorf("CLMocker: Could not ForkchoiceUpdatedV1: %v", err)
782+
cl.Errorf("CLMocker: Could not ForkchoiceUpdated: %v", err)
780783
responses[i].Error = err
781784
} else {
782785
responses[i].ForkchoiceResponse = &fcUpdatedResp

simulators/ethereum/engine/suites/cancun/tests.go

+20
Original file line numberDiff line numberDiff line change
@@ -1824,4 +1824,24 @@ func init() {
18241824
for _, test := range suite_engine.Tests {
18251825
Tests = append(Tests, test.WithMainFork(config.Cancun))
18261826
}
1827+
1828+
// Cancun specific variants for pre-existing tests
1829+
// Payload Attributes
1830+
for _, t := range []suite_engine.InvalidPayloadAttributesTest{
1831+
{
1832+
BaseSpec: test.BaseSpec{
1833+
MainFork: config.Cancun,
1834+
},
1835+
Description: "Missing BeaconRoot",
1836+
Customizer: &helper.BasePayloadAttributesCustomizer{
1837+
RemoveBeaconRoot: true,
1838+
},
1839+
// Error is expected on syncing because V3 checks all fields to be present
1840+
ErrorOnSync: true,
1841+
},
1842+
} {
1843+
Tests = append(Tests, t)
1844+
t.Syncing = true
1845+
Tests = append(Tests, t)
1846+
}
18271847
}

simulators/ethereum/engine/suites/engine/bad_hash.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ func (b BadHashOnNewPayload) Execute(t *test.Env) {
109109
// - {status: INVALID_BLOCK_HASH, latestValidHash: null, validationError: null} if the blockHash validation has failed
110110
// Starting from Shanghai, INVALID should be returned instead (https://github.com/ethereum/execution-apis/pull/338)
111111
r := t.TestEngine.TestEngineNewPayload(&alteredPayload)
112-
r.ExpectStatusEither(test.InvalidBlockHash, test.Invalid)
112+
if r.Version >= 2 {
113+
r.ExpectStatus(test.Invalid)
114+
} else {
115+
r.ExpectStatusEither(test.InvalidBlockHash, test.Invalid)
116+
}
113117
r.ExpectLatestValidHash(nil)
114118
},
115119
})
@@ -178,7 +182,11 @@ func (b ParentHashOnNewPayload) Execute(t *test.Env) {
178182
// - {status: INVALID_BLOCK_HASH, latestValidHash: null, validationError: null} if the blockHash validation has failed
179183
// Starting from Shanghai, INVALID should be returned instead (https://github.com/ethereum/execution-apis/pull/338)
180184
r := t.TestEngine.TestEngineNewPayload(&alteredPayload)
181-
r.ExpectStatusEither(test.InvalidBlockHash)
185+
if r.Version >= 2 {
186+
r.ExpectStatus(test.Invalid)
187+
} else {
188+
r.ExpectStatusEither(test.Invalid, test.InvalidBlockHash)
189+
}
182190
r.ExpectLatestValidHash(nil)
183191
},
184192
})

simulators/ethereum/engine/suites/engine/invalid_ancestor.go

+30-41
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func (tc InvalidMissingAncestorReOrgSyncTest) GetName() string {
202202
if tc.EmptyTransactions {
203203
name += "Empty Txs, "
204204
}
205-
name += fmt.Sprintf(", Invalid P%d', Reveal using sync", tc.InvalidIndex)
205+
name += fmt.Sprintf("Invalid P%d', Reveal using sync", tc.InvalidIndex)
206206
if tc.ReOrgFromCanonical {
207207
name += " (ReOrg from Canonical)"
208208
}
@@ -240,30 +240,17 @@ func (tc InvalidMissingAncestorReOrgSyncTest) Execute(t *test.Env) {
240240
t.CLMock.WaitForTTD()
241241

242242
// Produce blocks before starting the test
243-
var cA *types.Block
244-
245-
cAHeight := tc.CommonAncestorHeight
246-
if cAHeight == nil {
247-
// Default is to produce 5 PoS blocks before the common ancestor
248-
cAHeight = big.NewInt(5)
243+
// Default is to produce 5 PoS blocks before the common ancestor
244+
cAHeight := 5
245+
if tc.CommonAncestorHeight != nil {
246+
cAHeight = int(tc.CommonAncestorHeight.Int64())
249247
}
250248

251249
// Save the common ancestor
252-
if cAHeight.Cmp(big0) == 0 {
253-
// Common ancestor is the proof-of-work terminal block
254-
ctx, cancel := context.WithTimeout(t.TestContext, globals.RPCTimeout)
255-
defer cancel()
256-
b, err := secondaryClient.BlockByNumber(ctx, nil)
257-
if err != nil {
258-
t.Fatalf("FAIL (%s): Error while getting latest block: %v", t.TestName, err)
259-
}
260-
cA = b
250+
if cAHeight == 0 {
251+
t.Fatalf("FAIL (%s): Invalid common ancestor height: %d", t.TestName, cAHeight)
261252
} else {
262-
t.CLMock.ProduceBlocks(int(cAHeight.Int64()), clmock.BlockProcessCallbacks{})
263-
cA, err = typ.ExecutableDataToBlock(t.CLMock.LatestPayloadBuilt)
264-
if err != nil {
265-
t.Fatalf("FAIL (%s): Error converting payload to block: %v", t.TestName, err)
266-
}
253+
t.CLMock.ProduceBlocks(cAHeight, clmock.BlockProcessCallbacks{})
267254
}
268255

269256
// Amount of blocks to deviate starting from the common ancestor
@@ -274,15 +261,17 @@ func (tc InvalidMissingAncestorReOrgSyncTest) Execute(t *test.Env) {
274261
}
275262

276263
// Slice to save the side B chain
277-
altChainPayloads := make([]*types.Block, 0)
264+
altChainPayloads := make([]*typ.ExecutableData, 0)
278265

279266
// Append the common ancestor
280-
altChainPayloads = append(altChainPayloads, cA)
267+
cA := t.CLMock.LatestPayloadBuilt
268+
altChainPayloads = append(altChainPayloads, &cA)
281269

282270
// Produce blocks but at the same time create an side chain which contains an invalid payload at some point (INV_P)
283271
// CommonAncestor◄─▲── P1 ◄─ P2 ◄─ P3 ◄─ ... ◄─ Pn
284272
// │
285273
// └── P1' ◄─ P2' ◄─ ... ◄─ INV_P ◄─ ... ◄─ Pn'
274+
t.Log("INFO: Starting canonical chain production")
286275
t.CLMock.ProduceBlocks(n, clmock.BlockProcessCallbacks{
287276

288277
OnPayloadProducerSelected: func() {
@@ -312,7 +301,7 @@ func (tc InvalidMissingAncestorReOrgSyncTest) Execute(t *test.Env) {
312301
err error
313302
)
314303
// Insert extraData to ensure we deviate from the main payload, which contains empty extradata
315-
pHash := altChainPayloads[len(altChainPayloads)-1].Hash()
304+
pHash := altChainPayloads[len(altChainPayloads)-1].BlockHash
316305
customizer := &helper.CustomPayloadData{
317306
ParentHash: &pHash,
318307
ExtraData: &([]byte{0x01}),
@@ -327,7 +316,9 @@ func (tc InvalidMissingAncestorReOrgSyncTest) Execute(t *test.Env) {
327316
t.Fatalf("FAIL (%s): Unable to customize payload: %v", t.TestName, err)
328317
}
329318
}
319+
altChainPayloads = append(altChainPayloads, sidePayload)
330320

321+
// TODO: REMOVE THIS
331322
sideBlock, err := typ.ExecutableDataToBlock(*sidePayload)
332323
if err != nil {
333324
t.Fatalf("FAIL (%s): Error converting payload to block: %v", t.TestName, err)
@@ -351,10 +342,9 @@ func (tc InvalidMissingAncestorReOrgSyncTest) Execute(t *test.Env) {
351342
t.Fatalf("FAIL (%s): Unable to customize payload block: %v", t.TestName, err)
352343
}
353344
}
354-
355-
altChainPayloads = append(altChainPayloads, sideBlock)
356345
},
357346
})
347+
t.Log("INFO: Starting side chain production")
358348
t.CLMock.ProduceSingleBlock(clmock.BlockProcessCallbacks{
359349
// Note: We perform the test in the middle of payload creation by the CL Mock, in order to be able to
360350
// re-org back into this chain and use the new payload without issues.
@@ -369,30 +359,30 @@ func (tc InvalidMissingAncestorReOrgSyncTest) Execute(t *test.Env) {
369359
} else if i > tc.InvalidIndex {
370360
payloadValidStr = "VALID with INVALID ancestor"
371361
}
372-
payloadJs, _ := json.MarshalIndent(altChainPayloads[i].Header(), "", " ")
362+
payloadJs, _ := json.MarshalIndent(altChainPayloads[i], "", " ")
373363
t.Logf("INFO (%s): Invalid chain payload %d (%s):\n%s", t.TestName, i, payloadValidStr, payloadJs)
374364

375365
if i < tc.InvalidIndex {
376-
p := typ.BlockToExecutableData(altChainPayloads[i], common.Big0)
377-
r := secondaryTestClient.TestEngineNewPayload(&p)
366+
p := altChainPayloads[i]
367+
r := secondaryTestClient.TestEngineNewPayload(p)
378368
r.ExpectationDescription = "Sent modified payload to secondary client, expected to be accepted"
379369
r.ExpectStatusEither(test.Valid, test.Accepted)
380370

381371
s := secondaryTestClient.TestEngineForkchoiceUpdated(&api.ForkchoiceStateV1{
382372
HeadBlockHash: p.BlockHash,
383-
SafeBlockHash: cA.Hash(),
373+
SafeBlockHash: cA.BlockHash,
384374
FinalizedBlockHash: common.Hash{},
385375
}, nil, p.Timestamp)
386376
s.ExpectationDescription = "Sent modified payload forkchoice updated to secondary client, expected to be accepted"
387377
s.ExpectAnyPayloadStatus(test.Valid, test.Syncing)
388378

389379
} else {
390-
invalidBlock := altChainPayloads[i]
380+
invalidBlock, err := typ.ExecutableDataToBlock(*altChainPayloads[i])
391381
if err != nil {
392382
t.Fatalf("FAIL (%s): TEST ISSUE - Failed to create block from payload: %v", t.TestName, err)
393383
}
394384

395-
if err := secondaryClient.SetBlock(invalidBlock, altChainPayloads[i-1].NumberU64(), altChainPayloads[i-1].Root()); err != nil {
385+
if err := secondaryClient.SetBlock(invalidBlock, altChainPayloads[i-1].Number, altChainPayloads[i-1].StateRoot); err != nil {
396386
t.Fatalf("FAIL (%s): TEST ISSUE - Failed to set invalid block: %v", t.TestName, err)
397387
}
398388
t.Logf("INFO (%s): Invalid block successfully set %d (%s): %v", t.TestName, i, payloadValidStr, invalidBlock.Hash())
@@ -406,8 +396,8 @@ func (tc InvalidMissingAncestorReOrgSyncTest) Execute(t *test.Env) {
406396
t.Fatalf("FAIL (%s): TEST ISSUE - Secondary Node unable to reatrieve latest header: %v", t.TestName, err)
407397

408398
}
409-
if head.Hash() != altChainPayloads[n-1].Hash() {
410-
t.Fatalf("FAIL (%s): TEST ISSUE - Secondary Node has invalid blockhash got %v want %v gotNum %v wantNum %d", t.TestName, head.Hash(), altChainPayloads[n-1].Hash(), head.Number, altChainPayloads[n].NumberU64())
399+
if head.Hash() != altChainPayloads[n-1].BlockHash {
400+
t.Fatalf("FAIL (%s): TEST ISSUE - Secondary Node has invalid blockhash got %v want %v gotNum %v wantNum %d", t.TestName, head.Hash(), altChainPayloads[n-1].BlockHash, head.Number, altChainPayloads[n].Number)
411401
} else {
412402
t.Logf("INFO (%s): Secondary Node has correct block", t.TestName)
413403
}
@@ -425,24 +415,23 @@ func (tc InvalidMissingAncestorReOrgSyncTest) Execute(t *test.Env) {
425415
t.Logf("INFO (%s): Latest block on main client before sync: hash=%v, number=%d", t.TestName, l.Hash(), l.Number())
426416
}
427417
// If we are syncing through p2p, we need to keep polling until the client syncs the missing payloads
428-
ed := typ.BlockToExecutableData(altChainPayloads[n], common.Big0)
429418
for {
430-
r := t.TestEngine.TestEngineNewPayload(&ed)
419+
r := t.TestEngine.TestEngineNewPayload(altChainPayloads[n])
431420
t.Logf("INFO (%s): Response from main client: %v", t.TestName, r.Status)
432421
s := t.TestEngine.TestEngineForkchoiceUpdated(&api.ForkchoiceStateV1{
433-
HeadBlockHash: altChainPayloads[n].Hash(),
434-
SafeBlockHash: altChainPayloads[n].Hash(),
422+
HeadBlockHash: altChainPayloads[n].BlockHash,
423+
SafeBlockHash: altChainPayloads[n].BlockHash,
435424
FinalizedBlockHash: common.Hash{},
436-
}, nil, ed.Timestamp)
425+
}, nil, altChainPayloads[n].Timestamp)
437426
t.Logf("INFO (%s): Response from main client fcu: %v", t.TestName, s.Response.PayloadStatus)
438427

439428
if r.Status.Status == test.Invalid {
440429
// We also expect that the client properly returns the LatestValidHash of the block on the
441430
// side chain that is immediately prior to the invalid payload (or zero if parent is PoW)
442431
var lvh common.Hash
443-
if cAHeight.Cmp(big0) != 0 || tc.InvalidIndex != 1 {
432+
if cAHeight != 0 || tc.InvalidIndex != 1 {
444433
// Parent is NOT Proof of Work
445-
lvh = altChainPayloads[tc.InvalidIndex-1].Hash()
434+
lvh = altChainPayloads[tc.InvalidIndex-1].BlockHash
446435
}
447436
r.ExpectLatestValidHash(&lvh)
448437
// Response on ForkchoiceUpdated should be the same

simulators/ethereum/engine/suites/engine/payload_attributes.go

+17-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"fmt"
55
"math/rand"
66

7-
"github.com/ethereum/go-ethereum/common"
87
"github.com/ethereum/hive/simulators/ethereum/engine/clmock"
98
"github.com/ethereum/hive/simulators/ethereum/engine/config"
109
"github.com/ethereum/hive/simulators/ethereum/engine/helper"
@@ -16,6 +15,7 @@ type InvalidPayloadAttributesTest struct {
1615
Description string
1716
Customizer helper.PayloadAttributesCustomizer
1817
Syncing bool
18+
ErrorOnSync bool
1919
}
2020

2121
func (s InvalidPayloadAttributesTest) WithMainFork(fork config.Fork) test.Spec {
@@ -41,17 +41,21 @@ func (tc InvalidPayloadAttributesTest) Execute(t *test.Env) {
4141

4242
// Send a forkchoiceUpdated with invalid PayloadAttributes
4343
t.CLMock.ProduceSingleBlock(clmock.BlockProcessCallbacks{
44-
OnPayloadAttributesGenerated: func() {
44+
OnNewPayloadBroadcast: func() {
4545
// Try to apply the new payload with invalid attributes
4646
fcu := t.CLMock.LatestForkchoice
47-
var blockHash common.Hash
4847
if tc.Syncing {
4948
// Setting a random hash will put the client into `SYNCING`
5049
rand.Read(fcu.HeadBlockHash[:])
50+
} else {
51+
fcu.HeadBlockHash = t.CLMock.LatestPayloadBuilt.BlockHash
5152
}
52-
t.Logf("INFO (%s): Sending EngineForkchoiceUpdated (Syncing=%s) with invalid payload attributes: %s", t.TestName, tc.Syncing, tc.Description)
53+
t.Logf("INFO (%s): Sending EngineForkchoiceUpdated (Syncing=%t) with invalid payload attributes: %s", t.TestName, tc.Syncing, tc.Description)
5354

54-
attr, err := tc.Customizer.GetPayloadAttributes(&t.CLMock.LatestPayloadAttributes)
55+
// Get the payload attributes
56+
originalAttr := t.CLMock.LatestPayloadAttributes
57+
originalAttr.Timestamp += 1
58+
attr, err := tc.Customizer.GetPayloadAttributes(&originalAttr)
5559
if err != nil {
5660
t.Fatalf("FAIL (%s): Unable to customize payload attributes: %v", t.TestName, err)
5761
}
@@ -64,15 +68,20 @@ func (tc InvalidPayloadAttributesTest) Execute(t *test.Env) {
6468
if tc.Syncing {
6569
// If we are SYNCING, the outcome should be SYNCING regardless of the validity of the payload atttributes
6670
r := t.TestEngine.TestEngineForkchoiceUpdated(&fcu, attr, t.CLMock.LatestPayloadBuilt.Timestamp)
67-
r.ExpectPayloadStatus(test.Syncing)
68-
r.ExpectPayloadID(nil)
71+
if tc.ErrorOnSync {
72+
r.ExpectError()
73+
} else {
74+
r.ExpectPayloadStatus(test.Syncing)
75+
r.ExpectPayloadID(nil)
76+
}
6977
} else {
7078
r := t.TestEngine.TestEngineForkchoiceUpdated(&fcu, attr, t.CLMock.LatestPayloadBuilt.Timestamp)
7179
r.ExpectError()
7280

7381
// Check that the forkchoice was applied, regardless of the error
7482
s := t.TestEngine.TestHeaderByNumber(Head)
75-
s.ExpectHash(blockHash)
83+
s.ExpectationDescription = "Forkchoice is applied even on invalid payload attributes"
84+
s.ExpectHash(fcu.HeadBlockHash)
7685
}
7786
},
7887
})

0 commit comments

Comments
 (0)