paid-services 3.4.0 → 3.5.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.
@@ -0,0 +1,2 @@
1
+ bos
2
+ *.js
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Versions
2
2
 
3
+ ## Version 3.5.0
4
+
5
+ - `changeChannelCapacity`: Allow changing private/public status of channel
6
+
3
7
  ## Version 3.4.0
4
8
 
5
9
  - `changeChannelCapacity`: Fix broken preservation of channel announce status
@@ -24,6 +24,8 @@ const minNewLocalBalance = 0;
24
24
  const nonNegative = n => Math.max(0, n);
25
25
  const outputSize = 44;
26
26
  const positive = n => Math.max(1, n);
27
+ const privateType = 1;
28
+ const publicType = 0;
27
29
  const slowTarget = 1000;
28
30
  const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
29
31
  const sumOfTokens = arr => arr.reduce((sum, n) => sum + n.tokens, 0);
@@ -395,10 +397,37 @@ module.exports = ({ask, id, lnd}, cbk) => {
395
397
  ({amount}) => cbk(null, Number(amount)));
396
398
  }],
397
399
 
400
+ // Confirm or change the announce status of the replacement channel
401
+ askForPublicPrivate: [
402
+ 'askForDecrease',
403
+ 'askForIncrease',
404
+ 'channel',
405
+ ({channel}, cbk) =>
406
+ {
407
+ return ask({
408
+ choices: ['Public', 'Private'].map(type => {
409
+ const isPrivate = type === 'Private';
410
+
411
+ // Exit early when the type would be different
412
+ if (isPrivate !== channel.is_private) {
413
+ return type;
414
+ }
415
+
416
+ return `${type} (Keep Current Status)`;
417
+ }),
418
+ default: channel.is_private ? 'Private' : 'Public',
419
+ message: 'Channel type?',
420
+ name: 'type',
421
+ type: 'list',
422
+ },
423
+ ({type}) => cbk(null, {is_private: type === 'Private'}));
424
+ }],
425
+
398
426
  // Estimate the chain fee
