zold 0.29.25 → 0.29.26

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 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