zold 0.29.25 → 0.29.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -1
- data/lib/zold/commands/clean.rb +1 -1
- data/lib/zold/commands/fetch.rb +1 -1
- data/lib/zold/commands/node.rb +6 -2
- data/lib/zold/commands/routines.rb +28 -0
- data/lib/zold/commands/routines/audit.rb +16 -21
- data/lib/zold/commands/routines/gc.rb +19 -24
- data/lib/zold/commands/routines/reconcile.rb +65 -0
- data/lib/zold/commands/routines/reconnect.rb +25 -29
- data/lib/zold/commands/routines/spread.rb +16 -21
- data/lib/zold/node/pipeline.rb +2 -3
- data/lib/zold/patch.rb +23 -12
- data/lib/zold/version.rb +1 -1
- data/test/commands/routines/test_reconcile.rb +51 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 384032efafe3dc31d66fe3b69b8419c2ee15e55d9206844a3590ea5a65870d0d
|
4
|
+
data.tar.gz: bea95e958df2ab1f3d4158d61ad9bde9efbb768ed91d82a7cc6c72251611a6f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1aaa055e72196ea96d8bcd8b3c2179311317536e018daa4460edea4ffff9530b527b2442a655835be28bb5a6fd1cd9ed0e31ff469b1fbbc43d07b15d4eed431
|
7
|
+
data.tar.gz: 863cfbd9db8ad759bc67d4e3200d2379910d0951fb3fb16c9c2d0033c440fb77d12f4358cbc3c63e01d45351d23691df501af74efeaa9741fa524237b479ea6d
|
data/.rubocop.yml
CHANGED
@@ -5,6 +5,8 @@ AllCops:
|
|
5
5
|
DisplayCopNames: true
|
6
6
|
TargetRubyVersion: 2.5
|
7
7
|
|
8
|
+
Style/ClassAndModuleChildren:
|
9
|
+
Enabled: false
|
8
10
|
Layout/EmptyLineAfterGuardClause:
|
9
11
|
Enabled: false
|
10
12
|
Metrics/CyclomaticComplexity:
|
@@ -28,7 +30,7 @@ Metrics/ParameterLists:
|
|
28
30
|
Layout/AlignParameters:
|
29
31
|
Enabled: false
|
30
32
|
Metrics/PerceivedComplexity:
|
31
|
-
Max:
|
33
|
+
Max: 34
|
32
34
|
Metrics/LineLength:
|
33
35
|
Max: 120
|
34
36
|
Style/MultilineBlockChain:
|
data/lib/zold/commands/clean.rb
CHANGED
@@ -73,7 +73,7 @@ Available options:"
|
|
73
73
|
deleted = cps.clean(max: opts['max-age'] * 60 * 60)
|
74
74
|
list = cps.all.map do |c|
|
75
75
|
wallet = Wallet.new(c[:path])
|
76
|
-
"#{c[:name]}: #{c[:score]} #{wallet.mnemo} \
|
76
|
+
"#{c[:name]}: #{c[:score]} #{c[:total]}n #{wallet.mnemo} \
|
77
77
|
#{Size.new(File.size(c[:path]))}/#{Age.new(File.mtime(c[:path]))}#{c[:master] ? ' master' : ''}"
|
78
78
|
end
|
79
79
|
@log.debug(
|
data/lib/zold/commands/fetch.rb
CHANGED
@@ -140,7 +140,7 @@ run 'zold remote update' or use --tolerate-quorum=1"
|
|
140
140
|
@log.info("#{done.value} copies of #{id} fetched in #{Age.new(start)} with the total score of \
|
141
141
|
#{total.value} from #{nodes.value} nodes (#{masters.value} master nodes)")
|
142
142
|
list = cps.all.map do |c|
|
143
|
-
" ##{c[:name]}: #{c[:score]} #{Wallet.new(c[:path]).mnemo} \
|
143
|
+
" ##{c[:name]}: #{c[:score]} #{c[:total]}n #{Wallet.new(c[:path]).mnemo} \
|
144
144
|
#{Size.new(File.size(c[:path]))}/#{Age.new(File.mtime(c[:path]))}#{c[:master] ? ' master' : ''}"
|
145
145
|
end
|
146
146
|
@log.debug("#{cps.all.count} local copies of #{id}:\n#{list.join("\n")}")
|
data/lib/zold/commands/node.rb
CHANGED
@@ -319,7 +319,7 @@ the node won\'t connect to the network like that; try to do "zold remote reset"
|
|
319
319
|
)
|
320
320
|
farm.start(host, opts[:port], threads: opts[:threads]) do |f|
|
321
321
|
Front.set(:farm, f)
|
322
|
-
metronome(f, opts).start do |metronome|
|
322
|
+
metronome(f, opts, host, port).start do |metronome|
|
323
323
|
Front.set(:metronome, metronome)
|
324
324
|
@log.info("Starting up the web front at http://#{host}:#{opts[:port]}...")
|
325
325
|
Front.run!
|
@@ -429,7 +429,7 @@ the node won\'t connect to the network like that; try to do "zold remote reset"
|
|
429
429
|
pid
|
430
430
|
end
|
431
431
|
|
432
|
-
def metronome(farm, opts)
|
432
|
+
def metronome(farm, opts, host, port)
|
433
433
|
metronome = Metronome.new(@log)
|
434
434
|
if opts['no-metronome']
|
435
435
|
@log.info("Metronome hasn't been started because of --no-metronome")
|
@@ -457,6 +457,10 @@ the node won\'t connect to the network like that; try to do "zold remote reset"
|
|
457
457
|
end
|
458
458
|
require_relative 'routines/spread'
|
459
459
|
metronome.add(Routines::Spread.new(opts, @wallets, @remotes, @copies, log: @log))
|
460
|
+
if @remotes.master?(host, port)
|
461
|
+
require_relative 'routines/reconcile'
|
462
|
+
metronome.add(Routines::Reconcile.new(opts, @wallets, @remotes, @copies, "#{host}:#{port}", log: @log))
|
463
|
+
end
|
460
464
|
@log.info('Metronome started (use --no-metronome to disable it)')
|
461
465
|
metronome
|
462
466
|
end
|
@@ -0,0 +1,28 @@
|
|
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
|
+
# Routines.
|
24
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
25
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
26
|
+
# License:: MIT
|
27
|
+
module Zold::Routines
|
28
|
+
end
|
@@ -21,33 +21,28 @@
|
|
21
21
|
# SOFTWARE.
|
22
22
|
|
23
23
|
require 'get_process_mem'
|
24
|
+
require_relative '../routines'
|
24
25
|
require_relative '../../size'
|
25
26
|
|
26
27
|
# Audit and report as much as we can to the command line.
|
27
28
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
29
|
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
29
30
|
# License:: MIT
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
@opts = opts
|
37
|
-
@wallets = wallets
|
38
|
-
@log = log
|
39
|
-
end
|
31
|
+
class Zold::Routines::Audit
|
32
|
+
def initialize(opts, wallets, log: Log::NULL)
|
33
|
+
@opts = opts
|
34
|
+
@wallets = wallets
|
35
|
+
@log = log
|
36
|
+
end
|
40
37
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
38
|
+
def exec(_ = 0)
|
39
|
+
sleep(60) unless @opts['routine-immediately']
|
40
|
+
@log.info(
|
41
|
+
'Audit: ' + [
|
42
|
+
"memory used: #{Zold::Size.new(GetProcessMem.new.bytes.to_i)}",
|
43
|
+
"threads total: #{Thread.list.count}",
|
44
|
+
"wallets: #{@wallets.count}"
|
45
|
+
].join('; ')
|
46
|
+
)
|
52
47
|
end
|
53
48
|
end
|
@@ -20,6 +20,7 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
21
|
# SOFTWARE.
|
22
22
|
|
23
|
+
require_relative '../routines'
|
23
24
|
require_relative '../../log'
|
24
25
|
require_relative '../remove'
|
25
26
|
|
@@ -28,31 +29,25 @@ require_relative '../remove'
|
|
28
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
30
|
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
30
31
|
# License:: MIT
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@opts = opts
|
38
|
-
@wallets = wallets
|
39
|
-
@log = log
|
40
|
-
end
|
32
|
+
class Zold::Routines::Gc
|
33
|
+
def initialize(opts, wallets, log: Log::NULL)
|
34
|
+
@opts = opts
|
35
|
+
@wallets = wallets
|
36
|
+
@log = log
|
37
|
+
end
|
41
38
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
@log.info("Removed #{removed} empty+old wallets out of #{seen} total") unless removed.zero?
|
55
|
-
end
|
39
|
+
def exec(_ = 0)
|
40
|
+
sleep(60) unless @opts['routine-immediately']
|
41
|
+
cmd = Zold::Remove.new(wallets: @wallets, log: @log)
|
42
|
+
args = ['remove']
|
43
|
+
seen = 0
|
44
|
+
removed = 0
|
45
|
+
@wallets.all.each do |id|
|
46
|
+
seen += 1
|
47
|
+
next unless @wallets.acq(id) { |w| w.exists? && w.mtime < Time.now - @opts['gc-age'] && w.txns.empty? }
|
48
|
+
cmd.run(args + [id.to_s])
|
49
|
+
removed += 1
|
56
50
|
end
|
51
|
+
@log.info("Removed #{removed} empty+old wallets out of #{seen} total") unless removed.zero?
|
57
52
|
end
|
58
53
|
end
|
@@ -0,0 +1,65 @@
|
|
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 'shellwords'
|
24
|
+
require_relative '../routines'
|
25
|
+
require_relative '../../log'
|
26
|
+
require_relative '../../id'
|
27
|
+
require_relative '../../copies'
|
28
|
+
require_relative '../pull'
|
29
|
+
|
30
|
+
# R
|
31
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
32
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
33
|
+
# License:: MIT
|
34
|
+
class Zold::Routines::Reconcile
|
35
|
+
def initialize(opts, wallets, remotes, copies, address, log: Log::NULL)
|
36
|
+
@opts = opts
|
37
|
+
@wallets = wallets
|
38
|
+
@remotes = remotes
|
39
|
+
@copies = copies
|
40
|
+
@address = address
|
41
|
+
@log = log
|
42
|
+
end
|
43
|
+
|
44
|
+
def exec(_ = 0)
|
45
|
+
sleep(20 * 60) unless @opts['routine-immediately']
|
46
|
+
@remotes.iterate(@log) do |r|
|
47
|
+
next unless r.master?
|
48
|
+
next if r.to_mnemo == @address
|
49
|
+
res = r.http('/wallets').get
|
50
|
+
r.assert_code(200, res)
|
51
|
+
res.body.strip.split("\n").compact
|
52
|
+
.select { |i| /^[a-f0-9]{16}$/.match?(i) }
|
53
|
+
.reject { |i| @wallets.acq(Zold::Id.new(i), &:exists?) }
|
54
|
+
.each { |i| pull(i) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def pull(id)
|
61
|
+
Zold::Pull.new(wallets: @wallets, remotes: @remotes, copies: @copies, log: @log).run(
|
62
|
+
['pull', "--network=#{Shellwords.escape(@opts['network'])}", id.to_s, '--quiet-if-absent']
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
@@ -21,6 +21,7 @@
|
|
21
21
|
# SOFTWARE.
|
22
22
|
|
23
23
|
require 'shellwords'
|
24
|
+
require_relative '../routines'
|
24
25
|
require_relative '../remote'
|
25
26
|
require_relative '../../node/farm'
|
26
27
|
|
@@ -28,36 +29,31 @@ require_relative '../../node/farm'
|
|
28
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
30
|
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
30
31
|
# License:: MIT
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@remotes = remotes
|
39
|
-
@farm = farm
|
40
|
-
@log = log
|
41
|
-
end
|
32
|
+
class Zold::Routines::Reconnect
|
33
|
+
def initialize(opts, remotes, farm = Zold::Farm::Empty.new, log: Log::NULL)
|
34
|
+
@opts = opts
|
35
|
+
@remotes = remotes
|
36
|
+
@farm = farm
|
37
|
+
@log = log
|
38
|
+
end
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
cmd.run(args + ['trim'])
|
57
|
-
cmd.run(args + ['select'])
|
58
|
-
@log.info("Reconnected, there are #{@remotes.all.count} remote notes: \
|
59
|
-
#{@remotes.all.map { |r| "#{r[:host]}:#{r[:port]}/#{r[:score]}/#{r[:errors]}" }.join(', ')}")
|
60
|
-
end
|
40
|
+
def exec(step = 0)
|
41
|
+
sleep(60) unless @opts['routine-immediately']
|
42
|
+
cmd = Zold::Remote.new(remotes: @remotes, log: @log, farm: @farm)
|
43
|
+
args = ['remote', "--network=#{Shellwords.escape(@opts['network'])}", '--ignore-ping']
|
44
|
+
score = @farm.best[0]
|
45
|
+
args << "--ignore-node=#{Shellwords.escape("#{score.host}:#{score.port}")}" if score
|
46
|
+
cmd.run(args + ['masters']) unless @opts['routine-immediately']
|
47
|
+
all = @remotes.all
|
48
|
+
return if @opts['routine-immediately'] && all.empty?
|
49
|
+
cmd.run(args + ['select'])
|
50
|
+
if all.count < Zold::Remotes::MAX_NODES / 2 ||
|
51
|
+
all.any? { |r| r[:errors] > Remotes::TOLERANCE } || (step % 10).zero?
|
52
|
+
cmd.run(args + ['update'] + (@opts['never-reboot'] ? [] : ['--reboot']))
|
61
53
|
end
|
54
|
+
cmd.run(args + ['trim'])
|
55
|
+
cmd.run(args + ['select'])
|
56
|
+
@log.info("Reconnected, there are #{@remotes.all.count} remote notes: \
|
57
|
+
#{@remotes.all.map { |r| "#{r[:host]}:#{r[:port]}/#{r[:score]}/#{r[:errors]}" }.join(', ')}")
|
62
58
|
end
|
63
59
|
end
|
@@ -21,6 +21,7 @@
|
|
21
21
|
# SOFTWARE.
|
22
22
|
|
23
23
|
require 'shellwords'
|
24
|
+
require_relative '../routines'
|
24
25
|
require_relative '../../log'
|
25
26
|
require_relative '../../id'
|
26
27
|
require_relative '../../copies'
|
@@ -30,28 +31,22 @@ require_relative '../push'
|
|
30
31
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
31
32
|
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
32
33
|
# License:: MIT
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
@remotes = remotes
|
42
|
-
@copies = copies
|
43
|
-
@log = log
|
44
|
-
end
|
34
|
+
class Zold::Routines::Spread
|
35
|
+
def initialize(opts, wallets, remotes, copies, log: Log::NULL)
|
36
|
+
@opts = opts
|
37
|
+
@wallets = wallets
|
38
|
+
@remotes = remotes
|
39
|
+
@copies = copies
|
40
|
+
@log = log
|
41
|
+
end
|
45
42
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
end
|
43
|
+
def exec(_ = 0)
|
44
|
+
sleep(60) unless @opts['routine-immediately']
|
45
|
+
@wallets.all.sample(100).each do |id|
|
46
|
+
next if Zold::Copies.new(File.join(@copies, id)).all.count < 2
|
47
|
+
Zold::Push.new(wallets: @wallets, remotes: @remotes, log: @log).run(
|
48
|
+
['push', "--network=#{Shellwords.escape(@opts['network'])}", id.to_s]
|
49
|
+
)
|
55
50
|
end
|
56
51
|
end
|
57
52
|
end
|
data/lib/zold/node/pipeline.rb
CHANGED
@@ -87,13 +87,12 @@ module Zold
|
|
87
87
|
def merge(id, copies, wallets, log)
|
88
88
|
Tempfile.open do |f|
|
89
89
|
modified = Tempfile.open do |t|
|
90
|
-
|
90
|
+
host, port = @address.split(':')
|
91
91
|
Merge.new(wallets: wallets, remotes: @remotes, copies: copies.root, log: log).run(
|
92
92
|
['merge', id.to_s, "--ledger=#{Shellwords.escape(f.path)}"] +
|
93
93
|
["--trusted=#{Shellwords.escape(t.path)}"] +
|
94
94
|
["--network=#{Shellwords.escape(@network)}"] +
|
95
|
-
['--
|
96
|
-
# (@remotes.master?(host, port.to_i) ? ['--no-baseline', '--depth=4'] : [])
|
95
|
+
(@remotes.master?(host, port.to_i) ? ['--no-baseline', '--depth=4'] : [])
|
97
96
|
)
|
98
97
|
end
|
99
98
|
@mutex.synchronize do
|
data/lib/zold/patch.rb
CHANGED
@@ -96,36 +96,43 @@ module Zold
|
|
96
96
|
if txn.amount.negative?
|
97
97
|
dup = @txns.find { |t| t.id == txn.id && t.amount.negative? }
|
98
98
|
if dup
|
99
|
-
@log.error("An attempt to overwrite existing transaction
|
100
|
-
with a new one
|
99
|
+
@log.error("An attempt to overwrite existing transaction #{dup.to_text.inspect} \
|
100
|
+
with a new one #{txn.to_text.inspect} from #{wallet.mnemo}")
|
101
101
|
next
|
102
102
|
end
|
103
103
|
unless Signature.new(@network).valid?(@key, wallet.id, txn)
|
104
|
-
@log.error("Invalid RSA signature at the transaction ##{txn.id} of #{wallet.id}:
|
104
|
+
@log.error("Invalid RSA signature at the transaction ##{txn.id} of #{wallet.id}: #{txn.to_text.inspect}")
|
105
105
|
next
|
106
106
|
end
|
107
107
|
else
|
108
|
+
if Id::BANNED.include?(txn.bnf.to_s)
|
109
|
+
@log.debug("The paying wallet is banned, #{wallet.id} can't accept this: #{txn.to_text.inspect}")
|
110
|
+
next
|
111
|
+
end
|
108
112
|
dup = @txns.find { |t| t.id == txn.id && t.bnf == txn.bnf && t.amount.positive? }
|
109
113
|
if dup
|
110
|
-
@log.error("Overwriting
|
114
|
+
@log.error("Overwriting #{dup.to_text.inspect} with #{txn.to_text.inspect} \
|
115
|
+
from #{wallet.mnemo} (same ID/BNF)")
|
111
116
|
next
|
112
117
|
end
|
113
118
|
if !txn.sign.nil? && !txn.sign.empty?
|
114
|
-
@log.error("RSA signature is redundant at ##{txn.id} of #{wallet.id}:
|
119
|
+
@log.error("RSA signature is redundant at ##{txn.id} of #{wallet.id}: #{txn.to_text.inspect}")
|
115
120
|
next
|
116
121
|
end
|
117
122
|
unless wallet.prefix?(txn.prefix)
|
118
|
-
@log.debug("Payment prefix '#{txn.prefix}' doesn't match
|
123
|
+
@log.debug("Payment prefix '#{txn.prefix}' doesn't match \
|
124
|
+
with the key of #{wallet.id}: #{txn.to_text.inspect}")
|
119
125
|
next
|
120
126
|
end
|
121
127
|
unless @wallets.acq(txn.bnf, &:exists?)
|
122
128
|
if baseline
|
123
|
-
@log.debug("Paying wallet #{txn.bnf} is absent,
|
129
|
+
@log.debug("Paying wallet #{txn.bnf} is absent, \
|
130
|
+
but the txn in in the baseline: #{txn.to_text.inspect}")
|
124
131
|
else
|
125
132
|
next if pulled.include?(txn.bnf)
|
126
133
|
pulled << txn.bnf
|
127
134
|
if yield(txn) && !@wallets.acq(txn.bnf, &:exists?)
|
128
|
-
@log.error("Paying wallet #{txn.bnf} file is absent even after PULL:
|
135
|
+
@log.error("Paying wallet #{txn.bnf} file is absent even after PULL: #{txn.to_text.inspect}")
|
129
136
|
next
|
130
137
|
end
|
131
138
|
end
|
@@ -134,18 +141,18 @@ with a new one \"#{txn.to_text}\" from #{wallet.mnemo}")
|
|
134
141
|
!@wallets.acq(txn.bnf) { |p| p.includes_negative?(txn.id, wallet.id) }
|
135
142
|
if baseline
|
136
143
|
@log.debug("The beneficiary #{@wallets.acq(txn.bnf, &:mnemo)} of #{@id} \
|
137
|
-
doesn't have this transaction, but we trust it, since it's a baseline:
|
144
|
+
doesn't have this transaction, but we trust it, since it's a baseline: #{txn.to_text.inspect}")
|
138
145
|
else
|
139
146
|
if pulled.include?(txn.bnf)
|
140
147
|
@log.debug("The beneficiary #{@wallets.acq(txn.bnf, &:mnemo)} of #{@id} \
|
141
|
-
doesn't have this transaction:
|
148
|
+
doesn't have this transaction: #{txn.to_text.inspect}")
|
142
149
|
next
|
143
150
|
end
|
144
151
|
pulled << txn.bnf
|
145
152
|
yield(txn)
|
146
153
|
unless @wallets.acq(txn.bnf) { |p| p.includes_negative?(txn.id, wallet.id) }
|
147
154
|
@log.debug("The beneficiary #{@wallets.acq(txn.bnf, &:mnemo)} of #{@id} \
|
148
|
-
doesn't have this transaction:
|
155
|
+
doesn't have this transaction: #{txn.to_text.inspect}")
|
149
156
|
next
|
150
157
|
end
|
151
158
|
end
|
@@ -192,7 +199,11 @@ doesn't have this transaction: \"#{txn.to_text}\"")
|
|
192
199
|
end
|
193
200
|
temp.refurbish
|
194
201
|
if temp.balance.negative? && !temp.id.root? && !allow_negative_balance
|
195
|
-
|
202
|
+
if wallet.exists?
|
203
|
+
@log.info("The balance is negative, won't merge #{temp.mnemo} on top of #{wallet.mnemo}")
|
204
|
+
else
|
205
|
+
@log.info("The balance is negative, won't save #{temp.mnemo}")
|
206
|
+
end
|
196
207
|
else
|
197
208
|
FileUtils.mkdir_p(File.dirname(file))
|
198
209
|
IO.write(file, IO.read(f.path))
|
data/lib/zold/version.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
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 'minitest/autorun'
|
24
|
+
require 'webmock/minitest'
|
25
|
+
require_relative '../../test__helper'
|
26
|
+
require_relative '../../fake_home'
|
27
|
+
require_relative '../../../lib/zold/remotes'
|
28
|
+
require_relative '../../../lib/zold/commands/routines/reconcile.rb'
|
29
|
+
|
30
|
+
# Reconcile test.
|
31
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
32
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
33
|
+
# License:: MIT
|
34
|
+
class TestReconcile < Zold::Test
|
35
|
+
def test_reconciles
|
36
|
+
FakeHome.new(log: test_log).run do |home|
|
37
|
+
remotes = home.remotes
|
38
|
+
remotes.clean
|
39
|
+
remotes.masters
|
40
|
+
m = remotes.all[0]
|
41
|
+
remotes.all.each_with_index { |r, idx| remotes.remove(r[:host], r[:port]) if idx.positive? }
|
42
|
+
stub_request(:get, "http://#{m[:host]}:#{m[:port]}/wallets").to_return(status: 200, body: Zold::Id::ROOT.to_s)
|
43
|
+
stub_request(:get, "http://#{m[:host]}:#{m[:port]}/wallet/#{Zold::Id::ROOT}").to_return(status: 404)
|
44
|
+
opts = { 'never-reboot' => true, 'routine-immediately' => true }
|
45
|
+
routine = Zold::Routines::Reconcile.new(
|
46
|
+
opts, home.wallets, remotes, home.copies.root, 'some-fake-host:2096', log: test_log
|
47
|
+
)
|
48
|
+
routine.exec
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
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.29.
|
4
|
+
version: 0.29.26
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
@@ -659,8 +659,10 @@ files:
|
|
659
659
|
- lib/zold/commands/push.rb
|
660
660
|
- lib/zold/commands/remote.rb
|
661
661
|
- lib/zold/commands/remove.rb
|
662
|
+
- lib/zold/commands/routines.rb
|
662
663
|
- lib/zold/commands/routines/audit.rb
|
663
664
|
- lib/zold/commands/routines/gc.rb
|
665
|
+
- lib/zold/commands/routines/reconcile.rb
|
664
666
|
- lib/zold/commands/routines/reconnect.rb
|
665
667
|
- lib/zold/commands/routines/spread.rb
|
666
668
|
- lib/zold/commands/show.rb
|
@@ -717,6 +719,7 @@ files:
|
|
717
719
|
- resources/root.pub
|
718
720
|
- test/commands/routines/test_audit.rb
|
719
721
|
- test/commands/routines/test_gc.rb
|
722
|
+
- test/commands/routines/test_reconcile.rb
|
720
723
|
- test/commands/routines/test_reconnect.rb
|
721
724
|
- test/commands/test_alias.rb
|
722
725
|
- test/commands/test_calculate.rb
|
@@ -798,7 +801,7 @@ licenses:
|
|
798
801
|
- MIT
|
799
802
|
metadata: {}
|
800
803
|
post_install_message: |-
|
801
|
-
Thanks for installing Zold 0.29.
|
804
|
+
Thanks for installing Zold 0.29.26!
|
802
805
|
Study our White Paper: https://papers.zold.io/wp.pdf
|
803
806
|
Read our blog posts: https://blog.zold.io
|
804
807
|
Try ZLD online wallet at: https://wts.zold.io
|
@@ -831,6 +834,7 @@ test_files:
|
|
831
834
|
- features/support/env.rb
|
832
835
|
- test/commands/routines/test_audit.rb
|
833
836
|
- test/commands/routines/test_gc.rb
|
837
|
+
- test/commands/routines/test_reconcile.rb
|
834
838
|
- test/commands/routines/test_reconnect.rb
|
835
839
|
- test/commands/test_alias.rb
|
836
840
|
- test/commands/test_calculate.rb
|