zold 0.17.5 → 0.17.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c06af13af0d59a21c9855dc36c17c13cfe838286f7aadcb1ac3b130ed934d65d
4
- data.tar.gz: 4349ebaee96c42a6224b92a4fc9a398f28d0f7c07352a34fd965d63bbf00b706
3
+ metadata.gz: c7a2934cd243231fd712085b3f87a94d6bb4bf614cc1f5a1e9cada9f7268939d
4
+ data.tar.gz: f92eb91031505dee84d3bdbbc072e3d7384494e4954a5420b7656b8089d425e7
5
5
  SHA512:
6
- metadata.gz: 69b146cdf8bcc399e5213e1c8af4faa2aba937fd93a96ee845a0c9552ffbfe24fcb34d37c724298319aeddfde91ab2b30546f9afcb517232959000893ef40b4b
7
- data.tar.gz: 82943553b346434e975041142b6ac21ffe301bae24695dc509613ef9b8fd8c0a625003f1b060360550b3eab1076f3cd42ad02a7f5de7b7d405f09534f36a3c10
6
+ metadata.gz: 7d974ce11c5bf502b56ce917c19ac1d388d3a28399ddcf84e0fc3860dd2935576965451f26750bcf52744c9b33f411a7e885d6c84cdcdcfbecc1699e008d7e5f
7
+ data.tar.gz: 7bb56302734385c3a20a824b0c9d312ed5d88b02adca2c6c0d9c68554e91d598f26ed29f2019e0435d4622308c5b0e889cade6737773ace52c62701b4fc2570c
@@ -159,7 +159,7 @@ module Zold
159
159
  default: false
160
160
  o.string '--alias',
161
161
  'The alias of the node (default: host:port)'
162
- o.string '--no-spawn',
162
+ o.boolean '--no-spawn',
163
163
  'Don\'t use child processes for the score farm',
164
164
  default: false
165
165
  o.bool '--help', 'Print instructions'
@@ -259,8 +259,7 @@ module Zold
259
259
  network: opts['network']
260
260
  ).start do |entrance|
261
261
  Front.set(:entrance, entrance)
262
- farmer = opts['no-spawn'] ? Farmers::Plain.new : Farmers::Fork.new(log: @log)
263
- Farm.new(invoice, File.join(home, 'farm'), log: @log, farmer: farmer, strength: opts[:strength])
262
+ Farm.new(invoice, File.join(home, 'farm'), log: @log, farmer: farmer(opts), strength: opts[:strength])
264
263
  .start(host, opts[:port], threads: opts[:threads]) do |farm|
265
264
  Front.set(:farm, farm)
266
265
  metronome(farm, opts).start do |metronome|
@@ -276,6 +275,14 @@ module Zold
276
275
 
277
276
  private
278
277
 
278
+ def farmer(opts)
279
+ if opts['no-spawn']
280
+ @log.debug('Plain farmer is used, only one CPU will be utilized')
281
+ return Farmers::Plain.new
282
+ end
283
+ Farmers::Fork.new(log: @log)
284
+ end
285
+
279
286
  # Returns exit code
280
287
  def exec(cmd, nohup_log)
281
288
  start = Time.now
@@ -28,6 +28,7 @@ require_relative '../size'
28
28
  require_relative '../id'
29
29
  require_relative '../endless'
30
30
  require_relative '../dir_items'
31
+ require_relative 'soft_error'
31
32
 
32
33
  # The async entrance of the web front.
33
34
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -49,7 +50,8 @@ module Zold
49
50
  def to_json
50
51
  @entrance.to_json.merge(
51
52
  'queue': @queue.size,
52
- 'threads': @threads.count
53
+ 'threads': @threads.count,
54
+ 'queue_limit': @queue_limit
53
55
  )
54
56
  end
55
57
 
@@ -80,7 +82,12 @@ module Zold
80
82
 
81
83
  # Always returns an array with a single ID of the pushed wallet
82
84
  def push(id, body)
83
- raise "Queue is too long (#{@queue.size} wallets), try again later" if @queue.size > @queue_limit
85
+ if @queue.size > @queue_limit
86
+ raise(
87
+ SoftError,
88
+ "Queue is too long (#{@queue.size} wallets), can't add #{id}/#{Size.new(body.length)}, try again later"
89
+ )
90
+ end
84
91
  start = Time.now
