@lodestar/beacon-node 1.47.0-dev.7481aa5850 → 1.47.0-dev.7aa8c9c93a

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 (237) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +3 -2
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +8 -1
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +2 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  10. package/lib/api/impl/events/index.d.ts +1 -1
  11. package/lib/api/impl/events/index.d.ts.map +1 -1
  12. package/lib/api/impl/events/index.js +12 -3
  13. package/lib/api/impl/events/index.js.map +1 -1
  14. package/lib/api/rest/base.d.ts.map +1 -1
  15. package/lib/api/rest/base.js +7 -0
  16. package/lib/api/rest/base.js.map +1 -1
  17. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  18. package/lib/chain/blocks/importBlock.js +2 -7
  19. package/lib/chain/blocks/importBlock.js.map +1 -1
  20. package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
  21. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  22. package/lib/chain/blocks/importExecutionPayload.js +11 -9
  23. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  24. package/lib/chain/blocks/index.d.ts.map +1 -1
  25. package/lib/chain/blocks/index.js +14 -6
  26. package/lib/chain/blocks/index.js.map +1 -1
  27. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
  28. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  29. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
  30. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  31. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
  32. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  33. package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
  34. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
  35. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  36. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
  37. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  38. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  39. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  40. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  41. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  42. package/lib/chain/bls/index.d.ts +1 -1
  43. package/lib/chain/bls/index.d.ts.map +1 -1
  44. package/lib/chain/bls/interface.d.ts +5 -5
  45. package/lib/chain/bls/interface.d.ts.map +1 -1
  46. package/lib/chain/bls/multithread/index.d.ts +5 -11
  47. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  48. package/lib/chain/bls/multithread/index.js +116 -101
  49. package/lib/chain/bls/multithread/index.js.map +1 -1
  50. package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
  51. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  52. package/lib/chain/bls/multithread/jobItem.js +10 -65
  53. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  54. package/lib/chain/bls/multithread/types.d.ts +29 -8
  55. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  56. package/lib/chain/bls/multithread/types.js +12 -0
  57. package/lib/chain/bls/multithread/types.js.map +1 -1
  58. package/lib/chain/bls/multithread/utils.d.ts +4 -0
  59. package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
  60. package/lib/chain/bls/multithread/utils.js +10 -0
  61. package/lib/chain/bls/multithread/utils.js.map +1 -1
  62. package/lib/chain/bls/multithread/worker.js +49 -23
  63. package/lib/chain/bls/multithread/worker.js.map +1 -1
  64. package/lib/chain/bls/singleThread.d.ts +4 -10
  65. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  66. package/lib/chain/bls/singleThread.js +8 -45
  67. package/lib/chain/bls/singleThread.js.map +1 -1
  68. package/lib/chain/bls/utils.d.ts +4 -4
  69. package/lib/chain/bls/utils.d.ts.map +1 -1
  70. package/lib/chain/bls/utils.js +18 -19
  71. package/lib/chain/bls/utils.js.map +1 -1
  72. package/lib/chain/chain.d.ts +2 -1
  73. package/lib/chain/chain.d.ts.map +1 -1
  74. package/lib/chain/chain.js +12 -5
  75. package/lib/chain/chain.js.map +1 -1
  76. package/lib/chain/errors/blockError.d.ts +1 -0
  77. package/lib/chain/errors/blockError.d.ts.map +1 -1
  78. package/lib/chain/errors/blockError.js +6 -1
  79. package/lib/chain/errors/blockError.js.map +1 -1
  80. package/lib/chain/errors/proposerPreferences.d.ts +6 -0
  81. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
  82. package/lib/chain/errors/proposerPreferences.js +1 -0
  83. package/lib/chain/errors/proposerPreferences.js.map +1 -1
  84. package/lib/chain/interface.d.ts +2 -1
  85. package/lib/chain/interface.d.ts.map +1 -1
  86. package/lib/chain/interface.js.map +1 -1
  87. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  88. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  89. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  90. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  91. package/lib/chain/opPools/attestationPool.js +1 -1
  92. package/lib/chain/opPools/attestationPool.js.map +1 -1
  93. package/lib/chain/opPools/payloadAttestationPool.js +3 -3
  94. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  95. package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
  96. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  97. package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
  98. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  99. package/lib/chain/opPools/utils.d.ts +1 -1
  100. package/lib/chain/opPools/utils.d.ts.map +1 -1
  101. package/lib/chain/opPools/utils.js +1 -1
  102. package/lib/chain/opPools/utils.js.map +1 -1
  103. package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
  104. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  105. package/lib/chain/seenCache/seenAttesters.js +25 -4
  106. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  107. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +30 -1
  108. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  109. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +123 -13
  110. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  111. package/lib/chain/validation/attestation.d.ts.map +1 -1
  112. package/lib/chain/validation/attestation.js +1 -4
  113. package/lib/chain/validation/attestation.js.map +1 -1
  114. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  115. package/lib/chain/validation/attesterSlashing.js +1 -1
  116. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  117. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  118. package/lib/chain/validation/executionPayloadBid.js +1 -2
  119. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  120. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  121. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  122. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  123. package/lib/chain/validation/payloadAttestationMessage.js +5 -14
  124. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  125. package/lib/chain/validation/proposerPreferences.d.ts +1 -1
  126. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
  127. package/lib/chain/validation/proposerPreferences.js +13 -4
  128. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  129. package/lib/chain/validation/proposerSlashing.js +1 -1
  130. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  131. package/lib/metrics/metrics/lodestar.d.ts +45 -20
  132. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  133. package/lib/metrics/metrics/lodestar.js +87 -51
  134. package/lib/metrics/metrics/lodestar.js.map +1 -1
  135. package/lib/network/gossip/topic.d.ts +13 -0
  136. package/lib/network/gossip/topic.d.ts.map +1 -1
  137. package/lib/network/gossip/topic.js +37 -0
  138. package/lib/network/gossip/topic.js.map +1 -1
  139. package/lib/network/libp2p/index.d.ts.map +1 -1
  140. package/lib/network/libp2p/index.js +10 -2
  141. package/lib/network/libp2p/index.js.map +1 -1
  142. package/lib/network/network.d.ts.map +1 -1
  143. package/lib/network/network.js +22 -43
  144. package/lib/network/network.js.map +1 -1
  145. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  146. package/lib/network/processor/gossipHandlers.js +5 -1
  147. package/lib/network/processor/gossipHandlers.js.map +1 -1
  148. package/lib/network/reqresp/score.d.ts.map +1 -1
  149. package/lib/network/reqresp/score.js +5 -11
  150. package/lib/network/reqresp/score.js.map +1 -1
  151. package/lib/network/util.d.ts +0 -1
  152. package/lib/network/util.d.ts.map +1 -1
  153. package/lib/network/util.js +0 -4
  154. package/lib/network/util.js.map +1 -1
  155. package/lib/node/nodejs.d.ts +2 -1
  156. package/lib/node/nodejs.d.ts.map +1 -1
  157. package/lib/node/nodejs.js.map +1 -1
  158. package/lib/sync/range/batch.d.ts +23 -5
  159. package/lib/sync/range/batch.d.ts.map +1 -1
  160. package/lib/sync/range/batch.js +61 -22
  161. package/lib/sync/range/batch.js.map +1 -1
  162. package/lib/sync/range/chain.d.ts +2 -1
  163. package/lib/sync/range/chain.d.ts.map +1 -1
  164. package/lib/sync/range/chain.js +23 -10
  165. package/lib/sync/range/chain.js.map +1 -1
  166. package/lib/sync/types.d.ts.map +1 -1
  167. package/lib/sync/types.js.map +1 -1
  168. package/lib/sync/unknownBlock.d.ts +9 -0
  169. package/lib/sync/unknownBlock.d.ts.map +1 -1
  170. package/lib/sync/unknownBlock.js +99 -21
  171. package/lib/sync/unknownBlock.js.map +1 -1
  172. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  173. package/lib/sync/utils/downloadByRange.js +16 -11
  174. package/lib/sync/utils/downloadByRange.js.map +1 -1
  175. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  176. package/lib/sync/utils/downloadByRoot.js +3 -1
  177. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  178. package/package.json +35 -35
  179. package/src/api/impl/beacon/blocks/index.ts +3 -2
  180. package/src/api/impl/beacon/pool/index.ts +7 -1
  181. package/src/api/impl/beacon/state/utils.ts +2 -1
  182. package/src/api/impl/events/index.ts +12 -4
  183. package/src/api/rest/base.ts +7 -0
  184. package/src/chain/blocks/importBlock.ts +1 -6
  185. package/src/chain/blocks/importExecutionPayload.ts +12 -11
  186. package/src/chain/blocks/index.ts +18 -6
  187. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
  188. package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
  189. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
  190. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
  191. package/src/chain/bls/index.ts +1 -1
  192. package/src/chain/bls/interface.ts +7 -3
  193. package/src/chain/bls/multithread/index.ts +148 -120
  194. package/src/chain/bls/multithread/jobItem.ts +12 -82
  195. package/src/chain/bls/multithread/types.ts +33 -8
  196. package/src/chain/bls/multithread/utils.ts +11 -0
  197. package/src/chain/bls/multithread/worker.ts +85 -27
  198. package/src/chain/bls/singleThread.ts +11 -55
  199. package/src/chain/bls/utils.ts +23 -24
  200. package/src/chain/chain.ts +13 -6
  201. package/src/chain/errors/blockError.ts +8 -2
  202. package/src/chain/errors/proposerPreferences.ts +7 -0
  203. package/src/chain/interface.ts +2 -1
  204. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  205. package/src/chain/opPools/attestationPool.ts +1 -1
  206. package/src/chain/opPools/payloadAttestationPool.ts +3 -3
  207. package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
  208. package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
  209. package/src/chain/opPools/utils.ts +1 -1
  210. package/src/chain/seenCache/seenAttesters.ts +31 -5
  211. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +145 -14
  212. package/src/chain/validation/attestation.ts +1 -7
  213. package/src/chain/validation/attesterSlashing.ts +1 -8
  214. package/src/chain/validation/executionPayloadBid.ts +1 -2
  215. package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
  216. package/src/chain/validation/payloadAttestationMessage.ts +6 -17
  217. package/src/chain/validation/proposerPreferences.ts +15 -5
  218. package/src/chain/validation/proposerSlashing.ts +1 -1
  219. package/src/metrics/metrics/lodestar.ts +97 -54
  220. package/src/network/gossip/topic.ts +38 -0
  221. package/src/network/libp2p/index.ts +11 -2
  222. package/src/network/network.ts +27 -55
  223. package/src/network/processor/gossipHandlers.ts +5 -1
  224. package/src/network/reqresp/score.ts +5 -11
  225. package/src/network/util.ts +0 -5
  226. package/src/node/nodejs.ts +2 -1
  227. package/src/sync/range/batch.ts +83 -28
  228. package/src/sync/range/chain.ts +26 -11
  229. package/src/sync/types.ts +3 -1
  230. package/src/sync/unknownBlock.ts +115 -26
  231. package/src/sync/utils/downloadByRange.ts +21 -12
  232. package/src/sync/utils/downloadByRoot.ts +3 -1
  233. package/lib/chain/bls/maybeBatch.d.ts +0 -12
  234. package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
  235. package/lib/chain/bls/maybeBatch.js +0 -35
  236. package/lib/chain/bls/maybeBatch.js.map +0 -1
  237. package/src/chain/bls/maybeBatch.ts +0 -45
