zold 0.14.13 → 0.14.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/fixtures/scripts/distribute-wallet.sh +3 -2
  3. data/lib/zold/amount.rb +0 -0
  4. data/lib/zold/commands/calculate.rb +0 -0
  5. data/lib/zold/commands/node.rb +18 -12
  6. data/lib/zold/commands/pay.rb +1 -1
  7. data/lib/zold/commands/remote.rb +7 -6
  8. data/lib/zold/commands/routines/reconnect.rb +8 -8
  9. data/lib/zold/commands/routines/spread.rb +13 -11
  10. data/lib/zold/copies.rb +0 -0
  11. data/lib/zold/http.rb +10 -4
  12. data/lib/zold/metronome.rb +1 -0
  13. data/lib/zold/node/async_entrance.rb +2 -0
  14. data/lib/zold/node/entrance.rb +2 -2
  15. data/lib/zold/node/farm.rb +3 -0
  16. data/lib/zold/node/front.rb +26 -8
  17. data/lib/zold/node/nodup_entrance.rb +73 -0
  18. data/lib/zold/remotes.rb +3 -2
  19. data/lib/zold/score.rb +0 -0
  20. data/lib/zold/tax.rb +1 -1
  21. data/lib/zold/txn.rb +0 -0
  22. data/lib/zold/type.rb +0 -0
  23. data/lib/zold/upgrades.rb +0 -0
  24. data/lib/zold/version.rb +1 -1
  25. data/lib/zold/version_file.rb +0 -0
  26. data/lib/zold/wallet.rb +3 -1
  27. data/test/commands/routines/test_spread.rb +1 -4
  28. data/test/commands/test_node.rb +0 -0
  29. data/test/node/fake_node.rb +0 -0
  30. data/test/node/test_farm.rb +0 -0
  31. data/test/node/test_front.rb +0 -0
  32. data/test/node/test_nodup_entrance.rb +49 -0
  33. data/test/test_http.rb +0 -0
  34. data/test/test_score.rb +0 -0
  35. data/test/test_tax.rb +0 -0
  36. data/test/test_upgrades.rb +0 -0
  37. data/test/test_version.rb +0 -0
  38. data/test/test_wallet.rb +12 -0
  39. data/test/upgrades/test_protocol_up.rb +0 -0
  40. data/upgrades/2.rb +0 -0
  41. data/upgrades/protocol_up.rb +0 -0
  42. data/upgrades/rename_foreign_wallets.rb +0 -0
  43. metadata +5 -5
  44. data/lib/zold/commands/routines/bonuses.rb +0 -78
  45. data/test/commands/routines/test_bonuses.rb +0 -76
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 15c46c2740b4034dae78391ab88d747116977858
4
- data.tar.gz: 89bcbf8445379dddbff308e0dfb0a60fb11157e6
3
+ metadata.gz: 71369b8c56264180688b1f2e6fa6f9ce74bdbfd7
4
+ data.tar.gz: ae47e1e2501eab7fbb340b061f87c075884da2f0
5
5
  SHA512:
6
- metadata.gz: 1236cdbd4219b2b61dd11ffe556f26e867a2a91985d14c1d670ed2388393451e38fef70baefbaa0dd699c56b754798350a9e9afbdd116fdb7f5e21b0074ee586
7
- data.tar.gz: ae55db8d0224a10c1facebf9a3e52dc2f7be2baf9285138af232b808bba340171f74335237abf0a13909e24bf772671016de48873ec04858d552c8fc44905975
6
+ metadata.gz: 0445e6669bb843b41ffee95c9ea388ec452551fc7c833d3ddc3cfd7fbdd0bbba646974289500ed47ab7ed93e4928ac1e4e1d146fbfcd0bbff5f4e5218153b560
7
+ data.tar.gz: 4a1ecaea86ffa87784b43c92ec23415032bfd41e929f86759512beea2c778a333a4e05b4c64dbd892fe7c530c4d012e99505ddf67abdde88d1a70639c6d284a5
@@ -33,7 +33,8 @@ zold --home=${second} remote add localhost ${first}
33
33
  # the wallet to the remote, expecting it to distribute it to the second
34
34
  # wallet automatically.