85
92
  loop do
86
93
  uuid = SecureRandom.uuid
@@ -196,33 +196,28 @@ at #{host}:#{port}, strength is #{@strength}")
196
196
  def save(threads, list = [])
197
197
  scores = load + list
198
198
  period = @lifetime / [threads, 1].max
199
- Futex.new(@cache).open do |f|
200
- IO.write(
201
- f,
202
- scores.select(&:valid?)
203
- .reject(&:expired?)
204
- .reject { |s| s.strength < @strength }
205
- .sort_by(&:value)
206
- .reverse
207
- .uniq(&:time)
208
- .uniq { |s| (s.age / period).round }
209
- .map(&:to_s)
210
- .uniq
211
- .join("\n")
212
- )
213
- end
199
+ body = scores.select(&:valid?)
200
+ .reject(&:expired?)
201
+ .reject { |s| s.strength < @strength }
202
+ .sort_by(&:value)
203
+ .reverse
204
+ .uniq(&:time)
205
+ .uniq { |s| (s.age / period).round }
206
+ .map(&:to_s)
207
+ .uniq
208
+ .join("\n")
209
+ Futex.new(@cache).open { |f| IO.write(f, body) }
214
210
  end
215
211
 
216
212
  def load
217
213
  return [] unless File.exist?(@cache)
218
- Futex.new(@cache).open(false) do |f|
219
- IO.read(f).split(/\n/).map do |t|
220
- Score.parse(t)
221
- rescue StandardError => e
222
- @log.error(Backtrace.new(e).to_s)
223
- nil
224
- end.compact
225
- end
214
+ body = Futex.new(@cache).open(false) { |f| IO.read(f) }
215
+ body.split(/\n/).reject(&:empty?).map do |t|
216
+ Score.parse(t)
217
+ rescue StandardError => e
218
+ @log.error(Backtrace.new(e).to_s)
219
+ nil
220
+ end.compact
226
221
  end
227
222
  end
228
223
  end
@@ -61,15 +61,17 @@ module Zold
61
61
 
62
62
  def up(score)
63
63
  start = Time.now
64
- stdin, stdout = IO.pipe
64
+ stdout, stdin = IO.pipe
65
65
  pid = Process.fork do
66
- stdout.puts(score.next)
66
+ stdin.puts(score.next)
67
67
  end
68
68
  at_exit { Farmers.kill(@log, pid, start) }
69
69
  Process.wait
70
- stdout.close
71
- after = Score.parse(stdin.read.strip)
72
70
  stdin.close
