diff --git a/simulators/ethereum/engine/suites/withdrawals/README.md b/simulators/ethereum/engine/suites/withdrawals/README.md index a5491eaaa5..1f91ea9ee7 100644 --- a/simulators/ethereum/engine/suites/withdrawals/README.md +++ b/simulators/ethereum/engine/suites/withdrawals/README.md @@ -183,6 +183,17 @@ All test cases contain the following verifications: - Requested payload bodies past the highest known block are ignored and absent from the returned list - Payloads `32'` and `33'` are ignored by all requests since they are not part of the canonical chain. +- Payload Bodies By Hash/Range After Sync - Shanghai Fork on Block 16 - 16 Withdrawal Blocks + - Launch client `A` and create a canonical chain consisting of 32 blocks, where the first shanghai block is number 17 + - Payloads produced have: 16 Transactions, 16 Withdrawals + - Launch client `B` and send `NewPayload(P32)` + `FcU(P32)` to it. + - Wait until client `B` syncs the canonical chain, or timeout. + - Make multiple requests to obtain the payload bodies from the canonical chain (see `./tests.go` for full list) to client `B`. + - Verify that: + - Payload bodies of blocks before the Shanghai fork contain `withdrawals==null` + - All transactions and withdrawals are in the correct format and order. + - Requested payload bodies past the highest known block are ignored and absent from the returned list + - Payload Bodies By Hash - Shanghai Fork on Block 16 - 16 Withdrawal Blocks - Launch client `A` and create a canonical chain consisting of 32 blocks, where the first shanghai block is number 17 - Payloads produced of the following characteristics diff --git a/simulators/ethereum/engine/suites/withdrawals/tests.go b/simulators/ethereum/engine/suites/withdrawals/tests.go index 53f11946ee..3cb75e65ab 100644 --- a/simulators/ethereum/engine/suites/withdrawals/tests.go +++ b/simulators/ethereum/engine/suites/withdrawals/tests.go @@ -580,6 +580,56 @@ var Tests = []test.SpecInterface{ }, }, + &GetPayloadBodiesSpec{ + WithdrawalsBaseSpec: &WithdrawalsBaseSpec{ + Spec: test.Spec{ + Name: "GetPayloadBodies After Sync", + About: ` + Make multiple withdrawals to 16 accounts each payload. + Spawn a secondary client which must sync the canonical chain + from the first client. + Retrieve many of the payloads' bodies by number range from + this secondary client. + `, + TimeoutSeconds: 240, + SlotsToSafe: big.NewInt(32), + SlotsToFinalized: big.NewInt(64), + }, + WithdrawalsForkHeight: 17, + WithdrawalsBlockCount: 16, + WithdrawalsPerBlock: 16, + WithdrawableAccountCount: 1024, + }, + GetPayloadBodiesRequests: []GetPayloadBodyRequest{ + GetPayloadBodyRequestByRange{ + Start: 16, + Count: 2, + }, + GetPayloadBodyRequestByRange{ + Start: 31, + Count: 3, + }, + GetPayloadBodyRequestByHashIndex{ + BlockNumbers: []uint64{ + 1, + 16, + 2, + 17, + }, + }, + GetPayloadBodyRequestByHashIndex{ // Existing+Random hashes + BlockNumbers: []uint64{ + 32, + 1000, + 31, + 1000, + 30, + 1000, + }, + }, + }, + }, + &GetPayloadBodiesSpec{ WithdrawalsBaseSpec: &WithdrawalsBaseSpec{ Spec: test.Spec{ @@ -1842,6 +1892,7 @@ type GetPayloadBodiesSpec struct { *WithdrawalsBaseSpec GetPayloadBodiesRequests []GetPayloadBodyRequest GenerateSidechain bool + AfterSync bool } type GetPayloadBodyRequest interface { @@ -1950,6 +2001,8 @@ func (ws *GetPayloadBodiesSpec) Execute(t *test.Env) { payloadHistory := t.CLMock.ExecutedPayloadHistory + testEngine := t.TestEngine + if ws.GenerateSidechain { // First generate an extra payload on top of the canonical chain @@ -1997,11 +2050,44 @@ func (ws *GetPayloadBodiesSpec) Execute(t *test.Env) { n1.ExpectStatus(test.Valid) n2 := t.TestEngine.TestEngineNewPayloadV2(sidechainHead) n2.ExpectStatus(test.Valid) + } else if ws.AfterSync { + // Spawn a secondary client which will need to sync to the primary client + secondaryEngine, err := hive_rpc.HiveRPCEngineStarter{}.StartClient(t.T, t.TestContext, t.Genesis, t.ClientParams, t.ClientFiles, t.Engine) + if err != nil { + t.Fatalf("FAIL (%s): Unable to spawn a secondary client: %v", t.TestName, err) + } + secondaryEngineTest := test.NewTestEngineClient(t, secondaryEngine) + t.CLMock.AddEngineClient(secondaryEngine) + + loop: + for { + select { + case <-t.TimeoutContext.Done(): + t.Fatalf("FAIL (%s): Timeout while waiting for secondary client to sync", t.TestName) + case <-time.After(time.Second): + secondaryEngineTest.TestEngineNewPayloadV2( + &t.CLMock.LatestExecutedPayload, + ) + r := secondaryEngineTest.TestEngineForkchoiceUpdatedV2( + &t.CLMock.LatestForkchoice, + nil, + ) + if r.Response.PayloadStatus.Status == test.Valid { + break loop + } + if r.Response.PayloadStatus.Status == test.Invalid { + t.Fatalf("FAIL (%s): Syncing client rejected valid chain: %s", t.TestName, r.Response) + } + } + } + + // GetPayloadBodies will be sent to the secondary client + testEngine = secondaryEngineTest } - // Now send the range request, which should ignore the sidechain + // Now send the range request, which should ignore any sidechain for _, req := range ws.GetPayloadBodiesRequests { - req.Verify(t.TestEngine, payloadHistory) + req.Verify(testEngine, payloadHistory) } }