zold 0.17.5 → 0.17.6
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.
- checksums.yaml +4 -4
- data/lib/zold/commands/node.rb +10 -3
- data/lib/zold/node/async_entrance.rb +9 -2
- data/lib/zold/node/farm.rb +18 -23
- data/lib/zold/node/farmers.rb +6 -4
- data/lib/zold/node/front.rb +11 -4
- data/lib/zold/node/soft_error.rb +32 -0
- data/lib/zold/remotes.rb +6 -5
- data/lib/zold/version.rb +1 -1
- data/test/node/test_front.rb +16 -1
- data/zold.gemspec +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7a2934cd243231fd712085b3f87a94d6bb4bf614cc1f5a1e9cada9f7268939d
|
4
|
+
data.tar.gz: f92eb91031505dee84d3bdbbc072e3d7384494e4954a5420b7656b8089d425e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d974ce11c5bf502b56ce917c19ac1d388d3a28399ddcf84e0fc3860dd2935576965451f26750bcf52744c9b33f411a7e885d6c84cdcdcfbecc1699e008d7e5f
|
7
|
+
data.tar.gz: 7bb56302734385c3a20a824b0c9d312ed5d88b02adca2c6c0d9c68554e91d598f26ed29f2019e0435d4622308c5b0e889cade6737773ace52c62701b4fc2570c
|
data/lib/zold/commands/node.rb
CHANGED
@@ -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.
|
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
|
-
|
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
|
-
|
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
|
data/lib/zold/node/farm.rb
CHANGED
@@ -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
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
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)
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
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
|
data/lib/zold/node/farmers.rb
CHANGED
@@ -61,15 +61,17 @@ module Zold
|
|
61
61
|
|
62
62
|
def up(score)
|
63
63
|
start = Time.now
|
64
|
-
|
64
|
+
stdout, stdin = IO.pipe
|
65
65
|
pid = Process.fork do
|
66
|
-
|
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
|
data/lib/zold/node/front.rb
CHANGED
@@ -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(
|
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(
|
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
|
-
|
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
|
data/lib/zold/remotes.rb
CHANGED
@@ -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
|
-
|
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
|
|
data/lib/zold/version.rb
CHANGED
data/test/node/test_front.rb
CHANGED
@@ -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'
|
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|
|
data/zold.gemspec
CHANGED
@@ -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.
|
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.
|
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-
|
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.
|
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.
|
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.
|
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
|