@lodestar/beacon-node 1.45.0-dev.d7859e978b → 1.45.0-dev.e6c77a6488

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 (170) hide show
  1. package/lib/api/impl/beacon/index.d.ts +1 -1
  2. package/lib/api/impl/beacon/index.d.ts.map +1 -1
  3. package/lib/api/impl/beacon/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 +6 -43
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/index.d.ts +1 -1
  8. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/state/index.js +48 -5
  10. package/lib/api/impl/beacon/state/index.js.map +1 -1
  11. package/lib/api/impl/beacon/state/utils.d.ts +13 -3
  12. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  13. package/lib/api/impl/beacon/state/utils.js +48 -4
  14. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  15. package/lib/api/impl/debug/index.d.ts +1 -1
  16. package/lib/api/impl/debug/index.d.ts.map +1 -1
  17. package/lib/api/impl/debug/index.js +2 -2
  18. package/lib/api/impl/debug/index.js.map +1 -1
  19. package/lib/api/impl/lodestar/index.js +2 -2
  20. package/lib/api/impl/lodestar/index.js.map +1 -1
  21. package/lib/api/impl/proof/index.d.ts +1 -1
  22. package/lib/api/impl/proof/index.d.ts.map +1 -1
  23. package/lib/api/impl/proof/index.js +2 -2
  24. package/lib/api/impl/proof/index.js.map +1 -1
  25. package/lib/api/impl/utils.d.ts +23 -0
  26. package/lib/api/impl/utils.d.ts.map +1 -1
  27. package/lib/api/impl/utils.js +44 -1
  28. package/lib/api/impl/utils.js.map +1 -1
  29. package/lib/api/impl/validator/index.d.ts +0 -14
  30. package/lib/api/impl/validator/index.d.ts.map +1 -1
  31. package/lib/api/impl/validator/index.js +62 -61
  32. package/lib/api/impl/validator/index.js.map +1 -1
  33. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  34. package/lib/chain/blocks/importBlock.js +10 -8
  35. package/lib/chain/blocks/importBlock.js.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -2
  37. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  38. package/lib/chain/blocks/payloadEnvelopeProcessor.js +17 -17
  39. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  40. package/lib/chain/chain.d.ts +1 -2
  41. package/lib/chain/chain.d.ts.map +1 -1
  42. package/lib/chain/chain.js +1 -3
  43. package/lib/chain/chain.js.map +1 -1
  44. package/lib/chain/interface.d.ts +1 -2
  45. package/lib/chain/interface.d.ts.map +1 -1
  46. package/lib/chain/interface.js.map +1 -1
  47. package/lib/chain/opPools/proposerPreferencesPool.d.ts +2 -1
  48. package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
  49. package/lib/chain/opPools/proposerPreferencesPool.js +3 -0
  50. package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
  51. package/lib/chain/options.d.ts +1 -0
  52. package/lib/chain/options.d.ts.map +1 -1
  53. package/lib/chain/options.js +1 -0
  54. package/lib/chain/options.js.map +1 -1
  55. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  56. package/lib/chain/produceBlock/produceBlockBody.js +4 -12
  57. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  58. package/lib/chain/seenCache/index.d.ts +0 -1
  59. package/lib/chain/seenCache/index.d.ts.map +1 -1
  60. package/lib/chain/seenCache/index.js +0 -1
  61. package/lib/chain/seenCache/index.js.map +1 -1
  62. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +1 -0
  63. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  64. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +7 -0
  65. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  66. package/lib/chain/shufflingCache.d.ts +6 -0
  67. package/lib/chain/shufflingCache.d.ts.map +1 -1
  68. package/lib/chain/shufflingCache.js +21 -6
  69. package/lib/chain/shufflingCache.js.map +1 -1
  70. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  71. package/lib/chain/stateCache/persistentCheckpointsCache.js +3 -2
  72. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  73. package/lib/chain/validation/executionPayloadBid.js +11 -10
  74. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  75. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
  76. package/lib/chain/validation/proposerPreferences.js +14 -5
  77. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  78. package/lib/network/core/metrics.d.ts +65 -0
  79. package/lib/network/core/metrics.d.ts.map +1 -1
  80. package/lib/network/core/metrics.js +94 -0
  81. package/lib/network/core/metrics.js.map +1 -1
  82. package/lib/network/discv5/utils.d.ts.map +1 -1
  83. package/lib/network/discv5/utils.js +12 -3
  84. package/lib/network/discv5/utils.js.map +1 -1
  85. package/lib/network/gossip/encoding.d.ts.map +1 -1
  86. package/lib/network/gossip/encoding.js +7 -0
  87. package/lib/network/gossip/encoding.js.map +1 -1
  88. package/lib/network/gossip/gossipsub.d.ts.map +1 -1
  89. package/lib/network/gossip/gossipsub.js +2 -1
  90. package/lib/network/gossip/gossipsub.js.map +1 -1
  91. package/lib/network/gossip/topic.d.ts +6 -1
  92. package/lib/network/gossip/topic.d.ts.map +1 -1
  93. package/lib/network/gossip/topic.js +23 -3
  94. package/lib/network/gossip/topic.js.map +1 -1
  95. package/lib/network/peers/discover.d.ts.map +1 -1
  96. package/lib/network/peers/discover.js +17 -12
  97. package/lib/network/peers/discover.js.map +1 -1
  98. package/lib/network/peers/peerManager.d.ts.map +1 -1
  99. package/lib/network/peers/peerManager.js +10 -0
  100. package/lib/network/peers/peerManager.js.map +1 -1
  101. package/lib/network/peers/score/score.d.ts +3 -1
  102. package/lib/network/peers/score/score.d.ts.map +1 -1
  103. package/lib/network/peers/score/score.js +6 -1
  104. package/lib/network/peers/score/score.js.map +1 -1
  105. package/lib/network/peers/score/store.d.ts.map +1 -1
  106. package/lib/network/peers/score/store.js +6 -1
  107. package/lib/network/peers/score/store.js.map +1 -1
  108. package/lib/network/peers/utils/prioritizePeers.d.ts.map +1 -1
  109. package/lib/network/peers/utils/prioritizePeers.js +14 -0
  110. package/lib/network/peers/utils/prioritizePeers.js.map +1 -1
  111. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  112. package/lib/network/processor/gossipHandlers.js +32 -16
  113. package/lib/network/processor/gossipHandlers.js.map +1 -1
  114. package/lib/sync/range/chain.d.ts +4 -1
  115. package/lib/sync/range/chain.d.ts.map +1 -1
  116. package/lib/sync/range/chain.js +3 -3
  117. package/lib/sync/range/chain.js.map +1 -1
  118. package/lib/sync/range/range.d.ts.map +1 -1
  119. package/lib/sync/range/range.js +10 -0
  120. package/lib/sync/range/range.js.map +1 -1
  121. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  122. package/lib/sync/utils/downloadByRange.js +25 -19
  123. package/lib/sync/utils/downloadByRange.js.map +1 -1
  124. package/lib/util/graffiti.d.ts +15 -0
  125. package/lib/util/graffiti.d.ts.map +1 -1
  126. package/lib/util/graffiti.js +55 -0
  127. package/lib/util/graffiti.js.map +1 -1
  128. package/package.json +18 -18
  129. package/src/api/impl/beacon/index.ts +1 -1
  130. package/src/api/impl/beacon/pool/index.ts +5 -53
  131. package/src/api/impl/beacon/state/index.ts +55 -3
  132. package/src/api/impl/beacon/state/utils.ts +68 -4
  133. package/src/api/impl/debug/index.ts +3 -2
  134. package/src/api/impl/lodestar/index.ts +2 -2
  135. package/src/api/impl/proof/index.ts +2 -2
  136. package/src/api/impl/utils.ts +51 -1
  137. package/src/api/impl/validator/index.ts +70 -66
  138. package/src/chain/blocks/importBlock.ts +19 -10
  139. package/src/chain/blocks/payloadEnvelopeProcessor.ts +17 -17
  140. package/src/chain/chain.ts +0 -3
  141. package/src/chain/interface.ts +0 -2
  142. package/src/chain/opPools/proposerPreferencesPool.ts +5 -1
  143. package/src/chain/options.ts +2 -0
  144. package/src/chain/produceBlock/produceBlockBody.ts +9 -17
  145. package/src/chain/seenCache/index.ts +0 -1
  146. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +8 -0
  147. package/src/chain/shufflingCache.ts +23 -7
  148. package/src/chain/stateCache/persistentCheckpointsCache.ts +3 -2
  149. package/src/chain/validation/executionPayloadBid.ts +14 -9
  150. package/src/chain/validation/proposerPreferences.ts +15 -5
  151. package/src/network/core/metrics.ts +94 -0
  152. package/src/network/discv5/utils.ts +11 -3
  153. package/src/network/gossip/encoding.ts +7 -0
  154. package/src/network/gossip/gossipsub.ts +2 -1
  155. package/src/network/gossip/topic.ts +28 -4
  156. package/src/network/peers/discover.ts +16 -11
  157. package/src/network/peers/peerManager.ts +11 -0
  158. package/src/network/peers/score/score.ts +8 -1
  159. package/src/network/peers/score/store.ts +8 -1
  160. package/src/network/peers/utils/prioritizePeers.ts +15 -0
  161. package/src/network/processor/gossipHandlers.ts +35 -16
  162. package/src/sync/range/chain.ts +4 -5
  163. package/src/sync/range/range.ts +10 -0
  164. package/src/sync/utils/downloadByRange.ts +26 -19
  165. package/src/util/graffiti.ts +78 -0
  166. package/lib/chain/seenCache/seenProposerPreferences.d.ts +0 -16
  167. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +0 -1
  168. package/lib/chain/seenCache/seenProposerPreferences.js +0 -26
  169. package/lib/chain/seenCache/seenProposerPreferences.js.map +0 -1
  170. package/src/chain/seenCache/seenProposerPreferences.ts +0 -32
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/impl/proof/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,eAAe,CAAC;AACrC,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAEvC,wBAAgB,WAAW,CACzB,IAAI,EAAE,UAAU,EAChB,EAAC,KAAK,EAAE,MAAM,EAAC,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC,GAC3D,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAwC5C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/impl/proof/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,eAAe,CAAC;AACrC,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAEvC,wBAAgB,WAAW,CACzB,IAAI,EAAE,UAAU,EAChB,EAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAC,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,GAAG,MAAM,CAAC,GAC1E,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAwC5C"}
@@ -1,7 +1,7 @@
1
1
  import { ProofType, createProof } from "@chainsafe/persistent-merkle-tree";