35
35
  zold --public-key=id_rsa.pub create 0000000000000000
36
- zold pay --private-key=id_rsa 0000000000000000 NOPREFIX@aaaabbbbccccdddd 4.95 'To help you, dude!'
36
+ zold pay --private-key=id_rsa 0000000000000000 NOPREFIX@aaaabbbbccccdddd 4.95 'For the book'
37
+ zold remote clean
37
38
  zold remote add localhost ${first}
38
39
  zold push 0000000000000000
39
40
  zold remote clean
@@ -78,7 +79,7 @@ until zold fetch 0000000000000000 --ignore-score-weakness; do
78
79
  ((i++)) || sleep 1
79
80
  if ((i==5)); then
80
81
  cat ${first}/log.txt
81
- echo "The wallet has not been spread, after ${i} attempts"
82
+ echo "The wallet 0000000000000000 has not been spread, after ${i} attempts"
82
83
  exit 8
83
84
  fi
84
85
  sleep 1
data/lib/zold/amount.rb CHANGED
File without changes
File without changes
@@ -34,6 +34,7 @@ require_relative '../node/entrance'
34
34
  require_relative '../node/safe_entrance'
35
35
  require_relative '../node/spread_entrance'
36
36
  require_relative '../node/async_entrance'
37
+ require_relative '../node/nodup_entrance'
37
38
  require_relative '../node/front'
38
39
  require_relative '../node/farm'
39
40
  require_relative 'pull'
@@ -165,20 +166,25 @@ module Zold
165
166
  invoice = Invoice.new(wallets: @wallets, log: @log).run(['invoice', invoice])
166
167
  end
167
168
  SafeEntrance.new(
168
- AsyncEntrance.new(
169
- SpreadEntrance.new(
170
- Entrance.new(@wallets, @remotes, @copies, address, log: @log, network: opts['network']),
171
- @wallets, @remotes, address,
172
- log: @log,
173
- ignore_score_weakeness: opts['ignore-score-weakness']
174
- ), File.join(Dir.pwd, '.zoldata/entrance'), log: @log
175
- ), network: opts['network']
169
+ NoDupEntrance.new(
170
+ AsyncEntrance.new(
171
+ SpreadEntrance.new(
172
+ Entrance.new(@wallets, @remotes, @copies, address, log: @log, network: opts['network']),
173
+ @wallets, @remotes, address,
174
+ log: @log,
175
+ ignore_score_weakeness: opts['ignore-score-weakness']
176
+ ),
177
+ File.join(Dir.pwd, '.zoldata/entrance'), log: @log
178
+ ),
179
+ @wallets
180
+ ),
181
+ network: opts['network']
176
182
  ).start do |entrance|
177
183
  Front.set(:entrance, entrance)
178
184
  Farm.new(invoice, File.join(Dir.pwd, 'farm'), log: @log)
179
185
  .start(host, opts[:port], threads: opts[:threads], strength: opts[:strength]) do |farm|
180
186
  Front.set(:farm, farm)
181
- metronome(farm, entrance, opts).start do |metronome|
187
+ metronome(farm, opts).start do |metronome|
182
188
  Front.set(:metronome, metronome)
183
189
  @log.info("Starting up the web front at http://#{host}:#{opts[:port]}...")
184
190
  Front.run!
@@ -244,13 +250,13 @@ module Zold
244
250
  pid
245
251
  end
246
252
 
247
- def metronome(farm, entrance, opts)
253
+ def metronome(farm, opts)
248
254
  metronome = Metronome.new(@log)
249
255
  require_relative 'routines/spread'
250
- metronome.add(Routines::Spread.new(opts, @wallets, entrance, log: @log))
256
+ metronome.add(Routines::Spread.new(opts, @wallets, @remotes, log: @log))
251
257
  unless opts['standalone']
252
258
  require_relative 'routines/reconnect'
253
- metronome.add(Routines::Reconnect.new(opts, @remotes, farm, log: Log::Quiet.new))
259
+ metronome.add(Routines::Reconnect.new(opts, @remotes, farm, network: opts['network'], log: Log::Quiet.new))
254
260
  end
255
261
  @log.info('Metronome created')
256
262
  metronome
