zold 0.26.15 → 0.26.16
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/.rubocop.yml +1 -1
- data/lib/zold/commands/fetch.rb +1 -1
- data/lib/zold/commands/node.rb +21 -8
- data/lib/zold/commands/push.rb +3 -5
- data/lib/zold/commands/remote.rb +3 -3
- data/lib/zold/hungry_wallets.rb +5 -4
- data/lib/zold/log.rb +31 -0
- data/lib/zold/node/front.rb +58 -1
- data/lib/zold/node/journaled_entrance.rb +96 -0
- data/lib/zold/patch.rb +1 -1
- data/lib/zold/txn.rb +1 -1
- data/lib/zold/version.rb +1 -1
- data/test/commands/test_merge.rb +0 -21
- data/test/node/test_front.rb +31 -32
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7b0ae546cf6416b998bfd75490dae5b662d89c3e6e598958f1c73c86e51fda17
|
|
4
|
+
data.tar.gz: bcc69294f383f7832b3ac832742c89630eb7d8a880741aefd7c0397a88cb9042
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f746fba3dad2802bce2170facba75809d44fee26f29cf61a95c1c74245c61668f1fd75fed47722ab50bfc7676093b287b16e4e1683b280f99fd18715321e8574
|
|
7
|
+
data.tar.gz: fe15c859e3ff938901b7ef369e80346dc005be4451e4c2abd2cd45bd778b0b5b8939c3d0201ae78e4802c8d3aec6475779d94ab96a12857eec61e3e8d9476a7b
|
data/.rubocop.yml
CHANGED
data/lib/zold/commands/fetch.rb
CHANGED
|
@@ -171,7 +171,7 @@ run 'zold remote update' or use --tolerate-quorum=1"
|
|
|
171
171
|
raise "The balance of #{id} is #{wallet.balance} and it's not a root wallet"
|
|
172
172
|
end
|
|
173
173
|
copy = cps.add(IO.read(f), score.host, score.port, score.value, master: r.master?)
|
|
174
|
-
@log.
|
|
174
|
+
@log.debug("#{r} returned #{wallet.mnemo} #{Age.new(json['mtime'])}/#{json['copies']}c \
|
|
175
175
|
as copy ##{copy}/#{cps.all.count} in #{Age.new(start, limit: 4)}: \
|
|
176
176
|
#{Rainbow(score.value).green} (#{json['version']})")
|
|
177
177
|
end
|
data/lib/zold/commands/node.rb
CHANGED
|
@@ -45,6 +45,7 @@ require_relative '../node/async_entrance'
|
|
|
45
45
|
require_relative '../node/sync_entrance'
|
|
46
46
|
require_relative '../node/nodup_entrance'
|
|
47
47
|
require_relative '../node/nospam_entrance'
|
|
48
|
+
require_relative '../node/journaled_entrance'
|
|
48
49
|
require_relative '../node/front'
|
|
49
50
|
require_relative '../node/trace'
|
|
50
51
|
require_relative '../node/farm'
|
|
@@ -235,10 +236,10 @@ the node won\'t connect to the network like that; try to do "zold remote reset"
|
|
|
235
236
|
#{@remotes.all.map { |r| "#{r[:host]}:#{r[:port]}" }.join(', ')}")
|
|
236
237
|
@log.info("Wallets at: #{@wallets.path}")
|
|
237
238
|
if opts['standalone']
|
|
238
|
-
@remotes =
|
|
239
|
+
@remotes = Remotes::Empty.new
|
|
239
240
|
@log.info('Running in standalone mode! (will never talk to other remotes)')
|
|
240
241
|
elsif @remotes.exists?(host, port)
|
|
241
|
-
|
|
242
|
+
Remote.new(remotes: @remotes).run(['remote', 'remove', host, port.to_s])
|
|
242
243
|
@log.info("Removed current node (#{address}) from list of remotes")
|
|
243
244
|
end
|
|
244
245
|
if File.exist?(@copies)
|
|
@@ -249,8 +250,8 @@ the node won\'t connect to the network like that; try to do "zold remote reset"
|
|
|
249
250
|
if opts['not-hungry']
|
|
250
251
|
@log.info('Hungry pulling disabled because of --not-hungry')
|
|
251
252
|
else
|
|
252
|
-
hungry =
|
|
253
|
-
wts =
|
|
253
|
+
hungry = ThreadPool.new('hungry', log: @log)
|
|
254
|
+
wts = HungryWallets.new(@wallets, @remotes, @copies, hungry, log: @log, network: opts['network'])
|
|
254
255
|
end
|
|
255
256
|
Front.set(:zache, Zache.new(dirty: true))
|
|
256
257
|
Front.set(:wallets, wts)
|
|
@@ -266,17 +267,29 @@ the node won\'t connect to the network like that; try to do "zold remote reset"
|
|
|
266
267
|
async_dir = File.join(home, '.zoldata/async-entrance')
|
|
267
268
|
FileUtils.mkdir_p(async_dir)
|
|
268
269
|
Front.set(:async_dir, async_dir)
|
|
270
|
+
journal_dir = File.join(home, '.zoldata/journal')
|
|
271
|
+
FileUtils.mkdir_p(journal_dir)
|
|
272
|
+
Front.set(:journal_dir, journal_dir)
|
|
269
273
|
Front.set(:node_alias, node_alias(opts, address))
|
|
274
|
+
jlog = Logger.new(File.join(journal_dir, 'journal'))
|
|
275
|
+
jlog.level = Logger::DEBUG
|
|
276
|
+
jlog.formatter = Log::COMPACT
|
|
270
277
|
entrance = SafeEntrance.new(
|
|
271
278
|
NoSpamEntrance.new(
|
|
272
279
|
NoDupEntrance.new(
|
|
273
280
|
AsyncEntrance.new(
|
|
274
281
|
SpreadEntrance.new(
|
|
275
282
|
SyncEntrance.new(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
283
|
+
JournaledEntrance.new(
|
|
284
|
+
Entrance.new(
|
|
285
|
+
wts, @remotes, @copies, address,
|
|
286
|
+
ledger: ledger,
|
|
287
|
+
log: Log::Tee.new(@log, jlog), network: opts['network']
|
|
288
|
+
),
|
|
289
|
+
wts,
|
|
290
|
+
journal_dir,
|
|
291
|
+
jlog,
|
|
292
|
+
'journal'
|
|
280
293
|
),
|
|
281
294
|
File.join(home, '.zoldata/sync-entrance'),
|
|
282
295
|
log: @log
|
data/lib/zold/commands/push.rb
CHANGED
|
@@ -135,10 +135,8 @@ out of #{nodes.value} in #{Age.new(start)}, total score for #{id} is #{total.val
|
|
|
135
135
|
r.assert_valid_score(score)
|
|
136
136
|
r.assert_score_ownership(score)
|
|
137
137
|
r.assert_score_strength(score) unless opts['ignore-score-weakness']
|
|
138
|
-
|
|
139
|
-
@log.info("#{r} accepted #{@wallets.acq(id, &:mnemo)} in #{Age.new(start, limit: 4)}: \
|
|
138
|
+
@log.debug("#{r} accepted #{@wallets.acq(id, &:mnemo)} in #{Age.new(start, limit: 4)}: \
|
|
140
139
|
#{Rainbow(score.value).green} (#{json['version']})")
|
|
141
|
-
end
|
|
142
140
|
score.value
|
|
143
141
|
end
|
|
144
142
|
end
|
|
@@ -153,7 +151,7 @@ out of #{nodes.value} in #{Age.new(start)}, total score for #{id} is #{total.val
|
|
|
153
151
|
r.http(uri).put(f)
|
|
154
152
|
end
|
|
155
153
|
if response.status == 304
|
|
156
|
-
@log.
|
|
154
|
+
@log.debug("#{r}: same version of #{@wallets.acq(id, &:mnemo)} there, didn't push \
|
|
157
155
|
in #{Age.new(start, limit: 0.5)}")
|
|
158
156
|
return 0
|
|
159
157
|
end
|
|
@@ -164,7 +162,7 @@ in #{Age.new(start, limit: 0.5)}")
|
|
|
164
162
|
rescue JsonPage::CantParse, Score::CantParse, RemoteNode::CantAssert => e
|
|
165
163
|
attempt += 1
|
|
166
164
|
if attempt < opts['retry']
|
|
167
|
-
@log.
|
|
165
|
+
@log.debug("#{r} failed to push #{id}, trying again (attempt no.#{attempt}): #{e.message}")
|
|
168
166
|
retry
|
|
169
167
|
end
|
|
170
168
|
raise e
|
data/lib/zold/commands/remote.rb
CHANGED
|
@@ -316,7 +316,7 @@ Available options:"
|
|
|
316
316
|
rescue JsonPage::CantParse, Score::CantParse, RemoteNode::CantAssert => e
|
|
317
317
|
attempt += 1
|
|
318
318
|
if attempt < opts['retry']
|
|
319
|
-
@log.
|
|
319
|
+
@log.debug("#{r} failed to read, trying again (attempt no.#{attempt}): #{e.message}")
|
|
320
320
|
retry
|
|
321
321
|
end
|
|
322
322
|
raise e
|
|
@@ -354,7 +354,7 @@ it's recommended to reboot, but I don't do it because of --never-reboot")
|
|
|
354
354
|
@remotes.remove(r[:host], r[:port])
|
|
355
355
|
@log.debug("Remote #{r[:host]}:#{r[:port]}/#{r[:score]}/#{r[:errors]}e removed from the list")
|
|
356
356
|
end
|
|
357
|
-
@log.info("#{@remotes.all.count} remote nodes were selected to stay in the list")
|
|
357
|
+
@log.info("#{@remotes.all.count} best remote nodes were selected to stay in the list")
|
|
358
358
|
end
|
|
359
359
|
|
|
360
360
|
def terminate
|
|
@@ -368,7 +368,7 @@ it's recommended to reboot, but I don't do it because of --never-reboot")
|
|
|
368
368
|
res = Http.new(uri: "http://#{host}:#{port}/version", network: opts['network']).get
|
|
369
369
|
return true if res.status == 200
|
|
370
370
|
raise "The node #{host}:#{port} is not responding, #{res.status}:#{res.status_line}" unless opts['ignore-ping']
|
|
371
|
-
@log.error("The node #{host}:#{port} is not responding, #{res.status}:#{res.status_line}")
|
|
371
|
+
@log.error("The node #{host}:#{port} is not responding but we --ignore-ping, #{res.status}:#{res.status_line}")
|
|
372
372
|
false
|
|
373
373
|
end
|
|
374
374
|
end
|
data/lib/zold/hungry_wallets.rb
CHANGED
|
@@ -57,12 +57,13 @@ module Zold
|
|
|
57
57
|
unless wallet.exists?
|
|
58
58
|
if @queue.size > 256
|
|
59
59
|
@log.error("Hungry queue is full with #{@queue.size} wallets, can't add #{id}")
|
|
60
|
-
elsif @missed.exists?(id)
|
|
61
|
-
@log.
|
|
60
|
+
elsif @missed.exists?(id.to_s)
|
|
61
|
+
@log.debug("Hungry queue has seen #{id} just #{Age.new(@missed.mtime(id.to_s))} ago
|
|
62
|
+
(amoung #{@missed.size} others) and it was not found")
|
|
62
63
|
else
|
|
63
64
|
@mutex.synchronize do
|
|
64
65
|
unless @queue.include?(id)
|
|
65
|
-
@missed.put(id, lifetime: 5 * 60)
|
|
66
|
+
@missed.put(id.to_s, lifetime: 5 * 60)
|
|
66
67
|
@queue << id
|
|
67
68
|
@log.debug("Hungry queue got #{id}, at the pos no.#{@queue.size - 1}")
|
|
68
69
|
end
|
|
@@ -85,7 +86,7 @@ module Zold
|
|
|
85
86
|
Pull.new(wallets: @wallets, remotes: @remotes, copies: @copies, log: @log).run(
|
|
86
87
|
['pull', id.to_s, "--network=#{@network}", '--tolerate-edges', '--tolerate-quorum=1']
|
|
87
88
|
)
|
|
88
|
-
@missed.remove(id)
|
|
89
|
+
@missed.remove(id.to_s)
|
|
89
90
|
rescue Fetch::Error => e
|
|
90
91
|
@log.error("Can't hungry-pull #{id}: #{e.message}")
|
|
91
92
|
end
|
data/lib/zold/log.rb
CHANGED
|
@@ -104,5 +104,36 @@ module Zold
|
|
|
104
104
|
ERRORS.level = Logger::ERROR
|
|
105
105
|
ERRORS.formatter = COMPACT
|
|
106
106
|
ERRORS.freeze
|
|
107
|
+
|
|
108
|
+
# Tee logger.
|
|
109
|
+
class Tee
|
|
110
|
+
def initialize(first, second)
|
|
111
|
+
@first = first
|
|
112
|
+
@second = second
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def debug(msg)
|
|
116
|
+
@first.debug(msg)
|
|
117
|
+
@second.debug(msg)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def debug?
|
|
121
|
+
@first.debug? || @second.debug?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def info(msg)
|
|
125
|
+
@first.info(msg)
|
|
126
|
+
@second.info(msg)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def info?
|
|
130
|
+
@first.info? || @second.info?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def error(msg)
|
|
134
|
+
@first.error(msg)
|
|
135
|
+
@second.error(msg)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
107
138
|
end
|
|
108
139
|
end
|
data/lib/zold/node/front.rb
CHANGED
|
@@ -82,6 +82,7 @@ module Zold
|
|
|
82
82
|
set :node_alias, nil # to be injected at node.rb
|
|
83
83
|
set :zache, nil # to be injected at node.rb
|
|
84
84
|
set :async_dir, nil # to be injected at node.rb
|
|
85
|
+
set :journal_dir, nil # to be injected at node.rb
|
|
85
86
|
end
|
|
86
87
|
use Rack::Deflater
|
|
87
88
|
|
|
@@ -136,7 +137,7 @@ while #{settings.address} is in '#{settings.opts['network']}'")
|
|
|
136
137
|
headers['X-Zold-Thread'] = Thread.current.object_id.to_s
|
|
137
138
|
unless @start.nil?
|
|
138
139
|
if Time.now - @start > 1
|
|
139
|
-
settings.log.
|
|
140
|
+
settings.log.debug("Slow response to #{request.request_method} #{request.url} \
|
|
140
141
|
from #{request.ip} in #{Age.new(@start, limit: 1)}")
|
|
141
142
|
end
|
|
142
143
|
headers['X-Zold-Milliseconds'] = ((Time.now - @start) * 1000).round.to_s
|
|
@@ -317,6 +318,43 @@ this is not a normal behavior, you may want to report a bug to our GitHub reposi
|
|
|
317
318
|
end
|
|
318
319
|
end
|
|
319
320
|
|
|
321
|
+
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})\.html} do
|
|
322
|
+
fetch do |wallet|
|
|
323
|
+
[
|
|
324
|
+
'<!DOCTYPE html><html><head>',
|
|
325
|
+
'<title>' + wallet.id.to_s + '</title>',
|
|
326
|
+
'<link href="https://cdn.jsdelivr.net/gh/yegor256/tacit@gh-pages/tacit-css-1.4.2.min.css" rel="stylesheet"/>',
|
|
327
|
+
'<style>table { width: 100%; } td, th { padding: 0.2em .4em }</style>',
|
|
328
|
+
'</head><body><section>',
|
|
329
|
+
"<p>#{wallet.network}<br/>",
|
|
330
|
+
"#{wallet.protocol}<br/>",
|
|
331
|
+
"#{wallet.id}<br/>",
|
|
332
|
+
"#{wallet.key.to_pub}</p>",
|
|
333
|
+
'<table><thead><tr><th>Id</th><th>Date</th><th>Amount</th><th>Wallet</th><th>Details</th></thead>',
|
|
334
|
+
'<tbody>',
|
|
335
|
+
wallet.txns.map do |t|
|
|
336
|
+
[
|
|
337
|
+
'<tr>',
|
|
338
|
+
'<td style="color:' + (t.amount.negative? ? 'red' : 'green') + "\">#{t.id}</td>",
|
|
339
|
+
"<td>#{t.date.utc.iso8601}</td>",
|
|
340
|
+
'<td style="text-align:right">' + t.amount.to_zld(4) + '</td>',
|
|
341
|
+
"<td><a href='/wallet/#{t.bnf}.html'>#{t.bnf}</td>",
|
|
342
|
+
"<td>#{t.details}</td>",
|
|
343
|
+
'</tr>'
|
|
344
|
+
].join
|
|
345
|
+
end.join,
|
|
346
|
+
'<p>—<br/>',
|
|
347
|
+
"Balance: #{wallet.balance.to_zld(8)} ZLD (#{wallet.balance.to_i} zents)<br/>",
|
|
348
|
+
"Transactions: #{wallet.txns.count}<br/>",
|
|
349
|
+
"Taxes: #{Tax.new(wallet).paid} paid, the debt is #{Tax.new(wallet).debt}<br/>",
|
|
350
|
+
"File size: #{Size.new(wallet.size)}/#{wallet.size}, \
|
|
351
|
+
#{Copies.new(File.join(settings.copies, wallet.id)).all.count} copies<br/>",
|
|
352
|
+
"Modified: #{wallet.mtime.utc.iso8601} (#{Age.new(wallet.mtime.utc.iso8601)} ago)<br/>",
|
|
353
|
+
"Digest: #{wallet.digest}</p></section></body></html>"
|
|
354
|
+
].join
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
320
358
|
get %r{/wallet/(?<id>[A-Fa-f0-9]{16})\.bin} do
|
|
321
359
|
fetch { |w| send_file(w.path) }
|
|
322
360
|
end
|
|
@@ -442,6 +480,25 @@ this is not a normal behavior, you may want to report a bug to our GitHub reposi
|
|
|
442
480
|
end.join("\n")
|
|
443
481
|
end
|
|
444
482
|
|
|
483
|
+
get '/journal' do
|
|
484
|
+
content_type('text/html')
|
|
485
|
+
[
|
|
486
|
+
'<!DOCTYPE html><html><head>',
|
|
487
|
+
'<title>/journal</title>',
|
|
488
|
+
'<link href="https://cdn.jsdelivr.net/gh/yegor256/tacit@gh-pages/tacit-css-1.4.2.min.css" rel="stylesheet"/>',
|
|
489
|
+
'</head><body><section>',
|
|
490
|
+
DirItems.new(settings.journal_dir).fetch.sort.map do |f|
|
|
491
|
+
"<p><a href='/journal/item?id=#{f}'>#{f}</a></p>"
|
|
492
|
+
end.join,
|
|
493
|
+
'</section></body></html>'
|
|
494
|
+
].join
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
get '/journal/item' do
|
|
498
|
+
content_type('text/plain')
|
|
499
|
+
IO.read(File.join(settings.journal_dir, params[:id]))
|
|
500
|
+
end
|
|
501
|
+
|
|
445
502
|
not_found do
|
|
446
503
|
status(404)
|
|
447
504
|
content_type('text/plain')
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2018-2019 Zerocracy, Inc.
|
|
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 '../remotes'
|
|
26
|
+
require_relative '../copies'
|
|
27
|
+
require_relative '../tax'
|
|
28
|
+
require_relative '../age'
|
|
29
|
+
require_relative '../commands/clean'
|
|
30
|
+
require_relative '../commands/merge'
|
|
31
|
+
require_relative '../commands/fetch'
|
|
32
|
+
require_relative '../commands/push'
|
|
33
|
+
|
|
34
|
+
# The entrance with journals.
|
|
35
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
36
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
|
37
|
+
# License:: MIT
|
|
38
|
+
module Zold
|
|
39
|
+
# The entrance that keeps a journal for each wallet
|
|
40
|
+
class JournaledEntrance
|
|
41
|
+
# Decorated wallets
|
|
42
|
+
class Wallets < SimpleDelegator
|
|
43
|
+
def initialize(wallets, log)
|
|
44
|
+
@wallets = wallets
|
|
45
|
+
@log = log
|
|
46
|
+
super(wallets)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def acq(id, exclusive: false)
|
|
50
|
+
@wallets.acq(id, exclusive: exclusive) do |wallet|
|
|
51
|
+
return yield wallet unless exclusive
|
|
52
|
+
before = wallet.exists? ? IO.read(wallet.path) : ''
|
|
53
|
+
res = yield wallet
|
|
54
|
+
after = wallet.exists? ? IO.read(wallet.path) : ''
|
|
55
|
+
unless before == after
|
|
56
|
+
diff = Diffy::Diff.new(before, after, context: 0).to_s
|
|
57
|
+
@log.info("The wallet #{id} was modified:\n #{diff.gsub("\n", "\n ")}")
|
|
58
|
+
end
|
|
59
|
+
res
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def initialize(entrance, wallets, dir, log, journal)
|
|
65
|
+
@wallets = JournaledEntrance::Wallets.new(wallets, log)
|
|
66
|
+
@entrance = entrance
|
|
67
|
+
@dir = File.expand_path(dir)
|
|
68
|
+
@log = log
|
|
69
|
+
@journal = File.join(@dir, journal)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def start
|
|
73
|
+
raise 'Block must be given to start()' unless block_given?
|
|
74
|
+
FileUtils.mkdir_p(@dir)
|
|
75
|
+
yield(self)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def to_json
|
|
79
|
+
@entrance.to_json.merge(
|
|
80
|
+
'dir': @dir
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Returns a list of modifed wallets (as Zold::Id)
|
|
85
|
+
def push(id, body)
|
|
86
|
+
DirItems.new(@dir).fetch.each do |f|
|
|
87
|
+
f = File.join(@dir, f)
|
|
88
|
+
File.delete(f) if File.mtime(f) < Time.now - 24 * 60 * 60
|
|
89
|
+
end
|
|
90
|
+
@log.info("push(#{id}, #{body.length} bytes)")
|
|
91
|
+
modified = @entrance.push(id, body)
|
|
92
|
+
IO.write(File.join(@dir, "#{Time.now.utc.iso8601.gsub(/[^0-9]/, '-')}-#{id}"), IO.read(@journal))
|
|
93
|
+
modified
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/zold/patch.rb
CHANGED
|
@@ -172,7 +172,7 @@ doesn't have this transaction: \"#{txn.to_text}\"")
|
|
|
172
172
|
end
|
|
173
173
|
temp.refurbish
|
|
174
174
|
if temp.balance.negative? && !temp.id.root? && !allow_negative_balance
|
|
175
|
-
@log.info("The balance is negative, won't merge
|
|
175
|
+
@log.info("The balance is negative, won't merge #{temp.mnemo} on top of #{wallet.mnemo}")
|
|
176
176
|
else
|
|
177
177
|
FileUtils.mkdir_p(File.dirname(file))
|
|
178
178
|
IO.write(file, IO.read(f.path))
|
data/lib/zold/txn.rb
CHANGED
data/lib/zold/version.rb
CHANGED
data/test/commands/test_merge.rb
CHANGED
|
@@ -63,27 +63,6 @@ class TestMerge < Zold::Test
|
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
def test_merges_into_empty_wallet
|
|
67
|
-
FakeHome.new(log: test_log).run do |home|
|
|
68
|
-
wallet = home.create_wallet
|
|
69
|
-
first = home.create_wallet
|
|
70
|
-
IO.write(first.path, IO.read(wallet.path))
|
|
71
|
-
second = home.create_wallet
|
|
72
|
-
IO.write(second.path, IO.read(wallet.path))
|
|
73
|
-
Zold::Pay.new(wallets: home.wallets, copies: home.dir, remotes: home.remotes, log: test_log).run(
|
|
74
|
-
['pay', wallet.id.to_s, "NOPREFIX@#{Zold::Id.new}", '14.95', '--force', '--private-key=fixtures/id_rsa']
|
|
75
|
-
)
|
|
76
|
-
copies = home.copies(wallet)
|
|
77
|
-
copies.add(IO.read(first.path), 'host-1', 80, 5)
|
|
78
|
-
copies.add(IO.read(second.path), 'host-2', 80, 5)
|
|
79
|
-
modified = Zold::Merge.new(wallets: home.wallets, remotes: home.remotes, copies: copies.root, log: test_log).run(
|
|
80
|
-
['merge', wallet.id.to_s]
|
|
81
|
-
)
|
|
82
|
-
assert(1, modified.count)
|
|
83
|
-
assert(wallet.id, modified[0])
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
66
|
def test_merges_with_a_broken_copy
|
|
88
67
|
FakeHome.new(log: test_log).run do |home|
|
|
89
68
|
wallet = home.create_wallet
|
data/test/node/test_front.rb
CHANGED
|
@@ -45,7 +45,7 @@ class FrontTest < Zold::Test
|
|
|
45
45
|
def test_memory_leakage
|
|
46
46
|
skip
|
|
47
47
|
report = MemoryProfiler.report(top: 10) do
|
|
48
|
-
FakeNode.new(log: test_log).run(
|
|
48
|
+
FakeNode.new(log: test_log).run(opts('--network=foo')) do |port|
|
|
49
49
|
100.times do
|
|
50
50
|
Zold::Http.new(uri: "http://localhost:#{port}/", network: 'foo').get
|
|
51
51
|
end
|
|
@@ -55,7 +55,7 @@ class FrontTest < Zold::Test
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def test_renders_front_json
|
|
58
|
-
FakeNode.new(log: test_log).run(
|
|
58
|
+
FakeNode.new(log: test_log).run(opts('--network=foo')) do |port|
|
|
59
59
|
res = Zold::Http.new(uri: "http://localhost:#{port}/", network: 'foo').get
|
|
60
60
|
json = JSON.parse(res.body)
|
|
61
61
|
assert_equal(Zold::VERSION, json['version'])
|
|
@@ -73,7 +73,7 @@ class FrontTest < Zold::Test
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def test_renders_public_pages
|
|
76
|
-
FakeNode.new(log: test_log).run(
|
|
76
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
77
77
|
{
|
|
78
78
|
200 => [
|
|
79
79
|
'/robots.txt',
|
|
@@ -85,6 +85,7 @@ class FrontTest < Zold::Test
|
|
|
85
85
|
'/ledger',
|
|
86
86
|
'/ledger.json',
|
|
87
87
|
'/metronome',
|
|
88
|
+
'/journal',
|
|
88
89
|
'/score',
|
|
89
90
|
'/queue',
|
|
90
91
|
'/trace',
|
|
@@ -115,7 +116,7 @@ class FrontTest < Zold::Test
|
|
|
115
116
|
end
|
|
116
117
|
|
|
117
118
|
def test_updates_list_of_remotes
|
|
118
|
-
FakeNode.new(log: test_log).run(['--
|
|
119
|
+
FakeNode.new(log: test_log).run(['--no-metronome', '--ignore-score-weakness', '--no-cache']) do |port|
|
|
119
120
|
(Zold::Remotes::MAX_NODES + 5).times do |i|
|
|
120
121
|
score = Zold::Score.new(
|
|
121
122
|
host: 'localhost', port: i + 1, invoice: 'NOPREFIX@ffffffffffffffff', strength: 1
|
|
@@ -136,7 +137,7 @@ class FrontTest < Zold::Test
|
|
|
136
137
|
end
|
|
137
138
|
|
|
138
139
|
def test_increments_score
|
|
139
|
-
FakeNode.new(log: test_log).run(
|
|
140
|
+
FakeNode.new(log: test_log).run(opts('--threads=1')) do |port|
|
|
140
141
|
3.times do |i|
|
|
141
142
|
assert_equal_wait(true) do
|
|
142
143
|
response = Zold::Http.new(uri: "http://localhost:#{port}/").get
|
|
@@ -150,28 +151,20 @@ class FrontTest < Zold::Test
|
|
|
150
151
|
|
|
151
152
|
def test_renders_wallet_pages
|
|
152
153
|
FakeHome.new(log: test_log).run do |home|
|
|
153
|
-
FakeNode.new(log: test_log).run(
|
|
154
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
154
155
|
wallet = home.create_wallet(txns: 2)
|
|
155
156
|
base = "http://localhost:#{port}"
|
|
156
157
|
response = Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}").put(wallet.path)
|
|
157
158
|
assert_equal(200, response.status, response.body)
|
|
158
159
|
assert_equal_wait(200) { Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}").get.status }
|
|
159
160
|
[
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"/wallet/#{wallet.id}/size",
|
|
166
|
-
"/wallet/#{wallet.id}/age",
|
|
167
|
-
"/wallet/#{wallet.id}/mnemo",
|
|
168
|
-
"/wallet/#{wallet.id}/debt",
|
|
169
|
-
"/wallet/#{wallet.id}/txns",
|
|
170
|
-
"/wallet/#{wallet.id}/txns.json",
|
|
171
|
-
"/wallet/#{wallet.id}.bin",
|
|
172
|
-
"/wallet/#{wallet.id}/copies"
|
|
161
|
+
'.txt', '.html',
|
|
162
|
+
'/balance', '/key', '/mtime',
|
|
163
|
+
'/digest', '/size',
|
|
164
|
+
'/age', '/mnemo', '/debt', '/txns',
|
|
165
|
+
'/txns.json', '.bin', '/copies'
|
|
173
166
|
].each do |u|
|
|
174
|
-
assert_equal_wait(200) { Zold::Http.new(uri: "#{base}#{u}").get.status }
|
|
167
|
+
assert_equal_wait(200) { Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}#{u}").get.status }
|
|
175
168
|
end
|
|
176
169
|
end
|
|
177
170
|
end
|
|
@@ -179,7 +172,7 @@ class FrontTest < Zold::Test
|
|
|
179
172
|
|
|
180
173
|
def test_renders_wallets_page
|
|
181
174
|
FakeHome.new(log: test_log).run do |home|
|
|
182
|
-
FakeNode.new(log: test_log).run(
|
|
175
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
183
176
|
wallet = home.create_wallet(txns: 2)
|
|
184
177
|
base = "http://localhost:#{port}"
|
|
185
178
|
response = Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}").put(wallet.path)
|
|
@@ -193,7 +186,7 @@ class FrontTest < Zold::Test
|
|
|
193
186
|
end
|
|
194
187
|
|
|
195
188
|
def test_fetch_in_multiple_threads
|
|
196
|
-
FakeNode.new(log: test_log).run(
|
|
189
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
197
190
|
FakeHome.new(log: test_log).run do |home|
|
|
198
191
|
wallet = home.create_wallet
|
|
199
192
|
base = "http://localhost:#{port}"
|
|
@@ -214,7 +207,7 @@ class FrontTest < Zold::Test
|
|
|
214
207
|
end
|
|
215
208
|
|
|
216
209
|
def test_pushes_twice
|
|
217
|
-
FakeNode.new(log: test_log).run(
|
|
210
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
218
211
|
FakeHome.new(log: test_log).run do |home|
|
|
219
212
|
wallet = home.create_wallet
|
|
220
213
|
base = "http://localhost:#{port}"
|
|
@@ -232,7 +225,7 @@ class FrontTest < Zold::Test
|
|
|
232
225
|
end
|
|
233
226
|
|
|
234
227
|
def test_pushes_many_wallets
|
|
235
|
-
FakeNode.new(log: test_log).run(
|
|
228
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
236
229
|
base = "http://localhost:#{port}"
|
|
237
230
|
FakeHome.new(log: test_log).run do |home|
|
|
238
231
|
Threads.new(5).assert do
|
|
@@ -278,7 +271,7 @@ class FrontTest < Zold::Test
|
|
|
278
271
|
end
|
|
279
272
|
|
|
280
273
|
def test_gzip
|
|
281
|
-
FakeNode.new(log: test_log).run(
|
|
274
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
282
275
|
response = Zold::Http.new(uri: URI("http://localhost:#{port}/version")).get
|
|
283
276
|
assert_equal(200, response.status, response)
|
|
284
277
|
assert_operator(300, :>, response.body.length.to_i, 'Expected the content to be small')
|
|
@@ -287,7 +280,7 @@ class FrontTest < Zold::Test
|
|
|
287
280
|
|
|
288
281
|
def test_performance
|
|
289
282
|
times = Queue.new
|
|
290
|
-
FakeNode.new(log: test_log).run(
|
|
283
|
+
FakeNode.new(log: test_log).run(opts('--threads=4', '--strength=6')) do |port|
|
|
291
284
|
Threads.new(10).assert(100) do
|
|
292
285
|
start = Time.now
|
|
293
286
|
Zold::Http.new(uri: URI("http://localhost:#{port}/")).get
|
|
@@ -304,7 +297,7 @@ class FrontTest < Zold::Test
|
|
|
304
297
|
# HTTP request. This value is enough to identify a valueable node, and filter
|
|
305
298
|
# out those that are too weak.
|
|
306
299
|
def test_score_is_reduced
|
|
307
|
-
FakeNode.new(log: test_log).run(
|
|
300
|
+
FakeNode.new(log: test_log).run(opts('--threads=1', '--strength=1', '--farmer=plain')) do |port|
|
|
308
301
|
scores = []
|
|
309
302
|
50.times do
|
|
310
303
|
res = Zold::Http.new(uri: URI("http://localhost:#{port}/")).get
|
|
@@ -316,7 +309,7 @@ class FrontTest < Zold::Test
|
|
|
316
309
|
end
|
|
317
310
|
|
|
318
311
|
def test_headers_are_being_set_correctly
|
|
319
|
-
FakeNode.new(log: test_log).run(
|
|
312
|
+
FakeNode.new(log: test_log).run(opts('--expose-version=9.9.9')) do |port|
|
|
320
313
|
response = Zold::Http.new(uri: URI("http://localhost:#{port}/")).get
|
|
321
314
|
assert_equal('no-cache', response.headers['Cache-Control'])
|
|
322
315
|
assert_equal('close', response.headers['Connection'])
|
|
@@ -330,7 +323,7 @@ class FrontTest < Zold::Test
|
|
|
330
323
|
|
|
331
324
|
def test_alias_parameter
|
|
332
325
|
name = SecureRandom.hex(4)
|
|
333
|
-
FakeNode.new(log: test_log).run(
|
|
326
|
+
FakeNode.new(log: test_log).run(opts("--alias=#{name}")) do |port|
|
|
334
327
|
uri = URI("http://localhost:#{port}/")
|
|
335
328
|
response = Zold::Http.new(uri: uri).get
|
|
336
329
|
assert_match(
|
|
@@ -342,7 +335,7 @@ class FrontTest < Zold::Test
|
|
|
342
335
|
end
|
|
343
336
|
|
|
344
337
|
def test_default_alias_parameter
|
|
345
|
-
FakeNode.new(log: test_log).run(
|
|
338
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
346
339
|
uri = URI("http://localhost:#{port}/")
|
|
347
340
|
response = Zold::Http.new(uri: uri).get
|
|
348
341
|
assert_match(
|
|
@@ -355,7 +348,7 @@ class FrontTest < Zold::Test
|
|
|
355
348
|
|
|
356
349
|
def test_invalid_alias
|
|
357
350
|
exception = assert_raises RuntimeError do
|
|
358
|
-
FakeNode.new(log: test_log).run(
|
|
351
|
+
FakeNode.new(log: test_log).run(opts('--alias=invalid-alias')) do |port|
|
|
359
352
|
uri = URI("http://localhost:#{port}/")
|
|
360
353
|
Zold::Http.new(uri: uri).get
|
|
361
354
|
end
|
|
@@ -365,7 +358,7 @@ class FrontTest < Zold::Test
|
|
|
365
358
|
|
|
366
359
|
def test_push_fetch_in_multiple_threads
|
|
367
360
|
key = Zold::Key.new(text: IO.read('fixtures/id_rsa'))
|
|
368
|
-
FakeNode.new(log: test_log).run(
|
|
361
|
+
FakeNode.new(log: test_log).run(opts) do |port|
|
|
369
362
|
FakeHome.new(log: test_log).run do |home|
|
|
370
363
|
wallet = home.create_wallet(Zold::Id::ROOT)
|
|
371
364
|
base = "http://localhost:#{port}"
|
|
@@ -383,4 +376,10 @@ class FrontTest < Zold::Test
|
|
|
383
376
|
end
|
|
384
377
|
end
|
|
385
378
|
end
|
|
379
|
+
|
|
380
|
+
private
|
|
381
|
+
|
|
382
|
+
def opts(*extra)
|
|
383
|
+
['--no-metronome', '--ignore-score-weakness', '--standalone', '--threads=0', '--strength=1'] + extra
|
|
384
|
+
end
|
|
386
385
|
end
|
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.26.
|
|
4
|
+
version: 0.26.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-03-
|
|
11
|
+
date: 2019-03-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: backtrace
|
|
@@ -671,6 +671,7 @@ files:
|
|
|
671
671
|
- lib/zold/node/farm.rb
|
|
672
672
|
- lib/zold/node/farmers.rb
|
|
673
673
|
- lib/zold/node/front.rb
|
|
674
|
+
- lib/zold/node/journaled_entrance.rb
|
|
674
675
|
- lib/zold/node/nodup_entrance.rb
|
|
675
676
|
- lib/zold/node/nospam_entrance.rb
|
|
676
677
|
- lib/zold/node/safe_entrance.rb
|
|
@@ -779,7 +780,7 @@ licenses:
|
|
|
779
780
|
- MIT
|
|
780
781
|
metadata: {}
|
|
781
782
|
post_install_message: |-
|
|
782
|
-
Thanks for installing Zold 0.26.
|
|
783
|
+
Thanks for installing Zold 0.26.16!
|
|
783
784
|
Study our White Paper: https://papers.zold.io/wp.pdf
|
|
784
785
|
Read our blog posts: https://blog.zold.io
|
|
785
786
|
Try ZLD online wallet at: https://wts.zold.io
|