71
+ text = stdout.read.strip
72
+ stdout.close
73
+ raise "No score was calculated in the process ##{pid} in #{Age.new(start)}" if text.empty?
74
+ after = Score.parse(text)
73
75
  @log.debug("Next score #{after.value}/#{after.strength} found in proc ##{pid} \
74
76
  for #{after.host}:#{after.port} in #{Age.new(start)}: #{after.suffixes}")
75
77
  after
@@ -38,6 +38,7 @@ require_relative '../log'
38
38
  require_relative '../tax'
39
39
  require_relative '../id'
40
40
  require_relative '../http'
41
+ require_relative 'soft_error'
41
42
 
42
43
  # The web front of the node.
43
44
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -46,6 +47,10 @@ require_relative '../http'
46
47
  module Zold
47
48
  # Web front
48
49
  class Front < Sinatra::Base
50
+ # The minimum score required in order to recongnize a requestor
51
+ # as a valuable node and add it to the list of remotes.
52
+ MIN_SCORE = 16
53
+
49
54
  configure do
50
55
  Thread.current.name = 'sinatra'
51
56
  set :bind, '0.0.0.0'
@@ -76,6 +81,7 @@ module Zold
76
81
  use Rack::Deflater
77
82
 
78
83
  before do
84
+ Thread.current.name = "#{request.request_method}:#{request.url}"
79
85
  Thread.current.thread_variable_set(:uri, request.url)
80
86
  Thread.current.thread_variable_set(:ip, request.ip)
81
87
  @start = Time.now
@@ -101,6 +107,7 @@ while #{settings.address} is in '#{settings.opts['network']}'")
101
107
  s = Score.parse_text(header)
102
108
  error(400, 'The score is invalid') unless s.valid?
103
109
  error(400, 'The score is weak') if s.strength < Score::STRENGTH && !settings.opts['ignore-score-weakness']
110
+ return if s.value < Front::MIN_SCORE && !settings.opts['ignore-score-weakness']
104
111
  if settings.address == "#{s.host}:#{s.port}" && !settings.opts['ignore-score-weakness']
105
112
  error(400, 'Self-requests are prohibited')
106
113
  end
@@ -120,10 +127,11 @@ while #{settings.address} is in '#{settings.opts['network']}'")
120
127
  # Currently there are no tests at all that would verify the headers.
121
128
  after do
122
129
  headers['Cache-Control'] = 'no-cache'
130
+ headers['X-Zold-Path'] = request.url
123
131
  headers['X-Zold-Version'] = settings.opts['expose-version']
124
132
  headers[Http::PROTOCOL_HEADER] = settings.protocol.to_s
125
133
  headers['Access-Control-Allow-Origin'] = '*'
126
- headers[Http::SCORE_HEADER] = score.reduced(16).to_s
134
+ headers[Http::SCORE_HEADER] = score.reduced(Front::MIN_SCORE).to_s
127
135
  headers['X-Zold-Thread'] = Thread.current.object_id.to_s
128
136
  unless @start.nil?
129
137
  if Time.now - @start > 1
@@ -199,7 +207,7 @@ in #{Age.new(@start, limit: 1)}")
199
207
  require 'get_process_mem'
200
208
  mem = GetProcessMem.new.bytes.to_i
201
209
  if mem > 256 * 1024 * 1024 && !settings.opts['skip-oom']
202
- settings.log.error('We are too big in memory, quitting; use --skip-oom to never quit')
210
+ settings.log.error("We are too big in memory (#{Size.new(mem)}), quitting; use --skip-oom to never quit")
203
211
  Front.stop!
204
212
  end
205
213
  mem
@@ -420,8 +428,7 @@ in #{Age.new(@start, limit: 1)}")
420
428
  e = env['sinatra.error']
421
429
  content_type 'text/plain'
422
430
  headers['X-Zold-Error'] = e.message
423
- headers['X-Zold-Path'] = request.url
424
- settings.log.error(Backtrace.new(e).to_s)
431
+ settings.log.error(Backtrace.new(e).to_s) unless e.is_a?(SoftError)
425
432
  Backtrace.new(e).to_s
426
433
  end
427
434
 
@@ -0,0 +1,32 @@
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
+ # Soft error.
24
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
25
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
+ # License:: MIT
27
+ module Zold
28
+ # Soft error
29
+ module SoftError
30
+ # Nothing special
31
+ end
32
+ end
@@ -104,20 +104,21 @@ module Zold
104
104
 
105
105
  def assert_valid_score(score)
106
106
  raise "Invalid score #{score}" unless score.valid?
107
- raise "Expired score (#{Age.new(score.time)}) #{score}" if score.expired?
107
+ raise "Expired score (#{Age.new(score.time)}) #{score.reduce(4)}" if score.expired?
108
108
  end
109
109
 
110
110
  def assert_score_ownership(score)
111
- raise "Masqueraded host #{@host} as #{score.host}: #{score}" if @host != score.host
112
- raise "Masqueraded port #{@port} as #{score.port}: #{score}" if @port != score.port
111
+ raise "Masqueraded host #{@host} as #{score.host}: #{score.reduce(4)}" if @host != score.host
112
+ raise "Masqueraded port #{@port} as #{score.port}: #{score.reduce(4)}" if @port != score.port
113
113
  end
114
114
 
115
115
  def assert_score_strength(score)
116
- raise "Score #{score.strength} is too weak (<#{Score::STRENGTH}): #{score}" if score.strength < Score::STRENGTH
116
+ return if score.strength >= Score::STRENGTH
117
+ raise "Score #{score.strength} is too weak (<#{Score::STRENGTH}): #{score.reduce(4)}"
117
118
  end
118
119
 
119
120
  def assert_score_value(score, min)
120
- raise "Score #{score.value} is too small (<#{min}): #{score}" if score.value < min
121
+ raise "Score #{score.value} is too small (<#{min}): #{score.reduce(4)}" if score.value < min
121
122
  end
122
123
  end
123
124
 
@@ -25,6 +25,6 @@
25
25
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.17.5'
28
+ VERSION = '0.17.6'
29
29
  PROTOCOL = 2
30
30
  end
@@ -266,7 +266,7 @@ class FrontTest < Zold::Test
266
266
 
267
267
  def test_performance
268
268
  times = Queue.new
269
- FakeNode.new(log: test_log).run(['--threads=4', '--strength=6', '--no-metronome', '--farmer=ruby-proc']) do |port|
269
+ FakeNode.new(log: test_log).run(['--threads=4', '--strength=6', '--no-metronome']) do |port|
270
270
  Threads.new(10).assert(100) do
271
271
  start = Time.now
272
272
  Zold::Http.new(uri: URI("http://localhost:#{port}/")).get
@@ -278,6 +278,21 @@ class FrontTest < Zold::Test
278
278
  test_log.info("Average response time is #{all.inject(&:+) / all.count}")
279
279
  end
280
280
 
281
+ # The score exposed via the HTTP header must be reduced to the value of 16.
282
+ # We need this in order to optimize the amount of data we transfer in each
283
+ # HTTP request. This value is enough to identify a valueable node, and filter
284
+ # out those that are too weak.
285
+ def test_score_is_reduced
286
+ FakeNode.new(log: test_log).run(['--threads=1', '--strength=1', '--no-metronome', '--no-spawn']) do |port|
287
+ res = Zold::Http.new(uri: URI("http://localhost:#{port}/")).get
288
+ assert_wait { Zold::Score.parse(res.headers[Zold::Http::SCORE_HEADER]).value > Zold::Front::MIN_SCORE - 1 }
289
+ sleep(1)
290
+ assert_equal_wait(Zold::Front::MIN_SCORE) do
291
+ Zold::Score.parse(res.headers[Zold::Http::SCORE_HEADER]).value
292
+ end
293
+ end
294
+ end
295
+
281
296
  def test_headers_are_being_set_correctly
282
297
  Time.stub :now, Time.at(0) do
283
298
  FakeNode.new(log: test_log).run(['--expose-version=9.9.9', '--no-metronome', '--threads=0']) do |port|
@@ -65,7 +65,7 @@ and suggests a different architecture for digital wallet maintenance.'
65
65
  s.add_runtime_dependency 'concurrent-ruby', '1.1.3'
66
66
  s.add_runtime_dependency 'cucumber', '3.1.2' # has to stay here for Heroku
67
67
  s.add_runtime_dependency 'diffy', '3.2.1'
68
- s.add_runtime_dependency 'futex', '0.4.3'
68
+ s.add_runtime_dependency 'futex', '0.6.1'
69
69
  s.add_runtime_dependency 'get_process_mem', '0.2.3'
70
70
  s.add_runtime_dependency 'json', '2.1.0'
71
71
  s.add_runtime_dependency 'memory_profiler', '0.9.12'
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.17.5
4
+ version: 0.17.6
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-12-01 00:00:00.000000000 Z
11
+ date: 2018-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 0.4.3
75
+ version: 0.6.1
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 0.4.3
82
+ version: 0.6.1
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: get_process_mem
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -603,6 +603,7 @@ files:
603
603
  - lib/zold/node/nodup_entrance.rb
604
604
  - lib/zold/node/nospam_entrance.rb
605
605
  - lib/zold/node/safe_entrance.rb
606
+ - lib/zold/node/soft_error.rb
606
607
  - lib/zold/node/spread_entrance.rb
607
608
  - lib/zold/node/sync_entrance.rb
608
609
  - lib/zold/node/trace.rb
@@ -699,7 +700,7 @@ licenses:
699
700
  - MIT
700
701
  metadata: {}
701
702
  post_install_message: |-
702
- Thanks for installing Zold 0.17.5!
703
+ Thanks for installing Zold 0.17.6!
703
704
  Study our White Paper: https://papers.zold.io/wp.pdf
704
705
  Read our blog posts: https://blog.zold.io
705
706
  Try online wallet at: https://wts.zold.io