Skip to content

Commit dfb984e

Browse files
nflaigtwoeths
andauthored
test: fix unknownBlockSync e2e assertions for gloas (#9276)
We merged #9241 without actually checking if e2e test passed. --------- Co-authored-by: Tuyen Nguyen <twoeths@users.noreply.github.com>
1 parent 3847936 commit dfb984e

2 files changed

Lines changed: 51 additions & 30 deletions

File tree

packages/beacon-node/src/network/processor/gossipHandlers.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,10 +1060,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
10601060
const signedEnvelope = sszDeserialize(topic, serializedData);
10611061
const envelope = signedEnvelope.message;
10621062

1063-
// TODO GLOAS: consider optimistically create PayloadEnvelopeInput here similar to how we do that for beacon_block
1064-
// so that UnknownBlockSync can handle backward sync
1065-
// the problem now is we cannot create a PayloadEnvelopeInput without the beacon block being known, we need at least the proposer index
1066-
// we can achieve that by looking into the EpochCache
1063+
// unlike BlockInput, we send the envelope into UnknownBlockInput sync
1064+
// inside the sync it'll reconcile into PayloadEnvelopeInput and share the same cache with gossip
10671065
try {
10681066
await validateGossipExecutionPayloadEnvelope(chain, signedEnvelope);
10691067
} catch (e) {
@@ -1072,7 +1070,6 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
10721070
const slot = signedEnvelope.message.payload.slotNumber;
10731071
logger.debug("Gossip envelope has error", {slot, root: toRootHex(beaconBlockRoot), code: e.type.code});
10741072
if (e.type.code === ExecutionPayloadEnvelopeErrorCode.BLOCK_ROOT_UNKNOWN) {
1075-
// TODO GLOAS: UnknownBlockSync to handle this
10761073
chain.emitter.emit(ChainEvent.envelopeUnknownBlock, {
10771074
envelope: signedEnvelope,
10781075
peer: peerIdStr,

packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,40 @@ describe("sync / unknown block sync thru gloas", () => {
4848
}
4949
});
5050

51-
const testCases: {id: string; event: ChainEvent}[] = [
51+
const testCases: {id: string; event: ChainEvent; expectsPayloadImport: boolean}[] = [
5252
{
5353
id: "should do an unknown block parent sync from another BN",
5454
event: ChainEvent.blockUnknownParent,
55+
expectsPayloadImport: false,
5556
},
5657
{
5758
id: "should do an unknown block sync from another BN",
5859
event: ChainEvent.unknownBlockRoot,
60+
expectsPayloadImport: false,
5961
},
6062
{
6163
id: "should do an incompleteBlockInput sync from another BN",
6264
event: ChainEvent.incompleteBlockInput,
65+
expectsPayloadImport: false,
6366
},
6467
{
6568
id: "should do an unknownEnvelopeBlockRoot sync from another BN",
6669
event: ChainEvent.unknownEnvelopeBlockRoot,
70+
expectsPayloadImport: true,
71+
},
72+
{
73+
id: "should do an envelopeUnknownBlock sync from another BN",
74+
event: ChainEvent.envelopeUnknownBlock,
75+
expectsPayloadImport: true,
6776
},
6877
{
6978
id: "should do an incompletePayloadEnvelope sync from another BN",
7079
event: ChainEvent.incompletePayloadEnvelope,
80+
expectsPayloadImport: true,
7181
},
7282
];
7383

74-
for (const {id, event} of testCases) {
84+
for (const {id, event, expectsPayloadImport} of testCases) {
7585
it(id, async () => {
7686
// the node needs time to transpile/initialize bls worker threads
7787
const genesisSlotsDelay = 4;
@@ -158,15 +168,6 @@ describe("sync / unknown block sync thru gloas", () => {
158168
100000,
159169
({block}) => block === headRootHex
160170
);
161-
const maybeWaitForPayloadImported =
162-
event === ChainEvent.unknownEnvelopeBlockRoot || event === ChainEvent.incompletePayloadEnvelope
163-
? Promise.resolve()
164-
: waitForEvent<routes.events.EventData[routes.events.EventType.executionPayload]>(
165-
bn2.chain.emitter,
166-
routes.events.EventType.executionPayload,
167-
100000,
168-
({blockRoot}) => blockRoot === headRootHex
169-
);
170171

171172
const connected = Promise.all([onPeerConnect(bn2.network), onPeerConnect(bn.network)]);
172173
await connect(bn2.network, bn.network);
@@ -182,6 +183,15 @@ describe("sync / unknown block sync thru gloas", () => {
182183
forkName: bn.chain.config.getForkName(headSlot),
183184
daOutOfRange: false,
184185
});
186+
const waitForPayloadImported = expectsPayloadImport
187+
? waitForEvent<routes.events.EventData[routes.events.EventType.executionPayload]>(
188+
bn2.chain.emitter,
189+
routes.events.EventType.executionPayload,
190+
100000,
191+
({blockRoot}) => blockRoot === headRootHex
192+
)
193+
: undefined;
194+
185195
switch (event) {
186196
case ChainEvent.blockUnknownParent:
187197
await bn2.chain.processBlock(headInput).catch((e) => {
@@ -222,6 +232,20 @@ describe("sync / unknown block sync thru gloas", () => {
222232
source: BlockInputSource.gossip,
223233
});
224234
break;
235+
case ChainEvent.envelopeUnknownBlock: {
236+
// Node A produced the head; its cache has the full signed envelope (populated via
237+
// publishExecutionPayloadEnvelope -> payloadInput.addPayloadEnvelope).
238+
const payloadInputOnA = bn.chain.seenPayloadEnvelopeInputCache.get(headRootHex);
239+
if (!payloadInputOnA?.hasPayloadEnvelope()) {
240+
throw Error(`Expected node A to have signed envelope for ${headRootHex}`);
241+
}
242+
bn2.chain.emitter.emit(ChainEvent.envelopeUnknownBlock, {
243+
envelope: payloadInputOnA.getPayloadEnvelope(),
244+
peer: sourcePeerId,
245+
source: BlockInputSource.gossip,
246+
});
247+
break;
248+
}
225249
case ChainEvent.incompletePayloadEnvelope: {
226250
// get the chain started with an unknownBlockRoot
227251
bn2.chain.emitter.emit(ChainEvent.unknownBlockRoot, {
@@ -235,22 +259,19 @@ describe("sync / unknown block sync thru gloas", () => {
235259
throw Error("Unknown event type");
236260
}
237261

238-
// Wait for the block root to be processed in node B. Payload-aware entrypoints should also import
239-
// the separated payload envelope for the same root.
262+
// Wait for the block root to be processed in node B. The unknown-block-sync flow imports
263+
// parent payloads as needed to satisfy sanity checks but does not fetch the head block's
264+
// own payload envelope (which would normally arrive via gossip on a live network).
240265
await waitForSynced;
241266

242267
switch (event) {
243268
case ChainEvent.incompletePayloadEnvelope: {
244-
// After it syncs, send an incomplete payload envelope
245-
// and assert the payload gets imported
246-
const payloadInput = bn2.chain.seenPayloadEnvelopeInputCache.add({
247-
blockRootHex: headRootHex,
248-
forkName: bn2.config.getForkName(headSlot),
249-
block: head,
250-
sampledColumns: bn2.chain.custodyConfig.sampledColumns,
251-
custodyColumns: bn2.chain.custodyConfig.custodyColumns,
252-
timeCreatedSec: Math.floor(Date.now() / 1000),
253-
});
269+
// After it syncs, retrieve the PayloadEnvelopeInput created during block import
270+
// and emit incompletePayloadEnvelope to exercise the sync handler.
271+
const payloadInput = bn2.chain.seenPayloadEnvelopeInputCache.get(headRootHex);
272+
if (!payloadInput) {
273+
throw Error(`Expected PayloadEnvelopeInput for ${headRootHex} after block sync`);
274+
}
254275
bn2.chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
255276
payloadInput,
256277
peer: sourcePeerId,
@@ -262,8 +283,11 @@ describe("sync / unknown block sync thru gloas", () => {
262283
break;
263284
}
264285

265-
// only await payload import for events that imply importing it
266-
await maybeWaitForPayloadImported;
286+
// for incompletePayloadEnvelope the trigger is in the second switch above
287+
// so we have to assert payload import at the end
288+
if (waitForPayloadImported) {
289+
await waitForPayloadImported;
290+
}
267291
});
268292
}
269293
});

0 commit comments

Comments
 (0)