lighstorm 0.0.3 → 0.0.5

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +5 -0
  3. data/.github/workflows/ruby-rspec-tests.yml +39 -0
  4. data/.gitignore +1 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +10 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +26 -2
  9. data/README.md +30 -371
  10. data/adapters/connections/channel_node/fee.rb +26 -0
  11. data/adapters/connections/channel_node/policy.rb +61 -0
  12. data/adapters/connections/channel_node.rb +74 -0
  13. data/adapters/connections/payment_channel.rb +28 -0
  14. data/adapters/edges/channel.rb +96 -0
  15. data/adapters/edges/forward.rb +40 -0
  16. data/adapters/edges/payment/purpose.rb +32 -0
  17. data/adapters/edges/payment.rb +50 -0
  18. data/adapters/invoice.rb +49 -0
  19. data/adapters/nodes/node.rb +111 -0
  20. data/adapters/payment_request.rb +76 -0
  21. data/components/cache.rb +3 -2
  22. data/components/lnd.rb +5 -1
  23. data/controllers/channel/actions/apply_gossip.rb +194 -0
  24. data/controllers/channel/actions/update_fee.rb +76 -0
  25. data/controllers/channel/all.rb +79 -0
  26. data/controllers/channel/find_by_id.rb +153 -0
  27. data/controllers/channel/mine.rb +114 -0
  28. data/controllers/channel.rb +27 -0
  29. data/controllers/forward/all.rb +244 -0
  30. data/controllers/forward/group_by_channel.rb +89 -0
  31. data/controllers/forward.rb +28 -0
  32. data/controllers/invoice/actions/create.rb +36 -0
  33. data/controllers/invoice/actions/pay.rb +28 -0
  34. data/controllers/invoice/actions/pay_through_route.rb +71 -0
  35. data/controllers/invoice/all.rb +70 -0
  36. data/controllers/invoice/find_by_secret_hash.rb +42 -0
  37. data/controllers/invoice.rb +36 -0
  38. data/controllers/node/actions/apply_gossip.rb +112 -0
  39. data/controllers/node/all.rb +63 -0
  40. data/controllers/node/find_by_public_key.rb +49 -0
  41. data/controllers/node/myself.rb +34 -0
  42. data/controllers/node.rb +27 -0
  43. data/controllers/payment/all.rb +368 -0
  44. data/controllers/payment.rb +21 -0
  45. data/docs/.nojekyll +0 -0
  46. data/docs/README.md +731 -0
  47. data/docs/_coverpage.md +12 -0
  48. data/docs/index.html +26 -0
  49. data/docs/vendor/docsify/docsify@4.js +1 -0
  50. data/docs/vendor/docsify-themeable/theme-simple-dark.css +3 -0
  51. data/docs/vendor/docsify-themeable/theme-simple-dark.css.map +1 -0
  52. data/docs/vendor/prismjs/prism-bash.min.js +1 -0
  53. data/docs/vendor/prismjs/prism-ruby.min.js +1 -0
  54. data/docs/vendor/prismjs/prism-tomorrow.min.css +1 -0
  55. data/lighstorm.gemspec +3 -1
  56. data/models/concerns/protectable.rb +23 -0
  57. data/models/connections/channel_node/accounting.rb +7 -14
  58. data/models/connections/channel_node/fee.rb +55 -84
  59. data/models/connections/channel_node/htlc/blocks/delta.rb +39 -0
  60. data/models/connections/channel_node/htlc.rb +65 -11
  61. data/models/connections/channel_node/policy.rb +15 -18
  62. data/models/connections/channel_node.rb +48 -22
  63. data/models/connections/forward_channel.rb +8 -43
  64. data/models/connections/payment_channel.rb +18 -39
  65. data/models/edges/channel/accounting.rb +45 -20
  66. data/models/edges/channel/hop.rb +65 -0
  67. data/models/edges/channel.rb +111 -169
  68. data/models/edges/forward.rb +9 -119
  69. data/models/edges/groups/{analysis.rb → channel_forwards/analysis.rb} +9 -9
  70. data/models/edges/groups/channel_forwards.rb +10 -40
  71. data/models/edges/payment.rb +29 -215
  72. data/models/errors.rb +32 -0
  73. data/models/invoice.rb +49 -0
  74. data/models/nodes/node/lightning.rb +11 -16
  75. data/models/nodes/node/platform.rb +13 -13
  76. data/models/nodes/node.rb +59 -103
  77. data/models/payment_request.rb +72 -0
  78. data/models/rate.rb +11 -1
  79. data/models/satoshis.rb +5 -6
  80. data/ports/dsl/lighstorm/errors.rb +5 -0
  81. data/ports/dsl/lighstorm.rb +11 -9
  82. data/ports/grpc/session.rb +26 -0
  83. data/ports/grpc.rb +80 -0
  84. data/static/cache.rb +12 -0
  85. data/static/spec.rb +3 -1
  86. metadata +62 -6
  87. data/models/connections/channel_node/constraints.rb +0 -24
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ require_relative '../../../ports/grpc'
6
+ require_relative '../../../models/errors'
7
+ require_relative '../../../models/nodes/node'
8
+ require_relative '../../../adapters/nodes/node'
9
+
10
+ module Lighstorm
11
+ module Controllers
12
+ module Node
13
+ module ApplyGossip
14
+ SKIPABLE = %w[
15
+ _source
16
+ _key
17
+ ].freeze
18
+
19
+ NOT_ALLOWED = [
20
+ 'public_key'
21
+ ].freeze
22
+
23
+ APPLICABLE = %w[
24
+ alias
25
+ color
26
+ ].freeze
27
+
28
+ def self.perform(actual, gossip)
29
+ updated = Models::Node.new(Adapter::Node.subscribe_channel_graph(gossip))
30
+
31
+ actual_dump = actual.dump
32
+ updated_dump = updated.dump
33
+
34
+ diff = generate_diff(actual_dump, updated_dump)
35
+
36
+ diff.each do |change|
37
+ key = change[:path].join('/')
38
+ next unless NOT_ALLOWED.include?(key)
39
+
40
+ raise IncoherentGossipError, "Gossip doesn't belong to this Node"
41
+ end
42
+
43
+ diff.filter do |change|
44
+ key = change[:path].join('/')
45
+ if SKIPABLE.include?(key)
46
+ false
47
+ elsif APPLICABLE.include?(key)
48
+ apply!(actual, key, change)
49
+ true
50
+ else
51
+ raise Lighstorm::Errors::MissingGossipHandlerError, "don't know how to apply '#{key}'"
52
+ end
53
+ end
54
+ end
55
+
56
+ def self.apply!(actual, key, change)
57
+ case key
58
+ when 'alias'
59
+ token = SecureRandom.hex
60
+ actual.prepare_token!(token)
61
+ actual.alias = {
62
+ value: change[:to],
63
+ token: token
64
+ }
65
+ when 'color'
66
+ token = SecureRandom.hex
67
+ actual.prepare_token!(token)
68
+ actual.color = {
69
+ value: change[:to],
70
+ token: token
71
+ }
72
+ else
73
+ raise Lighstorm::Errors::MissingGossipHandlerError, "don't know how to apply '#{key}'"
74
+ end
75
+ end
76
+
77
+ def self.generate_diff(actual, node, path = [], diff = [])
78
+ case node
79
+ when Hash
80
+ result = {}
81
+ node.each_key do |key|
82
+ result[key] = generate_diff(actual, node[key], path.dup.push(key), diff)
83
+ end
84
+ when Array
85
+ result = []
86
+ node.each_with_index do |value, i|
87
+ result << generate_diff(actual, value, path.dup.push(i), diff)
88
+ end
89
+ else
90
+ new_value = node
91
+
92
+ unless new_value.nil?
93
+ actual_value = actual
94
+ path.each do |key|
95
+ if actual_value[key]
96
+ actual_value = actual_value[key]
97
+ else
98
+ actual_value = nil
99
+ break
100
+ end
101
+ end
102
+
103
+ diff << { path: path, from: actual_value, to: new_value } if actual_value != new_value
104
+ end
105
+ end
106
+
107
+ diff
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../ports/grpc'
4
+ require_relative '../../adapters/nodes/node'
5
+
6
+ module Lighstorm
7
+ module Controllers
8
+ module Node
9
+ module All
10
+ def self.fetch(limit: nil)
11
+ data = {
12
+ at: Time.now,
13
+ get_info: Ports::GRPC.lightning.get_info.to_h,
14
+ describe_graph: Ports::GRPC.lightning.describe_graph.nodes
15
+ }
16
+
17
+ data[:describe_graph] = data[:describe_graph][0..limit - 1] unless limit.nil?
18
+
19
+ data
20
+ end
21
+
22
+ def self.adapt(raw)
23
+ {
24
+ get_info: Lighstorm::Adapter::Node.get_info(raw[:get_info]),
25
+ describe_graph: raw[:describe_graph].map do |raw|
26
+ Lighstorm::Adapter::Node.describe_graph(raw.to_h)
27
+ end
28
+ }
29
+ end
30
+
31
+ def self.transform(describe_graph, get_info)
32
+ if get_info[:public_key] == describe_graph[:public_key]
33
+ get_info.merge(myself: true)
34
+ else
35
+ describe_graph.merge(
36
+ platform: {
37
+ blockchain: get_info[:platform][:blockchain],
38
+ network: get_info[:platform][:network]
39
+ },
40
+ myself: false
41
+ )
42
+ end
43
+ end
44
+
45
+ def self.data(limit: nil, &vcr)
46
+ raw = vcr.nil? ? fetch(limit: limit) : vcr.call(-> { fetch(limit: limit) })
47
+
48
+ adapted = adapt(raw)
49
+
50
+ adapted[:describe_graph].map do |data|
51
+ transform(data, adapted[:get_info])
52
+ end
53
+ end
54
+
55
+ def self.model(data)
56
+ data.map do |node_data|
57
+ Lighstorm::Models::Node.new(node_data)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../ports/grpc'
4
+ require_relative '../../adapters/nodes/node'
5
+
6
+ module Lighstorm
7
+ module Controllers
8
+ module Node
9
+ module FindByPublicKey
10
+ def self.fetch(public_key)
11
+ {
12
+ at: Time.now,
13
+ get_info: Ports::GRPC.lightning.get_info.to_h,
14
+ get_node_info: Ports::GRPC.lightning.get_node_info(pub_key: public_key).to_h
15
+ }
16
+ end
17
+
18
+ def self.adapt(raw)
19
+ {
20
+ get_info: Lighstorm::Adapter::Node.get_info(raw[:get_info]),
21
+ get_node_info: Lighstorm::Adapter::Node.get_node_info(raw[:get_node_info])
22
+ }
23
+ end
24
+
25
+ def self.data(public_key, &vcr)
26
+ raw = vcr.nil? ? fetch(public_key) : vcr.call(-> { fetch(public_key) })
27
+
28
+ adapted = adapt(raw)
29
+
30
+ if adapted[:get_info][:public_key] == adapted[:get_node_info][:public_key]
31
+ adapted[:get_info].merge(myself: true)
32
+ else
33
+ adapted[:get_node_info].merge(
34
+ platform: {
35
+ blockchain: adapted[:get_info][:platform][:blockchain],
36
+ network: adapted[:get_info][:platform][:network]
37
+ },
38
+ myself: false
39
+ )
40
+ end
41
+ end
42
+
43
+ def self.model(data)
44
+ Lighstorm::Models::Node.new(data)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../ports/grpc'
4
+ require_relative '../../adapters/nodes/node'
5
+
6
+ module Lighstorm
7
+ module Controllers
8
+ module Node
9
+ module Myself
10
+ def self.fetch
11
+ {
12
+ at: Time.now,
13
+ get_info: Ports::GRPC.lightning.get_info.to_h
14
+ }
15
+ end
16
+
17
+ def self.adapt(raw)
18
+ { get_info: Lighstorm::Adapter::Node.get_info(raw[:get_info]) }
19
+ end
20
+
21
+ def self.data(&vcr)
22
+ raw = vcr.nil? ? fetch : vcr.call(-> { fetch })
23
+
24
+ adapted = adapt(raw)
25
+ adapted[:get_info].merge(myself: true)
26
+ end
27
+
28
+ def self.model(data)
29
+ Lighstorm::Models::Node.new(data)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './node/myself'
4
+ require_relative './node/all'
5
+ require_relative './node/find_by_public_key'
6
+
7
+ module Lighstorm
8
+ module Controllers
9
+ module Node
10
+ def self.myself
11
+ Myself.model(Myself.data)
12
+ end
13
+
14
+ def self.all(limit: nil)
15
+ All.model(All.data(limit: limit))
16
+ end
17
+
18
+ def self.find_by_public_key(public_key)
19
+ FindByPublicKey.model(FindByPublicKey.data(public_key))
20
+ end
21
+
22
+ def self.adapt(dump: nil, gossip: nil)
23
+ Models::Node.adapt(dump: dump, gossip: gossip)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,368 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../ports/grpc'
4
+ require_relative '../../adapters/nodes/node'
5
+ require_relative '../../adapters/edges/payment'
6
+ require_relative '../../adapters/invoice'
7
+ require_relative '../../adapters/edges/payment/purpose'
8
+
9
+ require_relative '../../models/edges/payment'
10
+
11
+ module Lighstorm
12
+ module Controllers
13
+ module Payment
14
+ module All
15
+ def self.fetch(purpose: nil, limit: nil, fetch: {})
16
+ at = Time.now
17
+
18
+ grpc = Ports::GRPC.session
19
+
20
+ get_info = grpc.lightning.get_info.to_h
21
+
22
+ last_offset = 0
23
+
24
+ payments = []
25
+
26
+ loop do
27
+ response = grpc.lightning.list_payments(
28
+ index_offset: last_offset
29
+ )
30
+
31
+ response.payments.each do |payment|
32
+ payment = payment.to_h
33
+
34
+ payment_purpose = Adapter::Purpose.list_payments(payment, get_info)
35
+
36
+ case purpose
37
+ when 'self-payment', 'self'
38
+ payments << payment if payment_purpose == 'self-payment'
39
+ when 'peer-to-peer', 'p2p'
40
+ payments << payment if payment_purpose == 'peer-to-peer'
41
+ when '!peer-to-peer', '!p2p'
42
+ payments << payment unless payment_purpose == 'peer-to-peer'
43
+ when 'rebalance'
44
+ payments << payment if payment_purpose == 'rebalance'
45
+ when '!rebalance'
46
+ payments << payment unless payment_purpose == 'rebalance'
47
+ when '!payment'
48
+ payments << payment unless payment_purpose == 'payment'
49
+ when 'payment'
50
+ payments << payment if payment_purpose == 'payment'
51
+ else
52
+ payments << payment
53
+ end
54
+ end
55
+
56
+ # TODO: How to optimize this?
57
+ # break if !limit.nil? && payments.size >= limit
58
+
59
+ break if last_offset == response.last_index_offset || last_offset > response.last_index_offset
60
+
61
+ last_offset = response.last_index_offset
62
+ end
63
+
64
+ payments = payments.sort_by { |raw_payment| -raw_payment[:creation_time_ns] }
65
+
66
+ payments = payments[0..limit - 1] unless limit.nil?
67
+
68
+ data = {
69
+ at: at,
70
+ get_info: get_info,
71
+ fee_report: grpc.lightning.fee_report.to_h,
72
+ list_payments: payments,
73
+ list_channels: {},
74
+ get_chan_info: {},
75
+ get_node_info: {},
76
+ lookup_invoice: {},
77
+ decode_pay_req: {}
78
+ }
79
+
80
+ payments.each do |payment|
81
+ unless fetch[:decode_pay_req] == false || payment[:payment_request] == '' || data[:decode_pay_req][payment[:payment_request]]
82
+ data[:decode_pay_req][payment[:payment_request]] = grpc.lightning.decode_pay_req(
83
+ pay_req: payment[:payment_request]
84
+ ).to_h
85
+ end
86
+
87
+ unless fetch[:lookup_invoice] == false || data[:lookup_invoice][payment[:payment_hash]]
88
+ begin
89
+ data[:lookup_invoice][payment[:payment_hash]] = grpc.lightning.lookup_invoice(
90
+ r_hash_str: payment[:payment_hash]
91
+ ).to_h
92
+ rescue StandardError => e
93
+ data[:lookup_invoice][payment[:payment_hash]] = { _error: e }
94
+ end
95
+ end
96
+
97
+ payment[:htlcs].each do |htlc|
98
+ htlc[:route][:hops].each do |hop|
99
+ unless fetch[:get_chan_info] == false || data[:get_chan_info][hop[:chan_id]]
100
+ begin
101
+ data[:get_chan_info][hop[:chan_id]] = grpc.lightning.get_chan_info(
102
+ chan_id: hop[:chan_id]
103
+ ).to_h
104
+ rescue GRPC::Unknown => e
105
+ data[:get_chan_info][hop[:chan_id]] = { _error: e }
106
+ end
107
+ end
108
+
109
+ next if fetch[:get_node_info] == false || data[:get_node_info][hop[:pub_key]]
110
+
111
+ data[:get_node_info][hop[:pub_key]] = grpc.lightning.get_node_info(
112
+ pub_key: hop[:pub_key]
113
+ ).to_h
114
+ end
115
+ end
116
+ end
117
+
118
+ if fetch[:lookup_invoice] != false
119
+ data[:lookup_invoice].each_value do |invoice|
120
+ if fetch[:decode_pay_req] == false || invoice[:_error] || invoice[:payment_request] == '' || data[:decode_pay_req][invoice[:payment_request]]
121
+ next
122
+ end
123
+
124
+ data[:decode_pay_req][invoice[:payment_request]] = grpc.lightning.decode_pay_req(
125
+ pay_req: invoice[:payment_request]
126
+ ).to_h
127
+ end
128
+ end
129
+
130
+ list_channels_done = {}
131
+
132
+ data[:get_chan_info].each_value do |channel|
133
+ next if channel[:_error]
134
+
135
+ partners = [channel[:node1_pub], channel[:node2_pub]]
136
+
137
+ is_mine = partners.include?(data[:get_info][:identity_pubkey])
138
+
139
+ if is_mine
140
+ partner = partners.find { |p| p != data[:get_info][:identity_pubkey] }
141
+
142
+ unless list_channels_done[partner]
143
+ grpc.lightning.list_channels(
144
+ peer: [partner].pack('H*')
145
+ ).channels.map(&:to_h).each do |list_channels|
146
+ data[:list_channels][list_channels[:chan_id]] = list_channels
147
+ end
148
+
149
+ list_channels_done[partner] = true
150
+ end
151
+ end
152
+
153
+ unless fetch[:get_node_info] == false || data[:get_node_info][channel[:node1_pub]]
154
+ data[:get_node_info][channel[:node1_pub]] = grpc.lightning.get_node_info(
155
+ pub_key: channel[:node1_pub]
156
+ ).to_h
157
+ end
158
+
159
+ next if fetch[:get_node_info] == false || data[:get_node_info][channel[:node2_pub]]
160
+
161
+ data[:get_node_info][channel[:node2_pub]] = grpc.lightning.get_node_info(
162
+ pub_key: channel[:node2_pub]
163
+ ).to_h
164
+ end
165
+
166
+ data[:list_channels].each_value do |channel|
167
+ next if fetch[:get_node_info] == false || data[:get_node_info][channel[:remote_pubkey]]
168
+
169
+ data[:get_node_info][channel[:remote_pubkey]] = grpc.lightning.get_node_info(
170
+ pub_key: channel[:remote_pubkey]
171
+ ).to_h
172
+ end
173
+
174
+ data[:@meta] = { calls: grpc.calls }
175
+
176
+ data
177
+ end
178
+
179
+ def self.adapt(raw)
180
+ adapted = {
181
+ get_info: Lighstorm::Adapter::Node.get_info(raw[:get_info]),
182
+ list_payments: raw[:list_payments].map do |raw_payment|
183
+ Lighstorm::Adapter::Payment.list_payments(raw_payment, raw[:get_info])
184
+ end,
185
+ fee_report: raw[:fee_report][:channel_fees].map do |raw_fee|
186
+ Lighstorm::Adapter::Fee.fee_report(raw_fee.to_h)
187
+ end,
188
+ lookup_invoice: {},
189
+ list_channels: {},
190
+ get_chan_info: {},
191
+ get_node_info: {},
192
+ decode_pay_req: {}
193
+ }
194
+
195
+ raw[:decode_pay_req].each_key do |key|
196
+ next if raw[:decode_pay_req][key][:_error]
197
+
198
+ adapted[:decode_pay_req][key] = Lighstorm::Adapter::PaymentRequest.decode_pay_req(
199
+ raw[:decode_pay_req][key]
200
+ )
201
+ end
202
+
203
+ raw[:lookup_invoice].each_key do |key|
204
+ next if raw[:lookup_invoice][key][:_error]
205
+
206
+ adapted[:lookup_invoice][key] = Lighstorm::Adapter::Invoice.lookup_invoice(
207
+ raw[:lookup_invoice][key]
208
+ )
209
+ end
210
+
211
+ raw[:get_chan_info].each_key do |key|
212
+ next if raw[:get_chan_info][key][:_error]
213
+
214
+ adapted[:get_chan_info][key] = Lighstorm::Adapter::Channel.get_chan_info(
215
+ raw[:get_chan_info][key]
216
+ )
217
+ end
218
+
219
+ raw[:list_channels].each_key do |key|
220
+ adapted[:list_channels][key] = Lighstorm::Adapter::Channel.list_channels(
221
+ raw[:list_channels][key], raw[:at]
222
+ )
223
+ end
224
+
225
+ raw[:get_node_info].each_key do |key|
226
+ adapted[:get_node_info][key] = Lighstorm::Adapter::Node.get_node_info(
227
+ raw[:get_node_info][key]
228
+ )
229
+ end
230
+
231
+ adapted
232
+ end
233
+
234
+ def self.transform_channel(data, adapted)
235
+ if adapted[:get_chan_info][data[:id].to_i]
236
+ target = data[:target]
237
+ data = adapted[:get_chan_info][data[:id].to_i]
238
+ data[:target] = target
239
+ data[:known] = true
240
+ else
241
+ data[:_key] = Digest::SHA256.hexdigest(data[:id])
242
+ end
243
+
244
+ data[:mine] = true if data[:partners].size == 1
245
+
246
+ [0, 1].each do |i|
247
+ next unless data[:partners] && data[:partners][i]
248
+
249
+ if data[:partners][i][:node][:public_key] == adapted[:get_info][:public_key]
250
+ data[:partners][i][:node] = adapted[:get_info]
251
+ end
252
+
253
+ data[:partners].each do |partner|
254
+ if data[:partners][i][:node][:public_key] == partner[:node][:public_key]
255
+ data[:partners][i][:policy] = partner[:policy]
256
+ end
257
+ end
258
+
259
+ if data[:partners][i][:node][:public_key] == adapted[:get_info][:public_key]
260
+ data[:partners][i][:node][:platform] = adapted[:get_info][:platform]
261
+ data[:partners][i][:node][:myself] = true
262
+ data[:mine] = true
263
+ adapted[:fee_report].each do |channel|
264
+ next unless data[:id] == channel[:id]
265
+
266
+ if data[:partners][i][:policy].nil?
267
+ data[:partners][i][:policy] = channel[:partner][:policy]
268
+ else
269
+ data[:partners][i][:policy][:fee] = channel[:partner][:policy][:fee]
270
+ end
271
+ break
272
+ end
273
+ else
274
+ if adapted[:get_node_info][data[:partners][i][:node][:public_key]]
275
+ data[:partners][i][:node] = adapted[:get_node_info][data[:partners][i][:node][:public_key]]
276
+ end
277
+ data[:partners][i][:node][:platform] = {
278
+ blockchain: adapted[:get_info][:platform][:blockchain],
279
+ network: adapted[:get_info][:platform][:network]
280
+ }
281
+
282
+ data[:partners][i][:node][:myself] = false
283
+ end
284
+ end
285
+
286
+ channel = adapted[:list_channels][data[:id].to_i]
287
+
288
+ return data unless channel
289
+
290
+ channel.each_key do |key|
291
+ next if data.key?(key)
292
+
293
+ data[key] = channel[key]
294
+ end
295
+
296
+ data[:accounting] = channel[:accounting]
297
+
298
+ channel[:partners].each do |partner|
299
+ data[:partners].each_index do |i|
300
+ partner.each_key do |key|
301
+ next if data[:partners][i].key?(key)
302
+
303
+ data[:partners][i][key] = partner[key]
304
+ end
305
+ end
306
+ end
307
+
308
+ data
309
+ end
310
+
311
+ def self.transform(list_payments, adapted)
312
+ if adapted[:lookup_invoice][list_payments[:request][:secret][:hash]] &&
313
+ !adapted[:lookup_invoice][list_payments[:request][:secret][:hash]][:_error]
314
+
315
+ list_payments[:request] = adapted[:lookup_invoice][list_payments[:request][:secret][:hash]][:request]
316
+ else
317
+ list_payments[:request][:_key] = Digest::SHA256.hexdigest(
318
+ list_payments[:request][:code]
319
+ )
320
+ end
321
+ list_payments[:hops].each do |hop|
322
+ hop[:channel] = transform_channel(hop[:channel], adapted)
323
+ end
324
+
325
+ if adapted[:decode_pay_req][list_payments[:request][:code]]
326
+ decoded = adapted[:decode_pay_req][list_payments[:request][:code]]
327
+ request = list_payments[:request]
328
+
329
+ decoded.each_key do |key|
330
+ request[key] = decoded[key] unless request.key?(key)
331
+
332
+ next unless decoded[key].is_a?(Hash)
333
+
334
+ decoded[key].each_key do |sub_key|
335
+ request[key][sub_key] = decoded[key][sub_key] unless request[key].key?(sub_key)
336
+ end
337
+ end
338
+ end
339
+
340
+ list_payments
341
+ end
342
+
343
+ def self.data(purpose: nil, limit: nil, fetch: {}, &vcr)
344
+ raw = if vcr.nil?
345
+ self.fetch(purpose: purpose, limit: limit, fetch: fetch)
346
+ else
347
+ vcr.call(-> { self.fetch(purpose: purpose, limit: limit, fetch: fetch) })
348
+ end
349
+
350
+ adapted = adapt(raw)
351
+
352
+ {
353
+ data: adapted[:list_payments].map do |data|
354
+ transform(data, adapted)
355
+ end,
356
+ meta: raw[:@meta]
357
+ }
358
+ end
359
+
360
+ def self.model(data)
361
+ data[:data].map do |node_data|
362
+ Lighstorm::Models::Payment.new(node_data)
363
+ end
364
+ end
365
+ end
366
+ end
367
+ end
368
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './payment/all'
4
+
5
+ module Lighstorm
6
+ module Controllers
7
+ module Payment
8
+ def self.all(purpose: nil, limit: nil, fetch: {})
9
+ All.model(All.data(purpose: purpose, limit: limit, fetch: fetch))
10
+ end
11
+
12
+ def self.first(purpose: nil, fetch: {})
13
+ All.model(All.data(purpose: purpose, fetch: fetch)).first
14
+ end
15
+
16
+ def self.last(purpose: nil, fetch: {})
17
+ All.model(All.data(purpose: purpose, fetch: fetch)).last
18
+ end
19
+ end
20
+ end
21
+ end
data/docs/.nojekyll ADDED
File without changes