@lodestar/beacon-node 1.41.0-dev.e27085846c → 1.41.0-dev.ef310100c0
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/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +121 -3
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.js +8 -8
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +3 -4
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +5 -24
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +5 -2
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/lightclient/index.d.ts.map +1 -1
- package/lib/api/impl/lightclient/index.js +19 -2
- package/lib/api/impl/lightclient/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +104 -6
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +1 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +9 -0
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts +5 -6
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js +9 -10
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js +3 -3
- package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
- package/lib/chain/archiveStore/utils/archivePayloads.d.ts +7 -0
- package/lib/chain/archiveStore/utils/archivePayloads.d.ts.map +1 -0
- package/lib/chain/archiveStore/utils/archivePayloads.js +10 -0
- package/lib/chain/archiveStore/utils/archivePayloads.js.map +1 -0
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +0 -2
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +2 -1
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.js +3 -0
- package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
- package/lib/chain/bls/multithread/index.d.ts +3 -3
- package/lib/chain/bls/multithread/index.d.ts.map +1 -1
- package/lib/chain/bls/multithread/index.js +5 -5
- package/lib/chain/bls/multithread/index.js.map +1 -1
- package/lib/chain/bls/multithread/jobItem.d.ts +2 -2
- package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
- package/lib/chain/bls/multithread/jobItem.js +2 -2
- package/lib/chain/bls/multithread/jobItem.js.map +1 -1
- package/lib/chain/bls/singleThread.d.ts +4 -4
- package/lib/chain/bls/singleThread.d.ts.map +1 -1
- package/lib/chain/bls/singleThread.js +4 -4
- package/lib/chain/bls/singleThread.js.map +1 -1
- package/lib/chain/bls/utils.d.ts +2 -2
- package/lib/chain/bls/utils.d.ts.map +1 -1
- package/lib/chain/bls/utils.js +7 -4
- package/lib/chain/bls/utils.js.map +1 -1
- package/lib/chain/chain.d.ts +6 -9
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +32 -16
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +2 -2
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/interface.d.ts +4 -6
- 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 +1 -1
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.js +3 -3
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts +10 -2
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +24 -2
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +22 -7
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +110 -10
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +4 -1
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +1 -1
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts +2 -2
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +8 -1
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +1 -1
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.js +1 -1
- package/lib/db/beacon.d.ts +3 -1
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +5 -1
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/buckets.d.ts +3 -1
- package/lib/db/buckets.d.ts.map +1 -1
- package/lib/db/buckets.js +2 -0
- package/lib/db/buckets.js.map +1 -1
- package/lib/db/interface.d.ts +3 -1
- package/lib/db/interface.d.ts.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
- package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
- package/lib/db/repositories/dataColumnSidecar.d.ts +5 -3
- package/lib/db/repositories/dataColumnSidecar.d.ts.map +1 -1
- package/lib/db/repositories/dataColumnSidecar.js +14 -1
- package/lib/db/repositories/dataColumnSidecar.js.map +1 -1
- package/lib/db/repositories/dataColumnSidecarArchive.d.ts +5 -3
- package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
- package/lib/db/repositories/dataColumnSidecarArchive.js +14 -1
- package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
- package/lib/db/repositories/executionPayloadEnvelope.d.ts +19 -0
- package/lib/db/repositories/executionPayloadEnvelope.d.ts.map +1 -0
- package/lib/db/repositories/executionPayloadEnvelope.js +22 -0
- package/lib/db/repositories/executionPayloadEnvelope.js.map +1 -0
- package/lib/db/repositories/executionPayloadEnvelopeArchive.d.ts +18 -0
- package/lib/db/repositories/executionPayloadEnvelopeArchive.d.ts.map +1 -0
- package/lib/db/repositories/executionPayloadEnvelopeArchive.js +28 -0
- package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -0
- package/lib/db/repositories/index.d.ts +2 -0
- package/lib/db/repositories/index.d.ts.map +1 -1
- package/lib/db/repositories/index.js +2 -0
- package/lib/db/repositories/index.js.map +1 -1
- package/lib/execution/engine/http.d.ts +1 -0
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +3 -0
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/metrics/metrics/beacon.d.ts +1 -0
- package/lib/metrics/metrics/beacon.d.ts.map +1 -1
- package/lib/metrics/metrics/beacon.js +5 -0
- package/lib/metrics/metrics/beacon.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +8 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +14 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/metrics/metrics.d.ts.map +1 -1
- package/lib/metrics/metrics.js +8 -3
- package/lib/metrics/metrics.js.map +1 -1
- package/lib/monitoring/service.d.ts +2 -2
- package/lib/monitoring/service.d.ts.map +1 -1
- package/lib/monitoring/service.js +3 -2
- package/lib/monitoring/service.js.map +1 -1
- package/lib/network/gossip/interface.d.ts +3 -3
- package/lib/network/gossip/interface.d.ts.map +1 -1
- package/lib/network/gossip/topic.d.ts +113 -63
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +2 -2
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/interface.d.ts +3 -2
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +3 -2
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +10 -1
- package/lib/network/network.js.map +1 -1
- package/lib/network/peers/peerManager.d.ts +2 -0
- package/lib/network/peers/peerManager.d.ts.map +1 -1
- package/lib/network/peers/peerManager.js +54 -26
- package/lib/network/peers/peerManager.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +5 -1
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/lightClientUpdatesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/lightClientUpdatesByRange.js +7 -1
- package/lib/network/reqresp/handlers/lightClientUpdatesByRange.js.map +1 -1
- package/lib/node/nodejs.d.ts +3 -5
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +6 -4
- package/lib/node/nodejs.js.map +1 -1
- package/lib/util/blobs.d.ts +2 -2
- package/lib/util/blobs.d.ts.map +1 -1
- package/lib/util/blobs.js.map +1 -1
- package/lib/util/dataColumns.d.ts +11 -3
- package/lib/util/dataColumns.d.ts.map +1 -1
- package/lib/util/dataColumns.js +27 -0
- package/lib/util/dataColumns.js.map +1 -1
- package/lib/util/multifork.d.ts +8 -0
- package/lib/util/multifork.d.ts.map +1 -1
- package/lib/util/multifork.js +37 -0
- package/lib/util/multifork.js.map +1 -1
- package/lib/util/serializedCache.d.ts +5 -0
- package/lib/util/serializedCache.d.ts.map +1 -1
- package/lib/util/serializedCache.js +5 -0
- package/lib/util/serializedCache.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +145 -2
- package/src/api/impl/beacon/state/index.ts +8 -8
- package/src/api/impl/beacon/state/utils.ts +15 -29
- package/src/api/impl/debug/index.ts +8 -5
- package/src/api/impl/lightclient/index.ts +19 -2
- package/src/api/impl/validator/index.ts +127 -5
- package/src/chain/archiveStore/archiveStore.ts +10 -0
- package/src/chain/archiveStore/historicalState/getHistoricalState.ts +10 -11
- package/src/chain/archiveStore/historicalState/worker.ts +3 -3
- package/src/chain/archiveStore/utils/archivePayloads.ts +15 -0
- package/src/chain/blocks/importBlock.ts +0 -3
- package/src/chain/blocks/index.ts +2 -1
- package/src/chain/blocks/writeBlockInputToDb.ts +3 -0
- package/src/chain/bls/multithread/index.ts +7 -7
- package/src/chain/bls/multithread/jobItem.ts +3 -3
- package/src/chain/bls/singleThread.ts +5 -5
- package/src/chain/bls/utils.ts +8 -5
- package/src/chain/chain.ts +51 -26
- package/src/chain/emitter.ts +2 -2
- package/src/chain/interface.ts +4 -11
- package/src/chain/lightClient/index.ts +4 -1
- package/src/chain/options.ts +1 -0
- package/src/chain/prepareNextSlot.ts +5 -5
- package/src/chain/produceBlock/computeNewStateRoot.ts +35 -3
- package/src/chain/produceBlock/produceBlockBody.ts +163 -13
- package/src/chain/validation/attestation.ts +4 -1
- package/src/chain/validation/attesterSlashing.ts +1 -1
- package/src/chain/validation/dataColumnSidecar.ts +2 -5
- package/src/chain/validation/payloadAttestationMessage.ts +9 -1
- package/src/chain/validation/proposerSlashing.ts +1 -1
- package/src/chain/validation/syncCommitteeContributionAndProof.ts +1 -1
- package/src/db/beacon.ts +8 -0
- package/src/db/buckets.ts +3 -0
- package/src/db/interface.ts +5 -0
- package/src/db/repositories/dataColumnSidecar.ts +18 -3
- package/src/db/repositories/dataColumnSidecarArchive.ts +18 -3
- package/src/db/repositories/executionPayloadEnvelope.ts +26 -0
- package/src/db/repositories/executionPayloadEnvelopeArchive.ts +32 -0
- package/src/db/repositories/index.ts +2 -0
- package/src/execution/engine/http.ts +3 -0
- package/src/metrics/metrics/beacon.ts +5 -0
- package/src/metrics/metrics/lodestar.ts +14 -0
- package/src/metrics/metrics.ts +8 -3
- package/src/monitoring/service.ts +3 -2
- package/src/network/gossip/interface.ts +3 -3
- package/src/network/gossip/topic.ts +2 -1
- package/src/network/interface.ts +4 -1
- package/src/network/network.ts +21 -3
- package/src/network/peers/peerManager.ts +65 -27
- package/src/network/processor/gossipHandlers.ts +7 -1
- package/src/network/reqresp/handlers/lightClientUpdatesByRange.ts +6 -1
- package/src/node/nodejs.ts +8 -9
- package/src/util/blobs.ts +3 -3
- package/src/util/dataColumns.ts +37 -1
- package/src/util/multifork.ts +45 -0
- package/src/util/serializedCache.ts +5 -0
|
@@ -9,6 +9,7 @@ import {prettyPrintIndices, toHex, withTimeout} from "@lodestar/utils";
|
|
|
9
9
|
import {GOODBYE_KNOWN_CODES, GoodByeReasonCode, Libp2pEvent} from "../../constants/index.js";
|
|
10
10
|
import {IClock} from "../../util/clock.js";
|
|
11
11
|
import {computeColumnsForCustodyGroup, getCustodyGroups} from "../../util/dataColumns.js";
|
|
12
|
+
import {callInNextEventLoop} from "../../util/eventLoop.js";
|
|
12
13
|
import {NetworkCoreMetrics} from "../core/metrics.js";
|
|
13
14
|
import {LodestarDiscv5Opts} from "../discv5/types.js";
|
|
14
15
|
import {INetworkEventBus, NetworkEvent, NetworkEventData} from "../events.js";
|
|
@@ -196,6 +197,13 @@ export class PeerManager {
|
|
|
196
197
|
|
|
197
198
|
this.lastStatus = this.statusCache.get();
|
|
198
199
|
|
|
200
|
+
// A connection may already be open before listeners are attached.
|
|
201
|
+
// Seed those peers so they are tracked in connectedPeers immediately.
|
|
202
|
+
this.bootstrapAlreadyOpenConnections();
|
|
203
|
+
// Defer status/ping to the next event loop tick so the heartbeat interval and
|
|
204
|
+
// event listeners are fully registered before we begin handshakes.
|
|
205
|
+
callInNextEventLoop(() => this.pingAndStatusTimeouts());
|
|
206
|
+
|
|
199
207
|
// On start-up will connected to existing peers in libp2p.peerStore, same as autoDial behaviour
|
|
200
208
|
this.heartbeat();
|
|
201
209
|
this.intervals = [
|
|
@@ -692,36 +700,39 @@ export class PeerManager {
|
|
|
692
700
|
}
|
|
693
701
|
}
|
|
694
702
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
703
|
+
private bootstrapAlreadyOpenConnections(): void {
|
|
704
|
+
let bootstrapped = 0;
|
|
705
|
+
|
|
706
|
+
for (const {value: connections} of getConnectionsMap(this.libp2p).values()) {
|
|
707
|
+
for (const connection of connections) {
|
|
708
|
+
// trackLibp2pConnection handles deduplication via overwriteExisting: false
|
|
709
|
+
if (this.trackLibp2pConnection(connection, {overwriteExisting: false, triggerHandshakeNow: false})) {
|
|
710
|
+
bootstrapped++;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
if (bootstrapped > 0) {
|
|
716
|
+
this.logger.verbose("Bootstrapped already-open libp2p peers", {bootstrapped});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
private trackLibp2pConnection(
|
|
721
|
+
connection: Connection,
|
|
722
|
+
opts: {overwriteExisting: boolean; triggerHandshakeNow: boolean}
|
|
723
|
+
): boolean {
|
|
724
|
+
const {direction, status, remotePeer} = connection;
|
|
704
725
|
const remotePeerStr = remotePeer.toString();
|
|
705
726
|
const remotePeerPrettyStr = prettyPrintPeerId(remotePeer);
|
|
706
|
-
this.logger.verbose("peer connected", {peer: remotePeerPrettyStr, direction, status});
|
|
707
|
-
// NOTE: The peerConnect event is not emitted here here, but after asserting peer relevance
|
|
708
|
-
this.metrics?.peerConnectedEvent.inc({direction, status});
|
|
709
727
|
|
|
710
|
-
if (
|
|
728
|
+
if (status !== "open") {
|
|
711
729
|
this.logger.debug("Peer disconnected before identify protocol initiated", {
|
|
712
730
|
peerId: remotePeerPrettyStr,
|
|
713
|
-
status
|
|
731
|
+
status,
|
|
714
732
|
});
|
|
715
|
-
return;
|
|
733
|
+
return false;
|
|
716
734
|
}
|
|
717
735
|
|
|
718
|
-
// On connection:
|
|
719
|
-
// - Outbound connections: send a STATUS and PING request
|
|
720
|
-
// - Inbound connections: expect to be STATUS'd, schedule STATUS and PING for latter
|
|
721
|
-
// NOTE: libp2p may emit two "peer:connect" events: One for inbound, one for outbound
|
|
722
|
-
// If that happens, it's okay. Only the "outbound" connection triggers immediate action
|
|
723
|
-
const now = Date.now();
|
|
724
|
-
|
|
725
736
|
// Ethereum uses secp256k1 for node IDs, reject peers with other key types
|
|
726
737
|
if (remotePeer.type !== "secp256k1") {
|
|
727
738
|
this.logger.debug("Peer does not have secp256k1 key, disconnecting", {
|
|
@@ -729,9 +740,19 @@ export class PeerManager {
|
|
|
729
740
|
type: remotePeer.type,
|
|
730
741
|
});
|
|
731
742
|
void this.goodbyeAndDisconnect(remotePeer, GoodByeReasonCode.IRRELEVANT_NETWORK);
|
|
732
|
-
return;
|
|
743
|
+
return false;
|
|
733
744
|
}
|
|
734
745
|
|
|
746
|
+
if (!opts.overwriteExisting && this.connectedPeers.has(remotePeerStr)) {
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// On connection:
|
|
751
|
+
// - Outbound connections: send a STATUS and PING request
|
|
752
|
+
// - Inbound connections: expect to be STATUS'd, schedule STATUS and PING for later
|
|
753
|
+
// NOTE: libp2p may emit two "peer:connect" events: One for inbound, one for outbound
|
|
754
|
+
// If that happens, it's okay. Only the "outbound" connection triggers immediate action
|
|
755
|
+
const now = Date.now();
|
|
735
756
|
const nodeId = computeNodeId(remotePeer);
|
|
736
757
|
const peerData: PeerData = {
|
|
737
758
|
lastReceivedMsgUnixTsMs: direction === "outbound" ? 0 : now,
|
|
@@ -750,14 +771,13 @@ export class PeerManager {
|
|
|
750
771
|
};
|
|
751
772
|
this.connectedPeers.set(remotePeerStr, peerData);
|
|
752
773
|
|
|
753
|
-
if (direction === "outbound") {
|
|
754
|
-
// this.pingAndStatusTimeouts();
|
|
774
|
+
if (direction === "outbound" && opts.triggerHandshakeNow) {
|
|
755
775
|
void this.requestPing(remotePeer);
|
|
756
776
|
void this.requestStatus(remotePeer, this.statusCache.get());
|
|
757
777
|
}
|
|
758
778
|
|
|
759
779
|
this.libp2p.services.identify
|
|
760
|
-
.identify(
|
|
780
|
+
.identify(connection)
|
|
761
781
|
.then((result) => {
|
|
762
782
|
const agentVersion = result.agentVersion;
|
|
763
783
|
if (agentVersion) {
|
|
@@ -766,7 +786,7 @@ export class PeerManager {
|
|
|
766
786
|
}
|
|
767
787
|
})
|
|
768
788
|
.catch((err) => {
|
|
769
|
-
if (
|
|
789
|
+
if (connection.status !== "open") {
|
|
770
790
|
this.logger.debug("Peer disconnected during identify protocol", {
|
|
771
791
|
peerId: remotePeerPrettyStr,
|
|
772
792
|
error: (err as Error).message,
|
|
@@ -775,6 +795,24 @@ export class PeerManager {
|
|
|
775
795
|
this.logger.debug("Error setting agentVersion for the peer", {peerId: remotePeerPrettyStr}, err);
|
|
776
796
|
}
|
|
777
797
|
});
|
|
798
|
+
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* The libp2p Upgrader has successfully upgraded a peer connection on a particular multiaddress
|
|
804
|
+
* This event is routed through the connectionManager
|
|
805
|
+
*
|
|
806
|
+
* Registers a peer as connected. The `direction` parameter determines if the peer is being
|
|
807
|
+
* dialed or connecting to us.
|
|
808
|
+
*/
|
|
809
|
+
private onLibp2pPeerConnect = (evt: CustomEvent<Connection>): void => {
|
|
810
|
+
const {direction, status, remotePeer} = evt.detail;
|
|
811
|
+
this.logger.verbose("peer connected", {peer: prettyPrintPeerId(remotePeer), direction, status});
|
|
812
|
+
// NOTE: The peerConnect event is not emitted here here, but after asserting peer relevance
|
|
813
|
+
this.metrics?.peerConnectedEvent.inc({direction, status});
|
|
814
|
+
|
|
815
|
+
this.trackLibp2pConnection(evt.detail, {overwriteExisting: true, triggerHandshakeNow: true});
|
|
778
816
|
};
|
|
779
817
|
|
|
780
818
|
/**
|
|
@@ -548,7 +548,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
548
548
|
seenTimestampSec,
|
|
549
549
|
}: GossipHandlerParamGeneric<GossipType.data_column_sidecar>) => {
|
|
550
550
|
const {serializedData} = gossipData;
|
|
551
|
-
|
|
551
|
+
// TODO GLOAS: handle gloas.DataColumnSidecar
|
|
552
|
+
const dataColumnSidecar = sszDeserialize(topic, serializedData) as fulu.DataColumnSidecar;
|
|
552
553
|
const dataColumnSlot = dataColumnSidecar.signedBlockHeader.message.slot;
|
|
553
554
|
const index = dataColumnSidecar.index;
|
|
554
555
|
|
|
@@ -821,11 +822,16 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
821
822
|
[GossipType.execution_payload]: async ({
|
|
822
823
|
gossipData,
|
|
823
824
|
topic,
|
|
825
|
+
seenTimestampSec,
|
|
824
826
|
}: GossipHandlerParamGeneric<GossipType.execution_payload>) => {
|
|
825
827
|
const {serializedData} = gossipData;
|
|
826
828
|
const executionPayloadEnvelope = sszDeserialize(topic, serializedData);
|
|
827
829
|
await validateGossipExecutionPayloadEnvelope(chain, executionPayloadEnvelope);
|
|
828
830
|
|
|
831
|
+
const slot = executionPayloadEnvelope.message.slot;
|
|
832
|
+
const delaySec = seenTimestampSec - computeTimeAtSlot(config, slot, chain.genesisTime);
|
|
833
|
+
metrics?.gossipExecutionPayloadEnvelope.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
|
|
834
|
+
|
|
829
835
|
// TODO GLOAS: Handle valid envelope. Need an import flow that calls `processExecutionPayloadEnvelope` and fork choice
|
|
830
836
|
},
|
|
831
837
|
[GossipType.payload_attestation_message]: async ({
|
|
@@ -19,6 +19,7 @@ export async function* onLightClientUpdatesByRange(
|
|
|
19
19
|
assertLightClientServer(chain.lightClientServer);
|
|
20
20
|
|
|
21
21
|
const count = Math.min(MAX_REQUEST_LIGHT_CLIENT_UPDATES, requestBody.count);
|
|
22
|
+
let started = false;
|
|
22
23
|
for (let period = requestBody.startPeriod; period < requestBody.startPeriod + count; period++) {
|
|
23
24
|
try {
|
|
24
25
|
const update = await chain.lightClientServer.getUpdate(period);
|
|
@@ -29,9 +30,13 @@ export async function* onLightClientUpdatesByRange(
|
|
|
29
30
|
data: type.serialize(update),
|
|
30
31
|
boundary,
|
|
31
32
|
};
|
|
33
|
+
started = true;
|
|
32
34
|
} catch (e) {
|
|
33
35
|
if ((e as LightClientServerError).type?.code === LightClientServerErrorCode.RESOURCE_UNAVAILABLE) {
|
|
34
|
-
|
|
36
|
+
// Period not available, if we already started yielding, stop to
|
|
37
|
+
// preserve consecutive order. Otherwise skip leading gaps.
|
|
38
|
+
if (started) return;
|
|
39
|
+
continue;
|
|
35
40
|
}
|
|
36
41
|
throw new ResponseError(RespStatus.SERVER_ERROR, (e as Error).message);
|
|
37
42
|
}
|
package/src/node/nodejs.ts
CHANGED
|
@@ -2,12 +2,11 @@ import {setMaxListeners} from "node:events";
|
|
|
2
2
|
import {PrivateKey} from "@libp2p/interface";
|
|
3
3
|
import {Registry} from "prom-client";
|
|
4
4
|
import {hasher} from "@chainsafe/persistent-merkle-tree";
|
|
5
|
-
import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map";
|
|
6
5
|
import {BeaconApiMethods} from "@lodestar/api/beacon/server";
|
|
7
6
|
import {BeaconConfig} from "@lodestar/config";
|
|
8
7
|
import type {LoggerNode} from "@lodestar/logger/node";
|
|
9
8
|
import {ZERO_HASH_HEX} from "@lodestar/params";
|
|
10
|
-
import {CachedBeaconStateAllForks,
|
|
9
|
+
import {CachedBeaconStateAllForks, PubkeyCache, isExecutionCachedStateType} from "@lodestar/state-transition";
|
|
11
10
|
import {phase0} from "@lodestar/types";
|
|
12
11
|
import {sleep, toRootHex} from "@lodestar/utils";
|
|
13
12
|
import {ProcessShutdownCallback} from "@lodestar/validator";
|
|
@@ -47,8 +46,7 @@ export type BeaconNodeModules = {
|
|
|
47
46
|
export type BeaconNodeInitModules = {
|
|
48
47
|
opts: IBeaconNodeOptions;
|
|
49
48
|
config: BeaconConfig;
|
|
50
|
-
|
|
51
|
-
index2pubkey: Index2PubkeyCache;
|
|
49
|
+
pubkeyCache: PubkeyCache;
|
|
52
50
|
db: IBeaconDb;
|
|
53
51
|
logger: LoggerNode;
|
|
54
52
|
processShutdownCallback: ProcessShutdownCallback;
|
|
@@ -150,8 +148,7 @@ export class BeaconNode {
|
|
|
150
148
|
static async init<T extends BeaconNode = BeaconNode>({
|
|
151
149
|
opts,
|
|
152
150
|
config,
|
|
153
|
-
|
|
154
|
-
index2pubkey,
|
|
151
|
+
pubkeyCache,
|
|
155
152
|
db,
|
|
156
153
|
logger,
|
|
157
154
|
processShutdownCallback,
|
|
@@ -240,8 +237,7 @@ export class BeaconNode {
|
|
|
240
237
|
privateKey,
|
|
241
238
|
config,
|
|
242
239
|
clock,
|
|
243
|
-
|
|
244
|
-
index2pubkey,
|
|
240
|
+
pubkeyCache,
|
|
245
241
|
dataDir,
|
|
246
242
|
db,
|
|
247
243
|
dbName: opts.db.name,
|
|
@@ -364,9 +360,12 @@ export class BeaconNode {
|
|
|
364
360
|
if (this.restApi) await this.restApi.close();
|
|
365
361
|
await this.network.close();
|
|
366
362
|
if (this.metricsServer) await this.metricsServer.close();
|
|
367
|
-
if (this.monitoring) this.monitoring.close();
|
|
363
|
+
if (this.monitoring) await this.monitoring.close();
|
|
368
364
|
await this.chain.persistToDisk();
|
|
369
365
|
await this.chain.close();
|
|
366
|
+
// Abort signal last: close() calls above clear intervals/timeouts so no new
|
|
367
|
+
// operations get scheduled. If we aborted first, a still-pending interval could
|
|
368
|
+
// fire and schedule a new operation after abort, leaving it stuck and delaying shutdown.
|
|
370
369
|
if (this.controller) this.controller.abort();
|
|
371
370
|
await sleep(DELAY_BEFORE_CLOSING_DB_MS);
|
|
372
371
|
await this.db.close();
|
package/src/util/blobs.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
VERSIONED_HASH_VERSION_KZG,
|
|
14
14
|
} from "@lodestar/params";
|
|
15
15
|
import {signedBlockToSignedHeader} from "@lodestar/state-transition";
|
|
16
|
-
import {BeaconBlockBody, SSZTypesFor, SignedBeaconBlock, deneb, fulu, ssz} from "@lodestar/types";
|
|
16
|
+
import {BeaconBlockBody, DataColumnSidecars, SSZTypesFor, SignedBeaconBlock, deneb, fulu, ssz} from "@lodestar/types";
|
|
17
17
|
import {kzg} from "./kzg.js";
|
|
18
18
|
|
|
19
19
|
type VersionHash = Uint8Array;
|
|
@@ -149,7 +149,7 @@ export async function dataColumnMatrixRecovery(
|
|
|
149
149
|
* Reconstruct blobs from a set of data columns, at least 50%+ of all the columns
|
|
150
150
|
* must be provided to allow to reconstruct the full data matrix
|
|
151
151
|
*/
|
|
152
|
-
export async function reconstructBlobs(sidecars:
|
|
152
|
+
export async function reconstructBlobs(sidecars: DataColumnSidecars, indices?: number[]): Promise<deneb.Blobs> {
|
|
153
153
|
if (sidecars.length < NUMBER_OF_COLUMNS / 2) {
|
|
154
154
|
throw Error(
|
|
155
155
|
`Expected at least ${NUMBER_OF_COLUMNS / 2} data columns to reconstruct blobs, received ${sidecars.length}`
|
|
@@ -188,7 +188,7 @@ export async function reconstructBlobs(sidecars: fulu.DataColumnSidecars, indice
|
|
|
188
188
|
* Recover cells for specific blob indices from a set of data columns
|
|
189
189
|
*/
|
|
190
190
|
async function recoverBlobCells(
|
|
191
|
-
partialSidecars:
|
|
191
|
+
partialSidecars: DataColumnSidecars,
|
|
192
192
|
blobIndices: number[]
|
|
193
193
|
): Promise<Map<number, fulu.Cell[]> | null> {
|
|
194
194
|
const columnCount = partialSidecars.length;
|
package/src/util/dataColumns.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {ChainForkConfig} from "@lodestar/config";
|
|
|
4
4
|
import {
|
|
5
5
|
ForkAll,
|
|
6
6
|
ForkName,
|
|
7
|
+
ForkPostDeneb,
|
|
7
8
|
ForkPostFulu,
|
|
8
9
|
ForkPreGloas,
|
|
9
10
|
KZG_COMMITMENTS_GINDEX,
|
|
@@ -15,9 +16,11 @@ import {
|
|
|
15
16
|
BeaconBlockBody,
|
|
16
17
|
ColumnIndex,
|
|
17
18
|
CustodyIndex,
|
|
19
|
+
Root,
|
|
18
20
|
SSZTypesFor,
|
|
19
21
|
SignedBeaconBlock,
|
|
20
22
|
SignedBeaconBlockHeader,
|
|
23
|
+
Slot,
|
|
21
24
|
deneb,
|
|
22
25
|
fulu,
|
|
23
26
|
gloas,
|
|
@@ -269,7 +272,7 @@ export async function getCellsAndProofs(
|
|
|
269
272
|
*/
|
|
270
273
|
export function getBlobKzgCommitments(
|
|
271
274
|
fork: ForkName,
|
|
272
|
-
signedBlock: SignedBeaconBlock<
|
|
275
|
+
signedBlock: SignedBeaconBlock<ForkPostDeneb>
|
|
273
276
|
): deneb.KZGCommitment[] {
|
|
274
277
|
if (isForkPostGloas(fork)) {
|
|
275
278
|
return (signedBlock as gloas.SignedBeaconBlock).message.body.signedExecutionPayloadBid.message.blobKzgCommitments;
|
|
@@ -359,6 +362,39 @@ export function getDataColumnSidecarsFromColumnSidecar(
|
|
|
359
362
|
);
|
|
360
363
|
}
|
|
361
364
|
|
|
365
|
+
/**
|
|
366
|
+
* In Gloas, data column sidecars have a simplified structure with `slot` and `beaconBlockRoot`
|
|
367
|
+
* instead of `signedBlockHeader`, `kzgCommitments`, and `kzgCommitmentsInclusionProof`.
|
|
368
|
+
*/
|
|
369
|
+
export function getDataColumnSidecarsForGloas(
|
|
370
|
+
slot: Slot,
|
|
371
|
+
beaconBlockRoot: Root,
|
|
372
|
+
cellsAndKzgProofs: {cells: Uint8Array[]; proofs: Uint8Array[]}[]
|
|
373
|
+
): gloas.DataColumnSidecars {
|
|
374
|
+
// No need to create data column sidecars if there are no blobs
|
|
375
|
+
if (cellsAndKzgProofs.length === 0) {
|
|
376
|
+
return [];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const sidecars: gloas.DataColumnSidecars = [];
|
|
380
|
+
for (let columnIndex = 0; columnIndex < NUMBER_OF_COLUMNS; columnIndex++) {
|
|
381
|
+
const column: Uint8Array[] = [];
|
|
382
|
+
const kzgProofs: Uint8Array[] = [];
|
|
383
|
+
for (const {cells, proofs} of cellsAndKzgProofs) {
|
|
384
|
+
column.push(cells[columnIndex]);
|
|
385
|
+
kzgProofs.push(proofs[columnIndex]);
|
|
386
|
+
}
|
|
387
|
+
sidecars.push({
|
|
388
|
+
index: columnIndex,
|
|
389
|
+
column,
|
|
390
|
+
kzgProofs,
|
|
391
|
+
slot,
|
|
392
|
+
beaconBlockRoot,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
return sidecars;
|
|
396
|
+
}
|
|
397
|
+
|
|
362
398
|
/**
|
|
363
399
|
* If we receive more than half of NUMBER_OF_COLUMNS (64) we should recover all remaining columns
|
|
364
400
|
*/
|
package/src/util/multifork.ts
CHANGED
|
@@ -9,6 +9,11 @@ import {getSlotFromSignedBeaconBlockSerialized} from "./sszBytes.js";
|
|
|
9
9
|
*/
|
|
10
10
|
const SLOT_BYTE_COUNT = 8;
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* SSZ offset uint32
|
|
14
|
+
*/
|
|
15
|
+
const OFFSET_BYTE_COUNT = 4;
|
|
16
|
+
|
|
12
17
|
/**
|
|
13
18
|
* 8 + 32 = 40
|
|
14
19
|
* ```
|
|
@@ -67,3 +72,43 @@ export function getLightClientHeaderTypeFromBytes(
|
|
|
67
72
|
);
|
|
68
73
|
return config.getPostAltairForkTypes(slot).LightClientHeader;
|
|
69
74
|
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Position of first offset in DataColumnSidecar (after index field)
|
|
78
|
+
*
|
|
79
|
+
* Fulu DataColumnSidecar (6 fields):
|
|
80
|
+
* index: uint64 [fixed - 8 bytes]
|
|
81
|
+
* column: List [variable - 4-byte offset]
|
|
82
|
+
* kzgCommitments: List [variable - 4-byte offset]
|
|
83
|
+
* kzgProofs: List [variable - 4-byte offset]
|
|
84
|
+
* signedBlockHeader: Container [fixed - 208 bytes]
|
|
85
|
+
* kzgCommitmentsInclusionProof: Vector[Bytes32, 4] [fixed - 128 bytes]
|
|
86
|
+
* => First offset value = 8 + 4 + 4 + 4 + 208 + 128 = 356
|
|
87
|
+
*
|
|
88
|
+
* Gloas DataColumnSidecar (5 fields):
|
|
89
|
+
* index: uint64 [fixed - 8 bytes]
|
|
90
|
+
* column: List [variable - 4-byte offset]
|
|
91
|
+
* kzgProofs: List [variable - 4-byte offset]
|
|
92
|
+
* slot: uint64 [fixed - 8 bytes]
|
|
93
|
+
* beaconBlockRoot: Bytes32 [fixed - 32 bytes]
|
|
94
|
+
* => First offset value = 8 + 4 + 4 + 8 + 32 = 56
|
|
95
|
+
*/
|
|
96
|
+
const FIRST_OFFSET_POSITION_IN_DATA_COLUMN_SIDECAR = 8;
|
|
97
|
+
const GLOAS_DATA_COLUMN_SIDECAR_FIRST_OFFSET = 56;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Determines if DataColumnSidecar bytes are from Gloas fork by checking the SSZ offset structure.
|
|
101
|
+
*
|
|
102
|
+
* The first offset (bytes 8-12) indicates where variable-size data begins:
|
|
103
|
+
* - Gloas: 56 (small fixed section)
|
|
104
|
+
* - Fulu: 356
|
|
105
|
+
*/
|
|
106
|
+
export function isGloasDataColumnSidecarBytes(bytes: Uint8Array): boolean {
|
|
107
|
+
const firstOffset = bytesToInt(
|
|
108
|
+
bytes.subarray(
|
|
109
|
+
FIRST_OFFSET_POSITION_IN_DATA_COLUMN_SIDECAR,
|
|
110
|
+
FIRST_OFFSET_POSITION_IN_DATA_COLUMN_SIDECAR + OFFSET_BYTE_COUNT
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
return firstOffset === GLOAS_DATA_COLUMN_SIDECAR_FIRST_OFFSET;
|
|
114
|
+
}
|
|
@@ -14,6 +14,11 @@ export class SerializedCache {
|
|
|
14
14
|
this.map.set(obj, serialized);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Replace the internal WeakMap to force GC of all cached entries.
|
|
19
|
+
* Must only be called after all DB writes that may read from this cache have completed,
|
|
20
|
+
* otherwise cached serialized bytes will be unavailable and data will be re-serialized unnecessarily.
|
|
21
|
+
*/
|
|
17
22
|
clear(): void {
|
|
18
23
|
this.map = new WeakMap();
|
|
19
24
|
}
|