@@ -81,7 +81,7 @@ Available options:"
81
81
  if Tax.new(from).in_debt? && !opts['dont-pay-taxes']
82
82
  require_relative 'taxes'
83
83
  Taxes.new(wallets: @wallets, remotes: @remotes, log: @log).run(
84
- ['taxes', "--private-key=#{opts['private-key']}", id.to_s]
84
+ ['taxes', 'pay', "--private-key=#{opts['private-key']}", id.to_s]
85
85
  )
86
86
  end
87
87
  pay(from, invoice, amount, details, opts)
@@ -80,6 +80,9 @@ Available options:"
80
80
  o.bool '--ignore-score-value',
81
81
  'Don\'t complain when their score is too small',
82
82
  default: false
83
+ o.bool '--min-score',
84
+ "The minimum score required for winning the election (default: #{Tax::EXACT_SCORE})",
85
+ default: Tax::EXACT_SCORE
83
86
  o.bool '--force',
84
87
  'Add/remove if if this operation is not possible',
85
88
  default: false
@@ -192,7 +195,7 @@ Available options:"
192
195
  r.assert_valid_score(score)
193
196
  r.assert_score_ownership(score)
194
197
  r.assert_score_strength(score) unless opts['ignore-score-weakness']
195
- r.assert_score_value(score, Tax::EXACT_SCORE) unless opts['ignore-score-value']
198
+ r.assert_score_value(score, opts['min-score']) unless opts['ignore-score-value']
196
199
  scores << score
197
200
  end
198
201
  scores = scores.sample(1)
@@ -254,11 +257,9 @@ in #{(Time.now - start).round(2)}s")
254
257
  end
255
258
 
256
259
  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])
260
+ selected = @remotes.all.sort_by { |r| r[:score] }.first(opts['max-nodes'])
261
+ (@remotes.all - selected).each do |r|
262
+ @remotes.remove(r[:host], r[:port])
262
263
  end
263
264
  end
264
265
 
@@ -32,22 +32,22 @@ module Zold
32
32
  module Routines
33
33
  # Reconnect to the network
34
34
  class Reconnect
35
- def initialize(opts, remotes, farm = Farm::Empty.new, log: Log::Quiet.new)
35
+ def initialize(opts, remotes, farm = Farm::Empty.new, network: 'test', log: Log::Quiet.new)
36
36
  @opts = opts
37
37
  @remotes = remotes
38
38
  @farm = farm
39
+ @network = network
39
40
  @log = log
40
41
  end
41
42
 
42
43
  def exec(_ = 0)
43
44
  sleep(60) unless @opts['routine-immediately']
44
- unless @opts['routine-immediately']
45
- Remote.new(remotes: @remotes, log: @log).run(%w[remote add b1.zold.io 80 --force])
46
- end
47
- Remote.new(remotes: @remotes, log: @log).run(%w[remote trim])
48
- Remote.new(remotes: @remotes, farm: @farm, log: @log).run(
49
- %w[remote update] + (@opts['never-reboot'] ? [] : ['--reboot'])
50
- )
45
+ cmd = Remote.new(remotes: @remotes, log: @log, farm: @farm)
46
+ args = ['remote', "--network=#{@opts['network']}"]
47
+ cmd.run(args + ['add', 'b1.zold.io', '80', '--force']) unless @opts['routine-immediately']
48
+ cmd.run(args + ['trim'])
49
+ cmd.run(args + ['select'])
50
+ cmd.run(args + ['update'] + (@opts['never-reboot'] ? [] : ['--reboot']))
51
51
  end
52
52
  end
53
53
  end
@@ -20,9 +20,8 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- require_relative '../remote'
24
- require_relative '../pull'
25
- require_relative '../pay'
23
+ require_relative '../../log'
24
+ require_relative '../../id'
26
25
  require_relative '../push'
27
26
 
28
27
  # Spread random wallets to the network.
@@ -34,22 +33,25 @@ module Zold
34
33
  module Routines
35
34
  # Spread them
36
35
  class Spread
37
- def initialize(opts, wallets, entrance, log: Log::Quiet.new)
36
+ def initialize(opts, wallets, remotes, log: Log::Quiet.new)
38
37
  @opts = opts
39
38
  @wallets = wallets
