ln-service 53.1.2 → 53.4.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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,22 @@
1
1
  # Versions
2
2
 
3
- ## 53.1.1
3
+ ## 53.4.1
4
+
5
+ - `pay`, `payViaPaymentRequest`: Fix support for `outgoing_channels` constraint
6
+
7
+ ## 53.4.0
8
+
9
+ - `deletePendingChannel`: Add method to remove a stuck pending channel open
10
+
11
+ ## 53.3.0
12
+
13
+ - `getInvoices`: Add `is_unconfirmed` to filter out canceled/settled invoices
14
+
15
+ ## 53.2.0
16
+
17
+ - `getPendingChannels`: Add support for channel `capacity`
18
+
19
+ ## 53.1.2
4
20
 
5
21
  - `openChannels`: Fix `cooperative_close_address` not being set on channels
6
22
 
package/README.md CHANGED
@@ -74,8 +74,8 @@ the LND directory. (~/.lnd or ~/Library/Application Support/Lnd)
74
74
 
75
75
  Be careful to avoid copying any newline characters in creds. To exclude them:
76
76
 
77
- base64 ~/.lnd/tls.cert | tr -d '\n'
78
- base64 ~/.lnd/data/chain/bitcoin/mainnet/admin.macaroon | tr -d '\n'
77
+ base64 -w0 ~/.lnd/tls.cert
78
+ base64 -w0 ~/.lnd/data/chain/bitcoin/mainnet/admin.macaroon
79
79
 
80
80
  You can then use these to interact with your LND node directly:
81
81
 
@@ -102,7 +102,7 @@ for `unlocker` methods.
102
102
 
103
103
  ## All Methods
104
104
 