@@ -17,3 +17,14 @@ export function chunkifyMaximizeChunkSize<T>(arr: T[], minPerChunk: number): T[]
17
17
 
18
18
  return arrArr;
19
19
  }
20
+
21
+ /**
22
+ * Splits an array into chunks that do not exceed a maximum size.
23
+ */
24
+ export function chunkifyMaxChunkSize<T>(arr: T[], maxPerChunk: number): T[][] {
25
+ const chunks: T[][] = [];
26
+ for (let i = 0; i < arr.length; i += maxPerChunk) {
27
+ chunks.push(arr.slice(i, i + maxPerChunk));
28
+ }
29
+ return chunks;
30
+ }
@@ -1,8 +1,20 @@
1
1
  import worker from "node:worker_threads";
2
- import {PublicKey} from "@chainsafe/blst";
2
+ import {
3
+ type BlsSignatureSet,
4
+ verifySignatureSets,
5
+ verifySignatureSetsSameMessage,
6
+ } from "@chainsafe/lodestar-z/bls-verifier";
3
7
  import {expose} from "@chainsafe/threads/worker";
4
- import {SignatureSetDeserialized, verifySignatureSetsMaybeBatch} from "../maybeBatch.js";
5
- import {BlsWorkReq, BlsWorkResult, SerializedSet, WorkResult, WorkResultCode, WorkerData} from "./types.js";
8
+ import {
9
+ BlsWorkReq,
10
+ BlsWorkResult,
11
+ JobQueueItemType,
12
+ VerificationCall,
13
+ VerificationCallOperation,
14
+ WorkResult,
15
+ WorkResultCode,
16
+ WorkerData,
17
+ } from "./types.js";
6
18
  import {chunkifyMaximizeChunkSize} from "./utils.js";
