diff --git a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts index 69c7dedfc560..ad0ac0ff2c6b 100644 --- a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts +++ b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts @@ -59,8 +59,8 @@ export async function archiveBlocks( }); if (finalizedPostDeneb) { - await migrateBlobSidecarsFromHotToColdDb(config, db, finalizedCanonicalBlockRoots); - logger.verbose("Migrated blobSidecars from hot DB to cold DB"); + const migrate = await migrateBlobSidecarsFromHotToColdDb(config, db, finalizedCanonicalBlockRoots, currentEpoch); + logger.verbose(migrate ? "Migrated blobSidecars from hot DB to cold DB" : "Skip blobSidecars migration"); } } @@ -157,22 +157,36 @@ async function migrateBlocksFromHotToColdDb(db: IBeaconDb, blocks: BlockRootSlot } } +/** + * Migrate blobSidecars from hot db to cold db. + * @returns true if we do that, false if block is out of range data. + */ async function migrateBlobSidecarsFromHotToColdDb( config: ChainForkConfig, db: IBeaconDb, - blocks: BlockRootSlot[] -): Promise { + blocks: BlockRootSlot[], + currentEpoch: Epoch +): Promise { + let result = false; + for (let i = 0; i < blocks.length; i += BLOB_SIDECAR_BATCH_SIZE) { const toIdx = Math.min(i + BLOB_SIDECAR_BATCH_SIZE, blocks.length); const canonicalBlocks = blocks.slice(i, toIdx); // processCanonicalBlocks - if (canonicalBlocks.length === 0) return; + if (canonicalBlocks.length === 0) return false; // load Buffer instead of ssz deserialized to improve performance const canonicalBlobSidecarsEntries: KeyValue[] = await Promise.all( canonicalBlocks - .filter((block) => config.getForkSeq(block.slot) >= ForkSeq.deneb) + .filter((block) => { + const blockSlot = block.slot; + const blockEpoch = computeEpochAtSlot(blockSlot); + return ( + config.getForkSeq(blockSlot) >= ForkSeq.deneb && + blockEpoch >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS + ); + }) .map(async (block) => { const bytes = await db.blobSidecars.getBinary(block.root); if (!bytes) { @@ -182,12 +196,20 @@ async function migrateBlobSidecarsFromHotToColdDb( }) ); - // put to blockArchive db and delete block db - await Promise.all([ - db.blobSidecarsArchive.batchPutBinary(canonicalBlobSidecarsEntries), - db.blobSidecars.batchDelete(canonicalBlocks.map((block) => block.root)), - ]); + const migrate = canonicalBlobSidecarsEntries.length > 0; + + if (migrate) { + // put to blockArchive db and delete block db + await Promise.all([ + db.blobSidecarsArchive.batchPutBinary(canonicalBlobSidecarsEntries), + db.blobSidecars.batchDelete(canonicalBlocks.map((block) => block.root)), + ]); + } + + result = result || migrate; } + + return result; } /** diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index 21d781f11437..d19a7867d873 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -36,8 +36,9 @@ export async function beaconBlocksMaybeBlobsByRange( return blocks.map((block) => getBlockInput.preData(config, block.data, BlockSource.byRange, block.bytes)); } + // From Deneb // Only request blobs if they are recent enough - if (computeEpochAtSlot(startSlot) >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { + if (startEpoch >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { const [allBlocks, allBlobSidecars] = await Promise.all([ network.sendBeaconBlocksByRange(peerId, request), network.sendBlobSidecarsByRange(peerId, request), @@ -46,8 +47,9 @@ export async function beaconBlocksMaybeBlobsByRange( return matchBlockWithBlobs(config, allBlocks, allBlobSidecars, endSlot, BlockSource.byRange, BlobsSource.byRange); } - // Post Deneb but old blobs - throw Error("Cannot sync blobs outside of blobs prune window"); + // Data is out of range, only request blocks + const blocks = await network.sendBeaconBlocksByRange(peerId, request); + return blocks.map((block) => getBlockInput.outOfRangeData(config, block.data, BlockSource.byRange, block.bytes)); } // Assumes that the blobs are in the same sequence as blocks, doesn't require block to be sorted