Skip to content
Merged
Show file tree
Hide file tree
Changes from 181 commits
Commits
Show all changes
195 commits
Select commit Hold shift + click to select a range
ec4635c
feat: add blocksAndData testing utils
matthewkeil Aug 13, 2025
337d348
feat: add SeenBlockInputCache.getByColumn
matthewkeil Aug 13, 2025
004860a
feat: add downloadByRange.ts
matthewkeil Aug 13, 2025
b74691b
test: add tests for getByColumn and downloadByRange. need to get them…
matthewkeil Aug 13, 2025
8ef928b
wip: add roughed out downloadByRoot
matthewkeil Aug 13, 2025
6d374c9
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
wemeetagain Aug 14, 2025
1b6046d
chore: get src building
wemeetagain Aug 14, 2025
0be6543
chore: fix some test build issues
wemeetagain Aug 14, 2025
d7b5b66
chore: update chain processing
wemeetagain Aug 14, 2025
ec8727f
Revert "chore: fix some test build issues"
matthewkeil Aug 14, 2025
3b04598
chore: fix some build issues (reverts some of the details from previo…
matthewkeil Aug 14, 2025
a96efbf
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
wemeetagain Aug 15, 2025
c1bf66b
chore: fix up src/api
wemeetagain Aug 15, 2025
17846cb
chore: halfway thru gossip handlers
wemeetagain Aug 15, 2025
5bde098
fix: add fulu case to SeenBlockInput.getByBlock
matthewkeil Aug 15, 2025
4d97aaf
chore: finish updating gossip handlers
wemeetagain Aug 15, 2025
3fe3851
chore: remove stray function
wemeetagain Aug 15, 2025
60c66fe
feat: update how range sync Batch works
matthewkeil Aug 15, 2025
d664ce2
Merge branch 'mkeil/refactor-block-input-on-unstable' of github.com:C…
matthewkeil Aug 15, 2025
c6999c5
fix: logic errors in batch.getRequests
matthewkeil Aug 15, 2025
1448520
feat: update chain and range to use downloadByRoot and updated batch
matthewkeil Aug 16, 2025
6470907
feat: add throwOnDuplicateAdd to IBlockInput.addBlock
matthewkeil Aug 16, 2025
32adcd2
feat: add throwOnDuplicate option for blobs and columns
matthewkeil Aug 16, 2025
2a7b681
feat: rough out byRange caching
matthewkeil Aug 16, 2025
dfc11d4
refactor: remove beaconBlockMaybeBlobsByRange
matthewkeil Aug 18, 2025
aed92ef
refactor: remove beaconBlockMaybeBlobsByRoot
matthewkeil Aug 18, 2025
e3a093b
feat: switch "unknown*" event types from Network to Chain events
matthewkeil Aug 18, 2025
3358916
fix: type issue in SeenBlockInput
matthewkeil Aug 18, 2025
b116bfb
refactor: change name from UnknownBlock and options to BlockInputSync
matthewkeil Aug 18, 2025
f387cac
feat: add source to events data
matthewkeil Aug 18, 2025
021523c
fix: convert to new IBlockInput
matthewkeil Aug 18, 2025
5a450aa
fix: convert some BlockInput to IBlockInput for type safety in sync
matthewkeil Aug 18, 2025
97a5e6a
fix: remove old types that were used by UnknownBlock and move to new …
matthewkeil Aug 18, 2025
66672ef
fix: bug in Batch (add blocks back to state)
matthewkeil Aug 18, 2025
6b53b8e
fix: by range types to allow for batches that do not need blocks pulled
matthewkeil Aug 18, 2025
738e1fc
wip: start to update BlockInputSync and pendingBlocksTree
matthewkeil Aug 18, 2025
983cff0
refactor: rename unknownBlock.ts -> blockInputSync.ts
matthewkeil Aug 18, 2025
9380308
wip: more fixing up block input sync
wemeetagain Aug 19, 2025
ded5c6a
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
matthewkeil Aug 19, 2025
e48d21b
wip: get BlockInputSync class cleaned up after merging tuyen PR
matthewkeil Aug 20, 2025
e675be7
fix: types for UnknownBlockPeerBalancer
matthewkeil Aug 20, 2025
86aba63
chore: fix last build errors
wemeetagain Aug 20, 2025
821dd39
chore: move blockInput.ts to unknownBlock.ts
wemeetagain Aug 20, 2025
0f1b2a3
chore: clean up getUnknownAndAncestorBlocks
wemeetagain Aug 20, 2025
1c49e12
chore: fix getUnknownAndAncestorBlocks
wemeetagain Aug 20, 2025
edd7dc2
chore: another fix to getUnknownAndAncestorBlocks
wemeetagain Aug 20, 2025
bf70001
chore: fix up downloadBlock and processBlock
wemeetagain Aug 20, 2025
ed42752
chore: remove unused code in unknownBlock.ts
wemeetagain Aug 20, 2025
be7e3a1
chore: use sampledColumns vs sampledGroups
wemeetagain Aug 20, 2025
41b6193
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
wemeetagain Aug 20, 2025
b25ab64
feat: build out downloadByRoot
matthewkeil Aug 20, 2025
461f372
Merge branch 'mkeil/refactor-block-input-on-unstable' of github.com:C…
matthewkeil Aug 20, 2025
ab5b4d6
refactor: rename download to fetch
matthewkeil Aug 20, 2025
612af54
feat: update BlockInputCache to pass in blockRootHex instead of calcu…
matthewkeil Aug 20, 2025
43ec65f
fix: add caching to downloadByRoot and pass in executionEngine
matthewkeil Aug 20, 2025
dd819bc
chore: fix some of check-types
wemeetagain Aug 21, 2025
8a48222
chore: delete test
wemeetagain Aug 21, 2025
a1e3351
chore: remove old test files
wemeetagain Aug 21, 2025
511d9f6
feat: modify ColumnMeta to support getBlobsV2
matthewkeil Aug 21, 2025
57a7699
feat: make logger public on network
matthewkeil Aug 21, 2025
a7c69e5
feat: make getCellsAndProofs async
matthewkeil Aug 21, 2025
7265027
feat: add getBlobsV1 and V2 to downloadByRoot
matthewkeil Aug 21, 2025
4c248a3
test: rough out unit tests for downloadByRoot
matthewkeil Aug 22, 2025
cbda219
fix: debug blocksAndData test utils
matthewkeil Aug 25, 2025
93222b5
chore: fix some check-type errors
wemeetagain Aug 25, 2025
6603a16
test: partial testing of downloadByRoot with code changes from bugs f…
matthewkeil Aug 26, 2025
bff41ab
fix: rename dataAvailabilityStatus
matthewkeil Aug 26, 2025
68d5e83
Merge branch 'mkeil/refactor-block-input-on-unstable' of github.com:C…
matthewkeil Aug 26, 2025
0da2fc1
fix: type errors
matthewkeil Aug 26, 2025
d45f3e4
chore: lint
matthewkeil Aug 26, 2025
fa83ae1
test: rough out MockBlockInput for testing
matthewkeil Aug 26, 2025
c3adcf8
chore: fix check-types
matthewkeil Aug 26, 2025
efcdaa2
fix: update pendingBlocksTree.test for new BlockInput
matthewkeil Aug 27, 2025
1087c82
fix: check-types in blocksAndData test util
matthewkeil Aug 27, 2025
35883ba
chore: lint
matthewkeil Aug 27, 2025
8576a2b
test: unit testing downloadByRoot
matthewkeil Aug 27, 2025
9cf380b
test: testing fetchAndValidateBlobs
matthewkeil Aug 27, 2025
4b7a244
test: fetchAndValidateBlobs
matthewkeil Aug 27, 2025
2fa46f1
test: fetchAndValidateBlobs
matthewkeil Aug 27, 2025
29bc78b
test: fetchAndValidateColumns
matthewkeil Aug 27, 2025
46cfe6f
fix: clean up unused comments
matthewkeil Aug 27, 2025
7247a42
chore: fix up download by range
wemeetagain Aug 27, 2025
56742b1
chore: touch up batch states
wemeetagain Aug 27, 2025
4ba34a7
chore: more work on by range
wemeetagain Aug 27, 2025
d440a6a
chore: temporarily disable extra blobs check
wemeetagain Aug 27, 2025
8ac7c80
chore: update validate blobs input
wemeetagain Aug 27, 2025
92e97c8
chore: update vlaidate blobs input
wemeetagain Aug 27, 2025
836186e
fix: address spacing for @nflaig
matthewkeil Aug 28, 2025
11582b3
chore: fix some bugs
wemeetagain Aug 28, 2025
cd68138
chore: dedupe blobsRequestBlocks
wemeetagain Aug 28, 2025
6073afc
chore: improve log
wemeetagain Aug 28, 2025
fbe6919
chore: fix typo
wemeetagain Aug 28, 2025
d501655
chore: fix batch update when there are skip slots
wemeetagain Aug 28, 2025
218d997
chore: wip fix blob/column reqresp validation
wemeetagain Aug 28, 2025
97b9426
fix: wait for data before writing to db (#8291)
twoeths Aug 29, 2025
e66e36a
docs: add checklist docstring to downloadByRange
matthewkeil Aug 29, 2025
0cfc9e4
chore: refactor sidecar validation in by-range
wemeetagain Aug 29, 2025
01e6174
chore: fix column proof verification
wemeetagain Aug 29, 2025
1b7e37a
chore: fix up columns block input
wemeetagain Aug 29, 2025
6d225a2
chore: remove unnecessary sidecar validation step
wemeetagain Aug 31, 2025
adbcde8
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
matthewkeil Sep 1, 2025
f5b2f68
chore: remove unused validation fn, consolidate validation fn usage
wemeetagain Sep 1, 2025
43590a7
feat: downscore peers for sending range batches on wrong chain and us…
matthewkeil Sep 2, 2025
136e076
fix: put sorting of block in batch.downloadingSuccess
matthewkeil Sep 2, 2025
805a201
chore: simplify validation (use same validation functions everywhere)
wemeetagain Sep 2, 2025
8a9c8df
chore: fix an e2e test
wemeetagain Sep 2, 2025
d3000a8
chore: fix unit test
wemeetagain Sep 2, 2025
1097736
chore: fix another unit test
wemeetagain Sep 2, 2025
e191662
chore: fix more tests
wemeetagain Sep 2, 2025
1a43035
test: partial update of batch.test.ts
matthewkeil Sep 2, 2025
1b1134a
Merge branch 'mkeil/refactor-block-input-on-unstable' of github.com:C…
matthewkeil Sep 2, 2025
fbc7fcb
chore: fix more test
wemeetagain Sep 2, 2025
b9e4a62
feat: refactor downloadByRange.ts
matthewkeil Sep 2, 2025
604f0ca
feat: add AI analysis and unit test cases for downloadByRange
matthewkeil Sep 3, 2025
de11b44
fix: sort ascending
matthewkeil Sep 3, 2025
4d2ad9b
chore: downscore peers appropriately
wemeetagain Sep 3, 2025
89b9c7c
fix: debug test/utils/blocksAndData.ts
matthewkeil Sep 3, 2025
5ce5bb7
test: unit test getBlocksForDataValidation
matthewkeil Sep 3, 2025
ff687e3
chore: fix check-types
matthewkeil Sep 3, 2025
1fe1fce
chore: fix more tests
wemeetagain Sep 3, 2025
eb6379f
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
wemeetagain Sep 3, 2025
e2cf218
chore: lint
wemeetagain Sep 3, 2025
31407b0
chore: more cleanup
wemeetagain Sep 3, 2025
f30d9a2
chore: fix lint
wemeetagain Sep 3, 2025
3943b36
chore: add getBlobsV2 call to gossip block handler
wemeetagain Sep 3, 2025
be99499
chore: cleanup getDataColumnSidecarsFromExecution
wemeetagain Sep 3, 2025
45baecd
chore: apply #8282-ish solution
wemeetagain Sep 3, 2025
09f0044
chore: fetch data columns from execution upon data column sidecar
wemeetagain Sep 3, 2025
cc933e5
fix: throw on duplicate add (#8326)
twoeths Sep 5, 2025
9548fd5
fix: correct validateBlockDataColumnSidecars result mapping (#8328)
twoeths Sep 5, 2025
20292ec
fix: correct leveldb metrics (#8335)
twoeths Sep 5, 2025
49a3624
fix: handle full data BlockInput in downloadByRoot (#8339)
twoeths Sep 5, 2025
e338b69
fix: request columns by peer custodied columns (#8330)
twoeths Sep 5, 2025
4caea70
fix: remove getBlobs use during by root syncing (#8341)
wemeetagain Sep 5, 2025
03dc499
fix: allow for sparse blobs in blob validation (#8342)
wemeetagain Sep 5, 2025
92e477d
fix: new error code NOT_ENOUGH_SIDECARS_RECEIVED (#8351)
twoeths Sep 8, 2025
aabe8be
fix: resolve data promise for BlockInputPreData (#8299)
twoeths Sep 8, 2025
6351259
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
matthewkeil Sep 8, 2025
10dbede
docs: add TODO
matthewkeil Sep 8, 2025
423c77a
feat: only cache gossip block after validation
matthewkeil Sep 8, 2025
588c237
docs: update comments and add TODOs
matthewkeil Sep 8, 2025
1192618
refactor: dont create separate variable, use object prop
matthewkeil Sep 8, 2025
e257931
docs: add TODO
matthewkeil Sep 9, 2025
633d137
refactor: imports
matthewkeil Sep 9, 2025
5c3d888
fix: remove duplicate BlockInputCache
matthewkeil Sep 9, 2025
234c26f
feat: track DownloadByRoot errors on new metrics (#8352)
twoeths Sep 9, 2025
e9ab7a9
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
wemeetagain Sep 9, 2025
c1bea58
Merge branch 'mkeil/refactor-block-input-on-unstable' of github.com:C…
matthewkeil Sep 9, 2025
1737333
fix: build error
matthewkeil Sep 9, 2025
c884573
fix: build error
matthewkeil Sep 9, 2025
855bdbf
fix: prevent faulty by range EXTRA_COLUMNS error
wemeetagain Sep 9, 2025
143d184
feat: reimplement PR#7940 for column reconstruction
matthewkeil Sep 9, 2025
d482016
chore: lint and check-types
matthewkeil Sep 9, 2025
d119773
Merge branch 'mkeil/refactor-block-input-on-unstable' of github.com:C…
matthewkeil Sep 9, 2025
3b97226
feat: dont check for listener twice
matthewkeil Sep 9, 2025
cfe8ba2
feat: getLogMeta to print slot first
matthewkeil Sep 9, 2025
4804855
fix: dont destructure logMeta in debug call
matthewkeil Sep 9, 2025
02696de
fix: update log comment
matthewkeil Sep 9, 2025
92a992d
docs: add comment
matthewkeil Sep 9, 2025
7827f14
fix: replace extra validation check error with log statement
matthewkeil Sep 9, 2025
4f7d53c
feat: prune BlockInputs for ByRange
matthewkeil Sep 10, 2025
84c5895
feat: prune BlockInputs for ByRoot
matthewkeil Sep 10, 2025
2735565
Merge branch 'mkeil/refactor-block-input-on-unstable' of github.com:C…
matthewkeil Sep 10, 2025
07a214c
fix: build error. I love you TS!!!.... and i hate you but I love you!!!
matthewkeil Sep 10, 2025
d46bf59
feat: log number of pruned BlockInputs
matthewkeil Sep 10, 2025
1a7b1e4
chore: fix check-types
matthewkeil Sep 10, 2025
ee00704
fix: add blocks to all BatchState (#8369)
twoeths Sep 11, 2025
1d1fbe1
feat: track downloadByRange errors in metrics (#8372)
twoeths Sep 11, 2025
71269d3
fix: track getBlobsV2 calls via GetBlobsTracker (#8381)
wemeetagain Sep 11, 2025
369a160
feat: add imported columns by source metric (#8380)
wemeetagain Sep 11, 2025
83fcfec
fix: add valid request window check for each fork (#8379)
nazarhussain Sep 11, 2025
70d969e
feat: add gossip data column sidecar verification skip (#8382)
wemeetagain Sep 11, 2025
0dc23bf
feat: add ColumnReconstructionTracker (#8383)
wemeetagain Sep 11, 2025
dbe9b74
fix: wait until next event loop for getBlobsV2 (#8384)
wemeetagain Sep 11, 2025
f8e36f5
feat: relaxed data column response handler (#8387)
twoeths Sep 12, 2025
4e198eb
chore: fix unit tests (#8392)
wemeetagain Sep 12, 2025
b041e32
fix: pass testCaseName to spec testFunction to allow for case specifi…
matthewkeil Sep 15, 2025
d2b90db
fix: add default custody to test for unavailable peerDas data
matthewkeil Sep 15, 2025
d090d54
docs: add not to spec test about test case for future us to know what…
matthewkeil Sep 15, 2025
14a8ae3
docs: add note to spec test about test case for future us to know wha…
matthewkeil Sep 15, 2025
b829484
fix: e2e tests for blockinput refactor branch (#8394)
twoeths Sep 15, 2025
a6dd9e7
chore: review block input refactor (#8398)
nflaig Sep 15, 2025
4c73678
feat: get blobs v1 (#8399)
matthewkeil Sep 16, 2025
a767282
feat: add blockRoot to log entry
matthewkeil Sep 16, 2025
50c4a3d
docs: add missing comments to new ChainEvents
matthewkeil Sep 16, 2025
1b389d4
test: increase timeout on unknownBlockSync.test.ts
matthewkeil Sep 16, 2025
0223bb0
feat: audit versioned hashes (#8409)
matthewkeil Sep 16, 2025
103d854
Merge branch 'unstable' into mkeil/refactor-block-input-on-unstable
matthewkeil Sep 16, 2025
d10c4b8
Revert "test: increase timeout on unknownBlockSync.test.ts"
matthewkeil Sep 16, 2025
b2940b8
feat: track BlockInputSync result (#8416)
twoeths Sep 17, 2025
7a201b6
chore: add type annotations
wemeetagain Sep 17, 2025
e8fdc41
chore: add slot information to log messages (#8390)
nazarhussain Sep 17, 2025
0d70dde
fix: small fixes and e2e test fix (#8420)
wemeetagain Sep 18, 2025
b7e8237
feat: refine data column elapsedTimeTillReceived metric (#8423)
twoeths Sep 18, 2025
a0fb799
fix: DataColumSidecars recoverTime buckets (#8422)
twoeths Sep 18, 2025
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
118 changes: 55 additions & 63 deletions packages/beacon-node/src/api/impl/beacon/blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,11 @@ import {
sszTypesFor,
} from "@lodestar/types";
import {fromAsync, fromHex, sleep, toHex, toRootHex} from "@lodestar/utils";
import {
BlobsSource,
BlockInput,
BlockInputAvailableData,
BlockInputBlobs,
BlockInputDataColumns,
BlockInputType,
BlockSource,
DataColumnsSource,
ImportBlockOpts,
getBlockInput,
} from "../../../../chain/blocks/types.js";
import {BlockInputSource, isBlockInputBlobs, isBlockInputColumns} from "../../../../chain/blocks/blockInput/index.js";
import {ImportBlockOpts} from "../../../../chain/blocks/types.js";
import {verifyBlocksInEpoch} from "../../../../chain/blocks/verifyBlock.js";
import {BeaconChain} from "../../../../chain/chain.js";
import {ChainEvent} from "../../../../chain/emitter.js";
import {BlockError, BlockErrorCode, BlockGossipError} from "../../../../chain/errors/index.js";
import {
BlockType,
Expand All @@ -51,7 +42,6 @@ import {
} from "../../../../chain/produceBlock/index.js";
import {validateGossipBlock} from "../../../../chain/validation/block.js";
import {OpSource} from "../../../../chain/validatorMonitor.js";
import {NetworkEvent} from "../../../../network/index.js";
import {getBlobSidecars, kzgCommitmentToVersionedHash, reconstructBlobs} from "../../../../util/blobs.js";
import {getDataColumnSidecarsFromBlock} from "../../../../util/dataColumns.js";
import {isOptimisticBlock} from "../../../../util/forkChoice.js";
Expand Down Expand Up @@ -95,10 +85,15 @@ export function getBeaconBlockApi({
const fork = config.getForkName(slot);
const blockRoot = toRootHex(chain.config.getForkTypes(slot).BeaconBlock.hashTreeRoot(signedBlock.message));

let blockForImport: BlockInput, blobSidecars: deneb.BlobSidecars, dataColumnSidecars: fulu.DataColumnSidecars;
const blockForImport = chain.seenBlockInputCache.getByBlock({
block: signedBlock,
source: BlockInputSource.api,
seenTimestampSec,
blockRootHex: blockRoot,
});
let blobSidecars: deneb.BlobSidecars, dataColumnSidecars: fulu.DataColumnSidecars;

if (isDenebBlockContents(signedBlockContents)) {
let blockData: BlockInputAvailableData;
if (isForkPostFulu(fork)) {
const timer = metrics?.peerDas.dataColumnSidecarComputationTime.startTimer();
// If the block was produced by this node, we will already have computed cells
Expand All @@ -116,30 +111,32 @@ export function getBeaconBlockApi({
cellsAndProofs
);
timer?.();
blockData = {
fork,
dataColumns: dataColumnSidecars,
dataColumnsBytes: dataColumnSidecars.map(() => null),
dataColumnsSource: DataColumnsSource.api,
} as BlockInputDataColumns;
blobSidecars = [];
} else if (isForkPostDeneb(fork)) {
blobSidecars = getBlobSidecars(config, signedBlock, signedBlockContents.blobs, signedBlockContents.kzgProofs);
blockData = {
fork,
blobs: blobSidecars,
blobsSource: BlobsSource.api,
} as BlockInputBlobs;
dataColumnSidecars = [];
} else {
throw Error(`Invalid data fork=${fork} for publish`);
}

blockForImport = getBlockInput.availableData(config, signedBlock, BlockSource.api, blockData);
} else {
blobSidecars = [];
dataColumnSidecars = [];
blockForImport = getBlockInput.preData(config, signedBlock, BlockSource.api);
}

if (dataColumnSidecars.length > 0 && isBlockInputColumns(blockForImport)) {
for (const dataColumnSidecar of dataColumnSidecars) {
blockForImport.addColumn({
blockRootHex: blockRoot,
columnSidecar: dataColumnSidecar,
source: BlockInputSource.api,
seenTimestampSec,
});
}
}
if (blobSidecars.length > 0 && isBlockInputBlobs(blockForImport)) {
for (const blobSidecar of blobSidecars) {
blockForImport.addBlob({blockRootHex: blockRoot, blobSidecar, source: BlockInputSource.api, seenTimestampSec});
}
}

// check what validations have been requested before broadcasting and publishing the block
Expand Down Expand Up @@ -184,9 +181,10 @@ export function getBeaconBlockApi({
if (!blockLocallyProduced) {
const parentBlock = chain.forkChoice.getBlock(signedBlock.message.parentRoot);
if (parentBlock === null) {
network.events.emit(NetworkEvent.unknownBlockParent, {
chain.emitter.emit(ChainEvent.unknownParent, {
blockInput: blockForImport,
peer: IDENTITY_PEER_ID,
source: BlockInputSource.api,
});
chain.persistInvalidSszValue(
chain.config.getForkTypes(slot).SignedBeaconBlock,
Expand Down Expand Up @@ -247,18 +245,16 @@ export function getBeaconBlockApi({

// Simple implementation of a pending block queue. Keeping the block here recycles the API logic, and keeps the
// REST request promise without any extra infrastructure.
const msToBlockSlot =
computeTimeAtSlot(config, blockForImport.block.message.slot, chain.genesisTime) * 1000 - Date.now();
const msToBlockSlot = computeTimeAtSlot(config, slot, chain.genesisTime) * 1000 - Date.now();
if (msToBlockSlot <= MAX_API_CLOCK_DISPARITY_MS && msToBlockSlot > 0) {
// If block is a bit early, hold it in a promise. Equivalent to a pending queue.
await sleep(msToBlockSlot);
}

// TODO: Validate block
const delaySec =
seenTimestampSec - (chain.genesisTime + blockForImport.block.message.slot * config.SECONDS_PER_SLOT);
const delaySec = seenTimestampSec - (chain.genesisTime + slot * config.SECONDS_PER_SLOT);
metrics?.gossipBlock.elapsedTimeTillReceived.observe({source: OpSource.api}, delaySec);
chain.validatorMonitor?.registerBeaconBlock(OpSource.api, delaySec, blockForImport.block.message);
chain.validatorMonitor?.registerBeaconBlock(OpSource.api, delaySec, signedBlock.message);

chain.logger.info("Publishing block", valLogMeta);
const publishPromises = [
Expand All @@ -280,9 +276,10 @@ export function getBeaconBlockApi({
.processBlock(blockForImport, {...opts, eagerPersistBlock: false})
.catch((e) => {
if (e instanceof BlockError && e.type.code === BlockErrorCode.PARENT_UNKNOWN) {
network.events.emit(NetworkEvent.unknownBlockParent, {
chain.emitter.emit(ChainEvent.unknownParent, {
blockInput: blockForImport,
peer: IDENTITY_PEER_ID,
source: BlockInputSource.api,
});
}
throw e;
Expand Down Expand Up @@ -315,38 +312,33 @@ export function getBeaconBlockApi({

chain.emitter.emit(routes.events.EventType.blockGossip, {slot, block: blockRoot});

if (blockForImport.type === BlockInputType.availableData) {
if (isForkPostFulu(blockForImport.blockData.fork)) {
const {dataColumns} = blockForImport.blockData as BlockInputDataColumns;
metrics?.dataColumns.bySource.inc({source: DataColumnsSource.api}, dataColumns.length);

if (chain.emitter.listenerCount(routes.events.EventType.dataColumnSidecar)) {
for (const dataColumnSidecar of dataColumns) {
chain.emitter.emit(routes.events.EventType.dataColumnSidecar, {
blockRoot,
slot,
index: dataColumnSidecar.index,
kzgCommitments: dataColumnSidecar.kzgCommitments.map(toHex),
});
}
}
} else if (
isForkPostDeneb(blockForImport.blockData.fork) &&
chain.emitter.listenerCount(routes.events.EventType.blobSidecar)
) {
const {blobs} = blockForImport.blockData as BlockInputBlobs;

for (const blobSidecar of blobs) {
const {index, kzgCommitment} = blobSidecar;
chain.emitter.emit(routes.events.EventType.blobSidecar, {
if (isBlockInputColumns(blockForImport)) {
const dataColumns = blockForImport.getAllColumns();
metrics?.dataColumns.bySource.inc({source: BlockInputSource.api}, dataColumns.length);

if (chain.emitter.listenerCount(routes.events.EventType.dataColumnSidecar)) {
for (const dataColumnSidecar of dataColumns) {
chain.emitter.emit(routes.events.EventType.dataColumnSidecar, {
blockRoot,
slot,
index,
kzgCommitment: toHex(kzgCommitment),
versionedHash: toHex(kzgCommitmentToVersionedHash(kzgCommitment)),
index: dataColumnSidecar.index,
kzgCommitments: dataColumnSidecar.kzgCommitments.map(toHex),
});
}
}
} else if (isBlockInputBlobs(blockForImport) && chain.emitter.listenerCount(routes.events.EventType.blobSidecar)) {
const blobSidecars = blockForImport.getBlobs();

for (const blobSidecar of blobSidecars) {
const {index, kzgCommitment} = blobSidecar;
chain.emitter.emit(routes.events.EventType.blobSidecar, {
blockRoot,
slot,
index,
kzgCommitment: toHex(kzgCommitment),
versionedHash: toHex(kzgCommitmentToVersionedHash(kzgCommitment)),
});
}
}
};

Expand Down
2 changes: 1 addition & 1 deletion packages/beacon-node/src/api/impl/lodestar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export function getLodestarApi({
data: (chain as BeaconChain)["blockProcessor"].jobQueue.getItems().map((item) => {
const [blockInputs, opts] = item.args;
return {
blockSlots: blockInputs.map((blockInput) => blockInput.block.message.slot),
blockSlots: blockInputs.map((blockInput) => blockInput.slot),
jobOpts: opts,
addedTimeMs: item.addedTimeMs,
};
Expand Down
3 changes: 2 additions & 1 deletion packages/beacon-node/src/api/impl/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
toRootHex,
} from "@lodestar/utils";
import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator";
import {BlockInputSource} from "../../../chain/blocks/blockInput/types.js";
import {
AttestationError,
AttestationErrorCode,
Expand Down Expand Up @@ -978,7 +979,7 @@ export function getValidatorApi(
// see https://github.com/ChainSafe/lodestar/issues/5063
if (!chain.forkChoice.hasBlock(beaconBlockRoot)) {
const rootHex = toRootHex(beaconBlockRoot);
network.searchUnknownSlotRoot({slot, root: rootHex});
network.searchUnknownSlotRoot({slot, root: rootHex}, BlockInputSource.api);
// if result of this call is false, i.e. block hasn't seen after 1 slot then the below notOnOptimisticBlockRoot call will throw error
await chain.waitForBlock(slot, rootHex);
}
Expand Down
72 changes: 72 additions & 0 deletions packages/beacon-node/src/chain/ColumnReconstructionTracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {Logger, sleep} from "@lodestar/utils";
import {ChainEventEmitter} from "./emitter.js";
import {Metrics} from "../metrics/metrics.js";
import {ChainForkConfig} from "@lodestar/config";
import {BlockInputColumns} from "./blocks/blockInput/index.js";
import {recoverDataColumnSidecars} from "../util/dataColumns.js";

/**
* Minimum time to wait before attempting reconstruction
*/
const RECONSTRUCTION_DELAY_MIN_MS = 800;

/**
* Maximum time to wait before attempting reconstruction
*/
const RECONSTRUCTION_DELAY_MAX_MS = 1200;

export type ColumnReconstructionTrackerInit = {
logger: Logger;
emitter: ChainEventEmitter;
metrics: Metrics | null;
config: ChainForkConfig;
};

/**
* Tracks column reconstruction attempts to avoid duplicate and multiple in-flight calls
*/
export class ColumnReconstructionTracker {
logger: Logger;
emitter: ChainEventEmitter;
metrics: Metrics | null;
config: ChainForkConfig;

/**
* Track last attempted block root
*
* This is sufficient to avoid duplicate calls since we only call this
* function when we see a new data column sidecar from gossip.
*/
lastBlockRootHex: string | null = null;
/** Track if a reconstruction attempt is in-flight */
running = false;

constructor(init: ColumnReconstructionTrackerInit) {
this.logger = init.logger;
this.emitter = init.emitter;
this.metrics = init.metrics;
this.config = init.config;
}

triggerColumnReconstruction(blockInput: BlockInputColumns): void {
if (this.running) {
return;
}

if (this.lastBlockRootHex === blockInput.blockRootHex) {
return;
}

// We don't care about the outcome of this call,
// just that it has been triggered for this block root.
this.running = true;
this.lastBlockRootHex = blockInput.blockRootHex;
const delay =
RECONSTRUCTION_DELAY_MIN_MS + Math.random() * (RECONSTRUCTION_DELAY_MAX_MS - RECONSTRUCTION_DELAY_MIN_MS);
sleep(delay).then(() => {
recoverDataColumnSidecars(blockInput, this.emitter, this.metrics).finally(() => {
this.running = false;
});
});
}
}
75 changes: 75 additions & 0 deletions packages/beacon-node/src/chain/GetBlobsTracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {Logger} from "@lodestar/utils";
import {IExecutionEngine} from "../execution/index.js";
import {ChainEventEmitter} from "./emitter.js";
import {Metrics} from "../metrics/metrics.js";
import {ChainForkConfig} from "@lodestar/config";
import {IBlockInput} from "./blocks/blockInput/index.js";
import {getDataColumnSidecarsFromExecution} from "../util/execution.js";
import {callInNextEventLoop} from "../util/eventLoop.js";

export type GetBlobsTrackerInit = {
logger: Logger;
executionEngine: IExecutionEngine;
emitter: ChainEventEmitter;
metrics: Metrics | null;
config: ChainForkConfig;
};

/**
* Tracks getBlobsV2 calls to the execution engine to avoid duplicate and multiple in-flight calls
*/
export class GetBlobsTracker {
logger: Logger;
executionEngine: IExecutionEngine;
emitter: ChainEventEmitter;
metrics: Metrics | null;
config: ChainForkConfig;

/**
* Track last attempted block root
*
* This is sufficient to avoid duplicate calls since we only call this
* function when we see a new block or data column sidecar from gossip.
*/
lastBlockRootHex: string | null = null;
/** Track if a getBlobsV2 call is in-flight */
running = false;
// Preallocate buffers for getBlobsV2 RPC calls
// See https://github.com/ChainSafe/lodestar/pull/8282 for context
blobAndProofBuffers: Uint8Array[] = [];

constructor(init: GetBlobsTrackerInit) {
this.logger = init.logger;
this.executionEngine = init.executionEngine;
this.emitter = init.emitter;
this.metrics = init.metrics;
this.config = init.config;
}

triggerGetBlobs(blockInput: IBlockInput): void {
if (this.running) {
return;
}

if (this.lastBlockRootHex === blockInput.blockRootHex) {
return;
}

// We don't care about the outcome of this call,
// just that it has been triggered for this block root.
this.running = true;
this.lastBlockRootHex = blockInput.blockRootHex;
callInNextEventLoop(() => {
getDataColumnSidecarsFromExecution(
this.config,
this.executionEngine,
this.emitter,
blockInput,
this.metrics,
this.blobAndProofBuffers
).finally(() => {
this.running = false;
});
});
}
}
Loading
Loading