@lodestar/beacon-node 1.50.0-dev.9e2fc57acd → 1.50.0-dev.a28be61ecb
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/pool/index.js +4 -4
- package/lib/api/impl/beacon/pool/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 +6 -2
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts +4 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js +4 -3
- package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +4 -0
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/chain.js +3 -3
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/gossipValidation.d.ts +2 -1
- package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
- package/lib/chain/errors/gossipValidation.js +1 -0
- package/lib/chain/errors/gossipValidation.js.map +1 -1
- package/lib/chain/initState.d.ts +2 -9
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +5 -38
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/opPools/opPool.d.ts +5 -4
- package/lib/chain/opPools/opPool.d.ts.map +1 -1
- package/lib/chain/opPools/opPool.js +62 -18
- package/lib/chain/opPools/opPool.js.map +1 -1
- package/lib/chain/opPools/utils.d.ts +4 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +11 -1
- package/lib/chain/opPools/utils.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts +4 -4
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +3 -0
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.d.ts +3 -3
- package/lib/chain/validation/proposerSlashing.d.ts.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +3 -0
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +2 -0
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/repositories/proposerSlashing.d.ts +1 -0
- package/lib/db/repositories/proposerSlashing.d.ts.map +1 -1
- package/lib/db/repositories/proposerSlashing.js +5 -1
- package/lib/db/repositories/proposerSlashing.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/network/processor/gossipHandlers.js +4 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipValidatorFn.d.ts +3 -1
- package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
- package/lib/network/processor/gossipValidatorFn.js +1 -1
- package/lib/network/processor/gossipValidatorFn.js.map +1 -1
- package/lib/network/processor/index.d.ts +1 -0
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +28 -8
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +41 -26
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +9 -5
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +83 -42
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/execution.d.ts +2 -0
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +1 -1
- package/lib/util/execution.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/pool/index.ts +4 -4
- package/src/chain/archiveStore/archiveStore.ts +9 -3
- package/src/chain/archiveStore/utils/pruneHistory.ts +6 -4
- package/src/chain/blocks/importBlock.ts +4 -0
- package/src/chain/chain.ts +3 -3
- package/src/chain/errors/gossipValidation.ts +1 -0
- package/src/chain/initState.ts +8 -60
- package/src/chain/opPools/opPool.ts +91 -18
- package/src/chain/opPools/utils.ts +31 -3
- package/src/chain/validation/attesterSlashing.ts +7 -4
- package/src/chain/validation/proposerSlashing.ts +7 -4
- package/src/db/beacon.ts +2 -0
- package/src/db/repositories/proposerSlashing.ts +6 -1
- package/src/index.ts +1 -1
- package/src/network/processor/gossipHandlers.ts +4 -4
- package/src/network/processor/gossipValidatorFn.ts +1 -1
- package/src/network/processor/index.ts +34 -8
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +42 -28
- package/src/sync/unknownBlock.ts +94 -46
- package/src/util/execution.ts +1 -1
|
@@ -2,14 +2,20 @@ import { RespStatus, ResponseError } from "@lodestar/reqresp";
|
|
|
2
2
|
import { computeEpochAtSlot } from "@lodestar/state-transition";
|
|
3
3
|
import { toRootHex } from "@lodestar/utils";
|
|
4
4
|
import { EnvelopeReconstructionError } from "../../../chain/errors/index.js";
|
|
5
|
+
import { MAX_BODIES_PER_REQUEST } from "../../../util/execution.js";
|
|
5
6
|
import { prettyPrintPeerId } from "../../util.js";
|
|
6
7
|
export async function* onExecutionPayloadEnvelopesByRoot(requestBody, chain, db, peerId, peerClient) {
|
|
7
8
|
// The gloas req/resp spec uses MIN_EPOCHS_FOR_BLOCK_REQUESTS to define the minimum range peers MUST serve.
|
|
8
9
|
// Archival nodes may still serve older retained payloads to allow genesis sync.
|
|
9
|
-
// Resolve slots first so archived
|
|
10
|
+
// Resolve slots first so archived envelopes can be reconstructed in EL batches.
|
|
11
|
+
// Duplicate roots are served once, since each archived envelope costs an EL fetch and a rebuild.
|
|
10
12
|
const requests = [];
|
|
13
|
+
const seenRoots = new Set();
|
|
11
14
|
for (const root of requestBody) {
|
|
12
15
|
const rootHex = toRootHex(root);
|
|
16
|
+
if (seenRoots.has(rootHex))
|
|
17
|
+
continue;
|
|
18
|
+
seenRoots.add(rootHex);
|
|
13
19
|
const block = chain.forkChoice.getBlockHexDefaultStatus(rootHex);
|
|
14
20
|
// If the block is not in fork choice, it may be finalized. Attempt to find its slot in block archive
|
|
15
21
|
const slot = block ? block.slot : await db.blockArchive.getSlotByRoot(root);
|
|
@@ -23,33 +29,42 @@ export async function* onExecutionPayloadEnvelopesByRoot(requestBody, chain, db,
|
|
|
23
29
|
}
|
|
24
30
|
requests.push({ blockSlot: slot, blockRootHex: rootHex });
|
|
25
31
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// Yield between EL batches so the first response does not wait for the entire request.
|
|
33
|
+
let yielded = 0;
|
|
34
|
+
for (let i = 0; i < requests.length; i += MAX_BODIES_PER_REQUEST) {
|
|
35
|
+
const batch = requests.slice(i, i + MAX_BODIES_PER_REQUEST);
|
|
36
|
+
let envelopesBytes;
|
|
37
|
+
try {
|
|
38
|
+
// By-root allows omission, so a mismatched envelope is left out rather than failing the response.
|
|
39
|
+
envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(batch, "omit");
|
|
34
40
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(blockSlot)),
|
|
44
|
-
};
|
|
41
|
+
catch (e) {
|
|
42
|
+
if (e instanceof EnvelopeReconstructionError) {
|
|
43
|
+
// By-root permits partial responses, so an EL failure can end the response here.
|
|
44
|
+
if (yielded > 0)
|
|
45
|
+
return;
|
|
46
|
+
throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, `Failed to reconstruct archived envelopes: ${e.message}`);
|
|
47
|
+
}
|
|
48
|
+
throw e;
|
|
45
49
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
for (let j = 0; j < batch.length; j++) {
|
|
51
|
+
const { blockSlot, blockRootHex } = batch[j];
|
|
52
|
+
const envelopeBytes = envelopesBytes[j];
|
|
53
|
+
if (envelopeBytes) {
|
|
54
|
+
yielded++;
|
|
55
|
+
yield {
|
|
56
|
+
data: envelopeBytes,
|
|
57
|
+
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(blockSlot)),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
|
|
62
|
+
slot: blockSlot,
|
|
63
|
+
root: blockRootHex,
|
|
64
|
+
peer: prettyPrintPeerId(peerId),
|
|
65
|
+
client: peerClient,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
53
68
|
}
|
|
54
69
|
}
|
|
55
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executionPayloadEnvelopesByRoot.js","sourceRoot":"","sources":["../../../../src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,UAAU,EAAE,aAAa,EAAmB,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAC,kBAAkB,EAAC,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAC,2BAA2B,EAAC,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"executionPayloadEnvelopesByRoot.js","sourceRoot":"","sources":["../../../../src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts"],"names":[],"mappings":"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"}
|
|
@@ -156,14 +156,18 @@ export declare class BlockInputSync {
|
|
|
156
156
|
* Also verifies the received block root + returns the peer that provided the block for future downscoring.
|
|
157
157
|
*/
|
|
158
158
|
private fetchBlockInput;
|
|
159
|
+
private removePendingPayloadAndDescendants;
|
|
159
160
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* referenced more than one bad block.
|
|
161
|
+
* Same as `removeAndBanAllDescendants`, and downscores every peer that referenced or served a banned item, once per
|
|
162
|
+
* peer. Only call for consensus-layer invalidity, never for an INVALID execution payload:
|
|
163
|
+
* https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
|
|
164
164
|
*/
|
|
165
165
|
private removeAndDownScoreAllDescendants;
|
|
166
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Removes `block` and all its pending descendants and bans their roots in `knownBadBlocks`. Only call when the chain
|
|
168
|
+
* is provably bad: a banned root is never searched for again. Returns the banned items.
|
|
169
|
+
*/
|
|
170
|
+
private removeAndBanAllDescendants;
|
|
167
171
|
private removeAllDescendants;
|
|
168
172
|
private getMaxDownloadAttempts;
|
|
169
173
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unknownBlock.d.ts","sourceRoot":"","sources":["../../src/sync/unknownBlock.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAMjD,OAAO,EAAC,MAAM,EAA+E,MAAM,iBAAiB,CAAC;AAMrH,OAAO,EAA6B,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAG3E,OAAO,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAC,QAAQ,
|
|
1
|
+
{"version":3,"file":"unknownBlock.d.ts","sourceRoot":"","sources":["../../src/sync/unknownBlock.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAMjD,OAAO,EAAC,MAAM,EAA+E,MAAM,iBAAiB,CAAC;AAMrH,OAAO,EAA6B,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAG3E,OAAO,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAC,QAAQ,EAAmE,MAAM,qBAAqB,CAAC;AAC/G,OAAO,EAAC,YAAY,EAAC,MAAM,+BAA+B,CAAC;AAG3D,OAAO,EAAC,SAAS,EAAC,MAAM,mBAAmB,CAAC;AAK5C,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAmCzC;;GAEG;AACH,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAiB9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,cAAc;IAmBvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IAvBxB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAE7E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4C;IAC5E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAsB;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAClC,OAAO,CAAC,yBAAyB,CAAS;IAC1C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,uBAAuB,CAA6B;IAC5D;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAgF;IACrH,OAAO,CAAC,0BAA0B,CAA8B;IAEhE,YACmB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,IAAI,CAAC,EAAE,WAAW,YAAA,EAgBpC;IAED,kBAAkB,IAAI,IAAI,CAoCzB;IAED,sBAAsB,IAAI,IAAI,CAoB7B;IAED,KAAK,IAAI,IAAI,CAEZ;IAED,qBAAqB,IAAI,OAAO,CAE/B;IAED;;OAEG;IACH,OAAO,CAAC,kBAAkB,CAcxB;IAEF;;OAEG;IACH,OAAO,CAAC,sBAAsB,CAS5B;IAEF,OAAO,CAAC,0BAA0B,CAWhC;IAEF,OAAO,CAAC,8BAA8B,CAyBpC;IAEF,OAAO,CAAC,2BAA2B,CASjC;IAEF;;OAEG;IACH,OAAO,CAAC,eAAe,CA+BrB;IAEF,OAAO,CAAC,eAAe,CAIrB;IAEF,OAAO,CAAC,iBAAiB,CAKvB;IAEF;;;OAGG;IACH,OAAO,CAAC,cAAc,CAiFpB;IAEF,OAAO,CAAC,YAAY,CAsClB;IAEF,OAAO,CAAC,eAAe,CAuCrB;IAEF,OAAO,CAAC,mBAAmB,CAgDzB;IAEF;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,iBAAiB,CAqCvB;IAEF,OAAO,CAAC,eAAe,CASrB;IAEF,OAAO,CAAC,kBAAkB,CAIxB;IAEF;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAoCjC,OAAO,CAAC,mBAAmB;IAuC3B,OAAO,CAAC,qBAAqB;IA0B7B;;OAEG;IACH,OAAO,CAAC,yBAAyB,CAwF/B;IAEF,OAAO,CAAC,6BAA6B;IAuBrC,OAAO,CAAC,0BAA0B;IAOlC;;;OAGG;IACH,OAAO,CAAC,sBAAsB,CAqB5B;IAEF;;OAEG;YACW,kBAAkB;IA8EhC,OAAO,CAAC,sBAAsB;YAQhB,aAAa;IAmG3B;;;OAGG;YACW,iBAAiB;IA+H/B;;;;OAIG;YACW,wBAAwB;YAqExB,eAAe;YAmEf,cAAc;IA0F5B;;;;OAIG;YACW,iBAAiB;YAoLjB,6BAA6B;YAmB7B,mBAAmB;IAwCjC;;;;;;;;OAQG;YACW,eAAe;IAyK7B,OAAO,CAAC,kCAAkC;IAyB1C;;;;OAIG;IACH,OAAO,CAAC,gCAAgC;IAaxC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IA2BlC,OAAO,CAAC,oBAAoB;IA8B5B,OAAO,CAAC,sBAAsB;CAY/B;AAED;;GAEG;AACH,qBAAa,wBAAwB;IACnC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACjD,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChD,QAAQ,CAAC,sBAAsB,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAExD,cAIC;IAED,qCAAqC;IACrC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAM/D;IAED,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAI1C;IAED,4FAA4F;IAC5F,KAAK,IAAI,IAAI,CAIZ;IAED,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAEjE;IAED,uBAAuB,CAAC,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,IAAI,CA4BnG;IAED;;;;;;OAMG;IACH,yBAAyB,CACvB,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,aAAa,EAAE,GAAG,CAAC,SAAS,CAAC,EAC7B,cAAc,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,GAC9B,YAAY,GAAG,IAAI,CAiBrB;IAED;;;OAGG;IACH,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAEjC;IAED;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAE1C;IAED,sBAAsB,IAAI,MAAM,CAM/B;IAED,OAAO,CAAC,WAAW;IA8DnB,OAAO,CAAC,qBAAqB;CAO9B"}
|
package/lib/sync/unknownBlock.js
CHANGED
|
@@ -11,7 +11,7 @@ import { BlockError, BlockErrorCode } from "../chain/errors/index.js";
|
|
|
11
11
|
import { ChainEvent } from "../chain/index.js";
|
|
12
12
|
import { validateGloasBlockDataColumnSidecars } from "../chain/validation/dataColumnSidecar.js";
|
|
13
13
|
import { validateGossipExecutionPayloadEnvelope } from "../chain/validation/executionPayloadEnvelope.js";
|
|
14
|
-
import { NetworkEvent, prettyPrintPeerIdStr } from "../network/index.js";
|
|
14
|
+
import { NetworkEvent, PeerAction, prettyPrintPeerIdStr } from "../network/index.js";
|
|
15
15
|
import { MAX_PEERS_PER_ROOT } from "../network/processor/constants.js";
|
|
16
16
|
import { ClockEvent } from "../util/clock.js";
|
|
17
17
|
import { shuffle } from "../util/shuffle.js";
|
|
@@ -378,6 +378,10 @@ export class BlockInputSync {
|
|
|
378
378
|
});
|
|
379
379
|
};
|
|
380
380
|
addByRootHex = (rootHex, peerIdStr) => {
|
|
381
|
+
if (this.knownBadBlocks.has(rootHex)) {
|
|
382
|
+
this.logger.debug("Ignoring known bad block root", { root: rootHex, peerIdStr: peerIdStr ?? "unknown peer" });
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
381
385
|
let pendingBlock = this.pendingBlocks.get(rootHex);
|
|
382
386
|
let added = false;
|
|
383
387
|
if (!pendingBlock) {
|
|
@@ -409,6 +413,10 @@ export class BlockInputSync {
|
|
|
409
413
|
return added;
|
|
410
414
|
};
|
|
411
415
|
addByBlockInput = (blockInput, peerIdStr) => {
|
|
416
|
+
if (this.knownBadBlocks.has(blockInput.blockRootHex)) {
|
|
417
|
+
this.logger.debug("Ignoring known bad block", { slot: blockInput.slot, root: blockInput.blockRootHex, peerIdStr });
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
412
420
|
let pendingBlock = this.pendingBlocks.get(blockInput.blockRootHex);
|
|
413
421
|
// if entry is missing or was added via rootHex and now we have more complete information overwrite
|
|
414
422
|
// the existing information with the more complete cache entry
|
|
@@ -441,6 +449,14 @@ export class BlockInputSync {
|
|
|
441
449
|
}
|
|
442
450
|
};
|
|
443
451
|
addByPayloadRootHex = (rootHex, peerIdStr, slot) => {
|
|
452
|
+
if (this.knownBadBlocks.has(rootHex)) {
|
|
453
|
+
this.logger.debug("Ignoring payload for known bad block root", {
|
|
454
|
+
slot: slot ?? "unknown",
|
|
455
|
+
root: rootHex,
|
|
456
|
+
peerIdStr,
|
|
457
|
+
});
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
444
460
|
let pendingPayload = this.pendingPayloads.get(rootHex);
|
|
445
461
|
let added = false;
|
|
446
462
|
if (!pendingPayload) {
|
|
@@ -499,6 +515,14 @@ export class BlockInputSync {
|
|
|
499
515
|
return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
|
|
500
516
|
}
|
|
501
517
|
addByPayloadInput = (payloadInput, peerIdStr, envelope) => {
|
|
518
|
+
if (this.knownBadBlocks.has(payloadInput.blockRootHex)) {
|
|
519
|
+
this.logger.debug("Ignoring payload input for known bad block root", {
|
|
520
|
+
slot: payloadInput.slot,
|
|
521
|
+
root: payloadInput.blockRootHex,
|
|
522
|
+
peerIdStr,
|
|
523
|
+
});
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
502
526
|
const pendingPayload = this.toPendingPayloadInput(payloadInput, this.pendingPayloads.get(payloadInput.blockRootHex), envelope);
|
|
503
527
|
if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
|
|
504
528
|
pendingPayload.peerIdStrings.add(peerIdStr);
|
|
@@ -552,6 +576,7 @@ export class BlockInputSync {
|
|
|
552
576
|
if (this.chain.forkChoice.getBlockHexAndBlockHash(parentRootHex, parentBlockHashHex) !== null) {
|
|
553
577
|
return { kind: "ready" };
|
|
554
578
|
}
|
|
579
|
+
// The parent's payload is known but does not match `parentBlockHashHex`
|
|
555
580
|
if (this.chain.forkChoice.hasPayloadHexUnsafe(parentRootHex)) {
|
|
556
581
|
return { kind: "invalidParentPayload", parentRootHex, parentBlockHashHex };
|
|
557
582
|
}
|
|
@@ -882,7 +907,8 @@ export class BlockInputSync {
|
|
|
882
907
|
}
|
|
883
908
|
else if (blockSlot <= finalizedSlot) {
|
|
884
909
|
// the common ancestor of the downloading chain and canonical chain should be at least the finalized slot and
|
|
885
|
-
// we should found it through forkchoice. If not,
|
|
910
|
+
// we should found it through forkchoice. If not, drop the chain without penalizing peers because pending entries are
|
|
911
|
+
// block retained on failed download, so finalization can pass the block while it is still pending
|
|
886
912
|
// 0 - 1 - ... - n - finalizedSlot
|
|
887
913
|
// \
|
|
888
914
|
// parent 1 - parent 2 - ... - unknownParent block
|
|
@@ -890,7 +916,7 @@ export class BlockInputSync {
|
|
|
890
916
|
...logCtx2,
|
|
891
917
|
finalizedSlot,
|
|
892
918
|
});
|
|
893
|
-
this.
|
|
919
|
+
this.removeAllDescendants(block, DroppedItemReason.belowFinalized);
|
|
894
920
|
}
|
|
895
921
|
else {
|
|
896
922
|
this.onUnknownBlockRoot({ rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot });
|
|
@@ -1009,14 +1035,17 @@ export class BlockInputSync {
|
|
|
1009
1035
|
this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
|
|
1010
1036
|
break;
|
|
1011
1037
|
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
1012
|
-
//
|
|
1038
|
+
// Ban but do not downscore: optimistic-sync peers may forward and serve blocks whose payload is later
|
|
1039
|
+
// rejected by the execution engine. Per the spec, an INVALID execution payload SHOULD NOT cause a peer
|
|
1040
|
+
// to be down-scored or disconnected, only consensus-layer invalidity MAY.
|
|
1041
|
+
// https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
|
|
1013
1042
|
this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
|
|
1014
|
-
this.
|
|
1043
|
+
this.removeAndBanAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
|
|
1015
1044
|
break;
|
|
1016
1045
|
default:
|
|
1017
1046
|
// Block is not correct with respect to our chain. Log error loudly
|
|
1018
1047
|
this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
|
|
1019
|
-
this.
|
|
1048
|
+
this.removeAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
|
|
1020
1049
|
}
|
|
1021
1050
|
}
|
|
1022
1051
|
// Probably a queue error or something unwanted happened, mark as pending to try again latter
|
|
@@ -1254,10 +1283,10 @@ export class BlockInputSync {
|
|
|
1254
1283
|
throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
|
|
1255
1284
|
}
|
|
1256
1285
|
const { peerId, client: peerClient } = peerMeta;
|
|
1257
|
-
cacheItem.peerIdStrings.add(peerId);
|
|
1258
1286
|
try {
|
|
1259
1287
|
if (!envelope) {
|
|
1260
1288
|
envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
|
|
1289
|
+
cacheItem.peerIdStrings.add(peerId);
|
|
1261
1290
|
const slotWasUnknown = typeof slot !== "number";
|
|
1262
1291
|
slot = envelope.message.payload.slotNumber;
|
|
1263
1292
|
if (slotWasUnknown) {
|
|
@@ -1292,6 +1321,8 @@ export class BlockInputSync {
|
|
|
1292
1321
|
const missing = pendingPayload.payloadInput.getMissingSampledColumnMeta().missing;
|
|
1293
1322
|
if (missing.length > 0) {
|
|
1294
1323
|
const columnSidecars = await this.fetchPayloadColumns(peerMeta, pendingPayload.payloadInput, missing);
|
|
1324
|
+
// toPendingPayloadInput copied cacheItem's set, so add to the object that is carried forward
|
|
1325
|
+
pendingPayload.peerIdStrings.add(peerId);
|
|
1295
1326
|
const seenTimestampSec = Date.now() / 1000;
|
|
1296
1327
|
for (const columnSidecar of columnSidecars) {
|
|
1297
1328
|
if (pendingPayload.payloadInput.hasColumn(columnSidecar.index)) {
|
|
@@ -1433,7 +1464,6 @@ export class BlockInputSync {
|
|
|
1433
1464
|
throw Error(message);
|
|
1434
1465
|
}
|
|
1435
1466
|
const { peerId, client: peerClient } = peerMeta;
|
|
1436
|
-
cacheItem.peerIdStrings.add(peerId);
|
|
1437
1467
|
try {
|
|
1438
1468
|
const downloadResult = await downloadByRoot({
|
|
1439
1469
|
config: this.config,
|
|
@@ -1444,6 +1474,7 @@ export class BlockInputSync {
|
|
|
1444
1474
|
cacheItem,
|
|
1445
1475
|
});
|
|
1446
1476
|
cacheItem = downloadResult.result;
|
|
1477
|
+
cacheItem.peerIdStrings.add(peerId);
|
|
1447
1478
|
if (slot === undefined) {
|
|
1448
1479
|
slot = cacheItem.blockInput.slot;
|
|
1449
1480
|
// we were not able to observe the time into slot when starting the fetch, do it now
|
|
@@ -1545,37 +1576,6 @@ export class BlockInputSync {
|
|
|
1545
1576
|
this.metrics?.blockInputSync.fetchPeers.set({ result: FetchResult.FailureMaxAttempts }, i - 1);
|
|
1546
1577
|
throw Error(message);
|
|
1547
1578
|
}
|
|
1548
|
-
/**
|
|
1549
|
-
* Gets all descendant blocks of `block` recursively from `pendingBlocks`.
|
|
1550
|
-
* Assumes that if a parent block does not exist or is not processable, all descendant blocks are bad too.
|
|
1551
|
-
* Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
|
|
1552
|
-
* referenced more than one bad block.
|
|
1553
|
-
*/
|
|
1554
|
-
removeAndDownScoreAllDescendants(block, headReason) {
|
|
1555
|
-
// Get all blocks that are a descendant of this one
|
|
1556
|
-
const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
|
|
1557
|
-
// just console log and do not penalize on pending/bad blocks for debugging
|
|
1558
|
-
// console.log("removeAndDownscoreAllDescendants", {block});
|
|
1559
|
-
for (const block of badPendingBlocks) {
|
|
1560
|
-
//
|
|
1561
|
-
// TODO(fulu): why is this commented out here?
|
|
1562
|
-
//
|
|
1563
|
-
// this.knownBadBlocks.add(block.blockRootHex);
|
|
1564
|
-
// for (const peerIdStr of block.peerIdStrings) {
|
|
1565
|
-
// // TODO: Refactor peerRpcScores to work with peerIdStr only
|
|
1566
|
-
// this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadBlockByRoot");
|
|
1567
|
-
// }
|
|
1568
|
-
this.logger.debug("ignored Banning unknown block", {
|
|
1569
|
-
slot: getBlockInputSyncCacheItemSlot(block),
|
|
1570
|
-
root: getBlockInputSyncCacheItemRootHex(block),
|
|
1571
|
-
peerIdStrings: Array.from(block.peerIdStrings)
|
|
1572
|
-
.map((id) => prettyPrintPeerIdStr(id))
|
|
1573
|
-
.join(","),
|
|
1574
|
-
});
|
|
1575
|
-
}
|
|
1576
|
-
// Prune knownBadBlocks
|
|
1577
|
-
pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
|
|
1578
|
-
}
|
|
1579
1579
|
// Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
|
|
1580
1580
|
removePendingPayloadAndDescendants(rootHex, headReason) {
|
|
1581
1581
|
// Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
|
|
@@ -1600,9 +1600,50 @@ export class BlockInputSync {
|
|
|
1600
1600
|
});
|
|
1601
1601
|
}
|
|
1602
1602
|
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Same as `removeAndBanAllDescendants`, and downscores every peer that referenced or served a banned item, once per
|
|
1605
|
+
* peer. Only call for consensus-layer invalidity, never for an INVALID execution payload:
|
|
1606
|
+
* https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
|
|
1607
|
+
*/
|
|
1608
|
+
removeAndDownScoreAllDescendants(block, headReason) {
|
|
1609
|
+
const peersToReport = new Set();
|
|
1610
|
+
for (const bannedBlock of this.removeAndBanAllDescendants(block, headReason)) {
|
|
1611
|
+
for (const peerIdStr of bannedBlock.peerIdStrings) {
|
|
1612
|
+
peersToReport.add(peerIdStr);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
for (const peerIdStr of peersToReport) {
|
|
1616
|
+
this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, headReason);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* Removes `block` and all its pending descendants and bans their roots in `knownBadBlocks`. Only call when the chain
|
|
1621
|
+
* is provably bad: a banned root is never searched for again. Returns the banned items.
|
|
1622
|
+
*/
|
|
1623
|
+
removeAndBanAllDescendants(block, headReason) {
|
|
1624
|
+
const bannedBlocks = [];
|
|
1625
|
+
for (const badBlock of this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent)) {
|
|
1626
|
+
const rootHex = getBlockInputSyncCacheItemRootHex(badBlock);
|
|
1627
|
+
// a gossip import may race a failing sync path, never ban a root fork choice has imported
|
|
1628
|
+
if (this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
1629
|
+
continue;
|
|
1630
|
+
}
|
|
1631
|
+
this.knownBadBlocks.add(rootHex);
|
|
1632
|
+
bannedBlocks.push(badBlock);
|
|
1633
|
+
this.logger.debug("Banning unknown block", {
|
|
1634
|
+
slot: getBlockInputSyncCacheItemSlot(badBlock),
|
|
1635
|
+
root: rootHex,
|
|
1636
|
+
reason: headReason,
|
|
1637
|
+
peerIdStrings: Array.from(badBlock.peerIdStrings)
|
|
1638
|
+
.map((id) => prettyPrintPeerIdStr(id))
|
|
1639
|
+
.join(","),
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
|
|
1643
|
+
return bannedBlocks;
|
|
1644
|
+
}
|
|
1603
1645
|
removeAllDescendants(block, headReason, descendantReason = DroppedItemReason.invalidParent) {
|
|
1604
1646
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1605
|
-
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
1606
1647
|
// Get all blocks that are a descendant of this one (index 0 is the head item itself)
|
|
1607
1648
|
const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
|
|
1608
1649
|
for (const [i, block] of badPendingBlocks.entries()) {
|
|
@@ -1618,8 +1659,8 @@ export class BlockInputSync {
|
|
|
1618
1659
|
// Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
|
|
1619
1660
|
// importBlock()-owned lifecycle.
|
|
1620
1661
|
this.logger.debug("Removing bad/unknown/incomplete BlockInputSyncCacheItem", {
|
|
1621
|
-
slot,
|
|
1622
|
-
|
|
1662
|
+
slot: getBlockInputSyncCacheItemSlot(block),
|
|
1663
|
+
root: rootHex,
|
|
1623
1664
|
});
|
|
1624
1665
|
}
|
|
1625
1666
|
return badPendingBlocks;
|