lighstorm 0.0.12 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
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