105
- - [addPeer](#addPeer) - Connect to a peer
105
+ - [addPeer](#addpeer) - Connect to a peer
106
106
  - [authenticatedLndGrpc](#authenticatedlndgrpc) - LND API Object
107
107
  - [broadcastChainTransaction](#broadcastchaintransaction) - Push a chain tx
108
108
  - [cancelHodlInvoice](#cancelhodlinvoice) - Cancel a held or any open invoice
@@ -118,17 +118,22 @@ for `unlocker` methods.
118
118
  - [createUnsignedRequest](#createunsignedrequest) - create an unsigned invoice
119
119
  - [createWallet](#createwallet) - Make a new wallet
120
120
  - [decodePaymentRequest](#decodepaymentrequest) - Decode a Lightning invoice
121
- - [deleteFailedPayAttempts](#deletefailedpayattempts) - Remove records of failed pay attempts
122
- - [deleteFailedPayments](#deletefailedpayments) - Remove records of payments that failed
121
+ - [deleteFailedPayAttempts](#deletefailedpayattempts) - Remove records of
122
+ failed pay attempts
123
+ - [deleteFailedPayments](#deletefailedpayments) - Remove records of payments
124
+ that failed
123
125
  - [deleteForwardingReputations](#deleteforwardingreputations) - Wipe node reps
124
126
  - [deletePayment](#deletepayment) - Delete the record of a single past payment
125
127
  - [deletePayments](#deletepayments) - Delete entire history of past payments
128
+ - [deletePendingChannel](#deletependingchannel) - Delete a pending channel that
129
+ will never confirm due to a conflicting confirmed transaction
126
130
  - [diffieHellmanComputeSecret](#diffiehellmancomputesecret) - Get DH shared key
127
131
  - [disableChannel](#disablechannel) - Disable a channel for outgoing payments
128
132
  - [disconnectWatchtower](#disconnectwatchtower) - Disconnect a watchtower
129
133
  - [enableChannel](#enablechannel) - Enable a channel for outgoing payments
130
134
  - [fundPendingChannels](#fundpendingchannels) - Fund pending open channels
131
- - [fundPsbt](#fundpsbt) - Create an unsigned PSBT with funding inputs and spending outputs
135
+ - [fundPsbt](#fundpsbt) - Create an unsigned PSBT with funding inputs and
136
+ spending outputs
132
137
  - [getAccessIds](#getaccessids) - Get granted macaroon root access ids
133
138
  - [getAutopilot](#getautopilot) - Get autopilot status or node scores
134
139
  - [getBackup](#getbackup) - Get a backup of a channel
@@ -157,48 +162,53 @@ for `unlocker` methods.
157
162
  - [getNetworkGraph](#getnetworkgraph) - Get the channels and nodes of the graph
158
163
  - [getNetworkInfo](#getnetworkinfo) - Get high-level graph info
159
164
  - [getNode](#getnode) - Get graph info about a single node and its channels
160
- - [getPathfindingSettings](#getpathfindingsettings) - Get pathfinding system settings
165
+ - [getPathfindingSettings](#getpathfindingsettings) - Get pathfinding system
166
+ settings
161
167
  - [getPayment](#getpayment) - Get a past payment
162
168
  - [getPayments](#getpayments) - Get all past payments
163
169
  - [getPeers](#getpeers) - Get all connected peers
164
170
  - [getPendingChainBalance](#getpendingchainbalance) - Get pending chain balance
165
171
  - [getPendingChannels](#getpendingchannels) - Get channels in pending states
166
172
  - [getPublicKey](#getpublickey) - Get a public key out of the seed
167
- - [getRouteConfidence](#getRouteConfidence) - Get confidence in a route
168
- - [getRouteThroughHops](#getRouteThroughHops) - Get a route through nodes
169
- - [getRouteToDestination](#getRouteToDestination) - Get a route to a destination
170
- - [getSweepTransactions](#getSweepTransactions) - Get transactions sweeping to self
171
- - [getTowerServerInfo](#getTowerServerInfo) - Get information about tower server
172
- - [getUtxos](#getUtxos) - Get on-chain unspent outputs
173
- - [getWalletInfo](#getWalletInfo) - Get general wallet info
173
+ - [getRouteConfidence](#getrouteconfidence) - Get confidence in a route
174
+ - [getRouteThroughHops](#getroutethroughhops) - Get a route through nodes
175
+ - [getRouteToDestination](#getroutetodestination) - Get a route to a destination
176
+ - [getSweepTransactions](#getsweeptransactions) - Get transactions sweeping to
177
+ self
178
+ - [getTowerServerInfo](#gettowerserverinfo) - Get information about tower server
179
+ - [getUtxos](#getutxos) - Get on-chain unspent outputs
180
+ - [getWalletInfo](#getwalletinfo) - Get general wallet info
174
181
  - [getWalletStatus](#getwalletstatus) - Get the status of the wallet
175
- - [getWalletVersion](#getWalletVersion) - Get the build and version of the LND
176
- - [grantAccess](#grantAccess) - Grant an access credential macaroon
177
- - [grpcProxyServer](#grpcProxyServer) - REST proxy server for calling to gRPC
178
- - [isDestinationPayable](#isDestinationPayable) - Check can pay to destination
179
- - [lockUtxo](#lockUtxo) - Lock a UTXO temporarily to prevent it being used
180
- - [openChannel](#openChannel) - Open a new channel
181
- - [openChannels](#openChannels) - Open channels with external funding
182
- - [parsePaymentRequest](#parsePaymentRequest) - Parse a BOLT11 Payment Request
182
+ - [getWalletVersion](#getwalletversion) - Get the build and version of the LND
183
+ - [grantAccess](#grantaccess) - Grant an access credential macaroon
184
+ - [grpcProxyServer](#grpcproxyserver) - REST proxy server for calling to gRPC
185
+ - [isDestinationPayable](#isdestinationpayable) - Check can pay to destination
186
+ - [lockUtxo](#lockutxo) - Lock a UTXO temporarily to prevent it being used
187
+ - [openChannel](#openchannel) - Open a new channel
188
+ - [openChannels](#openchannels) - Open channels with external funding
189
+ - [parsePaymentRequest](#parsepaymentrequest) - Parse a BOLT11 Payment Request
183
190
  - [pay](#pay) - Send a payment
184
- - [payViaPaymentDetails](#payViaPaymentDetails) - Pay using decomposed details
185
- - [payViaPaymentRequest](#payViaPaymentRequest) - Pay using a payment request
186
- - [payViaRoutes](#payViaRoutes) - Make a payment over specified routes
187
- - [prepareForChannelProposal](#prepareForChannelProposal) - setup for a channel proposal
191
+ - [payViaPaymentDetails](#payviapaymentdetails) - Pay using decomposed details
192
+ - [payViaPaymentRequest](#payviapaymentrequest) - Pay using a payment request
193
+ - [payViaRoutes](#payviaroutes) - Make a payment over specified routes
194
+ - [prepareForChannelProposal](#prepareforchannelproposal) - setup for a channel
195
+ proposal
188
196
  - [probe](#probe) - Find a payable route by attempting a fake payment
189
- - [probeForRoute](#probeForRoute) - Actively probe to find a payable route
197
+ - [probeForRoute](#probeforroute) - Actively probe to find a payable route
190
198
  - [proposeChannel](#proposechannel) - Offer a channel proposal to a peer
191
- - [recoverFundsFromChannel](#recoverFundsFromChannel) - Restore a channel
192
- - [recoverFundsFromChannels](#recoverFundsFromChannels) - Restore all channels
193
- - [removePeer](#removePeer) - Disconnect from a connected peer
194
- - [requestChainFeeIncrease](#requestchainfeeincrease) - Request a CPFP spend on a UTXO
199
+ - [recoverFundsFromChannel](#recoverfundsfromchannel) - Restore a channel
200
+ - [recoverFundsFromChannels](#recoverfundsfromchannels) - Restore all channels
201
+ - [removePeer](#removepeer) - Disconnect from a connected peer
202
+ - [requestChainFeeIncrease](#requestchainfeeincrease) - Request a CPFP spend on
203
+ a UTXO
195
204
  - [restrictMacaroon](#restrictmacaroon) - Add limitations to a macaroon
196
205
  - [revokeAccess](#revokeaccess) - Revoke all access macaroons given to an id
197
206
  - [routeFromChannels](#routefromchannels) - Convert channel series to a route
198
207
  - [sendMessageToPeer](#sendmessagetopeer) - Send a custom message to a peer
199
208
  - [sendToChainAddress](#sendtochainaddress) - Send on-chain to an address
200
209
  - [sendToChainAddresses](#sendtochainaddresses) - Send on-chain to addresses
201
- - [sendToChainOutputScripts](#sendtochainoutputscripts) - Send to on-chain script outputs
210
+ - [sendToChainOutputScripts](#sendtochainoutputscripts) - Send to on-chain
211
+ script outputs
202
212
  - [setAutopilot](#setautopilot) - Turn autopilot on and set autopilot scores
203
213
  - [settleHodlInvoice](#settlehodlinvoice) - Accept a HODL HTLC invoice
204
214
  - [signBytes](#signbytes) - Sign over arbitrary bytes with node keys
@@ -211,18 +221,21 @@ for `unlocker` methods.
211
221
  - [subscribeToChainAddress](#subscribetochainaddress) - Subscribe to receives
212
222
  - [subscribeToChainSpend](#subscribetochainspend) - Subscribe to chain spends
213
223
  - [subscribeToChannels](#subscribetochannels) - Subscribe to channel statuses
214
- - [subscribeToForwardRequests](#subscribetoforwardrequests) - Interactively route
224
+ - [subscribeToForwardRequests](#subscribetoforwardrequests) - Interactively
225
+ route
215
226
  - [subscribeToForwards](#subscribetoforwards) - Subscribe to HTLC events
216
227
  - [subscribeToGraph](#subscribetograph) - Subscribe to network graph updates
217
228
  - [subscribeToInvoice](#subscribetoinvoice) - Subscribe to invoice updates
218
229
  - [subscribeToInvoices](#subscribetoinvoices) - Subscribe to all invoices
219
230
  - [subscribeToOpenRequests](#subscribetoopenrequests) - Approve open requests
220
231
  - [subscribeToPastPayment](#subscribetopastpayment) - Subscribe to a payment
221
- - [subscribeToPastPayments](#subscribetopastpayments) - Subscribe to all sent payments
232
+ - [subscribeToPastPayments](#subscribetopastpayments) - Subscribe to all sent
233
+ payments
222
234
  - [subscribeToPayViaDetails](#subscribetopayviadetails) - Pay using details
223
235
  - [subscribeToPayViaRequest](#subscribetopayviarequest) - Pay using a request
224
236
  - [subscribeToPayViaRoutes](#subscribetopayviaroutes) - Pay using routes
225
- - [subscribeToPeerMessages](#subscribetopeermessages) - Listen to incoming custom messages
237
+ - [subscribeToPeerMessages](#subscribetopeermessages) - Listen to incoming
238
+ custom messages
226
239
  - [subscribeToPeers](#subscribetopeers) - Subscribe to peers connectivity
227
240
  - [subscribeToProbe](#subscribetoprobe) - Subscribe to a probe for a route
228
241
  - [subscribeToProbeForRoute](#subscribetoprobeforroute) - Probe for a route
@@ -230,11 +243,14 @@ for `unlocker` methods.
230
243
  - [subscribeToTransactions](#subscribetotransactions) - Subscribe to chain tx
231
244
  - [subscribeToWalletStatus](#subscribetowalletstatus) - Subscribe to node state
232
245
  - [unauthenticatedLndGrpc](#unauthenticatedLndGrpc) - LND for locked lnd APIs
233
- - [unlockUtxo](#unlockUtxo) - Release a locked UTXO so that it can be used again
234
- - [unlockWallet](#unlockWallet) - Unlock a locked lnd
235
- - [updateChainTransaction](#updateChainTransaction) - Update a chain transaction
246
+ - [unlockUtxo](#unlockutxo) - Release a locked UTXO so that it can be used
247
+ again
248
+ - [unlockWallet](#unlockwallet) - Unlock a locked lnd
249
+ - [updateChainTransaction](#updatechaintransaction) - Update a chain
250
+ transaction
236
251
  - [updateConnectedWatchtower](#updateconnectedwatchtower) - Update watchtower
237
- - [updatePathfindingSettings](#updatepathfindingsettings) - Update pathfinding configuration
252
+ - [updatePathfindingSettings](#updatepathfindingsettings) - Update pathfinding
253
+ configuration
238
254
  - [updateRoutingFees](#updateroutingfees) - Change routing fees
239
255
  - [verifyAccess](#verifyaccess) - Verify a macaroon has access
240
256
  - [verifyBackup](#verifybackup) - Verify a channel backup
@@ -256,6 +272,7 @@ for `unlocker` methods.
256
272
  - run regtest integration tests
257
273
  - [ln-pathfinding](https://npmjs.com/package/ln-accounting) - pathfinding
258
274
  utilities
275
+ - [ln-sync](https://www.npmjs.com/package/ln-sync) - metadata helper methods
259
276
  - [probing](https://npmjs.com/package/probing) - payment probing utilities
260
277
  - [psbt](https://www.npmjs.com/package/psbt) - BIP 174 PSBT utilities
261
278
 
@@ -918,6 +935,36 @@ const {deletePayments} = require('ln-service');
918
935
  await deletePayments({lnd});
919
936
  ```
920
937
 
938
+ ### deletePendingChannel
939
+
940
+ Delete a pending channel
941
+
942
+ Pass the confirmed conflicting transaction that spends the same input to
943
+ make sure that no funds are being deleted.
944
+
945
+ This method is not supported on LND 0.13.3 and below
946
+
947
+ {
948
+ confirmed_transaction: <Hex Encoded Conflicting Transaction String>
949
+ lnd: <Authenticated LND API Object>
950
+ pending_transaction: <Hex Encoded Pending Transaction String>
951
+ pending_transaction_vout: <Pending Channel Output Index Number>
952
+ }
953
+
954
+ @returns via cbk or Promise
955
+
956
+ ```node
957
+ const {deletePendingChannel} = require('ln-service');
958
+
959
+ // Delete a stuck pending channel
960
+ await deletePendingChannel({
961
+ lnd,
962
+ confirmed_transaction: confirmedTransactionHex,
963
+ pending_transaction: stuckPendingChannelOpenTxHex,
964
+ pending_transaction_vout: pendingChannelOutputIndexNumber,
965
+ });
966
+ ```
967
+
921
968
  ### diffieHellmanComputeSecret
922
969
 
923
970
  Derive a shared secret
@@ -1952,6 +1999,7 @@ Requires `invoices:read` permission
1952
1999
  Invoice `payment` is not supported on LND 0.11.1 and below
1953
2000
 
1954
2001
  {
2002
+ [is_unconfirmed]: <Omit Canceled and Settled Invoices Bool>
1955
2003
  [limit]: <Page Result Limit Number>
1956
2004
  lnd: <Authenticated LND API Object>
1957
2005
  [token]: <Opaque Paging Token String>
@@ -2535,6 +2583,7 @@ Requires `offchain:read` permission
2535
2583
  @returns via cbk or Promise
2536
2584
  {
2537
2585
  pending_channels: [{
2586
+ capacity: <Channel Capacity Tokens Number>
2538
2587
  [close_transaction_id]: <Channel Closing Transaction Id String>
2539
2588
  is_active: <Channel Is Active Bool>
2540
2589
  is_closing: <Channel Is Closing Bool>
@@ -3205,11 +3254,11 @@ Requires `offchain:write`, `onchain:write`, `peers:write` permissions
3205
3254
  [give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
3206
3255
  [is_private]: <Channel is Private Bool> // Defaults to false
3207
3256
  lnd: <Authenticated LND API Object>
3208
- local_tokens: <Local Tokens Number>
3257
+ local_tokens: <Total Channel Capacity Tokens Number>
3209
3258
  [min_confirmations]: <Spend UTXOs With Minimum Confirmations Number>
3210
3259
  [min_htlc_mtokens]: <Minimum HTLC Millitokens String>
3211
- partner_public_key: <Public Key Hex String>
3212
3260
  [partner_csv_delay]: <Peer Output CSV Delay Number>
3261
+ partner_public_key: <Public Key Hex String>
3213
3262
  [partner_socket]: <Peer Connection Host:Port String>
3214
3263
  }
3215
3264
 
@@ -3250,8 +3299,8 @@ after the funding step.
3250
3299
  [give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
3251
3300
  [is_private]: <Channel is Private Bool> // Defaults to false
3252
3301
  [min_htlc_mtokens]: <Minimum HTLC Millitokens String>
3253
- partner_public_key: <Public Key Hex String>
3254
3302
  [partner_csv_delay]: <Peer Output CSV Delay Number>
3303
+ partner_public_key: <Public Key Hex String>
3255
3304
  [partner_socket]: <Peer Connection Host:Port String>
3256
3305
  }]
3257
3306
  [is_avoiding_broadcast]: <Avoid Broadcast of All Channels Bool>
@@ -6060,8 +6109,8 @@ This method is not supported in LND 0.13.4 and below
6060
6109
  local_tokens: <Local Tokens Number>
6061
6110
  [min_confirmations]: <Spend UTXOs With Minimum Confirmations Number>
6062
6111
  [min_htlc_mtokens]: <Minimum HTLC Millitokens String>
6063
- partner_public_key: <Public Key Hex String>
6064
6112
  [partner_csv_delay]: <Peer Output CSV Delay Number>
6113
+ partner_public_key: <Public Key Hex String>
6065
6114
  }
6066
6115
  uri: <RPC URI String>
6067
6116
  }
package/index.js CHANGED
@@ -19,6 +19,7 @@ const {deleteFailedPayAttempts} = require('lightning');
19
19
  const {deleteFailedPayments} = require('lightning');
20
20
  const {deletePayment} = require('lightning');
21
21
  const {deletePayments} = require('lightning');
22
+ const {deletePendingChannel} = require('lightning');
22
23
  const {diffieHellmanComputeSecret} = require('lightning');
23
24
  const {disableChannel} = require('lightning');
24
25
  const {disconnectWatchtower} = require('lightning');
@@ -157,6 +158,7 @@ module.exports = {
157
158
  deleteForwardingReputations,
158
159
  deletePayment,
159
160
  deletePayments,
161
+ deletePendingChannel,
160
162
  diffieHellmanComputeSecret,
161
163
  disableChannel,
162
164
  disconnectWatchtower,
package/package.json CHANGED
@@ -7,35 +7,36 @@
7
7
  "url": "https://github.com/alexbosworth/ln-service/issues"
8
8
  },
9
9
  "dependencies": {
10
- "bolt07": "1.7.4",
10
+ "bolt07": "1.8.0",
11
11
  "cors": "2.8.5",
12
- "express": "4.17.1",
13
- "invoices": "2.0.2",
14
- "lightning": "5.1.1",
12
+ "express": "4.17.2",
13
+ "invoices": "2.0.3",
14
+ "lightning": "5.3.1",
15
15
  "macaroon": "3.0.4",
16
16
  "morgan": "1.10.0",
17
- "ws": "8.3.0"
17
+ "ws": "8.4.2"
18
18
  },
19
19
  "description": "Interaction helper for your Lightning Network daemon",
20
20
  "devDependencies": {
21
21
  "@alexbosworth/tap": "15.0.10",
22
22
  "@alexbosworth/node-fetch": "2.6.2",
23
- "async": "3.2.2",
24
- "asyncjs-util": "1.2.7",
23
+ "async": "3.2.3",
24
+ "asyncjs-util": "1.2.8",
25
25
  "bip66": "1.1.5",
26
26
  "bitcoinjs-lib": "6.0.1",
27
27
  "bn.js": "5.2.0",
28
- "ecpair": "1.0.1",
29
- "ln-docker-daemons": "2.1.0",
28
+ "ecpair": "2.0.1",
29
+ "ln-docker-daemons": "2.2.0",
30
30
  "portfinder": "1.0.28",
31
31
  "psbt": "1.1.10",
32
32
  "rimraf": "3.0.2",
33
- "secp256k1": "4.0.2",
33
+ "secp256k1": "4.0.3",
34
+ "tiny-secp256k1": "2.1.2",
34
35
  "uuid": "8.3.2",
35
36
  "varuint-bitcoin": "1.1.2"
36
37
  },
37
38
  "engines": {
38
- "node": ">=12"
39
+ "node": ">=12.20"
39
40
  },
40
41
  "keywords": [
41
42
  "bitcoin",
@@ -54,5 +55,5 @@
54
55
  "scripts": {
55
56
  "test": "echo $DOCKER_LND_VERSION && tap -j 2 --branches=1 --functions=1 --lines=1 --statements=1 -t 200 test/autopilotrpc-integration/*.js test/chainrpc-integration/*.js test/integration/*.js test/invoicesrpc-integration/*.js test/routerrpc-integration/*.js test/signerrpc-integration/*.js test/tower_clientrpc-integration/*.js test/tower_serverrpc-integration/*.js test/walletrpc-integration/*.js"
56
57
  },
57
- "version": "53.1.2"
58
+ "version": "53.4.1"
58
59
  }
@@ -0,0 +1,144 @@
1
+ const {once} = require('events');
2
+
3
+ const asyncEach = require('async/each');
4
+ const asyncRetry = require('async/retry');
5
+ const {extractTransaction} = require('psbt');
6
+ const {spawnLightningCluster} = require('ln-docker-daemons');
7
+ const {test} = require('@alexbosworth/tap');
8
+
9
+ const {addPeer} = require('./../../');
10
+ const {broadcastChainTransaction} = require('./../../');
11
+ const {createCluster} = require('./../macros');
12
+ const {delay} = require('./../macros');
13
+ const {deletePendingChannel} = require('./../../');
14
+ const {fundPendingChannels} = require('./../../');
15
+ const {fundPsbt} = require('./../../');
16
+ const {getChainBalance} = require('./../../');
17
+ const {getChannels} = require('./../../');
18
+ const {getLockedUtxos} = require('./../../');
19
+ const {getPendingChannels} = require('./../../');
20
+ const {openChannels} = require('./../../');
21
+ const {signPsbt} = require('./../../');
22
+ const {unlockUtxo} = require('./../../');
23
+
24
+ const capacity = 1e6;
25
+ const count = 100;
26
+ const interval = 100;
27
+ const race = promises => Promise.race(promises);
28
+ const size = 3;
29
+ const timeout = 1000 * 5;
30
+ const times = 200;
31
+
32
+ // Forfeiting a pending channel should remove the pending channel
33
+ test(`Forfeit pending channel`, async ({end, equal}) => {
34
+ const {kill, nodes} = await spawnLightningCluster({size});
35
+
36
+ const [control, target, remote] = nodes;
37
+
38
+ const {generate, lnd} = control;
39
+
40
+ try {
41
+ await control.generate({count});
42
+
43
+ await asyncEach([target, remote], async node => {
44
+ return await addPeer({lnd, public_key: node.id, socket: node.socket});
45
+ });
46
+
47
+ const channels = [{capacity, partner_public_key: target.id}];
48
+
49
+ // Propose a channel to target
50
+ const proposeToTarget = await asyncRetry({interval, times}, async () => {
51
+ return await race([
52
+ delay(timeout),
53
+ openChannels({channels, lnd, is_avoiding_broadcast: true}),
54
+ ]);
55
+ });
56
+
57
+ // Setup funding for the target
58
+ const fundTarget = await fundPsbt({lnd, outputs: proposeToTarget.pending});
59
+
60
+ // Sign the funding to the target
61
+ const signTarget = await signPsbt({lnd, psbt: fundTarget.psbt});
62
+
63
+ // Fund the target channel
64
+ await fundPendingChannels({
65
+ lnd,
66
+ channels: proposeToTarget.pending.map(n => n.id),
67
+ funding: signTarget.psbt,
68
+ });
69
+
70
+ await asyncEach((await getLockedUtxos({lnd})).utxos, async utxo => {
71
+ return await unlockUtxo({
72
+ lnd,
73
+ id: utxo.lock_id,
74
+ transaction_id: utxo.transaction_id,
75
+ transaction_vout: utxo.transaction_vout,
76
+ });
77
+ });
78
+
79
+ // Propose a channel to remote
80
+ const proposeToRemote = await asyncRetry({interval, times}, async () => {
81
+ return await race([
82
+ delay(timeout),
83
+ openChannels({lnd,
84
+ channels: [{capacity, partner_public_key: remote.id}],
85
+ is_avoiding_broadcast: true,
86
+ }),
87
+ ]);
88
+ });
89
+
90
+ // Setup funding for the remote, using the same inputs
91
+ const fundRemote = await fundPsbt({
92
+ lnd,
93
+ inputs: fundTarget.inputs,
94
+ outputs: proposeToRemote.pending
95
+ });
96
+
97
+ // Sign the funding to the target
98
+ const signRemote = await signPsbt({lnd, psbt: fundRemote.psbt});
99
+
100
+ // Fund the remote channel
101
+ await fundPendingChannels({
102
+ lnd,
103
+ channels: proposeToRemote.pending.map(n => n.id),
104
+ funding: signRemote.psbt,
105
+ });
106
+
107
+ const {transaction} = extractTransaction({psbt: signRemote.psbt});
108
+
109
+ await broadcastChainTransaction({lnd, transaction});
110
+
111
+ const channel = await asyncRetry({interval, times}, async () => {
112
+ const [channel] = (await getChannels({lnd})).channels;
113
+
114
+ if (!!channel) {
115
+ return channel;
116
+ }
117
+
118
+ await generate({});
119
+
120
+ throw new Error('ExpectedNewChannelCreated');
121
+ });
122
+
123
+ const [pending] = (await getPendingChannels({lnd})).pending_channels;
124
+
125
+ const stuckTx = extractTransaction({psbt: signTarget.psbt});
126
+
127
+ await deletePendingChannel({
128
+ lnd,
129
+ confirmed_transaction: transaction,
130
+ pending_transaction: stuckTx.transaction,
131
+ pending_transaction_vout: pending.transaction_vout,
132
+ });
133
+
134
+ const [stillPending] = (await getPendingChannels({lnd})).pending_channels;
135
+
136
+ equal(stillPending, undefined, 'Conflicting pending channel deleted');
137
+ } catch (err) {
138
+ equal(err, null, 'No error is expected');
139
+ } finally {
140
+ await kill({});
141
+ }
142
+
143
+ return end();
144
+ });
@@ -1,13 +1,15 @@
1
+ const asyncEach = require('async/each');
1
2
  const {spawnLightningCluster} = require('ln-docker-daemons');
2
3
  const {test} = require('@alexbosworth/tap');
3
4
 
5
+ const {cancelHodlInvoice} = require('./../../');
4
6
  const {createInvoice} = require('./../../');
5
7
  const {getInvoices} = require('./../../');
6
8
 
7
9
  const limit = 1;
8
10
 
9
11
  // createInvoice should result in a created invoice
10
- test(`Create an invoice`, async ({end, equal}) => {
12
+ test(`Create an invoice`, async ({end, equal, strictSame}) => {
11
13
  const {kill, nodes} = await spawnLightningCluster({});
12
14
 
13
15
  try {
@@ -48,6 +50,16 @@ test(`Create an invoice`, async ({end, equal}) => {
48
50
  equal(invoice.secret, expected.secret, 'Payment secret');
49
51
  equal(invoice.tokens, expected.tokens, 'Tokens');
50
52
  });
53
+
54
+ const reversed = invoices.slice().reverse();
55
+
56
+ await asyncEach(reversed.filter((n, i) => !!i), async (invoice) => {
57
+ return await cancelHodlInvoice({lnd, id: invoice.id});
58
+ });
59
+
60
+ const unconfirmed = await getInvoices({limit, lnd, is_unconfirmed: true});
61
+
62
+ strictSame(unconfirmed, thirdPage, 'Pending invoices are ignored');
51
63
  } catch (err) {
52
64
  equal(err, null, 'No error is expected');
53
65
  }
@@ -51,6 +51,7 @@ test(`Get pending channels`, async ({end, equal}) => {
51
51
  equal(channel.pending_balance, 980950, 'Waiting on balance');
52
52
  }
53
53
 
54
+ equal(channel.capacity, 1000000, 'Got channel capacity');
54
55
  equal(channel.close_transaction_id, undefined, 'No close tx id');
55
56
  equal(channel.is_active, false, 'Ended');
56
57
  equal(channel.is_closing, true, 'Closing');
@@ -68,6 +68,7 @@ test(`Get pending channels`, async ({end, equal}) => {
68
68
  equal(pendingOpen.transaction_weight, 724, 'Channel tx weight');
69
69
  }
70
70
 
71
+ equal(pendingOpen.capacity, 1000000, 'Got channel opening capacity');
71
72
  equal(pendingOpen.close_transaction_id, undefined, 'Not closing');
72
73
  equal(pendingOpen.is_active, false, 'Not active yet');
73
74
  equal(pendingOpen.is_closing, false, 'Not closing yet');
@@ -111,6 +112,7 @@ test(`Get pending channels`, async ({end, equal}) => {
111
112
  equal(waitClose.pending_balance, 980950, 'Waiting on balance');
112
113
  }
113
114
 
115
+ equal(waitClose.capacity, 1000000, 'Got channel closing capacity');
114
116
  equal(waitClose.close_transaction_id, undefined, 'Waiting for close tx');
115
117
  equal(waitClose.is_active, false, 'Not active yet');
116
118
  equal(waitClose.is_closing, true, 'Channel is closing');
@@ -166,6 +168,7 @@ test(`Get pending channels`, async ({end, equal}) => {
166
168
  equal(forceClose.pending_balance, 980950, 'Waiting on balance');
167
169
  }
168
170
 
171
+ equal(forceClose.capacity, 1000000, 'Got channel close capacity');
169
172
  equal(forceClose.close_transaction_id, channelClose.transaction_id, 'Txid');
170
173
  equal(forceClose.is_active, false, 'Not active anymore');
171
174
  equal(forceClose.is_closing, true, 'Channel is force closing');
@@ -359,6 +359,7 @@ test(`Propose a channel with a coop delay`, async ({end, equal, ok}) => {
359
359
  equal(incoming.transaction_weight, 724, 'Funding tx weight');
360
360
  }
361
361
 
362
+ equal(incoming.capacity, 1000000, 'Incoming capacity is defined');
362
363
  equal(incoming.close_transaction_id, undefined, 'Not a closing tx');
363
364
  equal(incoming.is_active, false, 'Not active yet');
364
365
  equal(incoming.is_closing, false, 'Channel is not closing');
@@ -105,14 +105,16 @@ test(`Subscribe to open requests`, async ({end, equal, fail, ok}) => {
105
105
  });
106
106
 
107
107
  try {
108
- await openChannel({
109
- lnd: target.lnd,
110
- chain_fee_tokens_per_vbyte: defaultFee,
111
- give_tokens: giftTokens,
112
- is_private: true,
113
- local_tokens: channelCapacityTokens,
114
- partner_public_key: control.id,
115
- socket: control.socket,
108
+ await asyncRetry({interval, times}, async () => {
109
+ return await openChannel({
110
+ lnd: target.lnd,
111
+ chain_fee_tokens_per_vbyte: defaultFee,
112
+ give_tokens: giftTokens,
113
+ is_private: true,
114
+ local_tokens: channelCapacityTokens,
115
+ partner_public_key: control.id,
116
+ socket: control.socket,
117
+ });
116
118
  });
117
119
  } catch (err) {
118
120
  equal(err, null, 'Expected no error when a channel is accepted');
@@ -1,5 +1,6 @@
1
1
  const {once} = require('events');
2
2
 
3
+ const asyncRetry = require('async/retry');
3
4
  const {spawnLightningCluster} = require('ln-docker-daemons');
4
5
  const {test} = require('@alexbosworth/tap');
5
6
 
@@ -9,7 +10,9 @@ const {removePeer} = require('./../../');
9
10
  const {subscribeToPeers} = require('./../../');
10
11
 
11
12
  const all = promise => Promise.all(promise);
13
+ const interval = 10;
12
14
  const size = 2;
15
+ const times = 1000;
13
16
 
14
17
  // Subscribing to peer events should trigger reception of peer status changes
15
18
  test(`Subscribe to peers`, async ({end, equal}) => {
@@ -21,7 +24,9 @@ test(`Subscribe to peers`, async ({end, equal}) => {
21
24
 
22
25
  sub.on('error', () => {});
23
26
 
24
- await addPeer({lnd, public_key: target.id, socket: target.socket});
27
+ await asyncRetry({interval, times}, async () => {
28
+ await addPeer({lnd, public_key: target.id, socket: target.socket});
29
+ });
25
30
 
26
31
  const disconnect = removePeer({lnd, public_key: target.id});
27
32
  const receiveDisconnect = once(sub, 'disconnected');
@@ -32,7 +37,9 @@ test(`Subscribe to peers`, async ({end, equal}) => {
32
37
 
33
38
  equal(disconnected.public_key, target.id, 'Got d/c event');
34
39
 
35
- const connect = addPeer({lnd, public_key: target.id, socket: target.socket});
40
+ const connect = asyncRetry({interval, times}, async () => {
41
+ return addPeer({lnd, public_key: target.id, socket: target.socket});
42
+ });
36
43
 
37
44
  const receiveConnectMessage = once(sub, 'connected');
38
45
 
@@ -2,12 +2,11 @@ const {join} = require('path');
2
2
  const {spawn} = require('child_process');
3
3
 
4
4
  const asyncAuto = require('async/auto');
5
- const {ECPair} = require('ecpair');
6
5
  const openPortFinder = require('portfinder');
7
6
  const {networks} = require('bitcoinjs-lib');
8
7
  const {payments} = require('bitcoinjs-lib');
8
+ const tinysecp = require('tiny-secp256k1');
9
9
 
10
- const {fromPublicKey} = ECPair;
11
10
  const knownDaemons = ['btcd'];
12
11
  const localhost = '127.0.0.1';
13
12
  const notFoundIndex = -1;
@@ -37,6 +36,9 @@ const unableToStartServer = /Unable.to.start.server/;
37
36
  */
38
37
  module.exports = (args, cbk) => {
39
38
  return asyncAuto({
39
+ // Import ECPair library
40
+ ecp: async () => (await import('ecpair')).ECPairFactory(tinysecp),
41
+
40
42
  // Check arguments
41
43
  validate: cbk => {
42
44
  if (knownDaemons.indexOf(args.daemon) === notFoundIndex) {
@@ -85,11 +87,16 @@ module.exports = (args, cbk) => {
85
87
  }],
86
88
 
87
89
  // Spin up the chain daemon
88
- spawnDaemon: ['listenPort', 'rpcPort', ({listenPort, rpcPort}, cbk) => {
90
+ spawnDaemon: [
91
+ 'ecp',
92
+ 'listenPort',
93
+ 'rpcPort',
94
+ ({ecp, listenPort, rpcPort}, cbk) =>
95
+ {
89
96
  const miningKey = Buffer.from(args.mining_public_key, 'hex');
90
97
  const network = networks.testnet;
91
98
 
92
- const pubkey = fromPublicKey(miningKey, network).publicKey;
99
+ const pubkey = ecp.fromPublicKey(miningKey, network).publicKey;
93
100
 
94
101
  const daemon = spawn(args.daemon, [
95
102
  '--datadir', args.dir,
@@ -2,13 +2,13 @@ const {encode} = require('varuint-bitcoin');
2
2
 
3
3
  const {address} = require('bitcoinjs-lib');
4
4
  const {crypto} = require('bitcoinjs-lib');
5
- const {ECPair} = require('ecpair');
6
5
  const {networks} = require('bitcoinjs-lib');
7
6
  const {payments} = require('bitcoinjs-lib');
8
7
  const {script} = require('bitcoinjs-lib');
9
- const scriptBufAsScript = require('./script_buffers_as_script');
10
8
  const {Transaction} = require('bitcoinjs-lib');
11
9
 
10
+ const scriptBufAsScript = require('./script_buffers_as_script');
11
+
12
12
  const defaultNetwork = 'testnet';
13
13
  const encodeSignature = script.signature.encode;
14
14
  const hexBase = 16;
@@ -20,6 +20,7 @@ const {toOutputScript} = address;
20
20
 
21
21
  {
22
22
  destination: <Destination Address String>
23
+ ecp: <ECPair Object>
23
24
  fee: <Fee Tokens To Remove From Spend Number>
24
25
  private_key: <WIF Serialized Private Key String>
25
26
  spend_transaction_id: <Transaction Id to Spend Hex String>
@@ -32,11 +33,15 @@ const {toOutputScript} = address;
32
33
  transaction: <Transaction Hex Serialized String>
33
34
  }
34
35
  */
35
- module.exports = (args, cbk) => {
36
+ module.exports = args => {
36
37
  if (!args.destination) {
37
38
  throw new Error('ExpectedDestinationAddressToSendTokensTo');
38
39
  }
39
40
 
41
+ if (!args.ecp) {
42
+ throw new Error('ExpectedEcpairObjectToChainSendTransaction');
43
+ }
44
+
40
45
  if (!args.private_key) {
41
46
  throw new Error('ExpectedPrivateKeyToAuthorizeSend');
42
47
  }
@@ -55,7 +60,7 @@ module.exports = (args, cbk) => {
55
60
 
56
61
  const network = networks[defaultNetwork];
57
62
 
58
- const keyPair = ECPair.fromWIF(args.private_key, network);
63
+ const keyPair = args.ecp.fromWIF(args.private_key, network);
59
64
  const outputScript = toOutputScript(args.destination, network);
60
65
  const tx = new Transaction();
61
66
 
@@ -6,9 +6,9 @@ const {spawn} = require('child_process');
6
6
  const asyncAuto = require('async/auto');
7
7
  const asyncMapSeries = require('async/mapSeries');
8
8
  const asyncRetry = require('async/retry');
9
- const {ECPair} = require('ecpair');
10
9
  const {networks} = require('bitcoinjs-lib');
11
10
  const openPortFinder = require('portfinder');
11
+ const tinysecp = require('tiny-secp256k1');
12
12
 
13
13
  const {changePassword} = require('./../../');
14
14
  const {createSeed} = require('./../../');
@@ -53,6 +53,9 @@ const times = 100;
53
53
  */
54
54
  module.exports = ({network}, cbk) => {
55
55
  return asyncAuto({
56
+ // Import ECPair library
57
+ ecp: async () => (await import('ecpair')).ECPairFactory(tinysecp),
58
+
56
59
  // Find open ports for the listen, REST and RPC ports
57
60
  getPorts: cbk => {
58
61
  return asyncMapSeries(['listen', 'rest', 'rpc'], (_, cbk) => {
@@ -77,14 +80,14 @@ module.exports = ({network}, cbk) => {
77
80
  },
78
81
 
79
82
  // Make a private key for mining rewards
80
- miningKey: cbk => {
81
- const keyPair = ECPair.makeRandom({network: networks.testnet});
83
+ miningKey: ['ecp', ({ecp}, cbk) => {
84
+ const keyPair = ecp.makeRandom({network: networks.testnet});
82
85
 
83
86
  return cbk(null, {
84
87
  private_key: keyPair.toWIF(),
85
88
  public_key: keyPair.publicKey.toString('hex'),
86
89
  });
87
- },
90
+ }],
88
91
 
89
92
  // Spawn a backing chain daemon for lnd
90
93
  spawnChainDaemon: ['miningKey', ({miningKey}, cbk) => {
@@ -3,6 +3,7 @@ const {promisify} = require('util');
3
3
  const asyncAuto = require('async/auto');
4
4
  const asyncEach = require('async/each');
5
5
  const asyncRetry = require('async/retry');
6
+ const tinysecp = require('tiny-secp256k1');
6
7
 
7
8
  const {addPeer} = require('./../../');
8
9
  const chainSendTransaction = require('./chain_send_transaction');
@@ -62,6 +63,9 @@ const tokens = 50e8;
62
63
  */
63
64
  module.exports = (args, cbk) => {
64
65
  return asyncAuto({
66
+ // Import ECPair library
67
+ ecp: async () => (await import('ecpair')).ECPairFactory(tinysecp),
68
+
65
69
  // Create control lnd
66
70
  control: cbk => {
67
71
  return spawnLnd({
@@ -225,11 +229,13 @@ module.exports = (args, cbk) => {
225
229
  funding: [
226
230
  'control',
227
231
  'controlChainAddress',
232
+ 'ecp',
228
233
  'generateBlocks',
229
234
  'targetChainAddress',
230
235
  ({
231
236
  control,
232
237
  controlChainAddress,
238
+ ecp,
233
239
  generateBlocks,
234
240
  targetChainAddress,
235
241
  },
@@ -243,6 +249,7 @@ module.exports = (args, cbk) => {
243
249
  const [targetCoinbase] = targetBlock.transaction_ids;
244
250
 
245
251
  const controlChainSend = chainSendTransaction({
252
+ ecp,
246
253
  tokens,
247
254
  destination: controlChainAddress.address,
248
255
  fee: defaultFee,
@@ -252,6 +259,7 @@ module.exports = (args, cbk) => {
252
259
  });
253
260
 
254
261
  const targetChainSend = chainSendTransaction({
262
+ ecp,
255
263
  tokens,
256
264
  destination: targetChainAddress.address,
257
265
  fee: defaultFee,
@@ -2,14 +2,13 @@ const asyncAuto = require('async/auto');
2
2
  const asyncMap = require('async/map');
3
3
  const asyncTimesSeries = require('async/timesSeries');
4
4
  const asyncRetry = require('async/retry');
5
- const {ECPair} = require('ecpair');
6
5
  const {networks} = require('bitcoinjs-lib');
7
6
  const {payments} = require('bitcoinjs-lib');
8
7
  const {returnResult} = require('asyncjs-util');
8
+ const tinysecp = require('tiny-secp256k1');
9
9
 
10
10
  const rpc = require('./rpc');
11
11
 
12
- const {fromPublicKey} = ECPair;
13
12
  const interval = retryCount => 2000 * Math.random();
14
13
  const {p2pkh} = payments;
15
14
  const retryTimes = 50;
@@ -35,6 +34,9 @@ const retryTimes = 50;
35
34
  module.exports = ({cert, chain, count, host, key, pass, port, user}, cbk) => {
36
35
  return new Promise((resolve, reject) => {
37
36
  return asyncAuto({
37
+ // Import ECPair library
38
+ ecp: async () => (await import('ecpair')).ECPairFactory(tinysecp),
39
+
38
40
  // Check arguments
39
41
  validate: cbk => {
40
42
  if (!host) {
@@ -57,7 +59,7 @@ module.exports = ({cert, chain, count, host, key, pass, port, user}, cbk) => {
57
59
  },
58
60
 
59
61
  // Generate blocks
60
- generate: ['validate', ({}, cbk) => {
62
+ generate: ['ecp', 'validate', ({ecp}, cbk) => {
61
63
  let cmd;
62
64
  let params;
63
65
 
@@ -66,7 +68,7 @@ module.exports = ({cert, chain, count, host, key, pass, port, user}, cbk) => {
66
68
  const miningKey = Buffer.from(key, 'hex');
67
69
  const network = networks.testnet;
68
70
 
69
- const pubkey = fromPublicKey(miningKey, network).publicKey;
71
+ const pubkey = ecp.fromPublicKey(miningKey, network).publicKey;
70
72
 
71
73
  cmd = 'generatetoaddress';
72
74
  params = [[count].length, p2pkh({network, pubkey}).address];
@@ -7,9 +7,9 @@ const asyncAuto = require('async/auto');
7
7
  const asyncMap = require('async/map');
8
8
  const asyncMapSeries = require('async/mapSeries');
9
9
  const asyncRetry = require('async/retry');
10
- const {ECPair} = require('ecpair');
11
10
  const {networks} = require('bitcoinjs-lib');
12
11
  const openPortFinder = require('portfinder');
12
+ const tinysecp = require('tiny-secp256k1');
13
13
 
14
14
  const {authenticatedLndGrpc} = require('./../../');
15
15
  const {createSeed} = require('./../../');
@@ -79,6 +79,9 @@ const times = 30;
79
79
  */
80
80
  module.exports = (args, cbk) => {
81
81
  return asyncAuto({
82
+ // Import ECPair library
83
+ ecp: async () => (await import('ecpair')).ECPairFactory(tinysecp),
84
+
82
85
  // Find open ports for the listen, REST and RPC ports
83
86
  getPorts: cbk => {
84
87
  return asyncRetry({interval: n => round(random() * 100), times: 1000}, cbk => {
@@ -112,14 +115,14 @@ module.exports = (args, cbk) => {
112
115
  },
113
116
 
114
117
  // Make a private key for mining rewards
115
- miningKey: cbk => {
116
- const keyPair = ECPair.makeRandom({network: networks.testnet});
118
+ miningKey: ['ecp', ({ecp}, cbk) => {
119
+ const keyPair = ecp.makeRandom({network: networks.testnet});
117
120
 
118
121
  return cbk(null, {
119
122
  private_key: keyPair.toWIF(),
120
123
  public_key: keyPair.publicKey.toString('hex'),
121
124
  });
122
- },
125
+ }],
123
126
 
124
127
  // Spawn a backing chain daemon for lnd
125
128
  spawnChainDaemon: ['miningKey', ({miningKey}, cbk) => {
@@ -103,7 +103,7 @@ test(`Pay with multiple paths`, async ({end, equal, rejects, strictSame}) => {
103
103
  total_mtokens: parsed.mtokens,
104
104
  });
105
105
 
106
- // Pay using routes. Multiple channels must be used too avoid tempChanFail
106
+ // Pay using routes. Multiple channels must be used to avoid tempChanFail
107
107
  try {
108
108
  const routes = [route1.route, route2.route];
109
109
 
@@ -1,4 +1,5 @@
1
1
  const {test} = require('@alexbosworth/tap');
2
+ const tinysecp = require('tiny-secp256k1');
2
3
 
3
4
  const {broadcastChainTransaction} = require('./../../');
4
5
  const {chainSendTransaction} = require('./../macros');
@@ -32,6 +33,7 @@ test(`Send chain transaction`, async ({end, equal}) => {
32
33
  fee,
33
34
  tokens,
34
35
  destination: (await createChainAddress({format, lnd})).address,
36
+ ecp: (await import('ecpair')).ECPairFactory(tinysecp),
35
37
  private_key: node.mining_key,
36
38
  spend_transaction_id: coinbaseTransactionId,
37
39
  spend_vout: defaultVout,
@@ -1,4 +1,5 @@
1
1
  const {test} = require('@alexbosworth/tap');
2
+ const tinysecp = require('tiny-secp256k1');
2
3
 
3
4
  const {broadcastChainTransaction} = require('./../../');
4
5
  const {chainSendTransaction} = require('./../macros');
@@ -31,6 +32,7 @@ test(`Request chain fee increase`, async ({end, equal}) => {
31
32
  fee,
32
33
  tokens,
33
34
  destination: (await createChainAddress({format, lnd})).address,
35
+ ecp: (await import('ecpair')).ECPairFactory(tinysecp),
34
36
  private_key: node.mining_key,
35
37
  spend_transaction_id: coinbaseTransactionId,
36
38
  spend_vout: defaultVout,