lighstorm 0.0.12 → 0.0.14

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +18 -3
  3. data/Gemfile.lock +4 -4
  4. data/README.md +11 -5
  5. data/adapters/connections/channel_node.rb +1 -0
  6. data/adapters/edges/payment/purpose.rb +3 -3
  7. data/adapters/edges/payment.rb +1 -3
  8. data/adapters/invoice.rb +0 -2
  9. data/adapters/transaction.rb +23 -0
  10. data/adapters/wallet.rb +42 -0
  11. data/components/cache.rb +1 -1
  12. data/components/lnd.rb +67 -29
  13. data/controllers/action.rb +5 -0
  14. data/controllers/activity/all.rb +194 -0
  15. data/controllers/activity.rb +26 -0
  16. data/controllers/channel/actions/apply_gossip.rb +3 -4
  17. data/controllers/channel/actions/update_fee.rb +11 -7
  18. data/controllers/channel/all.rb +11 -7
  19. data/controllers/channel/find_by_id.rb +11 -11
  20. data/controllers/channel/mine.rb +10 -10
  21. data/controllers/channel.rb +25 -11
  22. data/controllers/concerns/impersonatable.rb +33 -0
  23. data/controllers/connection.rb +33 -0
  24. data/controllers/forward/all.rb +16 -12
  25. data/controllers/forward/group_by_channel.rb +2 -2
  26. data/controllers/forward.rb +19 -13
  27. data/controllers/invoice/actions/create.rb +21 -13
  28. data/controllers/invoice/actions/pay.rb +13 -12
  29. data/controllers/invoice/actions/pay_through_route.rb +2 -2
  30. data/controllers/invoice/all.rb +7 -7
  31. data/controllers/invoice/decode.rb +6 -6
  32. data/controllers/invoice/find_by_code.rb +7 -7
  33. data/controllers/invoice/find_by_secret_hash.rb +10 -6
  34. data/controllers/invoice.rb +46 -39
  35. data/controllers/node/actions/apply_gossip.rb +1 -1
  36. data/controllers/node/actions/pay.rb +13 -12
  37. data/controllers/node/all.rb +11 -7
  38. data/controllers/node/find_by_public_key.rb +11 -7
  39. data/controllers/node/myself.rb +6 -6
  40. data/controllers/node.rb +17 -11
  41. data/controllers/payment/actions/pay.rb +23 -19
  42. data/controllers/payment/all.rb +7 -4
  43. data/controllers/payment.rb +20 -14
  44. data/controllers/secret/valid_proof.rb +5 -5
  45. data/controllers/transaction/all.rb +29 -73
  46. data/controllers/transaction.rb +14 -6
  47. data/controllers/wallet/balance.rb +34 -0
  48. data/controllers/wallet.rb +19 -0
  49. data/docs/README.md +204 -31
  50. data/docs/_coverpage.md +1 -1
  51. data/docs/index.html +1 -1
  52. data/lighstorm.gemspec +1 -1
  53. data/models/activity.rb +52 -0
  54. data/models/connections/channel_node/fee.rb +5 -2
  55. data/models/connections/channel_node/policy.rb +3 -2
  56. data/models/connections/channel_node.rb +14 -4
  57. data/models/connections/forward_channel.rb +3 -2
  58. data/models/edges/channel/hop.rb +1 -1
  59. data/models/edges/channel.rb +5 -7
  60. data/models/edges/forward.rb +4 -3
  61. data/models/edges/groups/channel_forwards.rb +3 -2
  62. data/models/edges/payment.rb +4 -3
  63. data/models/errors.rb +16 -24
  64. data/models/invoice.rb +10 -4
  65. data/models/nodes/node.rb +10 -4
  66. data/models/secret.rb +10 -4
  67. data/models/transaction.rb +10 -15
  68. data/models/wallet.rb +40 -0
  69. data/ports/dsl/lighstorm.rb +8 -4
  70. data/ports/grpc.rb +30 -2
  71. data/static/cache.rb +3 -0
  72. data/static/spec.rb +1 -1
  73. metadata +14 -5
  74. data/deleted.sh +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 026ad34b202b5f4367e287568b22126ba4850145b9d3e9398cdfd2f70d9e25d7
