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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3267a66b285dc8f08ffc218d6f29bc75aa5553f6240125aee76fd06d4b897cdb
4
- data.tar.gz: f27a3f796b2e43945595b5c5c1f74e883e573ae98ed865e9dad4588f16626a7d
3
+ metadata.gz: 384032efafe3dc31d66fe3b69b8419c2ee15e55d9206844a3590ea5a65870d0d
4
+ data.tar.gz: bea95e958df2ab1f3d4158d61ad9bde9efbb768ed91d82a7cc6c72251611a6f0
5
5
  SHA512:
6
- metadata.gz: 2d045eb1fff2a665a0e019264e6a2450aee1fd10f4737477c0075809233d433990960e205a134a401758cefb3c1da1b57707b8ecef3a9bcfd5a3857a242db7d0
7
- data.tar.gz: 228fe183795be02c6331f44e57855afb5659211576285999c8346f8ce395b76b29b9c91f2c828a0c56a691f037ad4d06871bcf2ff03844be0eb42639ec03be4d
6
+ metadata.gz: a1aaa055e72196ea96d8bcd8b3c2179311317536e018daa4460edea4ffff9530b527b2442a655835be28bb5a6fd1cd9ed0e31ff469b1fbbc43d07b15d4eed431
7
+ data.tar.gz: 863cfbd9db8ad759bc67d4e3200d2379910d0951fb3fb16c9c2d0033c440fb77d12f4358cbc3c63e01d45351d23691df501af74efeaa9741fa524237b479ea6d
@@ -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: 30
33
+ Max: 34
32
34
  Metrics/LineLength:
33
35
  Max: 120
34
36
  Style/MultilineBlockChain:
@@ -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(
@@ -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")}")
@@ -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
- module Zold
31
- # Routines module
32
- module Routines
33
- # Audit the system
34
- class Audit
35
- def initialize(opts, wallets, log: Log::NULL)
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
- def exec(_ = 0)
42
- sleep(60) unless @opts['routine-immediately']
43
- @log.info(
44
- 'Audit: ' + [
45
- "memory used: #{Size.new(GetProcessMem.new.bytes.to_i)}",
46
- "threads total: #{Thread.list.count}",
47
- "wallets: #{@wallets.count}"
48
- ].join('; ')
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
- module Zold
32
- # Routines module
33
- module Routines
34
- # Garbage collector
35
- class Gc
36
- def initialize(opts, wallets, log: Log::NULL)
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
- def exec(_ = 0)
43
- sleep(60) unless @opts['routine-immediately']
44
- cmd = Remove.new(wallets: @wallets, log: @log)
45
- args = ['remove']
46
- seen = 0
47
- removed = 0
48
- @wallets.all.each do |id|
49
- seen += 1
50
- next unless @wallets.acq(id) { |w| w.exists? && w.mtime < Time.now - @opts['gc-age'] && w.txns.empty? }
51
- cmd.run(args + [id.to_s])
52
- removed += 1
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
- module Zold
32
- # Routines module
33
- module Routines
34
- # Reconnect to the network
35
- class Reconnect
36
- def initialize(opts, remotes, farm = Farm::Empty.new, log: Log::NULL)
37
- @opts = opts
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
- def exec(step = 0)
44
- sleep(60) unless @opts['routine-immediately']
45
- cmd = Remote.new(remotes: @remotes, log: @log, farm: @farm)
46
- args = ['remote', "--network=#{Shellwords.escape(@opts['network'])}", '--ignore-ping']
47
- score = @farm.best[0]
48
- args << "--ignore-node=#{Shellwords.escape("#{score.host}:#{score.port}")}" if score
49
- cmd.run(args + ['masters']) unless @opts['routine-immediately']
50
- all = @remotes.all
51
- return if @opts['routine-immediately'] && all.empty?
52
- cmd.run(args + ['select'])
53
- if all.count < Remotes::MAX_NODES / 2 || all.any? { |r| r[:errors] > Remotes::TOLERANCE } || (step % 10).zero?
54
- cmd.run(args + ['update'] + (@opts['never-reboot'] ? [] : ['--reboot']))
55
- end
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
- module Zold
34
- # Routines module
35
- module Routines
36
- # Spread them
37
- class Spread
38
- def initialize(opts, wallets, remotes, copies, log: Log::NULL)
39
- @opts = opts
40
- @wallets = wallets
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
- def exec(_ = 0)
47
- sleep(60) unless @opts['routine-immediately']
48
- @wallets.all.sample(100).each do |id|
49
- next if Copies.new(File.join(@copies, id)).all.count < 2
50
- Push.new(wallets: @wallets, remotes: @remotes, log: @log).run(
51
- ['push', "--network=#{Shellwords.escape(@opts['network'])}", id.to_s]
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
@@ -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
- # host, port = @address.split(':')
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
- ['--edge-baseline']
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
@@ -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 \"#{dup.to_text}\" \
100
- with a new one \"#{txn.to_text}\" from #{wallet.mnemo}")
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}: \"#{txn.to_text}\"")
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 \"#{dup.to_text}\" with \"#{txn.to_text}\" from #{wallet.mnemo} (same ID/BNF)")
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}: \"#{txn.to_text}\"")
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 with the key of #{wallet.id}: \"#{txn.to_text}\"")
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, but the txn in in the baseline: \"#{txn.to_text}\"")
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: \"#{txn.to_text}\"")
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: \"#{txn.to_text}\"")
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: \"#{txn.to_text}\"")
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: \"#{txn.to_text}\"")
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
- @log.info("The balance is negative, won't merge #{temp.mnemo} on top of #{wallet.mnemo}")
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))
@@ -25,7 +25,7 @@
25
25
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.29.25'
28
+ VERSION = '0.29.26'
29
29
  PROTOCOL = 2
30
30
  REPO = 'zold-io/zold'
31
31
  end
@@ -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.25
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.25!
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