forked from alexbosworth/ln-service
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhops_from_channels.js
99 lines (80 loc) · 2.72 KB
/
hops_from_channels.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
const {isArray} = Array;
/** Derive policy hops from an in-order set of channels with dual policies
Either individual destinations or a final destination is required
{
channels: [{
capacity: <Maximum Tokens Number>
[destination]: <Next Hop Destination Public Key String>
id: <Standard Format Channel Id String>
policies: [{
base_fee_mtokens: <Base Fee Millitokens String>
cltv_delta: <Locktime Delta Number>
fee_rate: <Fees Charged Per Million Tokens Number>
is_disabled: <Channel Is Disabled Bool>
min_htlc_mtokens: <Minimum HTLC Millitokens Value String>
public_key: <Node Public Key String>
}]
}]
[destination]: <Destination Public Key Hex String>
}
@throws
<Error>
@returns
{
hops: [{
base_fee_mtokens: <Base Fee Millitokens String>
channel: <Standard Format Channel Id String>
channel_capacity: <Maximum Tokens Number>
cltv_delta: <CLTV Delta Number>
fee_rate: <Fee Rate In Millitokens Per Million Number>
public_key: <Public Key Hex String>
}]
}
*/
module.exports = ({channels, destination}) => {
if (!isArray(channels) || !channels.length) {
throw new Error('ExpectedChannelsToDeriveHops');
}
let nextNode = destination;
const hopDestinations = channels.slice().reverse()
.map(channel => {
if (!isArray(channel.policies)) {
throw new Error('ExpectedChannelPoliciesWhenCalculatingHops');
}
const next = nextNode;
nextNode = channel.policies.map(n => n.public_key).find(n => n !== next);
return next;
})
.reverse();
const hops = channels.map((channel, i, chans) => {
if (!destination && !channel.destination) {
throw new Error('ExpectedNextHopPublicKey');
}
if (!channel.id) {
throw new Error('ExpectedChannelIdForTranslationToChannelHop');
}
if (!Array.isArray(channel.policies)) {
throw new Error('ExpectedArrayOfPoliciesForChannelInHop');
}
const nextHop = channel.destination || hopDestinations[i];
const nextPolicy = chans[i + [channel].length];
let overridePolicy;
const peer = channel.policies.find(n => n.public_key === nextHop);
const policy = channel.policies.find(n => n.public_key !== nextHop);
if (!policy) {
return null;
}
if (!i && !!nextPolicy) {
overridePolicy = nextPolicy.policies.find(n => n.public_key === nextHop);
}
return {
base_fee_mtokens: (overridePolicy || policy).base_fee_mtokens,
channel: channel.id,
channel_capacity: channel.capacity,
cltv_delta: peer.cltv_delta,
fee_rate: (overridePolicy || policy).fee_rate,
public_key: nextHop,
};
});
return {hops: hops.filter(n => !!n)};
};