@peerbit/shared-log 13.2.27 → 13.2.29

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/src/index.ts CHANGED
@@ -1494,8 +1494,8 @@ const createRepairFrontierByMode = () =>
1494
1494
  >(REPAIR_DISPATCH_MODES.map((mode) => [mode, new Map()]));
1495
1495
 
1496
1496
  const createRepairActiveTargetsByMode = () =>
1497
- new Map<RepairDispatchMode, Set<string>>(
1498
- REPAIR_DISPATCH_MODES.map((mode) => [mode, new Set()]),
1497
+ new Map<RepairDispatchMode, Map<string, object>>(
1498
+ REPAIR_DISPATCH_MODES.map((mode) => [mode, new Map()]),
1499
1499
  );
1500
1500
 
1501
1501
  const createRepairFrontierBypassKnownPeersByMode = () =>
@@ -3246,7 +3246,7 @@ export class SharedLog<
3246
3246
  >;
3247
3247
  private _repairFrontierActiveTargetsByMode!: Map<
3248
3248
  RepairDispatchMode,
3249
- Set<string>
3249
+ Map<string, object>
3250
3250
  >;
3251
3251
  private _repairFrontierBypassKnownPeersByMode!: Map<
3252
3252
  RepairDispatchMode,
@@ -7821,7 +7821,11 @@ export class SharedLog<
7821
7821
  ) {
7822
7822
  return;
7823
7823
  }
7824
- activeTargets.add(target);
7824
+ const runnerToken = {};
7825
+ activeTargets.set(target, runnerToken);
7826
+ const isCurrentRunner = () =>
7827
+ activeTargets.get(target) === runnerToken &&
7828
+ this.isRepairLifecycleActive(repairLifecycleController);
7825
7829
  const retrySchedule = resolveRepairRetrySchedule(
7826
7830
  mode,
7827
7831
  retryScheduleMs,
@@ -7840,12 +7844,12 @@ export class SharedLog<
7840
7844
  let attemptIndex = 0;
7841
7845
  try {
7842
7846
  for (;;) {
7843
- if (!this.isRepairLifecycleActive(repairLifecycleController)) {
7847
+ if (!isCurrentRunner()) {
7844
7848
  return;
7845
7849
  }
7846
7850
  const pending = this._repairFrontierByMode.get(mode)?.get(target);
7847
7851
  if (!pending || pending.size === 0) {
7848
- if (!this.isRepairLifecycleActive(repairLifecycleController)) {
7852
+ if (!isCurrentRunner()) {
7849
7853
  return;
7850
7854
  }
7851
7855
  this._repairFrontierBypassKnownPeersByMode
@@ -7872,7 +7876,7 @@ export class SharedLog<
7872
7876
  continue;
7873
7877
  }
7874
7878
 
7875
- if (!this.isRepairLifecycleActive(repairLifecycleController)) {
7879
+ if (!isCurrentRunner()) {
7876
7880
  return;
7877
7881
  }
7878
7882
  await this.sendMaybeMissingEntriesNow(
@@ -7889,7 +7893,7 @@ export class SharedLog<
7889
7893
  },
7890
7894
  repairLifecycleController,
7891
7895
  );
7892
- if (!this.isRepairLifecycleActive(repairLifecycleController)) {
7896
+ if (!isCurrentRunner()) {
7893
7897
  return;
7894
7898
  }
7895
7899
 
@@ -7911,21 +7915,25 @@ export class SharedLog<
7911
7915
  }
7912
7916
  }
7913
7917
  } finally {
7914
- activeTargets.delete(target);
7915
- if (
7916
- this.isRepairLifecycleActive(repairLifecycleController) &&
7917
- (this._repairFrontierByMode.get(mode)?.get(target)?.size || 0) > 0
7918
- ) {
7919
- this.ensureRepairFrontierRunner(
7920
- mode,
7921
- target,
7922
- retryScheduleMs,
7923
- repairLifecycleController,
7924
- );
7918
+ if (activeTargets.get(target) === runnerToken) {
7919
+ activeTargets.delete(target);
7920
+ if (
7921
+ this.isRepairLifecycleActive(repairLifecycleController) &&
7922
+ (this._repairFrontierByMode.get(mode)?.get(target)?.size || 0) > 0
7923
+ ) {
7924
+ this.ensureRepairFrontierRunner(
7925
+ mode,
7926
+ target,
7927
+ retryScheduleMs,
7928
+ repairLifecycleController,
7929
+ );
7930
+ }
7925
7931
  }
7926
7932
  }
7927
7933
  })().catch((error: any) => {
7928
- activeTargets.delete(target);
7934
+ if (activeTargets.get(target) === runnerToken) {
7935
+ activeTargets.delete(target);
7936
+ }
7929
7937
  if (this.isRepairLifecycleActive(repairLifecycleController)) {
7930
7938
  logger.error(error);
7931
7939
  }
@@ -16778,6 +16786,339 @@ export class SharedLog<
16778
16786
  });
16779
16787
  }
16780
16788
 
16789
+ /**
16790
+ * Normalize a raw exchange-heads receive into the regular exchange message
16791
+ * consumed by the rest of the receive path. An undefined result means the
16792
+ * message was fully handled (all heads were already present or the native
16793
+ * receive plan dropped every head).
16794
+ *
16795
+ * This helper intentionally runs inside `onMessage`'s shared try/finally
16796
+ * envelope so receive errors keep their existing classification and a
16797
+ * wire-backed message keeps its single outer stash-release boundary.
16798
+ */
16799
+ private async materializeRawReceiveMessage(
16800
+ msg: RawExchangeHeadsMessage,
16801
+ properties: {
16802
+ from: PublicSignKey;
16803
+ stashBackedRawMessage?: StashBackedRawExchangeHeadsMessage;
16804
+ syncProfile?: SyncProfileFn;
16805
+ receiveOwnershipRevision: number;
16806
+ },
16807
+ ): Promise<
16808
+ | {
16809
+ message: ExchangeHeadsMessage<any>;
16810
+ preparedSelection: NativeBackboneRawReceiveSelectionPlan | undefined;
16811
+ }
16812
+ | undefined
16813
+ > {
16814
+ const {
16815
+ from: rawFrom,
16816
+ stashBackedRawMessage,
16817
+ syncProfile,
16818
+ receiveOwnershipRevision,
16819
+ } = properties;
16820
+ const fromIsSelf = rawFrom.equals(this.node.identity.publicKey);
16821
+ if (syncProfile && !stashBackedRawMessage) {
16822
+ // Per-message JS-side entry decode: the heads were
16823
+ // borsh-decoded in TS (regular RPC path) instead of being
16824
+ // resolved from the native wire stash. Zero on the fused
16825
+ // hot path.
16826
+ emitSyncProfileEvent(syncProfile, {
16827
+ name: "sharedLog.rawReceive.jsEntryDecode",
16828
+ component: "shared-log",
16829
+ entries: msg.heads.length,
16830
+ messages: 1,
16831
+ });
16832
+ }
16833
+ const rawExistingStartedAt = syncProfileStart(syncProfile);
16834
+ const rawExistingHashes = await this.log.hasMany(
16835
+ msg.heads.map((head) => head.hash),
16836
+ );
16837
+ if (syncProfile) {
16838
+ emitSyncProfileDuration(syncProfile, rawExistingStartedAt, {
16839
+ name: "sharedLog.rawReceive.existingHeads",
16840
+ component: "shared-log",
16841
+ entries: msg.heads.length,
16842
+ messages: 1,
16843
+ });
16844
+ }
16845
+ const rawMissingHeads = [];
16846
+ const rawConfirmedHashes = new Set<string>();
16847
+ let rawMissingBytes = 0;
16848
+ for (const head of msg.heads) {
16849
+ if (rawExistingHashes.has(head.hash)) {
16850
+ rawConfirmedHashes.add(head.hash);
16851
+ } else {
16852
+ rawMissingHeads.push(head);
16853
+ rawMissingBytes += getRawExchangeHeadByteLength(head);
16854
+ }
16855
+ }
16856
+ if (rawConfirmedHashes.size > 0 && !fromIsSelf) {
16857
+ const rawConfirmStartedAt = syncProfileStart(syncProfile);
16858
+ this.markEntriesKnownByPeer(rawConfirmedHashes, rawFrom.hashcode());
16859
+ await this.sendRepairConfirmation(rawFrom, rawConfirmedHashes);
16860
+ if (syncProfile) {
16861
+ emitSyncProfileDuration(syncProfile, rawConfirmStartedAt, {
16862
+ name: "sharedLog.rawReceive.confirmExisting",
16863
+ component: "shared-log",
16864
+ entries: rawConfirmedHashes.size,
16865
+ messages: 1,
16866
+ });
16867
+ }
16868
+ }
16869
+ if (rawMissingHeads.length === 0) {
16870
+ return undefined;
16871
+ }
16872
+ const rawIsRepairHint =
16873
+ (msg.reserved[0] & EXCHANGE_HEADS_REPAIR_HINT) !== 0;
16874
+ const rawPrepareVerifySetting =
16875
+ this._logProperties?.sync?.rawExchangeHeadsVerifySignaturesDuringPrepare;
16876
+ // A program-level canAppend hook must observe every entry before
16877
+ // it commits, so the native join commit (which validates and
16878
+ // commits entirely in wasm) is not used for programs that
16879
+ // register one; those joins run through the lower-log batch
16880
+ // join where the hook fires per entry.
16881
+ const programCanAppend = !!this._logProperties?.canAppend;
16882
+ const canVerifyPreparedRawReceiveOnCommit =
16883
+ !programCanAppend &&
16884
+ !!this._nativeBackbone?.graph.commitVerifiedPreparedRawReceiveJoinBatch;
16885
+ const canDeferRawReceiveVerificationUntilNativeSelection =
16886
+ !rawIsRepairHint &&
16887
+ !!this._nativeBackbone?.verifyPreparedRawReceiveEntries &&
16888
+ !this._isReplicating &&
16889
+ !this.keep &&
16890
+ !this.closed &&
16891
+ !!this.syncronizer.onReceivedEntryHashes &&
16892
+ rawMissingHeads.every((head) => head.gidRefrences.length === 0);
16893
+ const verifyNativeBackboneSignaturesDuringPrepare =
16894
+ rawPrepareVerifySetting === true ||
16895
+ (rawPrepareVerifySetting !== false &&
16896
+ (canDeferRawReceiveVerificationUntilNativeSelection ||
16897
+ (this._isReplicating &&
16898
+ !rawIsRepairHint &&
16899
+ !canVerifyPreparedRawReceiveOnCommit)));
16900
+ const deferNativeBackboneSignatureVerificationUntilSelection =
16901
+ verifyNativeBackboneSignaturesDuringPrepare &&
16902
+ canDeferRawReceiveVerificationUntilNativeSelection;
16903
+ const deferNativeBackboneSignatureVerificationUntilCommit =
16904
+ deferNativeBackboneSignatureVerificationUntilSelection &&
16905
+ !programCanAppend &&
16906
+ !!this._nativeBackbone?.graph.commitVerifiedPreparedRawReceiveJoinBatch;
16907
+ let rawPreparedReceiveSelectionValue:
16908
+ | NativeBackboneRawReceiveSelectionPlan
16909
+ | undefined;
16910
+ let rawPreparedReceiveSelection:
16911
+ | Promise<NativeBackboneRawReceiveSelectionPlan | undefined>
16912
+ | undefined;
16913
+ const getRawPreparedReceiveSelection = async (
16914
+ heads: RawEntryWithRefs[],
16915
+ hashes: string[],
16916
+ ) => {
16917
+ if (rawPreparedReceiveSelectionValue) {
16918
+ return rawPreparedReceiveSelectionValue;
16919
+ }
16920
+ rawPreparedReceiveSelection ??=
16921
+ this.planNativePreparedRawReceiveSelection({
16922
+ heads,
16923
+ hashes,
16924
+ from: rawFrom,
16925
+ });
16926
+ rawPreparedReceiveSelectionValue = await rawPreparedReceiveSelection;
16927
+ return rawPreparedReceiveSelectionValue;
16928
+ };
16929
+ // Receive fusion: when this message was resolved from the wire
16930
+ // stash, the prepared receive reads entry block bytes straight
16931
+ // out of wasm memory (indexed into the stashed frame) instead
16932
+ // of copying a JS blocks array across the boundary.
16933
+ const rawStashIndexes = stashBackedRawMessage
16934
+ ? getRawExchangeHeadStashIndexes(rawMissingHeads)
16935
+ : undefined;
16936
+ const prepareNativeBackboneExpectedColumns =
16937
+ stashBackedRawMessage && rawStashIndexes
16938
+ ? ({
16939
+ hashes,
16940
+ verifySignatures,
16941
+ }: {
16942
+ hashes: string[];
16943
+ verifySignatures: boolean;
16944
+ }) => {
16945
+ const backbone = this._nativeBackbone;
16946
+ const wireSession = this._wireSyncSession;
16947
+ if (!backbone || !wireSession) {
16948
+ return undefined;
16949
+ }
16950
+ try {
16951
+ return backbone.prepareStashedRawReceiveExpectedColumnsBatch(
16952
+ wireSession,
16953
+ stashBackedRawMessage.messageId,
16954
+ rawStashIndexes,
16955
+ hashes,
16956
+ { verifySignatures },
16957
+ );
16958
+ } catch {
16959
+ return undefined;
16960
+ }
16961
+ }
16962
+ : undefined;
16963
+ const prepareNativeBackboneExpectedColumnsAndSelection = rawIsRepairHint
16964
+ ? undefined
16965
+ : async ({
16966
+ blocks,
16967
+ hashes,
16968
+ verifySignatures,
16969
+ }: {
16970
+ blocks: () => Uint8Array[];
16971
+ hashes: string[];
16972
+ verifySignatures: boolean;
16973
+ }) => {
16974
+ if (
16975
+ verifySignatures ||
16976
+ !canDeferRawReceiveVerificationUntilNativeSelection
16977
+ ) {
16978
+ return undefined;
16979
+ }
16980
+ try {
16981
+ const replicaOptions = {
16982
+ minReplicas: this.replicas.min?.getValue(this) || 1,
16983
+ maxReplicas: this.replicas.max?.getValue(this),
16984
+ };
16985
+ const leaderSelectionContext =
16986
+ await this.createLeaderSelectionContext();
16987
+ const prepareOptions = {
16988
+ verifySignatures: false as const,
16989
+ ...replicaOptions,
16990
+ leaderOptions: this.createNativeLeaderOptions(
16991
+ leaderSelectionContext,
16992
+ ),
16993
+ fromHash: rawFrom.hashcode(),
16994
+ };
16995
+ let prepared:
16996
+ | ReturnType<
16997
+ NativePeerbitBackbone["prepareRawReceiveExpectedColumnsAndSelectionBatch"]
16998
+ >
16999
+ | undefined;
17000
+ const wireSession = this._wireSyncSession;
17001
+ if (
17002
+ stashBackedRawMessage &&
17003
+ rawStashIndexes &&
17004
+ wireSession &&
17005
+ this._nativeBackbone
17006
+ ) {
17007
+ prepared =
17008
+ this._nativeBackbone.prepareStashedRawReceiveExpectedColumnsAndSelectionBatch(
17009
+ wireSession,
17010
+ stashBackedRawMessage.messageId,
17011
+ rawStashIndexes,
17012
+ hashes,
17013
+ prepareOptions,
17014
+ );
17015
+ }
17016
+ if (
17017
+ !prepared &&
17018
+ this._nativeBackbone
17019
+ ?.prepareRawReceiveExpectedColumnsAndSelectionBatch
17020
+ ) {
17021
+ prepared =
17022
+ this._nativeBackbone.prepareRawReceiveExpectedColumnsAndSelectionBatch(
17023
+ blocks(),
17024
+ hashes,
17025
+ prepareOptions,
17026
+ );
17027
+ }
17028
+ if (!prepared) {
17029
+ return undefined;
17030
+ }
17031
+ rawPreparedReceiveSelectionValue = prepared.selection;
17032
+ rawPreparedReceiveSelection = Promise.resolve(
17033
+ rawPreparedReceiveSelectionValue,
17034
+ );
17035
+ return { columns: prepared.columns };
17036
+ } catch {
17037
+ this.throwIfReplicationOwnershipPoisoned();
17038
+ return undefined;
17039
+ }
17040
+ };
17041
+ const rawMaterializeStartedAt = syncProfileStart(syncProfile);
17042
+ const materializedRawMessage =
17043
+ await materializeVerifiedRawExchangeHeadsMessage(
17044
+ new RawExchangeHeadsMessage({
17045
+ heads: rawMissingHeads,
17046
+ reserved: msg.reserved,
17047
+ }),
17048
+ this.log,
17049
+ syncProfile,
17050
+ {
17051
+ nativeBackbone: this._nativeBackbone,
17052
+ verifyNativeBackboneSignaturesDuringPrepare:
17053
+ verifyNativeBackboneSignaturesDuringPrepare,
17054
+ deferNativeBackboneSignatureVerificationUntilSelection:
17055
+ deferNativeBackboneSignatureVerificationUntilSelection,
17056
+ deferNativeBackboneSignatureVerificationUntilCommit:
17057
+ deferNativeBackboneSignatureVerificationUntilCommit,
17058
+ prepareNativeBackboneExpectedColumnsAndSelection:
17059
+ prepareNativeBackboneExpectedColumnsAndSelection,
17060
+ prepareNativeBackboneExpectedColumns:
17061
+ prepareNativeBackboneExpectedColumns,
17062
+ tryPreparedRawReceiveFastDrop: rawIsRepairHint
17063
+ ? undefined
17064
+ : async ({ heads, hashes }) =>
17065
+ this.tryFastDropPreparedRawReceive({
17066
+ heads,
17067
+ hashes,
17068
+ from: rawFrom,
17069
+ fromIsSelf,
17070
+ syncProfile,
17071
+ selection: await getRawPreparedReceiveSelection(
17072
+ heads,
17073
+ hashes,
17074
+ ),
17075
+ receiveOwnershipRevision,
17076
+ }),
17077
+ selectPreparedRawReceiveHashes: rawIsRepairHint
17078
+ ? undefined
17079
+ : async ({ heads, hashes }) =>
17080
+ this.selectNativePreparedRawReceiveHashes({
17081
+ heads,
17082
+ hashes,
17083
+ from: rawFrom,
17084
+ fromIsSelf,
17085
+ syncProfile,
17086
+ selection: await getRawPreparedReceiveSelection(
17087
+ heads,
17088
+ hashes,
17089
+ ),
17090
+ receiveOwnershipRevision,
17091
+ }),
17092
+ },
17093
+ );
17094
+ if (materializedRawMessage === undefined) {
17095
+ if (syncProfile) {
17096
+ emitSyncProfileDuration(syncProfile, rawMaterializeStartedAt, {
17097
+ name: "sharedLog.rawReceive.materialize",
17098
+ component: "shared-log",
17099
+ entries: rawMissingHeads.length,
17100
+ bytes: rawMissingBytes,
17101
+ messages: 1,
17102
+ details: { nativeFastDropEarly: true },
17103
+ });
17104
+ }
17105
+ return undefined;
17106
+ }
17107
+ if (syncProfile) {
17108
+ emitSyncProfileDuration(syncProfile, rawMaterializeStartedAt, {
17109
+ name: "sharedLog.rawReceive.materialize",
17110
+ component: "shared-log",
17111
+ entries: rawMissingHeads.length,
17112
+ bytes: rawMissingBytes,
17113
+ messages: 1,
17114
+ });
17115
+ }
17116
+ return {
17117
+ message: materializedRawMessage,
17118
+ preparedSelection: rawPreparedReceiveSelectionValue,
17119
+ };
17120
+ }
17121
+
16781
17122
  // Callback for receiving a message from the network
16782
17123
  async onMessage(
16783
17124
  msg: TransportMessage,
@@ -16855,307 +17196,23 @@ export class SharedLog<
16855
17196
  | NativeBackboneRawReceiveSelectionPlan
16856
17197
  | undefined;
16857
17198
  if (msg instanceof RawExchangeHeadsMessage) {
16858
- const rawFrom = context.from!;
16859
- const fromIsSelf = rawFrom.equals(this.node.identity.publicKey);
16860
- if (syncProfile && !stashBackedRawMessage) {
16861
- // Per-message JS-side entry decode: the heads were
16862
- // borsh-decoded in TS (regular RPC path) instead of being
16863
- // resolved from the native wire stash. Zero on the fused
16864
- // hot path.
16865
- emitSyncProfileEvent(syncProfile, {
16866
- name: "sharedLog.rawReceive.jsEntryDecode",
16867
- component: "shared-log",
16868
- entries: msg.heads.length,
16869
- messages: 1,
16870
- });
16871
- }
16872
- const rawExistingStartedAt = syncProfileStart(syncProfile);
16873
- const rawExistingHashes = await this.log.hasMany(
16874
- msg.heads.map((head) => head.hash),
16875
- );
16876
- if (syncProfile) {
16877
- emitSyncProfileDuration(syncProfile, rawExistingStartedAt, {
16878
- name: "sharedLog.rawReceive.existingHeads",
16879
- component: "shared-log",
16880
- entries: msg.heads.length,
16881
- messages: 1,
16882
- });
16883
- }
16884
- const rawMissingHeads = [];
16885
- const rawConfirmedHashes = new Set<string>();
16886
- let rawMissingBytes = 0;
16887
- for (const head of msg.heads) {
16888
- if (rawExistingHashes.has(head.hash)) {
16889
- rawConfirmedHashes.add(head.hash);
16890
- } else {
16891
- rawMissingHeads.push(head);
16892
- rawMissingBytes += getRawExchangeHeadByteLength(head);
16893
- }
16894
- }
16895
- if (rawConfirmedHashes.size > 0 && !fromIsSelf) {
16896
- const rawConfirmStartedAt = syncProfileStart(syncProfile);
16897
- this.markEntriesKnownByPeer(rawConfirmedHashes, rawFrom.hashcode());
16898
- await this.sendRepairConfirmation(rawFrom, rawConfirmedHashes);
16899
- if (syncProfile) {
16900
- emitSyncProfileDuration(syncProfile, rawConfirmStartedAt, {
16901
- name: "sharedLog.rawReceive.confirmExisting",
16902
- component: "shared-log",
16903
- entries: rawConfirmedHashes.size,
16904
- messages: 1,
16905
- });
16906
- }
16907
- }
16908
- if (rawMissingHeads.length === 0) {
16909
- return;
16910
- }
16911
- const rawIsRepairHint =
16912
- (msg.reserved[0] & EXCHANGE_HEADS_REPAIR_HINT) !== 0;
16913
- const rawPrepareVerifySetting =
16914
- this._logProperties?.sync
16915
- ?.rawExchangeHeadsVerifySignaturesDuringPrepare;
16916
- // A program-level canAppend hook must observe every entry before
16917
- // it commits, so the native join commit (which validates and
16918
- // commits entirely in wasm) is not used for programs that
16919
- // register one; those joins run through the lower-log batch
16920
- // join where the hook fires per entry.
16921
- const programCanAppend = !!this._logProperties?.canAppend;
16922
- const canVerifyPreparedRawReceiveOnCommit =
16923
- !programCanAppend &&
16924
- !!this._nativeBackbone?.graph
16925
- .commitVerifiedPreparedRawReceiveJoinBatch;
16926
- const canDeferRawReceiveVerificationUntilNativeSelection =
16927
- !rawIsRepairHint &&
16928
- !!this._nativeBackbone?.verifyPreparedRawReceiveEntries &&
16929
- !this._isReplicating &&
16930
- !this.keep &&
16931
- !this.closed &&
16932
- !!this.syncronizer.onReceivedEntryHashes &&
16933
- rawMissingHeads.every((head) => head.gidRefrences.length === 0);
16934
- const verifyNativeBackboneSignaturesDuringPrepare =
16935
- rawPrepareVerifySetting === true ||
16936
- (rawPrepareVerifySetting !== false &&
16937
- (canDeferRawReceiveVerificationUntilNativeSelection ||
16938
- (this._isReplicating &&
16939
- !rawIsRepairHint &&
16940
- !canVerifyPreparedRawReceiveOnCommit)));
16941
- const deferNativeBackboneSignatureVerificationUntilSelection =
16942
- verifyNativeBackboneSignaturesDuringPrepare &&
16943
- canDeferRawReceiveVerificationUntilNativeSelection;
16944
- const deferNativeBackboneSignatureVerificationUntilCommit =
16945
- deferNativeBackboneSignatureVerificationUntilSelection &&
16946
- !programCanAppend &&
16947
- !!this._nativeBackbone?.graph
16948
- .commitVerifiedPreparedRawReceiveJoinBatch;
16949
- let rawPreparedReceiveSelection:
16950
- | Promise<NativeBackboneRawReceiveSelectionPlan | undefined>
16951
- | undefined;
16952
- const getRawPreparedReceiveSelection = async (
16953
- heads: RawEntryWithRefs[],
16954
- hashes: string[],
16955
- ) => {
16956
- if (rawPreparedReceiveSelectionValue) {
16957
- return rawPreparedReceiveSelectionValue;
16958
- }
16959
- rawPreparedReceiveSelection ??=
16960
- this.planNativePreparedRawReceiveSelection({
16961
- heads,
16962
- hashes,
16963
- from: rawFrom,
16964
- });
16965
- rawPreparedReceiveSelectionValue = await rawPreparedReceiveSelection;
16966
- return rawPreparedReceiveSelectionValue;
16967
- };
16968
- // Receive fusion: when this message was resolved from the wire
16969
- // stash, the prepared receive reads entry block bytes straight
16970
- // out of wasm memory (indexed into the stashed frame) instead
16971
- // of copying a JS blocks array across the boundary.
16972
- const rawStashIndexes = stashBackedRawMessage
16973
- ? getRawExchangeHeadStashIndexes(rawMissingHeads)
16974
- : undefined;
16975
- const prepareNativeBackboneExpectedColumns =
16976
- stashBackedRawMessage && rawStashIndexes
16977
- ? ({
16978
- hashes,
16979
- verifySignatures,
16980
- }: {
16981
- hashes: string[];
16982
- verifySignatures: boolean;
16983
- }) => {
16984
- const backbone = this._nativeBackbone;
16985
- const wireSession = this._wireSyncSession;
16986
- if (!backbone || !wireSession) {
16987
- return undefined;
16988
- }
16989
- try {
16990
- return backbone.prepareStashedRawReceiveExpectedColumnsBatch(
16991
- wireSession,
16992
- stashBackedRawMessage.messageId,
16993
- rawStashIndexes,
16994
- hashes,
16995
- { verifySignatures },
16996
- );
16997
- } catch {
16998
- return undefined;
16999
- }
17000
- }
17001
- : undefined;
17002
- const prepareNativeBackboneExpectedColumnsAndSelection = rawIsRepairHint
17003
- ? undefined
17004
- : async ({
17005
- blocks,
17006
- hashes,
17007
- verifySignatures,
17008
- }: {
17009
- blocks: () => Uint8Array[];
17010
- hashes: string[];
17011
- verifySignatures: boolean;
17012
- }) => {
17013
- if (
17014
- verifySignatures ||
17015
- !canDeferRawReceiveVerificationUntilNativeSelection
17016
- ) {
17017
- return undefined;
17018
- }
17019
- try {
17020
- const replicaOptions = {
17021
- minReplicas: this.replicas.min?.getValue(this) || 1,
17022
- maxReplicas: this.replicas.max?.getValue(this),
17023
- };
17024
- const leaderSelectionContext =
17025
- await this.createLeaderSelectionContext();
17026
- const prepareOptions = {
17027
- verifySignatures: false as const,
17028
- ...replicaOptions,
17029
- leaderOptions: this.createNativeLeaderOptions(
17030
- leaderSelectionContext,
17031
- ),
17032
- fromHash: rawFrom.hashcode(),
17033
- };
17034
- let prepared:
17035
- | ReturnType<
17036
- NativePeerbitBackbone["prepareRawReceiveExpectedColumnsAndSelectionBatch"]
17037
- >
17038
- | undefined;
17039
- const wireSession = this._wireSyncSession;
17040
- if (
17041
- stashBackedRawMessage &&
17042
- rawStashIndexes &&
17043
- wireSession &&
17044
- this._nativeBackbone
17045
- ) {
17046
- prepared =
17047
- this._nativeBackbone.prepareStashedRawReceiveExpectedColumnsAndSelectionBatch(
17048
- wireSession,
17049
- stashBackedRawMessage.messageId,
17050
- rawStashIndexes,
17051
- hashes,
17052
- prepareOptions,
17053
- );
17054
- }
17055
- if (
17056
- !prepared &&
17057
- this._nativeBackbone
17058
- ?.prepareRawReceiveExpectedColumnsAndSelectionBatch
17059
- ) {
17060
- prepared =
17061
- this._nativeBackbone.prepareRawReceiveExpectedColumnsAndSelectionBatch(
17062
- blocks(),
17063
- hashes,
17064
- prepareOptions,
17065
- );
17066
- }
17067
- if (!prepared) {
17068
- return undefined;
17069
- }
17070
- rawPreparedReceiveSelectionValue = prepared.selection;
17071
- rawPreparedReceiveSelection = Promise.resolve(
17072
- rawPreparedReceiveSelectionValue,
17073
- );
17074
- return { columns: prepared.columns };
17075
- } catch {
17076
- this.throwIfReplicationOwnershipPoisoned();
17077
- return undefined;
17078
- }
17079
- };
17080
- const rawMaterializeStartedAt = syncProfileStart(syncProfile);
17081
- const materializedRawMessage =
17082
- await materializeVerifiedRawExchangeHeadsMessage(
17083
- new RawExchangeHeadsMessage({
17084
- heads: rawMissingHeads,
17085
- reserved: msg.reserved,
17086
- }),
17087
- this.log,
17199
+ const materializedRawReceive = await this.materializeRawReceiveMessage(
17200
+ msg,
17201
+ {
17202
+ from: context.from,
17203
+ stashBackedRawMessage,
17088
17204
  syncProfile,
17089
- {
17090
- nativeBackbone: this._nativeBackbone,
17091
- verifyNativeBackboneSignaturesDuringPrepare:
17092
- verifyNativeBackboneSignaturesDuringPrepare,
17093
- deferNativeBackboneSignatureVerificationUntilSelection:
17094
- deferNativeBackboneSignatureVerificationUntilSelection,
17095
- deferNativeBackboneSignatureVerificationUntilCommit:
17096
- deferNativeBackboneSignatureVerificationUntilCommit,
17097
- prepareNativeBackboneExpectedColumnsAndSelection:
17098
- prepareNativeBackboneExpectedColumnsAndSelection,
17099
- prepareNativeBackboneExpectedColumns:
17100
- prepareNativeBackboneExpectedColumns,
17101
- tryPreparedRawReceiveFastDrop: rawIsRepairHint
17102
- ? undefined
17103
- : async ({ heads, hashes }) =>
17104
- this.tryFastDropPreparedRawReceive({
17105
- heads,
17106
- hashes,
17107
- from: rawFrom,
17108
- fromIsSelf,
17109
- syncProfile,
17110
- selection: await getRawPreparedReceiveSelection(
17111
- heads,
17112
- hashes,
17113
- ),
17114
- receiveOwnershipRevision,
17115
- }),
17116
- selectPreparedRawReceiveHashes: rawIsRepairHint
17117
- ? undefined
17118
- : async ({ heads, hashes }) =>
17119
- this.selectNativePreparedRawReceiveHashes({
17120
- heads,
17121
- hashes,
17122
- from: rawFrom,
17123
- fromIsSelf,
17124
- syncProfile,
17125
- selection: await getRawPreparedReceiveSelection(
17126
- heads,
17127
- hashes,
17128
- ),
17129
- receiveOwnershipRevision,
17130
- }),
17131
- },
17132
- );
17133
- if (materializedRawMessage === undefined) {
17134
- if (syncProfile) {
17135
- emitSyncProfileDuration(syncProfile, rawMaterializeStartedAt, {
17136
- name: "sharedLog.rawReceive.materialize",
17137
- component: "shared-log",
17138
- entries: rawMissingHeads.length,
17139
- bytes: rawMissingBytes,
17140
- messages: 1,
17141
- details: { nativeFastDropEarly: true },
17142
- });
17143
- }
17205
+ receiveOwnershipRevision,
17206
+ },
17207
+ );
17208
+ if (materializedRawReceive === undefined) {
17144
17209
  return;
17145
17210
  }
17146
- msg = materializedRawMessage;
17211
+ msg = materializedRawReceive.message;
17212
+ rawPreparedReceiveSelectionValue =
17213
+ materializedRawReceive.preparedSelection;
17147
17214
  rawMaterializedKnownMissing = true;
17148
- if (syncProfile) {
17149
- emitSyncProfileDuration(syncProfile, rawMaterializeStartedAt, {
17150
- name: "sharedLog.rawReceive.materialize",
17151
- component: "shared-log",
17152
- entries: rawMissingHeads.length,
17153
- bytes: rawMissingBytes,
17154
- messages: 1,
17155
- });
17156
- }
17157
17215
  }
17158
-
17159
17216
  if (msg instanceof ExchangeHeadsMessage) {
17160
17217
  /**
17161
17218
  * I have received heads from someone else.