@lodestar/beacon-node 1.50.0-dev.ebecebb9ba → 1.50.0-dev.fef46df5ba

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.
Files changed (49) hide show
  1. package/lib/chain/archiveStore/archiveStore.d.ts +1 -0
  2. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  3. package/lib/chain/archiveStore/archiveStore.js +6 -2
  4. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  5. package/lib/chain/archiveStore/utils/pruneHistory.d.ts +4 -1
  6. package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
  7. package/lib/chain/archiveStore/utils/pruneHistory.js +4 -3
  8. package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
  9. package/lib/chain/initState.d.ts +2 -9
  10. package/lib/chain/initState.d.ts.map +1 -1
  11. package/lib/chain/initState.js +5 -38
  12. package/lib/chain/initState.js.map +1 -1
  13. package/lib/db/beacon.d.ts.map +1 -1
  14. package/lib/db/beacon.js +2 -0
  15. package/lib/db/beacon.js.map +1 -1
  16. package/lib/index.d.ts +1 -1
  17. package/lib/index.d.ts.map +1 -1
  18. package/lib/index.js +1 -1
  19. package/lib/index.js.map +1 -1
  20. package/lib/network/metadata.d.ts +1 -1
  21. package/lib/network/metadata.d.ts.map +1 -1
  22. package/lib/network/metadata.js +17 -17
  23. package/lib/network/metadata.js.map +1 -1
  24. package/lib/network/peers/datastore.d.ts +9 -9
  25. package/lib/network/peers/datastore.d.ts.map +1 -1
  26. package/lib/network/peers/datastore.js +36 -36
  27. package/lib/network/peers/datastore.js.map +1 -1
  28. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
  29. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +41 -26
  30. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  31. package/lib/sync/unknownBlock.d.ts +9 -5
  32. package/lib/sync/unknownBlock.d.ts.map +1 -1
  33. package/lib/sync/unknownBlock.js +83 -42
  34. package/lib/sync/unknownBlock.js.map +1 -1
  35. package/lib/util/execution.d.ts +2 -0
  36. package/lib/util/execution.d.ts.map +1 -1
  37. package/lib/util/execution.js +1 -1
  38. package/lib/util/execution.js.map +1 -1
  39. package/package.json +15 -15
  40. package/src/chain/archiveStore/archiveStore.ts +9 -3
  41. package/src/chain/archiveStore/utils/pruneHistory.ts +6 -4
  42. package/src/chain/initState.ts +8 -60
  43. package/src/db/beacon.ts +2 -0
  44. package/src/index.ts +1 -1
  45. package/src/network/metadata.ts +17 -17
  46. package/src/network/peers/datastore.ts +36 -36
  47. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +42 -28
  48. package/src/sync/unknownBlock.ts +94 -46
  49. package/src/util/execution.ts +1 -1
@@ -6,23 +6,23 @@ import { Key } from "interface-datastore";
6
6
  * This has a memory issue because all peer data stays in memory and loaded at startup time
7
7
  * This is written for libp2p >=0.35, we maintain the same mechanism but with bounded data structure
8
8
  * This datastore includes a memory datastore and fallback to db datastore
9
- * Use an in-memory datastore with last accessed time and _maxMemoryItems, on start it's empty (lazy load)
9
+ * Use an in-memory datastore with last accessed time and maxMemoryItems, on start it's empty (lazy load)
10
10
  * - get: Search in-memory datastore first, if not found search from db.
11
11
  * - If found from db, add back to the in-memory datastore
12
12
  * - Update lastAccessedMs
13
- * - put: move oldest items from memory to db if there are more than _maxMemoryItems items in memory
14
- * - update memory datastore, only update db datastore if there are at least _threshold dirty items
13
+ * - put: move oldest items from memory to db if there are more than maxMemoryItems items in memory
14
+ * - update memory datastore, only update db datastore if there are at least threshold dirty items
15
15
  * - Update lastAccessedMs
16
16
  */
