zold 0.14.8 → 0.14.9

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +0 -0
  4. data/Gemfile +2 -0
  5. data/Rakefile +2 -0
  6. data/appveyor.yml +8 -3
  7. data/features/step_definitions/steps.rb +2 -0
  8. data/features/support/env.rb +2 -0
  9. data/fixtures/merge/asserts.rb +2 -0
  10. data/fixtures/merge/into-no-wallet/assert.rb +2 -0
  11. data/fixtures/merge/random-expenses/assert.rb +2 -0
  12. data/fixtures/merge/simple-case/assert.rb +2 -0
  13. data/fixtures/scripts/_head.sh +13 -0
  14. data/fixtures/scripts/distribute-wallet.sh +86 -0
  15. data/fixtures/scripts/spread-wallets.sh +56 -0
  16. data/lib/zold.rb +2 -0
  17. data/lib/zold/amount.rb +3 -1
  18. data/lib/zold/atomic_file.rb +2 -0
  19. data/lib/zold/backtrace.rb +2 -0
  20. data/lib/zold/commands/alias.rb +2 -0
  21. data/lib/zold/commands/args.rb +2 -0
  22. data/lib/zold/commands/calculate.rb +5 -3
  23. data/lib/zold/commands/clean.rb +2 -0
  24. data/lib/zold/commands/create.rb +2 -0
  25. data/lib/zold/commands/diff.rb +2 -0
  26. data/lib/zold/commands/fetch.rb +7 -2
  27. data/lib/zold/commands/invoice.rb +2 -0
  28. data/lib/zold/commands/list.rb +2 -0
  29. data/lib/zold/commands/merge.rb +2 -0
  30. data/lib/zold/commands/node.rb +2 -0
  31. data/lib/zold/commands/pay.rb +2 -0
  32. data/lib/zold/commands/propagate.rb +2 -0
  33. data/lib/zold/commands/pull.rb +2 -0
  34. data/lib/zold/commands/push.rb +2 -0
  35. data/lib/zold/commands/remote.rb +11 -6
  36. data/lib/zold/commands/routines/bonuses.rb +78 -0
  37. data/lib/zold/commands/routines/reconnect.rb +2 -0
  38. data/lib/zold/commands/routines/spread.rb +2 -0
  39. data/lib/zold/commands/show.rb +2 -0
  40. data/lib/zold/commands/taxes.rb +2 -0
  41. data/lib/zold/copies.rb +4 -2
  42. data/lib/zold/hexnum.rb +2 -0
  43. data/lib/zold/http.rb +28 -20
  44. data/lib/zold/hungry_wallets.rb +2 -0
  45. data/lib/zold/id.rb +2 -0
  46. data/lib/zold/json_page.rb +2 -0
  47. data/lib/zold/key.rb +2 -0
  48. data/lib/zold/log.rb +2 -0
  49. data/lib/zold/metronome.rb +2 -0
  50. data/lib/zold/node/async_entrance.rb +3 -3
  51. data/lib/zold/node/emission.rb +2 -0
  52. data/lib/zold/node/entrance.rb +5 -2
  53. data/lib/zold/node/farm.rb +3 -1
  54. data/lib/zold/node/front.rb +4 -1
  55. data/lib/zold/node/safe_entrance.rb +2 -0
  56. data/lib/zold/node/spread_entrance.rb +2 -0
  57. data/lib/zold/patch.rb +2 -0
  58. data/lib/zold/prefixes.rb +2 -0
  59. data/lib/zold/remotes.rb +15 -13
  60. data/lib/zold/score.rb +62 -59
  61. data/lib/zold/signature.rb +2 -0
  62. data/lib/zold/tax.rb +3 -1
  63. data/lib/zold/txn.rb +4 -2
  64. data/lib/zold/type.rb +36 -0
  65. data/lib/zold/upgrades.rb +2 -4
  66. data/lib/zold/verbose_thread.rb +2 -0
  67. data/lib/zold/version.rb +4 -2
  68. data/lib/zold/version_file.rb +2 -0
  69. data/lib/zold/wallet.rb +4 -2
  70. data/lib/zold/wallets.rb +2 -0
  71. data/test/commands/routines/test_bonuses.rb +76 -0
  72. data/test/commands/routines/test_reconnect.rb +2 -0
  73. data/test/commands/routines/test_spread.rb +2 -0
  74. data/test/commands/test_alias.rb +2 -0
  75. data/test/commands/test_calculate.rb +2 -0
  76. data/test/commands/test_clean.rb +2 -0
  77. data/test/commands/test_create.rb +2 -0
  78. data/test/commands/test_diff.rb +2 -0
  79. data/test/commands/test_fetch.rb +2 -0
  80. data/test/commands/test_invoice.rb +2 -0
  81. data/test/commands/test_list.rb +2 -0
  82. data/test/commands/test_merge.rb +2 -0
  83. data/test/commands/test_node.rb +6 -0
  84. data/test/commands/test_pay.rb +2 -0
  85. data/test/commands/test_propagate.rb +2 -0
  86. data/test/commands/test_push.rb +2 -0
  87. data/test/commands/test_remote.rb +40 -0
  88. data/test/commands/test_show.rb +2 -0
  89. data/test/commands/test_taxes.rb +2 -0
  90. data/test/fake_home.rb +2 -0
  91. data/test/node/fake_entrance.rb +2 -0
  92. data/test/node/fake_node.rb +3 -1
  93. data/test/node/test_async_entrance.rb +2 -0
  94. data/test/node/test_emission.rb +2 -0
  95. data/test/node/test_entrance.rb +2 -0
  96. data/test/node/test_farm.rb +9 -7
  97. data/test/node/test_front.rb +15 -10
  98. data/test/node/test_safe_entrance.rb +2 -0
  99. data/test/node/test_spread_entrance.rb +2 -0
  100. data/test/test__helper.rb +2 -0
  101. data/test/test_amount.rb +2 -0
  102. data/test/test_atomic_file.rb +2 -0
  103. data/test/test_backtrace.rb +2 -0
  104. data/test/test_copies.rb +4 -1
  105. data/test/test_hexnum.rb +2 -0
  106. data/test/test_http.rb +5 -3
  107. data/test/test_id.rb +2 -0
  108. data/test/test_key.rb +2 -0
  109. data/test/test_metronome.rb +2 -0
  110. data/test/test_patch.rb +2 -0
  111. data/test/test_prefixes.rb +2 -0
  112. data/test/test_remotes.rb +11 -0
  113. data/test/test_score.rb +26 -24
  114. data/test/test_signature.rb +2 -0
  115. data/test/test_tax.rb +4 -2
  116. data/test/test_txn.rb +2 -0
  117. data/test/test_upgrades.rb +2 -0
  118. data/test/test_verbose_thread.rb +2 -0
  119. data/test/test_version.rb +2 -0
  120. data/test/test_wallet.rb +2 -0
  121. data/test/test_wallets.rb +2 -0
  122. data/test/test_zold.rb +2 -0
  123. data/test/upgrades/test_protocol_up.rb +2 -0
  124. data/upgrades/2.rb +2 -0
  125. data/upgrades/protocol_up.rb +2 -0
  126. data/upgrades/rename_foreign_wallets.rb +2 -0
  127. data/zold.gemspec +5 -1
  128. metadata +38 -4
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -138,7 +140,7 @@ Available options:"
138
140
 
