lightning 5.9.0 → 5.10.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,14 @@
1
1
  # Versions
2
2
 
3
- ## 5.9.0
3
+ ## 5.10.1
4
+
5
+ - Always use TLV when paying along routes
6
+
7
+ ## 5.10.0
8
+
9
+ - `signTransaction`: Add `spending` attribute for specifying external inputs
10
+
11
+ ## 5.9.1
4
12
 
5
13
  - `createChainAddress`: Add support for creating P2TR addresses
6
14
  - `getUtxos`: Add support for showing P2TR address types
@@ -119,7 +119,11 @@ message SpendRequest {
119
119
  /*
120
120
  The outpoint for which we should request a spend notification for. If set to
121
121
  a zero outpoint, then the spend notification will be requested for the
122
- script instead.
122
+ script instead. A zero or nil outpoint is not supported for Taproot spends
123
+ because the output script cannot reliably be computed from the witness alone
124
+ and the spent output script is not always available in the rescan context.
125
+ So an outpoint must _always_ be specified when registering a spend
126
+ notification for a Taproot output.
123
127
  */
124
128
  Outpoint outpoint = 1;
125
129
 
@@ -129,8 +129,11 @@ message SignDescriptor {
129
129
  bytes double_tweak = 3;
130
130
 
131
131
  /*
132
- The full script required to properly redeem the output. This field will
133
- only be populated if a p2wsh or a p2sh output is being signed.
132
+ The full script required to properly redeem the output. This field will
133
+ only be populated if a p2tr, p2wsh or a p2sh output is being signed. In case
134
+ taproot_key_spend is set to true then this value must correspond to the
135
+ taproot root hash (in case of a tapscript output) or the tap hashed internal
136
+ public key (in case of a BIP-0086 output).
134
137
  */
135
138
  bytes witness_script = 4;
136
139
 
@@ -150,6 +153,14 @@ message SignDescriptor {
150
153
  The target input within the transaction that should be signed.
151
154
  */
152
155
  int32 input_index = 8;
156
+
157
+ /*
158
+ Indicates that this should produce a signature that can be used for the key
159
+ spend path of a taproot input. This requires the witness_script field to be
160
+ set to the taproot root hash (in case of a tapscript output) or the tap
161
+ hashed internal public key (in case of a BIP-0086 output).
162
+ */
163
+ bool taproot_key_spend = 9;
153
164
  }
154
165
 
155
166
  message SignReq {
@@ -158,6 +169,12 @@ message SignReq {
158
169
 
159
170
  // A set of sign descriptors, for each input to be signed.
160
171
  repeated SignDescriptor sign_descs = 2;
172
+
173
+ /*
174
+ The full list of UTXO information for each of the inputs being spent. This
175
+ is required when spending one or more taproot (SegWit v1) outputs.
176
+ */
177
+ repeated TxOut prev_outputs = 3;
161
178
  }
162
179
 
163
180
  message SignResp {
@@ -334,6 +334,7 @@ enum AddressType {
334
334
  WITNESS_PUBKEY_HASH = 1;
335
335
  NESTED_WITNESS_PUBKEY_HASH = 2;
336
336
  HYBRID_NESTED_WITNESS_PUBKEY_HASH = 3;
337
+ TAPROOT_PUBKEY = 4;
337
338
  }
338
339
  message Account {
339
340
  // The name used to identify the account.
@@ -13,7 +13,7 @@ const type = 'default';
13
13
 
14
14
  Requires `address:write` permission
15
15
 
16
- LND 0.14.3 below do not support p2tr addresses
16
+ LND 0.14.3 and below do not support p2tr addresses
17
17
 
18
18
  {
19
19
  [format]: <Receive Address Type String> // "np2wpkh" || "p2tr" || "p2wpkh"
@@ -25,7 +25,7 @@ const type = 'chain';
25
25
 
26
26
  {
27
27
  [bech32_address]: <Address String>
28
- lnd: <Chain RPC LND API Object>
28
+ lnd: <Authenticated LND API Object>
29
29
  [min_confirmations]: <Minimum Confirmations Number>
30
30
  min_height: <Minimum Transaction Inclusion Blockchain Height Number>
31
31
  [output_script]: <Output Script Hex String>
@@ -5,19 +5,27 @@ const scriptFromChainAddress = require('./script_from_chain_address');
5
5
 
6
6
  const bufferAsHex = buffer => buffer.toString('hex');
7
7
  const dummyTxId = Buffer.alloc(32).toString('hex');
8
+ const events = ['confirmation', 'reorg'];
8
9
  const hexAsBuffer = hex => Buffer.from(hex, 'hex');
9
10
  const {isBuffer} = Buffer;
10
11
  const method = 'registerSpendNtfn';
12
+ const shutDownMessage = 'chain notifier shutting down';
13
+ const sumOf = arr => arr.reduce((sum, n) => sum + n, Number());
11
14
  const type = 'chain';
12
15
 
13
16
  /** Subscribe to confirmations of a spend
14
17
 
15
18
  A chain address or raw output script is required
16
19
 
20
+ When specifying a P2TR output script, `transaction_id` and `transaction_vout`
21
+ are required.
22
+
17
23
  Requires LND built with `chainrpc` build tag
18
24
 
19
25
  Requires `onchain:read` permission
20
26
 
27
+ Subscribing to P2TR outputs is not supported in LND 0.14.3 and below
28
+
21
29
  {
22
30
  [bech32_address]: <Bech32 P2WPKH or P2WSH Address String>
23
31
  lnd: <Authenticated LND API Object>
@@ -74,11 +82,33 @@ module.exports = args => {
74
82
  script: hexAsBuffer(script || args.output_script),
75
83
  });
76
84
 
85
+ // Cancel the subscription when all listeners are removed
86
+ eventEmitter.on('removeListener', () => {
87
+ const listenerCounts = events.map(n => eventEmitter.listenerCount(n));
88
+
89
+ // Exit early when there are still listeners
90
+ if (!!sumOf(listenerCounts)) {
91
+ return;
92
+ }
93
+
94
+ subscription.cancel();
95
+
96
+ return;
97
+ });
98
+
77
99
  subscription.on('end', () => eventEmitter.emit('end'));
78
100
  subscription.on('status', n => eventEmitter.emit('status', n));
79
101
 
80
102
  subscription.on('error', err => {
81
- eventEmitter.emit('error', new Error('UnexpectedErrInSpendSubscription'));
103
+ if (err.details === shutDownMessage) {
104
+ subscription.removeAllListeners();
105
+ }
106
+
107
+ if (!eventEmitter.listenerCount('error')) {
108
+ return;
109
+ }
110
+
111
+ eventEmitter.emit('error', err);
82
112
 
83
113
  return;
84
114
  });
@@ -3,16 +3,24 @@ const {returnResult} = require('asyncjs-util');
3
3
 
4
4
  const {isLnd} = require('./../../lnd_requests');
5
5
 
6
+ const bufferAsHex = buffer => buffer.toString('hex');
7
+ const hexAsBuffer = hex => Buffer.from(hex, 'hex');
6
8
  const {isArray} = Array;
9
+ const method = 'signOutputRaw';
7
10
  const notFound = -1;
11
+ const type = 'signer';
8
12
  const unimplementedError = '12 UNIMPLEMENTED: unknown service signrpc.Signer';
9
13
 
10
14
  /** Sign transaction
11
15
 
16
+ `spending` is required for non-internal inputs for a Taproot signature
17
+
12
18
  Requires LND built with `signrpc` build tag
13
19
 
14
20
  Requires `signer:generate` permission
15
21
 
22
+ `spending` is not supported in LND 0.14.3 and below
23
+
16
24
  {
17
25
  inputs: [{
18
26
  key_family: <Key Family Number>
@@ -24,6 +32,10 @@ const unimplementedError = '12 UNIMPLEMENTED: unknown service signrpc.Signer';
24
32
  witness_script: <Witness Script Hex String>
25
33
  }]
26
34
  lnd: <Authenticated LND API Object>
35
+ [spending]: [{
36
+ output_script: <Non-Internal Spend Output Script Hex String>
37
+ output_tokens: <Non-Internal Spend Output Tokens Number>
38
+ }]
27
39
  transaction: <Unsigned Transaction Hex String>
28
40
  }
29
41
 
@@ -32,7 +44,7 @@ const unimplementedError = '12 UNIMPLEMENTED: unknown service signrpc.Signer';
32
44
  signatures: [<Signature Hex String>]
33
45
  }
34
46
  */
35
- module.exports = ({inputs, lnd, transaction}, cbk) => {
47
+ module.exports = ({inputs, lnd, spending, transaction}, cbk) => {
36
48
  return new Promise((resolve, reject) => {
37
49
  return asyncAuto({
38
50
  // Check arguments
@@ -41,7 +53,7 @@ module.exports = ({inputs, lnd, transaction}, cbk) => {
41
53
  return cbk([400, 'ExpectedInputsToSignTransaction']);
42
54
  }
43
55
 
44
- if (!isLnd({lnd, method: 'signOutputRaw', type: 'signer'})) {
56
+ if (!isLnd({lnd, method, type})) {
45
57
  return cbk([400, 'ExpectedAuthenticatedLndToSignTransaction']);
46
58
  }
47
59
 
@@ -54,8 +66,12 @@ module.exports = ({inputs, lnd, transaction}, cbk) => {
54
66
 
55
67
  // Get signatures
56
68
  signTransaction: ['validate', ({}, cbk) => {
57
- return lnd.signer.signOutputRaw({
58
- raw_tx_bytes: Buffer.from(transaction, 'hex'),
69
+ return lnd[type][method]({
70
+ prev_outputs: [].concat(inputs).concat(spending || []).map(utxo => ({
71
+ pk_script: hexAsBuffer(utxo.output_script),
72
+ value: utxo.output_tokens,
73
+ })),
74
+ raw_tx_bytes: hexAsBuffer(transaction),
59
75
  sign_descs: inputs.map(input => ({
60
76
  input_index: input.vin,
61
77
  key_desc: {
@@ -65,11 +81,11 @@ module.exports = ({inputs, lnd, transaction}, cbk) => {
65
81
  },
66
82
  },
67
83
  output: {
68
- pk_script: Buffer.from(input.output_script, 'hex'),
84
+ pk_script: hexAsBuffer(input.output_script),
69
85
  value: input.output_tokens,
70
86
  },
71
87
  sighash: input.sighash,
72
- witness_script: Buffer.from(input.witness_script, 'hex'),
88
+ witness_script: hexAsBuffer(input.witness_script),
73
89
  })),
74
90
  },
75
91
  (err, res) => {
@@ -93,9 +109,7 @@ module.exports = ({inputs, lnd, transaction}, cbk) => {
93
109
  return cbk([503, 'ExpectedSignatureBuffersInSignResponse']);
94
110
  }
95
111
 
96
- return cbk(null, {
97
- signatures: res.raw_sigs.map(n => n.toString('hex'))
98
- });
112
+ return cbk(null, {signatures: res.raw_sigs.map(bufferAsHex)});
99
113
  });
100
114
  }],
101
115
  },
@@ -60,6 +60,7 @@ module.exports = args => {
60
60
  fee: millitokensAsTokens(args.fee_mtokens).toString(),
61
61
  fee_msat: args.fee_mtokens,
62
62
  pub_key: args.public_key,
63
+ tlv_payload: true,
63
64
  };
64
65
 
65
66
  // Exit early when there are no messages to encode in this hop
@@ -67,9 +68,6 @@ module.exports = args => {
67
68
  return hop;
68
69
  }
69
70
 
70
- // Set custom TLV payload records for this hop
71
- hop.tlv_payload = true;
72
-
73
71
  hop.custom_records = args.messages.reduce((tlv, n) => {
74
72
  tlv[n.type] = hexAsBuffer(n.value);
75
73
 
package/package.json CHANGED
@@ -7,24 +7,24 @@
7
7
  "url": "https://github.com/alexbosworth/lightning/issues"
8
8
  },
9
9
  "dependencies": {
10
- "@grpc/grpc-js": "1.6.1",
10
+ "@grpc/grpc-js": "1.6.2",
11
11
  "@grpc/proto-loader": "0.6.9",
12
12
  "@types/express": "4.17.13",
13
13
  "@types/node": "17.0.23",
14
14
  "@types/request": "2.48.8",
15
15
  "@types/ws": "8.5.3",
16
16
  "async": "3.2.3",
17
- "asyncjs-util": "1.2.8",
17
+ "asyncjs-util": "1.2.9",
18
18
  "bitcoinjs-lib": "6.0.1",
19
19
  "bn.js": "5.2.0",
20
- "body-parser": "1.19.2",
21
- "bolt07": "1.8.0",
22
- "bolt09": "0.2.2",
20
+ "body-parser": "1.20.0",
21
+ "bolt07": "1.8.1",
22
+ "bolt09": "0.2.3",
23
23
  "cbor": "8.1.0",
24
24
  "ecpair": "2.0.1",
25
25
  "express": "4.17.3",
26
- "invoices": "2.0.4",
27
- "psbt": "2.0.0",
26
+ "invoices": "2.0.5",
27
+ "psbt": "2.0.1",
28
28
  "tiny-secp256k1": "2.2.1",
29
29
  "type-fest": "2.12.2"
30
30
  },
@@ -59,5 +59,5 @@
59
59
  "directory": "test/typescript"
60
60
  },
61
61
  "types": "index.d.ts",
62
- "version": "5.9.0"
62
+ "version": "5.10.1"
63
63
  }
@@ -82,6 +82,8 @@ const tests = [
82
82
  ];
83
83
 
84
84
  tests.forEach(({args, description, error, expected}) => {
85
+ args.restart_delay_ms = 1;
86
+
85
87
  return test(description, async ({end, equal, match, strictSame, throws}) => {
86
88
  if (!!error) {
87
89
  throws(() => subscribeToInvoices(args), new Error(error), 'Got error');
@@ -39,6 +39,7 @@ const tests = [
39
39
  fee: '1',
40
40
  fee_msat: '1000',
41
41
  pub_key: 'public_key',
42
+ tlv_payload: true,
42
43
  },
43
44
  },
44
45
  {