7
19
 
8
20
  /**
@@ -27,23 +39,45 @@ expose({
27
39
 
28
40
  function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
29
41
  const [startSec, startNs] = process.hrtime();
30
- const results: WorkResult<boolean>[] = [];
42
+ const results: WorkResult<boolean[]>[] = [];
43
+ const verificationCalls: VerificationCall[] = [];
31
44
  let batchRetries = 0;
32
45
  let batchSigsSuccess = 0;
33
46
 
34
47
  // If there are multiple batchable sets attempt batch verification with them
35
- const batchableSets: {idx: number; sets: SignatureSetDeserialized[]}[] = [];
36
- const nonBatchableSets: {idx: number; sets: SignatureSetDeserialized[]}[] = [];
48
+ const batchableSets: {idx: number; sets: BlsSignatureSet[]}[] = [];
49
+ const nonBatchableSets: {
50
+ idx: number;
51
+ sets: BlsSignatureSet[];
52
+ operation: VerificationCallOperation.single | VerificationCallOperation.fallback;
53
+ }[] = [];
37
54
 
38
55
  // Split sets between batchable and non-batchable preserving their original index in the req array
39
56
  for (let i = 0; i < workReqArr.length; i++) {
40
57
  const workReq = workReqArr[i];
41
- const sets = workReq.sets.map(deserializeSet);
42
-
43
- if (workReq.opts.batchable) {
44
- batchableSets.push({idx: i, sets});
45
- } else {
46
- nonBatchableSets.push({idx: i, sets});
58
+ switch (workReq.type) {
59
+ case JobQueueItemType.default: {
60
+ const {sets} = workReq;
61
+ if (workReq.opts.batchable) {
62
+ batchableSets.push({idx: i, sets});
63
+ } else {
64
+ nonBatchableSets.push({idx: i, sets, operation: VerificationCallOperation.single});
65
+ }
66
+ break;
67
+ }
68
+ case JobQueueItemType.sameMessage:
69
+ try {
70
+ const result = recordVerificationCall(
71
+ verificationCalls,
72
+ VerificationCallOperation.sameMessage,
73
+ workReq.sets.length,
74
+ () => verifySignatureSetsSameMessage(workReq.sets, workReq.message)
75
+ );
76
+ results[i] = {code: WorkResultCode.success, result};
77
+ } catch (e) {
78
+ results[i] = {code: WorkResultCode.error, error: e as Error};
79
+ }
80
+ break;
47
81
  }
48
82
  }
49
83
 
@@ -52,7 +86,7 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
52
86
  const batchableChunks = chunkifyMaximizeChunkSize(batchableSets, BATCHABLE_MIN_PER_CHUNK);
53
87
 
54
88
  for (const batchableChunk of batchableChunks) {
55
- const allSets: SignatureSetDeserialized[] = [];
89
+ const allSets: BlsSignatureSet[] = [];
56
90
  for (const {sets} of batchableChunk) {
57
91
  for (const set of sets) {
58
92
  allSets.push(set);
@@ -61,33 +95,49 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
61
95
 
62
96
  try {
63
97
  // Attempt to verify multiple sets at once
64
- const isValid = verifySignatureSetsMaybeBatch(allSets);
98
+ const isValid = recordVerificationCall(verificationCalls, VerificationCallOperation.batch, allSets.length, () =>
99
+ verifySignatureSets(allSets)
100
+ );
65
101
 
66
102
  if (isValid) {
67
103
  // The entire batch is valid, return success to all
68
104
  for (const {idx, sets} of batchableChunk) {
69
105
  batchSigsSuccess += sets.length;
70
- results[idx] = {code: WorkResultCode.success, result: isValid};
106
+ results[idx] = {code: WorkResultCode.success, result: [isValid]};
71
107
  }
72
108
  } else {
73
109
  batchRetries++;
74
110
  // Re-verify all sigs
75
- nonBatchableSets.push(...batchableChunk);
111
+ nonBatchableSets.push(
112
+ ...batchableChunk.map(({idx, sets}) => ({
113
+ idx,
114
+ sets,
115
+ operation: VerificationCallOperation.fallback as const,
116
+ }))
117
+ );
76
118
  }
77
119
  } catch (_e) {
78
120
  // TODO: Ignore this error expecting that the same error will happen when re-verifying the set individually
79
- // It's not ideal but '@chainsafe/blst' may throw errors on some conditions
121
+ // It's not ideal but the BLS implementation may throw errors on some conditions
80
122
  batchRetries++;
81
123
  // Re-verify all sigs
82
- nonBatchableSets.push(...batchableChunk);
124
+ nonBatchableSets.push(
125
+ ...batchableChunk.map(({idx, sets}) => ({
126
+ idx,
127
+ sets,
128
+ operation: VerificationCallOperation.fallback as const,
129
+ }))
130
+ );
83
131
  }
84
132
  }
85
133
  }
86
134
 
87
- for (const {idx, sets} of nonBatchableSets) {
135
+ for (const {idx, sets, operation} of nonBatchableSets) {
88
136
  try {
89
- const isValid = verifySignatureSetsMaybeBatch(sets);
90
- results[idx] = {code: WorkResultCode.success, result: isValid};
137
+ const isValid = recordVerificationCall(verificationCalls, operation, sets.length, () =>
138
+ verifySignatureSets(sets)
139
+ );
140
+ results[idx] = {code: WorkResultCode.success, result: [isValid]};
91
141
  } catch (e) {
92
142
  results[idx] = {code: WorkResultCode.error, error: e as Error};
93
143
  }
@@ -99,16 +149,24 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
99
149
  workerId,
100
150
  batchRetries,
101
151
  batchSigsSuccess,
152
+ verificationCalls,
102
153
  workerStartTime: [startSec, startNs],
103
154
  workerEndTime: [workerEndSec, workerEndNs],
104
155
  results,
105
156
  };
106
157
  }
107
158
 
108
- function deserializeSet(set: SerializedSet): SignatureSetDeserialized {
109
- return {
110
- publicKey: PublicKey.fromBytes(set.publicKey),
111
- message: set.message,
112
- signature: set.signature,
113
- };
159
+ function recordVerificationCall<T>(
160
+ calls: VerificationCall[],
161
+ operation: VerificationCallOperation,
162
+ signatureSets: number,
163
+ verify: () => T
164
+ ): T {
165
+ const startTime = process.hrtime();
166
+ try {
167
+ return verify();
168
+ } finally {
169
+ const [seconds, nanoseconds] = process.hrtime(startTime);
170
+ calls.push({operation, signatureSets, duration: seconds + nanoseconds / 1e9});
171
+ }
114
172
  }
@@ -1,31 +1,20 @@
1
- import {PublicKey, Signature, aggregatePublicKeys, aggregateSignatures, verify} from "@chainsafe/blst";
2
- import {ISignatureSet, PubkeyCache} from "@lodestar/state-transition";
1
+ import {verifySignatureSetsSameMessage} from "@chainsafe/lodestar-z/bls-verifier";
2
+ import {ISignatureSet} from "@lodestar/state-transition";
3
3
  import {Metrics} from "../../metrics/index.js";
4
- import {IBlsVerifier} from "./interface.js";
5
- import {verifySignatureSetsMaybeBatch} from "./maybeBatch.js";
6
- import {getAggregatedPubkey, getAggregatedPubkeysCount} from "./utils.js";
4
+ import {IBlsVerifier, SameMessageSignatureSet} from "./interface.js";
5
+ import {chunkSameMessageSignatureSets, getAggregatedPubkeysCount, verifySignatureSetsInBatches} from "./utils.js";
7
6
 
8
7
  export class BlsSingleThreadVerifier implements IBlsVerifier {
9
8
  private readonly metrics: Metrics | null;
10
- private readonly pubkeyCache: PubkeyCache;
11
-
12
- constructor({metrics = null, pubkeyCache}: {metrics: Metrics | null; pubkeyCache: PubkeyCache}) {
9
+ constructor({metrics = null}: {metrics: Metrics | null}) {
13
10
  this.metrics = metrics;
14
- this.pubkeyCache = pubkeyCache;
15
11
  }
16
12
 
17
13
  async verifySignatureSets(sets: ISignatureSet[]): Promise<boolean> {
18
14
  this.metrics?.bls.aggregatedPubkeys.inc(getAggregatedPubkeysCount(sets));
19
15
 
20
- const setsAggregated = sets.map((set) => ({
21
- publicKey: getAggregatedPubkey(set, this.pubkeyCache, this.metrics),
22
- message: set.signingRoot,
23
- signature: set.signature,
24
- }));
25
-
26
- // Count time after aggregating
27
16
  const timer = this.metrics?.blsThreadPool.mainThreadDurationInThreadPool.startTimer();
28
- const isValid = verifySignatureSetsMaybeBatch(setsAggregated);
17
+ const isValid = verifySignatureSetsInBatches(sets);
29
18
 
30
19
  // Don't use a try/catch, only count run without exceptions
31
20
  if (timer) {
@@ -35,46 +24,13 @@ export class BlsSingleThreadVerifier implements IBlsVerifier {
35
24
  return isValid;
36
25
  }
37
26
 
38
- async verifySignatureSetsSameMessage(
39
- sets: {publicKey: PublicKey; signature: Uint8Array}[],
40
- message: Uint8Array
41
- ): Promise<boolean[]> {
27
+ async verifySignatureSetsSameMessage(sets: SameMessageSignatureSet[], message: Uint8Array): Promise<boolean[]> {
42
28
  const timer = this.metrics?.blsThreadPool.mainThreadDurationInThreadPool.startTimer();
43
- const pubkey = aggregatePublicKeys(sets.map((set) => set.publicKey));
44
- let isAllValid = true;
45
- // validate signature = true
46
- const signatures = sets.map((set) => {
47
- try {
48
- return Signature.fromBytes(set.signature, true);
49
- } catch (_) {
50
- // at least one set has malformed signature
51
- isAllValid = false;
52
- return null;
53
- }
54
- });
55
-
56
- if (isAllValid) {
57
- const signature = aggregateSignatures(signatures as Signature[]);
58
- isAllValid = verify(message, pubkey, signature);
59
- }
60
-
61
- let result: boolean[];
62
- if (isAllValid) {
63
- result = sets.map(() => true);
64
- } else {
65
- result = sets.map((set, i) => {
66
- const sig = signatures[i];
67
- if (sig === null) {
68
- return false;
69
- }
70
- return verify(message, set.publicKey, sig);
71
- });
29
+ const result: boolean[] = [];
30
+ for (const setsChunk of chunkSameMessageSignatureSets(sets)) {
31
+ result.push(...verifySignatureSetsSameMessage(setsChunk, message));
72
32
  }
73
-
74
- if (timer) {
75
- timer();
76
- }
77
-
33
+ timer?.();
78
34
  return result;
79
35
  }
80
36
 
@@ -1,33 +1,32 @@
1
- import {PublicKey, aggregatePublicKeys} from "@chainsafe/blst";
2
- import {ISignatureSet, PubkeyCache, SignatureSetType} from "@lodestar/state-transition";
3
- import {Metrics} from "../../metrics/metrics.js";
1
+ import {
2
+ BLS_VERIFIER_MAX_BATCH_SIZE,
3
+ BLS_VERIFIER_MAX_SAME_MESSAGE_BATCH_SIZE,
4
+ verifySignatureSets,
5
+ } from "@chainsafe/lodestar-z/bls-verifier";
6
+ import {ISignatureSet, SignatureSetType, toBlsSignatureSet} from "@lodestar/state-transition";
7
+ import {SameMessageSignatureSet} from "./interface.js";
4
8
 
5
- export function getAggregatedPubkey(
6
- signatureSet: ISignatureSet,
7
- pubkeyCache: PubkeyCache,
8
- metrics: Metrics | null = null
9
- ): PublicKey {
10
- switch (signatureSet.type) {
11
- case SignatureSetType.single:
12
- return signatureSet.pubkey;
9
+ export function verifySignatureSetsInBatches(signatureSets: ISignatureSet[]): boolean {
10
+ if (signatureSets.length === 0) {
11
+ return false;
12
+ }
13
13
 
14
- case SignatureSetType.indexed: {
15
- return pubkeyCache.getOrThrow(signatureSet.index);
14
+ for (let start = 0; start < signatureSets.length; start += BLS_VERIFIER_MAX_BATCH_SIZE) {
15
+ const sets = signatureSets.slice(start, start + BLS_VERIFIER_MAX_BATCH_SIZE).map(toBlsSignatureSet);
16
+ if (!verifySignatureSets(sets)) {
17
+ return false;
16
18
  }
19
+ }
17
20
 
18
- case SignatureSetType.aggregate: {
19
- const timer = metrics?.blsThreadPool.pubkeysAggregationMainThreadDuration.startTimer();
20
- const pubkeys = signatureSet.indices.map((i) => {
21
- return pubkeyCache.getOrThrow(i);
22
- });
23
- const aggregated = aggregatePublicKeys(pubkeys);
24
- timer?.();
25
- return aggregated;
26
- }
21
+ return true;
22
+ }
27
23
 
28
- default:
29
- throw Error("Unknown signature set type");
24
+ export function chunkSameMessageSignatureSets(sets: SameMessageSignatureSet[]): SameMessageSignatureSet[][] {
25
+ const chunks: SameMessageSignatureSet[][] = [];
26
+ for (let start = 0; start < sets.length; start += BLS_VERIFIER_MAX_SAME_MESSAGE_BATCH_SIZE) {
27
+ chunks.push(sets.slice(start, start + BLS_VERIFIER_MAX_SAME_MESSAGE_BATCH_SIZE));
30
28
  }
29
+ return chunks;
31
30
  }
32
31
 
33
32
  export function getAggregatedPubkeysCount(signatureSets: ISignatureSet[]): number {
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import {PrivateKey} from "@libp2p/interface";
3
+ import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
3
4
  import {Type} from "@chainsafe/ssz";
4
5
  import {routes} from "@lodestar/api";
5
6
  import {BeaconConfig} from "@lodestar/config";
@@ -25,7 +26,6 @@ import {
25
26
  EffectiveBalanceIncrements,
26
27
  EpochShuffling,
27
28
  IBeaconStateView,
28
- PubkeyCache,
29
29
  computeEndSlotAtEpoch,
30
30
  computeEpochAtSlot,
31
31
  computeStartSlotAtEpoch,
@@ -79,6 +79,7 @@ import {CheckpointBalancesCache} from "./balancesCache.js";
79
79
  import {BeaconProposerCache} from "./beaconProposerCache.js";
80
80
  import {IBlockInput, isBlockInputBlobs, isBlockInputColumns} from "./blocks/blockInput/index.js";
81
81
  import {BlockProcessor, ImportBlockOpts} from "./blocks/index.js";
82
+ import {PayloadEnvelopeInputSource} from "./blocks/payloadEnvelopeInput/index.js";
82
83
  import {PayloadEnvelopeProcessor} from "./blocks/payloadEnvelopeProcessor.js";
83
84
  import {ImportPayloadOpts} from "./blocks/types.js";
84
85
  import {persistBlockInput} from "./blocks/writeBlockInputToDb.js";
@@ -307,8 +308,8 @@ export class BeaconChain implements IBeaconChain {
307
308
  const emitter = new ChainEventEmitter();
308
309
  // by default, verify signatures on both main threads and worker threads
309
310
  const bls = opts.blsVerifyAllMainThread
310
- ? new BlsSingleThreadVerifier({metrics, pubkeyCache})
311
- : new BlsMultiThreadWorkerPool(opts, {logger, metrics, pubkeyCache});
311
+ ? new BlsSingleThreadVerifier({metrics})
312
+ : new BlsMultiThreadWorkerPool(opts, {logger, metrics});
312
313
 
313
314
  if (!clock) clock = new Clock({config, genesisTime: this.genesisTime, signal});
314
315
 
@@ -451,6 +452,9 @@ export class BeaconChain implements IBeaconChain {
451
452
  chainEvents: emitter,
452
453
  signal,
453
454
  serializedCache: this.serializedCache,
455
+ db,
456
+ seenBlockInputCache: this.seenBlockInputCache,
457
+ custodyConfig: this.custodyConfig,
454
458
  metrics,
455
459
  logger,
456
460
  });
@@ -466,7 +470,8 @@ export class BeaconChain implements IBeaconChain {
466
470
  bid: anchorBid,
467
471
  sampledColumns: this.custodyConfig.sampledColumns,
468
472
  custodyColumns: this.custodyConfig.custodyColumns,
469
- timeCreatedSec: Math.floor(Date.now() / 1000),
473
+ seenTimestampSec: Date.now() / 1000,
474
+ source: PayloadEnvelopeInputSource.anchorState,
470
475
  });
471
476
  }
472
477
 
@@ -579,7 +584,7 @@ export class BeaconChain implements IBeaconChain {
579
584
  // seenAggregators = single aggregator index, not participants of the aggregate
580
585
  this.seenAggregators.isKnown(epoch, index) ||
581
586
  // seenPayloadAttesters = single signer of payload attestation message
582
- this.seenPayloadAttesters.isKnown(epoch, index) ||
587
+ this.seenPayloadAttesters.seenAtEpoch(epoch, index) ||
583
588
  // seenBlockProposers = single block proposer
584
589
  this.seenBlockProposers.seenAtEpoch(epoch, index)
585
590
  );
@@ -1090,7 +1095,7 @@ export class BeaconChain implements IBeaconChain {
1090
1095
  RegenCaller.produceBlock
1091
1096
  );
1092
1097
  const proposerIndex = state.getBeaconProposer(slot);
1093
- const proposerPubKey = this.pubkeyCache.getOrThrow(proposerIndex).toBytes();
1098
+ const proposerPubKey = this.pubkeyCache.getPubkeyBytesOrThrow(proposerIndex);
1094
1099
 
1095
1100
  const {body, produceResult, executionPayloadValue, shouldOverrideBuilder} = await produceBlockBody.call(
1096
1101
  this,
@@ -1577,6 +1582,8 @@ export class BeaconChain implements IBeaconChain {
1577
1582
  // syncContributionAndProofPool tracks metrics on its own
1578
1583
  metrics.opPool.blsToExecutionChangePoolSize.set(this.opPool.blsToExecutionChangeSize);
1579
1584
  metrics.chain.blacklistedBlocks.set(this.blacklistedBlocks.size);
1585
+ metrics.bls.pubkeyCacheSize.set(this.pubkeyCache.size);
1586
+ metrics.bls.pubkeyCacheCapacity.set(this.pubkeyCache.capacity);
1580
1587
 
1581
1588
  const headState = this.getHeadState();
1582
1589
  if (isStatePostElectra(headState)) {
@@ -136,7 +136,7 @@ export type BlockErrorType =
136
136
  | {code: BlockErrorCode.NON_LINEAR_PARENT_ROOTS}
137
137
  | {code: BlockErrorCode.NON_LINEAR_SLOTS}
138
138
  | {code: BlockErrorCode.ENVELOPE_BLOCK_ROOT_MISMATCH; envelopeBlockRoot: RootHex; blockRoot: RootHex}
139
- | {code: BlockErrorCode.PER_BLOCK_PROCESSING_ERROR; error: Error}
139
+ | {code: BlockErrorCode.PER_BLOCK_PROCESSING_ERROR; blockRoot: RootHex; error: Error}
140
140
  | {code: BlockErrorCode.BEACON_CHAIN_ERROR; error: Error}
141
141
  | {code: BlockErrorCode.KNOWN_BAD_BLOCK}
142
142
  | {code: BlockErrorCode.BLACKLISTED_BLOCK}
@@ -184,13 +184,19 @@ export function isBlockErrorAborted(e: unknown): e is BlockError {
184
184
  export function renderBlockErrorType(type: BlockErrorType): Record<string, string | number | null> {
185
185
  switch (type.code) {
186
186
  case BlockErrorCode.PRESTATE_MISSING:
187
- case BlockErrorCode.PER_BLOCK_PROCESSING_ERROR:
188
187
  case BlockErrorCode.BEACON_CHAIN_ERROR:
189
188
  return {
190
189
  code: type.code,
191
190
  error: type.error.message,
192
191
  };
193
192
 
193
+ case BlockErrorCode.PER_BLOCK_PROCESSING_ERROR:
194
+ return {
195
+ code: type.code,
196
+ blockRoot: type.blockRoot,
197
+ error: type.error.message,
198
+ };
199
+
194
200
  case BlockErrorCode.INVALID_SIGNATURE:
195
201
  return {
196
202
  code: type.code,
@@ -1,7 +1,9 @@
1
+ import {ForkName} from "@lodestar/params";
1
2
  import {Epoch, RootHex, Slot, ValidatorIndex} from "@lodestar/types";
2
3
  import {GossipActionError} from "./gossipValidation.js";
3
4
 
4
5
  export enum ProposerPreferencesErrorCode {
6
+ PRE_GLOAS_PROPOSAL_SLOT = "PROPOSER_PREFERENCES_ERROR_PRE_GLOAS_PROPOSAL_SLOT",
5
7
  INVALID_EPOCH = "PROPOSER_PREFERENCES_ERROR_INVALID_EPOCH",
6
8
  PROPOSAL_SLOT_PASSED = "PROPOSER_PREFERENCES_ERROR_PROPOSAL_SLOT_PASSED",
7
9
  UNKNOWN_DEPENDENT_ROOT = "PROPOSER_PREFERENCES_ERROR_UNKNOWN_DEPENDENT_ROOT",
@@ -13,6 +15,11 @@ export enum ProposerPreferencesErrorCode {
13
15
  }
14
16
 
15
17
  export type ProposerPreferencesErrorType =
18
+ | {
19
+ code: ProposerPreferencesErrorCode.PRE_GLOAS_PROPOSAL_SLOT;
20
+ proposalSlot: Slot;
21
+ proposalFork: ForkName;
22
+ }
16
23
  | {
17
24
  code: ProposerPreferencesErrorCode.INVALID_EPOCH;
18
25
  proposalSlot: Slot;
@@ -1,7 +1,8 @@
1
+ import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
1
2
  import {Type} from "@chainsafe/ssz";
2
3
  import {BeaconConfig} from "@lodestar/config";
3
4
  import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
4
- import {EpochShuffling, IBeaconStateView, PubkeyCache} from "@lodestar/state-transition";
5
+ import {EpochShuffling, IBeaconStateView} from "@lodestar/state-transition";
5
6
  import {
6
7
  BeaconBlock,
7
8
  BlindedBeaconBlock,
@@ -1,4 +1,4 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/blst";
1
+ import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
2
  import {BitArray} from "@chainsafe/ssz";
3
3
  import {BeaconConfig} from "@lodestar/config";
4
4
  import {IForkChoice} from "@lodestar/fork-choice";
@@ -1,4 +1,4 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/blst";
1
+ import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
2
  import {BitArray} from "@chainsafe/ssz";
3
3
  import {ChainForkConfig} from "@lodestar/config";
4
4
  import {MAX_COMMITTEES_PER_SLOT, isForkPostElectra} from "@lodestar/params";
@@ -1,4 +1,4 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/blst";
1
+ import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
2
  import {BitArray} from "@chainsafe/ssz";
3
3
  import {ChainForkConfig} from "@lodestar/config";
4
4
  import {MAX_COMMITTEES_PER_SLOT, MAX_PAYLOAD_ATTESTATIONS, PTC_SIZE} from "@lodestar/params";
@@ -178,8 +178,8 @@ function aggregateMessageInto(
178
178
  validatorCommitteeIndices: number[],
179
179
  aggregate: AggregateFast
180
180
  ): InsertOutcome {
181
- // Gossip dedup via `seenPayloadAttesters` is keyed by (epoch, validatorIndex), so the same
182
- // validator's message is never processed twice all of its bits are set together or none.
181
+ // Gossip dedup via `seenPayloadAttesters` is keyed by (slot, validatorIndex), so the same
182
+ // validator's message is never processed twice for this aggregate's slot. All of its bits are set together or none.
183
183
  // Checking the first index is sufficient.
184
184
  if (aggregate.aggregationBits.get(validatorCommitteeIndices[0]) === true) {
185
185
  return InsertOutcome.AlreadyKnown;
@@ -1,4 +1,4 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/blst";
1
+ import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
2
  import {BitArray} from "@chainsafe/ssz";
3
3
  import {ChainForkConfig} from "@lodestar/config";
4
4
  import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
@@ -1,4 +1,4 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/blst";
1
+ import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
2
  import {BitArray} from "@chainsafe/ssz";
3
3
  import {ChainForkConfig} from "@lodestar/config";
4
4
  import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params";
@@ -1,4 +1,4 @@
1
- import {Signature} from "@chainsafe/blst";
1
+ import {Signature} from "@chainsafe/lodestar-z/blst";
2
2
  import {BLS_WITHDRAWAL_PREFIX} from "@lodestar/params";
3
3
  import {IBeaconStateView} from "@lodestar/state-transition";
4
4
  import {Slot, capella} from "@lodestar/types";
@@ -1,4 +1,5 @@
1
- import {Epoch, ValidatorIndex} from "@lodestar/types";
1
+ import {computeEpochAtSlot} from "@lodestar/state-transition";
2
+ import {Epoch, Slot, ValidatorIndex} from "@lodestar/types";
2
3
  import {MapDef} from "@lodestar/utils";
3
4
 
4
5
  // How many *non future* epochs we intend to keep for SeenAttesters.
@@ -57,7 +58,32 @@ export class SeenAttesters {
57
58
  */