139
141
  def show
140
142
  @remotes.all.each do |r|
141
- score = Rainbow("/#{r[:score]}").color(r[:score] > 0 ? :green : :red)
143
+ score = Rainbow("/#{r[:score]}").color(r[:score].positive? ? :green : :red)
142
144
  @log.info(r[:host] + Rainbow(":#{r[:port]}").gray + score)
143
145
  end
144
146
  end
@@ -155,7 +157,7 @@ Available options:"
155
157
 
156
158
  def add(host, port, opts)
157
159
  unless opts['skip-ping']
158
- res = Http.new("http://#{host}:#{port}/version", network: opts['network']).get
160
+ res = Http.new(uri: "http://#{host}:#{port}/version", score: nil, network: opts['network']).get
159
161
  raise "The node #{host}:#{port} is not responding (code is #{res.code})" unless res.code == '200'
160
162
  end
161
163
  if @remotes.exists?(host, port)
@@ -251,10 +253,13 @@ in #{(Time.now - start).round(2)}s")
251
253
  end
252
254
  end
253
255
 
254
- # @todo #292:30min Implement the logic of selecting the nodes as per #292.
255
- # The strongest n nodes should be selected, where n = opts['max-nodes'].
256
- def select(_opts)
257
- raise NotImplementedError, 'This feature is not yet implemented.'
256
+ def select(opts)
257
+ max_nodes = opts['max-nodes']
258
+ @log.info("Selecting #{max_nodes} strongest nodes.")
259
+ selected_remotes = @remotes.all.sort_by { |remote| remote[:score] }.first(max_nodes)
260
+ (@remotes.all - selected_remotes).each do |weak_remote|
261
+ @remotes.remove(weak_remote[:host], weak_remote[:port])
262
+ end
258
263
  end
