@lodestar/beacon-node 1.48.0-dev.baa28132d2 → 1.48.0-dev.bb3ffba9e9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +4 -4
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +39 -39
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +1 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +1 -0
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -0
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.js +12 -1
- package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.d.ts +2 -0
- package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js +4 -1
- package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +31 -34
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +0 -13
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +3 -2
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +10 -1
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.js +9 -16
- package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
- package/lib/chain/chain.d.ts +9 -3
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +127 -73
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +1 -1
- package/lib/chain/emitter.js +1 -1
- package/lib/chain/errors/blockError.d.ts +19 -7
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -2
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.d.ts +15 -2
- package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +10 -11
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +0 -2
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +13 -13
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +46 -64
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +35 -54
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +38 -13
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +10 -29
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +7 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +22 -5
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/db/beacon.d.ts +14 -5
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +17 -3
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/dataColumnStore.d.ts +39 -0
- package/lib/db/dataColumnStore.d.ts.map +1 -0
- package/lib/db/dataColumnStore.js +81 -0
- package/lib/db/dataColumnStore.js.map +1 -0
- package/lib/db/flatFileStore/atomicWrite.d.ts +8 -0
- package/lib/db/flatFileStore/atomicWrite.d.ts.map +1 -0
- package/lib/db/flatFileStore/atomicWrite.js +61 -0
- package/lib/db/flatFileStore/atomicWrite.js.map +1 -0
- package/lib/db/flatFileStore/dcolFormat.d.ts +90 -0
- package/lib/db/flatFileStore/dcolFormat.d.ts.map +1 -0
- package/lib/db/flatFileStore/dcolFormat.js +286 -0
- package/lib/db/flatFileStore/dcolFormat.js.map +1 -0
- package/lib/db/flatFileStore/errors.d.ts +82 -0
- package/lib/db/flatFileStore/errors.d.ts.map +1 -0
- package/lib/db/flatFileStore/errors.js +32 -0
- package/lib/db/flatFileStore/errors.js.map +1 -0
- package/lib/db/flatFileStore/flatFileStore.d.ts +41 -0
- package/lib/db/flatFileStore/flatFileStore.d.ts.map +1 -0
- package/lib/db/flatFileStore/flatFileStore.js +251 -0
- package/lib/db/flatFileStore/flatFileStore.js.map +1 -0
- package/lib/db/flatFileStore/index.d.ts +4 -0
- package/lib/db/flatFileStore/index.d.ts.map +1 -0
- package/lib/db/flatFileStore/index.js +2 -0
- package/lib/db/flatFileStore/index.js.map +1 -0
- package/lib/db/flatFileStore/interface.d.ts +25 -0
- package/lib/db/flatFileStore/interface.d.ts.map +1 -0
- package/lib/db/flatFileStore/interface.js +2 -0
- package/lib/db/flatFileStore/interface.js.map +1 -0
- package/lib/db/flatFileStore/metrics.d.ts +24 -0
- package/lib/db/flatFileStore/metrics.d.ts.map +1 -0
- package/lib/db/flatFileStore/metrics.js +25 -0
- package/lib/db/flatFileStore/metrics.js.map +1 -0
- package/lib/db/flatFileStore/path.d.ts +9 -0
- package/lib/db/flatFileStore/path.d.ts.map +1 -0
- package/lib/db/flatFileStore/path.js +21 -0
- package/lib/db/flatFileStore/path.js.map +1 -0
- package/lib/db/flatFileStore/slotIndex.d.ts +14 -0
- package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -0
- package/lib/db/flatFileStore/slotIndex.js +46 -0
- package/lib/db/flatFileStore/slotIndex.js.map +1 -0
- package/lib/db/flatFileStore/snappy.d.ts +3 -0
- package/lib/db/flatFileStore/snappy.d.ts.map +1 -0
- package/lib/db/flatFileStore/snappy.js +12 -0
- package/lib/db/flatFileStore/snappy.js.map +1 -0
- package/lib/db/index.d.ts +1 -0
- package/lib/db/index.d.ts.map +1 -1
- package/lib/db/interface.d.ts +8 -1
- package/lib/db/interface.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.d.ts +8 -1
- package/lib/db/repositories/blockArchive.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.js +65 -28
- package/lib/db/repositories/blockArchive.js.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.d.ts +1 -2
- package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.js +3 -7
- package/lib/db/repositories/blockArchiveIndex.js.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +4 -1
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +18 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +55 -1
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/monitoring/clientStats.js +1 -1
- package/lib/monitoring/clientStats.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +0 -7
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +2 -1
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +4 -20
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +6 -7
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/index.d.ts +49 -3
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +232 -98
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +112 -91
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +2 -0
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/protocols.d.ts.map +1 -1
- package/lib/network/reqresp/protocols.js +6 -22
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/network/reqresp/rateLimit.js +2 -1
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts +2 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js +14 -9
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/lib/node/nodejs.d.ts +2 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +4 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/util/sszBytes.d.ts +6 -0
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +1 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +18 -19
- package/src/api/impl/beacon/blocks/index.ts +8 -4
- package/src/api/impl/validator/index.ts +44 -43
- package/src/chain/archiveStore/archiveStore.ts +6 -1
- package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -0
- package/src/chain/archiveStore/historicalState/metrics.ts +14 -1
- package/src/chain/archiveStore/historicalState/types.ts +2 -0
- package/src/chain/archiveStore/historicalState/worker.ts +4 -1
- package/src/chain/archiveStore/utils/archiveBlocks.ts +34 -39
- package/src/chain/blocks/importBlock.ts +0 -13
- package/src/chain/blocks/index.ts +13 -2
- package/src/chain/blocks/utils/chainSegment.ts +10 -1
- package/src/chain/blocks/writeBlockInputToDb.ts +10 -17
- package/src/chain/chain.ts +149 -80
- package/src/chain/emitter.ts +1 -1
- package/src/chain/errors/blockError.ts +22 -10
- package/src/chain/errors/dataColumnSidecarError.ts +24 -8
- package/src/chain/errors/executionPayloadEnvelope.ts +14 -11
- package/src/chain/interface.ts +2 -2
- package/src/chain/prepareNextSlot.ts +16 -16
- package/src/chain/produceBlock/produceBlockBody.ts +50 -71
- package/src/chain/validation/block.ts +35 -70
- package/src/chain/validation/dataColumnSidecar.ts +47 -14
- package/src/chain/validation/executionPayloadEnvelope.ts +10 -37
- package/src/chain/validatorMonitor.ts +24 -7
- package/src/db/beacon.ts +33 -6
- package/src/db/dataColumnStore.ts +113 -0
- package/src/db/flatFileStore/atomicWrite.ts +65 -0
- package/src/db/flatFileStore/dcolFormat.ts +389 -0
- package/src/db/flatFileStore/errors.ts +53 -0
- package/src/db/flatFileStore/flatFileStore.ts +310 -0
- package/src/db/flatFileStore/index.ts +3 -0
- package/src/db/flatFileStore/interface.ts +21 -0
- package/src/db/flatFileStore/metrics.ts +48 -0
- package/src/db/flatFileStore/path.ts +32 -0
- package/src/db/flatFileStore/slotIndex.ts +56 -0
- package/src/db/flatFileStore/snappy.ts +14 -0
- package/src/db/index.ts +1 -0
- package/src/db/interface.ts +9 -1
- package/src/db/repositories/blockArchive.ts +89 -30
- package/src/db/repositories/blockArchiveIndex.ts +4 -9
- package/src/execution/engine/mock.ts +4 -1
- package/src/metrics/metrics/lodestar.ts +57 -1
- package/src/monitoring/clientStats.ts +1 -1
- package/src/network/gossip/encoding.ts +0 -7
- package/src/network/gossip/topic.ts +3 -25
- package/src/network/processor/gossipHandlers.ts +11 -11
- package/src/network/processor/index.ts +263 -148
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +139 -105
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +2 -0
- package/src/network/reqresp/protocols.ts +7 -24
- package/src/network/reqresp/rateLimit.ts +2 -1
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +15 -7
- package/src/node/nodejs.ts +6 -1
- package/src/util/sszBytes.ts +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {PeerId} from "@libp2p/interface";
|
|
2
2
|
import {ChainConfig} from "@lodestar/config";
|
|
3
3
|
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
4
|
-
import {ForkSeq, GENESIS_SLOT} from "@lodestar/params";
|
|
4
|
+
import {ForkSeq, GENESIS_SLOT, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
5
5
|
import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp";
|
|
6
6
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
7
|
-
import {ColumnIndex, Epoch, fulu} from "@lodestar/types";
|
|
8
|
-
import {fromHex} from "@lodestar/utils";
|
|
7
|
+
import {ColumnIndex, Epoch, RootHex, fulu} from "@lodestar/types";
|
|
8
|
+
import {fromHex, toRootHex} from "@lodestar/utils";
|
|
9
9
|
import {IBeaconChain} from "../../../chain/index.js";
|
|
10
10
|
import {IBeaconDb} from "../../../db/index.js";
|
|
11
11
|
import {prettyPrintPeerId} from "../../util.js";
|
|
@@ -50,121 +50,155 @@ export async function* onDataColumnSidecarsByRange(
|
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
const finalized = db.dataColumnSidecarArchive;
|
|
54
53
|
const finalizedSlot = chain.forkChoice.getFinalizedBlock().slot;
|
|
55
|
-
//
|
|
56
|
-
// -
|
|
57
|
-
// - Post-gloas: stay in the hot db (db.dataColumnSidecar) until the next finalization run,
|
|
58
|
-
// because the migration filter requires payloadStatus === FULL for gloas blocks.
|
|
59
|
-
// archiveMaxSlot is the last slot whose columns are served by the archive loop below;
|
|
60
|
-
// anything above it is served by the headChain loop.
|
|
54
|
+
// At Gloas, finalizing the beacon block does not finalize its payload. Keep the boundary block in the
|
|
55
|
+
// fork-choice-backed section until the following finalization, matching ExecutionPayloadEnvelopesByRange.
|
|
61
56
|
const isPostGloasFinalized = chain.config.getForkSeq(finalizedSlot) >= ForkSeq.gloas;
|
|
62
57
|
const archiveMaxSlot = isPostGloasFinalized ? finalizedSlot - 1 : finalizedSlot;
|
|
58
|
+
const headBlock = chain.forkChoice.getHead();
|
|
59
|
+
const headChain = chain.forkChoice.getAllAncestorBlocks(headBlock.blockRoot, headBlock.payloadStatus);
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
61
|
+
for await (const block of resolveCanonicalDataColumnBlocks(
|
|
62
|
+
chain,
|
|
63
|
+
db,
|
|
64
|
+
headChain,
|
|
65
|
+
startSlot,
|
|
66
|
+
endSlot,
|
|
67
|
+
archiveMaxSlot,
|
|
68
|
+
finalizedSlot
|
|
69
|
+
)) {
|
|
70
|
+
const dataColumnSidecars =
|
|
71
|
+
block.blockRoot === null
|
|
72
|
+
? await db.dataColumnSidecarArchive.getManyBinary(block.slot, availableColumns)
|
|
73
|
+
: await chain.getSerializedDataColumnSidecars(block.slot, block.blockRoot, availableColumns);
|
|
74
|
+
if (block.blockRoot === null && dataColumnSidecars.every((sidecar) => sidecar === undefined)) continue;
|
|
75
|
+
const unavailableColumnIndices: ColumnIndex[] = [];
|
|
76
|
+
for (let i = 0; i < dataColumnSidecars.length; i++) {
|
|
77
|
+
const dataColumnSidecarBytes = dataColumnSidecars[i];
|
|
78
|
+
if (dataColumnSidecarBytes) {
|
|
79
|
+
yield {
|
|
80
|
+
data: dataColumnSidecarBytes,
|
|
81
|
+
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(block.slot)),
|
|
82
|
+
};
|
|
83
|
+
} else {
|
|
84
|
+
unavailableColumnIndices.push(availableColumns[i]);
|
|
85
85
|
}
|
|
86
|
+
}
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
88
|
+
if (unavailableColumnIndices.length > 0) {
|
|
89
|
+
await handleColumnSidecarUnavailability({
|
|
90
|
+
chain,
|
|
91
|
+
db,
|
|
92
|
+
metrics: chain.metrics,
|
|
93
|
+
unavailableColumnIndices,
|
|
94
|
+
blockRoot: block.unavailabilityBlockRoot ? fromHex(block.unavailabilityBlockRoot) : undefined,
|
|
95
|
+
finalized: block.finalized,
|
|
96
|
+
slot: block.slot,
|
|
97
|
+
requestedColumns,
|
|
98
|
+
availableColumns,
|
|
99
|
+
});
|
|
98
100
|
}
|
|
99
101
|
}
|
|
102
|
+
}
|
|
100
103
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// filter below (pre-gloas this skips finalizedSlot, post-gloas it keeps it).
|
|
108
|
-
const headChain = chain.forkChoice.getAllAncestorBlocks(headRoot, headBlock.payloadStatus);
|
|
109
|
-
|
|
110
|
-
// Iterate head chain with ascending block numbers
|
|
111
|
-
for (let i = headChain.length - 1; i >= 0; i--) {
|
|
112
|
-
const block = headChain[i];
|
|
113
|
-
|
|
114
|
-
// Must include only columns in the range requested
|
|
115
|
-
if (block.slot > archiveMaxSlot && block.slot >= startSlot && block.slot < endSlot) {
|
|
116
|
-
// Post-gloas, columns exist only for FULL blocks (pre-gloas blocks are always FULL)
|
|
117
|
-
if (block.payloadStatus !== PayloadStatus.FULL) {
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Note: Here the forkChoice head may change due to a re-org, so the headChain reflects the canonical chain
|
|
122
|
-
// at the time of the start of the request. Spec is clear the chain of columns must be consistent, but on
|
|
123
|
-
// re-org there's no need to abort the request
|
|
124
|
-
// Spec: https://github.com/ethereum/consensus-specs/blob/ad36024441cf910d428d03f87f331fbbd2b3e5f1/specs/fulu/p2p-interface.md#L425-L429
|
|
125
|
-
const dataColumnSidecars = await chain.getSerializedDataColumnSidecars(
|
|
126
|
-
block.slot,
|
|
127
|
-
block.blockRoot,
|
|
128
|
-
availableColumns
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
const unavailableColumnIndices: ColumnIndex[] = [];
|
|
132
|
-
for (let i = 0; i < dataColumnSidecars.length; i++) {
|
|
133
|
-
const dataColumnSidecarBytes = dataColumnSidecars[i];
|
|
134
|
-
if (dataColumnSidecarBytes) {
|
|
135
|
-
yield {
|
|
136
|
-
data: dataColumnSidecarBytes,
|
|
137
|
-
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(block.slot)),
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// TODO: Check blobs for that block and respond resource_unavailable
|
|
142
|
-
// After we have consensus from other teams on the specs
|
|
143
|
-
else {
|
|
144
|
-
unavailableColumnIndices.push(availableColumns[i]);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (unavailableColumnIndices.length) {
|
|
149
|
-
await handleColumnSidecarUnavailability({
|
|
150
|
-
chain,
|
|
151
|
-
db,
|
|
152
|
-
metrics: chain.metrics,
|
|
153
|
-
unavailableColumnIndices,
|
|
154
|
-
blockRoot: fromHex(block.blockRoot),
|
|
155
|
-
slot: block.slot,
|
|
156
|
-
requestedColumns,
|
|
157
|
-
availableColumns,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}
|
|
104
|
+
type CanonicalDataColumnBlock = {
|
|
105
|
+
slot: number;
|
|
106
|
+
blockRoot: RootHex | null;
|
|
107
|
+
unavailabilityBlockRoot?: RootHex;
|
|
108
|
+
finalized: boolean;
|
|
109
|
+
};
|
|
161
110
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
111
|
+
async function* resolveCanonicalDataColumnBlocks(
|
|
112
|
+
chain: IBeaconChain,
|
|
113
|
+
db: IBeaconDb,
|
|
114
|
+
headChain: ReturnType<IBeaconChain["forkChoice"]["getAllAncestorBlocks"]>,
|
|
115
|
+
startSlot: number,
|
|
116
|
+
endSlot: number,
|
|
117
|
+
archiveMaxSlot: number,
|
|
118
|
+
finalizedSlot: number
|
|
119
|
+
): AsyncIterable<CanonicalDataColumnBlock> {
|
|
120
|
+
const canonicalBlocksBySlot = new Map(headChain.map((block) => [block.slot, block]));
|
|
121
|
+
const oldestForkChoiceSlot = headChain.at(-1)?.slot ?? Number.POSITIVE_INFINITY;
|
|
122
|
+
const archiveEnd = Math.min(endSlot, archiveMaxSlot + 1);
|
|
123
|
+
const recentRoots = getRecentCanonicalRoots(chain, startSlot, Math.min(archiveEnd, oldestForkChoiceSlot));
|
|
124
|
+
|
|
125
|
+
for (let slot = startSlot; slot < archiveEnd; slot++) {
|
|
126
|
+
if (slot >= oldestForkChoiceSlot) {
|
|
127
|
+
const block = canonicalBlocksBySlot.get(slot);
|
|
128
|
+
if (block?.payloadStatus === PayloadStatus.FULL) {
|
|
129
|
+
yield {
|
|
130
|
+
slot,
|
|
131
|
+
blockRoot: block.blockRoot,
|
|
132
|
+
unavailabilityBlockRoot: block.blockRoot,
|
|
133
|
+
finalized: true,
|
|
134
|
+
};
|
|
165
135
|
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let blockRoot = recentRoots.get(slot);
|
|
140
|
+
if (blockRoot === null) continue;
|
|
141
|
+
if (blockRoot === undefined) {
|
|
142
|
+
const root = await db.blockArchive.getRootBySlot(slot);
|
|
143
|
+
blockRoot = root === null ? null : toRootHex(root);
|
|
166
144
|
}
|
|
145
|
+
if (blockRoot === null && (db.lastLegacyArchiveSlot === null || slot > db.lastLegacyArchiveSlot)) continue;
|
|
146
|
+
if (
|
|
147
|
+
chain.config.getForkSeq(slot) >= ForkSeq.gloas &&
|
|
148
|
+
!(await hasExecutionPayloadEnvelope(chain, db, slot, blockRoot))
|
|
149
|
+
) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
yield {
|
|
153
|
+
slot,
|
|
154
|
+
blockRoot,
|
|
155
|
+
unavailabilityBlockRoot: chain.config.getForkSeq(slot) >= ForkSeq.gloas ? (blockRoot ?? undefined) : undefined,
|
|
156
|
+
finalized: true,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
for (let i = headChain.length - 1; i >= 0; i--) {
|
|
161
|
+
const block = headChain[i];
|
|
162
|
+
if (block.slot >= endSlot) break;
|
|
163
|
+
if (block.slot <= archiveMaxSlot || block.slot < startSlot || block.payloadStatus !== PayloadStatus.FULL) continue;
|
|
164
|
+
yield {
|
|
165
|
+
slot: block.slot,
|
|
166
|
+
blockRoot: block.blockRoot,
|
|
167
|
+
unavailabilityBlockRoot: block.blockRoot,
|
|
168
|
+
finalized: block.slot <= finalizedSlot,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Copy roots synchronously so serving a request never retains a head-state reference across I/O. */
|
|
174
|
+
function getRecentCanonicalRoots(chain: IBeaconChain, startSlot: number, endSlot: number): Map<number, RootHex | null> {
|
|
175
|
+
const roots = new Map<number, RootHex | null>();
|
|
176
|
+
if (startSlot >= endSlot) return roots;
|
|
177
|
+
const state = chain.getHeadState();
|
|
178
|
+
// Skipped slots repeat the prior root. At the oldest ring entry, that prior root is unavailable.
|
|
179
|
+
const start = Math.max(startSlot, state.slot - SLOTS_PER_HISTORICAL_ROOT + 1, 1);
|
|
180
|
+
const end = Math.min(endSlot, state.slot);
|
|
181
|
+
if (start >= end) return roots;
|
|
182
|
+
let previousRoot = toRootHex(state.getBlockRootAtSlot(start - 1));
|
|
183
|
+
for (let slot = start; slot < end; slot++) {
|
|
184
|
+
const root = toRootHex(state.getBlockRootAtSlot(slot));
|
|
185
|
+
roots.set(slot, root === previousRoot ? null : root);
|
|
186
|
+
previousRoot = root;
|
|
187
|
+
}
|
|
188
|
+
return roots;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function hasExecutionPayloadEnvelope(
|
|
192
|
+
chain: IBeaconChain,
|
|
193
|
+
db: IBeaconDb,
|
|
194
|
+
slot: number,
|
|
195
|
+
blockRoot: RootHex | null
|
|
196
|
+
): Promise<boolean> {
|
|
197
|
+
if (blockRoot !== null) {
|
|
198
|
+
if (chain.seenPayloadEnvelopeInputCache.hasPayload(blockRoot)) return true;
|
|
199
|
+
if ((await db.executionPayloadEnvelope.getBinary(fromHex(blockRoot))) !== null) return true;
|
|
167
200
|
}
|
|
201
|
+
return (await db.executionPayloadEnvelopeArchive.getBinary(slot)) !== null;
|
|
168
202
|
}
|
|
169
203
|
|
|
170
204
|
export function validateDataColumnSidecarsByRangeRequest(
|
|
@@ -81,12 +81,14 @@ export async function* onDataColumnSidecarsByRoot(
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
if (unavailableColumnIndices.length) {
|
|
84
|
+
const finalized = !block || (await db.blockArchive.getSlotByRoot(blockRoot)) === slot;
|
|
84
85
|
await handleColumnSidecarUnavailability({
|
|
85
86
|
chain,
|
|
86
87
|
db,
|
|
87
88
|
metrics: chain.metrics,
|
|
88
89
|
slot,
|
|
89
90
|
blockRoot,
|
|
91
|
+
finalized,
|
|
90
92
|
unavailableColumnIndices,
|
|
91
93
|
requestedColumns,
|
|
92
94
|
availableColumns,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
-
import {ForkName
|
|
2
|
+
import {ForkName} from "@lodestar/params";
|
|
3
3
|
import {ContextBytesFactory, ContextBytesType, Encoding, TypeSizes} from "@lodestar/reqresp";
|
|
4
4
|
import {rateLimitQuotas} from "./rateLimit.js";
|
|
5
5
|
import {ProtocolNoHandler, ReqRespMethod, Version, requestSszTypeByMethod, responseSszTypeByMethod} from "./types.js";
|
|
@@ -151,35 +151,18 @@ function toProtocol(protocol: ProtocolSummary) {
|
|
|
151
151
|
encoding: Encoding.SSZ_SNAPPY,
|
|
152
152
|
contextBytes: toContextBytes(protocol.contextBytesType, config),
|
|
153
153
|
inboundRateLimits: rateLimitQuotas(fork, config)[protocol.method],
|
|
154
|
-
requestSizes: requestType === null ? null : clampTypeSizes(requestType,
|
|
155
|
-
responseSizes: (fork) =>
|
|
156
|
-
clampTypeSizes(responseSszTypeByMethod[protocol.method](fork, protocol.version), protocol.method, fork, config),
|
|
154
|
+
requestSizes: requestType === null ? null : clampTypeSizes(requestType, config),
|
|
155
|
+
responseSizes: (fork) => clampTypeSizes(responseSszTypeByMethod[protocol.method](fork, protocol.version), config),
|
|
157
156
|
};
|
|
158
157
|
};
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* The length-prefix must be within the size bounds derived from the payload SSZ type or `MAX_PAYLOAD_SIZE`,
|
|
166
|
-
* whichever is smaller, see
|
|
167
|
-
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.12/specs/phase0/p2p-interface.md#encoding-strategies.
|
|
168
|
-
* Type-specific SSZ bounds supersede the bounds derived from the SSZ type, see
|
|
169
|
-
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.12/specs/gloas/p2p-interface.md#type-specific-ssz-bounds.
|
|
161
|
+
* Length-prefix must be within the SSZ type bounds or MAX_PAYLOAD_SIZE, whichever is smaller
|
|
162
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.12/specs/phase0/p2p-interface.md#encoding-strategies
|
|
170
163
|
*/
|
|
171
|
-
function clampTypeSizes(type: TypeSizes,
|
|
172
|
-
|
|
173
|
-
if (isForkPostGloas(fork)) {
|
|
174
|
-
switch (method) {
|
|
175
|
-
case ReqRespMethod.DataColumnSidecarsByRange:
|
|
176
|
-
case ReqRespMethod.DataColumnSidecarsByRoot:
|
|
177
|
-
typeSpecificBound = MAX_DATA_COLUMN_SIDECAR_SIZE;
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return {minSize: type.minSize, maxSize: Math.min(type.maxSize, typeSpecificBound)};
|
|
164
|
+
function clampTypeSizes(type: TypeSizes, config: BeaconConfig): TypeSizes {
|
|
165
|
+
return {minSize: type.minSize, maxSize: Math.min(type.maxSize, config.MAX_PAYLOAD_SIZE)};
|
|
183
166
|
}
|
|
184
167
|
|
|
185
168
|
function toContextBytes(type: ContextBytesType, config: BeaconConfig): ContextBytesFactory {
|
|
@@ -126,7 +126,8 @@ function getRequestCountFn<T extends ReqRespMethod>(
|
|
|
126
126
|
const type = requestSszTypeByMethod(fork, config)[method];
|
|
127
127
|
return (reqData: Uint8Array) => {
|
|
128
128
|
try {
|
|
129
|
-
|
|
129
|
+
// A schema-valid request can cost 0 tokens; floor to 1 so it stays charged and bannable, not free.
|
|
130
|
+
return Math.max(1, (type && fn(type.deserialize(reqData))) ?? 1);
|
|
130
131
|
} catch (_e) {
|
|
131
132
|
return 1;
|
|
132
133
|
}
|
|
@@ -16,12 +16,14 @@ export async function handleColumnSidecarUnavailability({
|
|
|
16
16
|
availableColumns,
|
|
17
17
|
slot,
|
|
18
18
|
blockRoot,
|
|
19
|
+
finalized,
|
|
19
20
|
}: {
|
|
20
21
|
chain: IBeaconChain;
|
|
21
22
|
db: IBeaconDb;
|
|
22
23
|
metrics: Metrics | null;
|
|
23
24
|
slot: Slot;
|
|
24
25
|
blockRoot?: Uint8Array;
|
|
26
|
+
finalized: boolean;
|
|
25
27
|
unavailableColumnIndices: ColumnIndex[];
|
|
26
28
|
requestedColumns: ColumnIndex[];
|
|
27
29
|
availableColumns: ColumnIndex[];
|
|
@@ -38,17 +40,23 @@ export async function handleColumnSidecarUnavailability({
|
|
|
38
40
|
|
|
39
41
|
chain.logger.debug("dataColumnSidecar requested unavailable", logData);
|
|
40
42
|
|
|
41
|
-
// Post-gloas, columns exist only for FULL blocks
|
|
42
|
-
//
|
|
43
|
-
if (
|
|
44
|
-
const
|
|
45
|
-
if (!
|
|
43
|
+
// Post-gloas, columns exist only for FULL blocks. The envelope may still be hot while finalization
|
|
44
|
+
// archiving is in progress. Bid blobsCount is unreliable since an EMPTY block's bid may still commit to blobs.
|
|
45
|
+
if (chain.config.getForkSeq(slot) >= ForkSeq.gloas) {
|
|
46
|
+
const hasCachedEnvelope = blockRoot ? chain.seenPayloadEnvelopeInputCache.hasPayload(toRootHex(blockRoot)) : false;
|
|
47
|
+
if (!hasCachedEnvelope) {
|
|
48
|
+
const hotEnvelopeBytes = blockRoot ? await db.executionPayloadEnvelope.getBinary(blockRoot) : null;
|
|
49
|
+
const envelopeBytes =
|
|
50
|
+
hotEnvelopeBytes ?? (finalized ? await db.executionPayloadEnvelopeArchive.getBinary(slot) : null);
|
|
51
|
+
if (!envelopeBytes) return;
|
|
52
|
+
}
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
const
|
|
55
|
+
const hotBlockBytes = blockRoot ? await db.block.getBinary(blockRoot) : null;
|
|
56
|
+
const blockBytes = hotBlockBytes ?? (finalized ? await db.blockArchive.getBinary(slot) : null);
|
|
49
57
|
if (!blockBytes) {
|
|
50
58
|
chain.logger.verbose(
|
|
51
|
-
`Expected ${
|
|
59
|
+
`Expected ${finalized ? "finalized" : "unfinalized"} block not found while handling unavailable dataColumnSidecar`,
|
|
52
60
|
{
|
|
53
61
|
slot,
|
|
54
62
|
blockRoot: blockRoot ? toRootHex(blockRoot) : "unknown",
|
package/src/node/nodejs.ts
CHANGED
|
@@ -54,6 +54,7 @@ export type BeaconNodeInitModules = {
|
|
|
54
54
|
processShutdownCallback: ProcessShutdownCallback;
|
|
55
55
|
privateKey: PrivateKey;
|
|
56
56
|
dataDir: string;
|
|
57
|
+
dataColumnDir: string;
|
|
57
58
|
peerStoreDir?: string;
|
|
58
59
|
anchorState: IBeaconStateView;
|
|
59
60
|
isAnchorStateFinalized: boolean;
|
|
@@ -156,6 +157,7 @@ export class BeaconNode {
|
|
|
156
157
|
processShutdownCallback,
|
|
157
158
|
privateKey,
|
|
158
159
|
dataDir,
|
|
160
|
+
dataColumnDir,
|
|
159
161
|
peerStoreDir,
|
|
160
162
|
anchorState,
|
|
161
163
|
isAnchorStateFinalized,
|
|
@@ -181,7 +183,7 @@ export class BeaconNode {
|
|
|
181
183
|
metrics = createMetrics(opts.metrics, anchorState.genesisTime, metricsRegistries);
|
|
182
184
|
initBeaconMetrics(metrics, anchorState);
|
|
183
185
|
// Since the db is instantiated before this, metrics must be injected manually afterwards
|
|
184
|
-
db.setMetrics(metrics.db);
|
|
186
|
+
db.setMetrics(metrics.db, metrics.flatFileStore);
|
|
185
187
|
signal.addEventListener("abort", metrics.close, {once: true});
|
|
186
188
|
}
|
|
187
189
|
|
|
@@ -198,6 +200,8 @@ export class BeaconNode {
|
|
|
198
200
|
|
|
199
201
|
const clock = new Clock({config, genesisTime: anchorState.genesisTime, signal});
|
|
200
202
|
|
|
203
|
+
await db.init();
|
|
204
|
+
|
|
201
205
|
// Prune hot db repos
|
|
202
206
|
// TODO: Should this call be awaited?
|
|
203
207
|
await db.pruneHotDb();
|
|
@@ -244,6 +248,7 @@ export class BeaconNode {
|
|
|
244
248
|
clock,
|
|
245
249
|
pubkeyCache,
|
|
246
250
|
dataDir,
|
|
251
|
+
dataColumnDir,
|
|
247
252
|
db,
|
|
248
253
|
dbName: opts.db.name,
|
|
249
254
|
logger: logger.child({module: LoggerModule.chain}),
|
package/src/util/sszBytes.ts
CHANGED
|
@@ -754,7 +754,7 @@ export function getParentBlockRootFromSignedExecutionPayloadBidSerialized(data:
|
|
|
754
754
|
*
|
|
755
755
|
* If the high bytes are not zero, return null
|
|
756
756
|
*/
|
|
757
|
-
function getSlotFromOffset(data: Uint8Array, offset: number): Slot | null {
|
|
757
|
+
export function getSlotFromOffset(data: Uint8Array, offset: number): Slot | null {
|
|
758
758
|
return checkSlotHighBytes(data, offset) ? getSlotFromOffsetTrusted(data, offset) : null;
|
|
759
759
|
}
|
|
760
760
|
|