zold 0.14.35 → 0.14.36
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/zold +13 -11
- data/lib/zold/commands/invoice.rb +3 -0
- data/lib/zold/commands/next.rb +1 -1
- data/lib/zold/commands/node.rb +7 -4
- data/lib/zold/http.rb +2 -6
- data/lib/zold/node/async_entrance.rb +1 -1
- data/lib/zold/node/farm.rb +49 -22
- data/lib/zold/node/front.rb +5 -3
- data/lib/zold/version.rb +1 -1
- data/resources/remotes +5 -0
- data/test/commands/test_remote.rb +1 -1
- data/test/node/fake_node.rb +6 -4
- data/test/node/test_farm.rb +8 -2
- data/test/node/test_front.rb +18 -7
- data/test/test__helper.rb +1 -1
- data/test/test_http.rb +24 -0
- data/zold.gemspec +1 -0
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0ac9a7fc3634c563abae9dce0f68ca709d46490
|
4
|
+
data.tar.gz: 59bb7653c11021d3d46c6cab7124480c9db2a103
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc4d99b314585fc077c82779463f09505d71f787a560087a2d55f3ab17184580df1aa0f12de8e0afb49914a0f2bff5d5064f343d579a9fe0d289562cacf94efe
|
7
|
+
data.tar.gz: 1995bae0601aa6cd84b5de1f3eeb58b27914f2d4d2935a503fa5226c88d12eaa659a6a76bcac58dae8b7103dac813ba90be1e66597490af4bf899e8f77ead092
|
data/bin/zold
CHANGED
@@ -113,6 +113,7 @@ Available options:"
|
|
113
113
|
default: Zold::Wallet::MAIN_NETWORK
|
114
114
|
o.bool '-h', '--help', 'Show these instructions'
|
115
115
|
o.bool '--trace', 'Show full stack trace in case of a problem'
|
116
|
+
o.bool '--skip-upgrades', 'Don\'t upgrade the storage', default: false
|
116
117
|
o.bool '--ignore-global-config', 'Don\'t read options from the ~/.zold file'
|
117
118
|
o.on '--no-colors', 'Disable colors in the ouput' do
|
118
119
|
Rainbow.enabled = false
|
@@ -146,17 +147,18 @@ Available options:"
|
|
146
147
|
|
147
148
|
zoldata = File.expand_path(File.join(Dir.pwd, '.zoldata'))
|
148
149
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
150
|
+
unless opts['skip-upgrades']
|
151
|
+
Zold::Upgrades.new(Zold::VersionFile.new(File.join(zoldata, 'version')), 'upgrades').run
|
152
|
+
# @todo #384:30min This is a workaround, move this code into Upgrades, somehow.
|
153
|
+
# We should find a way to run these arbitrary scripts and pass arguments
|
154
|
+
# to them. Each of them may need its own set of arguments.
|
155
|
+
require_relative '../upgrades/2'
|
156
|
+
Zold::UpgradeTo2.new(Dir.pwd, log).exec
|
157
|
+
require_relative '../upgrades/protocol_up'
|
158
|
+
Zold::ProtocolUp.new(Dir.pwd, log).exec
|
159
|
+
require_relative '../upgrades/rename_foreign_wallets'
|
160
|
+
Zold::RenameForeignWallets.new(Dir.pwd, opts['network'], log).exec
|
161
|
+
end
|
160
162
|
|
161
163
|
wallets = Zold::SyncWallets.new(Zold::Wallets.new('.'), File.join(zoldata, 'locks'), log: log)
|
162
164
|
remotes = Zold::Remotes.new(file: File.join(zoldata, 'remotes'), network: opts['network'])
|
@@ -48,6 +48,9 @@ Available options:"
|
|
48
48
|
o.integer '--length',
|
49
49
|
'The length of the invoice prefix (default: 8)',
|
50
50
|
default: 8
|
51
|
+
o.string '--network',
|
52
|
+
'The name of the network we work in',
|
53
|
+
default: 'test'
|
51
54
|
o.bool '--help', 'Print instructions'
|
52
55
|
end
|
53
56
|
mine = Args.new(opts, @log).take || return
|
data/lib/zold/commands/next.rb
CHANGED
data/lib/zold/commands/node.rb
CHANGED
@@ -76,8 +76,8 @@ module Zold
|
|
76
76
|
"The strength of the score (default: #{Score::STRENGTH})",
|
77
77
|
default: Score::STRENGTH
|
78
78
|
o.integer '--threads',
|
79
|
-
'How many threads to use for scores finding (default:
|
80
|
-
default:
|
79
|
+
'How many threads to use for scores finding (default: 2)',
|
80
|
+
default: 2
|
81
81
|
o.bool '--dump-errors',
|
82
82
|
'Make HTTP front-end errors visible in the log (false by default)',
|
83
83
|
default: false
|
@@ -302,14 +302,17 @@ module Zold
|
|
302
302
|
|
303
303
|
def metronome(farm, opts)
|
304
304
|
metronome = Metronome.new(@log)
|
305
|
-
|
305
|
+
if opts['no-metronome']
|
306
|
+
@log.info('Metronome hasn\'t been started because of --no-metronome')
|
307
|
+
return metronome
|
308
|
+
end
|
306
309
|
require_relative 'routines/spread'
|
307
310
|
metronome.add(Routines::Spread.new(opts, @wallets, @remotes, log: @log))
|
308
311
|
unless opts['standalone']
|
309
312
|
require_relative 'routines/reconnect'
|
310
313
|
metronome.add(Routines::Reconnect.new(opts, @remotes, farm, network: opts['network'], log: @log))
|
311
314
|
end
|
312
|
-
@log.info('Metronome
|
315
|
+
@log.info('Metronome started (use --no-metronome to disable it)')
|
313
316
|
metronome
|
314
317
|
end
|
315
318
|
|
data/lib/zold/http.rb
CHANGED
@@ -66,12 +66,8 @@ module Zold
|
|
66
66
|
# that is already taken care of in another issue. I am leaving a todo
|
67
67
|
# to check that rubocop doesn't complain anymore, otherwise find another
|
68
68
|
# solution
|
69
|
-
attribute :uri, (Types::Class.constructor
|
70
|
-
|
71
|
-
end)
|
72
|
-
attribute :score, (Types::Class.constructor do |value|
|
73
|
-
value.nil? ? Score::ZERO : value
|
74
|
-
end)
|
69
|
+
attribute :uri, (Types::Class.constructor { |v| v.is_a?(URI) ? v : URI(v) })
|
70
|
+
attribute :score, (Types::Class.constructor { |v| v.nil? ? Score::ZERO : v })
|
75
71
|
attribute :network, Types::Strict::String.optional.default('test')
|
76
72
|
|
77
73
|
def get
|
data/lib/zold/node/farm.rb
CHANGED
@@ -42,7 +42,7 @@ module Zold
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
def initialize(invoice, cache, log: Log::Quiet.new)
|
45
|
+
def initialize(invoice, cache = File.join(Dir.pwd, 'farm'), log: Log::Quiet.new)
|
46
46
|
@log = log
|
47
47
|
@cache = cache
|
48
48
|
@invoice = invoice
|
@@ -92,8 +92,15 @@ module Zold
|
|
92
92
|
@cleanup = Thread.new do
|
93
93
|
Thread.current.abort_on_exception = true
|
94
94
|
Thread.current.name = 'cleanup'
|
95
|
-
|
96
|
-
|
95
|
+
loop do
|
96
|
+
a = [0..600].take_while do
|
97
|
+
sleep 0.1
|
98
|
+
@alive
|
99
|
+
end
|
100
|
+
unless a.count == 600
|
101
|
+
@log.info("It's time to stop the cleanup thread...")
|
102
|
+
break
|
103
|
+
end
|
97
104
|
VerboseThread.new(@log).run do
|
98
105
|
cleanup(host, port, strength, threads)
|
99
106
|
end
|
@@ -106,25 +113,31 @@ module Zold
|
|
106
113
|
ensure
|
107
114
|
@log.info("Terminating the farm with #{@threads.count} threads...")
|
108
115
|
start = Time.now
|
109
|
-
@
|
110
|
-
|
111
|
-
@cleanup.join
|
112
|
-
@log.info("Cleanup thread finished in #{(Time.now - start).round(2)}s")
|
113
|
-
else
|
114
|
-
@cleanup.exit
|
115
|
-
@log.info("Cleanup thread killed in #{(Time.now - start).round(2)}s")
|
116
|
-
end
|
117
|
-
@threads.each do |t|
|
118
|
-
tstart = Time.now
|
119
|
-
t.join(0.1)
|
120
|
-
@log.info("Thread #{t.name} finished in #{(Time.now - tstart).round(2)}s")
|
121
|
-
end
|
116
|
+
finish(@cleanup)
|
117
|
+
@threads.each { |t| finish(t) }
|
122
118
|
@log.info("Farm stopped in #{(Time.now - start).round(2)}s")
|
123
119
|
end
|
124
120
|
end
|
125
121
|
|
126
122
|
private
|
127
123
|
|
124
|
+
def finish(thread)
|
125
|
+
start = Time.now
|
126
|
+
@alive = false
|
127
|
+
@log.info("Attempting to terminate the thread \"#{thread.name}\"...")
|
128
|
+
loop do
|
129
|
+
delay = (Time.now - start).round(2)
|
130
|
+
if thread.join(0.1)
|
131
|
+
@log.info("Thread \"#{thread.name}\" finished in #{delay}s")
|
132
|
+
break
|
133
|
+
end
|
134
|
+
if delay > 10
|
135
|
+
thread.exit
|
136
|
+
@log.error("Thread \"#{thread.name}\" forcefully terminated after #{delay}s")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
128
141
|
def cleanup(host, port, strength, threads)
|
129
142
|
scores = load
|
130
143
|
before = scores.map(&:value).max.to_i
|
@@ -141,14 +154,25 @@ module Zold
|
|
141
154
|
end
|
142
155
|
|
143
156
|
def cycle(host, port, strength, threads)
|
144
|
-
s =
|
157
|
+
s = []
|
158
|
+
loop do
|
159
|
+
return unless @alive
|
160
|
+
begin
|
161
|
+
s << @pipeline.pop(true)
|
162
|
+
rescue ThreadError => _
|
163
|
+
sleep 0.25
|
164
|
+
end
|
165
|
+
s.compact!
|
166
|
+
break unless s.empty?
|
167
|
+
end
|
168
|
+
s = s[0]
|
145
169
|
return unless s.valid?
|
146
170
|
return unless s.host == host
|
147
171
|
return unless s.port == port
|
148
172
|
return unless s.strength >= strength
|
149
173
|
Thread.current.name = s.to_mnemo
|
150
174
|
bin = File.expand_path(File.join(File.dirname(__FILE__), '../../../bin/zold'))
|
151
|
-
Open3.popen2e("ruby #{bin} next \"#{s}\"") do |stdin, stdout, thr|
|
175
|
+
Open3.popen2e("ruby #{bin} --skip-upgrades next \"#{s}\"") do |stdin, stdout, thr|
|
152
176
|
@log.debug("Score counting started in process ##{thr.pid}")
|
153
177
|
begin
|
154
178
|
stdin.close
|
@@ -157,18 +181,21 @@ module Zold
|
|
157
181
|
begin
|
158
182
|
buffer << stdout.read_nonblock(1024)
|
159
183
|
rescue IO::WaitReadable => e
|
160
|
-
@log.debug("Still waiting for data from the
|
184
|
+
@log.debug("Still waiting for the data from the process ##{thr.pid}: #{e.message}")
|
161
185
|
end
|
162
|
-
if buffer.end_with?("\n")
|
186
|
+
if buffer.end_with?("\n") && thr.value.to_i.zero?
|
163
187
|
score = Score.parse(buffer.strip)
|
164
188
|
@log.debug("New score discovered: #{score}")
|
165
189
|
save(threads, [score])
|
166
190
|
cleanup(host, port, strength, threads)
|
167
191
|
break
|
168
192
|
end
|
169
|
-
|
193
|
+
if stdout.closed?
|
194
|
+
raise "Failed to calculate the score (##{thr.value}): #{buffer}" unless thr.value.to_i.zero?
|
195
|
+
break
|
196
|
+
end
|
170
197
|
break unless @alive
|
171
|
-
sleep 0.
|
198
|
+
sleep 0.25
|
172
199
|
end
|
173
200
|
rescue StandardError => e
|
174
201
|
@log.error(Backtrace.new(e).to_s)
|
data/lib/zold/node/front.rb
CHANGED
@@ -27,6 +27,7 @@ require 'sinatra/base'
|
|
27
27
|
require 'webrick'
|
28
28
|
require 'get_process_mem'
|
29
29
|
require 'diffy'
|
30
|
+
require 'usagewatch_ext'
|
30
31
|
require 'concurrent'
|
31
32
|
require_relative '../backtrace'
|
32
33
|
require_relative '../version'
|
@@ -66,7 +67,7 @@ module Zold
|
|
66
67
|
set :farm, nil? # to be injected at node.rb
|
67
68
|
set :metronome, nil? # to be injected at node.rb
|
68
69
|
set :entrance, nil? # to be injected at node.rb
|
69
|
-
set :network,
|
70
|
+
set :network, 'test' # to be injected at node.rb
|
70
71
|
set :wallets, nil? # to be injected at node.rb
|
71
72
|
set :remotes, nil? # to be injected at node.rb
|
72
73
|
set :copies, nil? # to be injected at node.rb
|
@@ -162,13 +163,14 @@ while #{settings.address} is in '#{settings.network}'"
|
|
162
163
|
score: score.to_h,
|
163
164
|
pid: Process.pid,
|
164
165
|
cpus: Concurrent.processor_count,
|
165
|
-
memory: GetProcessMem.new.bytes,
|
166
|
+
memory: GetProcessMem.new.bytes.to_i,
|
166
167
|
platform: RUBY_PLATFORM,
|
168
|
+
load: Usagewatch.uw_load.to_f,
|
167
169
|
uptime: `uptime`.strip,
|
168
170
|
threads: "#{Thread.list.select { |t| t.status == 'run' }.count}/#{Thread.list.count}",
|
169
171
|
wallets: settings.wallets.all.count,
|
170
172
|
remotes: settings.remotes.all.count,
|
171
|
-
nscore: settings.remotes.all.map { |r| r[:score] }.inject(&:+),
|
173
|
+
nscore: settings.remotes.all.map { |r| r[:score] }.inject(&:+) || 0,
|
172
174
|
farm: settings.farm.to_json,
|
173
175
|
entrance: settings.entrance.to_json,
|
174
176
|
date: Time.now.utc.iso8601,
|
data/lib/zold/version.rb
CHANGED
data/resources/remotes
CHANGED
@@ -155,7 +155,7 @@ class TestRemote < Minitest::Test
|
|
155
155
|
)
|
156
156
|
cmd.run(%W[remote add localhost #{port}])
|
157
157
|
end
|
158
|
-
assert_equal(
|
158
|
+
assert_equal(11 + File.readlines('resources/remotes').count, remotes.all.count)
|
159
159
|
cmd.run(%w[remote select --max-nodes=5])
|
160
160
|
assert_equal(5, remotes.all.count)
|
161
161
|
end
|
data/test/node/fake_node.rb
CHANGED
@@ -68,11 +68,13 @@ class FakeNode
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
uri = "http://localhost:#{port}/"
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
loop do
|
72
|
+
ping = Zold::Http.new(uri: uri, score: nil, network: Zold::Front.network).get
|
73
|
+
break unless ping.code == '599' && node.alive?
|
74
|
+
@log.debug("Waiting for #{uri}: ##{ping.code}...")
|
75
|
+
sleep 0.5
|
74
76
|
end
|
75
|
-
raise
|
77
|
+
raise "The node is dead at #{uri}" unless node.alive?
|
76
78
|
begin
|
77
79
|
yield port
|
78
80
|
ensure
|
data/test/node/test_farm.rb
CHANGED
@@ -40,7 +40,7 @@ class FarmTest < Minitest::Test
|
|
40
40
|
def test_renders_in_json
|
41
41
|
Dir.mktmpdir do |dir|
|
42
42
|
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'), log: test_log)
|
43
|
-
farm.start('localhost', 80, threads:
|
43
|
+
farm.start('localhost', 80, threads: 2, strength: 2) do
|
44
44
|
assert_wait { !farm.best.empty? && !farm.best[0].value.zero? }
|
45
45
|
count = 0
|
46
46
|
100.times { count += farm.to_json[:best].length }
|
@@ -61,7 +61,7 @@ class FarmTest < Minitest::Test
|
|
61
61
|
def test_makes_best_score_in_background
|
62
62
|
Dir.mktmpdir do |dir|
|
63
63
|
farm = Zold::Farm.new('NOPREFIX1@ffffffffffffffff', File.join(dir, 'f'), log: test_log)
|
64
|
-
farm.start('localhost', 80, threads:
|
64
|
+
farm.start('localhost', 80, threads: 1, strength: 3) do
|
65
65
|
assert_wait { !farm.best.empty? && farm.best[0].value >= 3 }
|
66
66
|
score = farm.best[0]
|
67
67
|
assert(!score.expired?)
|
@@ -143,4 +143,10 @@ class FarmTest < Minitest::Test
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
end
|
146
|
+
|
147
|
+
def test_terminates_farm_entirely
|
148
|
+
Zold::Farm.new('NOPREFIX4@ffffffffffffffff', log: test_log).start('localhost', 4096, threads: 1, strength: 10) do
|
149
|
+
sleep 1
|
150
|
+
end
|
151
|
+
end
|
146
152
|
end
|
data/test/node/test_front.rb
CHANGED
@@ -32,6 +32,23 @@ require_relative '../../lib/zold/json_page'
|
|
32
32
|
require_relative '../../lib/zold/score'
|
33
33
|
|
34
34
|
class FrontTest < Minitest::Test
|
35
|
+
def test_renders_front_json
|
36
|
+
FakeNode.new(log: test_log).run(['--no-metronome', '--network=foo', '--threads=0']) do |port|
|
37
|
+
res = Zold::Http.new(uri: "http://localhost:#{port}/", network: 'foo', score: nil).get
|
38
|
+
json = JSON.parse(res.body)
|
39
|
+
assert_equal(Zold::VERSION, json['version'])
|
40
|
+
assert_equal(Zold::PROTOCOL, json['protocol'])
|
41
|
+
assert_equal('foo', json['network'])
|
42
|
+
assert(json['pid'].positive?)
|
43
|
+
assert(json['cpus'].positive?)
|
44
|
+
assert(json['memory'].positive?)
|
45
|
+
assert(json['load'].positive?)
|
46
|
+
assert(json['wallets'].positive?)
|
47
|
+
assert(json['remotes'].zero?)
|
48
|
+
assert(json['nscore'].zero?)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
35
52
|
def test_renders_public_pages
|
36
53
|
FakeNode.new(log: test_log).run(['--ignore-score-weakness']) do |port|
|
37
54
|
{
|
@@ -219,13 +236,7 @@ class FrontTest < Minitest::Test
|
|
219
236
|
'*',
|
220
237
|
response.header['Access-Control-Allow-Origin']
|
221
238
|
)
|
222
|
-
|
223
|
-
time: Time.now, host: 'localhost', port: port, invoice: 'NOPREFIX@ffffffffffffffff', strength: 2
|
224
|
-
)
|
225
|
-
assert_equal(
|
226
|
-
score.to_s,
|
227
|
-
response.header[Zold::Http::SCORE_HEADER]
|
228
|
-
)
|
239
|
+
assert(!response.header[Zold::Http::SCORE_HEADER].nil?)
|
229
240
|
end
|
230
241
|
end
|
231
242
|
end
|
data/test/test__helper.rb
CHANGED
data/test/test_http.rb
CHANGED
@@ -51,4 +51,28 @@ class TestHttp < Minitest::Test
|
|
51
51
|
res = Zold::Http.new(uri: 'http://good-host/', score: nil).get
|
52
52
|
assert_equal('200', res.code)
|
53
53
|
end
|
54
|
+
|
55
|
+
def test_sends_valid_network_header
|
56
|
+
stub_request(:get, 'http://some-host-1/')
|
57
|
+
.with(headers: { 'X-Zold-Network' => 'xyz' })
|
58
|
+
.to_return(status: 200)
|
59
|
+
res = Zold::Http.new(uri: 'http://some-host-1/', score: nil, network: 'xyz').get
|
60
|
+
assert_equal('200', res.code)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_sends_valid_protocol_header
|
64
|
+
stub_request(:get, 'http://some-host-2/')
|
65
|
+
.with(headers: { 'X-Zold-Protocol' => Zold::PROTOCOL })
|
66
|
+
.to_return(status: 200)
|
67
|
+
res = Zold::Http.new(uri: 'http://some-host-2/', score: nil).get
|
68
|
+
assert_equal('200', res.code)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_sends_valid_version_header
|
72
|
+
stub_request(:get, 'http://some-host-3/')
|
73
|
+
.with(headers: { 'X-Zold-Version' => Zold::VERSION })
|
74
|
+
.to_return(status: 200)
|
75
|
+
res = Zold::Http.new(uri: 'http://some-host-3/', score: nil).get
|
76
|
+
assert_equal('200', res.code)
|
77
|
+
end
|
54
78
|
end
|
data/zold.gemspec
CHANGED
@@ -71,6 +71,7 @@ and suggests a different architecture for digital wallet maintenance.'
|
|
71
71
|
s.add_runtime_dependency 'sinatra', '~>2.0'
|
72
72
|
s.add_runtime_dependency 'slop', '~>4.4'
|
73
73
|
s.add_runtime_dependency 'sys-proctable', '1.1.5'
|
74
|
+
s.add_runtime_dependency 'usagewatch_ext', '0.2.0'
|
74
75
|
s.add_runtime_dependency 'xcop', '~>0.5'
|
75
76
|
s.add_development_dependency 'codecov', '0.1.10'
|
76
77
|
s.add_development_dependency 'minitest', '5.11.3'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zold
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.36
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
@@ -248,6 +248,20 @@ dependencies:
|
|
248
248
|
- - '='
|
249
249
|
- !ruby/object:Gem::Version
|
250
250
|
version: 1.1.5
|
251
|
+
- !ruby/object:Gem::Dependency
|
252
|
+
name: usagewatch_ext
|
253
|
+
requirement: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - '='
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: 0.2.0
|
258
|
+
type: :runtime
|
259
|
+
prerelease: false
|
260
|
+
version_requirements: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - '='
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: 0.2.0
|
251
265
|
- !ruby/object:Gem::Dependency
|
252
266
|
name: xcop
|
253
267
|
requirement: !ruby/object:Gem::Requirement
|