2
2
  import { getBlockResponse } from "../beacon/blocks/utils.js";
3
3
  import { getStateResponseWithRegen } from "../beacon/state/utils.js";
4
- export function getProofApi(opts, { chain, config }) {
4
+ export function getProofApi(opts, { chain, config, sync }) {
5
5
  // It's currently possible to request gigantic proofs (eg: a proof of the entire beacon state)
6
6
  // We want some some sort of resistance against this DoS vector.
7
7
  const maxGindicesInProof = opts.maxGindicesInProof ?? 512;
@@ -11,7 +11,7 @@ export function getProofApi(opts, { chain, config }) {
11
11
  if (descriptor.length / 2 > maxGindicesInProof) {
12
12
  throw new Error("Requested proof is too large.");
13
13
  }
14
- const res = await getStateResponseWithRegen(chain, stateId);
14
+ const res = await getStateResponseWithRegen(chain, sync, stateId);
15
15
  const state = res.state instanceof Uint8Array ? chain.getHeadState().loadOtherState(res.state) : res.state;
16
16
  return {
17
17
  data: state.createMultiProof(descriptor),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/api/impl/proof/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,WAAW,EAAC,MAAM,mCAAmC,CAAC;AAI5F,OAAO,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAGnE,MAAM,UAAU,WAAW,CACzB,IAAgB,EAChB,EAAC,KAAK,EAAE,MAAM,EAA8C,EAChB;IAC5C,8FAA8F;IAC9F,gEAAgE;IAChE,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,IAAI,GAAG,CAAC;IAE1D,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,EAAC,OAAO,EAAE,UAAU,EAAC,EAAE;YACzC,kEAAkE;YAClE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,kBAAkB,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,yBAAyB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAE5D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;YAE3G,OAAO;gBACL,IAAI,EAAE,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC;gBACxC,IAAI,EAAE,EAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAC;aAChD,CAAC;QAAA,CACH;QACD,KAAK,CAAC,aAAa,CAAC,EAAC,OAAO,EAAE,UAAU,EAAC,EAAE;YACzC,kEAAkE;YAClE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,kBAAkB,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;YAED,MAAM,EAAC,KAAK,EAAC,GAAG,MAAM,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAEvD,4GAA4G;YAC5G,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;YAEjG,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,EAAE,EAAC,IAAI,EAAE,SAAS,CAAC,YAAY,EAAE,UAAU,EAAC,CAAC,CAAC;YAEjF,OAAO;gBACL,IAAI,EAAE,KAA0B;gBAChC,IAAI,EAAE,EAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAC;aACxD,CAAC;QAAA,CACH;KACF,CAAC;AAAA,CACH"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/api/impl/proof/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,WAAW,EAAC,MAAM,mCAAmC,CAAC;AAI5F,OAAO,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAGnE,MAAM,UAAU,WAAW,CACzB,IAAgB,EAChB,EAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAuD,EAC/B;IAC5C,8FAA8F;IAC9F,gEAAgE;IAChE,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,IAAI,GAAG,CAAC;IAE1D,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,EAAC,OAAO,EAAE,UAAU,EAAC,EAAE;YACzC,kEAAkE;YAClE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,kBAAkB,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,yBAAyB,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YAElE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;YAE3G,OAAO;gBACL,IAAI,EAAE,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC;gBACxC,IAAI,EAAE,EAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAC;aAChD,CAAC;QAAA,CACH;QACD,KAAK,CAAC,aAAa,CAAC,EAAC,OAAO,EAAE,UAAU,EAAC,EAAE;YACzC,kEAAkE;YAClE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,kBAAkB,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;YAED,MAAM,EAAC,KAAK,EAAC,GAAG,MAAM,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAEvD,4GAA4G;YAC5G,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;YAEjG,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,EAAE,EAAC,IAAI,EAAE,SAAS,CAAC,YAAY,EAAE,UAAU,EAAC,CAAC,CAAC;YAEjF,OAAO;gBACL,IAAI,EAAE,KAA0B;gBAChC,IAAI,EAAE,EAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAC;aACxD,CAAC;QAAA,CACH;KACF,CAAC;AAAA,CACH"}
@@ -1,3 +1,26 @@
1
+ import type { IBeaconChain } from "../../chain/index.js";
2
+ import { SyncState } from "../../sync/index.js";
3
+ /**
4
+ * If the node is within this many epochs from the head, we declare it to be synced regardless of
5
+ * the network sync state.
6
+ *
7
+ * This helps prevent attacks where nodes can convince us that we're syncing some non-existent
8
+ * finalized head.
9
+ *
10
+ * TODO: Lighthouse uses 8 for the attack described above. However, 8 kills Lodestar since validators
11
+ * can trigger regen to fast-forward head state 8 epochs to be immediately invalidated as sync sets
12
+ * a new head. Then the checkpoint state cache grows unbounded with very different states (because
13
+ * they are 8 epochs apart) and causes an OOM. Research a proper solution once regen and the state
14
+ * caches are better.
15
+ */
16
+ export declare const SYNC_TOLERANCE_EPOCHS = 1;
17
+ /**
18
+ * Reject any request while the node is syncing. Used by endpoints that must not serve while the
19
+ * node is behind — validator duties, and beacon state lookups whose regen could otherwise walk
20
+ * back past the block-root window (`SLOTS_PER_HISTORICAL_ROOT`) and wedge the node. Throws
21
+ * {@link NodeIsSyncing} (503).
22
+ */
23
+ export declare function notWhileSyncing(chain: IBeaconChain, syncState: SyncState): void;
1
24
  /**
2
25
  * Ensures that the array contains unique values, and throws an ApiError
3
26
  * otherwise.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/api/impl/utils.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAerF"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/api/impl/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAG9C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI,CAwB/E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAerF"}
@@ -1,4 +1,47 @@
1
- import { ApiError } from "./errors.js";
1
+ import { SLOTS_PER_EPOCH } from "@lodestar/params";
2
+ import { SyncState } from "../../sync/index.js";
3
+ import { ApiError, NodeIsSyncing } from "./errors.js";
4
+ /**
5
+ * If the node is within this many epochs from the head, we declare it to be synced regardless of
6
+ * the network sync state.
7
+ *
8
+ * This helps prevent attacks where nodes can convince us that we're syncing some non-existent
9
+ * finalized head.
10
+ *
11
+ * TODO: Lighthouse uses 8 for the attack described above. However, 8 kills Lodestar since validators
12
+ * can trigger regen to fast-forward head state 8 epochs to be immediately invalidated as sync sets
13
+ * a new head. Then the checkpoint state cache grows unbounded with very different states (because
14
+ * they are 8 epochs apart) and causes an OOM. Research a proper solution once regen and the state
15
+ * caches are better.
16
+ */
17
+ export const SYNC_TOLERANCE_EPOCHS = 1;
18
+ /**
19
+ * Reject any request while the node is syncing. Used by endpoints that must not serve while the
20
+ * node is behind — validator duties, and beacon state lookups whose regen could otherwise walk
21
+ * back past the block-root window (`SLOTS_PER_HISTORICAL_ROOT`) and wedge the node. Throws
22
+ * {@link NodeIsSyncing} (503).
23
+ */
24
+ export function notWhileSyncing(chain, syncState) {
25
+ // Consider node synced before or close to genesis
26
+ if (chain.clock.currentSlot < SLOTS_PER_EPOCH) {
27
+ return;
28
+ }
29
+ switch (syncState) {
30
+ case SyncState.SyncingFinalized:
31
+ case SyncState.SyncingHead: {
32
+ const currentSlot = chain.clock.currentSlot;
33
+ const headSlot = chain.forkChoice.getHead().slot;
34
+ if (currentSlot - headSlot > SYNC_TOLERANCE_EPOCHS * SLOTS_PER_EPOCH) {
35
+ throw new NodeIsSyncing(`headSlot ${headSlot} currentSlot ${currentSlot}`);
36
+ }
37
+ return;
38
+ }
39
+ case SyncState.Synced:
40
+ return;
41
+ case SyncState.Stalled:
42
+ throw new NodeIsSyncing("waiting for peers");
43
+ }
44
+ }
2
45
  /**
3
46
  * Ensures that the array contains unique values, and throws an ApiError
4
47
  * otherwise.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/api/impl/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA4B,EAAE,OAAe,EAAQ;IACrF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;IACT,CAAC;IAED,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,qBAAgC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrF,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3E,OAAO,qBAAqB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,qBAAqB,CAAC;IAAA,CAC9B,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,cAAc,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,GAAG,OAAO,KAAK,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;AAAA,CACF"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/api/impl/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAC,QAAQ,EAAE,aAAa,EAAC,MAAM,aAAa,CAAC;AAEpD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAmB,EAAE,SAAoB,EAAQ;IAC/E,kDAAkD;IAClD,IAAI,KAAK,CAAC,KAAK,CAAC,WAAW,GAAG,eAAe,EAAE,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,SAAS,CAAC,gBAAgB,CAAC;QAChC,KAAK,SAAS,CAAC,WAAW,EAAE,CAAC;YAC3B,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;YAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC;YACjD,IAAI,WAAW,GAAG,QAAQ,GAAG,qBAAqB,GAAG,eAAe,EAAE,CAAC;gBACrE,MAAM,IAAI,aAAa,CAAC,YAAY,QAAQ,gBAAgB,WAAW,EAAE,CAAC,CAAC;YAC7E,CAAC;YAED,OAAO;QACT,CAAC;QAED,KAAK,SAAS,CAAC,MAAM;YACnB,OAAO;QAET,KAAK,SAAS,CAAC,OAAO;YACpB,MAAM,IAAI,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACjD,CAAC;AAAA,CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA4B,EAAE,OAAe,EAAQ;IACrF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;IACT,CAAC;IAED,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,qBAAgC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrF,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3E,OAAO,qBAAqB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,qBAAqB,CAAC;IAAA,CAC9B,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,cAAc,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,GAAG,OAAO,KAAK,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;AAAA,CACF"}
@@ -3,20 +3,6 @@ import { ApplicationMethods } from "@lodestar/api/server";
3
3
  import { ProducedBlockSource } from "@lodestar/types";
4
4
  import { ApiOptions } from "../../options.js";
5
5
  import { ApiModules } from "../types.js";
6
- /**
7
- * If the node is within this many epochs from the head, we declare it to be synced regardless of
8
- * the network sync state.
9
- *
10
- * This helps prevent attacks where nodes can convince us that we're syncing some non-existent
11
- * finalized head.
12
- *
13
- * TODO: Lighthouse uses 8 for the attack described above. However, 8 kills Lodestar since validators
14
- * can trigger regen to fast-forward head state 8 epochs to be immediately invalidated as sync sets
15
- * a new head. Then the checkpoint state cache grows unbounded with very different states (because
16
- * they are 8 epochs apart) and causes an OOM. Research a proper solution once regen and the state
17
- * caches are better.
18
- */
19
- export declare const SYNC_TOLERANCE_EPOCHS = 1;
20
6
  /**
21
7
  * Engine block selection reasons tracked in metrics / logs
22
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/impl/validator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,eAAe,CAAC;AACrC,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AA+BxD,OAAO,EAQL,mBAAmB,EAUpB,MAAM,iBAAiB,CAAC;AAoCzB,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAGvC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AA8BvC;;GAEG;AACH,oBAAY,0BAA0B;IACpC,eAAe,qBAAqB;IACpC,YAAY,kBAAkB;IAC9B,cAAc,oBAAoB;IAClC,cAAc,oBAAoB;IAClC,YAAY,mBAAmB;IAC/B,iBAAiB,uBAAuB;IACxC,UAAU,gBAAgB;IAC1B,eAAe,qBAAqB;CACrC;AAED;;GAEG;AACH,oBAAY,2BAA2B;IACrC,cAAc,oBAAoB;IAClC,WAAW,iBAAiB;IAC5B,aAAa,mBAAmB;IAChC,UAAU,gBAAgB;IAC1B,gBAAgB,sBAAsB;CACvC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IACE,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC;IACnC,MAAM,EAAE,0BAA0B,CAAC;CACpC,GACD;IACE,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC;IACpC,MAAM,EAAE,2BAA2B,CAAC;CACrC,CAAC;AAEN;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,EAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAC,EAAE,UAAU,GAC1D,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAsmDhD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/impl/validator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,eAAe,CAAC;AACrC,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AA+BxD,OAAO,EAQL,mBAAmB,EAUpB,MAAM,iBAAiB,CAAC;AAsCzB,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAgCvC;;GAEG;AACH,oBAAY,0BAA0B;IACpC,eAAe,qBAAqB;IACpC,YAAY,kBAAkB;IAC9B,cAAc,oBAAoB;IAClC,cAAc,oBAAoB;IAClC,YAAY,mBAAmB;IAC/B,iBAAiB,uBAAuB;IACxC,UAAU,gBAAgB;IAC1B,eAAe,qBAAqB;CACrC;AAED;;GAEG;AACH,oBAAY,2BAA2B;IACrC,cAAc,oBAAoB;IAClC,WAAW,iBAAiB;IAC5B,aAAa,mBAAmB;IAChC,UAAU,gBAAgB;IAC1B,gBAAgB,sBAAsB;CACvC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IACE,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC;IACnC,MAAM,EAAE,0BAA0B,CAAC;CACpC,GACD;IACE,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC;IACpC,MAAM,EAAE,2BAA2B,CAAC;CACrC,CAAC;AAEN;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,EAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAC,EAAE,UAAU,GAC1D,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAsnDhD"}
@@ -6,38 +6,25 @@ import { ProducedBlockSource, getValidatorStatus, ssz, } from "@lodestar/types";
6
6
  import { TimeoutError, defer, formatWeiToEth, fromHex, prettyWeiToEth, resolveOrRacePromises, toHex, toRootHex, } from "@lodestar/utils";
7
7
  import { MAX_BUILDER_BOOST_FACTOR } from "@lodestar/validator";
8
8
  import { BlockInputSource } from "../../../chain/blocks/blockInput/types.js";
9
- import { AttestationError, AttestationErrorCode, GossipAction, SyncCommitteeError, SyncCommitteeErrorCode, } from "../../../chain/errors/index.js";
9
+ import { AttestationError, AttestationErrorCode, GossipAction, ProposerPreferencesError, ProposerPreferencesErrorCode, SyncCommitteeError, SyncCommitteeErrorCode, } from "../../../chain/errors/index.js";
10
10
  import { ChainEvent } from "../../../chain/index.js";
11
11
  import { PREPARE_NEXT_SLOT_BPS } from "../../../chain/prepareNextSlot.js";
12
12
  import { BlockType } from "../../../chain/produceBlock/index.js";
13
13
  import { RegenCaller } from "../../../chain/regen/index.js";
14
14
  import { validateApiAggregateAndProof } from "../../../chain/validation/index.js";
15
+ import { validateGossipProposerPreferences } from "../../../chain/validation/proposerPreferences.js";
15
16
  import { validateSyncCommitteeGossipContributionAndProof } from "../../../chain/validation/syncCommitteeContributionAndProof.js";
16
17
  import { ZERO_HASH } from "../../../constants/index.js";
17
18
  import { BuilderStatus, NoBidReceived } from "../../../execution/builder/http.js";
18
19
  import { validateGossipFnRetryUnknownRoot } from "../../../network/processor/gossipHandlers.js";
19
- import { SyncState } from "../../../sync/index.js";
20
20
  import { callInNextEventLoop } from "../../../util/eventLoop.js";
21
21
  import { isOptimisticBlock } from "../../../util/forkChoice.js";
22
- import { getDefaultGraffiti, toGraffitiBytes } from "../../../util/graffiti.js";
22
+ import { getBlockGraffiti, toGraffitiBytes } from "../../../util/graffiti.js";
23
23
  import { getLodestarClientVersion } from "../../../util/metadata.js";
24
24
  import { getStateResponseWithRegen } from "../beacon/state/utils.js";
25
25
  import { ApiError, IndexedError, NodeIsSyncing, OnlySupportedByDVT } from "../errors.js";
26
+ import { notWhileSyncing } from "../utils.js";
26
27
  import { computeSubnetForCommitteesAtSlot, getPubkeysForIndices, selectBlockProductionSource } from "./utils.js";
27
- /**
28
- * If the node is within this many epochs from the head, we declare it to be synced regardless of
29
- * the network sync state.
30
- *
31
- * This helps prevent attacks where nodes can convince us that we're syncing some non-existent
32
- * finalized head.
33
- *
34
- * TODO: Lighthouse uses 8 for the attack described above. However, 8 kills Lodestar since validators
35
- * can trigger regen to fast-forward head state 8 epochs to be immediately invalidated as sync sets
36
- * a new head. Then the checkpoint state cache grows unbounded with very different states (because
37
- * they are 8 epochs apart) and causes an OOM. Research a proper solution once regen and the state
38
- * caches are better.
39
- */
40
- export const SYNC_TOLERANCE_EPOCHS = 1;
41
28
  /**
42
29
  * Cutoff time to wait from start of the slot for execution and builder block production apis to resolve.
43
30
  * Post this time, race execution and builder to pick whatever resolves first.
@@ -221,31 +208,6 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
221
208
  }
222
209
  return null;
223
210
  }
224
- /**
225
- * Reject any request while the node is syncing
226
- */
227
- function notWhileSyncing() {
228
- // Consider node synced before or close to genesis
229
- if (chain.clock.currentSlot < SLOTS_PER_EPOCH) {
230
- return;
231
- }
232
- const syncState = sync.state;
233
- switch (syncState) {
234
- case SyncState.SyncingFinalized:
235
- case SyncState.SyncingHead: {
236
- const currentSlot = chain.clock.currentSlot;
237
- const headSlot = chain.forkChoice.getHead().slot;
238
- if (currentSlot - headSlot > SYNC_TOLERANCE_EPOCHS * SLOTS_PER_EPOCH) {
239
- throw new NodeIsSyncing(`headSlot ${headSlot} currentSlot ${currentSlot}`);
240
- }
241
- return;
242
- }
243
- case SyncState.Synced:
244
- return;
245
- case SyncState.Stalled:
246
- throw new NodeIsSyncing("waiting for peers");
247
- }
248
- }
249
211
  /**
250
212
  * Post merge, the CL and EL could be out of step in the sync, and could result in
251
213
  * Syncing status of the chain head. To be precise:
@@ -402,7 +364,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
402
364
  async function produceEngineOrBuilderBlock(slot, randaoReveal, graffiti,
403
365
  // TODO deneb: skip randao verification
404
366
  _skipRandaoVerification, builderBoostFactor, { feeRecipient, builderSelection, strictFeeRecipientCheck } = {}) {
405
- notWhileSyncing();
367
+ notWhileSyncing(chain, sync.state);
406
368
  await waitForSlot(slot); // Must never request for a future slot > currentSlot
407
369
  const parentBlock = chain.getProposerHead(slot);
408
370
  const { blockRoot: parentBlockRootHex, slot: parentSlot } = parentBlock;
@@ -433,7 +395,10 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
433
395
  if (!isEngineEnabled && !isBuilderEnabled) {
434
396
  throw Error(`Internal Error: Neither builder nor execution proposal flow activated isBuilderEnabled=${isBuilderEnabled} builderSelection=${builderSelection}`);
435
397
  }
436
- const graffitiBytes = toGraffitiBytes(graffiti ?? getDefaultGraffiti(getLodestarClientVersion(opts), chain.executionEngine.clientVersion, opts));
398
+ const graffitiBytes = toGraffitiBytes(getBlockGraffiti(graffiti, getLodestarClientVersion(opts), chain.executionEngine.clientVersion, {
399
+ private: opts.private,
400
+ graffitiAppend: chain.opts.graffitiAppend,
401
+ }));
437
402
  const loggerContext = {
438
403
  slot,
439
404
  parentSlot,
@@ -672,14 +637,17 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
672
637
  if (!isForkPostGloas(fork)) {
673
638
  throw new ApiError(400, `produceBlockV4 not supported for pre-gloas fork=${fork}`);
674
639
  }
675
- notWhileSyncing();
640
+ notWhileSyncing(chain, sync.state);
676
641
  await waitForSlot(slot);
677
642
  const parentBlock = chain.getProposerHead(slot);
678
643
  const { blockRoot: parentBlockRootHex, slot: parentSlot } = parentBlock;
679
644
  const parentBlockRoot = fromHex(parentBlockRootHex);
680
645
  notOnOutOfRangeData(parentBlockRoot);
681
646
  metrics?.blockProductionSlotDelta.set(slot - parentSlot);
682
- const graffitiBytes = toGraffitiBytes(graffiti ?? getDefaultGraffiti(getLodestarClientVersion(opts), chain.executionEngine.clientVersion, opts));
647
+ const graffitiBytes = toGraffitiBytes(getBlockGraffiti(graffiti, getLodestarClientVersion(opts), chain.executionEngine.clientVersion, {
648
+ private: opts.private,
649
+ graffitiAppend: chain.opts.graffitiAppend,
650
+ }));
683
651
  // TODO GLOAS: respect builderSelection (MaxProfit, BuilderAlways, ExecutionAlways, etc.) to let
684
652
  // the user control bid source preferences and value comparison. Also add external builder api
685
653
  // support when it is implemented.
@@ -770,7 +738,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
770
738
  };
771
739
  },
772
740
  async produceAttestationData({ committeeIndex, slot }) {
773
- notWhileSyncing();
741
+ notWhileSyncing(chain, sync.state);
774
742
  await waitForSlot(slot); // Must never request for a future slot > currentSlot
775
743
  // This needs a state in the same epoch as `slot` such that state.currentJustifiedCheckpoint is correct.
776
744
  // Note: This may trigger an epoch transition if there skipped slots at the beginning of the epoch.
@@ -841,12 +809,12 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
841
809
  if (!isForkPostGloas(fork)) {
842
810
  throw new ApiError(400, `producePayloadAttestationData is not supported before Gloas fork=${fork}`);
843
811
  }
844
- notWhileSyncing();
812
+ notWhileSyncing(chain, sync.state);
845
813
  await waitForSlot(slot);
846
814
  const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
847
815
  if (!block) {
848
- // No block is seen at slot. Return 404 so vc can skip casting payload attestation.
849
- throw new ApiError(404, `No canonical block found at slot=${slot}`);
816
+ // No canonical block is seen at slot. Return 204 so vc can skip casting payload attestation.
817
+ return { data: undefined, meta: { version: fork }, status: 204 };
850
818
  }
851
819
  const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
852
820
  // Spec: set payload_present only if the envelope was seen before get_payload_due_ms()
@@ -910,7 +878,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
910
878
  return { data: contribution };
911
879
  },
912
880
  async getProposerDuties({ epoch }, _context, opts) {
913
- notWhileSyncing();
881
+ notWhileSyncing(chain, sync.state);
914
882
  const currentEpoch = currentEpochWithDisparity();
915
883
  const nextEpoch = currentEpoch + 1;
916
884
  const startSlot = computeStartSlotAtEpoch(epoch);
@@ -952,7 +920,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
952
920
  state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.getDuties);
953
921
  }
954
922
  else {
955
- const res = await getStateResponseWithRegen(chain, startSlot);
923
+ const res = await getStateResponseWithRegen(chain, sync, startSlot);
956
924
  state = res.state instanceof Uint8Array ? chain.getHeadState().loadOtherState(res.state) : res.state;
957
925
  if (state.epoch !== epoch) {
958
926
  throw Error(`Loaded state epoch ${state.epoch} does not match requested epoch ${epoch}`);
@@ -1028,7 +996,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1028
996
  return this.getProposerDuties(args, context, { v2: true });
1029
997
  },
1030
998
  async getAttesterDuties({ epoch, indices }) {
1031
- notWhileSyncing();
999
+ notWhileSyncing(chain, sync.state);
1032
1000
  if (indices.length === 0) {
1033
1001
  throw new ApiError(400, "No validator to get attester duties");
1034
1002
  }
@@ -1076,7 +1044,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1076
1044
  };
1077
1045
  },
1078
1046
  async getPtcDuties({ epoch, indices }) {
1079
- notWhileSyncing();
1047
+ notWhileSyncing(chain, sync.state);
1080
1048
  if (indices.length === 0) {
1081
1049
  throw new ApiError(400, "No validator to get PTC duties");
1082
1050
  }
@@ -1129,7 +1097,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1129
1097
  * @param validatorIndices an array of the validator indices for which to obtain the duties.
1130
1098
  */
1131
1099
  async getSyncCommitteeDuties({ epoch, indices }) {
1132
- notWhileSyncing();
1100
+ notWhileSyncing(chain, sync.state);
1133
1101
  if (indices.length === 0) {
1134
1102
  throw new ApiError(400, "No validator to get attester duties");
1135
1103
  }
@@ -1169,7 +1137,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1169
1137
  };
1170
1138
  },
1171
1139
  async getAggregatedAttestationV2({ attestationDataRoot, slot, committeeIndex }) {
1172
- notWhileSyncing();
1140
+ notWhileSyncing(chain, sync.state);
1173
1141
  await waitForSlot(slot); // Must never request for a future slot > currentSlot
1174
1142
  const dataRootHex = toRootHex(attestationDataRoot);
1175
1143
  const aggregate = chain.attestationPool.getAggregate(slot, dataRootHex, committeeIndex);
@@ -1183,7 +1151,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1183
1151
  };
1184
1152
  },
1185
1153
  async publishAggregateAndProofsV2({ signedAggregateAndProofs }) {
1186
- notWhileSyncing();
1154
+ notWhileSyncing(chain, sync.state);
1187
1155
  const seenTimestampSec = Date.now() / 1000;
1188
1156
  const failures = [];
1189
1157
  const fork = chain.config.getForkName(chain.clock.currentSlot);
@@ -1229,7 +1197,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1229
1197
  * https://github.com/ethereum/beacon-APIs/pull/137
1230
1198
  */
1231
1199
  async publishContributionAndProofs({ contributionAndProofs }) {
1232
- notWhileSyncing();
1200
+ notWhileSyncing(chain, sync.state);
1233
1201
  const failures = [];
1234
1202
  await Promise.all(contributionAndProofs.map(async (contributionAndProof, i) => {
1235
1203
  try {
@@ -1262,7 +1230,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1262
1230
  }
1263
1231
  },
1264
1232
  async prepareBeaconCommitteeSubnet({ subscriptions }) {
1265
- notWhileSyncing();
1233
+ notWhileSyncing(chain, sync.state);
1266
1234
  await network.prepareBeaconCommitteeSubnets(subscriptions.map(({ validatorIndex, slot, isAggregator, committeesAtSlot, committeeIndex }) => ({
1267
1235
  validatorIndex: validatorIndex,
1268
1236
  subnet: computeSubnetForCommitteesAtSlot(slot, committeesAtSlot, committeeIndex),
@@ -1289,7 +1257,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1289
1257
  * https://github.com/ethereum/beacon-APIs/pull/136
1290
1258
  */
1291
1259
  async prepareSyncCommitteeSubnets({ subscriptions }) {
1292
- notWhileSyncing();
1260
+ notWhileSyncing(chain, sync.state);
1293
1261
  // A `validatorIndex` can be in multiple subnets, so compute the CommitteeSubscription with double for loop
1294
1262
  const subs = [];
1295
1263
  for (const sub of subscriptions) {
@@ -1364,12 +1332,45 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
1364
1332
  count: filteredRegistrations.length,
1365
1333
  });
1366
1334
  },
1335
+ async submitProposerPreferences({ signedProposerPreferences }) {
1336
+ const failures = [];
1337
+ await Promise.all(signedProposerPreferences.map(async (signed, i) => {
1338
+ try {
1339
+ await validateGossipProposerPreferences(chain, signed);
1340
+ chain.proposerPreferencesPool.add(signed);
1341
+ await network.publishProposerPreferences(signed);
1342
+ chain.emitter.emit(routes.events.EventType.proposerPreferences, {
1343
+ version: config.getForkName(signed.message.proposalSlot),
1344
+ data: signed,
1345
+ });
1346
+ }
1347
+ catch (e) {
1348
+ const logCtx = {
1349
+ slot: signed.message.proposalSlot,
1350
+ validatorIndex: signed.message.validatorIndex,
1351
+ dependentRoot: toRootHex(signed.message.dependentRoot),
1352
+ };
1353
+ if (e instanceof ProposerPreferencesError && e.type.code === ProposerPreferencesErrorCode.ALREADY_KNOWN) {
1354
+ logger.debug("Ignoring known signed proposer preferences", logCtx);
1355
+ return;
1356
+ }
1357
+ failures.push({ index: i, message: e.message });
1358
+ logger.verbose(`Error on submitProposerPreferences [${i}]`, logCtx, e);
1359
+ if (e instanceof ProposerPreferencesError && e.action === GossipAction.REJECT) {
1360
+ chain.persistInvalidSszValue(ssz.gloas.SignedProposerPreferences, signed, "api_reject");
1361
+ }
1362
+ }
1363
+ }));
1364
+ if (failures.length > 0) {
1365
+ throw new IndexedError("Error processing signed proposer preferences", failures);
1366
+ }
1367
+ },
1367
1368
  async getExecutionPayloadEnvelope({ slot, beaconBlockRoot }) {
1368
1369
  const fork = config.getForkName(slot);
1369
1370
  if (!isForkPostGloas(fork)) {
1370
1371
  throw new ApiError(400, `getExecutionPayloadEnvelope not supported for pre-gloas fork=${fork}`);
1371
1372
  }
1372
- notWhileSyncing();
1373
+ notWhileSyncing(chain, sync.state);
1373
1374
  await waitForSlot(slot);
1374
1375
  const blockRootHex = toRootHex(beaconBlockRoot);
1375
1376
  const produceResult = chain.blockProductionCache.get(blockRootHex);