lighstorm 0.0.2 → 0.0.4
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/.env.example +5 -0
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +5 -1
- data/Gemfile.lock +32 -8
- data/README.md +30 -341
- data/adapters/connections/channel_node/fee.rb +26 -0
- data/adapters/connections/channel_node.rb +52 -0
- data/adapters/connections/payment_channel.rb +28 -0
- data/adapters/edges/channel.rb +80 -0
- data/adapters/edges/forward.rb +41 -0
- data/adapters/edges/payment/purpose.rb +34 -0
- data/adapters/edges/payment.rb +53 -0
- data/adapters/invoice.rb +50 -0
- data/adapters/nodes/node.rb +77 -0
- data/adapters/payment_request.rb +77 -0
- data/components/cache.rb +3 -2
- data/components/lnd.rb +5 -1
- data/controllers/channel/actions/update_fee.rb +76 -0
- data/controllers/channel/all.rb +79 -0
- data/controllers/channel/find_by_id.rb +153 -0
- data/controllers/channel/mine.rb +114 -0
- data/controllers/channel.rb +23 -0
- data/controllers/forward/all.rb +244 -0
- data/controllers/forward/group_by_channel.rb +89 -0
- data/controllers/forward.rb +28 -0
- data/controllers/invoice/actions/create.rb +36 -0
- data/controllers/invoice/actions/pay.rb +28 -0
- data/controllers/invoice/actions/pay_through_route.rb +71 -0
- data/controllers/invoice/all.rb +70 -0
- data/controllers/invoice/find_by_secret_hash.rb +42 -0
- data/controllers/invoice.rb +36 -0
- data/controllers/node/all.rb +63 -0
- data/controllers/node/find_by_public_key.rb +49 -0
- data/controllers/node/myself.rb +34 -0
- data/controllers/node.rb +23 -0
- data/controllers/payment/all.rb +352 -0
- data/controllers/payment.rb +21 -0
- data/docs/.nojekyll +0 -0
- data/docs/README.md +655 -0
- data/docs/_coverpage.md +12 -0
- data/docs/index.html +26 -0
- data/docs/vendor/docsify/docsify@4.js +1 -0
- data/docs/vendor/docsify-themeable/theme-simple-dark.css +3 -0
- data/docs/vendor/docsify-themeable/theme-simple-dark.css.map +1 -0
- data/docs/vendor/prismjs/prism-bash.min.js +1 -0
- data/docs/vendor/prismjs/prism-ruby.min.js +1 -0
- data/docs/vendor/prismjs/prism-tomorrow.min.css +1 -0
- data/lighstorm.gemspec +4 -2
- data/models/connections/channel_node/accounting.rb +3 -12
- data/models/connections/channel_node/fee.rb +44 -56
- data/models/connections/channel_node/htlc.rb +52 -0
- data/models/connections/channel_node/policy.rb +11 -12
- data/models/connections/channel_node.rb +20 -19
- data/models/connections/forward_channel.rb +8 -43
- data/models/connections/payment_channel.rb +18 -39
- data/models/edges/channel/accounting.rb +42 -18
- data/models/edges/channel/hop.rb +65 -0
- data/models/edges/channel.rb +98 -120
- data/models/edges/forward.rb +9 -118
- data/models/edges/groups/{analysis.rb → channel_forwards/analysis.rb} +9 -9
- data/models/edges/groups/channel_forwards.rb +10 -40
- data/models/edges/payment.rb +29 -214
- data/models/errors.rb +29 -0
- data/models/invoice.rb +49 -0
- data/models/nodes/node/lightning.rb +5 -16
- data/models/nodes/node/platform.rb +7 -13
- data/models/nodes/node.rb +19 -56
- data/models/payment_request.rb +69 -0
- data/models/rate.rb +11 -1
- data/models/satoshis.rb +5 -6
- data/ports/dsl/lighstorm/errors.rb +5 -0
- data/ports/dsl/lighstorm.rb +12 -8
- data/ports/grpc.rb +62 -0
- data/static/cache.rb +12 -0
- data/static/spec.rb +3 -1
- metadata +58 -8
- data/models/connections/channel_node/constraints.rb +0 -24
@@ -1,71 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../edges/channel'
|
3
|
+
require_relative '../edges/channel/hop'
|
4
4
|
require_relative '../nodes/node'
|
5
5
|
|
6
6
|
module Lighstorm
|
7
7
|
module Models
|
8
8
|
class PaymentChannel
|
9
|
-
|
9
|
+
attr_reader :hop
|
10
|
+
|
11
|
+
def initialize(data, payment)
|
12
|
+
@data = data
|
10
13
|
|
11
|
-
|
12
|
-
@
|
13
|
-
@raw_hop = raw_hop
|
14
|
-
@hop = hop_index
|
14
|
+
@hop = data[:hop]
|
15
|
+
@payment = payment
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
+
def first?
|
19
|
+
@hop == 1
|
20
|
+
end
|
18
21
|
|
19
|
-
def
|
20
|
-
|
22
|
+
def last?
|
23
|
+
@data[:is_last] == true
|
21
24
|
end
|
22
25
|
|
23
26
|
def amount
|
24
|
-
@amount ||= Satoshis.new(milisatoshis: @
|
27
|
+
@amount ||= Satoshis.new(milisatoshis: @data[:amount][:milisatoshis])
|
25
28
|
end
|
26
29
|
|
27
30
|
def fee
|
28
|
-
@fee ||= Satoshis.new(milisatoshis: @
|
29
|
-
end
|
30
|
-
|
31
|
-
def raw
|
32
|
-
@raw_hop
|
31
|
+
@fee ||= Satoshis.new(milisatoshis: @data[:fee][:milisatoshis])
|
33
32
|
end
|
34
33
|
|
35
|
-
def
|
36
|
-
|
34
|
+
def channel
|
35
|
+
@channel ||= HopChannel.new(@data, @payment)
|
37
36
|
end
|
38
37
|
|
39
38
|
def to_h
|
40
|
-
|
39
|
+
{
|
41
40
|
hop: hop,
|
42
41
|
amount: amount.to_h,
|
43
42
|
fee: {
|
44
43
|
milisatoshis: fee.milisatoshis,
|
45
44
|
parts_per_million: fee.parts_per_million(amount.milisatoshis)
|
46
45
|
},
|
47
|
-
channel:
|
48
|
-
id: @raw_hop.chan_id.to_s,
|
49
|
-
node: {
|
50
|
-
public_key: @raw_hop.pub_key
|
51
|
-
}
|
52
|
-
}
|
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
|
-
}
|
46
|
+
channel: channel.to_h
|
66
47
|
}
|
67
|
-
|
68
|
-
response
|
69
48
|
end
|
70
49
|
end
|
71
50
|
end
|
@@ -1,43 +1,67 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../../satoshis'
|
4
|
+
require_relative '../../errors'
|
4
5
|
|
5
6
|
module Lighstorm
|
6
7
|
module Models
|
7
8
|
class ChannelAccounting
|
8
|
-
def initialize(
|
9
|
-
@
|
9
|
+
def initialize(data, is_mine)
|
10
|
+
@data = data
|
11
|
+
@is_mine = is_mine
|
10
12
|
end
|
11
13
|
|
12
14
|
def capacity
|
13
|
-
@capacity ||=
|
15
|
+
@capacity ||= if @data[:capacity]
|
16
|
+
Satoshis.new(
|
17
|
+
milisatoshis: @data[:capacity][:milisatoshis]
|
18
|
+
)
|
19
|
+
end
|
14
20
|
end
|
15
21
|
|
16
22
|
def sent
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
raise Errors::NotYourChannelError unless @is_mine
|
24
|
+
|
25
|
+
@sent ||= if @data[:sent]
|
26
|
+
Satoshis.new(
|
27
|
+
milisatoshis: @data[:sent][:milisatoshis]
|
28
|
+
)
|
29
|
+
end
|
20
30
|
end
|
21
31
|
|
22
32
|
def received
|
23
|
-
|
24
|
-
|
25
|
-
|
33
|
+
raise Errors::NotYourChannelError unless @is_mine
|
34
|
+
|
35
|
+
@received ||= if @data[:received]
|
36
|
+
Satoshis.new(
|
37
|
+
milisatoshis: @data[:received][:milisatoshis]
|
38
|
+
)
|
39
|
+
end
|
26
40
|
end
|
27
41
|
|
28
42
|
def unsettled
|
29
|
-
|
30
|
-
|
31
|
-
|
43
|
+
raise Errors::NotYourChannelError unless @is_mine
|
44
|
+
|
45
|
+
@unsettled ||= if @data[:unsettled]
|
46
|
+
Satoshis.new(
|
47
|
+
milisatoshis: @data[:unsettled][:milisatoshis]
|
48
|
+
)
|
49
|
+
end
|
32
50
|
end
|
33
51
|
|
34
52
|
def to_h
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
53
|
+
if @is_mine
|
54
|
+
{
|
55
|
+
capacity: capacity.to_h,
|
56
|
+
sent: sent.to_h,
|
57
|
+
received: received.to_h,
|
58
|
+
unsettled: unsettled.to_h
|
59
|
+
}
|
60
|
+
else
|
61
|
+
{
|
62
|
+
capacity: capacity.to_h
|
63
|
+
}
|
64
|
+
end
|
41
65
|
end
|
42
66
|
end
|
43
67
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../channel'
|
4
|
+
|
5
|
+
module Lighstorm
|
6
|
+
module Models
|
7
|
+
class HopChannel < Channel
|
8
|
+
def initialize(data, payment)
|
9
|
+
@hop_data = data
|
10
|
+
@payment = payment
|
11
|
+
super(data[:channel])
|
12
|
+
end
|
13
|
+
|
14
|
+
def target
|
15
|
+
partners.find do |partner|
|
16
|
+
partner.node.public_key == @hop_data[:channel][:target][:public_key]
|
17
|
+
end.node
|
18
|
+
end
|
19
|
+
|
20
|
+
def exit
|
21
|
+
@exit ||= if include_myself? && @hop_data[:hop] == 1
|
22
|
+
partners.reverse.find do |partner|
|
23
|
+
!partner.node.myself?
|
24
|
+
end.node
|
25
|
+
elsif @hop_data[:hop] == 1
|
26
|
+
target
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def entry
|
31
|
+
return nil if @hop_data[:is_last] && @hop_data[:hop] == 1
|
32
|
+
|
33
|
+
@entry ||= if include_myself? && @hop_data[:is_last]
|
34
|
+
if partners.size > 1
|
35
|
+
partners.reverse.find do |partner|
|
36
|
+
!partner.node.myself?
|
37
|
+
end.node
|
38
|
+
else
|
39
|
+
@payment.hops[@payment.hops.size - 2].channel.target
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def include_myself?
|
45
|
+
!partners.find { |partner| partner.node.myself? }.nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_h
|
49
|
+
if !known? && !partners.size.positive?
|
50
|
+
{ _key: _key, id: id }
|
51
|
+
else
|
52
|
+
target_hash = target.to_h
|
53
|
+
target_hash.delete(:platform)
|
54
|
+
|
55
|
+
result = { _key: _key, id: id, target: target_hash }
|
56
|
+
|
57
|
+
result[:entry] = entry.to_h if entry
|
58
|
+
result[:exit] = self.exit.to_h if self.exit
|
59
|
+
|
60
|
+
result
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/models/edges/channel.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
require 'time'
|
4
4
|
require 'date'
|
5
5
|
|
6
|
+
require_relative '../../ports/grpc'
|
7
|
+
require_relative '../../adapters/edges/channel'
|
8
|
+
|
6
9
|
require_relative '../../components/lnd'
|
7
10
|
require_relative '../../components/cache'
|
8
11
|
|
@@ -12,173 +15,148 @@ require_relative 'channel/accounting'
|
|
12
15
|
require_relative '../connections/channel_node'
|
13
16
|
require_relative '../satoshis'
|
14
17
|
|
18
|
+
require_relative '../errors'
|
19
|
+
|
15
20
|
module Lighstorm
|
16
21
|
module Models
|
17
22
|
class Channel
|
18
|
-
|
19
|
-
|
20
|
-
attr_reader :data
|
21
|
-
|
22
|
-
def self.all
|
23
|
-
response = Cache.for('lightning.list_channels') do
|
24
|
-
LND.instance.middleware('lightning.list_channels') do
|
25
|
-
LND.instance.client.lightning.list_channels
|
26
|
-
end
|
27
|
-
end
|
23
|
+
attr_reader :data, :_key, :id, :opened_at, :up_at, :active, :exposure
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
25
|
+
def initialize(data)
|
26
|
+
@data = data
|
33
27
|
|
34
|
-
|
35
|
-
|
28
|
+
@_key = data[:_key]
|
29
|
+
@id = data[:id]
|
36
30
|
end
|
37
31
|
|
38
|
-
def
|
39
|
-
|
32
|
+
def known?
|
33
|
+
@data[:known] == true
|
40
34
|
end
|
41
35
|
|
42
|
-
def
|
43
|
-
|
44
|
-
end
|
36
|
+
def mine?
|
37
|
+
ensure_known!
|
45
38
|
|
46
|
-
|
47
|
-
# Standard JSON don't support BigInt, so, a String is safer.
|
48
|
-
@id.to_s
|
39
|
+
@data[:mine]
|
49
40
|
end
|
50
41
|
|
51
|
-
def
|
52
|
-
|
53
|
-
response = Cache.for('lightning.get_chan_info', params: { chan_id: params[:id].to_i }) do
|
54
|
-
LND.instance.middleware('lightning.get_chan_info') do
|
55
|
-
LND.instance.client.lightning.get_chan_info(chan_id: params[:id].to_i)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
@data = { get_chan_info: response }
|
60
|
-
@id = @data[:get_chan_info].channel_id
|
61
|
-
rescue StandardError => e
|
62
|
-
@data = { get_chan_info: nil, error: e }
|
63
|
-
@id = params[:id]
|
64
|
-
end
|
65
|
-
|
66
|
-
fetch_from_fee_report!
|
42
|
+
def exposure
|
43
|
+
ensure_known!
|
67
44
|
|
68
|
-
|
69
|
-
calculate_times_after_list_channels!
|
45
|
+
@data[:exposure]
|
70
46
|
end
|
71
47
|
|
72
|
-
def
|
73
|
-
|
74
|
-
end
|
48
|
+
def opened_at
|
49
|
+
ensure_mine!
|
75
50
|
|
76
|
-
|
77
|
-
@data[:list_channels] ? @data[:list_channels][:channels].first.active : nil
|
51
|
+
@data[:opened_at]
|
78
52
|
end
|
79
53
|
|
80
|
-
def
|
81
|
-
|
54
|
+
def up_at
|
55
|
+
ensure_mine!
|
82
56
|
|
83
|
-
@data[:
|
57
|
+
@data[:up_at]
|
84
58
|
end
|
85
59
|
|
86
|
-
def
|
87
|
-
|
88
|
-
DateTime.parse(
|
89
|
-
(Time.now - @data[:list_channels][:channels].first.lifetime).to_s
|
90
|
-
)
|
91
|
-
end
|
92
|
-
end
|
60
|
+
def active
|
61
|
+
ensure_mine!
|
93
62
|
|
94
|
-
|
95
|
-
@up_at ||= if @data[:list_channels]
|
96
|
-
DateTime.parse(
|
97
|
-
(Time.now - @data[:list_channels][:channels].first.uptime).to_s
|
98
|
-
)
|
99
|
-
end
|
63
|
+
@data[:active]
|
100
64
|
end
|
101
65
|
|
102
66
|
def accounting
|
103
|
-
|
67
|
+
ensure_known!
|
68
|
+
|
69
|
+
@accounting ||= @data[:accounting] ? ChannelAccounting.new(@data[:accounting], mine?) : nil
|
70
|
+
end
|
104
71
|
|
105
|
-
|
72
|
+
def partners
|
73
|
+
@partners ||= if @data[:partners]
|
74
|
+
@data[:partners].map do |data|
|
75
|
+
ChannelNode.new(data, known? ? mine? : nil, transaction)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
[]
|
79
|
+
end
|
106
80
|
end
|
107
81
|
|
108
82
|
def myself
|
109
|
-
|
83
|
+
ensure_mine!
|
110
84
|
|
111
|
-
@myself ||=
|
85
|
+
@myself ||= partners.find { |partner| partner.node.myself? }
|
112
86
|
end
|
113
87
|
|
114
88
|
def partner
|
115
|
-
|
89
|
+
ensure_mine!
|
116
90
|
|
117
|
-
|
118
|
-
@data[:get_chan_info].node2_pub
|
119
|
-
else
|
120
|
-
@data[:get_chan_info].node1_pub
|
121
|
-
end
|
122
|
-
|
123
|
-
@partner ||= ChannelNode.new(self, Node.find_by_public_key(public_key))
|
124
|
-
end
|
125
|
-
|
126
|
-
def raw
|
127
|
-
{
|
128
|
-
get_chan_info: @data[:get_chan_info].to_h,
|
129
|
-
list_channels: { channels: @data[:list_channels][:channels].map(&:to_h) }
|
130
|
-
}
|
91
|
+
@partner ||= partners.find { |partner| !partner.node.myself? }
|
131
92
|
end
|
132
93
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
accounting: accounting.to_h,
|
141
|
-
partner: partner.to_h,
|
142
|
-
myself: myself.to_h
|
143
|
-
}
|
144
|
-
end
|
94
|
+
def transaction
|
95
|
+
Struct.new(:data) do
|
96
|
+
def funding
|
97
|
+
Struct.new(:data) do
|
98
|
+
def id
|
99
|
+
data[:id]
|
100
|
+
end
|
145
101
|
|
146
|
-
|
102
|
+
def index
|
103
|
+
data[:index]
|
104
|
+
end
|
147
105
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
LND.instance.client.lightning.fee_report
|
106
|
+
def to_h
|
107
|
+
{ id: id, index: index }
|
108
|
+
end
|
109
|
+
end.new(data[:funding])
|
153
110
|
end
|
154
|
-
end
|
155
111
|
|
156
|
-
|
157
|
-
|
158
|
-
@data[:fee_report] = { channel_fees: [channel] }
|
159
|
-
break
|
112
|
+
def to_h
|
113
|
+
{ funding: funding.to_h }
|
160
114
|
end
|
161
|
-
end
|
115
|
+
end.new(@data[:transaction])
|
162
116
|
end
|
163
117
|
|
164
|
-
def
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
118
|
+
def to_h
|
119
|
+
if !known? && partners.size.positive?
|
120
|
+
{ _key: _key, id: id, partners: partners.map(&:to_h) }
|
121
|
+
elsif !known?
|
122
|
+
{ _key: _key, id: id }
|
123
|
+
elsif mine?
|
124
|
+
{
|
125
|
+
_key: _key,
|
126
|
+
id: id,
|
127
|
+
opened_at: opened_at,
|
128
|
+
up_at: up_at,
|
129
|
+
active: active,
|
130
|
+
exposure: exposure,
|
131
|
+
accounting: accounting.to_h,
|
132
|
+
partner: partner.to_h,
|
133
|
+
myself: myself.to_h
|
134
|
+
}
|
135
|
+
elsif @data[:accounting]
|
136
|
+
{
|
137
|
+
_key: _key,
|
138
|
+
id: id,
|
139
|
+
accounting: accounting.to_h,
|
140
|
+
partners: partners.map(&:to_h)
|
141
|
+
}
|
142
|
+
else
|
143
|
+
{
|
144
|
+
_key: _key,
|
145
|
+
id: id,
|
146
|
+
partners: partners.map(&:to_h)
|
147
|
+
}
|
169
148
|
end
|
149
|
+
end
|
170
150
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
end
|
176
|
-
end
|
151
|
+
private
|
152
|
+
|
153
|
+
def ensure_known!
|
154
|
+
raise Errors::UnknownChannelError unless known?
|
177
155
|
end
|
178
156
|
|
179
|
-
def
|
180
|
-
|
181
|
-
|
157
|
+
def ensure_mine!
|
158
|
+
ensure_known!
|
159
|
+
raise Errors::NotYourChannelError if @data[:mine] == false
|
182
160
|
end
|
183
161
|
end
|
184
162
|
end
|
data/models/edges/forward.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'digest'
|
4
3
|
require 'time'
|
5
4
|
require 'date'
|
6
5
|
|
@@ -12,130 +11,30 @@ require_relative 'groups/channel_forwards'
|
|
12
11
|
module Lighstorm
|
13
12
|
module Models
|
14
13
|
class Forward
|
15
|
-
|
14
|
+
attr_reader :_key, :at
|
16
15
|
|
17
|
-
|
16
|
+
def initialize(data)
|
17
|
+
@data = data
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
forwards = []
|
23
|
-
|
24
|
-
loop do
|
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
|
34
|
-
end
|
35
|
-
|
36
|
-
response.forwarding_events.each { |raw_forward| forwards << raw_forward }
|
37
|
-
|
38
|
-
# Unfortunately, forwards aren't sorted in descending order. :(
|
39
|
-
# break if !limit.nil? && forwards.size >= limit
|
40
|
-
|
41
|
-
break if last_offset == response.last_offset_index || last_offset > response.last_offset_index
|
42
|
-
|
43
|
-
last_offset = response.last_offset_index
|
44
|
-
end
|
45
|
-
|
46
|
-
forwards = forwards.sort_by { |raw_forward| -raw_forward.timestamp_ns }
|
47
|
-
|
48
|
-
forwards = forwards[0..limit - 1] unless limit.nil?
|
49
|
-
|
50
|
-
return forwards if raw
|
51
|
-
|
52
|
-
forwards.map { |raw_forward| Forward.new(raw_forward, respond_info: info) }
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.first
|
56
|
-
all(limit: 1).first
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.last
|
60
|
-
all.last
|
61
|
-
end
|
62
|
-
|
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
|
109
|
-
@data = { forwarding_history: { forwarding_events: [raw] } }
|
110
|
-
end
|
111
|
-
|
112
|
-
def id
|
113
|
-
@id ||= Digest::SHA256.hexdigest(
|
114
|
-
@data[:forwarding_history][:forwarding_events].first.timestamp_ns.to_s
|
115
|
-
)
|
116
|
-
end
|
117
|
-
|
118
|
-
def at
|
119
|
-
DateTime.parse(Time.at(
|
120
|
-
@data[:forwarding_history][:forwarding_events].first.timestamp_ns / 1e+9
|
121
|
-
).to_s)
|
19
|
+
@_key = data[:_key]
|
20
|
+
@at = data[:at]
|
122
21
|
end
|
123
22
|
|
124
23
|
def fee
|
125
|
-
Satoshis.new(milisatoshis: @data[:
|
24
|
+
@fee ||= Satoshis.new(milisatoshis: @data[:fee][:milisatoshis])
|
126
25
|
end
|
127
26
|
|
128
27
|
def in
|
129
|
-
@in ||= ForwardChannel.new(:in
|
28
|
+
@in ||= ForwardChannel.new(@data[:in])
|
130
29
|
end
|
131
30
|
|
132
31
|
def out
|
133
|
-
@out ||= ForwardChannel.new(:out
|
32
|
+
@out ||= ForwardChannel.new(@data[:out])
|
134
33
|
end
|
135
34
|
|
136
35
|
def to_h
|
137
36
|
{
|
138
|
-
|
37
|
+
_key: _key,
|
139
38
|
at: at,
|
140
39
|
fee: {
|
141
40
|
milisatoshis: fee.milisatoshis,
|
@@ -145,14 +44,6 @@ module Lighstorm
|
|
145
44
|
out: out.to_h
|
146
45
|
}
|
147
46
|
end
|
148
|
-
|
149
|
-
def raw
|
150
|
-
{
|
151
|
-
forwarding_history: {
|
152
|
-
forwarding_events: [@data[:forwarding_history][:forwarding_events].first.to_h]
|
153
|
-
}
|
154
|
-
}
|
155
|
-
end
|
156
47
|
end
|
157
48
|
end
|
158
49
|
end
|