259
264
 
260
265
  def terminate
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require_relative '../remote'
24
+ require_relative '../pull'
25
+ require_relative '../pay'
26
+ require_relative '../push'
27
+
28
+ # Pay bonuses routine.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
31
+ # License:: MIT
32
+ module Zold
33
+ # Routines module
34
+ module Routines
35
+ # Pay bonuses to random nodes
36
+ class Bonuses
37
+ def initialize(opts, wallets, remotes, copies, farm, log: Log::Quiet.new)
38
+ @opts = opts
39
+ @wallets = wallets
40
+ @remotes = remotes
41
+ @copies = copies
42
+ @farm = farm
43
+ @log = log
44
+ end
45
+
46
+ def exec(_ = 0)
47
+ sleep(@opts['bonus-time'] * 60) unless @opts['routine-immediately']
48
+ raise '--private-key is required to pay bonuses' unless @opts['private-key']
49
+ raise '--bonus-wallet is required to pay bonuses' unless @opts['bonus-wallet']
50
+ raise '--bonus-amount is required to pay bonuses' unless @opts['bonus-amount']
51
+ winners = Remote.new(remotes: @remotes, log: @log, farm: @farm).run(
52
+ ['remote', 'elect', @opts['bonus-wallet'], '--private-key', @opts['private-key']] +
53
+ (@opts['ignore-score-weakness'] ? ['--ignore-score-weakness'] : [])
54
+ )
55
+ return if winners.empty?
56
+ unless @wallets.find(Id.new(@opts['bonus-wallet'])).exists?
57
+ Pull.new(wallets: @wallets, remotes: @remotes, copies: @copies, log: @log).run(
58
+ ['pull', @opts['bonus-wallet']] +
59
+ (@opts['ignore-score-weakness'] ? ['--ignore-score-weakness'] : [])
60
+ )
61
+ end
62
+ winners.each do |score|
63
+ Pay.new(wallets: @wallets, remotes: @remotes, log: @log).run(
64
+ [
65
+ 'pay', @opts['bonus-wallet'], score.invoice, @opts['bonus-amount'].to_s,
66
+ "Hosting bonus for #{score.host} #{score.port} #{score.value}",
67
+ '--private-key', @opts['private-key']
68
+ ]
69
+ )
70
+ end
71
+ Push.new(wallets: @wallets, remotes: @remotes, log: @log).run(
72
+ ['push', @opts['bonus-wallet']] +
73
+ (@opts['ignore-score-weakness'] ? ['--ignore-score-weakness'] : [])
74
+ )
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -88,11 +90,11 @@ module Zold
88
90
  def add(content, host, port, score, time = Time.now)
