beignet 0.27.0 → 0.29.0
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/dist/cli/beignet-node.js +101 -11
- package/dist/cli/beignet-node.js.map +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/lightning/gossip/graph-restore.js +162 -0
- package/dist/lightning/gossip/graph-restore.js.map +1 -0
- package/dist/lightning/gossip/index.js +1 -0
- package/dist/lightning/gossip/index.js.map +1 -1
- package/dist/lightning/gossip/network-graph.js +49 -20
- package/dist/lightning/gossip/network-graph.js.map +1 -1
- package/dist/lightning/gossip/rapid-sync.js +261 -86
- package/dist/lightning/gossip/rapid-sync.js.map +1 -1
- package/dist/lightning/keys/wallet-keys.js +35 -6
- package/dist/lightning/keys/wallet-keys.js.map +1 -1
- package/dist/lightning/message/codec.js +52 -1
- package/dist/lightning/message/codec.js.map +1 -1
- package/dist/lightning/node/lightning-node.js +363 -52
- package/dist/lightning/node/lightning-node.js.map +1 -1
- package/dist/lightning/node/types.js.map +1 -1
- package/dist/lightning/storage/encryption.js +5 -5
- package/dist/lightning/storage/encryption.js.map +1 -1
- package/dist/lightning/storage/sqlite-storage.js +42 -2
- package/dist/lightning/storage/sqlite-storage.js.map +1 -1
- package/dist/lightning/storage/types.js.map +1 -1
- package/dist/types/cli/beignet-node.d.ts +10 -1
- package/dist/types/cli/index.d.ts +1 -1
- package/dist/types/cli/types.d.ts +11 -0
- package/dist/types/lightning/gossip/graph-restore.d.ts +37 -0
- package/dist/types/lightning/gossip/index.d.ts +1 -0
- package/dist/types/lightning/gossip/network-graph.d.ts +8 -0
- package/dist/types/lightning/gossip/rapid-sync.d.ts +10 -0
- package/dist/types/lightning/keys/wallet-keys.d.ts +3 -0
- package/dist/types/lightning/message/codec.d.ts +4 -0
- package/dist/types/lightning/node/lightning-node.d.ts +36 -1
- package/dist/types/lightning/node/types.d.ts +22 -0
- package/dist/types/lightning/storage/encryption.d.ts +1 -0
- package/dist/types/lightning/storage/sqlite-storage.d.ts +3 -1
- package/dist/types/lightning/storage/types.d.ts +7 -0
- package/dist/types/types/wallet.d.ts +3 -1
- package/dist/types/wallet.js.map +1 -1
- package/dist/wallet/index.js +4 -2
- package/dist/wallet/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/beignet-node.js
CHANGED
|
@@ -722,6 +722,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
722
722
|
this.rapidGossipSync = true;
|
|
723
723
|
this._initialGossipPrime = null;
|
|
724
724
|
this._releaseBootRgs = null;
|
|
725
|
+
this._rapidGossipSync = null;
|
|
725
726
|
this._deferredGossipSyncs = new Set();
|
|
726
727
|
this.electrumServerCount = 1;
|
|
727
728
|
this._failoverInProgress = false;
|
|
@@ -916,7 +917,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
916
917
|
}
|
|
917
918
|
let encryptionKey;
|
|
918
919
|
if (opts.storageEncryption ?? true) {
|
|
919
|
-
encryptionKey = (0, encryption_1.deriveStorageKey)(
|
|
920
|
+
encryptionKey = (0, encryption_1.deriveStorageKey)(this.walletSeed());
|
|
920
921
|
}
|
|
921
922
|
this._storageEncryptionKey = encryptionKey;
|
|
922
923
|
this.finishStagedCapsuleRestore(dbPath);
|
|
@@ -977,6 +978,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
977
978
|
};
|
|
978
979
|
const walletResult = await wallet_1.Wallet.create({
|
|
979
980
|
mnemonic: this.mnemonic,
|
|
981
|
+
seed: this.walletSeed(),
|
|
980
982
|
network: beignetNetwork,
|
|
981
983
|
disableRefreshOnCreate: true,
|
|
982
984
|
...(opts.addressType
|
|
@@ -1092,8 +1094,10 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
1092
1094
|
});
|
|
1093
1095
|
}
|
|
1094
1096
|
this._nodeStorageView = (0, node_storage_view_1.nodeStorageView)(this.storage);
|
|
1097
|
+
const constructStarted = Date.now();
|
|
1095
1098
|
this.node = lightning_node_1.LightningNode.fromMnemonic(this.mnemonic, {
|
|
1096
1099
|
coinType,
|
|
1100
|
+
seed: this.walletSeed(),
|
|
1097
1101
|
network: lnNetwork,
|
|
1098
1102
|
storage: this._nodeStorageView,
|
|
1099
1103
|
newChannelsRefused: () => this.newChannelRefusal(),
|
|
@@ -1262,6 +1266,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
1262
1266
|
: {}
|
|
1263
1267
|
},
|
|
1264
1268
|
eagerGossipVerify: opts.eagerGossipVerify ?? false,
|
|
1269
|
+
cooperativeGraphRestore: opts.deferGraphRestore === true,
|
|
1265
1270
|
localFeatures: lightning_node_1.LightningNode.defaultFeatures(),
|
|
1266
1271
|
chainHashes: [chainHash],
|
|
1267
1272
|
alias: opts.alias,
|
|
@@ -1306,6 +1311,12 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
1306
1311
|
watchtowers: opts.watchtowers,
|
|
1307
1312
|
recovery: this.recoveryNodeConfig
|
|
1308
1313
|
});
|
|
1314
|
+
this._nodeConstructMs = Date.now() - constructStarted;
|
|
1315
|
+
this.node.on('graph:restored', () => {
|
|
1316
|
+
const stats = this.getGraphRestoreStats();
|
|
1317
|
+
if (stats)
|
|
1318
|
+
this.emit('graph:restored', stats);
|
|
1319
|
+
});
|
|
1309
1320
|
this.fforReceiveService = new ffor_receive_1.FforReceiveService(this, opts.fforSettle, opts.fforReceiveFunding, opts.fforSettleConcurrent !== false);
|
|
1310
1321
|
const receiveKey = 'automatic_receive_jobs_v1';
|
|
1311
1322
|
const receiveJobs = this.storage.loadWalletData(receiveKey);
|
|
@@ -1783,6 +1794,10 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
1783
1794
|
}
|
|
1784
1795
|
if (this.rapidGossipSync && this.networkName === 'mainnet') {
|
|
1785
1796
|
const rgs = this.syncRapidGossip().catch((err) => {
|
|
1797
|
+
if (err instanceof rapid_sync_1.RapidGossipCancelledError && this.destroyed) {
|
|
1798
|
+
this.log('debug', 'Rapid gossip sync cancelled by shutdown', {});
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1786
1801
|
this.log('warn', 'Rapid gossip sync failed', {
|
|
1787
1802
|
error: err instanceof Error ? err.message : String(err)
|
|
1788
1803
|
});
|
|
@@ -3092,10 +3107,19 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3092
3107
|
}
|
|
3093
3108
|
nodeSecret() {
|
|
3094
3109
|
if (!this._nodeSecret) {
|
|
3095
|
-
|
|
3110
|
+
if (!bip39.validateMnemonic(this.mnemonic)) {
|
|
3111
|
+
throw new Error('Invalid BIP39 mnemonic');
|
|
3112
|
+
}
|
|
3113
|
+
this._nodeSecret = (0, wallet_keys_1.deriveLightningKeysFromSeed)(this.walletSeed(), this.toCoinType(this.networkName)).nodePrivateKey;
|
|
3096
3114
|
}
|
|
3097
3115
|
return this._nodeSecret;
|
|
3098
3116
|
}
|
|
3117
|
+
walletSeed() {
|
|
3118
|
+
if (!this._walletSeed) {
|
|
3119
|
+
this._walletSeed = bip39.mnemonicToSeedSync(this.mnemonic);
|
|
3120
|
+
}
|
|
3121
|
+
return Buffer.from(this._walletSeed);
|
|
3122
|
+
}
|
|
3099
3123
|
async restoreFromGuardians() {
|
|
3100
3124
|
if (this._restoreInFlight) {
|
|
3101
3125
|
throw new errors_1.BeignetError('RESTORE_IN_PROGRESS', 'A guardian restore is already running; watch ' +
|
|
@@ -4192,24 +4216,62 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4192
4216
|
this._lastGraphSyncAt = Date.now();
|
|
4193
4217
|
return synced;
|
|
4194
4218
|
}
|
|
4195
|
-
|
|
4219
|
+
syncRapidGossip() {
|
|
4220
|
+
if (this._rapidGossipSync)
|
|
4221
|
+
return this._rapidGossipSync;
|
|
4222
|
+
const run = this.runRapidGossipSync();
|
|
4223
|
+
this._rapidGossipSync = run;
|
|
4224
|
+
const clear = () => {
|
|
4225
|
+
if (this._rapidGossipSync === run)
|
|
4226
|
+
this._rapidGossipSync = null;
|
|
4227
|
+
};
|
|
4228
|
+
void run.then(clear, clear);
|
|
4229
|
+
return run;
|
|
4230
|
+
}
|
|
4231
|
+
async runRapidGossipSync() {
|
|
4196
4232
|
if (this.networkName !== 'mainnet') {
|
|
4197
4233
|
this.log('warn', 'Rapid gossip sync is only available on mainnet', {});
|
|
4198
4234
|
return null;
|
|
4199
4235
|
}
|
|
4200
4236
|
const url = this.rapidGossipSyncUrl ?? rapid_sync_1.DEFAULT_RGS_URL;
|
|
4201
4237
|
this.log('info', 'Rapid gossip sync: downloading snapshot', { url });
|
|
4238
|
+
const downloadStart = Date.now();
|
|
4202
4239
|
const data = await (0, rapid_sync_1.fetchRapidGossipSnapshot)(url);
|
|
4203
|
-
const
|
|
4240
|
+
const downloadMs = Date.now() - downloadStart;
|
|
4241
|
+
if (this.destroyed)
|
|
4242
|
+
throw new rapid_sync_1.RapidGossipCancelledError();
|
|
4243
|
+
if (this.isGraphRestoring())
|
|
4244
|
+
await this.whenGraphRestored();
|
|
4245
|
+
if (this.destroyed)
|
|
4246
|
+
throw new rapid_sync_1.RapidGossipCancelledError();
|
|
4247
|
+
let slices = 0;
|
|
4248
|
+
let busyMs = 0;
|
|
4249
|
+
const applyStart = Date.now();
|
|
4250
|
+
const result = await this.node.loadRapidGossipSnapshotAsync(data, {
|
|
4251
|
+
cancelled: () => this.destroyed,
|
|
4252
|
+
onSlice: (ms) => {
|
|
4253
|
+
slices++;
|
|
4254
|
+
busyMs += ms;
|
|
4255
|
+
}
|
|
4256
|
+
});
|
|
4257
|
+
const applyMs = Date.now() - applyStart;
|
|
4204
4258
|
this._lastGraphSyncAt = Date.now();
|
|
4205
4259
|
this.log('info', 'Rapid gossip sync complete', {
|
|
4206
4260
|
channelsAdded: result.channelsAdded,
|
|
4207
4261
|
updatesApplied: result.updatesApplied,
|
|
4208
|
-
nodes: result.nodeCount
|
|
4262
|
+
nodes: result.nodeCount,
|
|
4263
|
+
downloadMs,
|
|
4264
|
+
applyMs,
|
|
4265
|
+
busyMs,
|
|
4266
|
+
slices
|
|
4209
4267
|
});
|
|
4210
4268
|
this.emit('gossip:synced', {
|
|
4211
4269
|
channelsAdded: result.channelsAdded,
|
|
4212
|
-
updatesApplied: result.updatesApplied
|
|
4270
|
+
updatesApplied: result.updatesApplied,
|
|
4271
|
+
downloadMs,
|
|
4272
|
+
applyMs,
|
|
4273
|
+
busyMs,
|
|
4274
|
+
slices
|
|
4213
4275
|
});
|
|
4214
4276
|
return {
|
|
4215
4277
|
channelsAdded: result.channelsAdded,
|
|
@@ -4249,6 +4311,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4249
4311
|
return this.openChannel(pubkey, amountSats, opts?.pushSats, opts?.satsPerVbyte, opts?.max, opts?.trusted ?? false);
|
|
4250
4312
|
}
|
|
4251
4313
|
async ensureMinimumChannels(count, satsPerChannel, _opts) {
|
|
4314
|
+
if (this.isGraphRestoring())
|
|
4315
|
+
await this.whenGraphRestored();
|
|
4252
4316
|
const existing = this.getReadyChannels();
|
|
4253
4317
|
if (existing.length >= count)
|
|
4254
4318
|
return existing;
|
|
@@ -6327,6 +6391,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6327
6391
|
}
|
|
6328
6392
|
async payInvoiceAll(bolt11, debitMsat, maxFeeMsat, timeoutMs = 60000) {
|
|
6329
6393
|
this._checkDraining();
|
|
6394
|
+
if (this.isGraphRestoring())
|
|
6395
|
+
await this.whenGraphRestored();
|
|
6330
6396
|
const decoded = decodeInvoiceInput(bolt11);
|
|
6331
6397
|
const debit = requireMsatValue(debitMsat, 'debitMsat');
|
|
6332
6398
|
const feeCap = requireMsatValue(maxFeeMsat, 'maxFeeMsat');
|
|
@@ -6345,6 +6411,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6345
6411
|
}
|
|
6346
6412
|
async payInvoice(bolt11, timeoutMs = 60000, maxFeeSats, amountSats, metadata, cltvLimit, maxFeeMsatCap) {
|
|
6347
6413
|
this._checkDraining();
|
|
6414
|
+
if (this.isGraphRestoring())
|
|
6415
|
+
await this.whenGraphRestored();
|
|
6348
6416
|
const decoded = decodeInvoiceInput(bolt11);
|
|
6349
6417
|
const paymentHashHex = decoded.paymentHash.toString('hex');
|
|
6350
6418
|
const amountMsat = amountSats !== undefined
|
|
@@ -6569,6 +6637,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6569
6637
|
}
|
|
6570
6638
|
async sendKeysend(pubkey, amountSats, timeoutMs = 60000, maxFeeSats, metadata, onPaymentHash) {
|
|
6571
6639
|
this._checkDraining();
|
|
6640
|
+
if (this.isGraphRestoring())
|
|
6641
|
+
await this.whenGraphRestored();
|
|
6572
6642
|
const amountMsat = BigInt(requireNonNegativeSafeInteger(amountSats, 'amountSats')) * 1000n;
|
|
6573
6643
|
const maxFeeMsat = resolveMaxFeeMsat(maxFeeSats, undefined, amountMsat);
|
|
6574
6644
|
const preimage = crypto.randomBytes(32);
|
|
@@ -7156,6 +7226,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7156
7226
|
.map(({ offer, encoded }) => this.toOfferInfo(offer, encoded));
|
|
7157
7227
|
}
|
|
7158
7228
|
async payOffer(offerStr, amountSats, timeoutMs = 60000, maxFeeSats, maxFeeMsatCap, onPaymentHash) {
|
|
7229
|
+
if (this.isGraphRestoring())
|
|
7230
|
+
await this.whenGraphRestored();
|
|
7159
7231
|
this._checkDraining();
|
|
7160
7232
|
const offer = decodeOfferInput(offerStr);
|
|
7161
7233
|
const callerMaxFeeMsat = explicitMaxFeeMsat(maxFeeSats, maxFeeMsatCap);
|
|
@@ -7579,6 +7651,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7579
7651
|
return { ...this.getLiquiditySnapshot(), rebalancePlan: plan };
|
|
7580
7652
|
}
|
|
7581
7653
|
async rebalanceChannel(fromChannelId, toChannelId, amountSats, maxFeeSats) {
|
|
7654
|
+
if (this.isGraphRestoring())
|
|
7655
|
+
await this.whenGraphRestored();
|
|
7582
7656
|
if (!/^[0-9a-fA-F]{64}$/.test(fromChannelId))
|
|
7583
7657
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, 'fromChannelId must be 64 hex chars');
|
|
7584
7658
|
if (!/^[0-9a-fA-F]{64}$/.test(toChannelId))
|
|
@@ -7715,6 +7789,20 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7715
7789
|
}))
|
|
7716
7790
|
};
|
|
7717
7791
|
}
|
|
7792
|
+
isGraphRestoring() {
|
|
7793
|
+
return this.node?.isGraphRestoring?.() ?? false;
|
|
7794
|
+
}
|
|
7795
|
+
whenGraphRestored() {
|
|
7796
|
+
return this.node?.whenGraphRestored?.() ?? Promise.resolve(true);
|
|
7797
|
+
}
|
|
7798
|
+
getGraphRestoreStats() {
|
|
7799
|
+
const stats = this.node?.getGraphRestoreStats() ?? null;
|
|
7800
|
+
if (!stats)
|
|
7801
|
+
return null;
|
|
7802
|
+
return this._nodeConstructMs === undefined
|
|
7803
|
+
? stats
|
|
7804
|
+
: { ...stats, constructMs: this._nodeConstructMs };
|
|
7805
|
+
}
|
|
7718
7806
|
getGraphInfo() {
|
|
7719
7807
|
const graph = this.node.getGraph();
|
|
7720
7808
|
const info = {
|
|
@@ -7724,6 +7812,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7724
7812
|
if (this._lastGraphSyncAt !== undefined) {
|
|
7725
7813
|
info.lastSyncAt = this._lastGraphSyncAt;
|
|
7726
7814
|
}
|
|
7815
|
+
if (this.isGraphRestoring())
|
|
7816
|
+
info.restoring = true;
|
|
7727
7817
|
return info;
|
|
7728
7818
|
}
|
|
7729
7819
|
getGraphNode(pubkey) {
|
|
@@ -8199,7 +8289,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
8199
8289
|
}
|
|
8200
8290
|
async backup(destPath) {
|
|
8201
8291
|
await this.storage.backup(destPath);
|
|
8202
|
-
await (0, backup_mac_1.writeBackupMac)((0, backup_mac_1.deriveBackupMacKey)(
|
|
8292
|
+
await (0, backup_mac_1.writeBackupMac)((0, backup_mac_1.deriveBackupMacKey)(this.walletSeed()), destPath);
|
|
8203
8293
|
}
|
|
8204
8294
|
storageFiles() {
|
|
8205
8295
|
const dbPath = fs.realpathSync.native(path.join(this.dataDir, `${this.networkName}.db`));
|
|
@@ -8250,14 +8340,14 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
8250
8340
|
createdAt: Date.now(),
|
|
8251
8341
|
channels: data.channels
|
|
8252
8342
|
};
|
|
8253
|
-
const seed =
|
|
8343
|
+
const seed = this.walletSeed();
|
|
8254
8344
|
const encoded = (0, scb_1.encodeScb)(backup, seed);
|
|
8255
8345
|
const scbPath = path.join(this.dataDir, 'channels.scb');
|
|
8256
8346
|
(0, fs_utils_1.writeFileAtomic)(scbPath, encoded);
|
|
8257
8347
|
return { encoded, channelCount: data.channels.length, path: scbPath };
|
|
8258
8348
|
}
|
|
8259
8349
|
async restoreFromScb(encoded) {
|
|
8260
|
-
const seed =
|
|
8350
|
+
const seed = this.walletSeed();
|
|
8261
8351
|
const backup = (0, scb_1.decodeScb)(encoded.trim(), seed);
|
|
8262
8352
|
const expectedNetwork = this.toLnNetwork(this.networkName);
|
|
8263
8353
|
if (backup.network !== expectedNetwork) {
|
|
@@ -8378,14 +8468,14 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
8378
8468
|
});
|
|
8379
8469
|
}
|
|
8380
8470
|
}
|
|
8381
|
-
const seed =
|
|
8471
|
+
const seed = this.walletSeed();
|
|
8382
8472
|
this.offerRetrievedScb((0, scb_1.encodeScb)(embedded, seed), embedded, peerPubkey, 'capsule');
|
|
8383
8473
|
return;
|
|
8384
8474
|
}
|
|
8385
8475
|
let backup;
|
|
8386
8476
|
const encoded = blob.toString('utf8');
|
|
8387
8477
|
try {
|
|
8388
|
-
const seed =
|
|
8478
|
+
const seed = this.walletSeed();
|
|
8389
8479
|
backup = (0, scb_1.decodeScb)(encoded, seed);
|
|
8390
8480
|
}
|
|
8391
8481
|
catch {
|