40
- @entrance = entrance
39
+ @remotes = remotes
41
40
  @log = log
42
41
  end
43
42
 
44
43
  def exec(_ = 0)
44
+ return if @remotes.all.empty?
45
45
  sleep(60) unless @opts['routine-immediately']
46
- pushed = []
47
- @wallets.all.sample(10).map do |w|
48
- id = Id.new(w)
49
- @entrance.push(id, File.read(@wallets.find(id).path))
50
- pushed << id
46
+ ids = @wallets.all.sample(10)
47
+ Push.new(wallets: @wallets, remotes: @remotes, log: @log).run(
48
+ ['push', "--network=#{@opts['network']}"] + ids
49
+ )
50
+ if ids.empty?
51
+ @log.info("Spread didn't push any wallets, we are empty")
52
+ else
53
+ @log.info("Spread #{ids.count} random wallets out of #{@wallets.all.count}: #{ids.join(', ')}")
51
54
  end
52
- @log.info("Spread #{pushed.count} random wallets out of #{@wallets.all.count}: #{pushed.join(', ')}")
53
55
  end
54
56
  end
55
57
  end
data/lib/zold/copies.rb CHANGED
File without changes
data/lib/zold/http.rb CHANGED
@@ -54,6 +54,12 @@ module Zold
54
54
  # protocol.
55
55
  PROTOCOL_HEADER = 'X-Zold-Protocol'
56
56
 
57
+ # Read timeout in seconds
58
+ READ_TIMEOUT = 32
59
+
60
+ # Connect timeout in seconds
61
+ CONNECT_TIMEOUT = 8
62
+
57
63
  # @todo #98:30m/DEV The following two statements are seen as issues by rubocop
58
64
  # raising a Lint/AmbiguousBlockAssociation offense. It is somthing
59
65
  # that could be solved by changing the TargetRubyVersion in .rubocop.yml
@@ -70,8 +76,8 @@ module Zold
70
76
 
71
77
  def get
72
78
  http = Net::HTTP.new(uri.host, uri.port)
73
- http.read_timeout = 8
74
- http.open_timeout = 4
79
+ http.read_timeout = Http::READ_TIMEOUT
80
+ http.open_timeout = Http::CONNECT_TIMEOUT
75
81
  path = uri.path
76
82
  path += '?' + uri.query if uri.query
77
83
  http.request_get(path, headers)
@@ -81,8 +87,8 @@ module Zold
81
87
 
82
88
  def put(body)
83
89
  http = Net::HTTP.new(uri.host, uri.port)
84
- http.read_timeout = 16
85
- http.open_timeout = 4
90
+ http.read_timeout = Http::READ_TIMEOUT
91
+ http.open_timeout = Http::CONNECT_TIMEOUT
86
92
  path = uri.path
87
93
  path += '?' + uri.query if uri.query