89
91
  raise "Content can't be empty" if content.empty?
90
92
  raise 'TCP port must be of type Integer' unless port.is_a?(Integer)
91
- raise "TCP port can't be negative: #{port}" if port < 0
93
+ raise "TCP port can't be negative: #{port}" if port.negative?
92
94
  raise 'Time must be of type Time' unless time.is_a?(Time)
93
95
  raise "Time must be in the past: #{time}" if time > Time.now
94
96
  raise 'Score must be Integer' unless score.is_a?(Integer)
95
- raise "Score can't be negative: #{score}" if score < 0
97
+ raise "Score can't be negative: #{score}" if score.negative?
96
98
  @mutex.synchronize do
97
99
  FileUtils.mkdir_p(@dir)
98
100
  list = load
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,6 +26,7 @@ require 'net/http'
24
26
  require_relative 'backtrace'
25
27
  require_relative 'version'
26
28
  require_relative 'score'
29
+ require_relative 'type'
27
30
 
28
31
  # HTTP page.
29
32
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -31,48 +34,53 @@ require_relative 'score'
31
34
  # License:: MIT
32
35
  module Zold
33
36
  # Http page
34
- class Http
37
+ class Http < Dry::Struct
35
38
  # HTTP header we add to each HTTP request, in order to inform
36
39
  # the other node about the score. If the score is big enough,
37
40
  # the remote node will add us to its list of remote nodes.
38
- SCORE_HEADER = 'X-Zold-Score'.freeze
41
+ SCORE_HEADER = 'X-Zold-Score'
39
42
 
40
43
  # HTTP header we add, in order to inform the node about our
41
44
  # version. This is done mostly in order to let the other node
42
45
  # reboot itself, if the version is higher.
43
- VERSION_HEADER = 'X-Zold-Version'.freeze
46
+ VERSION_HEADER = 'X-Zold-Version'
44
47
 
45
48
  # HTTP header we add, in order to inform the node about our
46
49
  # network. This is done in order to isolate test networks from
47
50
  # production one.
48
- NETWORK_HEADER = 'X-Zold-Network'.freeze
51
+ NETWORK_HEADER = 'X-Zold-Network'
49
52
 
50
- def initialize(uri, score = Score::ZERO, network: 'test')
51
- raise 'URI can\'t be nil' if uri.nil?
52
- @uri = uri.is_a?(String) ? URI(uri) : uri
53
- raise 'Score can\'t be nil' if score.nil?
54
- @score = score
55
- raise 'Network can\'t be nil' if network.nil?
56
- @network = network
57
- end
53
+ # @todo #98:30m/DEV The following two statements are seen as issues by rubocop
54
+ # raising a Lint/AmbiguousBlockAssociation offense. It is somthing
55
+ # that could be solved by changing the TargetRubyVersion in .rubocop.yml
56
+ # that is already taken care of in another issue. I am leaving a todo
57
+ # to check that rubocop doesn't complain anymore, otherwise find another
58
+ # solution
59
+ attribute :uri, (Types::Class.constructor do |value|
60
+ value.is_a?(URI) ? value : URI(value)
61
+ end)
62
+ attribute :score, (Types::Class.constructor do |value|
63
+ value.nil? ? Score::ZERO : value
64
+ end)
65
+ attribute :network, Types::Strict::String.optional.default('test')
58
66
 
59
67
  def get
60
- http = Net::HTTP.new(@uri.host, @uri.port)
68
+ http = Net::HTTP.new(uri.host, uri.port)
61
69
  http.read_timeout = 8
62
70
  http.open_timeout = 4
