Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {ForkName, ForkSeq} from "@lodestar/params";
import {SlotOptionalRoot, SlotRootHex} from "@lodestar/types";
import {
getBeaconBlockRootFromDataColumnSidecarSerialized,
getBeaconBlockRootFromFuluDataColumnSidecarSerialized,
getBlockRootFromBeaconAttestationSerialized,
getBlockRootFromPayloadAttestationMessageSerialized,
getBlockRootFromSignedAggregateAndProofSerialized,
Expand Down Expand Up @@ -65,7 +66,8 @@ export function createExtractBlockSlotRootFns(): ExtractSlotRootFns {
}

if (ForkSeq[fork] < ForkSeq.gloas) {
return {slot};
const root = getBeaconBlockRootFromFuluDataColumnSidecarSerialized(data);
return root !== null ? {slot, root} : {slot};
}

const root = getBeaconBlockRootFromDataColumnSidecarSerialized(data);
Expand Down
6 changes: 6 additions & 0 deletions packages/beacon-node/src/network/processor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,12 @@ export class NetworkProcessor {
preprocessResult = {action: PreprocessAction.PushToQueue};
}

if (topicType === GossipType.data_column_sidecar && ForkSeq[fork] < ForkSeq.gloas) {
// Fulu sidecar validation only needs the parent block/state, not the block referenced by the sidecar itself.
// Trigger unknown block sync above, but continue validation without waiting for the full block.
preprocessResult = {action: PreprocessAction.PushToQueue};
}

if (ForkSeq[fork] >= ForkSeq.gloas) {
// specific check for each topic
// note that it's supposed to NOT queue beacon_block (handled above) and execution_payload because it's not a one-off;
Expand Down
21 changes: 21 additions & 0 deletions packages/beacon-node/src/util/sszBytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ export function getSlotFromBlobSidecarSerialized(data: Uint8Array): Slot | null
const SLOT_BYTES_POSITION_IN_SIGNED_DATA_COLUMN_SIDECAR_PRE_GLOAS = 20;
const SLOT_BYTES_POSITION_IN_SIGNED_DATA_COLUMN_SIDECAR_POST_GLOAS = 16;
const BEACON_BLOCK_ROOT_POSITION_IN_GLOAS_DATA_COLUMN_SIDECAR = 24;
const BEACON_BLOCK_HEADER_SIZE = SLOT_SIZE + 8 + ROOT_SIZE + ROOT_SIZE + ROOT_SIZE;

export function getSlotFromDataColumnSidecarSerialized(data: Uint8Array, fork: ForkName): Slot | null {
const offset = isForkPostGloas(fork)
Expand Down Expand Up @@ -551,6 +552,26 @@ export function getBeaconBlockRootFromDataColumnSidecarSerialized(data: Uint8Arr
return "0x" + blockRootBuf.toString("hex");
}

export function getBeaconBlockRootFromFuluDataColumnSidecarSerialized(data: Uint8Array): RootHex | null {
if (data.length < SLOT_BYTES_POSITION_IN_SIGNED_DATA_COLUMN_SIDECAR_PRE_GLOAS + BEACON_BLOCK_HEADER_SIZE) {
return null;
}

try {
const blockHeader = ssz.phase0.BeaconBlockHeader.deserialize(
data.subarray(
SLOT_BYTES_POSITION_IN_SIGNED_DATA_COLUMN_SIDECAR_PRE_GLOAS,
SLOT_BYTES_POSITION_IN_SIGNED_DATA_COLUMN_SIDECAR_PRE_GLOAS + BEACON_BLOCK_HEADER_SIZE
)
);
const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader);
blockRootBuf.set(blockRoot);
return `0x${blockRootBuf.toString("hex")}`;
} catch {
return null;
}
}

/**
* SignedExecutionPayloadEnvelope SSZ Layout:
* ├─ 4 bytes: message offset (points to byte 100)
Expand Down
30 changes: 29 additions & 1 deletion packages/beacon-node/test/unit/util/sszBytes.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {describe, expect, it} from "vitest";
import {describe, expect, it, vi} from "vitest";
import {BitArray} from "@chainsafe/ssz";
import {createChainForkConfig} from "@lodestar/config";
import {ForkName, MAX_COMMITTEES_PER_SLOT} from "@lodestar/params";
Expand Down Expand Up @@ -29,6 +29,7 @@ import {
getAttesterIndexFromSingleAttestationSerialized,
getBeaconBlockRootFromDataColumnSidecarSerialized,
getBeaconBlockRootFromExecutionPayloadEnvelopeSerialized,
getBeaconBlockRootFromFuluDataColumnSidecarSerialized,
getBlobKzgCommitmentsCountFromSignedBeaconBlockSerialized,
getBlockRootFromAttestationSerialized,
getBlockRootFromPayloadAttestationMessageSerialized,
Expand Down Expand Up @@ -57,6 +58,7 @@ import {
getSlotFromSignedExecutionPayloadBidSerialized,
getSlotFromSingleAttestationSerialized,
} from "../../../src/util/sszBytes.js";
import {generateBlockWithColumnSidecars} from "../../utils/blocksAndData.js";
import {generateRandomBlob} from "../../utils/kzg.js";

describe("SinlgeAttestation SSZ serialized picking", () => {
Expand Down Expand Up @@ -611,13 +613,39 @@ describe("DataColumnSidecar SSZ serialized picking (fork-aware)", () => {
});
}

it("getBeaconBlockRootFromFuluDataColumnSidecarSerialized", () => {
const {columnSidecars, rootHex} = generateBlockWithColumnSidecars({forkName: ForkName.fulu});
const bytes = ssz.fulu.DataColumnSidecar.serialize(columnSidecars[0]);

expect(getBeaconBlockRootFromFuluDataColumnSidecarSerialized(bytes)).toBe(rootHex);
});

it("getSlotFromDataColumnSidecarSerialized - invalid data", () => {
// Slot is at offset 20 for pre-Gloas, need at least 28 bytes
const invalidSizes = [0, 10, 27];
for (const size of invalidSizes) {
expect(getSlotFromDataColumnSidecarSerialized(Buffer.alloc(size), ForkName.fulu)).toBeNull();
}
});

it("getBeaconBlockRootFromFuluDataColumnSidecarSerialized - invalid data", () => {
const invalidSizes = [0, 20, 131];
for (const size of invalidSizes) {
expect(getBeaconBlockRootFromFuluDataColumnSidecarSerialized(Buffer.alloc(size))).toBeNull();
}
});

it("getBeaconBlockRootFromFuluDataColumnSidecarSerialized - returns null if header parsing throws", () => {
const {columnSidecars} = generateBlockWithColumnSidecars({forkName: ForkName.fulu});
const bytes = ssz.fulu.DataColumnSidecar.serialize(columnSidecars[0]);
const deserializeSpy = vi.spyOn(ssz.phase0.BeaconBlockHeader, "deserialize").mockImplementation(() => {
throw new Error();
});

expect(getBeaconBlockRootFromFuluDataColumnSidecarSerialized(bytes)).toBeNull();

deserializeSpy.mockRestore();
});
});

describe("Gloas", () => {
Expand Down
Loading