zold 0.15.0 → 0.16.0
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 +4 -4
- data/.gitignore +1 -0
- data/bin/zold +9 -6
- data/features/gem_package.feature +1 -1
- data/features/step_definitions/steps.rb +2 -2
- data/fixtures/merge/into-no-wallet/assert.rb +1 -1
- data/fixtures/merge/random-expenses/assert.rb +1 -1
- data/fixtures/merge/simple-case/assert.rb +1 -1
- data/lib/zold/age.rb +16 -8
- data/lib/zold/amount.rb +4 -2
- data/lib/zold/cached_wallets.rb +5 -6
- data/lib/zold/commands/clean.rb +15 -8
- data/lib/zold/commands/diff.rb +3 -3
- data/lib/zold/commands/fetch.rb +4 -4
- data/lib/zold/commands/list.rb +5 -4
- data/lib/zold/commands/merge.rb +2 -1
- data/lib/zold/commands/node.rb +14 -12
- data/lib/zold/commands/propagate.rb +2 -2
- data/lib/zold/commands/push.rb +3 -3
- data/lib/zold/commands/remove.rb +4 -1
- data/lib/zold/commands/routines/reconnect.rb +1 -0
- data/lib/zold/copies.rb +13 -14
- data/lib/zold/dir_items.rb +44 -0
- data/lib/zold/head.rb +1 -1
- data/lib/zold/key.rb +2 -2
- data/lib/zold/log.rb +2 -0
- data/lib/zold/node/async_entrance.rb +38 -28
- data/lib/zold/node/entrance.rb +4 -11
- data/lib/zold/node/farm.rb +9 -9
- data/lib/zold/node/front.rb +40 -25
- data/lib/zold/node/nodup_entrance.rb +4 -4
- data/lib/zold/node/safe_entrance.rb +2 -2
- data/lib/zold/node/spread_entrance.rb +5 -9
- data/lib/zold/node/sync_entrance.rb +2 -23
- data/lib/zold/patch.rb +2 -2
- data/lib/zold/remotes.rb +10 -6
- data/lib/zold/sync_wallets.rb +3 -22
- data/lib/zold/tree_wallets.rb +11 -6
- data/lib/zold/txns.rb +1 -1
- data/lib/zold/version.rb +1 -1
- data/lib/zold/wallet.rb +14 -5
- data/lib/zold/wallets.rb +5 -4
- data/test/commands/routines/test_spread.rb +1 -1
- data/test/commands/test_alias.rb +4 -4
- data/test/commands/test_clean.rb +14 -1
- data/test/commands/test_create.rb +2 -2
- data/test/commands/test_diff.rb +5 -5
- data/test/commands/test_fetch.rb +2 -2
- data/test/commands/test_merge.rb +19 -19
- data/test/commands/test_node.rb +1 -1
- data/test/commands/test_pay.rb +7 -6
- data/test/commands/test_propagate.rb +2 -1
- data/test/commands/test_pull.rb +1 -1
- data/test/commands/test_push.rb +1 -1
- data/test/commands/test_remove.rb +57 -0
- data/test/commands/test_taxes.rb +1 -1
- data/test/fake_home.rb +11 -8
- data/test/node/fake_node.rb +2 -2
- data/test/node/test_async_entrance.rb +24 -8
- data/test/node/test_emission.rb +2 -2
- data/test/node/test_entrance.rb +8 -6
- data/test/node/test_farm.rb +1 -1
- data/test/node/test_front.rb +42 -33
- data/test/node/test_nodup_entrance.rb +2 -2
- data/test/node/test_safe_entrance.rb +5 -5
- data/test/node/test_spread_entrance.rb +3 -3
- data/test/node/test_sync_entrance.rb +1 -1
- data/test/test__helper.rb +3 -29
- data/test/test_cached_wallets.rb +1 -1
- data/test/test_copies.rb +4 -2
- data/test/test_dir_items.rb +88 -0
- data/test/test_key.rb +2 -2
- data/test/test_log.rb +38 -0
- data/test/test_patch.rb +11 -11
- data/test/test_prefixes.rb +1 -1
- data/test/test_remotes.rb +12 -6
- data/test/test_sync_wallets.rb +6 -6
- data/test/test_tax.rb +4 -4
- data/test/test_tree_wallets.rb +16 -2
- data/test/test_wallet.rb +26 -26
- data/test/test_wallets.rb +5 -2
- data/test/test_zold.rb +2 -2
- data/test/upgrades/test_protocol_up.rb +1 -1
- data/upgrades/move_wallets_into_tree.rb +1 -1
- data/upgrades/protocol_up.rb +3 -3
- data/upgrades/rename_foreign_wallets.rb +1 -1
- data/zold.gemspec +27 -25
- metadata +91 -56
| @@ -54,13 +54,13 @@ module Zold | |
| 54 54 | 
             
                  raise 'Id can\'t be nil' if id.nil?
         | 