4
- data.tar.gz: 63b0809d04e688ceab5c7a3ff5e9ee05588c8fece0a7b6323f96b8f0a871f9eb
3
+ metadata.gz: 9b600975d39699ef54c291ec8a06aa0d3f4284df248df2093ed85c3656dea685
4
+ data.tar.gz: 6d6373c5013c5ed9ad9f8479b26072da38f5847ba1e22b845132bd01167cacf2
5
5
  SHA512:
6
- metadata.gz: 00ba8bf8fa6f5930abb796bdb00434401a31d30db6d26397ea1cebeb587ce404b942777dd0df6eed38d8e24fec5f6574afaf3d343108379f1d359f7def4a80ba
7
- data.tar.gz: 39ebcc45331f332c5aa85e824245aec7e707bed958625d123cdb655f250610a361ae56a6dc0a8657ec34dcda977bd7e0630b47e82f0edb511b5cbf3a16b584bd
6
+ metadata.gz: 66a0b3ea07b3201a388b68cf91f38aad7d98ceecf1bd9138f699830c3539ea6522cfdb9a23479bebd3f88563a265fa04bc10e510c033eeb228dbbd039e97cc52
7
+ data.tar.gz: 32c16160feef6212038150df78f539c4b4adca382f440729217f3916871912f20fdbe2add7d4c74be22d14e0f3bb5e5369e6788124b6e6ad879368ffad60c948
data/.env.example CHANGED
@@ -1,6 +1,21 @@
1
- LIGHSTORM_LND_ADDRESS=127.0.0.1:10009
2
- LIGHSTORM_CERTIFICATE_PATH=/lnd/tls.cert
3
- LIGHSTORM_MACAROON_PATH=/lnd/data/chain/bitcoin/mainnet/admin.macaroon
4
1
  LIGHSTORM_RUN_INTEGRATION_TESTS=false
5
2
  LIGHSTORM_RUN_INTEGRATION_TESTS_SLOW=false
6
3
  LIGHSTORM_DELETE_UNUSED_TEST_DATA=false
4
+
5
+ # Option A: lndconnect
6
+ # LIGHSTORM_LND_CONNECT=lndconnect://127.0.0.1:10009?cert=MIICJz...JBEERQ&macaroon=AgEDbG...45ukJ4
7
+
8
+ # Option B: File Path
9
+ # LIGHSTORM_LND_ADDRESS=127.0.0.1:10009
10
+ # LIGHSTORM_LND_CERTIFICATE_PATH=/lnd/tls.cert
11
+ # LIGHSTORM_LND_MACAROON_PATH=/lnd/data/chain/bitcoin/mainnet/admin.macaroon
12
+
13
+ # Option C: Base64
14
+ # LIGHSTORM_LND_ADDRESS=127.0.0.1:10009
15
+ # LIGHSTORM_LND_CERTIFICATE=LS0tLS1CRU...UtLS0tLQo=
16
+ # LIGHSTORM_LND_MACAROON=AgEDbG5kAv...inv45ukJ4=
17
+
18
+ # Option D: Hex
19
+ # LIGHSTORM_LND_ADDRESS=127.0.0.1:10009
20
+ # LIGHSTORM_LND_CERTIFICATE=2d2d2d2d2d...2d2d2d2d0a
21
+ # LIGHSTORM_LND_MACAROON=0201036c6e...bf8e6e909e
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lighstorm (0.0.12)
4
+ lighstorm (0.0.14)
5
5
  dotenv (~> 2.8, >= 2.8.1)
6
- lnd-client (~> 0.0.5)
6
+ lnd-client (~> 0.0.7)
7
7
  zache (~> 0.12.0)
8
8
 
9
9
  GEM