88
94
  http.request_put(
@@ -53,6 +53,7 @@ module Zold
53
53
  alive = true
54
54
  @routines.each do |r|
55
55
  @threads << Thread.start do
56
+ Thread.current.abort_on_exception = true
56
57
  Thread.current.name = r.class.name
57
58
  Thread.current.priority = -100
58
59
  step = 0
@@ -88,10 +88,12 @@ module Zold
88
88
  end
89
89
  end
90
90
 
91
+ # Always returns an array with a single ID of the pushed wallet
91
92
  def push(id, body)
92
93
  @mutex.synchronize do
93
94
  AtomicFile.new(File.join(@dir, id.to_s)).write(body)
94
95
  end
96
+ [id]
95
97
  end
96
98
 
97
99
  private
@@ -95,8 +95,8 @@ module Zold
95
95
  @log.info("Accepted #{id} in #{sec}s and modified #{modified.join(', ')}")
96
96
  end
97
97
  @mutex.synchronize do
98
- @history.shift if @history.length > 16
99
- @speed.shift if @speed.length > 64
98
+ @history.shift if @history.length >= 16
99
+ @speed.shift if @speed.length >= 64
100
100
  wallet = @wallets.find(id)
101
101
  @history << "#{id}/#{sec}/#{modified.count}/#{wallet.balance.to_zld}/#{wallet.txns.count}t"
102
102
  @speed << sec
@@ -76,6 +76,7 @@ module Zold
76
76
  @log.info("#{@pipeline.size} scores pre-loaded, the best is: #{best[0]}")
77
77
  @threads = (1..threads).map do |t|
78
78
  Thread.new do
79
+ Thread.current.abort_on_exception = true
79
80
  Thread.current.name = "f#{t}"
80
81
  Thread.current.priority = -100
81
82
  loop do
@@ -87,7 +88,9 @@ module Zold
87
88
  end
88
89
  alive = true
89
90
  @cleanup = Thread.new do
91
+ Thread.current.abort_on_exception = true
90
92
  Thread.current.name = 'cleanup'
93
+ Thread.current.priority = -100
91
94
  while alive
92
95
  sleep(60) unless strength == 1 # which will only happen in tests
93
96
  VerboseThread.new(@log).run do
@@ -71,7 +71,8 @@ module Zold
71
71
  before do
72
72
  check_header(Http::NETWORK_HEADER) do |header|
73
73
  if header != settings.network
74
- raise "Network name mismatch, you are in '#{header}', we are in '#{settings.network}'"
74
+ raise "Network name mismatch at #{request.url}, #{request.ip} is in '#{header}', \
75
+ while #{settings.address} is in '#{settings.network}'"
75
76
  end
76
77
  end
77
78
  check_header(Http::PROTOCOL_HEADER) do |header|
@@ -162,6 +163,8 @@ module Zold
162
163
  content_type 'application/json'
163
164
  {
164
165
  version: settings.version,
166
+ protocol: settings.protocol,
167
+ id: wallet.id.to_s,
165
168
  score: score.to_h,
166
169
  wallets: settings.wallets.all.count,
167
170
  mtime: wallet.mtime.utc.iso8601,
@@ -171,6 +174,25 @@ module Zold
171
174
  }.to_json
172
175
  end
173
176
 
177
+ get %r{/wallet/(?<id>[A-Fa-f0-9]{16}).json} do
178
+ id = Id.new(params[:id])
179
+ wallet = settings.wallets.find(id)
180
+ error 404 unless wallet.exists?
181
+ content_type 'application/json'
182
+ {
183
+ version: settings.version,
184
+ protocol: settings.protocol,
185
+ id: wallet.id.to_s,
186
+ score: score.to_h,
187
+ wallets: settings.wallets.all.count,
188
+ key: wallet.key.to_pub,
189
+ mtime: wallet.mtime.utc.iso8601,
190
+ digest: wallet.digest,
191
+ balance: wallet.balance.to_i,
192
+ txns: wallet.txns.count
193
+ }.to_json
194
+ end
195
+
174
196
  get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/balance} do
175
197
  id = Id.new(params[:id])
176
198
  wallet = settings.wallets.find(id)
@@ -184,7 +206,7 @@ module Zold
184
206
  wallet = settings.wallets.find(id)
185
207
  error 404 unless wallet.exists?
186
208
  content_type 'text/plain'
187
- wallet.key.to_s
209
+ wallet.key.to_pub
188
210
  end
189
211
 
190
212
  get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/mtime} do
@@ -225,16 +247,12 @@ module Zold
225
247
  end
226
248
 
227
249
  put %r{/wallet/(?<id>[A-Fa-f0-9]{16})/?} do
228
- id = Id.new(params[:id])
229
- wallet = settings.wallets.find(id)
230
250
  request.body.rewind
231
- after = request.body.read.to_s
232
- before = wallet.exists? ? AtomicFile.new(wallet.path).read.to_s : ''
233
- if before == after
251
+ modified = settings.entrance.push(Id.new(params[:id]), request.body.read.to_s)
252
+ if modified.empty?
234
253
  status 304
235
254
  return
236
255
  end