| 55 55 | 
             
                  raise 'Id must be of type Id' unless id.is_a?(Id)
         | 
| 56 56 | 
             
                  raise 'Body can\'t be nil' if body.nil?
         | 
| 57 | 
            -
                  Tempfile.open(['', Wallet:: | 
| 58 | 
            -
                     | 
| 57 | 
            +
                  Tempfile.open(['', Wallet::EXT]) do |f|
         | 
| 58 | 
            +
                    IO.write(f, body)
         | 
| 59 59 | 
             
                    wallet = Wallet.new(f.path)
         | 
| 60 60 | 
             
                    wallet.refurbish
         | 
| 61 | 
            -
                    after =  | 
| 61 | 
            +
                    after = IO.read(wallet.path)
         | 
| 62 62 | 
             
                    before = @wallets.find(id) do |w|
         | 
| 63 | 
            -
                      w.exists? ?  | 
| 63 | 
            +
                      w.exists? ? IO.read(w.path).to_s : ''
         | 
| 64 64 | 
             
                    end
         | 
| 65 65 | 
             
                    if before == after
         | 
| 66 66 | 
             
                      @log.info(
         | 
| @@ -58,8 +58,8 @@ module Zold | |
| 58 58 | 
             
                  raise 'Id can\'t be nil' if id.nil?
         | 
| 59 59 | 
             
                  raise 'Id must be of type Id' unless id.is_a?(Id)
         | 
| 60 60 | 
             
                  raise 'Body can\'t be nil' if body.nil?
         | 
| 61 | 
            -
                  Tempfile.open(['', Wallet:: | 
| 62 | 
            -
                     | 
| 61 | 
            +
                  Tempfile.open(['', Wallet::EXT]) do |f|
         | 
| 62 | 
            +
                    IO.write(f, body)
         | 
| 63 63 | 
             
                    wallet = Wallet.new(f.path)
         | 
| 64 64 | 
             
                    wallet.refurbish
         | 
| 65 65 | 
             
                    unless wallet.protocol == Zold::PROTOCOL
         | 
| @@ -21,6 +21,7 @@ | |
| 21 21 | 
             
            # SOFTWARE.
         | 
| 22 22 |  | 
| 23 23 | 
             
            require 'concurrent'
         | 
| 24 | 
            +
            require 'concurrent/set'
         | 
| 24 25 | 
             
            require 'tempfile'
         | 
| 25 26 | 
             
            require_relative 'emission'
         | 
| 26 27 | 
             
            require_relative '../log'
         | 
| @@ -40,17 +41,10 @@ module Zold | |
| 40 41 | 
             
              # The entrance
         | 
| 41 42 | 
             
              class SpreadEntrance
         | 
| 42 43 | 
             
                def initialize(entrance, wallets, remotes, address, log: Log::Quiet.new, ignore_score_weakeness: false)
         | 
| 43 | 
            -
                  raise 'Entrance can\'t be nil' if entrance.nil?
         | 
| 44 44 | 
             
                  @entrance = entrance
         | 
| 45 | 
            -
                  raise 'Wallets can\'t be nil' if wallets.nil?
         | 
| 46 | 
            -
                  raise 'Wallets must implement the contract of Wallets: method #find is required' unless wallets.respond_to?(:find)
         | 
| 47 45 | 
             
                  @wallets = wallets
         | 
| 48 | 
            -
                  raise 'Remotes can\'t be nil' if remotes.nil?
         | 
| 49 | 
            -
                  raise 'Remotes must be of type Remotes' unless remotes.is_a?(Remotes)
         | 
| 50 46 | 
             
                  @remotes = remotes
         | 
| 51 | 
            -
                  raise 'Address can\'t be nil' if address.nil?
         | 
| 52 47 | 
             
                  @address = address
         | 
| 53 | 
            -
                  raise 'Log can\'t be nil' if log.nil?
         | 
| 54 48 | 
             
                  @log = log
         | 
| 55 49 | 
             
                  @ignore_score_weakeness = ignore_score_weakeness
         | 
| 56 50 | 
             
                end
         | 
| @@ -64,7 +58,7 @@ module Zold | |
| 64 58 |  | 
| 65 59 | 
             
                def start
         | 
| 66 60 | 
             
                  @entrance.start do
         | 
| 67 | 
            -
                    @seen = Set.new
         | 
| 61 | 
            +
                    @seen = Concurrent::Set.new
         | 
| 68 62 | 
             
                    @modified = Queue.new
         | 
| 69 63 | 
             
                    @push = Thread.start do
         | 
| 70 64 | 
             
                      Thread.current.abort_on_exception = true
         | 
| @@ -95,13 +89,15 @@ module Zold | |
| 95 89 | 
             
                  end
         | 
| 96 90 | 
             
                end
         | 
| 97 91 |  | 
| 92 | 
            +
                # This method is thread-safe
         | 
| 98 93 | 
             
                def push(id, body)
         | 
| 99 94 | 
             
                  mods = @entrance.push(id, body)
         | 
| 95 | 
            +
                  return mods if @remotes.all.empty?
         | 
| 100 96 | 
             
                  (mods + [id]).each do |m|
         | 
| 101 97 | 
             
                    next if @seen.include?(m)
         | 
| 102 98 | 
             
                    @seen << m
         | 
| 103 99 | 
             
                    @modified.push(m)
         | 
| 104 | 
            -
                    @log.debug(" | 
| 100 | 
            +
                    @log.debug("Spread-push scheduled for #{m}, queue size is #{@modified.size}")
         | 
| 105 101 | 
             
                  end
         | 
| 106 102 | 
             
                  mods
         | 
| 107 103 | 
             
                end
         | 
| @@ -21,6 +21,7 @@ | |
| 21 21 | 
             
            # SOFTWARE.
         | 
| 22 22 |  | 
| 23 23 | 
             
            require 'concurrent'
         | 
| 24 | 
            +
            require 'futex'
         | 
| 24 25 | 
             
            require_relative '../log'
         | 
| 25 26 | 
             
            require_relative '../id'
         | 
| 26 27 | 
             
            require_relative '../verbose_thread'
         | 
| @@ -33,12 +34,9 @@ module Zold | |
| 33 34 | 
             
              # The entrance that makes sure only one thread works with a wallet
         | 
| 34 35 | 
             
              class SyncEntrance
         | 
| 35 36 | 
             
                def initialize(entrance, dir, timeout: 30, log: Log::Quiet.new)
         | 
| 36 | 
            -
                  raise 'Entrance can\'t be nil' if entrance.nil?
         | 
| 37 37 | 
             
                  @entrance = entrance
         | 
| 38 | 
            -
                  raise 'Dir can\'t be nil' if dir.nil?
         | 
| 39 38 | 
             
                  @dir = dir
         | 
| 40 39 | 
             
                  @timeout = timeout
         | 
| 41 | 
            -
                  raise 'Log can\'t be nil' if log.nil?
         | 
| 42 40 | 
             
                  @log = log
         | 
| 43 41 | 
             
                end
         | 
| 44 42 |  | 
| @@ -54,26 +52,7 @@ module Zold | |
| 54 52 |  | 
| 55 53 | 
             
                # Always returns an array with a single ID of the pushed wallet
         | 
| 56 54 | 
             
                def push(id, body)
         | 
| 57 | 
            -
                   | 
| 58 | 
            -
                  FileUtils.mkdir_p(File.dirname(f))
         | 
| 59 | 
            -
                  File.open(f, File::RDWR | File::CREAT) do |lock|
         | 
| 60 | 
            -
                    start = Time.now
         | 
| 61 | 
            -
                    cycles = 0
         | 
| 62 | 
            -
                    loop do
         | 
| 63 | 
            -
                      break if lock.flock(File::LOCK_EX | File::LOCK_NB)
         | 
| 64 | 
            -
                      sleep 0.1
         | 
| 65 | 
            -
                      cycles += 1
         | 
| 66 | 
            -
                      delay = Time.now - start
         | 
| 67 | 
            -
                      if delay > @timeout
         | 
| 68 | 
            -
                        raise "##{Process.pid}/#{Thread.current.name} can't get exclusive access to the wallet #{id}/e \
         | 
| 69 | 
            -
            because of the lock at #{lock.path}: #{File.read(lock)}"
         | 
| 70 | 
            -
                      end
         | 
| 71 | 
            -
                      if (cycles % 20).zero? && delay > 10
         | 
| 72 | 
            -
                        @log.info("##{Process.pid}/#{Thread.current.name} still waiting for \
         | 
| 73 | 
            -
            exclusive access to #{id}/e, #{delay.round}s already")
         | 
| 74 | 
            -
                      end
         | 
| 75 | 
            -
                    end
         | 
| 76 | 
            -
                    File.write(lock, "##{Process.pid}/#{Thread.current.name}/#{Time.now.utc.iso8601}")
         | 
| 55 | 
            +
                  Futex.new(File.join(@dir, id), log: @log).open do
         | 
| 77 56 | 
             
                    @entrance.push(id, body)
         | 
| 78 57 | 
             
                  end
         | 
| 79 58 | 
             
                end
         | 
    
        data/lib/zold/patch.rb
    CHANGED
    
    | @@ -119,7 +119,7 @@ among #{payer.txns.count} transactions: #{txn.to_text}") | |
| 119 119 | 
             
                def save(file, overwrite: false)
         | 
| 120 120 | 
             
                  raise 'You have to join at least one wallet in' if @id.nil?
         | 
| 121 121 | 
             
                  before = ''
         | 
| 122 | 
            -
                  before =  | 
| 122 | 
            +
                  before = IO.read(file) if File.exist?(file)
         | 
| 123 123 | 
             
                  wallet = Wallet.new(file)
         | 
| 124 124 | 
             
                  wallet.init(@id, @key, overwrite: overwrite, network: @network)
         | 
| 125 125 | 
             
                  File.open(file, 'a') do |f|
         | 
| @@ -128,7 +128,7 @@ among #{payer.txns.count} transactions: #{txn.to_text}") | |
| 128 128 | 
             
                    end
         | 
| 129 129 | 
             
                  end
         | 
| 130 130 | 
             
                  wallet.refurbish
         | 
| 131 | 
            -
                  after =  | 
| 131 | 
            +
                  after = IO.read(file)
         | 
| 132 132 | 
             
                  before != after
         | 
| 133 133 | 
             
                end
         | 
| 134 134 | 
             
              end
         | 
    
        data/lib/zold/remotes.rb
    CHANGED
    
    | @@ -25,6 +25,7 @@ require 'csv' | |
| 25 25 | 
             
            require 'uri'
         | 
| 26 26 | 
             
            require 'net/http'
         | 
| 27 27 | 
             
            require 'time'
         | 
| 28 | 
            +
            require 'futex'
         | 
| 28 29 | 
             
            require 'fileutils'
         | 
| 29 30 | 
             
            require 'backtrace'
         | 
| 30 31 | 
             
            require_relative 'age'
         | 
| @@ -52,10 +53,13 @@ module Zold | |
| 52 53 | 
             
                attribute :file, Types::Strict::String
         | 
| 53 54 | 
             
                attribute :network, Types::Strict::String.optional.default('test')
         | 
| 54 55 | 
             
                attribute :timeout, Types::Strict::Integer.optional.default(16)
         | 
| 55 | 
            -
                attribute :mutex, Types::Object.optional.default(Mutex.new)
         | 
| 56 56 |  | 
| 57 57 | 
             
                # Empty, for standalone mode
         | 
| 58 | 
            -
                class Empty | 
| 58 | 
            +
                class Empty
         | 
| 59 | 
            +
                  def initialize
         | 
| 60 | 
            +
                    # Nothing to init here
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 59 63 | 
             
                  def all
         | 
| 60 64 | 
             
                    []
         | 
| 61 65 | 
             
                  end
         | 
| @@ -131,7 +135,7 @@ module Zold | |
| 131 135 | 
             
                end
         | 
| 132 136 |  | 
| 133 137 | 
             
                def defaults
         | 
| 134 | 
            -
                  other = Remotes.new(file: File.join(File.dirname(__FILE__), '../../resources/remotes'))
         | 
| 138 | 
            +
                  other = Remotes.new(file: File.expand_path(File.join(File.dirname(__FILE__), '../../resources/remotes')))
         | 
| 135 139 | 
             
                  other.all.each do |r|
         | 
| 136 140 | 
             
                    add(r[:host], r[:port])
         | 
| 137 141 | 
             
                  end
         | 
| @@ -220,13 +224,13 @@ module Zold | |
| 220 224 | 
             
                end
         | 
| 221 225 |  | 
| 222 226 | 
             
                def mtime
         | 
| 223 | 
            -
                  File.mtime(file)
         | 
| 227 | 
            +
                  File.exist?(file) ? File.mtime(file) : Time.now
         | 
| 224 228 | 
             
                end
         | 
| 225 229 |  | 
| 226 230 | 
             
                private
         | 
| 227 231 |  | 
| 228 232 | 
             
                def modify
         | 
| 229 | 
            -
                   | 
| 233 | 
            +
                  Futex.new(file).open do
         | 
| 230 234 | 
             
                    save(yield(load))
         | 
| 231 235 | 
             
                  end
         | 
| 232 236 | 
             
                end
         | 
| @@ -261,7 +265,7 @@ module Zold | |
| 261 265 |  | 
| 262 266 | 
             
                def save(list)
         | 
| 263 267 | 
             
                  FileUtils.mkdir_p(File.dirname(file))
         | 
| 264 | 
            -
                   | 
| 268 | 
            +
                  IO.write(
         | 
| 265 269 | 
             
                    file,
         | 
| 266 270 | 
             
                    list.uniq { |r| "#{r[:host]}:#{r[:port]}" }.map do |r|
         | 
| 267 271 | 
             
                      [
         | 
    
        data/lib/zold/sync_wallets.rb
    CHANGED
    
    | @@ -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 'futex'
         | 
| 23 24 | 
             
            require_relative 'log'
         | 
| 24 25 |  | 
| 25 26 | 
             
            # Sync collection of wallets.
         | 
| @@ -29,9 +30,8 @@ require_relative 'log' | |
| 29 30 | 
             
            module Zold
         | 
| 30 31 | 
             
              # Synchronized collection of wallets
         | 
| 31 32 | 
             
              class SyncWallets
         | 
| 32 | 
            -
                def initialize(wallets,  | 
| 33 | 
            +
                def initialize(wallets, timeout: 30, log: Log::Quiet.new)
         | 
| 33 34 | 
             
                  @wallets = wallets
         | 
| 34 | 
            -
                  @dir = dir
         | 
| 35 35 | 
             
                  @log = log
         | 
| 36 36 | 
             
                  @timeout = timeout
         | 
| 37 37 | 
             
                end
         | 
| @@ -50,26 +50,7 @@ module Zold | |
| 50 50 |  | 
| 51 51 | 
             
                def find(id)
         | 
| 52 52 | 
             
                  @wallets.find(id) do |wallet|
         | 
| 53 | 
            -
                     | 
| 54 | 
            -
                    FileUtils.mkdir_p(File.dirname(f))
         | 
| 55 | 
            -
                    File.open(f, File::RDWR | File::CREAT) do |lock|
         | 
| 56 | 
            -
                      start = Time.now
         | 
| 57 | 
            -
                      cycles = 0
         | 
| 58 | 
            -
                      loop do
         | 
| 59 | 
            -
                        break if lock.flock(File::LOCK_EX | File::LOCK_NB)
         | 
| 60 | 
            -
                        sleep 0.1
         | 
| 61 | 
            -
                        cycles += 1
         | 
| 62 | 
            -
                        delay = (Time.now - start).round(2)
         | 
| 63 | 
            -
                        if delay > @timeout
         | 
| 64 | 
            -
                          raise "##{Process.pid}/#{Thread.current.name} can't get exclusive access to the wallet #{id} \
         | 
| 65 | 
            -
            because of the lock at #{lock.path}, after #{delay}s of waiting: #{File.read(lock)}"
         | 
| 66 | 
            -
                        end
         | 
| 67 | 
            -
                        if (cycles % 20).zero? && delay > 10
         | 
| 68 | 
            -
                          @log.info("##{Process.pid}/#{Thread.current.name} still waiting for \
         | 
| 69 | 
            -
            exclusive access to #{id}, #{delay.round}s already: #{File.read(lock)}")
         | 
| 70 | 
            -
                        end
         | 
| 71 | 
            -
                      end
         | 
| 72 | 
            -
                      File.write(lock, "##{Process.pid}/#{Thread.current.name}")
         | 
| 53 | 
            +
                    Futex.new(wallet.path, log: @log).open do
         | 
| 73 54 | 
             
                      yield wallet
         | 
| 74 55 | 
             
                    end
         | 
| 75 56 | 
             
                  end
         | 
    
        data/lib/zold/tree_wallets.rb
    CHANGED
    
    | @@ -22,6 +22,7 @@ | |
| 22 22 | 
             
            require 'pathname'
         | 
| 23 23 | 
             
            require_relative 'id'
         | 
| 24 24 | 
             
            require_relative 'wallet'
         | 
| 25 | 
            +
            require_relative 'dir_items'
         | 
| 25 26 |  | 
| 26 27 | 
             
            # The local collection of wallets.
         | 
| 27 28 | 
             
            # Author:: Yegor Bugayenko (yegor256@gmail.com)
         | 
| @@ -45,19 +46,23 @@ module Zold | |
| 45 46 |  | 
| 46 47 | 
             
                # Returns the list of their IDs (as plain text)
         | 
| 47 48 | 
             
                def all
         | 
| 48 | 
            -
                   | 
| 49 | 
            -
                     | 
| 50 | 
            -
                    File. | 
| 51 | 
            -
             | 
| 49 | 
            +
                  DirItems.new(path).fetch.select do |f|
         | 
| 50 | 
            +
                    next unless f.end_with?(Wallet::EXT)
         | 
| 51 | 
            +
                    basename = File.basename(f, Wallet::EXT)
         | 
| 52 | 
            +
                    file = File.join(path, f)
         | 
| 53 | 
            +
                    File.file?(file) &&
         | 
| 54 | 
            +
                      !File.directory?(file) &&
         | 
| 52 55 | 
             
                      basename =~ /^[0-9a-fA-F]{16}$/ &&
         | 
| 53 56 | 
             
                      Id.new(basename).to_s == basename
         | 
| 54 | 
            -
                  end.map { |w| Id.new(File.basename(w, Wallet:: | 
| 57 | 
            +
                  end.map { |w| Id.new(File.basename(w, Wallet::EXT)) }
         | 
| 55 58 | 
             
                end
         | 
| 56 59 |  | 
| 57 60 | 
             
                def find(id)
         | 
| 58 61 | 
             
                  raise 'Id can\'t be nil' if id.nil?
         | 
| 59 62 | 
             
                  raise 'Id must be of type Id' unless id.is_a?(Id)
         | 
| 60 | 
            -
                  yield  | 
| 63 | 
            +
                  yield Wallet.new(
         | 
| 64 | 
            +
                    File.join(path, (id.to_s.split('', 5).take(4) + [id.to_s]).join('/') + Wallet::EXT)
         | 
| 65 | 
            +
                  )
         | 
| 61 66 | 
             
                end
         | 
| 62 67 | 
             
              end
         | 
| 63 68 | 
             
            end
         | 
    
        data/lib/zold/txns.rb
    CHANGED
    
    | @@ -39,7 +39,7 @@ module Zold | |
| 39 39 |  | 
| 40 40 | 
             
                def fetch
         | 
| 41 41 | 
             
                  raise "Wallet file '#{@file}' is absent" unless File.exist?(@file)
         | 
| 42 | 
            -
                  lines =  | 
| 42 | 
            +
                  lines = IO.read(@file).split(/\n/)
         | 
| 43 43 | 
             
                  raise "Not enough lines in #{@file}, just #{lines.count}" if lines.count < 4
         | 
| 44 44 | 
             
                  lines.drop(5)
         | 
| 45 45 | 
             
                    .each_with_index
         | 
    
        data/lib/zold/version.rb
    CHANGED
    
    
    
        data/lib/zold/wallet.rb
    CHANGED
    
    | @@ -27,6 +27,7 @@ require_relative 'key' | |
| 27 27 | 
             
            require_relative 'id'
         | 
| 28 28 | 
             
            require_relative 'txn'
         | 
| 29 29 | 
             
            require_relative 'tax'
         | 
| 30 | 
            +
            require_relative 'copies'
         | 
| 30 31 | 
             
            require_relative 'amount'
         | 
| 31 32 | 
             
            require_relative 'hexnum'
         | 
| 32 33 | 
             
            require_relative 'signature'
         | 
| @@ -50,10 +51,13 @@ module Zold | |
| 50 51 | 
             
                MAIN_NETWORK = 'zold'
         | 
| 51 52 |  | 
| 52 53 | 
             
                # The extension of the wallet files
         | 
| 53 | 
            -
                 | 
| 54 | 
            +
                EXT = '.z'
         | 
| 54 55 |  | 
| 55 56 | 
             
                def initialize(file)
         | 
| 56 | 
            -
                   | 
| 57 | 
            +
                  unless file.end_with?(Wallet::EXT, Copies::EXT)
         | 
| 58 | 
            +
                    raise "Wallet file must end with #{Wallet::EXT} or #{Copies::EXT}: #{file}"
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                  @file = File.absolute_path(file)
         | 
| 57 61 | 
             
                  @txns = Txns::Cached.new(Txns.new(@file))
         | 
| 58 62 | 
             
                  @head = Head::Cached.new(Head.new(@file))
         | 
| 59 63 | 
             
                end
         | 
| @@ -90,7 +94,7 @@ module Zold | |
| 90 94 | 
             
                  raise "File '#{@file}' already exists" if File.exist?(@file) && !overwrite
         | 
| 91 95 | 
             
                  raise "Invalid network name '#{network}'" unless network =~ /^[a-z]{4,16}$/
         | 
| 92 96 | 
             
                  FileUtils.mkdir_p(File.dirname(@file))
         | 
| 93 | 
            -
                   | 
| 97 | 
            +
                  IO.write(@file, "#{network}\n#{PROTOCOL}\n#{id}\n#{pubkey.to_pub}\n\n")
         | 
| 94 98 | 
             
                  @txns.flush
         | 
| 95 99 | 
             
                  @head.flush
         | 
| 96 100 | 
             
                end
         | 
| @@ -173,7 +177,7 @@ module Zold | |
| 173 177 | 
             
                end
         | 
| 174 178 |  | 
| 175 179 | 
             
                def digest
         | 
| 176 | 
            -
                  OpenSSL::Digest::SHA256.new( | 
| 180 | 
            +
                  OpenSSL::Digest::SHA256.new(IO.read(@file)).hexdigest
         | 
| 177 181 | 
             
                end
         | 
| 178 182 |  | 
| 179 183 | 
             
                # Age of wallet in hours
         | 
| @@ -187,13 +191,18 @@ module Zold | |
| 187 191 | 
             
                end
         | 
| 188 192 |  | 
| 189 193 | 
             
                def refurbish
         | 
| 190 | 
            -
                   | 
| 194 | 
            +
                  IO.write(
         | 
| 191 195 | 
             
                    @file,
         | 
| 192 196 | 
             
                    "#{network}\n#{protocol}\n#{id}\n#{key.to_pub}\n\n#{txns.map { |t| t.to_s + "\n" }.join}"
         | 
| 193 197 | 
             
                  )
         | 
| 194 198 | 
             
                  @txns.flush
         | 
| 195 199 | 
             
                end
         | 
| 196 200 |  | 
| 201 | 
            +
                def flush
         | 
| 202 | 
            +
                  @head.flush
         | 
| 203 | 
            +
                  @txns.flush
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
             | 
| 197 206 | 
             
                private
         | 
| 198 207 |  | 
| 199 208 | 
             
                def max
         | 
    
        data/lib/zold/wallets.rb
    CHANGED
    
    | @@ -22,6 +22,7 @@ | |
| 22 22 | 
             
            require 'pathname'
         | 
| 23 23 | 
             
            require_relative 'id'
         | 
| 24 24 | 
             
            require_relative 'wallet'
         | 
| 25 | 
            +
            require_relative 'dir_items'
         | 
| 25 26 |  | 
| 26 27 | 
             
            # The local collection of wallets.
         | 
| 27 28 | 
             
            # Author:: Yegor Bugayenko (yegor256@gmail.com)
         | 
| @@ -50,20 +51,20 @@ module Zold | |
| 50 51 |  | 
| 51 52 | 
             
                # Returns the list of their IDs (as plain text)
         | 
| 52 53 | 
             
                def all
         | 
| 53 | 
            -
                   | 
| 54 | 
            +
                  DirItems.new(path).fetch(recursive: false).select do |f|
         | 
| 54 55 | 
             
                    file = File.join(@dir, f)
         | 
| 55 | 
            -
                    basename = File.basename(f, Wallet:: | 
| 56 | 
            +
                    basename = File.basename(f, Wallet::EXT)
         | 
| 56 57 | 
             
                    File.file?(file) &&
         | 
| 57 58 | 
             
                      !File.directory?(file) &&
         | 
| 58 59 | 
             
                      basename =~ /^[0-9a-fA-F]{16}$/ &&
         | 
| 59 60 | 
             
                      Id.new(basename).to_s == basename
         | 
| 60 | 
            -
                  end.map { |w| Id.new(File.basename(w, Wallet:: | 
| 61 | 
            +
                  end.map { |w| Id.new(File.basename(w, Wallet::EXT)) }
         | 
| 61 62 | 
             
                end
         | 
| 62 63 |  | 
| 63 64 | 
             
                def find(id)
         | 
| 64 65 | 
             
                  raise 'Id can\'t be nil' if id.nil?
         | 
| 65 66 | 
             
                  raise "Id must be of type Id, #{id.class.name} instead" unless id.is_a?(Id)
         | 
| 66 | 
            -
                  yield  | 
| 67 | 
            +
                  yield Wallet.new(File.join(path, id.to_s + Wallet::EXT))
         | 
| 67 68 | 
             
                end
         | 
| 68 69 | 
             
              end
         | 
| 69 70 | 
             
            end
         | 
| @@ -34,7 +34,7 @@ require_relative '../../../lib/zold/node/entrance.rb' | |
| 34 34 | 
             
            # License:: MIT
         | 
| 35 35 | 
             
            class TestSpread < Minitest::Test
         | 
| 36 36 | 
             
              def test_spread_wallets
         | 
| 37 | 
            -
                FakeHome.new.run do |home|
         | 
| 37 | 
            +
                FakeHome.new(log: test_log).run do |home|
         | 
| 38 38 | 
             
                  5.times { home.create_wallet }
         | 
| 39 39 | 
             
                  opts = {
         | 
| 40 40 | 
             
                    'routine-immediately' => true
         | 
    
        data/test/commands/test_alias.rb
    CHANGED
    
    | @@ -11,7 +11,7 @@ class TestAlias < Minitest::Test | |
| 11 11 | 
             
              #  The syntax is already documented in the alias command in the help.
         | 
| 12 12 | 
             
              def test_set_writes_alias_to_the_alias_file
         | 
| 13 13 | 
             
                skip
         | 
| 14 | 
            -
                FakeHome.new.run do |home|
         | 
| 14 | 
            +
                FakeHome.new(log: test_log).run do |home|
         | 
| 15 15 | 
             
                  wallet = home.create_wallet
         | 
| 16 16 | 
             
                  Zold::Alias.new(wallets: home.wallets, log: test_log).run(%W[set #{wallet.id} my-alias])
         | 
| 17 17 | 
             
                  assert_equal read_alias_file(home), %W[my-alias #{wallet.id}]
         | 
| @@ -23,7 +23,7 @@ class TestAlias < Minitest::Test | |
| 23 23 | 
             
              #  The syntax is already documented in the alias command in the help.
         | 
| 24 24 | 
             
              def test_remove_removes_the_alias_from_the_alias_file
         | 
| 25 25 | 
             
                skip
         | 
| 26 | 
            -
                FakeHome.new.run do |home|
         | 
| 26 | 
            +
                FakeHome.new(log: test_log).run do |home|
         | 
| 27 27 | 
             
                  wallet = home.create_wallet
         | 
| 28 28 | 
             
                  cmd = Zold::Alias.new(wallets: home.wallets, log: test_log)
         | 
| 29 29 | 
             
                  cmd.run(%W[set #{wallet.id} my-alias])
         | 
| @@ -38,7 +38,7 @@ class TestAlias < Minitest::Test | |
| 38 38 | 
             
              #  The syntax is already documented in the alias command in the help.
         | 
| 39 39 | 
             
              def test_show_prints_out_the_aliased_wallet_id
         | 
| 40 40 | 
             
                skip
         | 
| 41 | 
            -
                FakeHome.new.run do |home|
         | 
| 41 | 
            +
                FakeHome.new(log: test_log).run do |home|
         | 
| 42 42 | 
             
                  wallet = home.create_wallet
         | 
| 43 43 | 
             
                  cmd = Zold::Alias.new(wallets: home.wallets, log: test_log)
         | 
| 44 44 | 
             
                  cmd.run(%W[set #{wallet.id} my-alias])
         | 
| @@ -51,6 +51,6 @@ class TestAlias < Minitest::Test | |
| 51 51 | 
             
              private
         | 
| 52 52 |  | 
| 53 53 | 
             
              def read_alias_file(home)
         | 
| 54 | 
            -
                 | 
| 54 | 
            +
                IO.read(File.join(home.dir, 'aliases')).split(' ')
         | 
| 55 55 | 
             
              end
         | 
| 56 56 | 
             
            end
         |