@lodestar/beacon-node 1.40.0-dev.db4220e83d → 1.40.0-dev.f58ab9b042
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/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +14 -0
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/rest/base.d.ts.map +1 -1
- package/lib/api/rest/base.js +12 -10
- package/lib/api/rest/base.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js +2 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js +2 -2
- package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +1 -2
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +2 -2
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +1 -2
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.js +2 -2
- package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
- package/lib/chain/serializeState.d.ts.map +1 -1
- package/lib/chain/serializeState.js +2 -1
- package/lib/chain/serializeState.js.map +1 -1
- package/lib/chain/validation/blobSidecar.js +2 -2
- package/lib/chain/validation/blobSidecar.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +2 -2
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/network/core/networkCore.d.ts +3 -0
- package/lib/network/core/networkCore.d.ts.map +1 -1
- package/lib/network/core/networkCore.js +9 -0
- package/lib/network/core/networkCore.js.map +1 -1
- package/lib/network/core/networkCoreWorker.js +3 -0
- package/lib/network/core/networkCoreWorker.js.map +1 -1
- package/lib/network/core/networkCoreWorkerHandler.d.ts +3 -0
- package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
- package/lib/network/core/networkCoreWorkerHandler.js +9 -0
- package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
- package/lib/network/core/types.d.ts +3 -0
- package/lib/network/core/types.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts +16 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +52 -0
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/network.d.ts +3 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +9 -0
- package/lib/network/network.js.map +1 -1
- package/lib/sync/backfill/backfill.d.ts.map +1 -1
- package/lib/sync/backfill/backfill.js +1 -2
- package/lib/sync/backfill/backfill.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +2 -2
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +1 -2
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/package.json +16 -16
- package/src/api/impl/lodestar/index.ts +17 -0
- package/src/api/rest/base.ts +15 -13
- package/src/chain/archiveStore/historicalState/getHistoricalState.ts +2 -1
- package/src/chain/blocks/blockInput/blockInput.ts +2 -2
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +1 -2
- package/src/chain/initState.ts +2 -2
- package/src/chain/lightClient/index.ts +1 -2
- package/src/chain/seenCache/seenGossipBlockInput.ts +2 -2
- package/src/chain/serializeState.ts +2 -1
- package/src/chain/validation/blobSidecar.ts +2 -2
- package/src/chain/validation/dataColumnSidecar.ts +2 -2
- package/src/network/core/networkCore.ts +12 -0
- package/src/network/core/networkCoreWorker.ts +3 -0
- package/src/network/core/networkCoreWorkerHandler.ts +9 -0
- package/src/network/core/types.ts +6 -0
- package/src/network/gossip/gossipsub.ts +62 -1
- package/src/network/network.ts +12 -0
- package/src/sync/backfill/backfill.ts +1 -2
- package/src/sync/utils/downloadByRange.ts +2 -2
- package/src/sync/utils/downloadByRoot.ts +1 -2
- package/lib/util/bytes.d.ts +0 -3
- package/lib/util/bytes.d.ts.map +0 -1
- package/lib/util/bytes.js +0 -11
- package/lib/util/bytes.js.map +0 -1
- package/src/util/bytes.ts +0 -11
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.40.0-dev.
|
|
14
|
+
"version": "1.40.0-dev.f58ab9b042",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -134,24 +134,24 @@
|
|
|
134
134
|
"@libp2p/peer-id": "^5.1.0",
|
|
135
135
|
"@libp2p/prometheus-metrics": "^4.3.15",
|
|
136
136
|
"@libp2p/tcp": "^10.1.8",
|
|
137
|
-
"@lodestar/api": "^1.40.0-dev.
|
|
138
|
-
"@lodestar/config": "^1.40.0-dev.
|
|
139
|
-
"@lodestar/db": "^1.40.0-dev.
|
|
140
|
-
"@lodestar/fork-choice": "^1.40.0-dev.
|
|
141
|
-
"@lodestar/light-client": "^1.40.0-dev.
|
|
142
|
-
"@lodestar/logger": "^1.40.0-dev.
|
|
143
|
-
"@lodestar/params": "^1.40.0-dev.
|
|
144
|
-
"@lodestar/reqresp": "^1.40.0-dev.
|
|
145
|
-
"@lodestar/state-transition": "^1.40.0-dev.
|
|
146
|
-
"@lodestar/types": "^1.40.0-dev.
|
|
147
|
-
"@lodestar/utils": "^1.40.0-dev.
|
|
148
|
-
"@lodestar/validator": "^1.40.0-dev.
|
|
137
|
+
"@lodestar/api": "^1.40.0-dev.f58ab9b042",
|
|
138
|
+
"@lodestar/config": "^1.40.0-dev.f58ab9b042",
|
|
139
|
+
"@lodestar/db": "^1.40.0-dev.f58ab9b042",
|
|
140
|
+
"@lodestar/fork-choice": "^1.40.0-dev.f58ab9b042",
|
|
141
|
+
"@lodestar/light-client": "^1.40.0-dev.f58ab9b042",
|
|
142
|
+
"@lodestar/logger": "^1.40.0-dev.f58ab9b042",
|
|
143
|
+
"@lodestar/params": "^1.40.0-dev.f58ab9b042",
|
|
144
|
+
"@lodestar/reqresp": "^1.40.0-dev.f58ab9b042",
|
|
145
|
+
"@lodestar/state-transition": "^1.40.0-dev.f58ab9b042",
|
|
146
|
+
"@lodestar/types": "^1.40.0-dev.f58ab9b042",
|
|
147
|
+
"@lodestar/utils": "^1.40.0-dev.f58ab9b042",
|
|
148
|
+
"@lodestar/validator": "^1.40.0-dev.f58ab9b042",
|
|
149
149
|
"@multiformats/multiaddr": "^12.1.3",
|
|
150
150
|
"datastore-core": "^10.0.2",
|
|
151
151
|
"datastore-fs": "^10.0.6",
|
|
152
152
|
"datastore-level": "^11.0.3",
|
|
153
153
|
"deepmerge": "^4.3.1",
|
|
154
|
-
"fastify": "^5.
|
|
154
|
+
"fastify": "^5.7.4",
|
|
155
155
|
"interface-datastore": "^8.3.0",
|
|
156
156
|
"it-all": "^3.0.4",
|
|
157
157
|
"it-pipe": "^3.0.1",
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
"@chainsafe/swap-or-not-shuffle": "^1.2.1",
|
|
170
170
|
"@libp2p/interface-internal": "^2.3.18",
|
|
171
171
|
"@libp2p/logger": "^5.1.21",
|
|
172
|
-
"@lodestar/spec-test-util": "^1.40.0-dev.
|
|
172
|
+
"@lodestar/spec-test-util": "^1.40.0-dev.f58ab9b042",
|
|
173
173
|
"@types/js-yaml": "^4.0.5",
|
|
174
174
|
"@types/qs": "^6.9.7",
|
|
175
175
|
"@types/tmp": "^0.2.3",
|
|
@@ -188,5 +188,5 @@
|
|
|
188
188
|
"beacon",
|
|
189
189
|
"blockchain"
|
|
190
190
|
],
|
|
191
|
-
"gitHead": "
|
|
191
|
+
"gitHead": "e8c409a006f8264d0dbd6f5c2479b9d364098ebd"
|
|
192
192
|
}
|
|
@@ -154,6 +154,23 @@ export function getLodestarApi({
|
|
|
154
154
|
await network.disconnectPeer(peerId);
|
|
155
155
|
},
|
|
156
156
|
|
|
157
|
+
async addDirectPeer({peer}) {
|
|
158
|
+
const peerId = await network.addDirectPeer(peer);
|
|
159
|
+
if (peerId === null) {
|
|
160
|
+
throw new ApiError(400, `Failed to add direct peer: invalid peer address or ENR "${peer}"`);
|
|
161
|
+
}
|
|
162
|
+
return {data: {peerId}};
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
async removeDirectPeer({peerId}) {
|
|
166
|
+
const removed = await network.removeDirectPeer(peerId);
|
|
167
|
+
return {data: {removed}};
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
async getDirectPeers() {
|
|
171
|
+
return {data: await network.getDirectPeers()};
|
|
172
|
+
},
|
|
173
|
+
|
|
157
174
|
async getPeers({state, direction}) {
|
|
158
175
|
const peers = (await network.dumpPeers()).filter(
|
|
159
176
|
(nodePeer) =>
|
package/src/api/rest/base.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import bearerAuthPlugin from "@fastify/bearer-auth";
|
|
2
2
|
import {fastifyCors} from "@fastify/cors";
|
|
3
|
-
import {FastifyInstance, FastifyRequest, errorCodes, fastify} from "fastify";
|
|
3
|
+
import {FastifyError, FastifyInstance, FastifyRequest, errorCodes, fastify} from "fastify";
|
|
4
4
|
import {parse as parseQueryString} from "qs";
|
|
5
5
|
import {addSszContentTypeParser} from "@lodestar/api/server";
|
|
6
6
|
import {ErrorAborted, Gauge, Histogram, Logger} from "@lodestar/utils";
|
|
@@ -73,15 +73,17 @@ export class RestApiServer {
|
|
|
73
73
|
const server = fastify({
|
|
74
74
|
logger: false,
|
|
75
75
|
ajv: {customOptions: {coerceTypes: "array"}},
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
routerOptions: {
|
|
77
|
+
querystringParser: (str) =>
|
|
78
|
+
parseQueryString(str, {
|
|
79
|
+
// Array as comma-separated values must be supported to be OpenAPI spec compliant
|
|
80
|
+
comma: true,
|
|
81
|
+
// Drop support for array query strings like `id[0]=1&id[1]=2&id[2]=3` as those are not required to
|
|
82
|
+
// be OpenAPI spec compliant and results are inconsistent, see https://github.com/ljharb/qs/issues/331.
|
|
83
|
+
// The schema validation will catch this and throw an error as parsed query string results in an object.
|
|
84
|
+
parseArrays: false,
|
|
85
|
+
}),
|
|
86
|
+
},
|
|
85
87
|
bodyLimit: opts.bodyLimit,
|
|
86
88
|
http: {maxHeaderSize: opts.headerLimit},
|
|
87
89
|
});
|
|
@@ -91,10 +93,10 @@ export class RestApiServer {
|
|
|
91
93
|
this.activeSockets = new HttpActiveSocketsTracker(server.server, metrics);
|
|
92
94
|
|
|
93
95
|
// To parse our ApiError -> statusCode
|
|
94
|
-
server.setErrorHandler((err, _req, res) => {
|
|
96
|
+
server.setErrorHandler<FastifyError | Error>((err, _req, res) => {
|
|
95
97
|
const stacktraces = opts.stacktraces ? err.stack?.split("\n") : undefined;
|
|
96
|
-
if (err.validation) {
|
|
97
|
-
const {instancePath, message} = err.validation[0];
|
|
98
|
+
if ("validation" in err && err.validation) {
|
|
99
|
+
const {instancePath = "unknown", message} = err.validation?.[0] ?? {};
|
|
98
100
|
const payload: ErrorResponse = {
|
|
99
101
|
code: 400,
|
|
100
102
|
message: `${instancePath.substring(instancePath.lastIndexOf("/") + 1)} ${message}`,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
createCachedBeaconState,
|
|
9
9
|
stateTransition,
|
|
10
10
|
} from "@lodestar/state-transition";
|
|
11
|
+
import {byteArrayEquals} from "@lodestar/utils";
|
|
11
12
|
import {IBeaconDb} from "../../../db/index.js";
|
|
12
13
|
import {getStateTypeFromBytes} from "../../../util/multifork.js";
|
|
13
14
|
import {HistoricalStateRegenMetrics} from "./metrics.js";
|
|
@@ -98,7 +99,7 @@ export async function getHistoricalState(
|
|
|
98
99
|
throw e;
|
|
99
100
|
}
|
|
100
101
|
blockCount++;
|
|
101
|
-
if (
|
|
102
|
+
if (!byteArrayEquals(state.hashTreeRoot(), block.message.stateRoot)) {
|
|
102
103
|
metrics?.regenErrorCount.inc({reason: RegenErrorType.invalidStateRoot});
|
|
103
104
|
}
|
|
104
105
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {ForkName, ForkPostFulu, ForkPreDeneb, ForkPreGloas, NUMBER_OF_COLUMNS} from "@lodestar/params";
|
|
2
2
|
import {BeaconBlockBody, BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
|
|
3
|
-
import {fromHex, prettyBytes, toRootHex, withTimeout} from "@lodestar/utils";
|
|
3
|
+
import {byteArrayEquals, fromHex, prettyBytes, toRootHex, withTimeout} from "@lodestar/utils";
|
|
4
4
|
import {VersionedHashes} from "../../../execution/index.js";
|
|
5
5
|
import {kzgCommitmentToVersionedHash} from "../../../util/blobs.js";
|
|
6
6
|
import {BlockInputError, BlockInputErrorCode} from "./errors.js";
|
|
@@ -529,7 +529,7 @@ function blockAndBlobArePaired(block: SignedBeaconBlock<ForkBlobsDA>, blobSideca
|
|
|
529
529
|
if (!blockCommitment || !blobSidecar.kzgCommitment) {
|
|
530
530
|
return false;
|
|
531
531
|
}
|
|
532
|
-
return
|
|
532
|
+
return byteArrayEquals(blockCommitment, blobSidecar.kzgCommitment);
|
|
533
533
|
}
|
|
534
534
|
|
|
535
535
|
function assertBlockAndBlobArePaired(
|
|
@@ -5,9 +5,8 @@ import {
|
|
|
5
5
|
StateHashTreeRootSource,
|
|
6
6
|
stateTransition,
|
|
7
7
|
} from "@lodestar/state-transition";
|
|
8
|
-
import {ErrorAborted, Logger} from "@lodestar/utils";
|
|
8
|
+
import {ErrorAborted, Logger, byteArrayEquals} from "@lodestar/utils";
|
|
9
9
|
import {Metrics} from "../../metrics/index.js";
|
|
10
|
-
import {byteArrayEquals} from "../../util/bytes.js";
|
|
11
10
|
import {nextEventLoop} from "../../util/eventLoop.js";
|
|
12
11
|
import {BlockError, BlockErrorCode} from "../errors/index.js";
|
|
13
12
|
import {BlockProcessOpts} from "../options.js";
|
package/src/chain/initState.ts
CHANGED
|
@@ -2,7 +2,7 @@ import {ChainForkConfig} from "@lodestar/config";
|
|
|
2
2
|
import {ZERO_HASH} from "@lodestar/params";
|
|
3
3
|
import {BeaconStateAllForks, computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
4
4
|
import {SignedBeaconBlock, ssz} from "@lodestar/types";
|
|
5
|
-
import {Logger, toHex, toRootHex} from "@lodestar/utils";
|
|
5
|
+
import {Logger, byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
6
6
|
import {GENESIS_SLOT} from "../constants/index.js";
|
|
7
7
|
import {IBeaconDb} from "../db/index.js";
|
|
8
8
|
import {Metrics} from "../metrics/index.js";
|
|
@@ -26,7 +26,7 @@ export async function persistAnchorState(
|
|
|
26
26
|
|
|
27
27
|
const latestBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(latestBlockHeader);
|
|
28
28
|
|
|
29
|
-
if (
|
|
29
|
+
if (!byteArrayEquals(blockRoot, latestBlockRoot)) {
|
|
30
30
|
throw Error(
|
|
31
31
|
`Genesis block root ${toRootHex(blockRoot)} does not match genesis state latest block root ${toRootHex(latestBlockRoot)}`
|
|
32
32
|
);
|
|
@@ -46,12 +46,11 @@ import {
|
|
|
46
46
|
ssz,
|
|
47
47
|
sszTypesFor,
|
|
48
48
|
} from "@lodestar/types";
|
|
49
|
-
import {Logger, MapDef, pruneSetToMax, toRootHex} from "@lodestar/utils";
|
|
49
|
+
import {Logger, MapDef, byteArrayEquals, pruneSetToMax, toRootHex} from "@lodestar/utils";
|
|
50
50
|
import {ZERO_HASH} from "../../constants/index.js";
|
|
51
51
|
import {IBeaconDb} from "../../db/index.js";
|
|
52
52
|
import {NUM_WITNESS, NUM_WITNESS_ELECTRA} from "../../db/repositories/lightclientSyncCommitteeWitness.js";
|
|
53
53
|
import {Metrics} from "../../metrics/index.js";
|
|
54
|
-
import {byteArrayEquals} from "../../util/bytes.js";
|
|
55
54
|
import {IClock} from "../../util/clock.js";
|
|
56
55
|
import {ChainEventEmitter} from "../emitter.js";
|
|
57
56
|
import {LightClientServerError, LightClientServerErrorCode} from "../errors/lightClientError.js";
|
|
@@ -3,7 +3,7 @@ import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
|
3
3
|
import {ForkName, ForkPostFulu, ForkPreGloas, isForkPostDeneb, isForkPostFulu, isForkPostGloas} from "@lodestar/params";
|
|
4
4
|
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
5
5
|
import {BLSSignature, RootHex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
|
|
6
|
-
import {LodestarError, Logger, pruneSetToMax} from "@lodestar/utils";
|
|
6
|
+
import {LodestarError, Logger, byteArrayEquals, pruneSetToMax} from "@lodestar/utils";
|
|
7
7
|
import {Metrics} from "../../metrics/metrics.js";
|
|
8
8
|
import {IClock} from "../../util/clock.js";
|
|
9
9
|
import {CustodyConfig} from "../../util/dataColumns.js";
|
|
@@ -344,7 +344,7 @@ export class SeenBlockInput {
|
|
|
344
344
|
return false;
|
|
345
345
|
}
|
|
346
346
|
// Only consider verified if the signature matches
|
|
347
|
-
return
|
|
347
|
+
return byteArrayEquals(cachedSignature, signature);
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
/**
|
|
@@ -20,7 +20,8 @@ export async function serializeState<T>(
|
|
|
20
20
|
stateBytes = bufferWithKey.buffer;
|
|
21
21
|
const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength);
|
|
22
22
|
state.serializeToBytes({uint8Array: stateBytes, dataView}, 0);
|
|
23
|
-
|
|
23
|
+
// Await to ensure buffer is not released back to pool until processFn completes
|
|
24
|
+
return await processFn(stateBytes);
|
|
24
25
|
}
|
|
25
26
|
// release the buffer back to the pool automatically
|
|
26
27
|
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
getBlockHeaderProposerSignatureSetByParentStateSlot,
|
|
13
13
|
} from "@lodestar/state-transition";
|
|
14
14
|
import {BlobIndex, Root, Slot, SubnetID, deneb, ssz} from "@lodestar/types";
|
|
15
|
-
import {toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
15
|
+
import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
16
16
|
import {kzg} from "../../util/kzg.js";
|
|
17
17
|
import {BlobSidecarErrorCode, BlobSidecarGossipError, BlobSidecarValidationError} from "../errors/blobSidecarError.js";
|
|
18
18
|
import {GossipAction} from "../errors/gossipValidation.js";
|
|
@@ -226,7 +226,7 @@ export async function validateBlockBlobSidecars(
|
|
|
226
226
|
const firstSidecarSignedBlockHeader = blobSidecars[0].signedBlockHeader;
|
|
227
227
|
const firstSidecarBlockHeader = firstSidecarSignedBlockHeader.message;
|
|
228
228
|
const firstBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(firstSidecarBlockHeader);
|
|
229
|
-
if (
|
|
229
|
+
if (!byteArrayEquals(blockRoot, firstBlockRoot)) {
|
|
230
230
|
throw new BlobSidecarValidationError(
|
|
231
231
|
{
|
|
232
232
|
code: BlobSidecarErrorCode.INCORRECT_BLOCK,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
getBlockHeaderProposerSignatureSetByParentStateSlot,
|
|
12
12
|
} from "@lodestar/state-transition";
|
|
13
13
|
import {Root, Slot, SubnetID, fulu, ssz} from "@lodestar/types";
|
|
14
|
-
import {toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
14
|
+
import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
15
15
|
import {Metrics} from "../../metrics/metrics.js";
|
|
16
16
|
import {kzg} from "../../util/kzg.js";
|
|
17
17
|
import {
|
|
@@ -318,7 +318,7 @@ export async function validateBlockDataColumnSidecars(
|
|
|
318
318
|
const firstSidecarSignedBlockHeader = dataColumnSidecars[0].signedBlockHeader;
|
|
319
319
|
const firstSidecarBlockHeader = firstSidecarSignedBlockHeader.message;
|
|
320
320
|
const firstBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(firstSidecarBlockHeader);
|
|
321
|
-
if (
|
|
321
|
+
if (!byteArrayEquals(blockRoot, firstBlockRoot)) {
|
|
322
322
|
throw new DataColumnSidecarValidationError(
|
|
323
323
|
{
|
|
324
324
|
code: DataColumnSidecarErrorCode.INCORRECT_BLOCK,
|
|
@@ -454,6 +454,18 @@ export class NetworkCore implements INetworkCore {
|
|
|
454
454
|
await this.libp2p.hangUp(peerIdFromString(peerIdStr));
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
+
async addDirectPeer(peer: routes.lodestar.DirectPeer): Promise<string | null> {
|
|
458
|
+
return this.gossip.addDirectPeer(peer);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async removeDirectPeer(peerIdStr: PeerIdStr): Promise<boolean> {
|
|
462
|
+
return this.gossip.removeDirectPeer(peerIdStr);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async getDirectPeers(): Promise<string[]> {
|
|
466
|
+
return this.gossip.getDirectPeers();
|
|
467
|
+
}
|
|
468
|
+
|
|
457
469
|
private _dumpPeer(peerIdStr: string, connections: Connection[]): routes.lodestar.LodestarNodePeer {
|
|
458
470
|
const peerData = this.peersData.connectedPeers.get(peerIdStr);
|
|
459
471
|
const fork = this.config.getForkName(this.clock.currentSlot);
|
|
@@ -153,6 +153,9 @@ const libp2pWorkerApi: NetworkWorkerApi = {
|
|
|
153
153
|
getConnectedPeerCount: () => core.getConnectedPeerCount(),
|
|
154
154
|
connectToPeer: (peer, multiaddr) => core.connectToPeer(peer, multiaddr),
|
|
155
155
|
disconnectPeer: (peer) => core.disconnectPeer(peer),
|
|
156
|
+
addDirectPeer: (peer) => core.addDirectPeer(peer),
|
|
157
|
+
removeDirectPeer: (peerId) => core.removeDirectPeer(peerId),
|
|
158
|
+
getDirectPeers: () => core.getDirectPeers(),
|
|
156
159
|
dumpPeers: () => core.dumpPeers(),
|
|
157
160
|
dumpPeer: (peerIdStr) => core.dumpPeer(peerIdStr),
|
|
158
161
|
dumpPeerScoreStats: () => core.dumpPeerScoreStats(),
|
|
@@ -247,6 +247,15 @@ export class WorkerNetworkCore implements INetworkCore {
|
|
|
247
247
|
disconnectPeer(peer: PeerIdStr): Promise<void> {
|
|
248
248
|
return this.getApi().disconnectPeer(peer);
|
|
249
249
|
}
|
|
250
|
+
addDirectPeer(peer: routes.lodestar.DirectPeer): Promise<string | null> {
|
|
251
|
+
return this.getApi().addDirectPeer(peer);
|
|
252
|
+
}
|
|
253
|
+
removeDirectPeer(peerId: PeerIdStr): Promise<boolean> {
|
|
254
|
+
return this.getApi().removeDirectPeer(peerId);
|
|
255
|
+
}
|
|
256
|
+
getDirectPeers(): Promise<string[]> {
|
|
257
|
+
return this.getApi().getDirectPeers();
|
|
258
|
+
}
|
|
250
259
|
dumpPeers(): Promise<routes.lodestar.LodestarNodePeer[]> {
|
|
251
260
|
return this.getApi().dumpPeers();
|
|
252
261
|
}
|
|
@@ -30,6 +30,12 @@ export interface INetworkCorePublic {
|
|
|
30
30
|
// Debug
|
|
31
31
|
connectToPeer(peer: PeerIdStr, multiaddr: MultiaddrStr[]): Promise<void>;
|
|
32
32
|
disconnectPeer(peer: PeerIdStr): Promise<void>;
|
|
33
|
+
|
|
34
|
+
// Direct peers management
|
|
35
|
+
addDirectPeer(peer: routes.lodestar.DirectPeer): Promise<string | null>;
|
|
36
|
+
removeDirectPeer(peerId: PeerIdStr): Promise<boolean>;
|
|
37
|
+
getDirectPeers(): Promise<string[]>;
|
|
38
|
+
|
|
33
39
|
dumpPeers(): Promise<routes.lodestar.LodestarNodePeer[]>;
|
|
34
40
|
dumpPeer(peerIdStr: PeerIdStr): Promise<routes.lodestar.LodestarNodePeer | undefined>;
|
|
35
41
|
dumpPeerScoreStats(): Promise<PeerScoreStats>;
|
|
@@ -5,6 +5,7 @@ import {GossipSub, GossipsubEvents} from "@chainsafe/libp2p-gossipsub";
|
|
|
5
5
|
import {MetricsRegister, TopicLabel, TopicStrToLabel} from "@chainsafe/libp2p-gossipsub/metrics";
|
|
6
6
|
import {PeerScoreParams} from "@chainsafe/libp2p-gossipsub/score";
|
|
7
7
|
import {AddrInfo, SignaturePolicy, TopicStr} from "@chainsafe/libp2p-gossipsub/types";
|
|
8
|
+
import {routes} from "@lodestar/api";
|
|
8
9
|
import {BeaconConfig, ForkBoundary} from "@lodestar/config";
|
|
9
10
|
import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
|
|
10
11
|
import {SubnetID} from "@lodestar/types";
|
|
@@ -87,6 +88,7 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
87
88
|
private readonly logger: Logger;
|
|
88
89
|
private readonly peersData: PeersData;
|
|
89
90
|
private readonly events: NetworkEventBus;
|
|
91
|
+
private readonly libp2p: Libp2p;
|
|
90
92
|
|
|
91
93
|
// Internal caches
|
|
92
94
|
private readonly gossipTopicCache: GossipTopicCache;
|
|
@@ -159,6 +161,7 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
159
161
|
this.logger = logger;
|
|
160
162
|
this.peersData = peersData;
|
|
161
163
|
this.events = events;
|
|
164
|
+
this.libp2p = modules.libp2p;
|
|
162
165
|
this.gossipTopicCache = gossipTopicCache;
|
|
163
166
|
|
|
164
167
|
this.addEventListener("gossipsub:message", this.onGossipsubMessage.bind(this));
|
|
@@ -341,6 +344,64 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
341
344
|
this.reportMessageValidationResult(data.msgId, data.propagationSource, data.acceptance);
|
|
342
345
|
});
|
|
343
346
|
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Add a peer as a direct peer at runtime. Accepts multiaddr with peer ID or ENR string.
|
|
350
|
+
* Direct peers maintain permanent mesh connections without GRAFT/PRUNE negotiation.
|
|
351
|
+
*/
|
|
352
|
+
async addDirectPeer(peerStr: routes.lodestar.DirectPeer): Promise<string | null> {
|
|
353
|
+
const parsed = parseDirectPeers([peerStr], this.logger);
|
|
354
|
+
if (parsed.length === 0) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const {id: peerId, addrs} = parsed[0];
|
|
359
|
+
const peerIdStr = peerId.toString();
|
|
360
|
+
|
|
361
|
+
// Prevent adding self as a direct peer
|
|
362
|
+
if (peerId.equals(this.libp2p.peerId)) {
|
|
363
|
+
this.logger.warn("Cannot add self as a direct peer", {peerId: peerIdStr});
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Direct peers need addresses to connect - reject if none provided
|
|
368
|
+
if (addrs.length === 0) {
|
|
369
|
+
this.logger.warn("Cannot add direct peer without addresses", {peerId: peerIdStr});
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Add addresses to peer store first so we can connect
|
|
374
|
+
try {
|
|
375
|
+
await this.libp2p.peerStore.merge(peerId, {multiaddrs: addrs});
|
|
376
|
+
} catch (e) {
|
|
377
|
+
this.logger.warn("Failed to add direct peer addresses to peer store", {peerId: peerIdStr}, e as Error);
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Add to direct peers set only after addresses are stored
|
|
382
|
+
this.direct.add(peerIdStr);
|
|
383
|
+
|
|
384
|
+
this.logger.info("Added direct peer via API", {peerId: peerIdStr});
|
|
385
|
+
return peerIdStr;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Remove a peer from direct peers.
|
|
390
|
+
*/
|
|
391
|
+
removeDirectPeer(peerIdStr: string): boolean {
|
|
392
|
+
const removed = this.direct.delete(peerIdStr);
|
|
393
|
+
if (removed) {
|
|
394
|
+
this.logger.info("Removed direct peer via API", {peerId: peerIdStr});
|
|
395
|
+
}
|
|
396
|
+
return removed;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Get list of current direct peer IDs.
|
|
401
|
+
*/
|
|
402
|
+
getDirectPeers(): string[] {
|
|
403
|
+
return Array.from(this.direct);
|
|
404
|
+
}
|
|
344
405
|
}
|
|
345
406
|
|
|
346
407
|
/**
|
|
@@ -406,7 +467,7 @@ function getForkBoundaryLabel(boundary: ForkBoundary): ForkBoundaryLabel {
|
|
|
406
467
|
* For multiaddrs, the string must contain a /p2p/ component with the peer ID.
|
|
407
468
|
* For ENRs, the TCP multiaddr and peer ID are extracted from the encoded record.
|
|
408
469
|
*/
|
|
409
|
-
export function parseDirectPeers(directPeerStrs:
|
|
470
|
+
export function parseDirectPeers(directPeerStrs: routes.lodestar.DirectPeer[], logger: Logger): AddrInfo[] {
|
|
410
471
|
const directPeers: AddrInfo[] = [];
|
|
411
472
|
|
|
412
473
|
for (const peerStr of directPeerStrs) {
|
package/src/network/network.ts
CHANGED
|
@@ -641,6 +641,18 @@ export class Network implements INetwork {
|
|
|
641
641
|
return this.core.disconnectPeer(peer);
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
addDirectPeer(peer: routes.lodestar.DirectPeer): Promise<string | null> {
|
|
645
|
+
return this.core.addDirectPeer(peer);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
removeDirectPeer(peerId: string): Promise<boolean> {
|
|
649
|
+
return this.core.removeDirectPeer(peerId);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
getDirectPeers(): Promise<string[]> {
|
|
653
|
+
return this.core.getDirectPeers();
|
|
654
|
+
}
|
|
655
|
+
|
|
644
656
|
dumpPeer(peerIdStr: string): Promise<routes.lodestar.LodestarNodePeer | undefined> {
|
|
645
657
|
return this.core.dumpPeer(peerIdStr);
|
|
646
658
|
}
|
|
@@ -4,13 +4,12 @@ import {BeaconConfig, ChainForkConfig} from "@lodestar/config";
|
|
|
4
4
|
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
5
5
|
import {BeaconStateAllForks, blockToHeader, computeAnchorCheckpoint} from "@lodestar/state-transition";
|
|
6
6
|
import {Root, SignedBeaconBlock, Slot, phase0, ssz} from "@lodestar/types";
|
|
7
|
-
import {ErrorAborted, Logger, sleep, toRootHex} from "@lodestar/utils";
|
|
7
|
+
import {ErrorAborted, Logger, byteArrayEquals, sleep, toRootHex} from "@lodestar/utils";
|
|
8
8
|
import {IBeaconChain} from "../../chain/index.js";
|
|
9
9
|
import {GENESIS_SLOT, ZERO_HASH} from "../../constants/index.js";
|
|
10
10
|
import {IBeaconDb} from "../../db/index.js";
|
|
11
11
|
import {Metrics} from "../../metrics/metrics.js";
|
|
12
12
|
import {INetwork, NetworkEvent, NetworkEventData, PeerAction} from "../../network/index.js";
|
|
13
|
-
import {byteArrayEquals} from "../../util/bytes.js";
|
|
14
13
|
import {ItTrigger} from "../../util/itTrigger.js";
|
|
15
14
|
import {PeerIdStr} from "../../util/peerId.js";
|
|
16
15
|
import {shuffleOne} from "../../util/shuffle.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
isForkPostGloas,
|
|
9
9
|
} from "@lodestar/params";
|
|
10
10
|
import {SignedBeaconBlock, Slot, deneb, fulu, phase0} from "@lodestar/types";
|
|
11
|
-
import {LodestarError, Logger, fromHex, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
11
|
+
import {LodestarError, Logger, byteArrayEquals, fromHex, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
12
12
|
import {
|
|
13
13
|
BlockInputSource,
|
|
14
14
|
DAType,
|
|
@@ -475,7 +475,7 @@ export function validateBlockByRangeResponse(
|
|
|
475
475
|
if (i < blocks.length - 1) {
|
|
476
476
|
// compare the block root against the next block's parent root
|
|
477
477
|
const parentRoot = blocks[i + 1].message.parentRoot;
|
|
478
|
-
if (
|
|
478
|
+
if (!byteArrayEquals(blockRoot, parentRoot)) {
|
|
479
479
|
throw new DownloadByRangeError(
|
|
480
480
|
{
|
|
481
481
|
code: DownloadByRangeErrorCode.PARENT_ROOT_MISMATCH,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
isForkPostFulu,
|
|
10
10
|
} from "@lodestar/params";
|
|
11
11
|
import {BeaconBlockBody, BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
|
|
12
|
-
import {LodestarError, fromHex, prettyPrintIndices, toHex, toRootHex} from "@lodestar/utils";
|
|
12
|
+
import {LodestarError, byteArrayEquals, fromHex, prettyPrintIndices, toHex, toRootHex} from "@lodestar/utils";
|
|
13
13
|
import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
14
14
|
import {BlockInputSource, IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
15
15
|
import {ChainEventEmitter} from "../../chain/emitter.js";
|
|
@@ -19,7 +19,6 @@ import {validateBlockDataColumnSidecars} from "../../chain/validation/dataColumn
|
|
|
19
19
|
import {INetwork} from "../../network/interface.js";
|
|
20
20
|
import {PeerSyncMeta} from "../../network/peers/peersData.js";
|
|
21
21
|
import {prettyPrintPeerIdStr} from "../../network/util.js";
|
|
22
|
-
import {byteArrayEquals} from "../../util/bytes.js";
|
|
23
22
|
import {PeerIdStr} from "../../util/peerId.js";
|
|
24
23
|
import {WarnResult} from "../../util/wrapError.js";
|
|
25
24
|
import {
|
package/lib/util/bytes.d.ts
DELETED
package/lib/util/bytes.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../../src/util/bytes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,iBAAiB,CAAC;AAErC,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,EAAE,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAQnF"}
|
package/lib/util/bytes.js
DELETED
package/lib/util/bytes.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bytes.js","sourceRoot":"","sources":["../../src/util/bytes.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,eAAe,CAAC,CAAoB,EAAE,CAAoB;IACxE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/src/util/bytes.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import {Root} from "@lodestar/types";
|
|
2
|
-
|
|
3
|
-
export function byteArrayEquals(a: Uint8Array | Root, b: Uint8Array | Root): boolean {
|
|
4
|
-
if (a.length !== b.length) {
|
|
5
|
-
return false;
|
|
6
|
-
}
|
|
7
|
-
for (let i = 0; i < a.length; i++) {
|
|
8
|
-
if (a[i] !== b[i]) return false;
|
|
9
|
-
}
|
|
10
|
-
return true;
|
|
11
|
-
}
|