237
- settings.entrance.push(id, after)
238
256
  JSON.pretty_generate(
239
257
  version: settings.version,
240
258
  score: score.to_h,
@@ -0,0 +1,73 @@
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 'tempfile'
24
+ require_relative '../log'
25
+ require_relative '../wallet'
26
+ require_relative '../atomic_file'
27
+
28
+ # The entrance that ignores duplicates.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
31
+ # License:: MIT
32
+ module Zold
33
+ # The safe entrance
34
+ class NoDupEntrance
35
+ def initialize(entrance, wallets, log: Log::Quiet.new)
36
+ raise 'Entrance can\'t be nil' if entrance.nil?
37
+ @entrance = entrance
38
+ raise 'Wallets can\'t be nil' if wallets.nil?
39
+ @wallets = wallets
40
+ raise 'Log can\'t be nil' if log.nil?
41
+ @log = log
42
+ end
43
+
44
+ def start
45
+ @entrance.start { yield(self) }
46
+ end
47
+
48
+ def to_json
49
+ @entrance.to_json
50
+ end
51
+
52
+ # Returns a list of modifed wallets (as Zold::Id)
53
+ def push(id, body)
54
+ raise 'Id can\'t be nil' if id.nil?
55
+ raise 'Id must be of type Id' unless id.is_a?(Id)
56
+ raise 'Body can\'t be nil' if body.nil?
57
+ Tempfile.open(['', Wallet::EXTENSION]) do |f|
58
+ File.write(f, body)
59
+ wallet = Wallet.new(f.path)
60
+ wallet.refurbish
61
+ after = File.read(wallet.path)
62
+ wallet = @wallets.find(id)
63
+ before = wallet.exists? ? AtomicFile.new(wallet.path).read.to_s : ''
64
+ if before == after
65
+ @log.info("Duplicate of #{id}/#{wallet.digest[0, 6]}/#{after.length}b/#{wallet.txns.count}t ignored")
66
+ return []
67
+ end
68
+ @log.info("New content for #{id} arrived, #{before.length}b before and #{after.length}b after")
69
+ @entrance.push(id, body)
70
+ end
71
+ end
72
+ end
73
+ end
data/lib/zold/remotes.rb CHANGED
@@ -186,6 +186,7 @@ module Zold
186
186
  pool = Concurrent::FixedThreadPool.new([all.count, Concurrent.processor_count * 4].min, max_queue: 0)
187
187
  all.each do |r|
188
188
  pool.post do
189
+ Thread.current.abort_on_exception = true
189
190
  Thread.current.name = 'remotes'
190
191
  Thread.current.priority = -100
191
192
  start = Time.now
@@ -197,14 +198,14 @@ module Zold
197
198
  error(r[:host], r[:port])
198
199
  errors = errors(r[:host], r[:port])
199
200
  log.info("#{Rainbow("#{r[:host]}:#{r[:port]}").red}: #{e.message} \
200
- in #{(Time.now - start).round}s; errors=#{errors}")
201
+ in #{(Time.now - start).round}s; errors=#{errors}")
201
202
  log.debug(Backtrace.new(e).to_s)
202
203
  remove(r[:host], r[:port]) if errors > Remotes::TOLERANCE
203
204
  end
204
205
  end
205
206
  end
206
207
  pool.shutdown
207
- raise 'Failed to terminate the pool' unless pool.wait_for_termination(60)
208
+ pool.kill unless pool.wait_for_termination(5 * 60)
208
209
  end
209
210
 
210
211
  def errors(host, port = Remotes::PORT)
data/lib/zold/score.rb CHANGED
File without changes
data/lib/zold/tax.rb CHANGED
@@ -33,7 +33,7 @@ module Zold
33
33
  # A single tax payment
34
34
  class Tax
35
35
  # The exact score a wallet can buy in order to pay taxes.
36
- EXACT_SCORE = 16
36
+ EXACT_SCORE = 8
37
37
 
38
38
  # The maximum allowed amount in one transaction.
39
39
  MAX_PAYMENT = Amount.new(zld: 1.0)
data/lib/zold/txn.rb CHANGED
File without changes
data/lib/zold/type.rb CHANGED
File without changes
data/lib/zold/upgrades.rb CHANGED
File without changes
data/lib/zold/version.rb CHANGED
@@ -25,6 +25,6 @@
25
25
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.14.13'
28
+ VERSION = '0.14.14'
29
29
  PROTOCOL = 2
30
30
  end
File without changes
data/lib/zold/wallet.rb CHANGED
@@ -172,7 +172,9 @@ module Zold
172
172
  end
173
173
 
174
174
  def refurbish
175
- AtomicFile.new(@file).write("#{network}\n#{protocol}\n#{id}\n#{key.to_pub}\n\n#{txns.join("\n")}\n")
175
+ AtomicFile.new(@file).write(
176
+ "#{network}\n#{protocol}\n#{id}\n#{key.to_pub}\n\n#{txns.map { |t| t.to_s + "\n" }.join}"
177
+ )
176
178
  end
177
179
 
178
180
  private
@@ -39,10 +39,7 @@ class TestSpread < Minitest::Test
39
39
  opts = {
40
40
  'routine-immediately' => true
41
41
  }
42
- entrance = Zold::Entrance.new(
43
- home.wallets, home.remotes, home.copies(home.create_wallet).root, 'x', log: test_log
44
- )
45
- Zold::Routines::Spread.new(opts, home.wallets, entrance, log: test_log).exec
42
+ Zold::Routines::Spread.new(opts, home.wallets, home.remotes, log: test_log).exec
46
43
  end
47
44
  end
48
45
  end
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,49 @@
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 'minitest/autorun'
24
+ require_relative '../fake_home'
25
+ require_relative '../test__helper'
26
+ require_relative '../../lib/zold/id'
27
+ require_relative '../../lib/zold/node/nodup_entrance'
28
+ require_relative 'fake_entrance'
29
+
30
+ # NoDupEntrance test.
31
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
32
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
33
+ # License:: MIT
34
+ class TestAsyncEntrance < Minitest::Test
35
+ def test_ignores_dup
36
+ FakeHome.new.run do |home|
37
+ wallet = home.create_wallet
38
+ Zold::NoDupEntrance.new(RealEntrance.new, home.wallets, log: test_log).start do |e|
39
+ assert(e.push(wallet.id, File.read(wallet.path)).empty?)
40
+ end
41
+ end
42
+ end
43
+
44
+ class RealEntrance < FakeEntrance
45
+ def push(id, _)
46
+ [id]
47
+ end
48
+ end
49
+ end
data/test/test_http.rb CHANGED
File without changes
data/test/test_score.rb CHANGED
File without changes
data/test/test_tax.rb CHANGED
File without changes
File without changes
data/test/test_version.rb CHANGED
File without changes
data/test/test_wallet.rb CHANGED
@@ -56,9 +56,21 @@ class TestWallet < Minitest::Test
56
56
  key = Zold::Key.new(file: 'fixtures/id_rsa')
57
57
  wallet.sub(amount, "NOPREFIX@#{Zold::Id.new}", key)
58
58
  wallet.sub(amount, "NOPREFIX@#{Zold::Id.new}", key)
59
+ before = File.read(wallet.path)
59
60
  File.write(wallet.path, File.read(wallet.path) + "\n\n\n")
60
61
  wallet.refurbish
61
62
  assert_equal(amount * -2, wallet.balance)
63
+ assert_equal(before, File.read(wallet.path))
64
+ end
65
+ end
66
+
67
+ def test_refurbishes_empty_wallet
68
+ FakeHome.new.run do |home|
69
+ wallet = home.create_wallet
70
+ before = File.read(wallet.path)
71
+ File.write(wallet.path, File.read(wallet.path) + "\n\n\n")
72
+ wallet.refurbish
73
+ assert_equal(before, File.read(wallet.path))
62
74
  end
63
75
  end
64
76
 
File without changes
data/upgrades/2.rb CHANGED
File without changes
File without changes
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.13
4
+ version: 0.14.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-16 00:00:00.000000000 Z
11
+ date: 2018-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -405,7 +405,6 @@ files:
405
405
  - lib/zold/commands/pull.rb
406
406
  - lib/zold/commands/push.rb
407
407
  - lib/zold/commands/remote.rb
408
- - lib/zold/commands/routines/bonuses.rb
409
408
  - lib/zold/commands/routines/reconnect.rb
410
409
  - lib/zold/commands/routines/spread.rb
411
410
  - lib/zold/commands/show.rb
@@ -424,6 +423,7 @@ files:
424
423
  - lib/zold/node/entrance.rb
425
424
  - lib/zold/node/farm.rb
426
425
  - lib/zold/node/front.rb
426
+ - lib/zold/node/nodup_entrance.rb
427
427
  - lib/zold/node/safe_entrance.rb
428
428
  - lib/zold/node/spread_entrance.rb
429
429
  - lib/zold/patch.rb
@@ -441,7 +441,6 @@ files:
441
441
  - lib/zold/wallet.rb
442
442
  - lib/zold/wallets.rb
443
443
  - resources/remotes
444
- - test/commands/routines/test_bonuses.rb
445
444
  - test/commands/routines/test_reconnect.rb
446
445
  - test/commands/routines/test_spread.rb
447
446
  - test/commands/test_alias.rb
@@ -468,6 +467,7 @@ files:
468
467
  - test/node/test_entrance.rb
469
468
  - test/node/test_farm.rb
470
469
  - test/node/test_front.rb
470
+ - test/node/test_nodup_entrance.rb
471
471
  - test/node/test_safe_entrance.rb
472
472
  - test/node/test_spread_entrance.rb
473
473
  - test/test__helper.rb
@@ -528,7 +528,6 @@ test_files:
528
528
  - features/gem_package.feature
529
529
  - features/step_definitions/steps.rb
530
530
  - features/support/env.rb
531
- - test/commands/routines/test_bonuses.rb
532
531
  - test/commands/routines/test_reconnect.rb
533
532
  - test/commands/routines/test_spread.rb
534
533
  - test/commands/test_alias.rb
@@ -555,6 +554,7 @@ test_files:
555
554
  - test/node/test_entrance.rb
556
555
  - test/node/test_farm.rb
557
556
  - test/node/test_front.rb
557
+ - test/node/test_nodup_entrance.rb
558
558
  - test/node/test_safe_entrance.rb
559
559
  - test/node/test_spread_entrance.rb
560
560
  - test/test__helper.rb
@@ -1,78 +0,0 @@
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,76 +0,0 @@
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 'minitest/autorun'
24
- require 'webmock/minitest'
25
- require_relative '../../test__helper'
26
- require_relative '../../fake_home'
27
- require_relative '../../node/fake_node'
28
- require_relative '../../../lib/zold/node/farm.rb'
29
- require_relative '../../../lib/zold/commands/push'
30
- require_relative '../../../lib/zold/commands/pay'
31
- require_relative '../../../lib/zold/commands/routines/bonuses.rb'
32
-
33
- # Bonuses test.
34
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
35
- # Copyright:: Copyright (c) 2018 Yegor Bugayenko
36
- # License:: MIT
37
- class TestBonuses < Minitest::Test
38
- def test_pays_bonuses
39
- FakeHome.new.run do |home|
40
- FakeNode.new(log: test_log).run(['--ignore-score-weakness']) do |port|
41
- bank = home.create_wallet
42
- Zold::Pay.new(wallets: home.wallets, remotes: home.remotes, log: test_log).run(
43
- ['pay', home.create_wallet.id.to_s, bank.id.to_s, '100', '--force', '--private-key=id_rsa']
44
- )
45
- assert_equal(Zold::Amount.new(zld: 100.0), bank.balance)
46
- opts = {
47
- 'ignore-score-weakness' => true,
48
- 'routine-immediately' => true,
49
- 'private-key' => 'id_rsa',
50
- 'bonus-wallet' => bank.id.to_s,
51
- 'bonus-amount' => 1,
52
- 'bonus-time' => 0
53
- }
54
- score = Zold::Score.new(
55
- time: Time.now, host: 'fake-node.local', port: 999, invoice: 'NOPREFIX@ffffffffffffffff', strength: 1
56
- )
57
- 16.times { score = score.next }
58
- remotes = home.remotes
59
- remotes.add('localhost', port)
60
- remotes.add(score.host, score.port)
61
- stub_request(:get, "http://#{score.host}:#{score.port}/").to_return(
62
- status: 200,
63
- body: {
64
- version: Zold::VERSION,
65
- score: score.to_h
66
- }.to_json
67
- )
68
- Zold::Routines::Bonuses.new(
69
- opts, home.wallets, remotes, home.copies(bank).root,
70
- Zold::Farm::Empty.new, log: test_log
71
- ).exec
72
- assert_equal(Zold::Amount.new(zld: 99.0), bank.balance)
73
- end
74
- end
75
- end
76
- end