63
- path = @uri.path
64
- path += '?' + @uri.query if @uri.query
71
+ path = uri.path
72
+ path += '?' + uri.query if uri.query
65
73
  http.request_get(path, headers)
66
74
  rescue StandardError => e
67
75
  Error.new(e)
68
76
  end
69
77
 
70
78
  def put(body)
71
- http = Net::HTTP.new(@uri.host, @uri.port)
79
+ http = Net::HTTP.new(uri.host, uri.port)
72
80
  http.read_timeout = 16
73
81
  http.open_timeout = 4
74
- path = @uri.path
75
- path += '?' + @uri.query if @uri.query
82
+ path = uri.path
83
+ path += '?' + uri.query if uri.query
76
84
  http.request_put(
77
85
  path, body,
78
86
  headers.merge(
@@ -112,8 +120,8 @@ module Zold
112
120
  'Accept-Encoding': 'gzip'
113
121
  }
114
122
  headers[Http::VERSION_HEADER] = VERSION
115
- headers[Http::NETWORK_HEADER] = @network
116
- headers[Http::SCORE_HEADER] = @score.reduced(4).to_text if @score.valid? && !@score.expired? && @score.value > 3
123
+ headers[Http::NETWORK_HEADER] = network
124
+ headers[Http::SCORE_HEADER] = score.reduced(4).to_text if score.valid? && !score.expired? && score.value > 3
117
125
  headers
118
126
  end
119
127
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delegate'
2
4
 
3
5
  module Zold
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -77,10 +79,8 @@ module Zold
77
79
 
78
80
  def to_json
79
81
  @entrance.to_json.merge(
80
- 'pool.completed_task_count': @pool.completed_task_count,
81
- 'pool.largest_length': @pool.largest_length,
82
+ 'queue': queue.count,
82
83
  'pool.length': @pool.length,
83
- 'pool.queue_length': @pool.queue_length,
84
84
  'pool.running': @pool.running?
85
85
  )
86
86
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -60,7 +62,8 @@ module Zold
60
62
 
61
63
  def to_json
62
64
  {
63
- history: @history.join(', ')
65
+ 'history': @history.join(', '),
66
+ 'history_size': @history.count
64
67
  }
65
68
  end
66
69
 
@@ -76,7 +79,7 @@ module Zold
76
79
  unless @remotes.all.empty?
77
80
  Fetch.new(
78
81
  wallets: @wallets, remotes: @remotes, copies: copies.root, log: @log
79
- ).run(['fetch', id.to_s, "--ignore-node=#{@address}", "--network=#{@network}"])
82
+ ).run(['fetch', id.to_s, "--ignore-node=#{@address}", "--network=#{@network}", '--quiet-if-absent'])
80
83
  end
