zold 0.14.52 → 0.14.53
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/diff.rb +1 -2
- data/lib/zold/commands/node.rb +12 -4
- data/lib/zold/commands/push.rb +1 -2
- data/lib/zold/copies.rb +4 -4
- data/lib/zold/head.rb +1 -1
- data/lib/zold/key.rb +1 -2
- data/lib/zold/node/async_entrance.rb +1 -1
- data/lib/zold/node/farm.rb +3 -3
- data/lib/zold/node/front.rb +30 -7
- data/lib/zold/node/nodup_entrance.rb +1 -2
- data/lib/zold/patch.rb +2 -3
- data/lib/zold/remotes.rb +6 -8
- data/lib/zold/txns.rb +1 -2
- data/lib/zold/version.rb +1 -1
- data/lib/zold/wallet.rb +4 -3
- data/test/fake_home.rb +1 -2
- data/test/node/test_front.rb +29 -21
- data/test/test_zold.rb +1 -1
- data/zold.gemspec +1 -0
- metadata +16 -5
- data/lib/zold/atomic_file.rb +0 -52
- data/test/test_atomic_file.rb +0 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12bf3dea4ff2630f3530269b7c5db959ad30cec8ab6346ba3336570c4a61822d
|
4
|
+
data.tar.gz: 1cb07c0e0ce665ededffc57a221ead9a235d99ba9eb391a8a75b1af6434bf093
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4788bfa23317ab20259ef9fae9266556d402caf07de529d8358d9541f61dca9f42b2921b6d15535e8b11583c4f79c130aae3fa82cda5cd8fd494aeb645f8fd8d
|
7
|
+
data.tar.gz: 2a929f263c3a0a2fa91e6cddc9436b273781c58f121753ad28191f4fa140b5df7b9f07bda75e84dcc448e6d30633695895906fac47089be453246b83f3665e83
|
data/lib/zold/commands/diff.rb
CHANGED
@@ -28,7 +28,6 @@ require_relative 'args'
|
|
28
28
|
require_relative '../log'
|
29
29
|
require_relative '../patch'
|
30
30
|
require_relative '../wallet'
|
31
|
-
require_relative '../atomic_file'
|
32
31
|
|
33
32
|
# DIFF command.
|
34
33
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -68,7 +67,7 @@ Available options:"
|
|
68
67
|
patch.join(Wallet.new(c[:path]))
|
69
68
|
end
|
70
69
|
before = @wallets.find(id) do |wallet|
|
71
|
-
|
70
|
+
File.read(wallet.path)
|
72
71
|
end
|
73
72
|
after = ''
|
74
73
|
Tempfile.open(['', Wallet::EXTENSION]) do |f|
|
data/lib/zold/commands/node.rb
CHANGED
@@ -135,6 +135,12 @@ module Zold
|
|
135
135
|
'Don\'t run the metronome',
|
136
136
|
required: true,
|
137
137
|
default: false
|
138
|
+
o.bool '--disable-push',
|
139
|
+
'Prohibit all PUSH requests',
|
140
|
+
default: false
|
141
|
+
o.bool '--disable-fetch',
|
142
|
+
'Prohibit all FETCH requests',
|
143
|
+
default: false
|
138
144
|
o.string '--alias',
|
139
145
|
'The alias of the node (default: host:port)',
|
140
146
|
require: false
|
@@ -160,6 +166,8 @@ module Zold
|
|
160
166
|
Front.set(:protocol, Zold::PROTOCOL)
|
161
167
|
Front.set(:logging, @log.debug?)
|
162
168
|
Front.set(:halt, opts['halt-code'])
|
169
|
+
Front.set(:disable_push, opts['disable-push'])
|
170
|
+
Front.set(:disable_fetch, opts['disable-fetch'])
|
163
171
|
Front.set(:home, opts['home'])
|
164
172
|
@log.info("Time: #{Time.now.utc.iso8601}")
|
165
173
|
@log.info("Home directory: #{opts['home']}")
|
@@ -198,7 +206,7 @@ module Zold
|
|
198
206
|
Front.set(:port, opts['bind-port'])
|
199
207
|
Front.set(:reboot, !opts['never-reboot'])
|
200
208
|
node_alias = opts[:alias] || address
|
201
|
-
unless node_alias.eql?(address) || node_alias =~ /^[
|
209
|
+
unless node_alias.eql?(address) || node_alias =~ /^[A-Za-z0-9]{4,16}$/
|
202
210
|
raise "Alias should be a 4 to 16 char long alphanumeric string: #{node_alias}"
|
203
211
|
end
|
204
212
|
Front.set(:node_alias, node_alias)
|
@@ -375,7 +383,7 @@ module Zold
|
|
375
383
|
end
|
376
384
|
|
377
385
|
def info(msg)
|
378
|
-
@log.debug(msg)
|
386
|
+
@log.debug('WEBRICK ' + msg)
|
379
387
|
end
|
380
388
|
|
381
389
|
def debug(msg)
|
@@ -383,11 +391,11 @@ module Zold
|
|
383
391
|
end
|
384
392
|
|
385
393
|
def error(msg)
|
386
|
-
@log.error(msg)
|
394
|
+
@log.error('WEBRICK ' + msg)
|
387
395
|
end
|
388
396
|
|
389
397
|
def fatal(msg)
|
390
|
-
@log.error(msg)
|
398
|
+
@log.error('WEBRICK ' + msg)
|
391
399
|
end
|
392
400
|
|
393
401
|
def debug?
|
data/lib/zold/commands/push.rb
CHANGED
@@ -31,7 +31,6 @@ require_relative '../log'
|
|
31
31
|
require_relative '../id'
|
32
32
|
require_relative '../http'
|
33
33
|
require_relative '../json_page'
|
34
|
-
require_relative '../atomic_file'
|
35
34
|
|
36
35
|
# PUSH command.
|
37
36
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -91,7 +90,7 @@ total score for #{id} is #{total}")
|
|
91
90
|
start = Time.now
|
92
91
|
content = @wallets.find(id) do |wallet|
|
93
92
|
raise "The wallet #{id} is absent" unless wallet.exists?
|
94
|
-
|
93
|
+
File.read(wallet.path)
|
95
94
|
end
|
96
95
|
uri = "/wallet/#{id}"
|
97
96
|
response = r.http(uri).put(content)
|
data/lib/zold/copies.rb
CHANGED
@@ -23,7 +23,6 @@
|
|
23
23
|
require 'time'
|
24
24
|
require 'csv'
|
25
25
|
require 'backtrace'
|
26
|
-
require_relative 'atomic_file'
|
27
26
|
require_relative 'log'
|
28
27
|
require_relative 'size'
|
29
28
|
require_relative 'wallet'
|
@@ -104,7 +103,7 @@ module Zold
|
|
104
103
|
list = load
|
105
104
|
target = list.find do |s|
|
106
105
|
f = File.join(@dir, "#{s[:name]}#{Copies::EXT}")
|
107
|
-
File.exist?(f) &&
|
106
|
+
File.exist?(f) && File.read(f) == content
|
108
107
|
end
|
109
108
|
if target.nil?
|
110
109
|
max = Dir.new(@dir)
|
@@ -113,7 +112,7 @@ module Zold
|
|
113
112
|
.max
|
114
113
|
max = 0 if max.nil?
|
115
114
|
name = (max + 1).to_s
|
116
|
-
|
115
|
+
File.write(File.join(@dir, "#{name}#{Copies::EXT}"), content)
|
117
116
|
else
|
118
117
|
name = target[:name]
|
119
118
|
end
|
@@ -161,7 +160,8 @@ module Zold
|
|
161
160
|
private
|
162
161
|
|
163
162
|
def save(list)
|
164
|
-
|
163
|
+
File.write(
|
164
|
+
file,
|
165
165
|
list.map do |r|
|
166
166
|
[
|
167
167
|
r[:name], r[:host],
|
data/lib/zold/head.rb
CHANGED
@@ -39,7 +39,7 @@ module Zold
|
|
39
39
|
|
40
40
|
def fetch
|
41
41
|
raise "Wallet file '#{@file}' is absent" unless File.exist?(@file)
|
42
|
-
lines =
|
42
|
+
lines = File.read(@file).split(/\n/)
|
43
43
|
raise "Not enough lines in #{@file}, just #{lines.count}" if lines.count < 4
|
44
44
|
lines.take(4)
|
45
45
|
end
|
data/lib/zold/key.rb
CHANGED
@@ -24,7 +24,6 @@ gem 'openssl'
|
|
24
24
|
require 'openssl'
|
25
25
|
require 'base64'
|
26
26
|
require 'tempfile'
|
27
|
-
require_relative 'atomic_file'
|
28
27
|
|
29
28
|
# The RSA key (either private or public).
|
30
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -38,7 +37,7 @@ module Zold
|
|
38
37
|
unless file.nil?
|
39
38
|
path = File.expand_path(file)
|
40
39
|
raise "Can't find RSA key at #{file} (#{path})" unless File.exist?(path)
|
41
|
-
return
|
40
|
+
return File.read(path)
|
42
41
|
end
|
43
42
|
unless text.nil?
|
44
43
|
return text if text.start_with?('-----')
|
@@ -97,7 +97,7 @@ module Zold
|
|
97
97
|
def push(id, body)
|
98
98
|
raise "Queue is too long (#{queue.count} wallets), try again later" if queue.count > AsyncEntrance::MAX_QUEUE
|
99
99
|
@mutex.synchronize do
|
100
|
-
|
100
|
+
File.write(File.join(@dir, id.to_s), body)
|
101
101
|
end
|
102
102
|
[id]
|
103
103
|
end
|
data/lib/zold/node/farm.rb
CHANGED
@@ -27,7 +27,6 @@ require_relative '../log'
|
|
27
27
|
require_relative '../score'
|
28
28
|
require_relative '../age'
|
29
29
|
require_relative '../verbose_thread'
|
30
|
-
require_relative '../atomic_file'
|
31
30
|
|
32
31
|
# The farm of scores.
|
33
32
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -222,7 +221,8 @@ module Zold
|
|
222
221
|
scores = load + list
|
223
222
|
period = 24 * 60 * 60 / [threads, 1].max
|
224
223
|
@mutex.synchronize do
|
225
|
-
|
224
|
+
File.write(
|
225
|
+
@cache,
|
226
226
|
scores.select(&:valid?)
|
227
227
|
.reject(&:expired?)
|
228
228
|
.sort_by(&:value)
|
@@ -239,7 +239,7 @@ module Zold
|
|
239
239
|
def load
|
240
240
|
@mutex.synchronize do
|
241
241
|
if File.exist?(@cache)
|
242
|
-
|
242
|
+
File.read(@cache).split(/\n/)
|
243
243
|
.map { |t| parse_score_line(t) }
|
244
244
|
.reject(&:zero?)
|
245
245
|
else
|
data/lib/zold/node/front.rb
CHANGED
@@ -35,11 +35,11 @@ require 'backtrace'
|
|
35
35
|
require_relative '../version'
|
36
36
|
require_relative '../size'
|
37
37
|
require_relative '../wallet'
|
38
|
+
require_relative '../age'
|
38
39
|
require_relative '../copies'
|
39
40
|
require_relative '../log'
|
40
41
|
require_relative '../id'
|
41
42
|
require_relative '../http'
|
42
|
-
require_relative '../atomic_file'
|
43
43
|
|
44
44
|
# The web front of the node.
|
45
45
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -56,7 +56,7 @@ module Zold
|
|
56
56
|
set :start, Time.now
|
57
57
|
set :lock, false
|
58
58
|
set :show_exceptions, false
|
59
|
-
set :server,
|
59
|
+
set :server, :puma
|
60
60
|
set :log, nil? # to be injected at node.rb
|
61
61
|
set :trace, nil? # to be injected at node.rb
|
62
62
|
set :halt, '' # to be injected at node.rb
|
@@ -110,17 +110,19 @@ while #{settings.address} is in '#{settings.network}'"
|
|
110
110
|
cmd = Remote.new(remotes: settings.remotes, log: settings.log)
|
111
111
|
cmd.run(['remote', 'add', s.host, s.port.to_s, "--network=#{settings.network}"])
|
112
112
|
end
|
113
|
+
@start = Time.now
|
113
114
|
end
|
114
115
|
|
115
116
|
# @todo #357:30min Test that the headers are being set correctly.
|
116
117
|
# Currently there are no tests at all that would verify the headers.
|
117
118
|
after do
|
118
119
|
headers['Cache-Control'] = 'no-cache'
|
119
|
-
headers['Connection'] = 'close'
|
120
120
|
headers['X-Zold-Version'] = settings.version
|
121
121
|
headers[Http::PROTOCOL_HEADER] = settings.protocol.to_s
|
122
122
|
headers['Access-Control-Allow-Origin'] = '*'
|
123
123
|
headers[Http::SCORE_HEADER] = score.reduced(16).to_s
|
124
|
+
headers['X-Zold-Thread'] = Thread.current.name
|
125
|
+
headers['X-Zold-Milliseconds'] = ((Time.now - @start) * 1000).round.to_s
|
124
126
|
end
|
125
127
|
|
126
128
|
get '/robots.txt' do
|
@@ -192,6 +194,7 @@ while #{settings.address} is in '#{settings.network}'"
|
|
192
194
|
end
|
193
195
|
|
194
196
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})} do
|
197
|
+
error 404 if settings.disable_fetch
|
195
198
|
id = Id.new(params[:id])
|
196
199
|
settings.wallets.find(id) do |wallet|
|
197
200
|
error 404 unless wallet.exists?
|
@@ -208,12 +211,13 @@ while #{settings.address} is in '#{settings.network}'"
|
|
208
211
|
digest: wallet.digest,
|
209
212
|
copies: Copies.new(File.join(settings.copies, id)).all.count,
|
210
213
|
balance: wallet.balance.to_i,
|
211
|
-
body:
|
214
|
+
body: File.new(wallet.path).read
|
212
215
|
)
|
213
216
|
end
|
214
217
|
end
|
215
218
|
|
216
219
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16}).json} do
|
220
|
+
error 404 if settings.disable_fetch
|
217
221
|
id = Id.new(params[:id])
|
218
222
|
settings.wallets.find(id) do |wallet|
|
219
223
|
error 404 unless wallet.exists?
|
@@ -235,6 +239,7 @@ while #{settings.address} is in '#{settings.network}'"
|
|
235
239
|
end
|
236
240
|
|
237
241
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/balance} do
|
242
|
+
error 404 if settings.disable_fetch
|
238
243
|
id = Id.new(params[:id])
|
239
244
|
settings.wallets.find(id) do |wallet|
|
240
245
|
error 404 unless wallet.exists?
|
@@ -244,6 +249,7 @@ while #{settings.address} is in '#{settings.network}'"
|
|
244
249
|
end
|
245
250
|
|
246
251
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/key} do
|
252
|
+
error 404 if settings.disable_fetch
|
247
253
|
id = Id.new(params[:id])
|
248
254
|
settings.wallets.find(id) do |wallet|
|
249
255
|
error 404 unless wallet.exists?
|
@@ -253,6 +259,7 @@ while #{settings.address} is in '#{settings.network}'"
|
|
253
259
|
end
|
254
260
|
|
255
261
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/mtime} do
|
262
|
+
error 404 if settings.disable_fetch
|
256
263
|
id = Id.new(params[:id])
|
257
264
|
settings.wallets.find(id) do |wallet|
|
258
265
|
error 404 unless wallet.exists?
|
@@ -262,6 +269,7 @@ while #{settings.address} is in '#{settings.network}'"
|
|
262
269
|
end
|
263
270
|
|
264
271
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/digest} do
|
272
|
+
error 404 if settings.disable_fetch
|
265
273
|
id = Id.new(params[:id])
|
266
274
|
settings.wallets.find(id) do |wallet|
|
267
275
|
error 404 unless wallet.exists?
|
@@ -271,6 +279,7 @@ while #{settings.address} is in '#{settings.network}'"
|
|
271
279
|
end
|
272
280
|
|
273
281
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})\.txt} do
|
282
|
+
error 404 if settings.disable_fetch
|
274
283
|
id = Id.new(params[:id])
|
275
284
|
settings.wallets.find(id) do |wallet|
|
276
285
|
error 404 unless wallet.exists?
|
@@ -284,25 +293,27 @@ while #{settings.address} is in '#{settings.network}'"
|
|
284
293
|
wallet.txns.map(&:to_text).join("\n"),
|
285
294
|
'',
|
286
295
|
'--',
|
287
|
-
"Balance: #{wallet.balance.to_zld} ZLD (#{wallet.balance.to_i} zents)",
|
296
|
+
"Balance: #{wallet.balance.to_zld(8)} ZLD (#{wallet.balance.to_i} zents)",
|
288
297
|
"Transactions: #{wallet.txns.count}",
|
289
298
|
"File size: #{File.size(wallet.path)} bytes (#{Copies.new(File.join(settings.copies, id)).all.count} copies)",
|
290
|
-
"Modified: #{wallet.mtime.utc.iso8601}",
|
299
|
+
"Modified: #{wallet.mtime.utc.iso8601} (#{Age.new(wallet.mtime.utc.iso8601)} ago)",
|
291
300
|
"Digest: #{wallet.digest}"
|
292
301
|
].join("\n")
|
293
302
|
end
|
294
303
|
end
|
295
304
|
|
296
305
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})\.bin} do
|
306
|
+
error 404 if settings.disable_fetch
|
297
307
|
id = Id.new(params[:id])
|
298
308
|
settings.wallets.find(id) do |wallet|
|
299
309
|
error 404 unless wallet.exists?
|
300
310
|
content_type 'text/plain'
|
301
|
-
|
311
|
+
File.read(wallet.path)
|
302
312
|
end
|
303
313
|
end
|
304
314
|
|
305
315
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/copies} do
|
316
|
+
error 404 if settings.disable_fetch
|
306
317
|
id = Id.new(params[:id])
|
307
318
|
settings.wallets.find(id) do |wallet|
|
308
319
|
error 404 unless wallet.exists?
|
@@ -321,6 +332,7 @@ while #{settings.address} is in '#{settings.network}'"
|
|
321
332
|
end
|
322
333
|
|
323
334
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/copy/(?<name>[0-9]+)} do
|
335
|
+
error 404 if settings.disable_fetch
|
324
336
|
id = Id.new(params[:id])
|
325
337
|
name = params[:name]
|
326
338
|
settings.wallets.find(id) do |wallet|
|
@@ -333,6 +345,7 @@ while #{settings.address} is in '#{settings.network}'"
|
|
333
345
|
end
|
334
346
|
|
335
347
|
put %r{/wallet/(?<id>[A-Fa-f0-9]{16})/?} do
|
348
|
+
error 404 if settings.disable_push
|
336
349
|
request.body.rewind
|
337
350
|
modified = settings.entrance.push(Id.new(params[:id]), request.body.read.to_s)
|
338
351
|
if modified.empty?
|
@@ -368,6 +381,16 @@ while #{settings.address} is in '#{settings.network}'"
|
|
368
381
|
settings.metronome.to_text
|
369
382
|
end
|
370
383
|
|
384
|
+
get '/threads' do
|
385
|
+
content_type 'text/plain'
|
386
|
+
Thread.list.map do |t|
|
387
|
+
[
|
388
|
+
"#{t.name}: status=#{t.status}; alive=#{t.alive?}",
|
389
|
+
t.backtrace.nil? ? 'NO BACKTRACE' : " #{t.backtrace.join("\n ")}"
|
390
|
+
].join("\n")
|
391
|
+
end.join("\n\n")
|
392
|
+
end
|
393
|
+
|
371
394
|
not_found do
|
372
395
|
status 404
|
373
396
|
content_type 'text/plain'
|
@@ -24,7 +24,6 @@ require 'tempfile'
|
|
24
24
|
require_relative '../log'
|
25
25
|
require_relative '../size'
|
26
26
|
require_relative '../wallet'
|
27
|
-
require_relative '../atomic_file'
|
28
27
|
|
29
28
|
# The entrance that ignores duplicates.
|
30
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -61,7 +60,7 @@ module Zold
|
|
61
60
|
wallet.refurbish
|
62
61
|
after = File.read(wallet.path)
|
63
62
|
before = @wallets.find(id) do |w|
|
64
|
-
w.exists? ?
|
63
|
+
w.exists? ? File.read(w.path).to_s : ''
|
65
64
|
end
|
66
65
|
if before == after
|
67
66
|
@log.info(
|
data/lib/zold/patch.rb
CHANGED
@@ -23,7 +23,6 @@
|
|
23
23
|
require_relative 'log'
|
24
24
|
require_relative 'wallet'
|
25
25
|
require_relative 'signature'
|
26
|
-
require_relative 'atomic_file'
|
27
26
|
|
28
27
|
# Patch.
|
29
28
|
#
|
@@ -120,7 +119,7 @@ among #{payer.txns.count} transactions: #{txn.to_text}")
|
|
120
119
|
def save(file, overwrite: false)
|
121
120
|
raise 'You have to join at least one wallet in' if @id.nil?
|
122
121
|
before = ''
|
123
|
-
before =
|
122
|
+
before = File.read(file) if File.exist?(file)
|
124
123
|
wallet = Wallet.new(file)
|
125
124
|
wallet.init(@id, @key, overwrite: overwrite, network: @network)
|
126
125
|
File.open(file, 'a') do |f|
|
@@ -129,7 +128,7 @@ among #{payer.txns.count} transactions: #{txn.to_text}")
|
|
129
128
|
end
|
130
129
|
end
|
131
130
|
wallet.refurbish
|
132
|
-
after =
|
131
|
+
after = File.read(file)
|
133
132
|
before != after
|
134
133
|
end
|
135
134
|
end
|
data/lib/zold/remotes.rb
CHANGED
@@ -31,7 +31,6 @@ require_relative 'age'
|
|
31
31
|
require_relative 'score'
|
32
32
|
require_relative 'http'
|
33
33
|
require_relative 'node/farm'
|
34
|
-
require_relative 'atomic_file'
|
35
34
|
require_relative 'type'
|
36
35
|
|
37
36
|
# The list of remotes.
|
@@ -50,12 +49,10 @@ module Zold
|
|
50
49
|
# Default number of nodes to fetch.
|
51
50
|
MAX_NODES = 16
|
52
51
|
|
53
|
-
# Mutex object
|
54
|
-
MUTEX = Mutex.new
|
55
|
-
|
56
52
|
attribute :file, Types::Strict::String
|
57
53
|
attribute :network, Types::Strict::String.optional.default('test')
|
58
54
|
attribute :timeout, Types::Strict::Integer.optional.default(16)
|
55
|
+
attribute :mutex, Types::Object.optional.default(Mutex.new)
|
59
56
|
|
60
57
|
# Empty, for standalone mode
|
61
58
|
class Empty < Remotes
|
@@ -183,7 +180,7 @@ module Zold
|
|
183
180
|
list.each do |r|
|
184
181
|
pool.post do
|
185
182
|
Thread.current.abort_on_exception = true
|
186
|
-
Thread.current.name = "remotes@#{r[:host]}:#{r[:port]}"
|
183
|
+
Thread.current.name = "remotes-#{idx}@#{r[:host]}:#{r[:port]}"
|
187
184
|
start = Time.now
|
188
185
|
begin
|
189
186
|
yield Remotes::Remote.new(
|
@@ -194,7 +191,6 @@ module Zold
|
|
194
191
|
log: log,
|
195
192
|
network: network
|
196
193
|
)
|
197
|
-
idx += 1
|
198
194
|
raise 'Took too long to execute' if (Time.now - start).round > timeout
|
199
195
|
rescue StandardError => e
|
200
196
|
error(r[:host], r[:port])
|
@@ -203,6 +199,7 @@ module Zold
|
|
203
199
|
remove(r[:host], r[:port]) if errors > Remotes::TOLERANCE
|
204
200
|
end
|
205
201
|
end
|
202
|
+
idx += 1
|
206
203
|
end
|
207
204
|
pool.shutdown
|
208
205
|
pool.kill unless pool.wait_for_termination(5 * 60)
|
@@ -230,7 +227,7 @@ module Zold
|
|
230
227
|
private
|
231
228
|
|
232
229
|
def modify
|
233
|
-
|
230
|
+
mutex.synchronize do
|
234
231
|
save(yield(load))
|
235
232
|
end
|
236
233
|
end
|
@@ -261,7 +258,8 @@ module Zold
|
|
261
258
|
end
|
262
259
|
|
263
260
|
def save(list)
|
264
|
-
|
261
|
+
File.write(
|
262
|
+
file,
|
265
263
|
list.uniq { |r| "#{r[:host]}:#{r[:port]}" }.map do |r|
|
266
264
|
[
|
267
265
|
r[:host],
|
data/lib/zold/txns.rb
CHANGED
@@ -21,7 +21,6 @@
|
|
21
21
|
# SOFTWARE.
|
22
22
|
|
23
23
|
require_relative 'txn'
|
24
|
-
require_relative 'atomic_file'
|
25
24
|
|
26
25
|
# Transactions in a wallet.
|
27
26
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -40,7 +39,7 @@ module Zold
|
|
40
39
|
|
41
40
|
def fetch
|
42
41
|
raise "Wallet file '#{@file}' is absent" unless File.exist?(@file)
|
43
|
-
lines =
|
42
|
+
lines = File.read(@file).split(/\n/)
|
44
43
|
raise "Not enough lines in #{@file}, just #{lines.count}" if lines.count < 4
|
45
44
|
lines.drop(5)
|
46
45
|
.each_with_index
|
data/lib/zold/version.rb
CHANGED
data/lib/zold/wallet.rb
CHANGED
@@ -30,7 +30,6 @@ require_relative 'tax'
|
|
30
30
|
require_relative 'amount'
|
31
31
|
require_relative 'hexnum'
|
32
32
|
require_relative 'signature'
|
33
|
-
require_relative 'atomic_file'
|
34
33
|
require_relative 'txns'
|
35
34
|
require_relative 'head'
|
36
35
|
|
@@ -90,7 +89,8 @@ module Zold
|
|
90
89
|
def init(id, pubkey, overwrite: false, network: 'test')
|
91
90
|
raise "File '#{@file}' already exists" if File.exist?(@file) && !overwrite
|
92
91
|
raise "Invalid network name '#{network}'" unless network =~ /^[a-z]{4,16}$/
|
93
|
-
|
92
|
+
FileUtils.mkdir_p(File.dirname(@file))
|
93
|
+
File.write(@file, "#{network}\n#{PROTOCOL}\n#{id}\n#{pubkey.to_pub}\n\n")
|
94
94
|
@txns.flush
|
95
95
|
@head.flush
|
96
96
|
end
|
@@ -187,7 +187,8 @@ module Zold
|
|
187
187
|
end
|
188
188
|
|
189
189
|
def refurbish
|
190
|
-
|
190
|
+
File.write(
|
191
|
+
@file,
|
191
192
|
"#{network}\n#{protocol}\n#{id}\n#{key.to_pub}\n\n#{txns.map { |t| t.to_s + "\n" }.join}"
|
192
193
|
)
|
193
194
|
@txns.flush
|
data/test/fake_home.rb
CHANGED
@@ -28,7 +28,6 @@ require_relative '../lib/zold/sync_wallets'
|
|
28
28
|
require_relative '../lib/zold/key'
|
29
29
|
require_relative '../lib/zold/version'
|
30
30
|
require_relative '../lib/zold/remotes'
|
31
|
-
require_relative '../lib/zold/atomic_file'
|
32
31
|
|
33
32
|
# Fake home dir.
|
34
33
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -74,7 +73,7 @@ class FakeHome
|
|
74
73
|
mtime: wallet.mtime.utc.iso8601,
|
75
74
|
digest: wallet.digest,
|
76
75
|
balance: wallet.balance.to_i,
|
77
|
-
body:
|
76
|
+
body: File.read(wallet.path)
|
78
77
|
}.to_json
|
79
78
|
end
|
80
79
|
end
|
data/test/node/test_front.rb
CHANGED
@@ -61,7 +61,8 @@ class FrontTest < Minitest::Test
|
|
61
61
|
'/farm',
|
62
62
|
'/metronome',
|
63
63
|
'/score',
|
64
|
-
'/trace'
|
64
|
+
'/trace',
|
65
|
+
'/threads'
|
65
66
|
],
|
66
67
|
'404' => [
|
67
68
|
'/this-is-absent',
|
@@ -121,6 +122,27 @@ class FrontTest < Minitest::Test
|
|
121
122
|
end
|
122
123
|
end
|
123
124
|
|
125
|
+
def test_fetch_in_multiple_threads
|
126
|
+
FakeNode.new(log: test_log).run(['--no-metronome']) do |port|
|
127
|
+
FakeHome.new.run do |home|
|
128
|
+
wallet = home.create_wallet
|
129
|
+
base = "http://localhost:#{port}"
|
130
|
+
Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}", score: nil).put(File.read(wallet.path))
|
131
|
+
assert_equal_wait('200') { Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}", score: nil).get.code }
|
132
|
+
threads = []
|
133
|
+
mutex = Mutex.new
|
134
|
+
assert_in_threads(loops: 100) do
|
135
|
+
assert_equal_wait('200') do
|
136
|
+
res = Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}", score: nil).get
|
137
|
+
mutex.synchronize { threads << res.header['X-Zold-Thread'] }
|
138
|
+
res.code
|
139
|
+
end
|
140
|
+
end
|
141
|
+
assert(threads.uniq.count > 1)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
124
146
|
def test_pushes_twice
|
125
147
|
FakeNode.new(log: test_log).run do |port|
|
126
148
|
FakeHome.new.run do |home|
|
@@ -221,26 +243,12 @@ class FrontTest < Minitest::Test
|
|
221
243
|
Time.stub :now, Time.at(0) do
|
222
244
|
FakeNode.new(log: test_log).run(['--ignore-score-weakness']) do |port|
|
223
245
|
response = Zold::Http.new(uri: URI("http://localhost:#{port}/"), score: nil).get
|
224
|
-
assert_equal(
|
225
|
-
|
226
|
-
|
227
|
-
)
|
228
|
-
assert_equal(
|
229
|
-
|
230
|
-
response.header['Connection']
|
231
|
-
)
|
232
|
-
assert_equal(
|
233
|
-
app.settings.version,
|
234
|
-
response.header['X-Zold-Version']
|
235
|
-
)
|
236
|
-
assert_equal(
|
237
|
-
app.settings.protocol.to_s,
|
238
|
-
response.header[Zold::Http::PROTOCOL_HEADER]
|
239
|
-
)
|
240
|
-
assert_equal(
|
241
|
-
'*',
|
242
|
-
response.header['Access-Control-Allow-Origin']
|
243
|
-
)
|
246
|
+
assert_equal('no-cache', response.header['Cache-Control'])
|
247
|
+
assert_equal('close', response.header['Connection'])
|
248
|
+
assert_equal(app.settings.version, response.header['X-Zold-Version'])
|
249
|
+
assert_equal(app.settings.protocol.to_s, response.header[Zold::Http::PROTOCOL_HEADER])
|
250
|
+
assert_equal('*', response.header['Access-Control-Allow-Origin'])
|
251
|
+
assert(response.header['X-Zold-Milliseconds'])
|
244
252
|
assert(!response.header[Zold::Http::SCORE_HEADER].nil?)
|
245
253
|
end
|
246
254
|
end
|
data/test/test_zold.rb
CHANGED
@@ -34,7 +34,7 @@ require_relative '../lib/zold/version'
|
|
34
34
|
class TestZold < Minitest::Test
|
35
35
|
def test_all_scripts
|
36
36
|
Dir.new('fixtures/scripts').select { |f| f =~ /\.sh$/ && !f.start_with?('_') }.each do |f|
|
37
|
-
# next unless f == '
|
37
|
+
# next unless f == 'deadlocks.sh'
|
38
38
|
Dir.mktmpdir do |dir|
|
39
39
|
FileUtils.cp('fixtures/id_rsa.pub', dir)
|
40
40
|
FileUtils.cp('fixtures/id_rsa', dir)
|
data/zold.gemspec
CHANGED
@@ -65,6 +65,7 @@ and suggests a different architecture for digital wallet maintenance.'
|
|
65
65
|
s.add_runtime_dependency 'json', '~>1.8'
|
66
66
|
s.add_runtime_dependency 'moneta', '~>1.0'
|
67
67
|
s.add_runtime_dependency 'openssl', '~>2.1'
|
68
|
+
s.add_runtime_dependency 'puma'
|
68
69
|
s.add_runtime_dependency 'rainbow', '~>3.0'
|
69
70
|
s.add_runtime_dependency 'rake', '~>12.3' # has to stay here for Heroku
|
70
71
|
s.add_runtime_dependency 'rubocop', '0.58.1' # has to stay here for Heroku
|
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.
|
4
|
+
version: 0.14.53
|
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-10-
|
11
|
+
date: 2018-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: backtrace
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '2.1'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: puma
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
167
181
|
- !ruby/object:Gem::Dependency
|
168
182
|
name: rainbow
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -488,7 +502,6 @@ files:
|
|
488
502
|
- lib/zold.rb
|
489
503
|
- lib/zold/age.rb
|
490
504
|
- lib/zold/amount.rb
|
491
|
-
- lib/zold/atomic_file.rb
|
492
505
|
- lib/zold/cached_wallets.rb
|
493
506
|
- lib/zold/commands/alias.rb
|
494
507
|
- lib/zold/commands/args.rb
|
@@ -587,7 +600,6 @@ files:
|
|
587
600
|
- test/test__helper.rb
|
588
601
|
- test/test_age.rb
|
589
602
|
- test/test_amount.rb
|
590
|
-
- test/test_atomic_file.rb
|
591
603
|
- test/test_cached_wallets.rb
|
592
604
|
- test/test_copies.rb
|
593
605
|
- test/test_gem.rb
|
@@ -684,7 +696,6 @@ test_files:
|
|
684
696
|
- test/test__helper.rb
|
685
697
|
- test/test_age.rb
|
686
698
|
- test/test_amount.rb
|
687
|
-
- test/test_atomic_file.rb
|
688
699
|
- test/test_cached_wallets.rb
|
689
700
|
- test/test_copies.rb
|
690
701
|
- test/test_gem.rb
|
data/lib/zold/atomic_file.rb
DELETED
@@ -1,52 +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
|
-
# Atomic file.
|
24
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
25
|
-
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
26
|
-
# License:: MIT
|
27
|
-
module Zold
|
28
|
-
# Atomic file
|
29
|
-
class AtomicFile
|
30
|
-
def initialize(file)
|
31
|
-
raise 'File can\'t be nil' if file.nil?
|
32
|
-
@file = file
|
33
|
-
@mutex = Mutex.new
|
34
|
-
end
|
35
|
-
|
36
|
-
def read
|
37
|
-
@mutex.synchronize do
|
38
|
-
File.open(@file, 'rb', &:read)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def write(content)
|
43
|
-
raise 'Content can\'t be nil' if content.nil?
|
44
|
-
FileUtils.mkdir_p(File.dirname(@file))
|
45
|
-
@mutex.synchronize do
|
46
|
-
File.open(@file, 'wb') do |f|
|
47
|
-
f.write(content)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/test/test_atomic_file.rb
DELETED
@@ -1,55 +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 'tmpdir'
|
25
|
-
require 'securerandom'
|
26
|
-
require_relative 'test__helper'
|
27
|
-
require_relative '../lib/zold/atomic_file'
|
28
|
-
require_relative '../lib/zold/verbose_thread'
|
29
|
-
|
30
|
-
# AtomicFile test.
|
31
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
32
|
-
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
33
|
-
# License:: MIT
|
34
|
-
class TestAtomicFile < Minitest::Test
|
35
|
-
def test_writes_and_reads
|
36
|
-
Dir.mktmpdir do |dir|
|
37
|
-
file = Zold::AtomicFile.new(File.join(dir, 'test.txt'))
|
38
|
-
['', 'hello, dude!'].each do |t|
|
39
|
-
file.write(t)
|
40
|
-
assert_equal(t, file.read)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_writes_from_many_threads
|
46
|
-
Dir.mktmpdir do |dir|
|
47
|
-
file = Zold::AtomicFile.new(File.join(dir, 'a.txt'))
|
48
|
-
content = SecureRandom.hex(1000)
|
49
|
-
assert_in_threads(loops: 1000) do
|
50
|
-
file.write(content)
|
51
|
-
assert_equal(content, file.read, 'Invalid content')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|