@@ -22,7 +22,7 @@ GEM
22
22
  google-protobuf (~> 3.21)
23
23
  googleapis-common-protos-types (~> 1.0)
24
24
  json (2.6.3)
25
- lnd-client (0.0.5)
25
+ lnd-client (0.0.7)
26
26
  grpc (~> 1.52)
27
27
  method_source (1.0.0)
28
28
  parallel (1.22.1)
@@ -51,7 +51,7 @@ GEM
51
51
  diff-lcs (>= 1.2.0, < 2.0)
52
52
  rspec-support (~> 3.12.0)
53
53
  rspec-support (3.12.0)
54
- rubocop (1.48.0)
54
+ rubocop (1.48.1)
55
55
  json (~> 2.3)
56
56
  parallel (~> 1.10)
57
57
  parser (>= 3.2.0.0)
data/README.md CHANGED
@@ -35,19 +35,25 @@ Although it tries to stay close to [Lightning's terminologies](https://docs.ligh
35
35
  Add to your `Gemfile`:
36
36
 
37
37
  ```ruby
38
- gem 'lighstorm', '~> 0.0.12'
38
+ gem 'lighstorm', '~> 0.0.14'
39
39
  ```
40
40
 
41
41
  ```ruby
42
42
  require 'lighstorm'
43
43
 
44
- Lighstorm.config!(
45
- lnd_address: '127.0.0.1:10009',
44
+ # lndconnect
45
+ Lighstorm.connect!(
46
+ 'lndconnect://127.0.0.1:10009?cert=MIICJz...JBEERQ&macaroon=AgEDbG...45ukJ4'
47
+ )
48
+
49
+ # File Path
50
+ Lighstorm.connect!(
51
+ address: '127.0.0.1:10009',
46
52
  certificate_path: '/lnd/tls.cert',
47
- macaroon_path: '/lnd/data/chain/bitcoin/mainnet/admin.macaroon',
53
+ macaroon_path: '/lnd/data/chain/bitcoin/mainnet/admin.macaroon'
48
54
  )
49
55
 
50
- puts Lighstorm.version # => 0.0.12
56
+ puts Lighstorm.version # => 0.0.14
51
57
 
52
58
  Lighstorm::Node.myself.alias # => icebaker/old-stone
53
59
 
@@ -10,6 +10,7 @@ module Lighstorm
10
10
  data = {
11
11
  _source: :list_channels,
12
12
  state: grpc[:active] ? 'active' : 'inactive',
13
+ initiator: grpc[:initiator] && key == :local,
13
14
  accounting: { balance: { millisatoshis: grpc[:"#{key}_balance"] * 1000 } },
14
15
  node: Node.list_channels(grpc, key)
15
16
  }
@@ -16,9 +16,9 @@ module Lighstorm
16
16
  def self.list_payments(grpc, node_get_info)
17
17
  return 'unknown' if grpc[:htlcs].empty?
18
18
 
19
- return 'self-payment' if self_payment?(grpc[:htlcs].first[:route][:hops])
20
- return 'peer-to-peer' if peer_to_peer?(grpc[:htlcs].first[:route][:hops])
21
- return 'rebalance' if rebalance?(grpc[:htlcs].first[:route][:hops], node_get_info)
19
+ return 'self-payment' if self_payment?(grpc[:htlcs].last[:route][:hops])
20
+ return 'peer-to-peer' if peer_to_peer?(grpc[:htlcs].last[:route][:hops])
21
+ return 'rebalance' if rebalance?(grpc[:htlcs].last[:route][:hops], node_get_info)
22
22
 
23
23
  'payment'
24
24
  end
@@ -30,8 +30,6 @@ module Lighstorm
30
30
  end
31
31
 
32
32
  def self.list_payments(grpc, node_myself, invoice_decode = nil)
33
- raise UnexpectedNumberOfHTLCsError, "htlcs: #{grpc[:htlcs].size}" if grpc[:htlcs].size > 1
34
-
35
33
  data = {
36
34
  _source: :list_payments,
37
35
  _key: _key(grpc),
@@ -45,7 +43,7 @@ module Lighstorm
45
43
 
46
44
  data[:secret] = data[:invoice][:secret]
47
45
 
48
- htlc = grpc[:htlcs].first
46
+ htlc = grpc[:htlcs].last
49
47
 
50
48
  return data if htlc.nil?
51
49
 
data/adapters/invoice.rb CHANGED
@@ -142,8 +142,6 @@ module Lighstorm
142
142
  end
143
143
 
144
144
  def self.list_payments(grpc, invoice_decode = nil)
145
- raise UnexpectedNumberOfHTLCsError, "htlcs: #{grpc[:htlcs].size}" if grpc[:htlcs].size > 1
146
-
147
145
  data = {
148
146
  _key: _key(grpc),
149
147
  _source: :list_payments,
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Lighstorm
6
+ module Adapter
7
+ class Transaction
8
+ def self.get_transactions(grpc)
9
+ {
10
+ _source: :get_transactions,
11
+ _key: Digest::SHA256.hexdigest(
12
+ [grpc[:time_stamp], grpc[:tx_hash], grpc[:amount], grpc[:total_fees]].join('/')
13
+ ),
14
+ at: Time.at(grpc[:time_stamp]),
15
+ amount: { millisatoshis: grpc[:amount] * 1000 },
16
+ fee: { millisatoshis: grpc[:total_fees] * 1000 },
17
+ hash: grpc[:tx_hash],
18
+ label: grpc[:label]
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Lighstorm
6
+ module Adapter
7
+ class Wallet
8
+ def self.balance(raw)
9
+ {
10
+ _key: Digest::SHA256.hexdigest(
11
+ [
12
+ raw[:at],
13
+ channel_balance(raw[:channel_balance])[:amount],
14
+ wallet_balance(raw[:wallet_balance])[:amount]
15
+ ].join('/')
16
+ ),
17
+ at: raw[:at],
18
+ bitcoin: wallet_balance(raw[:wallet_balance])[:amount],
19
+ lightning: channel_balance(raw[:channel_balance])[:amount],
20
+ total: { millisatoshis: (
21
+ wallet_balance(raw[:wallet_balance])[:amount][:millisatoshis] +
22
+ channel_balance(raw[:channel_balance])[:amount][:millisatoshis]
23
+ ) }
24
+ }
25
+ end
26
+
27
+ def self.wallet_balance(grpc)
28
+ {
29
+ _source: :wallet_balance,
30
+ amount: { millisatoshis: grpc[:total_balance] * 1000 }
31
+ }
32
+ end
33
+
34
+ def self.channel_balance(grpc)
35
+ {
36
+ _source: :channel_balance,
37
+ amount: { millisatoshis: grpc[:local_balance][:msat] }
38
+ }
39
+ end
40
+ end
41
+ end
42
+ end
data/components/cache.rb CHANGED
@@ -22,7 +22,7 @@ module Lighstorm
22
22
  end
23
23
 
24
24
  def safety_key(key)
25
- key.gsub('.', '_').to_sym
25
+ key.gsub('.', '_').sub(/^\[.*\]:/, '').to_sym
26
26
  end
27
27
 
28
28
  def for(key, ttl: nil, params: {}, &block)
data/components/lnd.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'singleton'
4
-
4
+ require 'securerandom'
5
5
  require 'lnd-client'
6
6
 
7
7
  require_relative '../ports/dsl/lighstorm/errors'
@@ -10,50 +10,88 @@ module Lighstorm
10
10
  class LND
11
11
  include Singleton
12
12
 
13
- attr_writer :config, :middleware
13
+ attr_writer :middleware
14
14
 
15
15
  def initialize
16
- @config = nil
17
- @client = nil
16
+ @default_key = SecureRandom.hex
18
17
  @middleware = ->(_key, &block) { block.call }
19
18
  end
20
19
 
20
+ def connect!(*params)
21
+ if params.last.is_a?(Hash)
22
+ unless params.last.key?(:lightning)
23
+ params.last[:lightning] = {
24
+ channel_args: { 'grpc.max_receive_message_length' => 1024 * 1024 * 50 }
25
+ }
26
+ end
27
+ else
28
+ params << {
29
+ lightning: { channel_args: { 'grpc.max_receive_message_length' => 1024 * 1024 * 50 } }
30
+ }
31
+ end
32
+
33
+ LNDClient.add_connection!(@default_key, *params)
34
+ end
35
+
36
+ def as(id)
37
+ LNDClient.as(id)
38
+ end
39
+
40
+ def add_connection!(...)
41
+ LNDClient.add_connection!(...)
42
+ end
43
+
44
+ def connections(...)
45
+ LNDClient.connections(...)
46
+ end
47
+
48
+ def remove_connection!(...)
49
+ LNDClient.remove_connection!(...)
50
+ end
51
+
21
52
  def middleware(key, &block)
22
53
  @middleware.call(key, &block)
23
54
  end
24
55
 
56
+ def for(id)
57
+ as(id)&.connection
58
+ end
59
+
60
+ def default
61
+ client.connection.merge(id: @default_key)
62
+ end
63
+
25
64
  def client
26
- return @client if @client
65
+ try_to_connect_from_environment_variables! unless LNDClient.connections.include?(@default_key)
66
+ LNDClient.as(@default_key)
67
+ end
27
68
 
28
- raise MissingCredentialsError, 'missing credentials' if @config.nil? && ENV.fetch(
29
- 'LIGHSTORM_CERTIFICATE_PATH', nil
30
- ).nil?
69
+ def try_to_connect_from_environment_variables!
70
+ return connect!(ENV.fetch('LIGHSTORM_LND_CONNECT')) if ENV.fetch('LIGHSTORM_LND_CONNECT', nil)
31
71
 
32
- @client = if @config
33
- create_client_from_config
34
- else
35
- create_client_from_environment_variables
36
- end
72
+ params = {}
37
73
 
38
- @client.lightning(channel_args: { 'grpc.max_receive_message_length' => 1024 * 1024 * 50 })
74
+ raise MissingCredentialsError, 'missing credentials [address]' unless ENV.fetch('LIGHSTORM_LND_ADDRESS', nil)
39
75
 
40
- @client
41
- end
76
+ params[:address] = ENV.fetch('LIGHSTORM_LND_ADDRESS')
42
77
 
43
- def create_client_from_config
44
- LNDClient.new(
45
- socket_address: @config[:lnd_address],
46
- certificate_path: @config[:certificate_path],
47
- macaroon_path: @config[:macaroon_path]
48
- )
49
- end
78
+ if ENV.fetch('LIGHSTORM_LND_CERTIFICATE', nil)
79
+ params[:certificate] = ENV.fetch('LIGHSTORM_LND_CERTIFICATE')
80
+ elsif ENV.fetch('LIGHSTORM_LND_CERTIFICATE_PATH', nil)
81
+ params[:certificate_path] = ENV.fetch('LIGHSTORM_LND_CERTIFICATE_PATH')
82
+ else
83
+ raise MissingCredentialsError, 'missing credentials [certificate]'
84
+ end
85
+
86
+ if ENV.fetch('LIGHSTORM_LND_MACAROON', nil)
87
+ params[:macaroon] = ENV.fetch('LIGHSTORM_LND_MACAROON')
88
+ elsif ENV.fetch('LIGHSTORM_LND_MACAROON_PATH', nil)
89
+ params[:macaroon_path] = ENV.fetch('LIGHSTORM_LND_MACAROON_PATH')
90
+ else
91
+ raise MissingCredentialsError, 'missing credentials [macaroon]'
92
+ end
50
93
 
51
- def create_client_from_environment_variables
52
- LNDClient.new(
53
- socket_address: ENV.fetch('LIGHSTORM_LND_ADDRESS', nil),
54
- certificate_path: ENV.fetch('LIGHSTORM_CERTIFICATE_PATH', nil),
55
- macaroon_path: ENV.fetch('LIGHSTORM_MACAROON_PATH', nil)
56
- )
94
+ connect!(params)
57
95
  end
58
96
  end
59
97
  end
@@ -4,6 +4,10 @@ module Lighstorm
4
4
  module Controllers
5
5
  module Action
6
6
  Output = Struct.new(:data) do
7
+ def request
8
+ data[:request]
9
+ end
10
+
7
11
  def response
8
12
  data[:response]
9
13
  end
@@ -14,6 +18,7 @@ module Lighstorm
14
18
 
15
19
  def to_h
16
20
  {
21
+ request: request,
17
22
  response: response,
18
23
  result: result.to_h
19
24
  }
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../invoice/all'
4
+ require_relative '../payment/all'
5
+ require_relative '../forward/all'
6
+ require_relative '../transaction/all'
7
+ require_relative '../../models/activity'
8
+
9
+ module Lighstorm
10
+ module Controllers
11
+ module Activity
12
+ module All
13
+ def self.bitcoin_how(transaction_label)
14
+ if transaction_label =~ /:openchannel:/
15
+ 'opening-channel'
16
+ elsif transaction_label =~ /:closechannel:/
17
+ 'closing-channel'
18
+ else
19
+ 'spontaneously'
20
+ end
21
+ end
22
+
23
+ def self.fetch(components, direction: nil, layer: nil, how: nil, order: nil, limit: nil)
24
+ activities = []
25
+
26
+ # components[:grpc].lightning.list_channels.channels.each do |channel|
27
+ # if (layer.nil? || layer == 'lightning')
28
+ # activities << {
29
+ # direction: 'out',
30
+ # layer: 'lightning',
31
+ # at: Time.now,
32
+ # amount: {
33
+ # millisatoshis: channel.to_h[:local_chan_reserve_sat] * 1000
34
+ # },
35
+ # how: 'reserve',
36
+ # message: nil,
37
+ # data: {}
38
+ # }
39
+
40
+ # activities << {
41
+ # direction: 'out',
42
+ # layer: 'lightning',
43
+ # at: Time.now,
44
+ # amount: {
45
+ # millisatoshis: channel.to_h[:commit_fee] * 1000
46
+ # },
47
+ # how: 'commit',
48
+ # message: nil,
49
+ # data: {}
50
+ # }
51
+ # end
52
+ # end
53
+
54
+ Transaction::All.data(components).each do |transaction|
55
+ transaction_how = bitcoin_how(transaction[:label])
56
+
57
+ if (layer.nil? || layer == 'bitcoin') && (how.nil? || transaction_how =~ /#{Regexp.escape(how)}/)
58
+ activities << {
59
+ direction: (transaction[:amount][:millisatoshis]).positive? ? 'in' : 'out',
60
+ layer: 'bitcoin',
61
+ at: transaction[:at],
62
+ amount: {
63
+ millisatoshis: if (transaction[:amount][:millisatoshis]).positive?
64
+ transaction[:amount][:millisatoshis]
65
+ else
66
+ -transaction[:amount][:millisatoshis]
67
+ end
68
+ },
69
+ how: transaction_how,
70
+ message: nil,
71
+ data: { transaction: transaction }
72
+ }
73
+ end
74
+
75
+ next unless (layer.nil? || layer == 'lightning') && (how.nil? || transaction_how =~ /#{Regexp.escape(how)}/) && %w[
76
+ channel opening-channel closing-channel
77
+ ].include?(transaction_how)
78
+
79
+ activities << {
80
+ direction: (transaction[:amount][:millisatoshis]).positive? ? 'out' : 'in',
81
+ layer: 'lightning',
82
+ at: transaction[:at] + ((transaction[:amount][:millisatoshis]).positive? ? -1 : 1),
83
+ amount: {
84
+ millisatoshis: if (transaction[:amount][:millisatoshis]).positive?
85
+ (transaction[:amount][:millisatoshis] - transaction[:fee][:millisatoshis])
86
+ else
87
+ -(transaction[:amount][:millisatoshis] + transaction[:fee][:millisatoshis])
88
+ end
89
+ },
90
+ how: transaction_how,
91
+ message: nil,
92
+ data: { transaction: transaction }
93
+ }
94
+ end
95
+
96
+ if (direction.nil? || direction == 'in') && (layer.nil? || layer == 'lightning')
97
+ Invoice::All.data(components, spontaneous: true).filter do |invoice|
98
+ !invoice[:payments].nil? && invoice[:payments].size.positive?
99
+ end.each do |invoice|
100
+ activity_how = invoice[:code].nil? ? 'spontaneously' : 'with-invoice'
101
+
102
+ next if !how.nil? && how != activity_how
103
+
104
+ # TODO: Improve performance by reducing invoice fields and removing payments?
105
+ invoice[:payments].each do |payment|
106
+ activities << {
107
+ direction: 'in',
108
+ layer: 'lightning',
109
+ at: payment[:at],
110
+ amount: payment[:amount],
111
+ how: activity_how,
112
+ message: payment[:message],
113
+ data: { invoice: invoice }
114
+ }
115
+ end
116
+ end
117
+
118
+ Forward::All.data(components).each do |forward|
119
+ next if !how.nil? && how != 'forwarding'
120
+
121
+ activities << {
122
+ direction: 'in',
123
+ layer: 'lightning',
124
+ at: forward[:at],
125
+ amount: forward[:fee],
126
+ how: 'forwarding',
127
+ message: nil,
128
+ data: {}
129
+ }
130
+ end
131
+ end
132
+
133
+ if (direction.nil? || direction == 'out') && (layer.nil? || layer == 'lightning')
134
+ Payment::All.data(
135
+ components,
136
+ fetch: {
137
+ get_node_info: false,
138
+ lookup_invoice: false,
139
+ decode_pay_req: true,
140
+ get_chan_info: false
141
+ }
142
+ )[:data].each do |payment|
143
+ activity_how = payment[:invoice][:code].nil? ? 'spontaneously' : 'with-invoice'
144
+
145
+ next if !how.nil? && how != activity_how
146
+
147
+ # TODO: Improve performance by reducing invoice fields?
148
+ activities << {
149
+ direction: 'out',
150
+ layer: 'lightning',
151
+ at: payment[:at],
152
+ amount: payment[:amount],
153
+ how: activity_how,
154
+ message: payment[:message],
155
+ data: { invoice: payment[:invoice] }
156
+ }
157
+ end
158
+ end
159
+
160
+ activities = if order.nil? || order == 'desc'
161
+ activities.sort_by { |activity| -activity[:at].to_i }
162
+ else
163
+ activities.sort_by { |activity| activity[:at].to_i }
164
+ end
165
+
166
+ activities = activities[0..limit - 1] unless limit.nil?
167
+
168
+ { activities: activities }
169
+ end
170
+
171
+ def self.transform(raw)
172
+ raw[:activities].map do |activity|
173
+ activity[:_key] = SecureRandom.hex
174
+ activity
175
+ end
176
+ end
177
+
178
+ def self.data(components, direction: nil, layer: nil, how: nil, order: nil, limit: nil, &vcr)
179
+ raw = if vcr.nil?
180
+ fetch(components, direction: direction, layer: layer, how: how, order: order, limit: limit)
181
+ else
182
+ vcr.call(-> { fetch(components, direction: direction, how: how, order: order, limit: limit) })
183
+ end
184
+
185
+ transform(raw)
186
+ end
187
+
188
+ def self.model(data)
189
+ data.map { |data| Models::Activity.new(data) }
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './concerns/impersonatable'
4
+
5
+ require_relative './activity/all'
6
+
7
+ module Lighstorm
8
+ module Controllers
9
+ module Activity
10
+ extend Impersonatable
11
+
12
+ class DSL < Impersonatable::DSL
13
+ def all(direction: nil, layer: nil, how: nil, order: nil, limit: nil)
14
+ All.model(All.data(
15
+ components,
16
+ direction: direction,
17
+ how: how,
18
+ layer: layer,
19
+ order: order,
20
+ limit: limit
21
+ ))
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'securerandom'
4
4
 
5
- require_relative '../../../ports/grpc'
6
5
  require_relative '../../../models/errors'
7
6
  require_relative '../../../models/edges/channel'
8
7
  require_relative '../../../adapters/edges/channel'
@@ -41,7 +40,7 @@ module Lighstorm
41
40
  ].freeze
42
41
 
43
42
  def self.perform(actual, gossip)
44
- updated = Models::Channel.new(Adapter::Channel.subscribe_channel_graph(gossip))
43
+ updated = Models::Channel.new(Adapter::Channel.subscribe_channel_graph(gossip), nil)
45
44
 
46
45
  actual_dump = actual.dump
47
46
  updated_dump = updated.dump
@@ -99,7 +98,7 @@ module Lighstorm
99
98
  when 'partners/0/policy/htlc/minimum/millisatoshis',
100
99
  'partners/1/policy/htlc/minimum/millisatoshis' then
101
100
  if actual.partners[change[:path][1]].policy.nil?
102
- actual.partners[change[:path][1]].policy = Lighstorm::Models::Policy.new({})
101
+ actual.partners[change[:path][1]].policy = Lighstorm::Models::Policy.new({}, nil)
103
102
  end
104
103
 
105
104
  policy = actual.partners[change[:path][1]].policy
@@ -113,7 +112,7 @@ module Lighstorm
113
112
  when 'partners/0/policy/htlc/blocks/delta/minimum',
114
113
  'partners/1/policy/htlc/blocks/delta/minimum' then
115
114
  if actual.partners[change[:path][1]].policy.nil?
116
- actual.partners[change[:path][1]].policy = Lighstorm::Models::Policy.new({})
115
+ actual.partners[change[:path][1]].policy = Lighstorm::Models::Policy.new({}, nil)
117
116
  end
118
117
 
119
118
  policy = actual.partners[change[:path][1]].policy
@@ -46,22 +46,26 @@ module Lighstorm
46
46
  grpc_request
47
47
  end
48
48
 
49
- def self.call(grpc_request)
50
- Lighstorm::Ports::GRPC.send(grpc_request[:service]).send(
49
+ def self.call(components, grpc_request)
50
+ components[:grpc].send(grpc_request[:service]).send(
51
51
  grpc_request[:method], grpc_request[:params]
52
52
  ).to_h
53
53
  end
54
54
 
55
- def self.dispatch(grpc_request, &vcr)
56
- vcr.nil? ? call(grpc_request) : vcr.call(-> { call(grpc_request) }, :dispatch)
55
+ def self.dispatch(components, grpc_request, &vcr)
56
+ if vcr.nil?
57
+ call(components, grpc_request)
58
+ else
59
+ vcr.call(-> { call(components, grpc_request) }, :dispatch)
60
+ end
57
61
  end
58
62
 
59
- def self.perform(policy, transaction, params, preview: false, &vcr)
63
+ def self.perform(components, policy, transaction, params, preview: false, &vcr)
60
64
  grpc_request = prepare(policy.to_h, transaction.to_h, params)
61
65
 
62
66
  return grpc_request if preview
63
67
 
64
- response = dispatch(grpc_request, &vcr)
68
+ response = dispatch(components, grpc_request, &vcr)
65
69
 
66
70
  raise UpdateChannelPolicyError.new(nil, response) unless response[:failed_updates].empty?
67
71
 
@@ -79,7 +83,7 @@ module Lighstorm
79
83
  token: token
80
84
  }
81
85
 
82
- Action::Output.new({ response: response, result: policy })
86
+ Action::Output.new({ request: grpc_request, response: response, result: policy })
83
87
  end
84
88
  end
85
89
  end