81
84
  modified = Merge.new(
82
85
  wallets: @wallets, copies: copies.root, log: @log
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -121,7 +123,7 @@ module Zold
121
123
  def cleanup(host, port, strength, threads)
122
124
  scores = load
123
125
  before = scores.map(&:value).max.to_i
124
- save(threads, [Score.new(Time.now, host, port, @invoice, strength: strength)])
126
+ save(threads, [Score.new(time: Time.now, host: host, port: port, invoice: @invoice, strength: strength)])
125
127
  scores = load
126
128
  push(scores)
127
129
  after = scores.map(&:value).max.to_i
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -131,6 +133,7 @@ module Zold
131
133
  JSON.pretty_generate(
132
134
  version: settings.version,
133
135
  network: settings.network,
136
+ protocol: settings.protocol,
134
137
  score: score.to_h,
135
138
  pid: Process.pid,
136
139
  cpus: Concurrent.processor_count,
@@ -203,7 +206,7 @@ module Zold
203
206
  wallet.network,
204
207
  wallet.protocol,
205
208
  wallet.id.to_s,
206
- wallet.key.to_s,
209
+ wallet.key.to_pub,
207
210
  '',
208
211
  wallet.txns.map(&:to_text).join("\n"),
209
212
  '',
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright (c) 2018 Yegor Bugayenko
2
4
  #
3
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -77,7 +79,7 @@ module Zold
77
79
  end
78
80
 
79
81
  def http(path = '/')
80
- Http.new("http://#{@host}:#{@port}#{path}", @score, network: @network)
82
+ Http.new(uri: "http://#{@host}:#{@port}#{path}", score: @score, network: @network)
81
83
  end
82
84
 
83
85
  def to_s
@@ -155,12 +157,11 @@ module Zold
155
157
  raise 'Port can\'t be nil' if port.nil?
156
158
  raise 'Port has to be of type Integer' unless port.is_a?(Integer)
157
159
  raise 'Port can\'t be zero' if port.zero?
158
- raise 'Port can\'t be negative' if port < 0
160
+ raise 'Port can\'t be negative' if port.negative?
159
161
  raise 'Port can\'t be over 65536' if port > 0xffff
160
162
  raise "#{host}:#{port} already exists" if exists?(host, port)
161
163
  list = load
162
164
  list << { host: host.downcase, port: port, score: 0 }
163
- list.uniq! { |r| "#{r[:host]}:#{r[:port]}" }
164
165
  save(list)
165
166
  end
166
167
 
@@ -168,7 +169,6 @@ module Zold
168
169
  raise 'Port has to be of type Integer' unless port.is_a?(Integer)
169
170
  raise 'Host can\'t be nil' if host.nil?
170
171
  raise 'Port can\'t be nil' if port.nil?
171
- raise "#{host}:#{port} is absent" unless exists?(host, port)
172
172
  list = load
173
173
  list.reject! { |r| r[:host] == host.downcase && r[:port] == port }
174
174
  save(list)
@@ -211,10 +211,7 @@ in #{(Time.now - start).round}s; errors=#{errors}")
211
211
  raise 'Host can\'t be nil' if host.nil?
212
212
  raise 'Port can\'t be nil' if port.nil?
213
213
  raise 'Port has to be of type Integer' unless port.is_a?(Integer)
214
- list = load
215
- raise "#{host}:#{port} is absent among #{list.count} remotes" unless exists?(host, port)
216
- list.find { |r| r[:host] == host.downcase && r[:port] == port }[:errors] += 1
217
- save(list)
214
+ if_present(host, port) { |r| r[:errors] += 1 }
218
215
  end
219
216
 
220
217
  def rescore(host, port, score)
@@ -222,14 +219,19 @@ in #{(Time.now - start).round}s; errors=#{errors}")
222
219
  raise 'Port can\'t be nil' if port.nil?
223
220
  raise 'Score can\'t be nil' if score.nil?
224
221
  raise 'Port has to be of type Integer' unless port.is_a?(Integer)
225
- raise "#{host}:#{port} is absent" unless exists?(host, port)
226
- list = load
227
- list.find { |r| r[:host] == host.downcase && r[:port] == port }[:score] = score
228
- save(list)
222
+ if_present(host, port) { |r| r[:score] = score }
229
223
  end
230
224
 
231
225
  private
232
226
 
227
+ def if_present(host, port)
228
+ list = load
229
+ remote = list.find { |r| r[:host] == host.downcase && r[:port] == port }
230
+ return unless remote
231
+ yield remote
232
+ save(list)
233
+ end
234
+
233
235
  def load
234
236
  @mutex.synchronize do
235
237
  raw = CSV.read(file).map do |r|
@@ -250,7 +252,7 @@ in #{(Time.now - start).round}s; errors=#{errors}")
250
252
  def save(list)
251
253
  @mutex.synchronize do
252
254
  AtomicFile.new(file).write(
253
- list.map do |r|
255
+ list.uniq { |r| "#{r[:host]}:#{r[:port]}" }.map do |r|
254
256
  [
255
257
  r[:host],
256
258
  r[:port],