@lodestar/beacon-node 1.45.0-dev.b94232ff23 → 1.45.0-dev.bd1bed5b8f
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/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.map +1 -1
- package/lib/api/impl/beacon/state/index.js +46 -3
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +11 -2
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +39 -3
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +46 -6
- package/lib/api/impl/validator/index.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/payloadEnvelopeProcessor.d.ts +5 -2
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +17 -17
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/chain.d.ts +1 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +1 -3
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/interface.d.ts +1 -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 +1 -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/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/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/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 +6 -1
- 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/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 +18 -18
- package/src/api/impl/beacon/pool/index.ts +5 -53
- package/src/api/impl/beacon/state/index.ts +52 -1
- package/src/api/impl/beacon/state/utils.ts +57 -4
- package/src/api/impl/validator/index.ts +54 -5
- package/src/chain/blocks/importBlock.ts +2 -7
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +17 -17
- package/src/chain/chain.ts +0 -3
- package/src/chain/interface.ts +0 -2
- package/src/chain/opPools/proposerPreferencesPool.ts +5 -1
- package/src/chain/options.ts +2 -0
- 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/executionPayloadBid.ts +14 -9
- package/src/chain/validation/proposerPreferences.ts +15 -5
- 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/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.d.ts
CHANGED
|
@@ -11,4 +11,19 @@ export declare function fromGraffitiBytes(graffiti: Bytes32): string;
|
|
|
11
11
|
export declare function getDefaultGraffiti(consensusClientVersion: ClientVersion, executionClientVersion: ClientVersion | null | undefined, opts: {
|
|
12
12
|
private?: boolean;
|
|
13
13
|
}): string;
|
|
14
|
+
/**
|
|
15
|
+
* Appends the richest available client watermark that fits after user graffiti.
|
|
16
|
+
*
|
|
17
|
+
* Tiers are:
|
|
18
|
+
* - full EL/CL watermark, e.g. " BU9b0eLS80c2"
|
|
19
|
+
* - EL/CL client codes, e.g. " BULS"
|
|
20
|
+
* - CL client code, e.g. " LS"
|
|
21
|
+
*/
|
|
22
|
+
export declare function appendClientInfoToGraffiti(userGraffiti: string, consensusClientVersion: ClientVersion, executionClientVersion: ClientVersion | null | undefined, opts?: {
|
|
23
|
+
private?: boolean;
|
|
24
|
+
}): string;
|
|
25
|
+
export declare function getBlockGraffiti(userGraffiti: string | undefined, consensusClientVersion: ClientVersion, executionClientVersion: ClientVersion | null | undefined, opts: {
|
|
26
|
+
private?: boolean;
|
|
27
|
+
graffitiAppend?: boolean;
|
|
28
|
+
}): string;
|
|
14
29
|
//# sourceMappingURL=graffiti.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graffiti.d.ts","sourceRoot":"","sources":["../../src/util/graffiti.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAExC,OAAO,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAC;AAEpD;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAI3D;AAED,wBAAgB,kBAAkB,CAChC,sBAAsB,EAAE,aAAa,EACrC,sBAAsB,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EACxD,IAAI,EAAE;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAC,GACxB,MAAM,CAcR"}
|
|
1
|
+
{"version":3,"file":"graffiti.d.ts","sourceRoot":"","sources":["../../src/util/graffiti.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAExC,OAAO,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAC;AAEpD;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAI3D;AAED,wBAAgB,kBAAkB,CAChC,sBAAsB,EAAE,aAAa,EACrC,sBAAsB,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EACxD,IAAI,EAAE;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAC,GACxB,MAAM,CAcR;AAmBD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EACpB,sBAAsB,EAAE,aAAa,EACrC,sBAAsB,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EACxD,IAAI,GAAE;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAM,GAC7B,MAAM,CA6BR;AAED,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,sBAAsB,EAAE,aAAa,EACrC,sBAAsB,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EACxD,IAAI,EAAE;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAC,GAClD,MAAM,CAUR"}
|
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.bd1bed5b8f",
|
|
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.bd1bed5b8f",
|
|
138
|
+
"@lodestar/config": "^1.45.0-dev.bd1bed5b8f",
|
|
139
|
+
"@lodestar/db": "^1.45.0-dev.bd1bed5b8f",
|
|
140
|
+
"@lodestar/fork-choice": "^1.45.0-dev.bd1bed5b8f",
|
|
141
|
+
"@lodestar/logger": "^1.45.0-dev.bd1bed5b8f",
|
|
142
|
+
"@lodestar/params": "^1.45.0-dev.bd1bed5b8f",
|
|
143
|
+
"@lodestar/reqresp": "^1.45.0-dev.bd1bed5b8f",
|
|
144
|
+
"@lodestar/state-transition": "^1.45.0-dev.bd1bed5b8f",
|
|
145
|
+
"@lodestar/types": "^1.45.0-dev.bd1bed5b8f",
|
|
146
|
+
"@lodestar/utils": "^1.45.0-dev.bd1bed5b8f",
|
|
147
|
+
"@lodestar/validator": "^1.45.0-dev.bd1bed5b8f",
|
|
148
148
|
"@multiformats/multiaddr": "^13.0.1",
|
|
149
149
|
"datastore-core": "^11.0.2",
|
|
150
150
|
"datastore-fs": "^11.0.2",
|
|
@@ -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.bd1bed5b8f",
|
|
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": "226eaf0154e3f70cb00c066f6eabd92c06e58634"
|
|
188
188
|
}
|
|
@@ -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,
|
|
@@ -143,6 +145,55 @@ export function getBeaconStateApi({
|
|
|
143
145
|
return this.getStateValidators(args, context);
|
|
144
146
|
},
|
|
145
147
|
|
|
148
|
+
async getStateBuilders({stateId, builderIds = [], statuses = []}) {
|
|
149
|
+
const {state, executionOptimistic, finalized} = await getState(stateId);
|
|
150
|
+
if (!isStatePostGloas(state)) {
|
|
151
|
+
throw new ApiError(400, `Builders are not supported for pre-gloas state fork=${state.forkName}`);
|
|
152
|
+
}
|
|
153
|
+
const finalizedEpoch = state.finalizedCheckpoint.epoch;
|
|
154
|
+
|
|
155
|
+
const builderResponses: routes.beacon.BuilderResponse[] = [];
|
|
156
|
+
if (builderIds.length) {
|
|
157
|
+
assertUniqueItems(builderIds, "Duplicate builder IDs provided");
|
|
158
|
+
|
|
159
|
+
for (const id of builderIds) {
|
|
160
|
+
const resp = getStateBuilderIndex(id, state);
|
|
161
|
+
if (resp.valid) {
|
|
162
|
+
const builderIndex = resp.builderIndex;
|
|
163
|
+
const builder = state.getBuilder(builderIndex);
|
|
164
|
+
const status = getBuilderStatus(builder, finalizedEpoch);
|
|
165
|
+
if (statuses.length && !statuses.includes(status)) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
builderResponses.push({index: builderIndex, status, builder});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
data: builderResponses,
|
|
173
|
+
meta: {executionOptimistic, finalized},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (statuses.length) {
|
|
178
|
+
assertUniqueItems(statuses, "Duplicate statuses provided");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const buildersLength = state.getBuildersLength();
|
|
182
|
+
for (let builderIndex = 0; builderIndex < buildersLength; builderIndex++) {
|
|
183
|
+
const builder = state.getBuilder(builderIndex);
|
|
184
|
+
const status = getBuilderStatus(builder, finalizedEpoch);
|
|
185
|
+
if (statuses.length && !statuses.includes(status)) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
builderResponses.push({index: builderIndex, status, builder});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
data: builderResponses,
|
|
193
|
+
meta: {executionOptimistic, finalized},
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
|
|
146
197
|
async postStateValidatorIdentities({stateId, validatorIds = []}) {
|
|
147
198
|
const {state, executionOptimistic, finalized} = await getState(stateId);
|
|
148
199
|
const {pubkeyCache} = chain;
|
|
@@ -1,9 +1,18 @@
|
|
|
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";
|
|
8
17
|
import {ApiError, ValidationError} from "../../errors.js";
|
|
9
18
|
|
|
@@ -78,6 +87,50 @@ export function toValidatorResponse(
|
|
|
78
87
|
};
|
|
79
88
|
}
|
|
80
89
|
|
|
90
|
+
type StateBuilderIndexResponse =
|
|
91
|
+
| {valid: true; builderIndex: BuilderIndex}
|
|
92
|
+
| {valid: false; code: number; reason: string};
|
|
93
|
+
|
|
94
|
+
export function getStateBuilderIndex(
|
|
95
|
+
id: routes.beacon.BuilderId | BLSPubkey,
|
|
96
|
+
state: IBeaconStateViewGloas
|
|
97
|
+
): StateBuilderIndexResponse {
|
|
98
|
+
if (typeof id === "string") {
|
|
99
|
+
// mutate `id` and fallthrough to below
|
|
100
|
+
if (id.startsWith("0x")) {
|
|
101
|
+
try {
|
|
102
|
+
id = fromHex(id);
|
|
103
|
+
} catch (_e) {
|
|
104
|
+
return {valid: false, code: 400, reason: "Invalid pubkey hex encoding"};
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
id = Number(id);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (typeof id === "number") {
|
|
112
|
+
const builderIndex = id;
|
|
113
|
+
// builder is invalid or added later than given stateId
|
|
114
|
+
if (!Number.isSafeInteger(builderIndex) || builderIndex < 0) {
|
|
115
|
+
return {valid: false, code: 400, reason: "Invalid builder index"};
|
|
116
|
+
}
|
|
117
|
+
if (builderIndex >= state.getBuildersLength()) {
|
|
118
|
+
return {valid: false, code: 404, reason: "Builder index from future state"};
|
|
119
|
+
}
|
|
120
|
+
return {valid: true, builderIndex};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// typeof id === Uint8Array
|
|
124
|
+
// There is no builder pubkey cache, linear scan over the registry
|
|
125
|
+
const buildersLength = state.getBuildersLength();
|
|
126
|
+
for (let builderIndex = 0; builderIndex < buildersLength; builderIndex++) {
|
|
127
|
+
if (byteArrayEquals(state.getBuilder(builderIndex).pubkey, id)) {
|
|
128
|
+
return {valid: true, builderIndex};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return {valid: false, code: 404, reason: "Builder pubkey not found in state"};
|
|
132
|
+
}
|
|
133
|
+
|
|
81
134
|
export function filterStateValidatorsByStatus(
|
|
82
135
|
statuses: string[],
|
|
83
136
|
state: IBeaconStateView,
|
|
@@ -122,7 +175,7 @@ export function getStateValidatorIndex(
|
|
|
122
175
|
if (typeof id === "number") {
|
|
123
176
|
const validatorIndex = id;
|
|
124
177
|
// validator is invalid or added later than given stateId
|
|
125
|
-
if (!Number.isSafeInteger(validatorIndex)) {
|
|
178
|
+
if (!Number.isSafeInteger(validatorIndex) || validatorIndex < 0) {
|
|
126
179
|
return {valid: false, code: 400, reason: "Invalid validator index"};
|
|
127
180
|
}
|
|
128
181
|
if (validatorIndex >= state.validatorCount) {
|
|
@@ -65,6 +65,8 @@ import {
|
|
|
65
65
|
AttestationError,
|
|
66
66
|
AttestationErrorCode,
|
|
67
67
|
GossipAction,
|
|
68
|
+
ProposerPreferencesError,
|
|
69
|
+
ProposerPreferencesErrorCode,
|
|
68
70
|
SyncCommitteeError,
|
|
69
71
|
SyncCommitteeErrorCode,
|
|
70
72
|
} from "../../../chain/errors/index.js";
|
|
@@ -74,6 +76,7 @@ import {BlockType, ProduceFullDeneb, ProduceFullGloas} from "../../../chain/prod
|
|
|
74
76
|
import {RegenCaller} from "../../../chain/regen/index.js";
|
|
75
77
|
import {CheckpointHex} from "../../../chain/stateCache/types.js";
|
|
76
78
|
import {validateApiAggregateAndProof} from "../../../chain/validation/index.js";
|
|
79
|
+
import {validateGossipProposerPreferences} from "../../../chain/validation/proposerPreferences.js";
|
|
77
80
|
import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/validation/syncCommitteeContributionAndProof.js";
|
|
78
81
|
import {ZERO_HASH} from "../../../constants/index.js";
|
|
79
82
|
import {BuilderStatus, NoBidReceived} from "../../../execution/builder/http.js";
|
|
@@ -82,7 +85,7 @@ import {CommitteeSubscription} from "../../../network/subnets/index.js";
|
|
|
82
85
|
import {SyncState} from "../../../sync/index.js";
|
|
83
86
|
import {callInNextEventLoop} from "../../../util/eventLoop.js";
|
|
84
87
|
import {isOptimisticBlock} from "../../../util/forkChoice.js";
|
|
85
|
-
import {
|
|
88
|
+
import {getBlockGraffiti, toGraffitiBytes} from "../../../util/graffiti.js";
|
|
86
89
|
import {getLodestarClientVersion} from "../../../util/metadata.js";
|
|
87
90
|
import {ApiOptions} from "../../options.js";
|
|
88
91
|
import {getStateResponseWithRegen} from "../beacon/state/utils.js";
|
|
@@ -611,7 +614,10 @@ export function getValidatorApi(
|
|
|
611
614
|
}
|
|
612
615
|
|
|
613
616
|
const graffitiBytes = toGraffitiBytes(
|
|
614
|
-
graffiti
|
|
617
|
+
getBlockGraffiti(graffiti, getLodestarClientVersion(opts), chain.executionEngine.clientVersion, {
|
|
618
|
+
private: opts.private,
|
|
619
|
+
graffitiAppend: chain.opts.graffitiAppend,
|
|
620
|
+
})
|
|
615
621
|
);
|
|
616
622
|
|
|
617
623
|
const loggerContext = {
|
|
@@ -921,7 +927,10 @@ export function getValidatorApi(
|
|
|
921
927
|
metrics?.blockProductionSlotDelta.set(slot - parentSlot);
|
|
922
928
|
|
|
923
929
|
const graffitiBytes = toGraffitiBytes(
|
|
924
|
-
graffiti
|
|
930
|
+
getBlockGraffiti(graffiti, getLodestarClientVersion(opts), chain.executionEngine.clientVersion, {
|
|
931
|
+
private: opts.private,
|
|
932
|
+
graffitiAppend: chain.opts.graffitiAppend,
|
|
933
|
+
})
|
|
925
934
|
);
|
|
926
935
|
|
|
927
936
|
// TODO GLOAS: respect builderSelection (MaxProfit, BuilderAlways, ExecutionAlways, etc.) to let
|
|
@@ -1112,8 +1121,8 @@ export function getValidatorApi(
|
|
|
1112
1121
|
|
|
1113
1122
|
const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
|
|
1114
1123
|
if (!block) {
|
|
1115
|
-
// No block is seen at slot. Return
|
|
1116
|
-
|
|
1124
|
+
// No canonical block is seen at slot. Return 204 so vc can skip casting payload attestation.
|
|
1125
|
+
return {data: undefined, meta: {version: fork}, status: 204};
|
|
1117
1126
|
}
|
|
1118
1127
|
|
|
1119
1128
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
|
|
@@ -1765,6 +1774,46 @@ export function getValidatorApi(
|
|
|
1765
1774
|
});
|
|
1766
1775
|
},
|
|
1767
1776
|
|
|
1777
|
+
async submitProposerPreferences({signedProposerPreferences}) {
|
|
1778
|
+
const failures: FailureList = [];
|
|
1779
|
+
|
|
1780
|
+
await Promise.all(
|
|
1781
|
+
signedProposerPreferences.map(async (signed, i) => {
|
|
1782
|
+
try {
|
|
1783
|
+
await validateGossipProposerPreferences(chain, signed);
|
|
1784
|
+
|
|
1785
|
+
chain.proposerPreferencesPool.add(signed);
|
|
1786
|
+
await network.publishProposerPreferences(signed);
|
|
1787
|
+
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
1788
|
+
version: config.getForkName(signed.message.proposalSlot),
|
|
1789
|
+
data: signed,
|
|
1790
|
+
});
|
|
1791
|
+
} catch (e) {
|
|
1792
|
+
const logCtx = {
|
|
1793
|
+
slot: signed.message.proposalSlot,
|
|
1794
|
+
validatorIndex: signed.message.validatorIndex,
|
|
1795
|
+
dependentRoot: toRootHex(signed.message.dependentRoot),
|
|
1796
|
+
};
|
|
1797
|
+
|
|
1798
|
+
if (e instanceof ProposerPreferencesError && e.type.code === ProposerPreferencesErrorCode.ALREADY_KNOWN) {
|
|
1799
|
+
logger.debug("Ignoring known signed proposer preferences", logCtx);
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
failures.push({index: i, message: (e as Error).message});
|
|
1804
|
+
logger.verbose(`Error on submitProposerPreferences [${i}]`, logCtx, e as Error);
|
|
1805
|
+
if (e instanceof ProposerPreferencesError && e.action === GossipAction.REJECT) {
|
|
1806
|
+
chain.persistInvalidSszValue(ssz.gloas.SignedProposerPreferences, signed, "api_reject");
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
})
|
|
1810
|
+
);
|
|
1811
|
+
|
|
1812
|
+
if (failures.length > 0) {
|
|
1813
|
+
throw new IndexedError("Error processing signed proposer preferences", failures);
|
|
1814
|
+
}
|
|
1815
|
+
},
|
|
1816
|
+
|
|
1768
1817
|
async getExecutionPayloadEnvelope({slot, beaconBlockRoot}) {
|
|
1769
1818
|
const fork = config.getForkName(slot);
|
|
1770
1819
|
|
|
@@ -124,18 +124,13 @@ export async function importBlock(
|
|
|
124
124
|
executionStatus = parentBlock.executionStatus;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
// getBeaconProposerOrNull will return null if head state is more than one epoch away
|
|
128
|
-
// from block slot. We skip proposer boost canonical check as we cannot determine the canonical proposer
|
|
129
|
-
const expectedProposerIndex: number | null = this.getHeadState().getBeaconProposerOrNull(blockSlot);
|
|
130
|
-
|
|
131
127
|
const blockSummary = this.forkChoice.onBlock(
|
|
132
128
|
block.message,
|
|
133
129
|
postState,
|
|
134
130
|
blockDelaySec,
|
|
135
131
|
currentSlot,
|
|
136
132
|
executionStatus,
|
|
137
|
-
dataAvailabilityStatus
|
|
138
|
-
expectedProposerIndex
|
|
133
|
+
dataAvailabilityStatus
|
|
139
134
|
);
|
|
140
135
|
|
|
141
136
|
// This adds the state necessary to process the next block
|
|
@@ -426,7 +421,7 @@ export async function importBlock(
|
|
|
426
421
|
}
|
|
427
422
|
} catch (e) {
|
|
428
423
|
if (isStartSlotOfEpoch(proposalSlot)) {
|
|
429
|
-
notOverrideFcuReason = NotReorgedReason.
|
|
424
|
+
notOverrideFcuReason = NotReorgedReason.AtEpochBoundary;
|
|
430
425
|
} else {
|
|
431
426
|
this.logger.warn("Unable to get beacon proposer. Do not override fcu.", {proposalSlot}, e as Error);
|
|
432
427
|
}
|
|
@@ -8,28 +8,24 @@ import {ImportPayloadOpts} from "./types.js";
|
|
|
8
8
|
// TODO GLOAS: Set to be equal to DEFAULT_MAX_PENDING_UNFINALIZED_PAYLOAD_ENVELOPE_WRITES for now
|
|
9
9
|
const QUEUE_MAX_LENGTH = 16;
|
|
10
10
|
|
|
11
|
-
enum PayloadEnvelopeImportStatus {
|
|
12
|
-
queued = "queued",
|
|
13
|
-
importing = "importing",
|
|
14
|
-
imported = "imported",
|
|
15
|
-
}
|
|
16
|
-
|
|
17
11
|
/**
|
|
18
12
|
* PayloadEnvelopeProcessor processes payload envelope jobs in a queued fashion, one after the other.
|
|
19
13
|
*
|
|
20
14
|
* Jobs are enqueued only on envelope arrival (gossip or API). The envelope may reach us before
|
|
21
15
|
* the sampled data columns; importExecutionPayload awaits `verifyPayloadsDataAvailability`
|
|
22
16
|
* internally, so a queued job can pend for up to `PAYLOAD_DATA_AVAILABILITY_TIMEOUT` while
|
|
23
|
-
* waiting for columns. Duplicate triggers for the same payloadInput are deduped
|
|
17
|
+
* waiting for columns. Duplicate triggers for the same payloadInput are deduped by sharing the
|
|
18
|
+
* in-flight import promise: every caller observes the real import outcome. Resolving duplicates
|
|
19
|
+
* early instead would let BlockInputSync mark a still-pending payload as processed, re-queue it,
|
|
20
|
+
* and spin re-processing the same root until OOM while the import is blocked (e.g. EL syncing).
|
|
24
21
|
*/
|
|
25
22
|
export class PayloadEnvelopeProcessor {
|
|
26
23
|
readonly jobQueue: JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>;
|
|
27
|
-
private readonly
|
|
24
|
+
private readonly imports = new WeakMap<PayloadEnvelopeInput, Promise<void>>();
|
|
28
25
|
|
|
29
26
|
constructor(chain: BeaconChain, metrics: Metrics | null, signal: AbortSignal) {
|
|
30
27
|
this.jobQueue = new JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>(
|
|
31
28
|
(payloadInput, opts) => {
|
|
32
|
-
this.importStatus.set(payloadInput, PayloadEnvelopeImportStatus.importing);
|
|
33
29
|
return processExecutionPayload.call(chain, payloadInput, signal, opts);
|
|
34
30
|
},
|
|
35
31
|
{maxLength: QUEUE_MAX_LENGTH, noYieldIfOneItem: true, signal},
|
|
@@ -38,24 +34,28 @@ export class PayloadEnvelopeProcessor {
|
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
async processPayloadEnvelopeJob(payloadInput: PayloadEnvelopeInput, opts: ImportPayloadOpts = {}): Promise<void> {
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
const existing = this.imports.get(payloadInput);
|
|
38
|
+
if (existing) {
|
|
39
|
+
return existing;
|
|
43
40
|
}
|
|
44
41
|
|
|
45
42
|
await this.jobQueue.waitForSpace();
|
|
46
43
|
|
|
47
44
|
// Re-check after await, as another call may have queued this payload.
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
const queued = this.imports.get(payloadInput);
|
|
46
|
+
if (queued) {
|
|
47
|
+
return queued;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
this.
|
|
50
|
+
const importPromise = this.jobQueue.push(payloadInput, opts);
|
|
51
|
+
this.imports.set(payloadInput, importPromise);
|
|
53
52
|
|
|
54
53
|
try {
|
|
55
|
-
await
|
|
56
|
-
this.importStatus.set(payloadInput, PayloadEnvelopeImportStatus.imported);
|
|
54
|
+
await importPromise;
|
|
57
55
|
} catch (e) {
|
|
58
|
-
|
|
56
|
+
// Drop the failed import so a later attempt can retry once the failure cause is resolved
|
|
57
|
+
// (e.g. BLOCK_NOT_IN_FORK_CHOICE after the block lands in fork choice)
|
|
58
|
+
this.imports.delete(payloadInput);
|
|
59
59
|
throw e;
|
|
60
60
|
}
|
|
61
61
|
}
|
package/src/chain/chain.ts
CHANGED
|
@@ -107,7 +107,6 @@ import {
|
|
|
107
107
|
SeenExecutionPayloadBids,
|
|
108
108
|
SeenPayloadAttesters,
|
|
109
109
|
SeenPayloadEnvelopeInput,
|
|
110
|
-
SeenProposerPreferences,
|
|
111
110
|
SeenSyncCommitteeMessages,
|
|
112
111
|
} from "./seenCache/index.js";
|
|
113
112
|
import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
|
|
@@ -189,7 +188,6 @@ export class BeaconChain implements IBeaconChain {
|
|
|
189
188
|
readonly seenPayloadAttesters = new SeenPayloadAttesters();
|
|
190
189
|
readonly seenAggregatedAttestations: SeenAggregatedAttestations;
|
|
191
190
|
readonly seenExecutionPayloadBids = new SeenExecutionPayloadBids();
|
|
192
|
-
readonly seenProposerPreferences = new SeenProposerPreferences();
|
|
193
191
|
readonly seenBlockProposers = new SeenBlockProposers();
|
|
194
192
|
readonly seenSyncCommitteeMessages = new SeenSyncCommitteeMessages();
|
|
195
193
|
readonly seenContributionAndProof: SeenContributionAndProof;
|
|
@@ -1473,7 +1471,6 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1473
1471
|
this.payloadAttestationPool.prune(slot);
|
|
1474
1472
|
this.executionPayloadBidPool.prune(slot);
|
|
1475
1473
|
this.seenExecutionPayloadBids.prune(slot);
|
|
1476
|
-
this.seenProposerPreferences.prune(slot);
|
|
1477
1474
|
this.proposerPreferencesPool.prune(slot);
|
|
1478
1475
|
this.seenAttestationDatas.onSlot(slot);
|
|
1479
1476
|
this.reprocessController.onSlot(slot);
|