@lodestar/beacon-node 1.45.0-dev.9d930bdc5b → 1.45.0-dev.aadf7a7167
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/blocks/verifyExecutionPayloadEnvelope.js +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.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/errors/blockError.d.ts +7 -0
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -0
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +11 -0
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +2 -0
- package/lib/chain/errors/executionPayloadEnvelope.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/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +11 -6
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/lightClient/proofs.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.js +28 -2
- package/lib/chain/lightClient/proofs.js.map +1 -1
- package/lib/chain/lightClient/types.d.ts +3 -1
- package/lib/chain/lightClient/types.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.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/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +3 -2
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +52 -1
- package/lib/chain/validation/block.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/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +30 -0
- package/lib/chain/validation/executionPayloadEnvelope.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/chain/validation/signatureSets/aggregateAndProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.js +2 -3
- package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
- package/lib/db/repositories/lightclientSyncCommitteeWitness.d.ts.map +1 -1
- package/lib/db/repositories/lightclientSyncCommitteeWitness.js +42 -7
- package/lib/db/repositories/lightclientSyncCommitteeWitness.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 +2 -2
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +22 -9
- 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 +4 -3
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +831 -226
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +47 -4
- 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/sync/range/chain.d.ts +4 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +3 -3
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +10 -0
- package/lib/sync/range/range.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/blocks/verifyExecutionPayloadEnvelope.ts +2 -2
- package/src/chain/builderCircuitBreaker.ts +84 -0
- package/src/chain/chain.ts +7 -3
- package/src/chain/errors/blockError.ts +3 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +9 -0
- package/src/chain/interface.ts +2 -2
- package/src/chain/lightClient/index.ts +12 -7
- package/src/chain/lightClient/proofs.ts +36 -1
- package/src/chain/lightClient/types.ts +3 -1
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- 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/stateCache/persistentCheckpointsCache.ts +3 -2
- package/src/chain/validation/block.ts +69 -1
- package/src/chain/validation/executionPayloadBid.ts +14 -9
- package/src/chain/validation/executionPayloadEnvelope.ts +39 -0
- package/src/chain/validation/proposerPreferences.ts +15 -5
- package/src/chain/validation/signatureSets/aggregateAndProof.ts +3 -3
- package/src/db/repositories/lightclientSyncCommitteeWitness.ts +57 -9
- 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 +20 -7
- package/src/network/gossip/gossipsub.ts +9 -3
- package/src/network/gossip/topic.ts +59 -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/sync/range/chain.ts +4 -5
- package/src/sync/range/range.ts +10 -0
- 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
package/lib/util/graffiti.js
CHANGED
|
@@ -25,4 +25,59 @@ export function getDefaultGraffiti(consensusClientVersion, executionClientVersio
|
|
|
25
25
|
// No EL client info available. We still want to include CL info albeit not spec compliant
|
|
26
26
|
return `${consensusClientVersion.code}${consensusClientVersion.commit.slice(0, 4)}`;
|
|
27
27
|
}
|
|
28
|
+
function appendLongestFittingSuffix(userGraffiti, suffixes) {
|
|
29
|
+
const userGraffitiBytes = Buffer.byteLength(userGraffiti, "utf8");
|
|
30
|
+
if (userGraffitiBytes >= GRAFFITI_SIZE) {
|
|
31
|
+
return userGraffiti;
|
|
32
|
+
}
|
|
33
|
+
const availableBytes = GRAFFITI_SIZE - userGraffitiBytes;
|
|
34
|
+
for (const suffix of suffixes) {
|
|
35
|
+
if (Buffer.byteLength(suffix, "utf8") <= availableBytes) {
|
|
36
|
+
return `${userGraffiti}${suffix}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return userGraffiti;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Appends the richest available client watermark that fits after user graffiti.
|
|
43
|
+
*
|
|
44
|
+
* Tiers are:
|
|
45
|
+
* - full EL/CL watermark, e.g. " BU9b0eLS80c2"
|
|
46
|
+
* - EL/CL client codes, e.g. " BULS"
|
|
47
|
+
* - CL client code, e.g. " LS"
|
|
48
|
+
*/
|
|
49
|
+
export function appendClientInfoToGraffiti(userGraffiti, consensusClientVersion, executionClientVersion, opts = {}) {
|
|
50
|
+
if (opts.private) {
|
|
51
|
+
return userGraffiti;
|
|
52
|
+
}
|
|
53
|
+
// Graffiti supplied via the beacon API is decoded from a fixed 32-byte field (see
|
|
54
|
+
// fromGraffitiHex) and arrives right-padded with NUL bytes. Trim only trailing padding
|
|
55
|
+
// NULs; a NUL that appears in the middle of the string is data, not padding.
|
|
56
|
+
let end = userGraffiti.length;
|
|
57
|
+
while (end > 0 && userGraffiti.charCodeAt(end - 1) === 0) {
|
|
58
|
+
end--;
|
|
59
|
+
}
|
|
60
|
+
const graffiti = userGraffiti.slice(0, end);
|
|
61
|
+
const fullClientInfo = getDefaultGraffiti(consensusClientVersion, executionClientVersion, { private: false });
|
|
62
|
+
if (graffiti.length === 0) {
|
|
63
|
+
return fullClientInfo;
|
|
64
|
+
}
|
|
65
|
+
const suffixes = executionClientVersion != null
|
|
66
|
+
? [
|
|
67
|
+
` ${fullClientInfo}`,
|
|
68
|
+
` ${executionClientVersion.code}${consensusClientVersion.code}`,
|
|
69
|
+
` ${consensusClientVersion.code}`,
|
|
70
|
+
]
|
|
71
|
+
: [` ${fullClientInfo}`, ` ${consensusClientVersion.code}`];
|
|
72
|
+
return appendLongestFittingSuffix(graffiti, suffixes);
|
|
73
|
+
}
|
|
74
|
+
export function getBlockGraffiti(userGraffiti, consensusClientVersion, executionClientVersion, opts) {
|
|
75
|
+
if (userGraffiti === undefined) {
|
|
76
|
+
return getDefaultGraffiti(consensusClientVersion, executionClientVersion, opts);
|
|
77
|
+
}
|
|
78
|
+
if (opts.graffitiAppend === false) {
|
|
79
|
+
return userGraffiti;
|
|
80
|
+
}
|
|
81
|
+
return appendClientInfoToGraffiti(userGraffiti, consensusClientVersion, executionClientVersion, opts);
|
|
82
|
+
}
|
|
28
83
|
//# sourceMappingURL=graffiti.js.map
|
package/lib/util/graffiti.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graffiti.js","sourceRoot":"","sources":["../../src/util/graffiti.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAC;AAGpD;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAW;IACzD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;AAAA,CACtG;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAiB,EAAU;IAC3D,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC;SAC1E,QAAQ,CAAC,MAAM,CAAC;SAChB,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAAA,CAC7B;AAED,MAAM,UAAU,kBAAkB,CAChC,sBAAqC,EACrC,sBAAwD,EACxD,IAAyB,EACjB;IACR,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,sBAAsB,IAAI,IAAI,EAAE,CAAC;QACnC,MAAM,EAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAC,GAAG,sBAAsB,CAAC;QAE9E,iHAAiH;QACjH,OAAO,GAAG,aAAa,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,sBAAsB,CAAC,IAAI,GAAG,sBAAsB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACpI,CAAC;IAED,0FAA0F;IAC1F,OAAO,GAAG,sBAAsB,CAAC,IAAI,GAAG,sBAAsB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AAAA,CACrF"}
|
|
1
|
+
{"version":3,"file":"graffiti.js","sourceRoot":"","sources":["../../src/util/graffiti.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/ChainSafe/lodestar/issues"
|
|
13
13
|
},
|
|
14
|
-
"version": "1.45.0-dev.
|
|
14
|
+
"version": "1.45.0-dev.aadf7a7167",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -108,16 +108,16 @@
|
|
|
108
108
|
"check-readme": "pnpm exec ts-node ../../scripts/check_readme.ts"
|
|
109
109
|
},
|
|
110
110
|
"dependencies": {
|
|
111
|
-
"@chainsafe/as-sha256": "^1.2.
|
|
111
|
+
"@chainsafe/as-sha256": "^1.2.4",
|
|
112
112
|
"@chainsafe/blst": "^2.2.0",
|
|
113
113
|
"@chainsafe/discv5": "^12.0.1",
|
|
114
114
|
"@chainsafe/enr": "^6.0.1",
|
|
115
115
|
"@chainsafe/libp2p-noise": "^17.0.0",
|
|
116
|
-
"@chainsafe/libp2p-quic": "^2.
|
|
117
|
-
"@chainsafe/persistent-merkle-tree": "^1.
|
|
116
|
+
"@chainsafe/libp2p-quic": "^2.1.1",
|
|
117
|
+
"@chainsafe/persistent-merkle-tree": "^1.3.0",
|
|
118
118
|
"@chainsafe/prometheus-gc-stats": "^1.0.0",
|
|
119
119
|
"@chainsafe/snappy-wasm": "^0.5.0",
|
|
120
|
-
"@chainsafe/ssz": "^1.
|
|
120
|
+
"@chainsafe/ssz": "^1.6.2",
|
|
121
121
|
"@chainsafe/threads": "^1.11.3",
|
|
122
122
|
"@crate-crypto/node-eth-kzg": "0.9.1",
|
|
123
123
|
"@fastify/bearer-auth": "^10.0.1",
|
|
@@ -134,17 +134,17 @@
|
|
|
134
134
|
"@libp2p/peer-id": "^6.0.4",
|
|
135
135
|
"@libp2p/prometheus-metrics": "^5.0.14",
|
|
136
136
|
"@libp2p/tcp": "^11.0.13",
|
|
137
|
-
"@lodestar/api": "^1.45.0-dev.
|
|
138
|
-
"@lodestar/config": "^1.45.0-dev.
|
|
139
|
-
"@lodestar/db": "^1.45.0-dev.
|
|
140
|
-
"@lodestar/fork-choice": "^1.45.0-dev.
|
|
141
|
-
"@lodestar/logger": "^1.45.0-dev.
|
|
142
|
-
"@lodestar/params": "^1.45.0-dev.
|
|
143
|
-
"@lodestar/reqresp": "^1.45.0-dev.
|
|
144
|
-
"@lodestar/state-transition": "^1.45.0-dev.
|
|
145
|
-
"@lodestar/types": "^1.45.0-dev.
|
|
146
|
-
"@lodestar/utils": "^1.45.0-dev.
|
|
147
|
-
"@lodestar/validator": "^1.45.0-dev.
|
|
137
|
+
"@lodestar/api": "^1.45.0-dev.aadf7a7167",
|
|
138
|
+
"@lodestar/config": "^1.45.0-dev.aadf7a7167",
|
|
139
|
+
"@lodestar/db": "^1.45.0-dev.aadf7a7167",
|
|
140
|
+
"@lodestar/fork-choice": "^1.45.0-dev.aadf7a7167",
|
|
141
|
+
"@lodestar/logger": "^1.45.0-dev.aadf7a7167",
|
|
142
|
+
"@lodestar/params": "^1.45.0-dev.aadf7a7167",
|
|
143
|
+
"@lodestar/reqresp": "^1.45.0-dev.aadf7a7167",
|
|
144
|
+
"@lodestar/state-transition": "^1.45.0-dev.aadf7a7167",
|
|
145
|
+
"@lodestar/types": "^1.45.0-dev.aadf7a7167",
|
|
146
|
+
"@lodestar/utils": "^1.45.0-dev.aadf7a7167",
|
|
147
|
+
"@lodestar/validator": "^1.45.0-dev.aadf7a7167",
|
|
148
148
|
"@multiformats/multiaddr": "^13.0.1",
|
|
149
149
|
"datastore-core": "^11.0.2",
|
|
150
150
|
"datastore-fs": "^11.0.2",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
"libp2p": "3.1.6",
|
|
157
157
|
"multiformats": "^13.4.2",
|
|
158
158
|
"prom-client": "^15.1.0",
|
|
159
|
-
"qs": "^6.
|
|
159
|
+
"qs": "^6.14.2",
|
|
160
160
|
"strict-event-emitter-types": "^2.0.0",
|
|
161
161
|
"systeminformation": "^5.22.9",
|
|
162
162
|
"uint8arraylist": "^2.4.7",
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
"@libp2p/interface-internal": "^3.0.13",
|
|
168
168
|
"@libp2p/logger": "^6.2.2",
|
|
169
169
|
"@libp2p/utils": "^7.0.13",
|
|
170
|
-
"@lodestar/spec-test-util": "^1.45.0-dev.
|
|
170
|
+
"@lodestar/spec-test-util": "^1.45.0-dev.aadf7a7167",
|
|
171
171
|
"@types/js-yaml": "^4.0.5",
|
|
172
172
|
"@types/qs": "^6.9.7",
|
|
173
173
|
"@types/tmp": "^0.2.3",
|
|
@@ -184,5 +184,5 @@
|
|
|
184
184
|
"beacon",
|
|
185
185
|
"blockchain"
|
|
186
186
|
],
|
|
187
|
-
"gitHead": "
|
|
187
|
+
"gitHead": "45040d27fa2b7e11ae93ace5559fac5b51f14f76"
|
|
188
188
|
}
|
|
@@ -7,7 +7,7 @@ import {getBeaconRewardsApi} from "./rewards/index.js";
|
|
|
7
7
|
import {getBeaconStateApi} from "./state/index.js";
|
|
8
8
|
|
|
9
9
|
export function getBeaconApi(
|
|
10
|
-
modules: Pick<ApiModules, "chain" | "config" | "logger" | "metrics" | "network" | "db">
|
|
10
|
+
modules: Pick<ApiModules, "chain" | "config" | "logger" | "metrics" | "network" | "db" | "sync">
|
|
11
11
|
): ApplicationMethods<routes.beacon.Endpoints> {
|
|
12
12
|
const block = getBeaconBlockApi(modules);
|
|
13
13
|
const pool = getBeaconPoolApi(modules);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ApplicationMethods} from "@lodestar/api/server";
|
|
3
3
|
import {
|
|
4
|
-
ForkName,
|
|
5
4
|
ForkPostElectra,
|
|
6
5
|
ForkPreElectra,
|
|
7
6
|
SYNC_COMMITTEE_SUBNET_SIZE,
|
|
@@ -17,15 +16,12 @@ import {
|
|
|
17
16
|
GossipAction,
|
|
18
17
|
PayloadAttestationError,
|
|
19
18
|
PayloadAttestationErrorCode,
|
|
20
|
-
ProposerPreferencesError,
|
|
21
|
-
ProposerPreferencesErrorCode,
|
|
22
19
|
SyncCommitteeError,
|
|
23
20
|
} from "../../../../chain/errors/index.js";
|
|
24
21
|
import {validateApiAttesterSlashing} from "../../../../chain/validation/attesterSlashing.js";
|
|
25
22
|
import {validateApiBlsToExecutionChange} from "../../../../chain/validation/blsToExecutionChange.js";
|
|
26
23
|
import {toElectraSingleAttestation, validateApiAttestation} from "../../../../chain/validation/index.js";
|
|
27
24
|
import {validateApiPayloadAttestationMessage} from "../../../../chain/validation/payloadAttestationMessage.js";
|
|
28
|
-
import {validateGossipProposerPreferences} from "../../../../chain/validation/proposerPreferences.js";
|
|
29
25
|
import {validateApiProposerSlashing} from "../../../../chain/validation/proposerSlashing.js";
|
|
30
26
|
import {validateApiSyncCommittee} from "../../../../chain/validation/syncCommittee.js";
|
|
31
27
|
import {validateApiVoluntaryExit} from "../../../../chain/validation/voluntaryExit.js";
|
|
@@ -66,55 +62,6 @@ export function getBeaconPoolApi({
|
|
|
66
62
|
return {data: chain.payloadAttestationPool.getAll(slot), meta: {version: fork}};
|
|
67
63
|
},
|
|
68
64
|
|
|
69
|
-
async getPoolProposerPreferences({slot}) {
|
|
70
|
-
const fork = chain.config.getForkName(slot ?? chain.clock.currentSlot);
|
|
71
|
-
if (!isForkPostGloas(fork)) {
|
|
72
|
-
throw new ApiError(400, `Proposer preferences pool is not supported before Gloas fork=${fork}`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {data: chain.proposerPreferencesPool.getAll(slot), meta: {version: fork}};
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
async submitSignedProposerPreferences({signedProposerPreferences}) {
|
|
79
|
-
const failures: FailureList = [];
|
|
80
|
-
|
|
81
|
-
await Promise.all(
|
|
82
|
-
signedProposerPreferences.map(async (signed, i) => {
|
|
83
|
-
try {
|
|
84
|
-
await validateGossipProposerPreferences(chain, signed);
|
|
85
|
-
|
|
86
|
-
chain.proposerPreferencesPool.add(signed);
|
|
87
|
-
await network.publishProposerPreferences(signed);
|
|
88
|
-
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
89
|
-
version: ForkName.gloas,
|
|
90
|
-
data: signed,
|
|
91
|
-
});
|
|
92
|
-
} catch (e) {
|
|
93
|
-
const logCtx = {
|
|
94
|
-
slot: signed.message.proposalSlot,
|
|
95
|
-
validatorIndex: signed.message.validatorIndex,
|
|
96
|
-
dependentRoot: toRootHex(signed.message.dependentRoot),
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
if (e instanceof ProposerPreferencesError && e.type.code === ProposerPreferencesErrorCode.ALREADY_KNOWN) {
|
|
100
|
-
logger.debug("Ignoring known signed proposer preferences", logCtx);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
failures.push({index: i, message: (e as Error).message});
|
|
105
|
-
logger.verbose(`Error on submitSignedProposerPreferences [${i}]`, logCtx, e as Error);
|
|
106
|
-
if (e instanceof ProposerPreferencesError && e.action === GossipAction.REJECT) {
|
|
107
|
-
chain.persistInvalidSszValue(ssz.gloas.SignedProposerPreferences, signed, "api_reject");
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
if (failures.length > 0) {
|
|
114
|
-
throw new IndexedError("Error processing signed proposer preferences", failures);
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
|
|
118
65
|
async getPoolAttesterSlashingsV2() {
|
|
119
66
|
const fork = chain.config.getForkName(chain.clock.currentSlot);
|
|
120
67
|
return {data: chain.opPool.getAllAttesterSlashings(), meta: {version: fork}};
|
|
@@ -294,6 +241,11 @@ export function getBeaconPoolApi({
|
|
|
294
241
|
payloadAttestationMessage.data.blobDataAvailable
|
|
295
242
|
);
|
|
296
243
|
|
|
244
|
+
chain.emitter.emit(routes.events.EventType.payloadAttestationMessage, {
|
|
245
|
+
version: chain.config.getForkName(slot),
|
|
246
|
+
data: payloadAttestationMessage,
|
|
247
|
+
});
|
|
248
|
+
|
|
297
249
|
await network.publishPayloadAttestationMessage(payloadAttestationMessage);
|
|
298
250
|
} catch (e) {
|
|
299
251
|
const logCtx = {
|
|
@@ -9,13 +9,15 @@ import {
|
|
|
9
9
|
isStatePostAltair,
|
|
10
10
|
isStatePostElectra,
|
|
11
11
|
isStatePostFulu,
|
|
12
|
+
isStatePostGloas,
|
|
12
13
|
} from "@lodestar/state-transition";
|
|
13
|
-
import {ValidatorIndex, getValidatorStatus, ssz} from "@lodestar/types";
|
|
14
|
+
import {ValidatorIndex, getBuilderStatus, getValidatorStatus, ssz} from "@lodestar/types";
|
|
14
15
|
import {ApiError} from "../../errors.js";
|
|
15
16
|
import {ApiModules} from "../../types.js";
|
|
16
17
|
import {assertUniqueItems} from "../../utils.js";
|
|
17
18
|
import {
|
|
18
19
|
filterStateValidatorsByStatus,
|
|
20
|
+
getStateBuilderIndex,
|
|
19
21
|
getStateResponseWithRegen,
|
|
20
22
|
getStateValidatorIndex,
|
|
21
23
|
toValidatorResponse,
|
|
@@ -24,11 +26,12 @@ import {
|
|
|
24
26
|
export function getBeaconStateApi({
|
|
25
27
|
chain,
|
|
26
28
|
config,
|
|
27
|
-
|
|
29
|
+
sync,
|
|
30
|
+
}: Pick<ApiModules, "chain" | "config" | "sync">): ApplicationMethods<routes.beacon.state.Endpoints> {
|
|
28
31
|
async function getState(
|
|
29
32
|
stateId: routes.beacon.StateId
|
|
30
33
|
): Promise<{state: IBeaconStateView; executionOptimistic: boolean; finalized: boolean}> {
|
|
31
|
-
const {state, executionOptimistic, finalized} = await getStateResponseWithRegen(chain, stateId);
|
|
34
|
+
const {state, executionOptimistic, finalized} = await getStateResponseWithRegen(chain, sync, stateId);
|
|
32
35
|
|
|
33
36
|
return {
|
|
34
37
|
state: state instanceof Uint8Array ? chain.getHeadState().loadOtherState(state) : state,
|
|
@@ -143,6 +146,55 @@ export function getBeaconStateApi({
|
|
|
143
146
|
return this.getStateValidators(args, context);
|
|
144
147
|
},
|
|
145
148
|
|
|
149
|
+
async getStateBuilders({stateId, builderIds = [], statuses = []}) {
|
|
150
|
+
const {state, executionOptimistic, finalized} = await getState(stateId);
|
|
151
|
+
if (!isStatePostGloas(state)) {
|
|
152
|
+
throw new ApiError(400, `Builders are not supported for pre-gloas state fork=${state.forkName}`);
|
|
153
|
+
}
|
|
154
|
+
const finalizedEpoch = state.finalizedCheckpoint.epoch;
|
|
155
|
+
|
|
156
|
+
const builderResponses: routes.beacon.BuilderResponse[] = [];
|
|
157
|
+
if (builderIds.length) {
|
|
158
|
+
assertUniqueItems(builderIds, "Duplicate builder IDs provided");
|
|
159
|
+
|
|
160
|
+
for (const id of builderIds) {
|
|
161
|
+
const resp = getStateBuilderIndex(id, state);
|
|
162
|
+
if (resp.valid) {
|
|
163
|
+
const builderIndex = resp.builderIndex;
|
|
164
|
+
const builder = state.getBuilder(builderIndex);
|
|
165
|
+
const status = getBuilderStatus(builder, finalizedEpoch);
|
|
166
|
+
if (statuses.length && !statuses.includes(status)) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
builderResponses.push({index: builderIndex, status, builder});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
data: builderResponses,
|
|
174
|
+
meta: {executionOptimistic, finalized},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (statuses.length) {
|
|
179
|
+
assertUniqueItems(statuses, "Duplicate statuses provided");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const buildersLength = state.getBuildersLength();
|
|
183
|
+
for (let builderIndex = 0; builderIndex < buildersLength; builderIndex++) {
|
|
184
|
+
const builder = state.getBuilder(builderIndex);
|
|
185
|
+
const status = getBuilderStatus(builder, finalizedEpoch);
|
|
186
|
+
if (statuses.length && !statuses.includes(status)) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
builderResponses.push({index: builderIndex, status, builder});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
data: builderResponses,
|
|
194
|
+
meta: {executionOptimistic, finalized},
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
|
|
146
198
|
async postStateValidatorIdentities({stateId, validatorIds = []}) {
|
|
147
199
|
const {state, executionOptimistic, finalized} = await getState(stateId);
|
|
148
200
|
const {pubkeyCache} = chain;
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {CheckpointWithHex, IForkChoice} from "@lodestar/fork-choice";
|
|
3
3
|
import {GENESIS_SLOT} from "@lodestar/params";
|
|
4
|
-
import {IBeaconStateView, PubkeyCache} from "@lodestar/state-transition";
|
|
5
|
-
import {
|
|
6
|
-
|
|
4
|
+
import {IBeaconStateView, IBeaconStateViewGloas, PubkeyCache} from "@lodestar/state-transition";
|
|
5
|
+
import {
|
|
6
|
+
BLSPubkey,
|
|
7
|
+
BuilderIndex,
|
|
8
|
+
Epoch,
|
|
9
|
+
RootHex,
|
|
10
|
+
Slot,
|
|
11
|
+
ValidatorIndex,
|
|
12
|
+
getValidatorStatus,
|
|
13
|
+
phase0,
|
|
14
|
+
} from "@lodestar/types";
|
|
15
|
+
import {byteArrayEquals, fromHex} from "@lodestar/utils";
|
|
7
16
|
import {IBeaconChain} from "../../../../chain/index.js";
|
|
17
|
+
import {IBeaconSync} from "../../../../sync/index.js";
|
|
8
18
|
import {ApiError, ValidationError} from "../../errors.js";
|
|
19
|
+
import {notWhileSyncing} from "../../utils.js";
|
|
9
20
|
|
|
10
21
|
export function resolveStateId(
|
|
11
22
|
forkChoice: IForkChoice,
|
|
@@ -42,8 +53,17 @@ export function resolveStateId(
|
|
|
42
53
|
|
|
43
54
|
export async function getStateResponseWithRegen(
|
|
44
55
|
chain: IBeaconChain,
|
|
56
|
+
sync: IBeaconSync,
|
|
45
57
|
inStateId: routes.beacon.StateId
|
|
46
58
|
): Promise<{state: IBeaconStateView | Uint8Array; executionOptimistic: boolean; finalized: boolean}> {
|
|
59
|
+
// "head", "finalized" and "justified" resolve to already-available cached states, and "genesis" to a
|
|
60
|
+
// historical DB read - none trigger the forward regen that can walk back past the block-root window
|
|
61
|
+
// (SLOTS_PER_HISTORICAL_ROOT) and wedge a far-behind node. Keep serving those (node observability,
|
|
62
|
+
// dashboards, validator client checks) even while syncing; guard only the regen-capable lookups.
|
|
63
|
+
if (inStateId !== "head" && inStateId !== "finalized" && inStateId !== "justified" && inStateId !== "genesis") {
|
|
64
|
+
notWhileSyncing(chain, sync.state);
|
|
65
|
+
}
|
|
66
|
+
|
|
47
67
|
const stateId = resolveStateId(chain.forkChoice, inStateId);
|
|
48
68
|
|
|
49
69
|
const res =
|
|
@@ -78,6 +98,50 @@ export function toValidatorResponse(
|
|
|
78
98
|
};
|
|
79
99
|
}
|
|
80
100
|
|
|
101
|
+
type StateBuilderIndexResponse =
|
|
102
|
+
| {valid: true; builderIndex: BuilderIndex}
|
|
103
|
+
| {valid: false; code: number; reason: string};
|
|
104
|
+
|
|
105
|
+
export function getStateBuilderIndex(
|
|
106
|
+
id: routes.beacon.BuilderId | BLSPubkey,
|
|
107
|
+
state: IBeaconStateViewGloas
|
|
108
|
+
): StateBuilderIndexResponse {
|
|
109
|
+
if (typeof id === "string") {
|
|
110
|
+
// mutate `id` and fallthrough to below
|
|
111
|
+
if (id.startsWith("0x")) {
|
|
112
|
+
try {
|
|
113
|
+
id = fromHex(id);
|
|
114
|
+
} catch (_e) {
|
|
115
|
+
return {valid: false, code: 400, reason: "Invalid pubkey hex encoding"};
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
id = Number(id);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (typeof id === "number") {
|
|
123
|
+
const builderIndex = id;
|
|
124
|
+
// builder is invalid or added later than given stateId
|
|
125
|
+
if (!Number.isSafeInteger(builderIndex) || builderIndex < 0) {
|
|
126
|
+
return {valid: false, code: 400, reason: "Invalid builder index"};
|
|
127
|
+
}
|
|
128
|
+
if (builderIndex >= state.getBuildersLength()) {
|
|
129
|
+
return {valid: false, code: 404, reason: "Builder index from future state"};
|
|
130
|
+
}
|
|
131
|
+
return {valid: true, builderIndex};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// typeof id === Uint8Array
|
|
135
|
+
// There is no builder pubkey cache, linear scan over the registry
|
|
136
|
+
const buildersLength = state.getBuildersLength();
|
|
137
|
+
for (let builderIndex = 0; builderIndex < buildersLength; builderIndex++) {
|
|
138
|
+
if (byteArrayEquals(state.getBuilder(builderIndex).pubkey, id)) {
|
|
139
|
+
return {valid: true, builderIndex};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return {valid: false, code: 404, reason: "Builder pubkey not found in state"};
|
|
143
|
+
}
|
|
144
|
+
|
|
81
145
|
export function filterStateValidatorsByStatus(
|
|
82
146
|
statuses: string[],
|
|
83
147
|
state: IBeaconStateView,
|
|
@@ -122,7 +186,7 @@ export function getStateValidatorIndex(
|
|
|
122
186
|
if (typeof id === "number") {
|
|
123
187
|
const validatorIndex = id;
|
|
124
188
|
// validator is invalid or added later than given stateId
|
|
125
|
-
if (!Number.isSafeInteger(validatorIndex)) {
|
|
189
|
+
if (!Number.isSafeInteger(validatorIndex) || validatorIndex < 0) {
|
|
126
190
|
return {valid: false, code: 400, reason: "Invalid validator index"};
|
|
127
191
|
}
|
|
128
192
|
if (validatorIndex >= state.validatorCount) {
|
|
@@ -39,7 +39,8 @@ function toPayloadStatusName(status: PayloadStatus): "pending" | "empty" | "full
|
|
|
39
39
|
export function getDebugApi({
|
|
40
40
|
chain,
|
|
41
41
|
config,
|
|
42
|
-
|
|
42
|
+
sync,
|
|
43
|
+
}: Pick<ApiModules, "chain" | "config" | "db" | "sync">): ApplicationMethods<routes.debug.Endpoints> {
|
|
43
44
|
return {
|
|
44
45
|
async getDebugChainHeadsV2() {
|
|
45
46
|
const heads = chain.forkChoice.getHeads();
|
|
@@ -132,7 +133,7 @@ export function getDebugApi({
|
|
|
132
133
|
},
|
|
133
134
|
|
|
134
135
|
async getStateV2({stateId}, context) {
|
|
135
|
-
const {state, executionOptimistic, finalized} = await getStateResponseWithRegen(chain, stateId);
|
|
136
|
+
const {state, executionOptimistic, finalized} = await getStateResponseWithRegen(chain, sync, stateId);
|
|
136
137
|
let slot: number, data: Uint8Array | BeaconState;
|
|
137
138
|
if (state instanceof Uint8Array) {
|
|
138
139
|
slot = getStateSlotFromBytes(state);
|
|
@@ -217,7 +217,7 @@ export function getLodestarApi({
|
|
|
217
217
|
},
|
|
218
218
|
|
|
219
219
|
async getHistoricalSummaries({stateId}) {
|
|
220
|
-
const {state, executionOptimistic, finalized} = await getStateResponseWithRegen(chain, stateId);
|
|
220
|
+
const {state, executionOptimistic, finalized} = await getStateResponseWithRegen(chain, sync, stateId);
|
|
221
221
|
|
|
222
222
|
const stateView = state instanceof Uint8Array ? chain.getHeadState().loadOtherState(state) : state;
|
|
223
223
|
|
|
@@ -332,7 +332,7 @@ export function getLodestarApi({
|
|
|
332
332
|
|
|
333
333
|
for (const [epoch, attestationsPerEpoch] of attestations) {
|
|
334
334
|
const slot = computeStartSlotAtEpoch(epoch);
|
|
335
|
-
const {state} = await getStateResponseWithRegen(chain, slot);
|
|
335
|
+
const {state} = await getStateResponseWithRegen(chain, sync, slot);
|
|
336
336
|
const stateView = state instanceof Uint8Array ? chain.getHeadState().loadOtherState(state) : state;
|
|
337
337
|
const shuffling = stateView.getShufflingAtEpoch(epoch);
|
|
338
338
|
for (const attestation of attestationsPerEpoch) {
|
|
@@ -8,7 +8,7 @@ import {ApiModules} from "../types.js";
|
|
|
8
8
|
|
|
9
9
|
export function getProofApi(
|
|
10
10
|
opts: ApiOptions,
|
|
11
|
-
{chain, config}: Pick<ApiModules, "chain" | "config" | "db">
|
|
11
|
+
{chain, config, sync}: Pick<ApiModules, "chain" | "config" | "db" | "sync">
|
|
12
12
|
): ApplicationMethods<routes.proof.Endpoints> {
|
|
13
13
|
// It's currently possible to request gigantic proofs (eg: a proof of the entire beacon state)
|
|
14
14
|
// We want some some sort of resistance against this DoS vector.
|
|
@@ -21,7 +21,7 @@ export function getProofApi(
|
|
|
21
21
|
throw new Error("Requested proof is too large.");
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const res = await getStateResponseWithRegen(chain, stateId);
|
|
24
|
+
const res = await getStateResponseWithRegen(chain, sync, stateId);
|
|
25
25
|
|
|
26
26
|
const state = res.state instanceof Uint8Array ? chain.getHeadState().loadOtherState(res.state) : res.state;
|
|
27
27
|
|
package/src/api/impl/utils.ts
CHANGED
|
@@ -1,4 +1,54 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import type {IBeaconChain} from "../../chain/index.js";
|
|
3
|
+
import {SyncState} from "../../sync/index.js";
|
|
4
|
+
import {ApiError, NodeIsSyncing} from "./errors.js";
|
|
5
|
+
|
|
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 const SYNC_TOLERANCE_EPOCHS = 1;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Reject any request while the node is syncing. Used by endpoints that must not serve while the
|
|
23
|
+
* node is behind — validator duties, and beacon state lookups whose regen could otherwise walk
|
|
24
|
+
* back past the block-root window (`SLOTS_PER_HISTORICAL_ROOT`) and wedge the node. Throws
|
|
25
|
+
* {@link NodeIsSyncing} (503).
|
|
26
|
+
*/
|
|
27
|
+
export function notWhileSyncing(chain: IBeaconChain, syncState: SyncState): void {
|
|
28
|
+
// Consider node synced before or close to genesis
|
|
29
|
+
if (chain.clock.currentSlot < SLOTS_PER_EPOCH) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
switch (syncState) {
|
|
34
|
+
case SyncState.SyncingFinalized:
|
|
35
|
+
case SyncState.SyncingHead: {
|
|
36
|
+
const currentSlot = chain.clock.currentSlot;
|
|
37
|
+
const headSlot = chain.forkChoice.getHead().slot;
|
|
38
|
+
if (currentSlot - headSlot > SYNC_TOLERANCE_EPOCHS * SLOTS_PER_EPOCH) {
|
|
39
|
+
throw new NodeIsSyncing(`headSlot ${headSlot} currentSlot ${currentSlot}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
case SyncState.Synced:
|
|
46
|
+
return;
|
|
47
|
+
|
|
48
|
+
case SyncState.Stalled:
|
|
49
|
+
throw new NodeIsSyncing("waiting for peers");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
2
52
|
|
|
3
53
|
/**
|
|
4
54
|
* Ensures that the array contains unique values, and throws an ApiError
|