58
59
  export class SeenAggregators extends SeenAttesters {}
59
60
 
60
- /**
61
- * Keeps a cache to filter payload attestations from the same attesters in the same epoch
62
- */
63
- export class SeenPayloadAttesters extends SeenAttesters {}
61
+ /** Keeps a cache to filter payload attestations from the same validator in the same slot. */
62
+ export class SeenPayloadAttesters {
63
+ private readonly validatorIndexesBySlot = new MapDef<Slot, Set<ValidatorIndex>>(() => new Set<ValidatorIndex>());
64
+ private readonly validatorIndexesByEpoch = new SeenAttesters();
65
+
66
+ isKnown(slot: Slot, validatorIndex: ValidatorIndex): boolean {
67
+ return this.validatorIndexesBySlot.get(slot)?.has(validatorIndex) === true;
68
+ }
69
+
70
+ add(slot: Slot, validatorIndex: ValidatorIndex): void {
71
+ const epoch = computeEpochAtSlot(slot);
72
+ this.validatorIndexesByEpoch.add(epoch, validatorIndex);
73
+ this.validatorIndexesBySlot.getOrDefault(slot).add(validatorIndex);
74
+ }
75
+
76
+ seenAtEpoch(epoch: Epoch, validatorIndex: ValidatorIndex): boolean {
77
+ return this.validatorIndexesByEpoch.isKnown(epoch, validatorIndex);
78
+ }
79
+
80
+ prune(currentEpoch: Epoch): void {
81
+ const lowestPermissibleEpoch = Math.max(currentEpoch - EPOCH_LOOKBACK_LIMIT, 0);
82
+ for (const slot of this.validatorIndexesBySlot.keys()) {
83
+ if (computeEpochAtSlot(slot) < lowestPermissibleEpoch) {
84
+ this.validatorIndexesBySlot.delete(slot);
85
+ }
86
+ }
87
+ this.validatorIndexesByEpoch.prune(currentEpoch);
88
+ }
89
+ }