lib/zold/commands/fetch.rb in zold-0.21.4 vs lib/zold/commands/fetch.rb in zold-0.22.0
- old
+ new
@@ -85,10 +85,13 @@
'The name of the network we work in',
default: 'test'
o.integer '--threads',
'How many threads to use for fetching wallets (default: 1)',
default: 1
+ o.integer '--retry',
+ 'How many times to retry each node before reporting a failure (default: 2)',
+ default: 2
o.bool '--help', 'Print instructions'
end
mine = Args.new(opts, @log).take || return
list = mine.empty? ? @wallets.all : mine.map { |i| Id.new(i) }
ThreadPool.new('fetch', log: @log).run(opts['threads'], list.uniq) do |id|
@@ -131,51 +134,67 @@
end
@log.debug("#{cps.all.count} local copies of #{id}:\n#{list.join("\n")}")
end
def fetch_one(id, r, cps, opts)
- start = Time.now
if opts['ignore-node'].include?(r.to_s)
@log.debug("#{r} ignored because of --ignore-node")
return 0
end
- uri = "/wallet/#{id}"
- head = r.http(uri).get
- r.assert_code(200, head)
- json = JsonPage.new(head.body, uri).to_hash
- score = Score.parse_json(json['score'])
- r.assert_valid_score(score)
- r.assert_score_ownership(score)
- r.assert_score_strength(score) unless opts['ignore-score-weakness']
- copy = nil
- cps.all.each do |c|
- next unless json['digest'] == OpenSSL::Digest::SHA256.file(c[:path]).hexdigest &&
- json['size'] == File.size(c[:path])
- copy = cps.add(IO.read(c[:path]), score.host, score.port, score.value, master: r.master?)
- @log.debug("No need to fetch #{id} from #{r}, it's the same content as copy ##{copy}")
- break
- end
- if copy.nil?
- Tempfile.open(['', Wallet::EXT]) do |f|
- r.http(uri + '.bin').get_file(f)
- wallet = Wallet.new(f.path)
- wallet.refurbish
- if wallet.protocol != Zold::PROTOCOL
- raise "Protocol #{wallet.protocol} doesn't match #{Zold::PROTOCOL} in #{id}"
+ start = Time.now
+ read_one(id, r, opts) do |json, score|
+ r.assert_valid_score(score)
+ r.assert_score_ownership(score)
+ r.assert_score_strength(score) unless opts['ignore-score-weakness']
+ copy = nil
+ cps.all.each do |c|
+ next unless json['digest'] == OpenSSL::Digest::SHA256.file(c[:path]).hexdigest &&
+ json['size'] == File.size(c[:path])
+ copy = cps.add(IO.read(c[:path]), score.host, score.port, score.value, master: r.master?)
+ @log.debug("No need to fetch #{id} from #{r}, it's the same content as copy ##{copy}")
+ break
+ end
+ if copy.nil?
+ Tempfile.open(['', Wallet::EXT]) do |f|
+ r.http("/wallet/#{id}.bin").get_file(f)
+ wallet = Wallet.new(f.path)
+ wallet.refurbish
+ if wallet.protocol != Zold::PROTOCOL
+ raise "Protocol #{wallet.protocol} doesn't match #{Zold::PROTOCOL} in #{id}"
+ end
+ if wallet.network != opts['network']
+ raise "The wallet #{id} is in network '#{wallet.network}', while we are in '#{opts['network']}'"
+ end
+ if wallet.balance.negative? && !wallet.root?
+ raise "The balance of #{id} is #{wallet.balance} and it's not a root wallet"
+ end
+ copy = cps.add(IO.read(f), score.host, score.port, score.value, master: r.master?)
+ @log.info("#{r} returned #{wallet.mnemo} #{Age.new(json['mtime'])}/#{json['copies']}c \
+ as copy ##{copy}/#{cps.all.count} in #{Age.new(start, limit: 4)}: \
+ #{Rainbow(score.value).green} (#{json['version']})")
end
- if wallet.network != opts['network']
- raise "The wallet #{id} is in network '#{wallet.network}', while we are in '#{opts['network']}'"
- end
- if wallet.balance.negative? && !wallet.root?
- raise "The balance of #{id} is #{wallet.balance} and it's not a root wallet"
- end
- copy = cps.add(IO.read(f), score.host, score.port, score.value, master: r.master?)
- @log.info("#{r} returned #{wallet.mnemo} #{Age.new(json['mtime'])}/#{json['copies']}c \
-as copy ##{copy}/#{cps.all.count} in #{Age.new(start, limit: 4)}: \
-#{Rainbow(score.value).green} (#{json['version']})")
end
+ score.value
end
- score.value
+ end
+
+ def read_one(id, r, opts)
+ attempt = 0
+ begin
+ uri = "/wallet/#{id}"
+ head = r.http(uri).get
+ r.assert_code(200, head)
+ json = JsonPage.new(head.body, uri).to_hash
+ score = Score.parse_json(json['score'])
+ yield json, score
+ rescue JsonPage::CantParse, Score::CantParse, RemoteNode::CantAssert => e
+ attempt += 1
+ if attempt < opts['retry']
+ @log.error("#{r} failed to fetch #{id}, trying again (attempt no.#{attempt}): #{e.message}")
+ retry
+ end
+ raise e
+ end
end
def digest(json)
hash = json['digest']
return '?' if hash.nil?