beignet 0.38.0 → 0.38.1

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.
@@ -22248,32 +22248,71 @@ class LightningNode extends typed_emitter_1.TypedEmitter {
22248
22248
  if (!destination)
22249
22249
  return null;
22250
22250
  const sourceBuf = Buffer.from(this.nodeId, 'hex');
22251
+ const finalCltvExpiry = decoded.minFinalCltvExpiry || types_5.DEFAULT_MIN_FINAL_CLTV_EXPIRY;
22252
+ const localChannels = this.getLocalChannelEdges();
22251
22253
  // Try to find a route
22252
- const route = (0, pathfinding_1.findRoute)(this.graph, sourceBuf, destination, amountMsat, decoded.minFinalCltvExpiry || types_5.DEFAULT_MIN_FINAL_CLTV_EXPIRY, 20, // maxHops
22254
+ let route = (0, pathfinding_1.findRoute)(this.graph, sourceBuf, destination, amountMsat, finalCltvExpiry, 20, // maxHops
22253
22255
  undefined, // excludedChannels
22254
22256
  this.missionControl, undefined, // maxCltvExpiry
22255
22257
  decoded.routingHints, undefined, // currentTimestamp
22256
- this.getLocalChannelEdges());
22257
- if (!route)
22258
- return null;
22259
- // Calculate success probability from MissionControl penalties
22258
+ localChannels);
22259
+ // As sendPayment judges it: a single route whose outgoing channel
22260
+ // cannot carry the total would only die in addHtlc, so the payment
22261
+ // splits instead, and the estimate prices what the payment would do.
22262
+ if (route) {
22263
+ const firstHopChannel = this.firstHopChannelFor(route);
22264
+ if (firstHopChannel &&
22265
+ firstHopChannel.getSpendableOutboundMsat() < route.totalAmountMsat) {
22266
+ route = null;
22267
+ }
22268
+ }
22269
+ // The paths priced: the one route, or the parts a multi-path payment
22270
+ // takes when no single path carries the amount and the payee takes
22271
+ // parts (basic_mpp with a payment secret, BOLT 4), exactly the
22272
+ // fallback sendPayment makes. An estimate that stopped at the single
22273
+ // path refused, as "no route", a payment the engine would have split
22274
+ // across two channels (coreyphillips/beignet#1924).
22275
+ let parts;
22276
+ let totalFeeMsat;
22277
+ let split = false;
22278
+ if (route) {
22279
+ parts = [route];
22280
+ totalFeeMsat = route.totalFeeMsat;
22281
+ }
22282
+ else {
22283
+ if (!decoded.paymentSecret ||
22284
+ !decoded.featureBits?.hasFeature(flags_1.Feature.BASIC_MPP))
22285
+ return null;
22286
+ const multiRoute = (0, pathfinding_1.findMultiPathRoute)(this.graph, sourceBuf, destination, amountMsat, finalCltvExpiry, undefined, undefined, this.missionControl, decoded.routingHints, undefined, // currentTimestamp
22287
+ localChannels);
22288
+ if (!multiRoute)
22289
+ return null;
22290
+ parts = multiRoute.parts;
22291
+ totalFeeMsat = multiRoute.totalFeeMsat;
22292
+ split = true;
22293
+ }
22294
+ // Calculate success probability from MissionControl penalties: every
22295
+ // hop of every part has to succeed, each judged at its part's amount.
22260
22296
  let successProbability = 1.0;
22261
- for (const hop of route.hops) {
22262
- const scidHex = hop.shortChannelId.toString('hex');
22263
- const penalty = this.missionControl.getPenalty(scidHex, amountMsat);
22264
- // Higher penalty = lower success probability
22265
- // MissionControl penalties are in msat, normalize to a probability
22266
- const hopProb = penalty > 0n
22267
- ? Math.max(0.1, 1.0 - Number(penalty) / 1000000)
22268
- : 0.95;
22269
- successProbability *= hopProb;
22297
+ for (const part of parts) {
22298
+ for (const hop of part.hops) {
22299
+ const scidHex = hop.shortChannelId.toString('hex');
22300
+ const penalty = this.missionControl.getPenalty(scidHex, part.totalAmountMsat);
22301
+ // Higher penalty = lower success probability
22302
+ // MissionControl penalties are in msat, normalize to a probability
22303
+ const hopProb = penalty > 0n
22304
+ ? Math.max(0.1, 1.0 - Number(penalty) / 1000000)
22305
+ : 0.95;
22306
+ successProbability *= hopProb;
22307
+ }
22270
22308
  }
22271
22309
  const successPct = Math.round(successProbability * 100);
22272
- const hopCount = route.hops.length;
22310
+ // The parts fly together, so the longest part sets the hop count.
22311
+ const hopCount = Math.max(...parts.map((part) => part.hops.length));
22273
22312
  // Rounded UP, like estimateRouteFee: maxFeeSats is whole sats checked
22274
22313
  // against the route in msat, so a cap equal to a floored quote refused
22275
22314
  // the very route it priced (issue #998).
22276
- const feeSats = Number((route.totalFeeMsat + 999n) / 1000n);
22315
+ const feeSats = Number((totalFeeMsat + 999n) / 1000n);
22277
22316
  // Route quality based on hop count and probability
22278
22317
  let routeQuality = 'HIGH';
22279
22318
  if (hopCount > 4 || successPct < 50)
@@ -22282,15 +22321,17 @@ class LightningNode extends typed_emitter_1.TypedEmitter {
22282
22321
  routeQuality = 'MEDIUM';
22283
22322
  // Estimated time: ~2s per hop for HTLC settlement
22284
22323
  const estimatedTimeMs = hopCount * 2000;
22285
- // Check if alternative routes exist (MPP)
22286
- let alternativeAvailable = false;
22287
- try {
22288
- const altRoute = (0, pathfinding_1.findMultiPathRoute)(this.graph, sourceBuf, destination, amountMsat, decoded.minFinalCltvExpiry || types_5.DEFAULT_MIN_FINAL_CLTV_EXPIRY, undefined, undefined, this.missionControl, decoded.routingHints, undefined, // currentTimestamp
22289
- this.getLocalChannelEdges());
22290
- alternativeAvailable = altRoute !== null && altRoute.parts.length > 1;
22291
- }
22292
- catch {
22293
- // No alternative route
22324
+ // Check if alternative routes exist (MPP): a split is one already.
22325
+ let alternativeAvailable = split;
22326
+ if (!split) {
22327
+ try {
22328
+ const altRoute = (0, pathfinding_1.findMultiPathRoute)(this.graph, sourceBuf, destination, amountMsat, finalCltvExpiry, undefined, undefined, this.missionControl, decoded.routingHints, undefined, // currentTimestamp
22329
+ localChannels);
22330
+ alternativeAvailable = altRoute !== null && altRoute.parts.length > 1;
22331
+ }
22332
+ catch {
22333
+ // No alternative route
22334
+ }
22294
22335
  }
22295
22336
  // Warnings
22296
22337
  let warning;
@@ -22310,7 +22351,7 @@ class LightningNode extends typed_emitter_1.TypedEmitter {
22310
22351
  warning,
22311
22352
  alternativeAvailable,
22312
22353
  estimatedFeeSats: feeSats,
22313
- estimatedFeeMsat: route.totalFeeMsat,
22354
+ estimatedFeeMsat: totalFeeMsat,
22314
22355
  hopCount
22315
22356
  };
22316
22357
  }