zold 0.11.14 → 0.11.15

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
  SHA1:
3
- metadata.gz: f6e2499c65eb639ec4dd6a1177e4cf6186269688
4
- data.tar.gz: c5482c8cb8b66a97f097626009ee0b461a57cc19
3
+ metadata.gz: ca4077a7a79a8ff6e6cc6ca27ebeda18571a3b7a
4
+ data.tar.gz: b5259cec4a2a73e33be07e387466a3b020d30be7
5
5
  SHA512:
6
- metadata.gz: 6e0cad7598ca9560cfde7a8a7e9cc3ffb53065931c063e0f7ff69d8668e489d9a72f795707ee931a1ddf5715340fb38bb160a56fd366ae239aa368fb094340d3
7
- data.tar.gz: 423b9534d67f3479accfcc33db73818c9574161c21131d62dae5b149179394da25ce9812dcf196bfc89412984f2b846e62dcc89926d00e9fc6881e0cf10f752c
6
+ metadata.gz: 4251510624adf3efade782f91cf3ba44bccbd1dfd2561da972253abbd3ab0aff08940c57a66e642a25ea5d42c706167d892babb1871bf8fbe25f684a4fd48da9
7
+ data.tar.gz: 27a737d9cccff7cd12c97ff096b69860ee0542f01f2a33908d05bbce0828429d847b6ca12c1d71c03f3273ed83196cfccc18f056a71ec4c972cdef605c829342
data/INSTALL.md CHANGED
@@ -14,16 +14,16 @@ then the [gem](https://rubygems.org/gems/zold).
14
14
 
15
15
  ```bash
16
16
  $ sudo apt update -y
17
- $ sudo apt install -y ruby-dev rubygems zlib1g-dev libssl-dev make
18
- $ gem install zold
17
+ $ sudo apt install -y ruby-dev rubygems zlib1g-dev libssl-dev make build-essential
18
+ $ gem install --no-ri --no-rdoc zold
19
19
  ```
20
20
 
21
21
  ## Ubuntu 16.04
22
22
 
23
23
  ```bash
24
24
  $ sudo apt-get update -y
25
- $ sudo apt-get install -y ruby-dev rubygems zlib1g-dev libssl-dev
26
- $ gem install zold
25
+ $ sudo apt-get install -y ruby-dev rubygems zlib1g-dev libssl-dev build-essential
26
+ $ gem install --no-ri --no-rdoc zold
27
27
  ```
28
28
 
29
29
  ## OSX
@@ -35,7 +35,7 @@ $ brew install rbenv ruby-build
35
35
  $ rbenv install 2.5.1
36
36
  $ rbenv global 2.5.1
37
37
  $ ruby -v
38
- $ gem install zold
38
+ $ gem install --no-ri --no-rdoc zold
39
39
  ```
40
40
 
41
41
  Without homebrew:
@@ -63,12 +63,16 @@ Available options:"
63
63
  private
64
64
 
65
65
  def diff(wallet, cps, _)
66
- raise 'There are no remote copies, try FETCH first' if cps.all.empty?
66
+ raise "There are no remote copies, try 'zold fetch' first" if cps.all.empty?
67
67
  cps = cps.all.sort_by { |c| c[:score] }.reverse
68
68
  patch = Patch.new
69
- patch.start(Wallet.new(cps[0][:path]))
70
- cps[1..-1].each do |c|
71
- patch.join(Wallet.new(c[:path]))
69
+ cps.each do |c|
70
+ begin
71
+ patch.join(Wallet.new(c[:path]))
72
+ rescue StandardError => e
73
+ @log.error("Can't use a copy of #{wallet.id} from #{c[:host]}:#{c[:port]}; #{e.class.name}: #{e.message}")
74
+ @log.debug(e.backtrace.join("\n\t"))
75
+ end
72
76
  end
73
77
  before = AtomicFile.new(wallet.path).read
74
78
  after = ''
@@ -65,22 +65,18 @@ Available options:"
65
65
  @log.error("There are no remote copies of #{id}, try 'zold fetch' first")
66
66
  return
67
67
  end
68
- wallet = @wallets.find(id)
69
68
  cps = cps.all.sort_by { |c| c[:score] }.reverse
70
69
  patch = Patch.new
71
- main = Wallet.new(cps[0][:path])
72
- patch.start(main)
73
- cps[1..-1].each do |c|
74
- extra = Wallet.new(c[:path])
75
- if extra.network != main.network
76
- @log.error("The wallet is from a different network '#{extra.network}', ours is '#{main.network}'")
77
- next
78
- end
79
- if extra.key != main.key
80
- @log.error('Public key mismatch')
81
- next
82
- end
83
- patch.join(extra)
70
+ cps.each do |c|
71
+ merge_one(patch, Wallet.new(c[:path]), "#{c[:host]}:#{c[:port]}")
72
+ @log.debug("#{c[:host]}:#{c[:port]} merged: #{patch}")
73
+ end
74
+ wallet = @wallets.find(id)
75
+ if wallet.exists?
76
+ merge_one(patch, wallet, 'localhost')
77
+ @log.debug("Local copy merged: #{patch}")
78
+ else
79
+ @log.debug("Local copy is absent, won't merge")
84
80
  end
85
81
  modified = patch.save(wallet.path, overwrite: true)
86
82
  if modified
@@ -90,5 +86,12 @@ Available options:"
90
86
  end
91
87
  modified
92
88
  end
89
+
90
+ def merge_one(patch, wallet, name)
91
+ patch.join(wallet)
92
+ rescue StandardError => e
93
+ @log.error("Can't merge a copy coming from #{name}; #{e.class.name}: #{e.message}")
94
+ @log.debug(e.backtrace.join("\n\t"))
95
+ end
93
96
  end
94
97
  end
@@ -94,6 +94,8 @@ module Zold
94
94
  load.group_by { |s| s[:name] }.map do |name, scores|
95
95
  {
96
96
  name: name,
97
+ host: scores[0][:host],
98
+ port: scores[0][:port],
97
99
  path: File.join(@dir, name),
98
100
  score: scores.select { |s| s[:time] > Time.now - 24 * 60 * 60 }
99
101
  .map { |s| s[:score] }
@@ -77,7 +77,7 @@ module Zold
77
77
  end
78
78
  s = @scores.pop
79
79
  next unless s.valid?
80
- next if s.expired?
80
+ next if s.expired?(20)
81
81
  next if s.strength < strength
82
82
  @semaphore.synchronize do
83
83
  save(s)
@@ -149,7 +149,7 @@ module Zold
149
149
  wallet = settings.wallets.find(id)
150
150
  request.body.rewind
151
151
  after = request.body.read.to_s
152
- before = wallet.exists? ? AtomicFile.new(wallet.path).read : ''
152
+ before = wallet.exists? ? AtomicFile.new(wallet.path).read.to_s : ''
153
153
  if before == after
154
154
  status 304
155
155
  return
@@ -30,14 +30,23 @@ require_relative 'atomic_file'
30
30
  module Zold
31
31
  # A patch
32
32
  class Patch
33
- def start(wallet)
34
- @id = wallet.id
35
- @key = wallet.key
36
- @txns = wallet.txns
37
- @network = wallet.network
33
+ def to_s
34
+ return 'empty' if @id.nil?
35
+ "#{@txns.count} txns"
38
36
  end
39
37
 
40
38
  def join(wallet)
39
+ if @id.nil?
40
+ @id = wallet.id
41
+ @key = wallet.key
42
+ @txns = wallet.txns
43
+ @network = wallet.network
44
+ end
45
+ if wallet.network != @network
46
+ raise "The wallet is from a different network '#{wallet.network}', ours is '#{@network}'"
47
+ end
48
+ raise 'Public key mismatch' if wallet.key != @key
49
+ raise "Wallet ID mismatch: #{@id} != #{wallet.id}" if wallet.id != @id
41
50
  negative = @txns.select { |t| t.amount.negative? }
42
51
  max = negative.empty? ? 0 : negative.max_by(&:id).id
43
52
  wallet.txns.each do |txn|
@@ -47,13 +56,16 @@ module Zold
47
56
  (txn.id <= max ||
48
57
  @txns.find { |t| t.id == txn.id } ||
49
58
  @txns.map(&:amount).inject(&:+) < txn.amount)
50
- next unless Signature.new.valid?(@key, wallet.id, txn)
59
+ unless Signature.new.valid?(@key, wallet.id, txn)
60
+ raise "Invalid RSA signature at transaction ##{txn.id} of #{wallet.id}"
61
+ end
51
62
  @txns << txn
52
63
  end
53
64
  end
54
65
 
55
66
  # Returns TRUE if the file was actually modified
56
67
  def save(file, overwrite: false)
68
+ raise 'You have to join at least one wallet in' if @id.nil?
57
69
  before = ''
58
70
  before = AtomicFile.new(file).read if File.exist?(file)
59
71
  wallet = Wallet.new(file)
@@ -167,8 +167,8 @@ module Zold
167
167
  (Time.now - @time) / 60
168
168
  end
169
169
 
170
- def expired?
171
- @time < Time.now - 24 * 60 * 60
170
+ def expired?(hours = 24)
171
+ @time < Time.now - hours * 60 * 60
172
172
  end
173
173
 
174
174
  def prefix
@@ -23,5 +23,5 @@
23
23
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
24
24
  # License:: MIT
25
25
  module Zold
26
- VERSION = '0.11.14'.freeze
26
+ VERSION = '0.11.15'.freeze
27
27
  end
@@ -160,8 +160,10 @@ module Zold
160
160
  end
161
161
 
162
162
  def lines
163
- raise "File '#{@file}' is absent" unless File.exist?(@file)
164
- AtomicFile.new(@file).read.split(/\n/)
163
+ raise "Wallet file '#{@file}' is absent" unless File.exist?(@file)
164
+ lines = AtomicFile.new(@file).read.split(/\n/)
165
+ raise "Not enough lines in #{@file}, just #{lines.count}" if lines.count < 4
166
+ lines
165
167
  end
166
168
  end
167
169
  end
@@ -79,4 +79,31 @@ class TestMerge < Minitest::Test
79
79
  assert(wallet.id, modified[0])
80
80
  end
81
81
  end
82
+
83
+ def test_merges_with_a_broken_copy
84
+ FakeHome.new.run do |home|
85
+ wallet = home.create_wallet
86
+ copies = home.copies(wallet)
87
+ copies.add(File.read(wallet.path), 'good-host', 80, 5)
88
+ copies.add('some garbage', 'bad-host', 80, 5)
89
+ modified = Zold::Merge.new(wallets: home.wallets, copies: copies.root, log: test_log).run(
90
+ ['merge', wallet.id.to_s]
91
+ )
92
+ assert(modified.empty?)
93
+ end
94
+ end
95
+
96
+ def test_merges_a_copy_on_top
97
+ FakeHome.new.run do |home|
98
+ wallet = home.create_wallet
99
+ copies = home.copies(wallet)
100
+ copies.add(File.read(wallet.path), 'good-host', 80, 5)
101
+ key = Zold::Key.new(file: 'fixtures/id_rsa')
102
+ wallet.sub(Zold::Amount.new(zld: 9.99), "NOPREFIX@#{Zold::Id.new}", key)
103
+ Zold::Merge.new(wallets: home.wallets, copies: copies.root, log: test_log).run(
104
+ ['merge', wallet.id.to_s]
105
+ )
106
+ assert(!wallet.balance.zero?)
107
+ end
108
+ end
82
109
  end
@@ -46,9 +46,13 @@ class TestPatch < Minitest::Test
46
46
  t = third.sub(Zold::Amount.new(zld: 10.0), "NOPREFIX@#{Zold::Id.new}", key)
47
47
  third.add(t.inverse(first.id))
48
48
  patch = Zold::Patch.new
49
- patch.start(first)
50
- patch.join(second)
51
- patch.join(third)
49
+ begin
50
+ patch.join(first)
51
+ patch.join(second)
52
+ patch.join(third)
53
+ rescue StandardError => e
54
+ test_log.info("Ignore it: #{e.message}")
55
+ end
52
56
  FileUtils.rm(first.path)
53
57
  assert_equal(true, patch.save(first.path))
54
58
  assert_equal(Zold::Amount.new(zld: -53.0), first.balance)
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.11.14
4
+ version: 0.11.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko