@lodestar/beacon-node 1.45.0-dev.f535421f29 → 1.45.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/impl/beacon/index.d.ts +1 -1
- package/lib/api/impl/beacon/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +6 -43
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.d.ts +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +48 -5
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +13 -3
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +48 -4
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +2 -2
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +2 -2
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/proof/index.d.ts +1 -1
- package/lib/api/impl/proof/index.d.ts.map +1 -1
- package/lib/api/impl/proof/index.js +2 -2
- package/lib/api/impl/proof/index.js.map +1 -1
- package/lib/api/impl/utils.d.ts +23 -0
- package/lib/api/impl/utils.d.ts.map +1 -1
- package/lib/api/impl/utils.js +44 -1
- package/lib/api/impl/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts +0 -14
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +67 -62
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/rest/base.d.ts.map +1 -1
- package/lib/api/rest/base.js +8 -0
- package/lib/api/rest/base.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +2 -5
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/builderCircuitBreaker.d.ts +31 -0
- package/lib/chain/builderCircuitBreaker.d.ts.map +1 -0
- package/lib/chain/builderCircuitBreaker.js +59 -0
- package/lib/chain/builderCircuitBreaker.js.map +1 -0
- package/lib/chain/chain.d.ts +3 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +4 -3
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/interface.d.ts +3 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +2 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js +3 -0
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
- package/lib/chain/options.d.ts +5 -0
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -0
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +12 -7
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +4 -12
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/seenCache/index.d.ts +0 -1
- package/lib/chain/seenCache/index.d.ts.map +1 -1
- package/lib/chain/seenCache/index.js +0 -1
- package/lib/chain/seenCache/index.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +11 -10
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +14 -5
- package/lib/chain/validation/proposerPreferences.js.map +1 -1
- package/lib/execution/builder/http.d.ts +18 -0
- package/lib/execution/builder/http.d.ts.map +1 -1
- package/lib/execution/builder/http.js +20 -11
- package/lib/execution/builder/http.js.map +1 -1
- package/lib/metrics/metrics/beacon.d.ts +6 -0
- package/lib/metrics/metrics/beacon.d.ts.map +1 -1
- package/lib/metrics/metrics/beacon.js +18 -0
- package/lib/metrics/metrics/beacon.js.map +1 -1
- package/lib/network/core/metrics.d.ts +65 -0
- package/lib/network/core/metrics.d.ts.map +1 -1
- package/lib/network/core/metrics.js +94 -0
- package/lib/network/core/metrics.js.map +1 -1
- package/lib/network/discv5/utils.d.ts.map +1 -1
- package/lib/network/discv5/utils.js +12 -3
- package/lib/network/discv5/utils.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +7 -0
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +2 -1
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +765 -3
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +23 -3
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/peers/peerManager.d.ts.map +1 -1
- package/lib/network/peers/peerManager.js +10 -0
- package/lib/network/peers/peerManager.js.map +1 -1
- package/lib/network/peers/score/score.d.ts +3 -1
- package/lib/network/peers/score/score.d.ts.map +1 -1
- package/lib/network/peers/score/score.js +6 -1
- package/lib/network/peers/score/score.js.map +1 -1
- package/lib/network/peers/score/store.d.ts.map +1 -1
- package/lib/network/peers/score/store.js +6 -1
- package/lib/network/peers/score/store.js.map +1 -1
- package/lib/network/peers/utils/prioritizePeers.d.ts.map +1 -1
- package/lib/network/peers/utils/prioritizePeers.js +14 -0
- package/lib/network/peers/utils/prioritizePeers.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +6 -3
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/util/graffiti.d.ts +15 -0
- package/lib/util/graffiti.d.ts.map +1 -1
- package/lib/util/graffiti.js +55 -0
- package/lib/util/graffiti.js.map +1 -1
- package/package.json +19 -19
- package/src/api/impl/beacon/index.ts +1 -1
- package/src/api/impl/beacon/pool/index.ts +5 -53
- package/src/api/impl/beacon/state/index.ts +55 -3
- package/src/api/impl/beacon/state/utils.ts +68 -4
- package/src/api/impl/debug/index.ts +3 -2
- package/src/api/impl/lodestar/index.ts +2 -2
- package/src/api/impl/proof/index.ts +2 -2
- package/src/api/impl/utils.ts +51 -1
- package/src/api/impl/validator/index.ts +75 -67
- package/src/api/rest/base.ts +9 -0
- package/src/chain/blocks/importBlock.ts +2 -7
- package/src/chain/builderCircuitBreaker.ts +84 -0
- package/src/chain/chain.ts +7 -3
- package/src/chain/interface.ts +2 -2
- package/src/chain/opPools/proposerPreferencesPool.ts +5 -1
- package/src/chain/options.ts +6 -0
- package/src/chain/prepareNextSlot.ts +11 -7
- package/src/chain/produceBlock/produceBlockBody.ts +9 -17
- package/src/chain/seenCache/index.ts +0 -1
- package/src/chain/validation/executionPayloadBid.ts +14 -9
- package/src/chain/validation/proposerPreferences.ts +15 -5
- package/src/execution/builder/http.ts +30 -17
- package/src/metrics/metrics/beacon.ts +19 -0
- package/src/network/core/metrics.ts +94 -0
- package/src/network/discv5/utils.ts +11 -3
- package/src/network/gossip/encoding.ts +7 -0
- package/src/network/gossip/gossipsub.ts +2 -1
- package/src/network/gossip/topic.ts +28 -4
- package/src/network/peers/peerManager.ts +11 -0
- package/src/network/peers/score/score.ts +8 -1
- package/src/network/peers/score/store.ts +8 -1
- package/src/network/peers/utils/prioritizePeers.ts +15 -0
- package/src/network/processor/gossipHandlers.ts +6 -2
- package/src/util/graffiti.ts +78 -0
- package/lib/chain/seenCache/seenProposerPreferences.d.ts +0 -16
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +0 -1
- package/lib/chain/seenCache/seenProposerPreferences.js +0 -26
- package/lib/chain/seenCache/seenProposerPreferences.js.map +0 -1
- 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,
|
|
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,
|
|
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"}
|
package/lib/api/impl/utils.d.ts
CHANGED
|
@@ -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":"
|
|
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"}
|
package/lib/api/impl/utils.js
CHANGED
|
@@ -1,4 +1,47 @@
|
|
|
1
|
-
import {
|
|
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;
|
|
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;
|
|
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,CA0nDhD"}
|
|
@@ -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 {
|
|
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
|
|
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,26 +637,33 @@ 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
|
|
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.
|
|
686
654
|
const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
|
|
687
655
|
const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
|
|
688
|
-
const
|
|
656
|
+
const circuitBreakerActive = chain.builderCircuitBreaker.isActive(slot);
|
|
657
|
+
const builderBid = circuitBreakerActive
|
|
658
|
+
? null
|
|
659
|
+
: chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
|
|
689
660
|
const logCtx = {
|
|
690
661
|
slot,
|
|
691
662
|
parentSlot,
|
|
692
663
|
parentBlockRoot: parentBlockRootHex,
|
|
693
664
|
parentBlockHash: parentBlock.executionPayloadBlockHash,
|
|
694
665
|
fork,
|
|
666
|
+
circuitBreakerActive,
|
|
695
667
|
...(builderBid !== null
|
|
696
668
|
? {
|
|
697
669
|
bidValue: builderBid.message.value,
|
|
@@ -770,7 +742,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
770
742
|
};
|
|
771
743
|
},
|
|
772
744
|
async produceAttestationData({ committeeIndex, slot }) {
|
|
773
|
-
notWhileSyncing();
|
|
745
|
+
notWhileSyncing(chain, sync.state);
|
|
774
746
|
await waitForSlot(slot); // Must never request for a future slot > currentSlot
|
|
775
747
|
// This needs a state in the same epoch as `slot` such that state.currentJustifiedCheckpoint is correct.
|
|
776
748
|
// Note: This may trigger an epoch transition if there skipped slots at the beginning of the epoch.
|
|
@@ -841,12 +813,12 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
841
813
|
if (!isForkPostGloas(fork)) {
|
|
842
814
|
throw new ApiError(400, `producePayloadAttestationData is not supported before Gloas fork=${fork}`);
|
|
843
815
|
}
|
|
844
|
-
notWhileSyncing();
|
|
816
|
+
notWhileSyncing(chain, sync.state);
|
|
845
817
|
await waitForSlot(slot);
|
|
846
818
|
const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
|
|
847
819
|
if (!block) {
|
|
848
|
-
// No block is seen at slot. Return
|
|
849
|
-
|
|
820
|
+
// No canonical block is seen at slot. Return 204 so vc can skip casting payload attestation.
|
|
821
|
+
return { data: undefined, meta: { version: fork }, status: 204 };
|
|
850
822
|
}
|
|
851
823
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
|
|
852
824
|
// Spec: set payload_present only if the envelope was seen before get_payload_due_ms()
|
|
@@ -910,7 +882,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
910
882
|
return { data: contribution };
|
|
911
883
|
},
|
|
912
884
|
async getProposerDuties({ epoch }, _context, opts) {
|
|
913
|
-
notWhileSyncing();
|
|
885
|
+
notWhileSyncing(chain, sync.state);
|
|
914
886
|
const currentEpoch = currentEpochWithDisparity();
|
|
915
887
|
const nextEpoch = currentEpoch + 1;
|
|
916
888
|
const startSlot = computeStartSlotAtEpoch(epoch);
|
|
@@ -952,7 +924,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
952
924
|
state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.getDuties);
|
|
953
925
|
}
|
|
954
926
|
else {
|
|
955
|
-
const res = await getStateResponseWithRegen(chain, startSlot);
|
|
927
|
+
const res = await getStateResponseWithRegen(chain, sync, startSlot);
|
|
956
928
|
state = res.state instanceof Uint8Array ? chain.getHeadState().loadOtherState(res.state) : res.state;
|
|
957
929
|
if (state.epoch !== epoch) {
|
|
958
930
|
throw Error(`Loaded state epoch ${state.epoch} does not match requested epoch ${epoch}`);
|
|
@@ -1028,7 +1000,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1028
1000
|
return this.getProposerDuties(args, context, { v2: true });
|
|
1029
1001
|
},
|
|
1030
1002
|
async getAttesterDuties({ epoch, indices }) {
|
|
1031
|
-
notWhileSyncing();
|
|
1003
|
+
notWhileSyncing(chain, sync.state);
|
|
1032
1004
|
if (indices.length === 0) {
|
|
1033
1005
|
throw new ApiError(400, "No validator to get attester duties");
|
|
1034
1006
|
}
|
|
@@ -1076,7 +1048,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1076
1048
|
};
|
|
1077
1049
|
},
|
|
1078
1050
|
async getPtcDuties({ epoch, indices }) {
|
|
1079
|
-
notWhileSyncing();
|
|
1051
|
+
notWhileSyncing(chain, sync.state);
|
|
1080
1052
|
if (indices.length === 0) {
|
|
1081
1053
|
throw new ApiError(400, "No validator to get PTC duties");
|
|
1082
1054
|
}
|
|
@@ -1129,7 +1101,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1129
1101
|
* @param validatorIndices an array of the validator indices for which to obtain the duties.
|
|
1130
1102
|
*/
|
|
1131
1103
|
async getSyncCommitteeDuties({ epoch, indices }) {
|
|
1132
|
-
notWhileSyncing();
|
|
1104
|
+
notWhileSyncing(chain, sync.state);
|
|
1133
1105
|
if (indices.length === 0) {
|
|
1134
1106
|
throw new ApiError(400, "No validator to get attester duties");
|
|
1135
1107
|
}
|
|
@@ -1169,7 +1141,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1169
1141
|
};
|
|
1170
1142
|
},
|
|
1171
1143
|
async getAggregatedAttestationV2({ attestationDataRoot, slot, committeeIndex }) {
|
|
1172
|
-
notWhileSyncing();
|
|
1144
|
+
notWhileSyncing(chain, sync.state);
|
|
1173
1145
|
await waitForSlot(slot); // Must never request for a future slot > currentSlot
|
|
1174
1146
|
const dataRootHex = toRootHex(attestationDataRoot);
|
|
1175
1147
|
const aggregate = chain.attestationPool.getAggregate(slot, dataRootHex, committeeIndex);
|
|
@@ -1183,7 +1155,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1183
1155
|
};
|
|
1184
1156
|
},
|
|
1185
1157
|
async publishAggregateAndProofsV2({ signedAggregateAndProofs }) {
|
|
1186
|
-
notWhileSyncing();
|
|
1158
|
+
notWhileSyncing(chain, sync.state);
|
|
1187
1159
|
const seenTimestampSec = Date.now() / 1000;
|
|
1188
1160
|
const failures = [];
|
|
1189
1161
|
const fork = chain.config.getForkName(chain.clock.currentSlot);
|
|
@@ -1229,7 +1201,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1229
1201
|
* https://github.com/ethereum/beacon-APIs/pull/137
|
|
1230
1202
|
*/
|
|
1231
1203
|
async publishContributionAndProofs({ contributionAndProofs }) {
|
|
1232
|
-
notWhileSyncing();
|
|
1204
|
+
notWhileSyncing(chain, sync.state);
|
|
1233
1205
|
const failures = [];
|
|
1234
1206
|
await Promise.all(contributionAndProofs.map(async (contributionAndProof, i) => {
|
|
1235
1207
|
try {
|
|
@@ -1262,7 +1234,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1262
1234
|
}
|
|
1263
1235
|
},
|
|
1264
1236
|
async prepareBeaconCommitteeSubnet({ subscriptions }) {
|
|
1265
|
-
notWhileSyncing();
|
|
1237
|
+
notWhileSyncing(chain, sync.state);
|
|
1266
1238
|
await network.prepareBeaconCommitteeSubnets(subscriptions.map(({ validatorIndex, slot, isAggregator, committeesAtSlot, committeeIndex }) => ({
|
|
1267
1239
|
validatorIndex: validatorIndex,
|
|
1268
1240
|
subnet: computeSubnetForCommitteesAtSlot(slot, committeesAtSlot, committeeIndex),
|
|
@@ -1289,7 +1261,7 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1289
1261
|
* https://github.com/ethereum/beacon-APIs/pull/136
|
|
1290
1262
|
*/
|
|
1291
1263
|
async prepareSyncCommitteeSubnets({ subscriptions }) {
|
|
1292
|
-
notWhileSyncing();
|
|
1264
|
+
notWhileSyncing(chain, sync.state);
|
|
1293
1265
|
// A `validatorIndex` can be in multiple subnets, so compute the CommitteeSubscription with double for loop
|
|
1294
1266
|
const subs = [];
|
|
1295
1267
|
for (const sub of subscriptions) {
|
|
@@ -1364,12 +1336,45 @@ export function getValidatorApi(opts, { chain, config, logger, metrics, network,
|
|
|
1364
1336
|
count: filteredRegistrations.length,
|
|
1365
1337
|
});
|
|
1366
1338
|
},
|
|
1339
|
+
async submitProposerPreferences({ signedProposerPreferences }) {
|
|
1340
|
+
const failures = [];
|
|
1341
|
+
await Promise.all(signedProposerPreferences.map(async (signed, i) => {
|
|
1342
|
+
try {
|
|
1343
|
+
await validateGossipProposerPreferences(chain, signed);
|
|
1344
|
+
chain.proposerPreferencesPool.add(signed);
|
|
1345
|
+
await network.publishProposerPreferences(signed);
|
|
1346
|
+
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
1347
|
+
version: config.getForkName(signed.message.proposalSlot),
|
|
1348
|
+
data: signed,
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
catch (e) {
|
|
1352
|
+
const logCtx = {
|
|
1353
|
+
slot: signed.message.proposalSlot,
|
|
1354
|
+
validatorIndex: signed.message.validatorIndex,
|
|
1355
|
+
dependentRoot: toRootHex(signed.message.dependentRoot),
|
|
1356
|
+
};
|
|
1357
|
+
if (e instanceof ProposerPreferencesError && e.type.code === ProposerPreferencesErrorCode.ALREADY_KNOWN) {
|
|
1358
|
+
logger.debug("Ignoring known signed proposer preferences", logCtx);
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
failures.push({ index: i, message: e.message });
|
|
1362
|
+
logger.verbose(`Error on submitProposerPreferences [${i}]`, logCtx, e);
|
|
1363
|
+
if (e instanceof ProposerPreferencesError && e.action === GossipAction.REJECT) {
|
|
1364
|
+
chain.persistInvalidSszValue(ssz.gloas.SignedProposerPreferences, signed, "api_reject");
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}));
|
|
1368
|
+
if (failures.length > 0) {
|
|
1369
|
+
throw new IndexedError("Error processing signed proposer preferences", failures);
|
|
1370
|
+
}
|
|
1371
|
+
},
|
|
1367
1372
|
async getExecutionPayloadEnvelope({ slot, beaconBlockRoot }) {
|
|
1368
1373
|
const fork = config.getForkName(slot);
|
|
1369
1374
|
if (!isForkPostGloas(fork)) {
|
|
1370
1375
|
throw new ApiError(400, `getExecutionPayloadEnvelope not supported for pre-gloas fork=${fork}`);
|
|
1371
1376
|
}
|
|
1372
|
-
notWhileSyncing();
|
|
1377
|
+
notWhileSyncing(chain, sync.state);
|
|
1373
1378
|
await waitForSlot(slot);
|
|
1374
1379
|
const blockRootHex = toRootHex(beaconBlockRoot);
|
|
1375
1380
|
const produceResult = chain.blockProductionCache.get(blockRootHex);
|