lighstorm 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +5 -5
- data/README.md +63 -10
- data/components/cache.rb +10 -1
- data/models/connections/channel_node/fee.rb +46 -0
- data/models/connections/channel_node/policy.rb +3 -3
- data/models/connections/forward_channel.rb +28 -19
- data/models/connections/payment_channel.rb +26 -12
- data/models/edges/channel.rb +18 -12
- data/models/edges/forward.rb +65 -10
- data/models/edges/groups/analysis.rb +69 -0
- data/models/edges/groups/channel_forwards.rb +66 -0
- data/models/edges/payment.rb +14 -9
- data/models/nodes/node/lightning.rb +7 -1
- data/models/nodes/node/platform.rb +1 -1
- data/models/nodes/node.rb +12 -5
- data/models/rate.rb +2 -0
- data/static/cache.rb +65 -0
- data/static/spec.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5255fb12e5463a29335c433ca7ccc20cdc6154a686f25c1272d4bf608e71764b
|
4
|
+
data.tar.gz: 7865931e5f6ee408a810481f1f809edcdf3d5fabfcd31e76bf3e3cad1dfabe64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c7793a2361ffe29f9e97b1be00500274054f58acea841bb025fac94ebac969117c09f69cc644219825e06883df93a400cebce0db1f72f1b72e75ab3296e37b6
|
7
|
+
data.tar.gz: 81ce8ce6fcc5d564ae5b0a51c99080d0f301ecbf9a5fb6da45bd8f633a4d35eea6adb1b77f1f0a2ecebb9bf4c8e11c0185aca35f688f21f2118ff73a0f5ac1ab
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
lighstorm (0.0.
|
4
|
+
lighstorm (0.0.2)
|
5
5
|
dotenv (~> 2.8, >= 2.8.1)
|
6
6
|
lnd-client (~> 0.0.4)
|
7
7
|
zache (~> 0.12.0)
|
@@ -16,7 +16,7 @@ GEM
|
|
16
16
|
google-protobuf (3.21.12)
|
17
17
|
googleapis-common-protos-types (1.5.0)
|
18
18
|
google-protobuf (~> 3.14)
|
19
|
-
grpc (1.
|
19
|
+
grpc (1.52.0-x86_64-linux)
|
20
20
|
google-protobuf (~> 3.21)
|
21
21
|
googleapis-common-protos-types (~> 1.0)
|
22
22
|
json (2.6.3)
|
@@ -24,7 +24,7 @@ GEM
|
|
24
24
|
grpc (~> 1.51)
|
25
25
|
method_source (1.0.0)
|
26
26
|
parallel (1.22.1)
|
27
|
-
parser (3.2.
|
27
|
+
parser (3.2.1.0)
|
28
28
|
ast (~> 2.4.1)
|
29
29
|
pry (0.14.2)
|
30
30
|
coderay (~> 1.1)
|
@@ -33,9 +33,9 @@ GEM
|
|
33
33
|
byebug (~> 11.0)
|
34
34
|
pry (>= 0.13, < 0.15)
|
35
35
|
rainbow (3.1.1)
|
36
|
-
regexp_parser (2.
|
36
|
+
regexp_parser (2.7.0)
|
37
37
|
rexml (3.2.5)
|
38
|
-
rubocop (1.
|
38
|
+
rubocop (1.45.1)
|
39
39
|
json (~> 2.3)
|
40
40
|
parallel (~> 1.10)
|
41
41
|
parser (>= 3.2.0.0)
|
data/README.md
CHANGED
@@ -33,7 +33,7 @@ _Lighstorm_ is an opinionated abstraction layer on top of the [lnd-client](https
|
|
33
33
|
|
34
34
|
It brings an [object-oriented](https://en.wikipedia.org/wiki/Object-oriented_programming) approach for interacting with a [Lightning Node](https://github.com/lightningnetwork/lnd), influenced by the [Active Record Pattern](https://www.martinfowler.com/eaaCatalog/activeRecord.html) and [Active Record Models](https://guides.rubyonrails.org/active_record_basics.html) conventions.
|
35
35
|
|
36
|
-
Although it tries to stay close to [Lightning's terminologies](https://docs.lightning.engineering/lightning-network-tools/lnd), it brings its own vocabulary and data modeling, optimizing for [programmer happiness](https://rubyonrails.org/doctrine).
|
36
|
+
Although it tries to stay close to [Lightning's terminologies](https://docs.lightning.engineering/lightning-network-tools/lnd), it brings its own vocabulary and [data modeling](#data-modeling), optimizing for [programmer happiness](https://rubyonrails.org/doctrine).
|
37
37
|
|
38
38
|
## Usage
|
39
39
|
|
@@ -42,7 +42,7 @@ Although it tries to stay close to [Lightning's terminologies](https://docs.ligh
|
|
42
42
|
Add to your `Gemfile`:
|
43
43
|
|
44
44
|
```ruby
|
45
|
-
gem 'lighstorm', '~> 0.0.
|
45
|
+
gem 'lighstorm', '~> 0.0.2'
|
46
46
|
```
|
47
47
|
|
48
48
|
Run `bundle install`.
|
@@ -90,6 +90,7 @@ node.channels
|
|
90
90
|
node.alias
|
91
91
|
node.public_key
|
92
92
|
node.color
|
93
|
+
node.myself?
|
93
94
|
|
94
95
|
node.platform.blockchain
|
95
96
|
node.platform.network
|
@@ -129,6 +130,14 @@ channel.myself.node.color
|
|
129
130
|
channel.myself.policy.fee.base.milisatoshis
|
130
131
|
channel.myself.policy.fee.rate.parts_per_million
|
131
132
|
|
133
|
+
channel.myself.policy.fee.update(
|
134
|
+
{ rate: { parts_per_million: 25 } }, preview: true
|
135
|
+
)
|
136
|
+
|
137
|
+
channel.myself.policy.fee.update(
|
138
|
+
{ rate: { parts_per_million: 25 } }
|
139
|
+
)
|
140
|
+
|
132
141
|
Lighstorm::Forward
|
133
142
|
Lighstorm::Forward.all
|
134
143
|
Lighstorm::Forward.first
|
@@ -141,7 +150,9 @@ forward.id
|
|
141
150
|
forward.at
|
142
151
|
|
143
152
|
forward.fee.milisatoshis
|
144
|
-
forward.fee.parts_per_million
|
153
|
+
forward.fee.parts_per_million(
|
154
|
+
forward.in.amount.milisatoshis
|
155
|
+
)
|
145
156
|
|
146
157
|
forward.in.amount.milisatoshis
|
147
158
|
|
@@ -155,6 +166,37 @@ forward.out.channel.partner.node.alias
|
|
155
166
|
forward.out.channel.partner.node.public_key
|
156
167
|
forward.out.channel.partner.node.color
|
157
168
|
|
169
|
+
Lighstorm::Forward.group_by_channel(direction: :in, hours_ago: 24, limit: 5)
|
170
|
+
|
171
|
+
group.to_h
|
172
|
+
|
173
|
+
group.last_at
|
174
|
+
group.analysis.count
|
175
|
+
group.analysis.sums.amount.milisatoshis
|
176
|
+
group.analysis.sums.fee.milisatoshis
|
177
|
+
group.analysis.averages.amount.milisatoshis
|
178
|
+
group.analysis.averages.fee.milisatoshis
|
179
|
+
group.analysis.averages.fee.parts_per_million(
|
180
|
+
group.analysis.averages.amount.milisatoshis
|
181
|
+
)
|
182
|
+
|
183
|
+
group.in.id
|
184
|
+
group.in.partner.node.alias
|
185
|
+
group.in.partner.node.public_key
|
186
|
+
group.in.partner.node.color
|
187
|
+
|
188
|
+
Lighstorm::Forward.group_by_channel(direction: :out)
|
189
|
+
|
190
|
+
group.to_h
|
191
|
+
|
192
|
+
group.last_at
|
193
|
+
group.analysis.count
|
194
|
+
|
195
|
+
group.out.id
|
196
|
+
group.out.partner.node.alias
|
197
|
+
group.out.partner.node.public_key
|
198
|
+
group.out.partner.node.color
|
199
|
+
|
158
200
|
Lighstorm::Payment
|
159
201
|
Lighstorm::Payment.all
|
160
202
|
Lighstorm::Payment.first
|
@@ -168,12 +210,17 @@ payment.purpose
|
|
168
210
|
payment.status
|
169
211
|
payment.amount.milisatoshis
|
170
212
|
payment.fee.milisatoshis
|
171
|
-
payment.fee.parts_per_million
|
213
|
+
payment.fee.parts_per_million(
|
214
|
+
payment.amount.milisatoshis
|
215
|
+
)
|
172
216
|
|
173
217
|
payment.from.hop
|
174
218
|
payment.from.amount.milisatoshis
|
175
219
|
payment.from.fee.milisatoshis
|
176
|
-
payment.from.fee.parts_per_million
|
220
|
+
payment.from.fee.parts_per_million(
|
221
|
+
payment.from.amount.milisatoshis
|
222
|
+
)
|
223
|
+
|
177
224
|
payment.from.channel.id
|
178
225
|
payment.from.channel.partner.node.alias
|
179
226
|
payment.from.channel.partner.node.public_key
|
@@ -182,7 +229,10 @@ payment.from.channel.partner.node.color
|
|
182
229
|
payment.to.hop
|
183
230
|
payment.to.amount.milisatoshis
|
184
231
|
payment.to.fee.milisatoshis
|
185
|
-
payment.to.fee.parts_per_million
|
232
|
+
payment.to.fee.parts_per_million(
|
233
|
+
payment.to.amount.milisatoshis
|
234
|
+
)
|
235
|
+
|
186
236
|
payment.to.channel.id
|
187
237
|
payment.to.channel.partner.node.alias
|
188
238
|
payment.to.channel.partner.node.public_key
|
@@ -193,7 +243,10 @@ payment.hops.size
|
|
193
243
|
payment.hops[0].hop
|
194
244
|
payment.hops[0].amount.milisatoshis
|
195
245
|
payment.hops[0].fee.milisatoshis
|
196
|
-
payment.hops[0].fee.parts_per_million
|
246
|
+
payment.hops[0].fee.parts_per_million(
|
247
|
+
payment.hops[0].amount.milisatoshis
|
248
|
+
)
|
249
|
+
|
197
250
|
payment.hops[0].channel.id
|
198
251
|
payment.hops[0].channel.partner.node.alias
|
199
252
|
payment.hops[0].channel.partner.node.public_key
|
@@ -221,7 +274,7 @@ satoshis.parts_per_million(reference_in_milisatoshis)
|
|
221
274
|
```ruby
|
222
275
|
require 'lighstorm'
|
223
276
|
|
224
|
-
puts Lighstorm.version # => 0.0.
|
277
|
+
puts Lighstorm.version # => 0.0.2
|
225
278
|
|
226
279
|
Lighstorm::Satoshis.new(
|
227
280
|
milisatoshis: 75621650
|
@@ -343,7 +396,7 @@ gem 'lighstorm', path: '/home/user/lighstorm'
|
|
343
396
|
# demo.rb
|
344
397
|
require 'lighstorm'
|
345
398
|
|
346
|
-
puts Lighstorm.version # => 0.0.
|
399
|
+
puts Lighstorm.version # => 0.0.2
|
347
400
|
```
|
348
401
|
|
349
402
|
```sh
|
@@ -358,5 +411,5 @@ gem build lighstorm.gemspec
|
|
358
411
|
|
359
412
|
gem signin
|
360
413
|
|
361
|
-
gem push lighstorm-0.0.
|
414
|
+
gem push lighstorm-0.0.2.gem
|
362
415
|
```
|
data/components/cache.rb
CHANGED
@@ -4,6 +4,8 @@ require 'singleton'
|
|
4
4
|
|
5
5
|
require 'zache'
|
6
6
|
|
7
|
+
require_relative '../static/cache'
|
8
|
+
|
7
9
|
module Lighstorm
|
8
10
|
class Cache
|
9
11
|
include Singleton
|
@@ -18,7 +20,14 @@ module Lighstorm
|
|
18
20
|
@client = Zache.new
|
19
21
|
end
|
20
22
|
|
21
|
-
def for(key, ttl:
|
23
|
+
def for(key, ttl: nil, params: {}, &block)
|
24
|
+
if ttl.nil?
|
25
|
+
ttl = Lighstorm::Static::CACHE[key.sub('lightning.', '').to_sym]
|
26
|
+
raise "missing ttl for #{key}" if ttl.nil?
|
27
|
+
|
28
|
+
ttl = ttl[:ttl]
|
29
|
+
end
|
30
|
+
|
22
31
|
key = build_key_for(key, params)
|
23
32
|
|
24
33
|
@client.get(key, lifetime: ttl) do
|
@@ -3,10 +3,16 @@
|
|
3
3
|
require_relative '../../satoshis'
|
4
4
|
require_relative '../../rate'
|
5
5
|
|
6
|
+
require_relative '../../../components/lnd'
|
7
|
+
|
6
8
|
module Lighstorm
|
7
9
|
module Models
|
8
10
|
class Fee
|
11
|
+
attr_reader :rate, :base
|
12
|
+
|
9
13
|
def initialize(policy, channel, node)
|
14
|
+
@channel = channel
|
15
|
+
@policy = policy
|
10
16
|
if node.myself?
|
11
17
|
@base = Satoshis.new(
|
12
18
|
milisatoshis: channel.data[:fee_report][:channel_fees].first.base_fee_msat
|
@@ -22,6 +28,46 @@ module Lighstorm
|
|
22
28
|
end
|
23
29
|
end
|
24
30
|
|
31
|
+
def update(params, preview: false)
|
32
|
+
chan_point = @channel.data[:get_chan_info].chan_point.split(':')
|
33
|
+
|
34
|
+
# add_message "lnrpc.PolicyUpdateRequest" do
|
35
|
+
# optional :base_fee_msat, :int64, 3
|
36
|
+
# optional :fee_rate, :double, 4
|
37
|
+
# optional :fee_rate_ppm, :uint32, 9
|
38
|
+
# optional :time_lock_delta, :uint32, 5
|
39
|
+
# optional :max_htlc_msat, :uint64, 6
|
40
|
+
# optional :min_htlc_msat, :uint64, 7
|
41
|
+
# optional :min_htlc_msat_specified, :bool, 8
|
42
|
+
# oneof :scope do
|
43
|
+
# optional :global, :bool, 1
|
44
|
+
# optional :chan_point, :message, 2, "lnrpc.ChannelPoint"
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
|
48
|
+
grpc_request = {
|
49
|
+
method: :update_channel_policy,
|
50
|
+
params: {
|
51
|
+
chan_point: {
|
52
|
+
funding_txid_str: chan_point[0],
|
53
|
+
output_index: chan_point[1].to_i
|
54
|
+
},
|
55
|
+
fee_rate_ppm: @policy.data.fee_rate_milli_msat,
|
56
|
+
base_fee_msat: @policy.data.fee_base_msat,
|
57
|
+
time_lock_delta: @policy.data.time_lock_delta,
|
58
|
+
max_htlc_msat: @policy.data.max_htlc_msat
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
grpc_request[:params][:fee_rate_ppm] = params[:rate][:parts_per_million]
|
63
|
+
|
64
|
+
return grpc_request if preview
|
65
|
+
|
66
|
+
LND.instance.middleware("lightning.#{grpc_request[:method]}") do
|
67
|
+
LND.instance.client.lightning.send(grpc_request[:method], grpc_request[:params])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
25
71
|
def to_h
|
26
72
|
{
|
27
73
|
base: @base.to_h,
|
@@ -7,21 +7,14 @@ module Lighstorm
|
|
7
7
|
class ForwardChannel
|
8
8
|
KIND = :connection
|
9
9
|
|
10
|
-
def initialize(direction, forward)
|
10
|
+
def initialize(direction, forward, respond_info: true)
|
11
|
+
@respond_info = respond_info
|
11
12
|
@direction = direction
|
12
13
|
@forward = forward
|
13
14
|
end
|
14
15
|
|
15
16
|
def channel
|
16
|
-
@channel ||=
|
17
|
-
Channel.find_by_id(
|
18
|
-
@forward.data[:forwarding_history][:forwarding_events].first.chan_id_in
|
19
|
-
)
|
20
|
-
else
|
21
|
-
Channel.find_by_id(
|
22
|
-
@forward.data[:forwarding_history][:forwarding_events].first.chan_id_out
|
23
|
-
)
|
24
|
-
end
|
17
|
+
@channel ||= Channel.find_by_id(channel_id)
|
25
18
|
end
|
26
19
|
|
27
20
|
def amount
|
@@ -35,19 +28,35 @@ module Lighstorm
|
|
35
28
|
end
|
36
29
|
|
37
30
|
def to_h
|
38
|
-
{
|
31
|
+
response = {
|
39
32
|
amount: amount.to_h,
|
40
|
-
channel: {
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
33
|
+
channel: { id: channel_id }
|
34
|
+
}
|
35
|
+
|
36
|
+
return response unless @respond_info
|
37
|
+
|
38
|
+
response[:channel] = {
|
39
|
+
id: channel.id,
|
40
|
+
partner: {
|
41
|
+
node: {
|
42
|
+
alias: channel.partner&.node&.alias,
|
43
|
+
public_key: channel.partner&.node&.public_key,
|
44
|
+
color: channel.partner&.node&.color
|
48
45
|
}
|
49
46
|
}
|
50
47
|
}
|
48
|
+
|
49
|
+
response
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def channel_id
|
55
|
+
if @direction == :in
|
56
|
+
@forward.data[:forwarding_history][:forwarding_events].first.chan_id_in.to_s
|
57
|
+
else
|
58
|
+
@forward.data[:forwarding_history][:forwarding_events].first.chan_id_out.to_s
|
59
|
+
end
|
51
60
|
end
|
52
61
|
end
|
53
62
|
end
|
@@ -8,13 +8,16 @@ module Lighstorm
|
|
8
8
|
class PaymentChannel
|
9
9
|
KIND = :connection
|
10
10
|
|
11
|
-
def initialize(raw_hop, hop_index)
|
11
|
+
def initialize(raw_hop, hop_index, respond_info: true)
|
12
|
+
@respond_info = respond_info
|
12
13
|
@raw_hop = raw_hop
|
13
|
-
@
|
14
|
+
@hop = hop_index
|
14
15
|
end
|
15
16
|
|
17
|
+
attr_reader :hop
|
18
|
+
|
16
19
|
def channel
|
17
|
-
|
20
|
+
Channel.find_by_id(@raw_hop.chan_id)
|
18
21
|
end
|
19
22
|
|
20
23
|
def amount
|
@@ -34,24 +37,35 @@ module Lighstorm
|
|
34
37
|
end
|
35
38
|
|
36
39
|
def to_h
|
37
|
-
{
|
38
|
-
hop:
|
40
|
+
response = {
|
41
|
+
hop: hop,
|
39
42
|
amount: amount.to_h,
|
40
43
|
fee: {
|
41
44
|
milisatoshis: fee.milisatoshis,
|
42
45
|
parts_per_million: fee.parts_per_million(amount.milisatoshis)
|
43
46
|
},
|
44
47
|
channel: {
|
45
|
-
id:
|
46
|
-
|
47
|
-
|
48
|
-
alias: partner_node&.alias,
|
49
|
-
public_key: partner_node&.public_key,
|
50
|
-
color: partner_node&.color
|
51
|
-
}
|
48
|
+
id: @raw_hop.chan_id.to_s,
|
49
|
+
node: {
|
50
|
+
public_key: @raw_hop.pub_key
|
52
51
|
}
|
53
52
|
}
|
54
53
|
}
|
54
|
+
|
55
|
+
return response unless @respond_info
|
56
|
+
|
57
|
+
response[:channel] = {
|
58
|
+
id: channel.id,
|
59
|
+
partner: {
|
60
|
+
node: {
|
61
|
+
alias: partner_node&.alias,
|
62
|
+
public_key: partner_node&.public_key,
|
63
|
+
color: partner_node&.color
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
response
|
55
69
|
end
|
56
70
|
end
|
57
71
|
end
|
data/models/edges/channel.rb
CHANGED
@@ -17,17 +17,17 @@ module Lighstorm
|
|
17
17
|
class Channel
|
18
18
|
KIND = :edge
|
19
19
|
|
20
|
-
attr_reader :
|
20
|
+
attr_reader :data
|
21
21
|
|
22
22
|
def self.all
|
23
|
-
response = Cache.for('lightning.list_channels'
|
23
|
+
response = Cache.for('lightning.list_channels') do
|
24
24
|
LND.instance.middleware('lightning.list_channels') do
|
25
25
|
LND.instance.client.lightning.list_channels
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
response.channels.map do |channel|
|
30
|
-
Channel.find_by_id(channel.chan_id)
|
30
|
+
Channel.find_by_id(channel.chan_id.to_s)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -43,21 +43,23 @@ module Lighstorm
|
|
43
43
|
Channel.new({ id: id })
|
44
44
|
end
|
45
45
|
|
46
|
+
def id
|
47
|
+
# Standard JSON don't support BigInt, so, a String is safer.
|
48
|
+
@id.to_s
|
49
|
+
end
|
50
|
+
|
46
51
|
def initialize(params)
|
47
52
|
begin
|
48
|
-
response = Cache.for(
|
49
|
-
'lightning.get_chan_info',
|
50
|
-
ttl: 1, params: { chan_id: params[:id] }
|
51
|
-
) do
|
53
|
+
response = Cache.for('lightning.get_chan_info', params: { chan_id: params[:id].to_i }) do
|
52
54
|
LND.instance.middleware('lightning.get_chan_info') do
|
53
|
-
LND.instance.client.lightning.get_chan_info(chan_id: params[:id])
|
55
|
+
LND.instance.client.lightning.get_chan_info(chan_id: params[:id].to_i)
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
57
59
|
@data = { get_chan_info: response }
|
58
60
|
@id = @data[:get_chan_info].channel_id
|
59
|
-
rescue StandardError =>
|
60
|
-
@data = { get_chan_info: nil }
|
61
|
+
rescue StandardError => e
|
62
|
+
@data = { get_chan_info: nil, error: e }
|
61
63
|
@id = params[:id]
|
62
64
|
end
|
63
65
|
|
@@ -67,6 +69,10 @@ module Lighstorm
|
|
67
69
|
calculate_times_after_list_channels!
|
68
70
|
end
|
69
71
|
|
72
|
+
def error
|
73
|
+
@data[:error]
|
74
|
+
end
|
75
|
+
|
70
76
|
def active
|
71
77
|
@data[:list_channels] ? @data[:list_channels][:channels].first.active : nil
|
72
78
|
end
|
@@ -141,7 +147,7 @@ module Lighstorm
|
|
141
147
|
|
142
148
|
# Ensure that we are getting fresh up-date data about our own fees.
|
143
149
|
def fetch_from_fee_report!
|
144
|
-
response = Cache.for('lightning.fee_report'
|
150
|
+
response = Cache.for('lightning.fee_report') do
|
145
151
|
LND.instance.middleware('lightning.fee_report') do
|
146
152
|
LND.instance.client.lightning.fee_report
|
147
153
|
end
|
@@ -156,7 +162,7 @@ module Lighstorm
|
|
156
162
|
end
|
157
163
|
|
158
164
|
def fetch_from_list_channels!
|
159
|
-
response = Cache.for('lightning.list_channels'
|
165
|
+
response = Cache.for('lightning.list_channels') do
|
160
166
|
LND.instance.middleware('lightning.list_channels') do
|
161
167
|
LND.instance.client.lightning.list_channels
|
162
168
|
end
|
data/models/edges/forward.rb
CHANGED
@@ -7,6 +7,7 @@ require 'date'
|
|
7
7
|
require_relative '../satoshis'
|
8
8
|
|
9
9
|
require_relative '../connections/forward_channel'
|
10
|
+
require_relative 'groups/channel_forwards'
|
10
11
|
|
11
12
|
module Lighstorm
|
12
13
|
module Models
|
@@ -15,16 +16,21 @@ module Lighstorm
|
|
15
16
|
|
16
17
|
attr_reader :data
|
17
18
|
|
18
|
-
def self.all(limit: nil)
|
19
|
+
def self.all(limit: nil, raw: false, info: true)
|
19
20
|
last_offset = 0
|
20
21
|
|
21
22
|
forwards = []
|
22
23
|
|
23
24
|
loop do
|
24
|
-
response =
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
response = Cache.for(
|
26
|
+
'lightning.forwarding_history',
|
27
|
+
params: { peer_alias_lookup: true, index_offset: last_offset }
|
28
|
+
) do
|
29
|
+
LND.instance.middleware('lightning.forwarding_history') do
|
30
|
+
LND.instance.client.lightning.forwarding_history(
|
31
|
+
peer_alias_lookup: true, index_offset: last_offset
|
32
|
+
)
|
33
|
+
end
|
28
34
|
end
|
29
35
|
|
30
36
|
response.forwarding_events.each { |raw_forward| forwards << raw_forward }
|
@@ -41,7 +47,9 @@ module Lighstorm
|
|
41
47
|
|
42
48
|
forwards = forwards[0..limit - 1] unless limit.nil?
|
43
49
|
|
44
|
-
forwards
|
50
|
+
return forwards if raw
|
51
|
+
|
52
|
+
forwards.map { |raw_forward| Forward.new(raw_forward, respond_info: info) }
|
45
53
|
end
|
46
54
|
|
47
55
|
def self.first
|
@@ -52,7 +60,52 @@ module Lighstorm
|
|
52
60
|
all.last
|
53
61
|
end
|
54
62
|
|
55
|
-
def
|
63
|
+
def self.group_by_channel(direction: :out, hours_ago: nil, limit: nil, info: true)
|
64
|
+
raw_forwards = all(raw: true)
|
65
|
+
|
66
|
+
direction = direction.to_sym
|
67
|
+
|
68
|
+
groups = {}
|
69
|
+
|
70
|
+
raw_forwards.each do |raw_forward|
|
71
|
+
channel_id = direction == :in ? raw_forward.chan_id_in : raw_forward.chan_id_out
|
72
|
+
|
73
|
+
if hours_ago
|
74
|
+
forward_hours_ago = (
|
75
|
+
Time.now - Time.at(raw_forward.timestamp_ns / 1e+9)
|
76
|
+
).to_f / 3600
|
77
|
+
|
78
|
+
next if forward_hours_ago > hours_ago
|
79
|
+
end
|
80
|
+
|
81
|
+
unless groups[channel_id]
|
82
|
+
groups[channel_id] = {
|
83
|
+
last_at: nil,
|
84
|
+
analysis: { count: 0, sums: { amount: 0, fee: 0 } },
|
85
|
+
direction => { id: channel_id }
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
groups[channel_id][:analysis][:count] += 1
|
90
|
+
groups[channel_id][:analysis][:sums][:amount] += raw_forward.amt_in_msat
|
91
|
+
groups[channel_id][:analysis][:sums][:fee] += raw_forward.fee_msat
|
92
|
+
|
93
|
+
if groups[channel_id][:last_at].nil? || raw_forward.timestamp_ns > groups[channel_id][:last_at]
|
94
|
+
groups[channel_id][:last_at] = raw_forward.timestamp_ns
|
95
|
+
groups[channel_id][:sample] = raw_forward
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
groups = groups.values.sort_by { |group| - group[:last_at] }
|
100
|
+
.sort_by { |group| - group[:analysis][:count] }
|
101
|
+
|
102
|
+
groups = groups[0..limit - 1] unless limit.nil?
|
103
|
+
|
104
|
+
groups.map { |raw_group| ChannelForwardsGroup.new(direction, raw_group) }
|
105
|
+
end
|
106
|
+
|
107
|
+
def initialize(raw, respond_info: true)
|
108
|
+
@respond_info = respond_info
|
56
109
|
@data = { forwarding_history: { forwarding_events: [raw] } }
|
57
110
|
end
|
58
111
|
|
@@ -63,7 +116,9 @@ module Lighstorm
|
|
63
116
|
end
|
64
117
|
|
65
118
|
def at
|
66
|
-
DateTime.parse(Time.at(
|
119
|
+
DateTime.parse(Time.at(
|
120
|
+
@data[:forwarding_history][:forwarding_events].first.timestamp_ns / 1e+9
|
121
|
+
).to_s)
|
67
122
|
end
|
68
123
|
|
69
124
|
def fee
|
@@ -71,11 +126,11 @@ module Lighstorm
|
|
71
126
|
end
|
72
127
|
|
73
128
|
def in
|
74
|
-
@in ||= ForwardChannel.new(:in, self)
|
129
|
+
@in ||= ForwardChannel.new(:in, self, respond_info: @respond_info)
|
75
130
|
end
|
76
131
|
|
77
132
|
def out
|
78
|
-
@out ||= ForwardChannel.new(:out, self)
|
133
|
+
@out ||= ForwardChannel.new(:out, self, respond_info: @respond_info)
|
79
134
|
end
|
80
135
|
|
81
136
|
def to_h
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lighstorm
|
4
|
+
module Models
|
5
|
+
class ChannelForwardsGroup
|
6
|
+
Analysis = Struct.new(:analysis) do
|
7
|
+
def count
|
8
|
+
analysis[:count]
|
9
|
+
end
|
10
|
+
|
11
|
+
def sums
|
12
|
+
Struct.new(:sums) do
|
13
|
+
def amount
|
14
|
+
Satoshis.new(milisatoshis: sums[:amount])
|
15
|
+
end
|
16
|
+
|
17
|
+
def fee
|
18
|
+
Satoshis.new(milisatoshis: sums[:fee])
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_h
|
22
|
+
{
|
23
|
+
amount: amount.to_h,
|
24
|
+
fee: {
|
25
|
+
milisatoshis: fee.milisatoshis,
|
26
|
+
parts_per_million: fee.parts_per_million(amount.milisatoshis)
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end.new(analysis[:sums])
|
31
|
+
end
|
32
|
+
|
33
|
+
def averages
|
34
|
+
Struct.new(:analysis) do
|
35
|
+
def amount
|
36
|
+
Satoshis.new(
|
37
|
+
milisatoshis: analysis[:sums][:amount].to_f / analysis[:count]
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def fee
|
42
|
+
Satoshis.new(
|
43
|
+
milisatoshis: analysis[:sums][:fee].to_f / analysis[:count]
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_h
|
48
|
+
{
|
49
|
+
amount: amount.to_h,
|
50
|
+
fee: {
|
51
|
+
milisatoshis: fee.milisatoshis,
|
52
|
+
parts_per_million: fee.parts_per_million(amount.milisatoshis)
|
53
|
+
}
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end.new(analysis)
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_h
|
60
|
+
{
|
61
|
+
count: count,
|
62
|
+
sums: sums.to_h,
|
63
|
+
averages: averages.to_h
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../satoshis'
|
4
|
+
require_relative 'analysis'
|
5
|
+
|
6
|
+
module Lighstorm
|
7
|
+
module Models
|
8
|
+
class ChannelForwardsGroup
|
9
|
+
def initialize(direction, data)
|
10
|
+
@direction = direction
|
11
|
+
@data = data
|
12
|
+
end
|
13
|
+
|
14
|
+
def last_at
|
15
|
+
@last_at ||= DateTime.parse(Time.at(@data[:last_at].to_f / 1e+9).to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
def analysis
|
19
|
+
Analysis.new(@data[:analysis])
|
20
|
+
end
|
21
|
+
|
22
|
+
def in
|
23
|
+
return @in if @in
|
24
|
+
|
25
|
+
raise raise ArgumentError, "Method `in` doesn't exist." unless @direction == :in
|
26
|
+
|
27
|
+
@in = Channel.new({ id: @data[:in][:id] })
|
28
|
+
end
|
29
|
+
|
30
|
+
def out
|
31
|
+
return @out if @out
|
32
|
+
|
33
|
+
raise raise ArgumentError, "Method `out` doesn't exist." unless @direction == :out
|
34
|
+
|
35
|
+
@out = Channel.new({ id: @data[:out][:id] })
|
36
|
+
end
|
37
|
+
|
38
|
+
# def capacity
|
39
|
+
# @capacity ||= Satoshis.new(milisatoshis: @channel.data[:get_chan_info].capacity * 1000)
|
40
|
+
# end
|
41
|
+
|
42
|
+
def to_h
|
43
|
+
{
|
44
|
+
last_at: last_at,
|
45
|
+
analysis: analysis.to_h,
|
46
|
+
@direction => {
|
47
|
+
id: channel.id,
|
48
|
+
partner: {
|
49
|
+
node: {
|
50
|
+
alias: channel&.partner&.node&.alias,
|
51
|
+
public_key: channel&.partner&.node&.public_key,
|
52
|
+
color: channel&.partner&.node&.color
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def channel
|
62
|
+
@channel ||= @direction == :in ? self.in : out
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/models/edges/payment.rb
CHANGED
@@ -15,14 +15,16 @@ module Lighstorm
|
|
15
15
|
|
16
16
|
attr_reader :data
|
17
17
|
|
18
|
-
def self.all(limit: nil, purpose: nil, hops: true)
|
18
|
+
def self.all(limit: nil, purpose: nil, hops: true, info: true)
|
19
19
|
last_offset = 0
|
20
20
|
|
21
21
|
payments = []
|
22
22
|
|
23
23
|
loop do
|
24
|
-
response =
|
25
|
-
LND.instance.
|
24
|
+
response = Cache.for('lightning.list_payments', params: { index_offset: last_offset }) do
|
25
|
+
LND.instance.middleware('lightning.list_payments') do
|
26
|
+
LND.instance.client.lightning.list_payments(index_offset: last_offset)
|
27
|
+
end
|
26
28
|
end
|
27
29
|
|
28
30
|
response.payments.each do |raw_payment|
|
@@ -57,7 +59,7 @@ module Lighstorm
|
|
57
59
|
payments = payments[0..limit - 1] unless limit.nil?
|
58
60
|
|
59
61
|
payments.map do |raw_payment|
|
60
|
-
Payment.new(raw_payment, respond_hops: hops)
|
62
|
+
Payment.new(raw_payment, respond_hops: hops, respond_info: info)
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
@@ -69,8 +71,9 @@ module Lighstorm
|
|
69
71
|
all.last
|
70
72
|
end
|
71
73
|
|
72
|
-
def initialize(raw, respond_hops: true)
|
74
|
+
def initialize(raw, respond_hops: true, respond_info: true)
|
73
75
|
@respond_hops = respond_hops
|
76
|
+
@respond_info = respond_info
|
74
77
|
@data = { list_payments: { payments: [raw] } }
|
75
78
|
end
|
76
79
|
|
@@ -163,7 +166,7 @@ module Lighstorm
|
|
163
166
|
|
164
167
|
@from = PaymentChannel.new(
|
165
168
|
@data[:list_payments][:payments].first.htlcs.first.route.hops.first,
|
166
|
-
1
|
169
|
+
1, respond_info: @respond_info
|
167
170
|
)
|
168
171
|
|
169
172
|
@from
|
@@ -185,12 +188,14 @@ module Lighstorm
|
|
185
188
|
@data[:list_payments][:payments].first.htlcs.first.route.hops[
|
186
189
|
@data[:list_payments][:payments].first.htlcs.first.route.hops.size - 2
|
187
190
|
],
|
188
|
-
@data[:list_payments][:payments].first.htlcs.first.route.hops.size - 1
|
191
|
+
@data[:list_payments][:payments].first.htlcs.first.route.hops.size - 1,
|
192
|
+
respond_info: @respond_info
|
189
193
|
)
|
190
194
|
else
|
191
195
|
PaymentChannel.new(
|
192
196
|
@data[:list_payments][:payments].first.htlcs.first.route.hops.last,
|
193
|
-
@data[:list_payments][:payments].first.htlcs.first.route.hops.size
|
197
|
+
@data[:list_payments][:payments].first.htlcs.first.route.hops.size,
|
198
|
+
respond_info: @respond_info
|
194
199
|
)
|
195
200
|
end
|
196
201
|
|
@@ -203,7 +208,7 @@ module Lighstorm
|
|
203
208
|
validated_htlcs_number!
|
204
209
|
|
205
210
|
@hops = @data[:list_payments][:payments].first.htlcs.first.route.hops.map.with_index do |raw_hop, i|
|
206
|
-
PaymentChannel.new(raw_hop, i + 1)
|
211
|
+
PaymentChannel.new(raw_hop, i + 1, respond_info: @respond_info)
|
207
212
|
end
|
208
213
|
end
|
209
214
|
|
@@ -5,6 +5,8 @@ require_relative '../../../components/lnd'
|
|
5
5
|
module Lighstorm
|
6
6
|
module Models
|
7
7
|
class Lightning
|
8
|
+
IMPLEMENTATION = 'lnd'
|
9
|
+
|
8
10
|
def initialize(platform, node)
|
9
11
|
raise 'cannot provide platform details for a node that is not yours' unless node.myself?
|
10
12
|
|
@@ -19,9 +21,13 @@ module Lighstorm
|
|
19
21
|
{ get_info: @data[:get_info].to_h }
|
20
22
|
end
|
21
23
|
|
24
|
+
def implementation
|
25
|
+
@implementation ||= IMPLEMENTATION
|
26
|
+
end
|
27
|
+
|
22
28
|
def to_h
|
23
29
|
{
|
24
|
-
implementation:
|
30
|
+
implementation: implementation,
|
25
31
|
version: version
|
26
32
|
}
|
27
33
|
end
|
@@ -12,7 +12,7 @@ module Lighstorm
|
|
12
12
|
def initialize(node)
|
13
13
|
@node = node
|
14
14
|
|
15
|
-
response = Cache.for('lightning.get_info'
|
15
|
+
response = Cache.for('lightning.get_info') do
|
16
16
|
LND.instance.middleware('lightning.get_info') do
|
17
17
|
LND.instance.client.lightning.get_info
|
18
18
|
end
|
data/models/nodes/node.rb
CHANGED
@@ -14,7 +14,7 @@ module Lighstorm
|
|
14
14
|
attr_reader :alias, :public_key, :color
|
15
15
|
|
16
16
|
def self.myself
|
17
|
-
response = Cache.for('lightning.get_info'
|
17
|
+
response = Cache.for('lightning.get_info') do
|
18
18
|
LND.instance.middleware('lightning.get_info') do
|
19
19
|
LND.instance.client.lightning.get_info
|
20
20
|
end
|
@@ -59,15 +59,22 @@ module Lighstorm
|
|
59
59
|
private
|
60
60
|
|
61
61
|
def initialize(params, myself: false)
|
62
|
-
response = Cache.for(
|
63
|
-
'lightning.get_node_info',
|
64
|
-
ttl: 5 * 60, params: { pub_key: params[:public_key] }
|
65
|
-
) do
|
62
|
+
response = Cache.for('lightning.get_node_info', params: { pub_key: params[:public_key] }) do
|
66
63
|
LND.instance.middleware('lightning.get_node_info') do
|
67
64
|
LND.instance.client.lightning.get_node_info(pub_key: params[:public_key])
|
68
65
|
end
|
69
66
|
end
|
70
67
|
|
68
|
+
unless myself
|
69
|
+
response_get_info = Cache.for('lightning.get_info') do
|
70
|
+
LND.instance.middleware('lightning.get_info') do
|
71
|
+
LND.instance.client.lightning.get_info
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
myself = true if params[:public_key] == response_get_info.identity_pubkey
|
76
|
+
end
|
77
|
+
|
71
78
|
@data = { get_node_info: response }
|
72
79
|
|
73
80
|
@myself = myself
|
data/models/rate.rb
CHANGED
data/static/cache.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lighstorm
|
4
|
+
module Static
|
5
|
+
CACHE = {
|
6
|
+
fee_report: {
|
7
|
+
ttl: 0.01,
|
8
|
+
properties: %i[
|
9
|
+
base_fee_msat fee_per_mil
|
10
|
+
]
|
11
|
+
},
|
12
|
+
forwarding_history: {
|
13
|
+
ttl: 1,
|
14
|
+
properties: %i[
|
15
|
+
amt_in_msat
|
16
|
+
amt_out_msat
|
17
|
+
chan_id_in
|
18
|
+
chan_id_out
|
19
|
+
fee_msat
|
20
|
+
timestamp_ns
|
21
|
+
]
|
22
|
+
},
|
23
|
+
get_chan_info: {
|
24
|
+
ttl: 5 * 60,
|
25
|
+
properties: %i[
|
26
|
+
channel_id
|
27
|
+
chan_point
|
28
|
+
node1_pub
|
29
|
+
node1_policy
|
30
|
+
node2_pub
|
31
|
+
node2_policy
|
32
|
+
capacity
|
33
|
+
]
|
34
|
+
},
|
35
|
+
get_info: {
|
36
|
+
ttl: 5 * 60,
|
37
|
+
properties: %i[identity_pubkey version chains chain network]
|
38
|
+
},
|
39
|
+
get_node_info: {
|
40
|
+
ttl: 5 * 60,
|
41
|
+
properties: %i[alias pub_key color]
|
42
|
+
},
|
43
|
+
list_channels: {
|
44
|
+
ttl: 1,
|
45
|
+
properties: %i[
|
46
|
+
local_balance remote_balance unsettled_balance
|
47
|
+
local_constraints remote_constraints
|
48
|
+
active private
|
49
|
+
lifetime uptime
|
50
|
+
total_satoshis_sent total_satoshis_received
|
51
|
+
]
|
52
|
+
},
|
53
|
+
list_payments: {
|
54
|
+
ttl: 1,
|
55
|
+
properties: %i[
|
56
|
+
creation_date payment_hash status
|
57
|
+
value_msat fee_msat
|
58
|
+
htlcs route hops
|
59
|
+
chan_id pub_key
|
60
|
+
amt_to_forward_msat fee_msat
|
61
|
+
]
|
62
|
+
}
|
63
|
+
}.freeze
|
64
|
+
end
|
65
|
+
end
|
data/static/spec.rb
CHANGED
@@ -4,7 +4,7 @@ module Lighstorm
|
|
4
4
|
module Static
|
5
5
|
SPEC = {
|
6
6
|
name: 'lighstorm',
|
7
|
-
version: '0.0.
|
7
|
+
version: '0.0.2',
|
8
8
|
author: 'icebaker',
|
9
9
|
summary: 'API for interacting with a Lightning Node.',
|
10
10
|
description: 'Lighstorm is an opinionated abstraction layer on top of the lnd-client for interacting with a Lightning Node.',
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lighstorm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- icebaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dotenv
|
@@ -84,6 +84,8 @@ files:
|
|
84
84
|
- models/edges/channel.rb
|
85
85
|
- models/edges/channel/accounting.rb
|
86
86
|
- models/edges/forward.rb
|
87
|
+
- models/edges/groups/analysis.rb
|
88
|
+
- models/edges/groups/channel_forwards.rb
|
87
89
|
- models/edges/payment.rb
|
88
90
|
- models/nodes/node.rb
|
89
91
|
- models/nodes/node/lightning.rb
|
@@ -91,6 +93,7 @@ files:
|
|
91
93
|
- models/rate.rb
|
92
94
|
- models/satoshis.rb
|
93
95
|
- ports/dsl/lighstorm.rb
|
96
|
+
- static/cache.rb
|
94
97
|
- static/spec.rb
|
95
98
|
homepage: https://github.com/icebaker/lighstorm
|
96
99
|
licenses:
|