17
17
  export class Eth2PeerDataStore extends BaseDatastore {
18
- _dbDatastore;
19
- _memoryDatastore;
18
+ dbDatastore;
19
+ memoryDatastore;
20
20
  /** Same to PersistentPeerStore of the old libp2p implementation */
21
- _dirtyItems = new Set();
21
+ dirtyItems = new Set();
22
22
  /** If there are more dirty items than threshold, commit data to db */
23
- _threshold;
23
+ threshold;
24
24
  /** If there are more memory items than this, prune oldest ones from memory and move to db */
25
- _maxMemoryItems;
25
+ maxMemoryItems;
26
26
  constructor(dbDatastore, { threshold = 5, maxMemoryItems = 50 } = {}) {
27
27
  super();
28
28
  if (threshold <= 0 || maxMemoryItems <= 0) {
@@ -31,31 +31,31 @@ export class Eth2PeerDataStore extends BaseDatastore {
31
31
  if (threshold > maxMemoryItems) {
32
32
  throw Error(`Threshold ${threshold} should be at most maxMemoryItems ${maxMemoryItems}`);
33
33
  }
34
- this._dbDatastore = typeof dbDatastore === "string" ? new LevelDatastore(dbDatastore) : dbDatastore;
35
- this._memoryDatastore = new Map();
36
- this._threshold = threshold;
37
- this._maxMemoryItems = maxMemoryItems;
34
+ this.dbDatastore = typeof dbDatastore === "string" ? new LevelDatastore(dbDatastore) : dbDatastore;
35
+ this.memoryDatastore = new Map();
36
+ this.threshold = threshold;
37
+ this.maxMemoryItems = maxMemoryItems;
38
38
  }
39
39
  async open() {
40
- return this._dbDatastore.open();
40
+ return this.dbDatastore.open();
41
41
  }
42
42
  async close() {
43
- return this._dbDatastore.close();
43
+ return this.dbDatastore.close();
44
44
  }
45
45
  async put(key, val, _options) {
46
46
  return this._put(key, val, false);
47
47
  }
48
48
  /**
49
49
  * Same interface to put with "fromDb" option, if this item is updated back from db
50
- * Move oldest items from memory data store to db if it's over this._maxMemoryItems
50
+ * Move oldest items from memory data store to db if it's over this.maxMemoryItems
51
51
  */
52
52
  async _put(key, val, fromDb = false) {
53
- while (this._memoryDatastore.size >= this._maxMemoryItems) {
53
+ while (this.memoryDatastore.size >= this.maxMemoryItems) {
54
54
  // it's likely this is called only 1 time
55
55
  await this.pruneMemoryDatastore();
56
56
  }
57
57
  const keyStr = key.toString();
58
- const memoryItem = this._memoryDatastore.get(keyStr);
58
+ const memoryItem = this.memoryDatastore.get(keyStr);
59
59
  if (memoryItem) {
60
60
  // update existing
61
61
  memoryItem.lastAccessedMs = Date.now();
@@ -63,7 +63,7 @@ export class Eth2PeerDataStore extends BaseDatastore {
63
63
  }
64
64
  else {
65
65
  // new
66
- this._memoryDatastore.set(keyStr, { data: val, lastAccessedMs: Date.now() });
66
+ this.memoryDatastore.set(keyStr, { data: val, lastAccessedMs: Date.now() });
67
67
  }
68
68
  if (!fromDb)
69
69
  await this._addDirtyItem(keyStr);
@@ -77,14 +77,14 @@ export class Eth2PeerDataStore extends BaseDatastore {
77
77
  */
78
78
  async get(key, options) {
79
79
  const keyStr = key.toString();
80
- const memoryItem = this._memoryDatastore.get(keyStr);
80
+ const memoryItem = this.memoryDatastore.get(keyStr);
81
81
  if (memoryItem) {
82
82
  memoryItem.lastAccessedMs = Date.now();
83
83
  return memoryItem.data;
84
84
  }
85
85
  // this throws error if not found
86
- const dbValue = await this._dbDatastore.get(key, options);
87
- // don't call this._memoryDatastore.set directly
86
+ const dbValue = await this.dbDatastore.get(key, options);
87
+ // don't call this.memoryDatastore.set directly
88
88
  // we want to get through prune() logic with fromDb as true
89
89
  await this._put(key, dbValue, true);
90
90
  return dbValue;
@@ -103,27 +103,27 @@ export class Eth2PeerDataStore extends BaseDatastore {
103
103
  return true;
104
104
  }
105
105
  async delete(key, options) {
106
- this._memoryDatastore.delete(key.toString());
107
- await this._dbDatastore.delete(key, options);
106
+ this.memoryDatastore.delete(key.toString());
107
+ await this.dbDatastore.delete(key, options);
108
108
  }
109
109
  async *_all(q, options) {
110
- for (const [key, value] of this._memoryDatastore.entries()) {
110
+ for (const [key, value] of this.memoryDatastore.entries()) {
111
111
  yield {
112
112
  key: new Key(key),
113
113
  value: value.data,
114
114
  };
115
115
  }
116
- yield* this._dbDatastore.query(q, options);
116
+ yield* this.dbDatastore.query(q, options);
117
117
  }
118
118
  async *_allKeys(q, options) {
119
- for (const key of this._memoryDatastore.keys()) {
119
+ for (const key of this.memoryDatastore.keys()) {
120
120
  yield new Key(key);
121
121
  }
122
- yield* this._dbDatastore.queryKeys(q, options);
122
+ yield* this.dbDatastore.queryKeys(q, options);
123
123
  }
124
124
  async _addDirtyItem(keyStr) {
125
- this._dirtyItems.add(keyStr);
126
- if (this._dirtyItems.size >= this._threshold) {
125
+ this.dirtyItems.add(keyStr);
126
+ if (this.dirtyItems.size >= this.threshold) {
127
127
  try {
128
128
  await this._commitData();
129
129
  }
@@ -131,15 +131,15 @@ export class Eth2PeerDataStore extends BaseDatastore {
131
131
  }
132
132
  }
133
133
  async _commitData() {
134
- const batch = this._dbDatastore.batch();
135
- for (const keyStr of this._dirtyItems) {
136
- const memoryItem = this._memoryDatastore.get(keyStr);
134
+ const batch = this.dbDatastore.batch();
135
+ for (const keyStr of this.dirtyItems) {
136
+ const memoryItem = this.memoryDatastore.get(keyStr);
137
137
  if (memoryItem) {
138
138
  batch.put(new Key(keyStr), memoryItem.data);
139
139
  }
140
140
  }
141
141
  await batch.commit();
142
- this._dirtyItems.clear();
142
+ this.dirtyItems.clear();
143
143
  }
144
144
  /**
145
145
  * Prune from memory and move to db
@@ -148,7 +148,7 @@ export class Eth2PeerDataStore extends BaseDatastore {
148
148
  let oldestAccessedMs = Date.now() + 1000;
149
149
  let oldestKey = undefined;
150
150
  let oldestValue = undefined;
151
- for (const [key, value] of this._memoryDatastore) {
151
+ for (const [key, value] of this.memoryDatastore) {
152
152
  if (value.lastAccessedMs < oldestAccessedMs) {
153
153
  oldestAccessedMs = value.lastAccessedMs;
154
154
  oldestKey = key;
@@ -156,8 +156,8 @@ export class Eth2PeerDataStore extends BaseDatastore {
156
156
  }
157
157
  }
158
158
  if (oldestKey && oldestValue) {
159
- await this._dbDatastore.put(new Key(oldestKey), oldestValue);
160
- this._memoryDatastore.delete(oldestKey);
159
+ await this.dbDatastore.put(new Key(oldestKey), oldestValue);
160
+ this.memoryDatastore.delete(oldestKey);
161
161
  }
162
162
  }
163
163
  }
@@ -1 +1 @@
1
- {"version":3,"file":"datastore.js","sourceRoot":"","sources":["../../../src/network/peers/datastore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"datastore.js","sourceRoot":"","sources":["../../../src/network/peers/datastore.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"executionPayloadEnvelopesByRoot.d.ts","sourceRoot":"","sources":["../../../../src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAA4B,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AAK9E,OAAO,EAAC,YAAY,EAAC,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAC,SAAS,EAAC,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAC,sCAAsC,EAAC,MAAM,wBAAwB,CAAC;AAG9E,wBAAuB,iCAAiC,CACtD,WAAW,EAAE,sCAAsC,EACnD,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,SAAS,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,aAAa,CAAC,gBAAgB,CAAC,CAyDjC"}
1
+ {"version":3,"file":"executionPayloadEnvelopesByRoot.d.ts","sourceRoot":"","sources":["../../../../src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAA4B,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AAK9E,OAAO,EAAC,YAAY,EAAC,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAC,SAAS,EAAC,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EAAC,sCAAsC,EAAC,MAAM,wBAAwB,CAAC;AAG9E,wBAAuB,iCAAiC,CACtD,WAAW,EAAE,sCAAsC,EACnD,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,SAAS,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,aAAa,CAAC,gBAAgB,CAAC,CAsEjC"}
@@ -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 header envelopes are rebuilt in one EL batch, not one call per root
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
- let envelopesBytes;
27
- try {
28
- // by-root allows omission, so a mismatched envelope is left out rather than failing the response
29
- envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(requests, "omit");
30
- }
31
- catch (e) {
32
- if (e instanceof EnvelopeReconstructionError) {
33
- throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, `Failed to reconstruct archived envelopes: ${e.message}`);
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
- throw e;
36
- }
37
- for (let i = 0; i < requests.length; i++) {
38
- const { blockSlot, blockRootHex } = requests[i];
39
- const envelopeBytes = envelopesBytes[i];
40
- if (envelopeBytes) {
41
- yield {
42
- data: envelopeBytes,
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
- else {
47
- chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
48
- slot: blockSlot,
49
- root: blockRootHex,
50
- peer: prettyPrintPeerId(peerId),
51
- client: peerClient,
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;AAI3E,OAAO,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AAEhD,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,iCAAiC,CACtD,WAAmD,EACnD,KAAmB,EACnB,EAAa,EACb,MAAc,EACd,UAAkB;IAElB,2GAA2G;IAC3G,gFAAgF;IAEhF,sGAAsG;IACtG,MAAM,QAAQ,GAA+C,EAAE,CAAC;IAChE,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC;QACjE,qGAAqG;QACrG,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAE5E,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,KAAK,CAAC,MAAM,CAAC,KAAK,CAChB,8FAA8F,EAC9F;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC;gBAC/B,MAAM,EAAE,UAAU;aACnB,CACF,CAAC;YACF,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,cAAqC,CAAC;IAC1C,IAAI,CAAC;QACH,iGAAiG;QACjG,cAAc,GAAG,MAAM,KAAK,CAAC,sCAAsC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxF,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,2BAA2B,EAAE,CAAC;YAC7C,MAAM,IAAI,aAAa,CACrB,UAAU,CAAC,oBAAoB,EAC/B,6CAA6C,CAAC,CAAC,OAAO,EAAE,CACzD,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAC,SAAS,EAAE,YAAY,EAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM;gBACJ,IAAI,EAAE,aAAa;gBACnB,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;aAC7E,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,kEAAkE,EAAE;gBACrF,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC;gBAC/B,MAAM,EAAE,UAAU;aACnB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,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
- * Gets all descendant blocks of `block` recursively from `pendingBlocks`.
161
- * Assumes that if a parent block does not exist or is not processable, all descendant blocks are bad too.
162
- * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
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
- private removePendingPayloadAndDescendants;
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":"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"}
1
+ {"version":3,"file":"unknownBlock.d.ts","sourceRoot":"","sources":["../../src/sync/unknownBlock.ts"],"names":[],"mappings":"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"}
@@ -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, we should penalize all peers sending us this block chain
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.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
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
- // the peer served a bad block
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.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
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.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
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
- blockRoot: rootHex,
1662
+ slot: getBlockInputSyncCacheItemSlot(block),
1663
+ root: rootHex,
1623
1664
  });
1624
1665
  }
1625
1666
  return badPendingBlocks;