@lodestar/beacon-node 1.44.0-dev.b66425f010 → 1.44.0-dev.be2850b7bb
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/config/constants.d.ts +1 -0
- package/lib/api/impl/config/constants.d.ts.map +1 -1
- package/lib/api/impl/config/constants.js +2 -1
- package/lib/api/impl/config/constants.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +69 -12
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +21 -9
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +0 -1
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +0 -4
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/errors/payloadAttestation.d.ts +6 -0
- package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
- package/lib/chain/errors/payloadAttestation.js +1 -0
- package/lib/chain/errors/payloadAttestation.js.map +1 -1
- package/lib/chain/prepareNextSlot.js +1 -1
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +3 -3
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +0 -1
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/queued.d.ts +0 -1
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +0 -4
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +0 -5
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +0 -5
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -4
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +5 -2
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +0 -2
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +22 -5
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +10 -0
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +19 -766
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +9 -5
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +13 -3
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +16 -6
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +15 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/index.js +4 -4
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js +22 -3
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/lib/util/dataColumns.d.ts.map +1 -1
- package/lib/util/dataColumns.js +16 -11
- package/lib/util/dataColumns.js.map +1 -1
- package/package.json +14 -16
- package/src/api/impl/config/constants.ts +2 -0
- package/src/api/impl/debug/index.ts +73 -12
- package/src/api/impl/validator/index.ts +23 -14
- package/src/chain/archiveStore/archiveStore.ts +0 -5
- package/src/chain/errors/payloadAttestation.ts +2 -0
- package/src/chain/prepareNextSlot.ts +1 -1
- package/src/chain/produceBlock/produceBlockBody.ts +3 -3
- package/src/chain/regen/interface.ts +0 -1
- package/src/chain/regen/queued.ts +0 -5
- package/src/chain/stateCache/fifoBlockStateCache.ts +0 -6
- package/src/chain/stateCache/persistentCheckpointsCache.ts +6 -2
- package/src/chain/stateCache/types.ts +0 -2
- package/src/chain/validation/executionPayloadBid.ts +23 -5
- package/src/chain/validation/payloadAttestationMessage.ts +11 -0
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +12 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -3
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -1
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +22 -6
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +20 -1
- package/src/network/reqresp/handlers/index.ts +4 -4
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +21 -3
- package/src/util/dataColumns.ts +17 -12
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/ChainSafe/lodestar/issues"
|
|
13
13
|
},
|
|
14
|
-
"version": "1.44.0-dev.
|
|
14
|
+
"version": "1.44.0-dev.be2850b7bb",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -116,7 +116,6 @@
|
|
|
116
116
|
"@chainsafe/libp2p-quic": "^2.0.1",
|
|
117
117
|
"@chainsafe/persistent-merkle-tree": "^1.2.5",
|
|
118
118
|
"@chainsafe/prometheus-gc-stats": "^1.0.0",
|
|
119
|
-
"@chainsafe/pubkey-index-map": "^3.0.0",
|
|
120
119
|
"@chainsafe/snappy-wasm": "^0.5.0",
|
|
121
120
|
"@chainsafe/ssz": "^1.4.0",
|
|
122
121
|
"@chainsafe/threads": "^1.11.3",
|
|
@@ -135,17 +134,17 @@
|
|
|
135
134
|
"@libp2p/peer-id": "^6.0.4",
|
|
136
135
|
"@libp2p/prometheus-metrics": "^5.0.14",
|
|
137
136
|
"@libp2p/tcp": "^11.0.13",
|
|
138
|
-
"@lodestar/api": "^1.44.0-dev.
|
|
139
|
-
"@lodestar/config": "^1.44.0-dev.
|
|
140
|
-
"@lodestar/db": "^1.44.0-dev.
|
|
141
|
-
"@lodestar/fork-choice": "^1.44.0-dev.
|
|
142
|
-
"@lodestar/logger": "^1.44.0-dev.
|
|
143
|
-
"@lodestar/params": "^1.44.0-dev.
|
|
144
|
-
"@lodestar/reqresp": "^1.44.0-dev.
|
|
145
|
-
"@lodestar/state-transition": "^1.44.0-dev.
|
|
146
|
-
"@lodestar/types": "^1.44.0-dev.
|
|
147
|
-
"@lodestar/utils": "^1.44.0-dev.
|
|
148
|
-
"@lodestar/validator": "^1.44.0-dev.
|
|
137
|
+
"@lodestar/api": "^1.44.0-dev.be2850b7bb",
|
|
138
|
+
"@lodestar/config": "^1.44.0-dev.be2850b7bb",
|
|
139
|
+
"@lodestar/db": "^1.44.0-dev.be2850b7bb",
|
|
140
|
+
"@lodestar/fork-choice": "^1.44.0-dev.be2850b7bb",
|
|
141
|
+
"@lodestar/logger": "^1.44.0-dev.be2850b7bb",
|
|
142
|
+
"@lodestar/params": "^1.44.0-dev.be2850b7bb",
|
|
143
|
+
"@lodestar/reqresp": "^1.44.0-dev.be2850b7bb",
|
|
144
|
+
"@lodestar/state-transition": "^1.44.0-dev.be2850b7bb",
|
|
145
|
+
"@lodestar/types": "^1.44.0-dev.be2850b7bb",
|
|
146
|
+
"@lodestar/utils": "^1.44.0-dev.be2850b7bb",
|
|
147
|
+
"@lodestar/validator": "^1.44.0-dev.be2850b7bb",
|
|
149
148
|
"@multiformats/multiaddr": "^13.0.1",
|
|
150
149
|
"datastore-core": "^11.0.2",
|
|
151
150
|
"datastore-fs": "^11.0.2",
|
|
@@ -168,13 +167,12 @@
|
|
|
168
167
|
"@libp2p/interface-internal": "^3.0.13",
|
|
169
168
|
"@libp2p/logger": "^6.2.2",
|
|
170
169
|
"@libp2p/utils": "^7.0.13",
|
|
171
|
-
"@lodestar/spec-test-util": "^1.44.0-dev.
|
|
170
|
+
"@lodestar/spec-test-util": "^1.44.0-dev.be2850b7bb",
|
|
172
171
|
"@types/js-yaml": "^4.0.5",
|
|
173
172
|
"@types/qs": "^6.9.7",
|
|
174
173
|
"@types/tmp": "^0.2.3",
|
|
175
174
|
"dotenv": "^16.4.5",
|
|
176
175
|
"js-yaml": "^4.1.0",
|
|
177
|
-
"rewiremock": "^3.14.5",
|
|
178
176
|
"rimraf": "^4.4.1",
|
|
179
177
|
"snappy": "^7.2.2",
|
|
180
178
|
"snappyjs": "^0.7.0",
|
|
@@ -186,5 +184,5 @@
|
|
|
186
184
|
"beacon",
|
|
187
185
|
"blockchain"
|
|
188
186
|
],
|
|
189
|
-
"gitHead": "
|
|
187
|
+
"gitHead": "6006ab1cca25bb4d64302db69d3864ef42d6b23e"
|
|
190
188
|
}
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
VERSIONED_HASH_VERSION_KZG,
|
|
54
54
|
WEIGHT_DENOMINATOR,
|
|
55
55
|
WITHDRAWAL_REQUEST_TYPE,
|
|
56
|
+
ZERO_HASH_HEX,
|
|
56
57
|
} from "@lodestar/params";
|
|
57
58
|
|
|
58
59
|
/**
|
|
@@ -69,6 +70,7 @@ export const specConstants = {
|
|
|
69
70
|
DEPOSIT_CONTRACT_TREE_DEPTH,
|
|
70
71
|
JUSTIFICATION_BITS_LENGTH,
|
|
71
72
|
ENDIANNESS: "little",
|
|
73
|
+
EMPTY_BLOCK_HASH: ZERO_HASH_HEX,
|
|
72
74
|
// ## Withdrawal prefixes
|
|
73
75
|
BLS_WITHDRAWAL_PREFIX: toHexByte(BLS_WITHDRAWAL_PREFIX),
|
|
74
76
|
ETH1_ADDRESS_WITHDRAWAL_PREFIX: toHexByte(ETH1_ADDRESS_WITHDRAWAL_PREFIX),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ApplicationMethods} from "@lodestar/api/server";
|
|
3
|
-
import {ExecutionStatus} from "@lodestar/fork-choice";
|
|
3
|
+
import {ExecutionStatus, PayloadStatus} from "@lodestar/fork-choice";
|
|
4
4
|
import {ForkPostDeneb, ZERO_HASH_HEX, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
|
|
5
|
+
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
5
6
|
import {BeaconState, DataColumnSidecar, DataColumnSidecars, type SignedBeaconBlock, sszTypesFor} from "@lodestar/types";
|
|
6
7
|
import {toRootHex} from "@lodestar/utils";
|
|
7
8
|
import {getBlobKzgCommitments} from "../../../util/dataColumns.js";
|
|
@@ -12,6 +13,29 @@ import {getStateResponseWithRegen} from "../beacon/state/utils.js";
|
|
|
12
13
|
import {ApiModules} from "../types.js";
|
|
13
14
|
import {assertUniqueItems} from "../utils.js";
|
|
14
15
|
|
|
16
|
+
function toForkChoiceValidity(status: ExecutionStatus): "valid" | "invalid" | "optimistic" {
|
|
17
|
+
switch (status) {
|
|
18
|
+
case ExecutionStatus.Valid:
|
|
19
|
+
return "valid";
|
|
20
|
+
case ExecutionStatus.Invalid:
|
|
21
|
+
return "invalid";
|
|
22
|
+
case ExecutionStatus.Syncing:
|
|
23
|
+
case ExecutionStatus.PreMerge:
|
|
24
|
+
return "optimistic";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function toPayloadStatusName(status: PayloadStatus): "pending" | "empty" | "full" {
|
|
29
|
+
switch (status) {
|
|
30
|
+
case PayloadStatus.PENDING:
|
|
31
|
+
return "pending";
|
|
32
|
+
case PayloadStatus.EMPTY:
|
|
33
|
+
return "empty";
|
|
34
|
+
case PayloadStatus.FULL:
|
|
35
|
+
return "full";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
15
39
|
export function getDebugApi({
|
|
16
40
|
chain,
|
|
17
41
|
config,
|
|
@@ -40,23 +64,60 @@ export function getDebugApi({
|
|
|
40
64
|
justifiedEpoch: node.justifiedEpoch,
|
|
41
65
|
finalizedEpoch: node.finalizedEpoch,
|
|
42
66
|
weight: node.weight,
|
|
43
|
-
validity: (
|
|
44
|
-
switch (node.executionStatus) {
|
|
45
|
-
case ExecutionStatus.Valid:
|
|
46
|
-
return "valid";
|
|
47
|
-
case ExecutionStatus.Invalid:
|
|
48
|
-
return "invalid";
|
|
49
|
-
case ExecutionStatus.Syncing:
|
|
50
|
-
case ExecutionStatus.PreMerge:
|
|
51
|
-
return "optimistic";
|
|
52
|
-
}
|
|
53
|
-
})(),
|
|
67
|
+
validity: toForkChoiceValidity(node.executionStatus),
|
|
54
68
|
executionBlockHash: node.executionPayloadBlockHash ?? ZERO_HASH_HEX,
|
|
55
69
|
})),
|
|
56
70
|
},
|
|
57
71
|
};
|
|
58
72
|
},
|
|
59
73
|
|
|
74
|
+
async getDebugForkChoiceV2() {
|
|
75
|
+
const {forkChoice} = chain;
|
|
76
|
+
return {
|
|
77
|
+
data: {
|
|
78
|
+
justifiedCheckpoint: forkChoice.getJustifiedCheckpoint(),
|
|
79
|
+
finalizedCheckpoint: forkChoice.getFinalizedCheckpoint(),
|
|
80
|
+
forkChoiceNodes: forkChoice.getAllNodes().map((node) => {
|
|
81
|
+
// Payload-specific fields apply only to a revealed Gloas payload = the FULL variant of a
|
|
82
|
+
// Gloas block
|
|
83
|
+
const ptc = node.payloadStatus === PayloadStatus.FULL ? forkChoice.getPTCVoteCounts(node.blockRoot) : null;
|
|
84
|
+
return {
|
|
85
|
+
payloadStatus: toPayloadStatusName(node.payloadStatus),
|
|
86
|
+
slot: node.slot,
|
|
87
|
+
blockRoot: node.blockRoot,
|
|
88
|
+
parentRoot: node.parentRoot,
|
|
89
|
+
weight: node.weight,
|
|
90
|
+
validity: toForkChoiceValidity(node.executionStatus),
|
|
91
|
+
executionBlockHash: node.executionPayloadBlockHash ?? ZERO_HASH_HEX,
|
|
92
|
+
extraData: {
|
|
93
|
+
executionOptimistic: isOptimisticBlock(node),
|
|
94
|
+
timestamp: computeTimeAtSlot(config, node.slot, chain.genesisTime),
|
|
95
|
+
target: node.targetRoot,
|
|
96
|
+
justifiedEpoch: node.justifiedEpoch,
|
|
97
|
+
finalizedEpoch: node.finalizedEpoch,
|
|
98
|
+
unrealizedJustifiedEpoch: node.unrealizedJustifiedEpoch,
|
|
99
|
+
unrealizedFinalizedEpoch: node.unrealizedFinalizedEpoch,
|
|
100
|
+
payloadAttesterCount: ptc?.attesterCount ?? null,
|
|
101
|
+
payloadAvailabilityYesCount: ptc?.payloadPresentCount ?? null,
|
|
102
|
+
payloadDataAvailabilityYesCount: ptc?.dataAvailableCount ?? null,
|
|
103
|
+
gasLimit:
|
|
104
|
+
node.payloadStatus === PayloadStatus.FULL && "executionPayloadGasLimit" in node
|
|
105
|
+
? node.executionPayloadGasLimit
|
|
106
|
+
: null,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}),
|
|
110
|
+
extraData: {
|
|
111
|
+
unrealizedJustifiedCheckpoint: forkChoice.getUnrealizedJustifiedCheckpoint(),
|
|
112
|
+
unrealizedFinalizedCheckpoint: forkChoice.getUnrealizedFinalizedCheckpoint(),
|
|
113
|
+
proposerBoostRoot: forkChoice.getProposerBoostRoot(),
|
|
114
|
+
previousProposerBoostRoot: forkChoice.getPreviousProposerBoostRoot(),
|
|
115
|
+
headRoot: forkChoice.getHeadRoot(),
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
|
|
60
121
|
async getProtoArrayNodes() {
|
|
61
122
|
const nodes = chain.forkChoice.getAllNodes().map((node) => ({
|
|
62
123
|
// if node has executionPayloadNumber, it will overwrite the below default
|
|
@@ -927,11 +927,9 @@ export function getValidatorApi(
|
|
|
927
927
|
// TODO GLOAS: respect builderSelection (MaxProfit, BuilderAlways, ExecutionAlways, etc.) to let
|
|
928
928
|
// the user control bid source preferences and value comparison. Also add external builder api
|
|
929
929
|
// support when it is implemented.
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
parentBlockRootHex
|
|
934
|
-
);
|
|
930
|
+
const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
|
|
931
|
+
const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
|
|
932
|
+
const builderBid = chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
|
|
935
933
|
|
|
936
934
|
const logCtx = {
|
|
937
935
|
slot,
|
|
@@ -1112,23 +1110,34 @@ export function getValidatorApi(
|
|
|
1112
1110
|
notWhileSyncing();
|
|
1113
1111
|
await waitForSlot(slot);
|
|
1114
1112
|
|
|
1115
|
-
const block = chain.forkChoice.
|
|
1113
|
+
const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
|
|
1116
1114
|
if (!block) {
|
|
1117
|
-
|
|
1115
|
+
// No block is seen at slot. Return 404 so vc can skip casting payload attestation.
|
|
1116
|
+
throw new ApiError(404, `No canonical block found at slot=${slot}`);
|
|
1118
1117
|
}
|
|
1119
1118
|
|
|
1120
|
-
const blockIsForSlot = block.slot === slot;
|
|
1121
1119
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
|
|
1122
1120
|
// Spec: set payload_present only if the envelope was seen before get_payload_due_ms()
|
|
1123
1121
|
// into the slot. Use the envelope's own arrival time (getPayloadEnvelopeSource), not
|
|
1124
1122
|
// the input's creation time.
|
|
1125
1123
|
const payloadDueSec = config.getPayloadDueMs() / 1000;
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
const blobDataAvailable =
|
|
1124
|
+
const payloadSeenSec =
|
|
1125
|
+
payloadInput?.hasPayloadEnvelope() === true
|
|
1126
|
+
? chain.clock.secFromSlot(slot, payloadInput.getPayloadEnvelopeSource().seenTimestampSec)
|
|
1127
|
+
: null;
|
|
1128
|
+
const payloadPresent = payloadSeenSec !== null && payloadSeenSec < payloadDueSec;
|
|
1129
|
+
const blobDataAvailable = payloadInput?.hasAllData() === true;
|
|
1130
|
+
|
|
1131
|
+
logger.debug("Produced payload attestation data", {
|
|
1132
|
+
slot,
|
|
1133
|
+
blockRoot: block.blockRoot,
|
|
1134
|
+
blockSlot: block.slot,
|
|
1135
|
+
payloadPresent,
|
|
1136
|
+
blobDataAvailable,
|
|
1137
|
+
hasPayloadInput: payloadInput !== undefined,
|
|
1138
|
+
payloadSeenSec,
|
|
1139
|
+
payloadDueSec,
|
|
1140
|
+
});
|
|
1132
1141
|
|
|
1133
1142
|
return {
|
|
1134
1143
|
data: {
|
|
@@ -30,7 +30,6 @@ export enum ArchiveStoreTask {
|
|
|
30
30
|
PruneHistory = "prune_history",
|
|
31
31
|
OnFinalizedCheckpoint = "on_finalized_checkpoint",
|
|
32
32
|
MaybeArchiveState = "maybe_archive_state",
|
|
33
|
-
RegenPruneOnFinalized = "regen_prune_on_finalized",
|
|
34
33
|
ForkchoicePrune = "forkchoice_prune",
|
|
35
34
|
UpdateBackfillRange = "update_backfill_range",
|
|
36
35
|
}
|
|
@@ -229,10 +228,6 @@ export class ArchiveStore {
|
|
|
229
228
|
await this.statesArchiverStrategy.maybeArchiveState(finalized, this.metrics);
|
|
230
229
|
timer?.({source: ArchiveStoreTask.MaybeArchiveState});
|
|
231
230
|
|
|
232
|
-
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
233
|
-
this.chain.regen.pruneOnFinalized(finalizedEpoch);
|
|
234
|
-
timer?.({source: ArchiveStoreTask.RegenPruneOnFinalized});
|
|
235
|
-
|
|
236
231
|
// tasks rely on extended fork choice
|
|
237
232
|
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
238
233
|
const prunedBlocks = this.chain.forkChoice.prune(finalized.rootHex);
|
|
@@ -5,6 +5,7 @@ export enum PayloadAttestationErrorCode {
|
|
|
5
5
|
NOT_CURRENT_SLOT = "PAYLOAD_ATTESTATION_ERROR_NOT_CURRENT_SLOT",
|
|
6
6
|
PAYLOAD_ATTESTATION_ALREADY_KNOWN = "PAYLOAD_ATTESTATION_ERROR_PAYLOAD_ATTESTATION_ALREADY_KNOWN",
|
|
7
7
|
UNKNOWN_BLOCK_ROOT = "PAYLOAD_ATTESTATION_ERROR_UNKNOWN_BLOCK_ROOT",
|
|
8
|
+
INVALID_BLOCK_SLOT = "PAYLOAD_ATTESTATION_ERROR_INVALID_BLOCK_SLOT",
|
|
8
9
|
INVALID_BLOCK = "PAYLOAD_ATTESTATION_ERROR_INVALID_BLOCK",
|
|
9
10
|
INVALID_ATTESTER = "PAYLOAD_ATTESTATION_ERROR_INVALID_ATTESTER",
|
|
10
11
|
INVALID_SIGNATURE = "PAYLOAD_ATTESTATION_ERROR_INVALID_SIGNATURE",
|
|
@@ -18,6 +19,7 @@ export type PayloadAttestationErrorType =
|
|
|
18
19
|
blockRoot: RootHex;
|
|
19
20
|
}
|
|
20
21
|
| {code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT; blockRoot: RootHex}
|
|
22
|
+
| {code: PayloadAttestationErrorCode.INVALID_BLOCK_SLOT; blockRoot: RootHex; blockSlot: Slot; slot: Slot}
|
|
21
23
|
| {code: PayloadAttestationErrorCode.INVALID_BLOCK; blockRoot: RootHex}
|
|
22
24
|
| {code: PayloadAttestationErrorCode.INVALID_ATTESTER; attesterIndex: ValidatorIndex}
|
|
23
25
|
| {code: PayloadAttestationErrorCode.INVALID_SIGNATURE};
|
|
@@ -170,7 +170,7 @@ export class PrepareNextSlotScheduler {
|
|
|
170
170
|
let stateAfterParentPayload: IBeaconStateViewBellatrix = updatedPrepareState;
|
|
171
171
|
if (isStatePostGloas(updatedPrepareState)) {
|
|
172
172
|
// Spec: should_build_on_full(store, head) — see produceBlockBody.ts for context.
|
|
173
|
-
if (this.chain.forkChoice.shouldBuildOnFull(updatedHead)) {
|
|
173
|
+
if (this.chain.forkChoice.shouldBuildOnFull(updatedHead, prepareSlot)) {
|
|
174
174
|
parentBlockHash = updatedPrepareState.latestExecutionPayloadBid.blockHash;
|
|
175
175
|
// Skip applying parent payload unless we're proposing the next slot or have to emit payload_attributes events
|
|
176
176
|
if (feeRecipient !== undefined || this.chain.opts.emitPayloadAttributes === true) {
|
|
@@ -276,9 +276,9 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
276
276
|
// Apply parent payload once here as it's reused by EL prep and voluntary exit filtering below
|
|
277
277
|
let stateAfterParentPayload: IBeaconStateViewBellatrix = currentState;
|
|
278
278
|
// Spec: should_build_on_full(store, head). `parentBlock` is the proposer's head
|
|
279
|
-
// (set by chain.getProposerHead(slot)). Returns false when the PTC majority
|
|
280
|
-
//
|
|
281
|
-
const isBuildingOnFull = this.forkChoice.shouldBuildOnFull(parentBlock);
|
|
279
|
+
// (set by chain.getProposerHead(slot)). Returns false when the PTC majority signalled
|
|
280
|
+
// the blob data is not available or the payload was not timely, forcing a build on EMPTY (reorg).
|
|
281
|
+
const isBuildingOnFull = this.forkChoice.shouldBuildOnFull(parentBlock, blockSlot);
|
|
282
282
|
if (isBuildingOnFull) {
|
|
283
283
|
parentBlockHash = currentState.latestExecutionPayloadBid.blockHash;
|
|
284
284
|
parentExecutionRequests = await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot);
|
|
@@ -47,7 +47,6 @@ export interface IStateRegenerator extends IStateRegeneratorInternal {
|
|
|
47
47
|
getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null;
|
|
48
48
|
getClosestHeadState(head: ProtoBlock): IBeaconStateView | null;
|
|
49
49
|
pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void;
|
|
50
|
-
pruneOnFinalized(finalizedEpoch: Epoch): void;
|
|
51
50
|
processState(blockRootHex: RootHex, postState: IBeaconStateView): void;
|
|
52
51
|
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void;
|
|
53
52
|
updateHeadState(newHead: ProtoBlock, maybeHeadState: IBeaconStateView): void;
|
|
@@ -143,11 +143,6 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
143
143
|
this.blockStateCache.prune(headStateRoot);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
pruneOnFinalized(finalizedEpoch: number): void {
|
|
147
|
-
this.checkpointStateCache.pruneFinalized(finalizedEpoch);
|
|
148
|
-
this.blockStateCache.deleteAllBeforeEpoch(finalizedEpoch);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
146
|
processState(blockRootHex: RootHex, postState: IBeaconStateView): void {
|
|
152
147
|
this.blockStateCache.add(postState);
|
|
153
148
|
this.checkpointStateCache.processState(blockRootHex, postState).catch((e) => {
|
|
@@ -167,12 +167,6 @@ export class FIFOBlockStateCache implements BlockStateCache {
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
/**
|
|
171
|
-
* No need for this implementation
|
|
172
|
-
* This is only to conform to the old api
|
|
173
|
-
*/
|
|
174
|
-
deleteAllBeforeEpoch(): void {}
|
|
175
|
-
|
|
176
170
|
/**
|
|
177
171
|
* ONLY FOR DEBUGGING PURPOSES. For lodestar debug API.
|
|
178
172
|
*/
|
|
@@ -414,11 +414,12 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
414
414
|
|
|
415
415
|
/**
|
|
416
416
|
* Prune all checkpoint states before the provided finalized epoch.
|
|
417
|
+
* Driven sequentially from processState() so it never interleaves with persist.
|
|
417
418
|
*/
|
|
418
|
-
pruneFinalized(finalizedEpoch: Epoch): void {
|
|
419
|
+
private async pruneFinalized(finalizedEpoch: Epoch): Promise<void> {
|
|
419
420
|
for (const epoch of this.epochIndex.keys()) {
|
|
420
421
|
if (epoch < finalizedEpoch) {
|
|
421
|
-
this.deleteAllEpochItems(epoch).catch((e) =>
|
|
422
|
+
await this.deleteAllEpochItems(epoch).catch((e) =>
|
|
422
423
|
this.logger.debug("Error delete all epoch items", {epoch, finalizedEpoch}, e as Error)
|
|
423
424
|
);
|
|
424
425
|
}
|
|
@@ -476,6 +477,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
476
477
|
* As of Mar 2024, it takes <=350ms to persist a holesky state on fast server
|
|
477
478
|
*/
|
|
478
479
|
async processState(blockRootHex: RootHex, state: IBeaconStateView): Promise<number> {
|
|
480
|
+
// prune finalized in the same flow so a finalized cp state is pruned, never persisted
|
|
481
|
+
await this.pruneFinalized(state.finalizedCheckpoint.epoch);
|
|
482
|
+
|
|
479
483
|
let persistCount = 0;
|
|
480
484
|
// it's important to sort the epochs in ascending order, in case of big reorg we always want to keep the most recent checkpoint states
|
|
481
485
|
const sortedEpochs = Array.from(this.epochIndex.keys()).sort((a, b) => a - b);
|
|
@@ -30,7 +30,6 @@ export interface BlockStateCache {
|
|
|
30
30
|
clear(): void;
|
|
31
31
|
size: number;
|
|
32
32
|
prune(headStateRootHex: RootHex): void;
|
|
33
|
-
deleteAllBeforeEpoch(finalizedEpoch: Epoch): void;
|
|
34
33
|
dumpSummary(): routes.lodestar.StateCacheItem[];
|
|
35
34
|
/** Expose beacon states stored in cache. Use with caution */
|
|
36
35
|
getStates(): IterableIterator<IBeaconStateView>;
|
|
@@ -67,7 +66,6 @@ export interface CheckpointStateCache {
|
|
|
67
66
|
getOrReloadLatest(rootHex: RootHex, maxEpoch: Epoch): Promise<IBeaconStateView | null>;
|
|
68
67
|
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null;
|
|
69
68
|
prune(finalizedEpoch: Epoch, justifiedEpoch: Epoch): void;
|
|
70
|
-
pruneFinalized(finalizedEpoch: Epoch): void;
|
|
71
69
|
processState(blockRootHex: RootHex, state: IBeaconStateView): Promise<number>;
|
|
72
70
|
clear(): void;
|
|
73
71
|
dumpSummary(): routes.lodestar.StateCacheItem[];
|
|
@@ -35,10 +35,6 @@ async function validateExecutionPayloadBid(
|
|
|
35
35
|
const bid = signedExecutionPayloadBid.message;
|
|
36
36
|
const parentBlockRootHex = toRootHex(bid.parentBlockRoot);
|
|
37
37
|
const parentBlockHashHex = toRootHex(bid.parentBlockHash);
|
|
38
|
-
const state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.validateGossipExecutionPayloadBid);
|
|
39
|
-
if (!isStatePostGloas(state)) {
|
|
40
|
-
throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
|
|
41
|
-
}
|
|
42
38
|
|
|
43
39
|
// [IGNORE] `bid.slot` is the current slot or the next slot.
|
|
44
40
|
const currentSlot = chain.clock.currentSlot;
|
|
@@ -111,9 +107,31 @@ async function validateExecutionPayloadBid(
|
|
|
111
107
|
});
|
|
112
108
|
}
|
|
113
109
|
|
|
110
|
+
// Use the bid's parent branch state for builder checks
|
|
111
|
+
const state = await chain.regen
|
|
112
|
+
.getBlockSlotState(parentBlock, bid.slot, {dontTransferCache: true}, RegenCaller.validateGossipExecutionPayloadBid)
|
|
113
|
+
.catch(() => {
|
|
114
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
115
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
116
|
+
parentBlockRoot: parentBlockRootHex,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (!isStatePostGloas(state)) {
|
|
121
|
+
throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
114
124
|
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
115
125
|
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
116
|
-
|
|
126
|
+
let builder: gloas.Builder;
|
|
127
|
+
try {
|
|
128
|
+
builder = state.getBuilder(bid.builderIndex);
|
|
129
|
+
} catch {
|
|
130
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
131
|
+
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
132
|
+
builderIndex: bid.builderIndex,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
117
135
|
if (!isActiveBuilder(builder, state.finalizedCheckpoint.epoch)) {
|
|
118
136
|
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
119
137
|
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
@@ -70,6 +70,17 @@ async function validatePayloadAttestationMessage(
|
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// [IGNORE] The block referenced by `data.beacon_block_root` is at slot `data.slot`,
|
|
74
|
+
// i.e. the block has `block.slot == data.slot`.
|
|
75
|
+
if (block.slot !== data.slot) {
|
|
76
|
+
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
77
|
+
code: PayloadAttestationErrorCode.INVALID_BLOCK_SLOT,
|
|
78
|
+
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
79
|
+
blockSlot: block.slot,
|
|
80
|
+
slot: data.slot,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
73
84
|
// [REJECT] The message's block `data.beacon_block_root` passes validation.
|
|
74
85
|
// TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
|
|
75
86
|
// it is possible that the block didn't pass the validation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {PeerId} from "@libp2p/interface";
|
|
2
2
|
import {BeaconConfig} from "@lodestar/config";
|
|
3
|
-
import {GENESIS_SLOT, isForkPostDeneb
|
|
3
|
+
import {GENESIS_SLOT, isForkPostDeneb} from "@lodestar/params";
|
|
4
4
|
import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp";
|
|
5
5
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
6
6
|
import {deneb, phase0} from "@lodestar/types";
|
|
@@ -29,13 +29,20 @@ export async function* onBeaconBlocksByRange(
|
|
|
29
29
|
// starts above it to avoid duplicate yields. See archiveBlocks.ts for the migration logic.
|
|
30
30
|
const archiveMaxSlot = finalizedSlot;
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
// endSlot is exclusive, so highest served slot is endSlot - 1.
|
|
33
|
+
// Throw only when the entire requested range is below earliestAvailableSlot.
|
|
34
|
+
if (endSlot - 1 < chain.earliestAvailableSlot) {
|
|
35
|
+
chain.logger.verbose("Peer requested range before earliestAvailableSlot for BeaconBlocksByRange", {
|
|
35
36
|
peer: prettyPrintPeerId(peerId),
|
|
36
37
|
client: peerClient,
|
|
38
|
+
startSlot,
|
|
39
|
+
count,
|
|
40
|
+
earliestAvailableSlot: chain.earliestAvailableSlot,
|
|
37
41
|
});
|
|
38
|
-
|
|
42
|
+
throw new ResponseError(
|
|
43
|
+
RespStatus.RESOURCE_UNAVAILABLE,
|
|
44
|
+
`Requested range is before earliestAvailableSlot startSlot=${startSlot} count=${count} earliestAvailableSlot=${chain.earliestAvailableSlot}`
|
|
45
|
+
);
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
// Finalized range of blocks
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {PeerId} from "@libp2p/interface";
|
|
2
2
|
import {ChainConfig} from "@lodestar/config";
|
|
3
|
+
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
3
4
|
import {ForkSeq, GENESIS_SLOT} from "@lodestar/params";
|
|
4
5
|
import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp";
|
|
5
6
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
@@ -33,12 +34,20 @@ export async function* onDataColumnSidecarsByRange(
|
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
// endSlot is exclusive, so highest served slot is endSlot - 1.
|
|
38
|
+
// Throw only when the entire requested range is below earliestAvailableSlot.
|
|
39
|
+
if (endSlot - 1 < chain.earliestAvailableSlot) {
|
|
40
|
+
chain.logger.verbose("Peer requested range before earliestAvailableSlot for DataColumnSidecarsByRange", {
|
|
38
41
|
peer: prettyPrintPeerId(peerId),
|
|
39
42
|
client: peerClient,
|
|
43
|
+
startSlot,
|
|
44
|
+
count,
|
|
45
|
+
earliestAvailableSlot: chain.earliestAvailableSlot,
|
|
40
46
|
});
|
|
41
|
-
|
|
47
|
+
throw new ResponseError(
|
|
48
|
+
RespStatus.RESOURCE_UNAVAILABLE,
|
|
49
|
+
`Requested range is before earliestAvailableSlot startSlot=${startSlot} count=${count} earliestAvailableSlot=${chain.earliestAvailableSlot}`
|
|
50
|
+
);
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
const finalized = db.dataColumnSidecarArchive;
|
|
@@ -104,6 +113,11 @@ export async function* onDataColumnSidecarsByRange(
|
|
|
104
113
|
|
|
105
114
|
// Must include only columns in the range requested
|
|
106
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
|
+
|
|
107
121
|
// Note: Here the forkChoice head may change due to a re-org, so the headChain reflects the canonical chain
|
|
108
122
|
// at the time of the start of the request. Spec is clear the chain of columns must be consistent, but on
|
|
109
123
|
// re-org there's no need to abort the request
|
|
@@ -30,7 +30,7 @@ export async function* onDataColumnSidecarsByRoot(
|
|
|
30
30
|
const {blockRoot, columns: requestedColumns} = dataColumnsByRootIdentifier;
|
|
31
31
|
const availableColumns = validateRequestedDataColumns(chain, requestedColumns);
|
|
32
32
|
if (availableColumns.length === 0) {
|
|
33
|
-
|
|
33
|
+
continue;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const blockRootHex = toRootHex(blockRoot);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {PeerId} from "@libp2p/interface";
|
|
1
2
|
import {ChainConfig} from "@lodestar/config";
|
|
2
3
|
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
3
4
|
import {GENESIS_SLOT} from "@lodestar/params";
|
|
@@ -6,23 +7,38 @@ import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
|
6
7
|
import {gloas} from "@lodestar/types";
|
|
7
8
|
import {IBeaconChain} from "../../../chain/index.js";
|
|
8
9
|
import {IBeaconDb} from "../../../db/index.js";
|
|
10
|
+
import {prettyPrintPeerId} from "../../util.js";
|
|
9
11
|
|
|
10
12
|
export async function* onExecutionPayloadEnvelopesByRange(
|
|
11
13
|
request: gloas.ExecutionPayloadEnvelopesByRangeRequest,
|
|
12
14
|
chain: IBeaconChain,
|
|
13
|
-
db: IBeaconDb
|
|
15
|
+
db: IBeaconDb,
|
|
16
|
+
peerId: PeerId,
|
|
17
|
+
peerClient: string
|
|
14
18
|
): AsyncIterable<ResponseOutgoing> {
|
|
15
19
|
const {startSlot, count} = validateExecutionPayloadEnvelopesByRangeRequest(chain.config, request);
|
|
16
20
|
const endSlot = startSlot + count;
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
// endSlot is exclusive, so highest served slot is endSlot - 1.
|
|
23
|
+
// Throw only when the entire requested range is below earliestAvailableSlot.
|
|
24
|
+
if (endSlot - 1 < chain.earliestAvailableSlot) {
|
|
25
|
+
chain.logger.verbose("Peer requested range before earliestAvailableSlot for ExecutionPayloadEnvelopesByRange", {
|
|
26
|
+
peer: prettyPrintPeerId(peerId),
|
|
27
|
+
client: peerClient,
|
|
28
|
+
startSlot,
|
|
29
|
+
count,
|
|
30
|
+
earliestAvailableSlot: chain.earliestAvailableSlot,
|
|
31
|
+
});
|
|
32
|
+
throw new ResponseError(
|
|
33
|
+
RespStatus.RESOURCE_UNAVAILABLE,
|
|
34
|
+
`Requested range is before earliestAvailableSlot startSlot=${startSlot} count=${count} earliestAvailableSlot=${chain.earliestAvailableSlot}`
|
|
35
|
+
);
|
|
20
36
|
}
|
|
21
37
|
|
|
22
38
|
const finalized = db.executionPayloadEnvelopeArchive;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// in the next finalization run
|
|
39
|
+
// Use the finalized block's actual slot as the checkpoint epoch-boundary slot may be skipped
|
|
40
|
+
const finalizedSlot = chain.forkChoice.getFinalizedBlock().slot;
|
|
41
|
+
// The finalized block's envelope stays in the hot db until the next finalization run
|
|
26
42
|
const archiveMaxSlot = finalizedSlot - 1;
|
|
27
43
|
|
|
28
44
|
// Finalized range of envelopes
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import {PeerId} from "@libp2p/interface";
|
|
1
2
|
import {ResponseOutgoing} from "@lodestar/reqresp";
|
|
2
3
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
3
4
|
import {toRootHex} from "@lodestar/utils";
|
|
4
5
|
import {IBeaconChain} from "../../../chain/index.js";
|
|
5
6
|
import {IBeaconDb} from "../../../db/index.js";
|
|
6
7
|
import {ExecutionPayloadEnvelopesByRootRequest} from "../../../util/types.js";
|
|
8
|
+
import {prettyPrintPeerId} from "../../util.js";
|
|
7
9
|
|
|
8
10
|
export async function* onExecutionPayloadEnvelopesByRoot(
|
|
9
11
|
requestBody: ExecutionPayloadEnvelopesByRootRequest,
|
|
10
12
|
chain: IBeaconChain,
|
|
11
|
-
db: IBeaconDb
|
|
13
|
+
db: IBeaconDb,
|
|
14
|
+
peerId: PeerId,
|
|
15
|
+
peerClient: string
|
|
12
16
|
): AsyncIterable<ResponseOutgoing> {
|
|
13
17
|
// The gloas req/resp spec uses MIN_EPOCHS_FOR_BLOCK_REQUESTS to define the minimum range peers MUST serve.
|
|
14
18
|
// Archival nodes may still serve older retained payloads to allow genesis sync.
|
|
@@ -20,6 +24,14 @@ export async function* onExecutionPayloadEnvelopesByRoot(
|
|
|
20
24
|
const slot = block ? block.slot : await db.blockArchive.getSlotByRoot(root);
|
|
21
25
|
|
|
22
26
|
if (slot === null) {
|
|
27
|
+
chain.logger.debug(
|
|
28
|
+
"Cannot serve ExecutionPayloadEnvelopesByRoot: block root not in fork choice or block archive",
|
|
29
|
+
{
|
|
30
|
+
root: rootHex,
|
|
31
|
+
peer: prettyPrintPeerId(peerId),
|
|
32
|
+
client: peerClient,
|
|
33
|
+
}
|
|
34
|
+
);
|
|
23
35
|
continue;
|
|
24
36
|
}
|
|
25
37
|
|
|
@@ -29,6 +41,13 @@ export async function* onExecutionPayloadEnvelopesByRoot(
|
|
|
29
41
|
data: envelopeBytes,
|
|
30
42
|
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(slot)),
|
|
31
43
|
};
|
|
44
|
+
} else {
|
|
45
|
+
chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
|
|
46
|
+
slot,
|
|
47
|
+
root: rootHex,
|
|
48
|
+
peer: prettyPrintPeerId(peerId),
|
|
49
|
+
client: peerClient,
|
|
50
|
+
});
|
|
32
51
|
}
|
|
33
52
|
}
|
|
34
53
|
}
|