lighstorm 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +7 -7
  4. data/adapters/bitcoin/address.rb +19 -0
  5. data/adapters/bitcoin/transaction.rb +34 -0
  6. data/adapters/lightning/connections/channel_node/fee.rb +28 -0
  7. data/adapters/lightning/connections/channel_node/policy.rb +63 -0
  8. data/adapters/lightning/connections/channel_node.rb +77 -0
  9. data/adapters/lightning/connections/payment_channel.rb +30 -0
  10. data/adapters/lightning/edges/channel.rb +98 -0
  11. data/adapters/lightning/edges/forward.rb +42 -0
  12. data/adapters/lightning/edges/payment/purpose.rb +45 -0
  13. data/adapters/lightning/edges/payment.rb +89 -0
  14. data/adapters/lightning/invoice.rb +186 -0
  15. data/adapters/lightning/nodes/node.rb +113 -0
  16. data/controllers/action.rb +1 -1
  17. data/controllers/bitcoin/address/actions/create.rb +91 -0
  18. data/controllers/bitcoin/address/actions/pay.rb +119 -0
  19. data/controllers/bitcoin/address.rb +24 -0
  20. data/controllers/bitcoin/transaction/all.rb +65 -0
  21. data/controllers/bitcoin/transaction.rb +25 -0
  22. data/controllers/concerns/impersonatable.rb +5 -3
  23. data/controllers/connection.rb +1 -1
  24. data/controllers/lightning/channel/actions/apply_gossip.rb +201 -0
  25. data/controllers/lightning/channel/actions/update_fee.rb +94 -0
  26. data/controllers/lightning/channel/all.rb +85 -0
  27. data/controllers/lightning/channel/find_by_id.rb +155 -0
  28. data/controllers/lightning/channel/mine.rb +116 -0
  29. data/controllers/lightning/channel.rb +43 -0
  30. data/controllers/lightning/forward/all.rb +250 -0
  31. data/controllers/lightning/forward/group_by_channel.rb +91 -0
  32. data/controllers/lightning/forward.rb +36 -0
  33. data/controllers/lightning/invoice/actions/create.rb +90 -0
  34. data/controllers/lightning/invoice/actions/pay.rb +97 -0
  35. data/controllers/lightning/invoice/actions/pay_through_route.rb +73 -0
  36. data/controllers/lightning/invoice/all.rb +82 -0
  37. data/controllers/lightning/invoice/decode.rb +50 -0
  38. data/controllers/lightning/invoice/find_by_code.rb +76 -0
  39. data/controllers/lightning/invoice/find_by_secret_hash.rb +56 -0
  40. data/controllers/lightning/invoice.rb +64 -0
  41. data/controllers/lightning/node/actions/apply_gossip.rb +114 -0
  42. data/controllers/lightning/node/actions/pay.rb +117 -0
  43. data/controllers/lightning/node/all.rb +69 -0
  44. data/controllers/lightning/node/find_by_public_key.rb +55 -0
  45. data/controllers/lightning/node/myself.rb +36 -0
  46. data/controllers/lightning/node.rb +35 -0
  47. data/controllers/lightning/payment/actions/pay.rb +110 -0
  48. data/controllers/lightning/payment/all.rb +439 -0
  49. data/controllers/lightning/payment.rb +37 -0
  50. data/controllers/lightning/secret/valid_proof.rb +60 -0
  51. data/controllers/lightning/secret.rb +16 -0
  52. data/controllers/wallet/activity/all.rb +196 -0
  53. data/controllers/wallet/activity.rb +28 -0
  54. data/controllers/wallet/balance.rb +3 -3
  55. data/controllers/wallet.rb +1 -1
  56. data/docs/README.md +229 -148
  57. data/docs/_coverpage.md +1 -1
  58. data/docs/index.html +1 -1
  59. data/models/bitcoin/address.rb +49 -0
  60. data/models/bitcoin/transaction.rb +41 -0
  61. data/models/concerns/protectable.rb +1 -1
  62. data/models/errors.rb +7 -8
  63. data/models/lightning/connections/channel_node/accounting.rb +27 -0
  64. data/models/lightning/connections/channel_node/fee.rb +82 -0
  65. data/models/lightning/connections/channel_node/htlc/blocks/delta.rb +41 -0
  66. data/models/lightning/connections/channel_node/htlc.rb +88 -0
  67. data/models/lightning/connections/channel_node/policy.rb +41 -0
  68. data/models/lightning/connections/channel_node.rb +86 -0
  69. data/models/lightning/connections/forward_channel.rb +31 -0
  70. data/models/lightning/connections/payment_channel.rb +58 -0
  71. data/models/lightning/edges/channel/accounting.rb +87 -0
  72. data/models/lightning/edges/channel/hop.rb +67 -0
  73. data/models/lightning/edges/channel.rb +197 -0
  74. data/models/lightning/edges/forward.rb +51 -0
  75. data/models/lightning/edges/groups/channel_forwards/analysis.rb +71 -0
  76. data/models/lightning/edges/groups/channel_forwards.rb +39 -0
  77. data/models/lightning/edges/payment.rb +104 -0
  78. data/models/lightning/invoice.rb +115 -0
  79. data/models/lightning/nodes/node/lightning.rb +33 -0
  80. data/models/lightning/nodes/node/platform.rb +50 -0
  81. data/models/lightning/nodes/node.rb +145 -0
  82. data/models/lightning/rate.rb +37 -0
  83. data/models/lightning/secret.rb +57 -0
  84. data/models/satoshis.rb +1 -1
  85. data/models/wallet/activity.rb +54 -0
  86. data/models/wallet/balance.rb +42 -0
  87. data/ports/dsl/lighstorm.rb +29 -16
  88. data/static/cache.rb +2 -0
  89. data/static/spec.rb +1 -1
  90. metadata +74 -68
  91. data/adapters/connections/channel_node/fee.rb +0 -26
  92. data/adapters/connections/channel_node/policy.rb +0 -61
  93. data/adapters/connections/channel_node.rb +0 -75
  94. data/adapters/connections/payment_channel.rb +0 -28
  95. data/adapters/edges/channel.rb +0 -96
  96. data/adapters/edges/forward.rb +0 -40
  97. data/adapters/edges/payment/purpose.rb +0 -43
  98. data/adapters/edges/payment.rb +0 -87
  99. data/adapters/invoice.rb +0 -184
  100. data/adapters/nodes/node.rb +0 -111
  101. data/adapters/transaction.rb +0 -23
  102. data/controllers/activity/all.rb +0 -194
  103. data/controllers/activity.rb +0 -26
  104. data/controllers/channel/actions/apply_gossip.rb +0 -193
  105. data/controllers/channel/actions/update_fee.rb +0 -91
  106. data/controllers/channel/all.rb +0 -83
  107. data/controllers/channel/find_by_id.rb +0 -153
  108. data/controllers/channel/mine.rb +0 -114
  109. data/controllers/channel.rb +0 -41
  110. data/controllers/forward/all.rb +0 -248
  111. data/controllers/forward/group_by_channel.rb +0 -89
  112. data/controllers/forward.rb +0 -34
  113. data/controllers/invoice/actions/create.rb +0 -88
  114. data/controllers/invoice/actions/pay.rb +0 -95
  115. data/controllers/invoice/actions/pay_through_route.rb +0 -71
  116. data/controllers/invoice/all.rb +0 -80
  117. data/controllers/invoice/decode.rb +0 -44
  118. data/controllers/invoice/find_by_code.rb +0 -70
  119. data/controllers/invoice/find_by_secret_hash.rb +0 -54
  120. data/controllers/invoice.rb +0 -62
  121. data/controllers/node/actions/apply_gossip.rb +0 -112
  122. data/controllers/node/actions/pay.rb +0 -115
  123. data/controllers/node/all.rb +0 -67
  124. data/controllers/node/find_by_public_key.rb +0 -53
  125. data/controllers/node/myself.rb +0 -34
  126. data/controllers/node.rb +0 -33
  127. data/controllers/payment/actions/pay.rb +0 -108
  128. data/controllers/payment/all.rb +0 -437
  129. data/controllers/payment.rb +0 -35
  130. data/controllers/secret/valid_proof.rb +0 -58
  131. data/controllers/transaction/all.rb +0 -61
  132. data/controllers/transaction.rb +0 -25
  133. data/models/activity.rb +0 -52
  134. data/models/connections/channel_node/accounting.rb +0 -25
  135. data/models/connections/channel_node/fee.rb +0 -80
  136. data/models/connections/channel_node/htlc/blocks/delta.rb +0 -39
  137. data/models/connections/channel_node/htlc.rb +0 -86
  138. data/models/connections/channel_node/policy.rb +0 -39
  139. data/models/connections/channel_node.rb +0 -84
  140. data/models/connections/forward_channel.rb +0 -29
  141. data/models/connections/payment_channel.rb +0 -56
  142. data/models/edges/channel/accounting.rb +0 -85
  143. data/models/edges/channel/hop.rb +0 -65
  144. data/models/edges/channel.rb +0 -195
  145. data/models/edges/forward.rb +0 -49
  146. data/models/edges/groups/channel_forwards/analysis.rb +0 -69
  147. data/models/edges/groups/channel_forwards.rb +0 -37
  148. data/models/edges/payment.rb +0 -102
  149. data/models/invoice.rb +0 -113
  150. data/models/nodes/node/lightning.rb +0 -31
  151. data/models/nodes/node/platform.rb +0 -48
  152. data/models/nodes/node.rb +0 -143
  153. data/models/rate.rb +0 -35
  154. data/models/secret.rb +0 -55
  155. data/models/transaction.rb +0 -39
  156. data/models/wallet.rb +0 -40
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ require_relative '../../../../models/errors'
6
+ require_relative '../../../../models/lightning/edges/channel'
7
+ require_relative '../../../../adapters/lightning/edges/channel'
8
+
9
+ module Lighstorm
10
+ module Controller
11
+ module Lightning
12
+ module Channel
13
+ module ApplyGossip
14
+ SKIPABLE = [
15
+ '_key',
16
+ '_source',
17
+ 'partners/0/_source',
18
+ 'partners/0/policy/_source',
19
+ 'partners/1/_source',
20
+ 'partners/1/policy/_source'
21
+ ].freeze
22
+
23
+ NOT_ALLOWED = [
24
+ 'id'
25
+ ].freeze
26
+
27
+ APPLICABLE = [
28
+ 'accounting/capacity/millisatoshis',
29
+ 'partners/0/policy/fee/base/millisatoshis',
30
+ 'partners/0/state',
31
+ 'partners/1/policy/fee/base/millisatoshis',
32
+ 'partners/1/state',
33
+ 'partners/1/policy/fee/rate/parts_per_million',
34
+ 'partners/0/policy/fee/rate/parts_per_million',
35
+ 'partners/0/policy/htlc/minimum/millisatoshis',
36
+ 'partners/1/policy/htlc/minimum/millisatoshis',
37
+ 'partners/0/policy/htlc/maximum/millisatoshis',
38
+ 'partners/1/policy/htlc/maximum/millisatoshis',
39
+ 'partners/0/policy/htlc/blocks/delta/minimum',
40
+ 'partners/1/policy/htlc/blocks/delta/minimum'
41
+ ].freeze
42
+
43
+ def self.perform(actual, gossip)
44
+ updated = Model::Lightning::Channel.new(
45
+ Adapter::Lightning::Channel.subscribe_channel_graph(gossip), nil
46
+ )
47
+
48
+ actual_dump = actual.dump
49
+ updated_dump = updated.dump
50
+
51
+ if actual.partners.first.node.public_key == updated.partners.last.node.public_key &&
52
+ actual.partners.last.node.public_key == updated.partners.first.node.public_key
53
+ a = updated_dump[:partners][0]
54
+ b = updated_dump[:partners][1]
55
+
56
+ updated_dump[:partners][0] = b
57
+ updated_dump[:partners][1] = a
58
+ end
59
+
60
+ diff = generate_diff(actual_dump, updated_dump)
61
+
62
+ diff.each do |change|
63
+ key = change[:path].join('/')
64
+ next unless NOT_ALLOWED.include?(key)
65
+
66
+ raise IncoherentGossipError, "Gossip doesn't belong to this Channel"
67
+ end
68
+
69
+ diff.filter do |change|
70
+ key = change[:path].join('/')
71
+ if SKIPABLE.include?(key)
72
+ false
73
+ elsif APPLICABLE.include?(key)
74
+ apply!(actual, key, change)
75
+ true
76
+ else
77
+ raise Lighstorm::Errors::MissingGossipHandlerError, "don't know how to apply '#{key}'"
78
+ end
79
+ end
80
+ end
81
+
82
+ def self.apply!(actual, key, change)
83
+ case key
84
+ when 'accounting/capacity/millisatoshis'
85
+ token = SecureRandom.hex
86
+ actual.accounting.prepare_token!(token)
87
+ actual.accounting.capacity = {
88
+ value: Model::Satoshis.new(millisatoshis: change[:to]),
89
+ token: token
90
+ }
91
+ when 'partners/0/policy/htlc/maximum/millisatoshis',
92
+ 'partners/1/policy/htlc/maximum/millisatoshis' then
93
+ policy = actual.partners[change[:path][1]].policy
94
+
95
+ token = SecureRandom.hex
96
+ policy.htlc.prepare_token!(token)
97
+ policy.htlc.maximum = {
98
+ value: Model::Satoshis.new(millisatoshis: change[:to]),
99
+ token: token
100
+ }
101
+ when 'partners/0/policy/htlc/minimum/millisatoshis',
102
+ 'partners/1/policy/htlc/minimum/millisatoshis' then
103
+ if actual.partners[change[:path][1]].policy.nil?
104
+ actual.partners[change[:path][1]].policy = Lighstorm::Lightning::Model::Policy.new(
105
+ {}, nil
106
+ )
107
+ end
108
+
109
+ policy = actual.partners[change[:path][1]].policy
110
+
111
+ token = SecureRandom.hex
112
+ policy.htlc.prepare_token!(token)
113
+ policy.htlc.minimum = {
114
+ value: Model::Satoshis.new(millisatoshis: change[:to]),
115
+ token: token
116
+ }
117
+ when 'partners/0/policy/htlc/blocks/delta/minimum',
118
+ 'partners/1/policy/htlc/blocks/delta/minimum' then
119
+ if actual.partners[change[:path][1]].policy.nil?
120
+ actual.partners[change[:path][1]].policy = Lighstorm::Lightning::Model::Policy.new(
121
+ {}, nil
122
+ )
123
+ end
124
+
125
+ policy = actual.partners[change[:path][1]].policy
126
+
127
+ token = SecureRandom.hex
128
+ policy.htlc.blocks.delta.prepare_token!(token)
129
+ policy.htlc.blocks.delta.minimum = {
130
+ value: change[:to],
131
+ token: token
132
+ }
133
+ when 'partners/0/policy/fee/rate/parts_per_million',
134
+ 'partners/1/policy/fee/rate/parts_per_million' then
135
+ policy = actual.partners[change[:path][1]].policy
136
+
137
+ token = SecureRandom.hex
138
+ policy.fee.prepare_token!(token)
139
+ policy.fee.rate = {
140
+ value: Model::Lightning::Rate.new(parts_per_million: change[:to]),
141
+ token: token
142
+ }
143
+ when 'partners/0/policy/fee/base/millisatoshis',
144
+ 'partners/1/policy/fee/base/millisatoshis' then
145
+ policy = actual.partners[change[:path][1]].policy
146
+
147
+ token = SecureRandom.hex
148
+ policy.fee.prepare_token!(token)
149
+ policy.fee.base = {
150
+ value: Model::Satoshis.new(millisatoshis: change[:to]),
151
+ token: token
152
+ }
153
+ when 'partners/0/state',
154
+ 'partners/1/state' then
155
+ partner = actual.partners[change[:path][1]]
156
+
157
+ token = SecureRandom.hex
158
+ partner.prepare_token!(token)
159
+ partner.state = { value: change[:to], token: token }
160
+ else
161
+ raise Lighstorm::Errors::MissingGossipHandlerError, "don't know how to apply '#{key}'"
162
+ end
163
+ end
164
+
165
+ def self.generate_diff(actual, node, path = [], diff = [])
166
+ case node
167
+ when Hash
168
+ result = {}
169
+ node.each_key do |key|
170
+ result[key] = generate_diff(actual, node[key], path.dup.push(key), diff)
171
+ end
172
+ when Array
173
+ result = []
174
+ node.each_with_index do |value, i|
175
+ result << generate_diff(actual, value, path.dup.push(i), diff)
176
+ end
177
+ else
178
+ new_value = node
179
+
180
+ unless new_value.nil?
181
+ actual_value = actual
182
+ path.each do |key|
183
+ if actual_value[key]
184
+ actual_value = actual_value[key]
185
+ else
186
+ actual_value = nil
187
+ break
188
+ end
189
+ end
190
+
191
+ diff << { path: path, from: actual_value, to: new_value } if actual_value != new_value
192
+ end
193
+ end
194
+
195
+ diff
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../ports/grpc'
4
+ require_relative '../../../../models/errors'
5
+ require_relative '../../../../models/satoshis'
6
+ require_relative '../../../../models/lightning/rate'
7
+ require_relative '../../../action'
8
+
9
+ module Lighstorm
10
+ module Controller
11
+ module Lightning
12
+ module Channel
13
+ module UpdateFee
14
+ def self.prepare(policy, transaction, params)
15
+ grpc_request = {
16
+ service: :lightning,
17
+ method: :update_channel_policy,
18
+ params: {
19
+ chan_point: {
20
+ funding_txid_str: transaction[:funding][:id],
21
+ output_index: transaction[:funding][:index]
22
+ },
23
+ base_fee_msat: policy[:fee][:base][:millisatoshis],
24
+ fee_rate_ppm: policy[:fee][:rate][:parts_per_million],
25
+ time_lock_delta: policy[:htlc][:blocks][:delta][:minimum],
26
+ max_htlc_msat: policy[:htlc][:maximum][:millisatoshis],
27
+ min_htlc_msat: policy[:htlc][:minimum][:millisatoshis]
28
+ }
29
+ }
30
+
31
+ if params[:rate] && params[:rate][:parts_per_million]
32
+ if (params[:rate][:parts_per_million]).negative?
33
+ raise Errors::NegativeNotAllowedError,
34
+ "fee rate can't be negative: #{params[:rate][:parts_per_million]}"
35
+ end
36
+
37
+ grpc_request[:params][:fee_rate_ppm] = params[:rate][:parts_per_million]
38
+ end
39
+
40
+ if params[:base] && params[:base][:millisatoshis]
41
+ if (params[:base][:millisatoshis]).negative?
42
+ raise Errors::NegativeNotAllowedError, "fee base can't be negative: #{params[:base][:millisatoshis]}"
43
+ end
44
+
45
+ grpc_request[:params][:base_fee_msat] = params[:base][:millisatoshis]
46
+ end
47
+
48
+ grpc_request
49
+ end
50
+
51
+ def self.call(components, grpc_request)
52
+ components[:grpc].send(grpc_request[:service]).send(
53
+ grpc_request[:method], grpc_request[:params]
54
+ ).to_h
55
+ end
56
+
57
+ def self.dispatch(components, grpc_request, &vcr)
58
+ if vcr.nil?
59
+ call(components, grpc_request)
60
+ else
61
+ vcr.call(-> { call(components, grpc_request) }, :dispatch)
62
+ end
63
+ end
64
+
65
+ def self.perform(components, policy, transaction, params, preview: false, &vcr)
66
+ grpc_request = prepare(policy.to_h, transaction.to_h, params)
67
+
68
+ return grpc_request if preview
69
+
70
+ response = dispatch(components, grpc_request, &vcr)
71
+
72
+ raise UpdateChannelPolicyError.new(nil, response) unless response[:failed_updates].empty?
73
+
74
+ token = SecureRandom.hex
75
+ policy.fee.prepare_token!(token)
76
+ policy.fee.base = {
77
+ value: Model::Satoshis.new(millisatoshis: grpc_request[:params][:base_fee_msat]),
78
+ token: token
79
+ }
80
+
81
+ token = SecureRandom.hex
82
+ policy.fee.prepare_token!(token)
83
+ policy.fee.rate = {
84
+ value: Model::Lightning::Rate.new(parts_per_million: grpc_request[:params][:fee_rate_ppm]),
85
+ token: token
86
+ }
87
+
88
+ Action::Output.new({ request: grpc_request, response: response, result: policy })
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mine'
4
+
5
+ require_relative '../../../ports/grpc'
6
+ require_relative '../../../adapters/lightning/edges/channel'
7
+ require_relative '../../../adapters/lightning/nodes/node'
8
+ require_relative '../../../adapters/lightning/connections/channel_node/fee'
9
+
10
+ module Lighstorm
11
+ module Controller
12
+ module Lightning
13
+ module Channel
14
+ module All
15
+ def self.fetch(components, limit: nil)
16
+ data = {
17
+ at: Time.now,
18
+ mine: Mine.fetch(components),
19
+ describe_graph: components[:grpc].lightning.describe_graph.edges
20
+ }
21
+
22
+ data[:describe_graph] = data[:describe_graph][0..limit - 1] unless limit.nil?
23
+
24
+ data
25
+ end
26
+
27
+ def self.adapt(raw)
28
+ mine_adapted = Mine.adapt(raw[:mine])
29
+
30
+ mine = mine_adapted[:list_channels].map do |data|
31
+ Mine.transform(data, mine_adapted)
32
+ end
33
+
34
+ adapted = {
35
+ mine: {},
36
+ describe_graph: raw[:describe_graph].map do |raw_channel|
37
+ Lighstorm::Adapter::Lightning::Channel.describe_graph(raw_channel.to_h)
38
+ end
39
+ }
40
+
41
+ mine.each do |channel|
42
+ adapted[:mine][channel[:id]] = channel
43
+ end
44
+
45
+ adapted
46
+ end
47
+
48
+ def self.transform(data, adapted)
49
+ return adapted[:mine][data[:id]] if adapted[:mine][data[:id]]
50
+
51
+ data[:known] = true
52
+ data[:mine] = false
53
+
54
+ data[:partners].each do |partner|
55
+ partner[:node][:platform] = {
56
+ blockchain: adapted[:mine].first[1][:partners][0][:node][:platform][:blockchain],
57
+ network: adapted[:mine].first[1][:partners][0][:node][:platform][:network]
58
+ }
59
+ end
60
+
61
+ data
62
+ end
63
+
64
+ def self.data(components, limit: nil, &vcr)
65
+ raw = if vcr.nil?
66
+ fetch(components, limit: limit)
67
+ else
68
+ vcr.call(-> { fetch(components, limit: limit) })
69
+ end
70
+
71
+ adapted = adapt(raw)
72
+
73
+ adapted[:describe_graph].map { |data| transform(data, adapted) }
74
+ end
75
+
76
+ def self.model(data, components)
77
+ data.map do |node_data|
78
+ Lighstorm::Model::Lightning::Channel.new(node_data, components)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../ports/grpc'
4
+ require_relative '../../../adapters/lightning/edges/channel'
5
+ require_relative '../../../adapters/lightning/nodes/node'
6
+ require_relative '../../../adapters/lightning/connections/channel_node/fee'
7
+
8
+ require_relative '../node/find_by_public_key'
9
+
10
+ module Lighstorm
11
+ module Controller
12
+ module Lightning
13
+ module Channel
14
+ module FindById
15
+ def self.fetch(components, id)
16
+ data = {
17
+ at: Time.now,
18
+ get_info: components[:grpc].lightning.get_info.to_h,
19
+ # Ensure that we are getting fresh up-date data about our own fees.
20
+ fee_report: components[:grpc].lightning.fee_report.to_h,
21
+ get_chan_info: components[:grpc].lightning.get_chan_info(chan_id: id.to_i).to_h,
22
+ get_node_info: {},
23
+ list_channels: []
24
+ }
25
+
26
+ data[:get_node_info][data[:get_chan_info][:node1_pub]] = components[:grpc].lightning.get_node_info(
27
+ pub_key: data[:get_chan_info][:node1_pub]
28
+ ).to_h
29
+
30
+ data[:get_node_info][data[:get_chan_info][:node2_pub]] = components[:grpc].lightning.get_node_info(
31
+ pub_key: data[:get_chan_info][:node2_pub]
32
+ ).to_h
33
+
34
+ partners = [
35
+ data[:get_chan_info][:node1_pub],
36
+ data[:get_chan_info][:node2_pub]
37
+ ]
38
+
39
+ is_mine = partners.include?(data[:get_info][:identity_pubkey])
40
+
41
+ if is_mine
42
+ partner = partners.find { |p| p != data[:get_info][:identity_pubkey] }
43
+
44
+ data[:list_channels] = components[:grpc].lightning.list_channels(
45
+ peer: [partner].pack('H*')
46
+ ).channels.map(&:to_h)
47
+ end
48
+
49
+ data
50
+ end
51
+
52
+ def self.adapt(raw)
53
+ adapted = {
54
+ get_info: Lighstorm::Adapter::Lightning::Node.get_info(raw[:get_info]),
55
+ get_chan_info: Lighstorm::Adapter::Lightning::Channel.get_chan_info(raw[:get_chan_info]),
56
+ fee_report: raw[:fee_report][:channel_fees].map do |raw_fee|
57
+ Lighstorm::Adapter::Lightning::Fee.fee_report(raw_fee.to_h)
58
+ end,
59
+ list_channels: raw[:list_channels].map do |raw_channel|
60
+ Lighstorm::Adapter::Lightning::Channel.list_channels(raw_channel.to_h, raw[:at])
61
+ end,
62
+ get_node_info: {}
63
+ }
64
+
65
+ raw[:get_node_info].each_key do |public_key|
66
+ adapted[:get_node_info][public_key] = Lighstorm::Adapter::Lightning::Node.get_node_info(
67
+ raw[:get_node_info][public_key]
68
+ )
69
+ end
70
+
71
+ adapted
72
+ end
73
+
74
+ def self.transform(data, adapted)
75
+ [0, 1].each do |i|
76
+ adapted[:list_channels].each_index do |c|
77
+ if adapted[:list_channels][c][:partners][i][:node].nil?
78
+ adapted[:list_channels][c][:partners][i][:node] = adapted[:get_info]
79
+ end
80
+ end
81
+ end
82
+
83
+ data[:known] = true
84
+ data[:mine] = false
85
+ data[:exposure] = 'public'
86
+
87
+ [0, 1].each do |i|
88
+ data[:partners][i][:node] = adapted[:get_info] if data[:partners][i][:node][:public_key].nil?
89
+
90
+ if data[:partners][i][:node][:public_key] == adapted[:get_info][:public_key]
91
+ data[:partners][i][:node] = adapted[:get_info]
92
+ data[:partners][i][:node][:myself] = true
93
+ data[:mine] = true
94
+ adapted[:fee_report].each do |channel|
95
+ next unless data[:id] == channel[:id]
96
+
97
+ data[:partners][i][:policy][:fee] = channel[:partner][:policy][:fee]
98
+ break
99
+ end
100
+ else
101
+ data[:partners][i][:node] = adapted[:get_node_info][data[:partners][i][:node][:public_key]]
102
+ data[:partners][i][:node][:platform] = {
103
+ blockchain: adapted[:get_info][:platform][:blockchain],
104
+ network: adapted[:get_info][:platform][:network]
105
+ }
106
+
107
+ data[:partners][i][:node][:myself] = false
108
+ end
109
+ end
110
+
111
+ adapted[:list_channels].each do |channel|
112
+ next unless channel[:id] == data[:id]
113
+
114
+ channel.each_key do |key|
115
+ next if data.key?(key)
116
+
117
+ data[key] = channel[key]
118
+ end
119
+
120
+ data[:accounting] = channel[:accounting]
121
+
122
+ channel[:partners].each do |partner|
123
+ data[:partners].each_index do |i|
124
+ next unless data[:partners][i][:node][:public_key] == partner[:node][:public_key]
125
+
126
+ partner.each_key do |key|
127
+ next if data[:partners][i].key?(key)
128
+
129
+ data[:partners][i][key] = partner[key]
130
+ end
131
+ end
132
+ end
133
+
134
+ break
135
+ end
136
+
137
+ data
138
+ end
139
+
140
+ def self.data(components, id, &vcr)
141
+ raw = vcr.nil? ? fetch(components, id) : vcr.call(-> { fetch(components, id) })
142
+
143
+ adapted = adapt(raw)
144
+
145
+ transform(adapted[:get_chan_info], adapted)
146
+ end
147
+
148
+ def self.model(data, components)
149
+ Lighstorm::Model::Lightning::Channel.new(data, components)
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../ports/grpc'
4
+ require_relative '../../../adapters/lightning/edges/channel'
5
+ require_relative '../../../adapters/lightning/nodes/node'
6
+ require_relative '../../../adapters/lightning/connections/channel_node/fee'
7
+
8
+ module Lighstorm
9
+ module Controller
10
+ module Lightning
11
+ module Channel
12
+ module Mine
13
+ def self.fetch(components)
14
+ data = {
15
+ at: Time.now,
16
+ get_info: components[:grpc].lightning.get_info.to_h,
17
+ # Ensure that we are getting fresh up-date data about our own fees.
18
+ fee_report: components[:grpc].lightning.fee_report.to_h,
19
+ list_channels: components[:grpc].lightning.list_channels.channels.map(&:to_h),
20
+ get_chan_info: {},
21
+ get_node_info: {}
22
+ }
23
+
24
+ data[:list_channels].each do |channel|
25
+ unless data[:get_chan_info][channel[:chan_id]]
26
+ data[:get_chan_info][channel[:chan_id]] = components[:grpc].lightning.get_chan_info(
27
+ chan_id: channel[:chan_id]
28
+ ).to_h
29
+ end
30
+
31
+ next if data[:get_node_info][channel[:remote_pubkey]]
32
+
33
+ data[:get_node_info][channel[:remote_pubkey]] = components[:grpc].lightning.get_node_info(
34
+ pub_key: channel[:remote_pubkey]
35
+ ).to_h
36
+ end
37
+
38
+ data
39
+ end
40
+
41
+ def self.adapt(raw)
42
+ adapted = {
43
+ get_info: Lighstorm::Adapter::Lightning::Node.get_info(raw[:get_info]),
44
+ fee_report: raw[:fee_report][:channel_fees].map do |raw_fee|
45
+ Lighstorm::Adapter::Lightning::Fee.fee_report(raw_fee.to_h)
46
+ end,
47
+ list_channels: raw[:list_channels].map do |raw_channel|
48
+ Lighstorm::Adapter::Lightning::Channel.list_channels(raw_channel.to_h, raw[:at])
49
+ end,
50
+ get_chan_info: {},
51
+ get_node_info: {}
52
+ }
53
+
54
+ raw[:get_chan_info].each do |key, value|
55
+ adapted[:get_chan_info][key] = Lighstorm::Adapter::Lightning::Channel.get_chan_info(value.to_h)
56
+ end
57
+
58
+ raw[:get_node_info].each do |key, value|
59
+ adapted[:get_node_info][key] = Lighstorm::Adapter::Lightning::Node.get_node_info(value.to_h)
60
+ end
61
+
62
+ adapted
63
+ end
64
+
65
+ def self.transform(data, adapted)
66
+ [0, 1].each do |i|
67
+ data[:partners][i][:node] = adapted[:get_info] if data[:partners][i][:node].nil?
68
+
69
+ adapted[:get_chan_info][data[:id].to_i][:partners].each do |partner|
70
+ if data[:partners][i][:node][:public_key] == partner[:node][:public_key]
71
+ data[:partners][i][:policy] = partner[:policy]
72
+ end
73
+ end
74
+
75
+ if data[:partners][i][:node][:public_key] == adapted[:get_info][:public_key]
76
+ data[:partners][i][:node][:platform] = adapted[:get_info][:platform]
77
+ data[:partners][i][:node][:myself] = true
78
+ data[:known] = true
79
+ data[:mine] = true
80
+ adapted[:fee_report].each do |channel|
81
+ next unless data[:id] == channel[:id]
82
+
83
+ data[:partners][i][:policy][:fee] = channel[:partner][:policy][:fee]
84
+ break
85
+ end
86
+ else
87
+ data[:partners][i][:node] = adapted[:get_node_info][data[:partners][i][:node][:public_key]]
88
+ data[:partners][i][:node][:platform] = {
89
+ blockchain: adapted[:get_info][:platform][:blockchain],
90
+ network: adapted[:get_info][:platform][:network]
91
+ }
92
+
93
+ data[:partners][i][:node][:myself] = false
94
+ end
95
+ end
96
+ data
97
+ end
98
+
99
+ def self.data(components, &vcr)
100
+ raw = vcr.nil? ? fetch(components) : vcr.call(-> { fetch(components) })
101
+
102
+ adapted = adapt(raw)
103
+
104
+ adapted[:list_channels].map { |data| transform(data, adapted) }
105
+ end
106
+
107
+ def self.model(data, components)
108
+ data.map do |node_data|
109
+ Lighstorm::Model::Lightning::Channel.new(node_data, components)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../concerns/impersonatable'
4
+
5
+ require_relative './channel/mine'
6
+ require_relative './channel/all'
7
+ require_relative './channel/find_by_id'
8
+
9
+ module Lighstorm
10
+ module Controller
11
+ module Lightning
12
+ module Channel
13
+ extend Impersonatable
14
+
15
+ class DSL < Impersonatable::DSL
16
+ def mine(injected_components = nil)
17
+ if injected_components.nil?
18
+ Mine.model(Mine.data(components), components)
19
+ else
20
+ Mine.model(Mine.data(injected_components), injected_components)
21
+ end
22
+ end
23
+
24
+ def all(limit: nil)
25
+ All.model(All.data(components, limit: limit), components)
26
+ end
27
+
28
+ def find_by_id(id, injected_components = nil)
29
+ if injected_components.nil?
30
+ FindById.model(FindById.data(components, id), components)
31
+ else
32
+ FindById.model(FindById.data(injected_components, id), injected_components)
33
+ end
34
+ end
35
+
36
+ def adapt(dump: nil, gossip: nil)
37
+ Model::Lightning::Channel.adapt(dump: dump, gossip: gossip)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end