399
427
  estimateChainFee: [
400
428
  'askForDecrease',
401
429
  'askForIncrease',
430
+ 'askForPublicPrivate',
402
431
  'channel',
403
432
  'getFeeRate',
404
433
  ({askForDecrease, askForIncrease, channel, getFeeRate}, cbk) =>
@@ -417,6 +446,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
417
446
 
418
447
  // Confirm chain fee payment estimate
419
448
  confirmFeeEstimate: [
449
+ 'askForPublicPrivate',
420
450
  'channel',
421
451
  'estimateChainFee',
422
452
  ({channel, estimateChainFee}, cbk) =>
@@ -437,6 +467,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
437
467
  details: [
438
468
  'askForDecrease',
439
469
  'askForIncrease',
470
+ 'askForPublicPrivate',
440
471
  'channel',
441
472
  'confirmFeeEstimate',
442
473
  'estimateChainFee',
@@ -444,6 +475,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
444
475
  ({
445
476
  askForDecrease,
446
477
  askForIncrease,
478
+ askForPublicPrivate,
447
479
  channel,
448
480
  confirmFeeEstimate,
449
481
  estimateChainFee,
@@ -478,6 +510,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
478
510
  channel: channel.id,
479
511
  decrease: !!askForDecrease ? sumOfTokens(askForDecrease) : undefined,
480
512
  increase: askForIncrease,
513
+ type: askForPublicPrivate.is_private ? privateType : publicType,
481
514
  });
482
515
 
483
516
  return cbk(null, {
@@ -491,7 +524,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
491
524
  fee_rate: channel.fee_rate,
492
525
  id: channel.id,
493
526
  increase: askForIncrease,
494
- is_private: channel.is_private,
527
+ is_private: askForPublicPrivate.is_private,
495
528
  open_transaction: channel.open_transaction,
496
529
  partner_csv_delay: channel.partner_csv_delay,
497
530
  partner_public_key: channel.partner_public_key,
@@ -1,3 +1,5 @@
1
+ const privateAsType = isPrivate => isPrivate ? 1 : 0;
2
+
1
3
  /** Map change requests to requests considering local channels
2
4
 
3
5
  {
@@ -13,6 +15,7 @@
13
15
  from: <From Node Public Key Id Hex String>
14
16
  id: <Change Request Id Hex String>
15
17
  [increase]: <Add Capacity Tokens Number>
18
+ [type]: <Intended Replacement Channel Channel Type Flags Number>
16
19
  }]
17
20
  }
18
21
 
@@ -26,6 +29,7 @@
26
29
  from: <From Node Public Key Id Hex String>
27
30
  id: <Change Request Id Hex String>
28
31
  [increase]: <Add Capacity Tokens Number>
32
+ [type]: <Change Channel Channel Type Flags Number>
29
33
  }]
30
34
  }
31
35
  */
@@ -61,6 +65,10 @@ module.exports = ({channels, requests}) => {
61
65
  .map(request => {
62
66
  const channel = channels.find(chan => chan.id === request.channel);
63
67
 
68
+ const currentType = privateAsType(channel.is_private);
69
+
70
+ const type = request.type !== undefined && request.type !== currentType;
71
+
64
72
  return {
65
73
  address: channel.cooperative_close_address,
66
74
  capacity: channel.capacity,
@@ -69,6 +77,7 @@ module.exports = ({channels, requests}) => {
69
77
  from: channel.partner_public_key,
70
78
  id: request.id,
71
79
  increase: request.increase,
80
+ type: type ? request.type : undefined,
72
81
  };
73
82
  });
74
83
 
@@ -10,6 +10,7 @@ const acceptCapacityChange = require('./accept_capacity_change');
10
10
  const getCapacityChangeRequests = require('./get_capacity_change_requests');
11
11
  const initiateCapacityChange = require('./initiate_capacity_change');
12
12
 
13
+ const describeType = type => !(type & 0) ? 'private' : 'public';
13
14
  const interval = 10 * 1000;
14
15
  const peerName = ({alias, id}) => `${alias} ${id.substring(0, 8)}`.trim();
15
16
  const times = 6 * 60 * 6;
@@ -89,17 +90,22 @@ module.exports = ({ask, delay, lnd, logger}, cbk) => {
89
90
 
90
91
  const change = !!request.increase ? 'Increase' : 'Decrease';
91
92
  const delta = request.decrease || request.increase;
93
+ const hasType = request.type !== undefined;
92
94
  const id = request.channel;
93
95
  const peer = peerName(res);
94
96
  const size = tokensAsBigUnit(request.capacity);
95
97
 
98
+
96
99
  const action = `${change} capacity ${size} channel ${id}`;
97
100
  const by = !!delta ? ` by ${tokensAsBigUnit(delta)}` : '';
101
+ const type = hasType ? describeType(request.type) : '';
102
+
103
+ const changeType = hasType ? ` and make channel ${type}` : '';
98
104
 
99
105
  return ask({
100
106
  type: 'confirm',
101
107
  name: 'accept',
102
- message: `${action} with ${peer}${by}?`,
108
+ message: `${action} with ${peer}${by}${changeType}?`,
103
109
  },
104
110
  ({accept}) => {
105
111
  if (!accept) {
@@ -1,10 +1,12 @@
1
1
  const {encodeBigSize} = require('bolt01');
2
2
  const {rawChanId} = require('bolt07');
3
3
 
4
+ const channelFlagsType = '5';
4
5
  const channelIdRecordType = '2';
5
6
  const decreaseRecordType = '3';
6
7
  const increaseRecordType = '4';
7
8
  const requestIdRecordType = '1';
9
+ const typeAsHex = type => Buffer.from([type]).toString('hex');
8
10
 
9
11
  /** Encode a request to change a channel capacity
10
12
 
@@ -13,6 +15,7 @@ const requestIdRecordType = '1';
13
15
  [decrease]: <Remove Channel Funds By Tokens Number>
14
16
  id: <Request Id Hex String>
15
17
  increase: <Add Channel Funds By Tokens Number>
18
+ type: <New Channel Type Number>
16
19
  }
17
20
 
18
21
  @returns
@@ -23,7 +26,7 @@ const requestIdRecordType = '1';
23
26
  }]
24
27
  }
25
28
  */
26
- module.exports = ({channel, decrease, id, increase}) => {
29
+ module.exports = ({channel, decrease, id, increase, type}) => {
27
30
  const records = [
28
31
  {
29
32
  type: requestIdRecordType,
@@ -33,6 +36,10 @@ module.exports = ({channel, decrease, id, increase}) => {
33
36
  type: channelIdRecordType,
34
37
  value: rawChanId({channel}).id,
35
38
  },
39
+ {
40
+ type: channelFlagsType,
41
+ value: typeAsHex(type),
42
+ },
36
43
  ];
37
44
 
38
45
  if (!!decrease) {
@@ -28,6 +28,7 @@ const waitForRequestsTimeoutMs = 5000;
28
28
  from: <From Node Public Key Id Hex String>
29
29
  id: <Change Request Id Hex String>
30
30
  [increase]: <Add Capacity Tokens Number>
31
+ [type]: <Intended Replacement Channel Channel Type Flags Number>
31
32
  }]
32
33
  }
33
34
  */
@@ -266,6 +266,7 @@ module.exports = (args, cbk) => {
266
266
  give_tokens: pendingChannel.remote_balance,
267
267
  is_private: args.is_private,
268
268
  partner_public_key: pendingChannel.partner_public_key,
269
+ is_private: args.is_private,
269
270
  }],
270
271
  is_avoiding_broadcast: true,
271
272
  lnd: args.lnd,
@@ -438,7 +438,7 @@ module.exports = ({ask, lnd, logger}, cbk) => {
438
438
  increase_transaction_id: getFunding.id,
439
439
  increase_transaction_vout: getFunding.vout,
440
440
  increase_witness_script: getFunding.script,
441
- is_private: channel.is_private,
441
+ is_private: askForChangeDetails.is_private,
442
442
  open_transaction: sendBasicRequest,
443
443
  partner_public_key: askForChangeDetails.partner_public_key,
444
444
  transaction_id: channel.transaction_id,
@@ -4,6 +4,7 @@ const {decodeBigSize} = require('bolt01');
4
4
  const channelIdHexLength = 16;
5
5
  const decodeNumber = encoded => BigInt(decodeBigSize({encoded}).decoded);
6
6
  const defaultRecord = {value: '00'};
7
+ const hexAsNumber = n => Buffer.from(n, 'hex').readUInt8();
7
8
  const idHexLength = 64;
8
9
  const tooLarge = BigInt(Number.MAX_SAFE_INTEGER);
9
10
 
@@ -11,6 +12,7 @@ const findChannelRecord = records => records.find(n => n.type === '2');
11
12
  const findDecreaseRecord = records => records.find(n => n.type === '3');
12
13
  const findIncreaseRecord = records => records.find(n => n.type === '4');
13
14
  const findRequestIdRecord = records => records.find(n => n.type === '1');
15
+ const findTypeRecord = records => records.find(n => n.type === '5');
14
16
  const findVersionRecord = records => records.find(n => n.type === '0');
15
17
 
16
18
  /** Parse a capacity change request
@@ -31,6 +33,7 @@ const findVersionRecord = records => records.find(n => n.type === '0');
31
33
  from: <From Node Public Key Id Hex String>
32
34
  id: <Change Request Id Hex String>
33
35
  [increase]: <Add Capacity Tokens Number>
36
+ [type]: <Intended Replacement Channel Channel Type Flags Number>
34
37
  }
35
38
  }
36
39
  */
@@ -52,6 +55,7 @@ module.exports = ({from, records}) => {
52
55
  return {};
53
56
  }
54
57
 
58
+ // Make sure the channel id is a regular one
55
59
  try {
56
60
  chanFormat({id: channelRecord.value});
57
61
  } catch (err) {
@@ -67,6 +71,7 @@ module.exports = ({from, records}) => {
67
71
 
68
72
  const decreaseRecord = findDecreaseRecord(records);
69
73
  const increaseRecord = findIncreaseRecord(records);
74
+ const typeRecord = findTypeRecord(records);
70
75
 
71
76
  // Exit early when there is a change in both directions
72
77
  if (!!decreaseRecord && !!increaseRecord) {
@@ -75,10 +80,11 @@ module.exports = ({from, records}) => {
75
80
 
76
81
  const {channel} = chanFormat({id: channelRecord.value});
77
82
  const id = idRecord.value;
83
+ const type = typeRecord ? hexAsNumber(typeRecord.value) : undefined;
78
84
 
79
85
  // Exit early when there is no decrease or increase
80
86
  if (!decreaseRecord && !increaseRecord) {
81
- return {request: {channel, from, id}};
87
+ return {request: {channel, from, id, type}};
82
88
  }
83
89
 
84
90
  const decrease = decodeNumber((decreaseRecord || defaultRecord).value);
@@ -94,6 +100,7 @@ module.exports = ({from, records}) => {
94
100
  channel,
95
101
  from,
96
102
  id,
103
+ type,
97
104
  decrease: Number(decrease) || undefined,
98
105
  increase: Number(increase) || undefined,
99
106
  },
@@ -122,6 +122,7 @@ module.exports = (args, cbk) => {
122
122
  id: args.channel,
123
123
  is_private: args.is_private,
124
124
  increase: args.increase,
125
+ is_private: args.is_private,
125
126
  lnd: args.lnd,
126
127
  open_transaction: args.open_transaction,
127
128
  transaction_id: args.transaction_id,
package/package.json CHANGED
@@ -40,5 +40,5 @@
40
40
  "integration-tests": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 120 test/integration/*.js",
41
41
  "test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 60 test/actions/*.js test/capacity/*.js test/client/*.js test/config/*.js test/p2p/*.js test/records/*.js test/respond/*.js test/server/*.js test/server/*.js test/services/*.js test/trades/*.js"
42
42
  },
43
- "version": "3.4.0"
43
+ "version": "3.5.0"
44
44
  }
@@ -34,6 +34,7 @@ const tests = [
34
34
  from: Buffer.alloc(33, 3).toString('hex'),
35
35
  id: Buffer.alloc(32).toString('hex'),
36
36
  increase: undefined,
37
+ type: undefined,
37
38
  }],
38
39
  },
39
40
  },
@@ -8,6 +8,7 @@ const makeArgs = overrides => {
8
8
  decrease: 0,
9
9
  id: Buffer.alloc(32).toString('hex'),
10
10
  increase: undefined,
11
+ type: 1,
11
12
  };
12
13
 
13
14
  Object.keys(overrides).forEach(k => args[k] = overrides[k]);
@@ -29,6 +30,10 @@ const tests = [
29
30
  type: '2',
30
31
  value: '0000000000000000',
31
32
  },
33
+ {
34
+ type: '5',
35
+ value: '01',
36
+ },
32
37
  ],
33
38
  },
34
39
  },
@@ -31,6 +31,7 @@ const tests = [
31
31
  channel: '102x1x0',
32
32
  from: '0218819f4e0dbab6c6bc434913bace0b69f20d832f68934acd72fc610a9b76fe30',
33
33
  id: '2bf4a6bf1b97aff5bbb760f1aa7a5705c885194b4e29d42e5576498107f02361',
34
+ type: undefined,
34
35
  },
35
36
  },
36
37
  },
@@ -104,6 +104,10 @@ test(`Accept capacity replacement`, async ({end, equal, strictSame}) => {
104
104
  return cbk({query: target.id});
105
105
  }
106
106
 
107
+ if (args.name === 'type') {
108
+ return cbk({type: args.default});
109
+ }
110
+
107
111
  throw new Error('UnknownQueryNameForInitiator');
108
112
  },
109
113
  logger: {error: log, info: log},
@@ -47,11 +47,13 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
47
47
 
48
48
  try {
49
49
  // Open up a new channel
50
- const channelOpen = await openChannel({
51
- lnd,
52
- local_tokens: capacity,
53
- partner_public_key: target.id,
54
- partner_socket: target.socket,
50
+ const channelOpen = await asyncRetry({interval, times}, async () => {
51
+ return await openChannel({
52
+ lnd,
53
+ local_tokens: capacity,
54
+ partner_public_key: target.id,
55
+ partner_socket: target.socket,
56
+ });
55
57
  });
56
58
 
57
59
  // Wait for the channel to be active
@@ -116,6 +118,10 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
116
118
  return cbk({query: target.id});
117
119
  }
118
120
 
121
+ if (args.name === 'type') {
122
+ return cbk({type: 'Private'});
123
+ }
124
+
119
125
  throw new Error('UnexpectedQueryNameForProposingSide');
120
126
  },
121
127
  });
@@ -159,7 +165,9 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
159
165
  interval: slow,
160
166
  },
161
167
  async () => {
162
- const [channel] = (await getChannels({lnd, is_active: true})).channels.filter(n => n.capacity < capacity);
168
+ const {channels} = await getChannels({lnd, is_active: true});
169
+
170
+ const [channel] = channels.filter(n => n.capacity < capacity);
163
171
 
164
172
  await generate({});
165
173
 
@@ -167,6 +175,8 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
167
175
  throw new Error('ExpectedChannelActivation');
168
176
  }
169
177
 
178
+ equal(channel.is_private, true, 'Channel is changed to private');
179
+
170
180
  {
171
181
  const {policies} = await getChannel({lnd, id: channel.id});
172
182
 
@@ -111,6 +111,10 @@ test(`Accept capacity replacement`, async ({end, equal, strictSame}) => {
111
111
  return cbk({query: target.id});
112
112
  }
113
113
 
114
+ if (args.name === 'type') {
115
+ return cbk({type: args.default});
116
+ }
117
+
114
118
  throw new Error('UnexpectedQueryNameForProposingSide');
115
119
  },
116
120
  });