zold 0.31.8 → 0.31.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.0pdd.yml +20 -0
- data/.github/workflows/actionlint.yml +41 -0
- data/.github/workflows/codecov.yml +23 -4
- data/.github/workflows/copyrights.yml +30 -0
- data/.github/workflows/pdd.yml +26 -3
- data/.github/workflows/rake.yml +24 -2
- data/.github/workflows/xcop.yml +21 -2
- data/.github/workflows/yamllint.yml +34 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +21 -0
- data/.ruby-version +1 -1
- data/.rultor.yml +35 -5
- data/.simplecov +1 -1
- data/Dockerfile +28 -2
- data/Gemfile +11 -11
- data/Gemfile.lock +340 -0
- data/LICENSE.txt +1 -1
- data/Rakefile +9 -12
- data/bin/zold +1 -1
- data/cucumber.yml +20 -0
- data/deploy.sh +20 -0
- data/features/step_definitions/steps.rb +1 -1
- data/features/support/env.rb +1 -1
- data/fixtures/merge/asserts.rb +1 -1
- data/fixtures/merge/into_no_wallet/assert.rb +1 -1
- data/fixtures/merge/legacy_negatives_stay/assert.rb +1 -1
- data/fixtures/merge/missed_wallets/assert.rb +1 -1
- data/fixtures/merge/negative_overwriting/assert.rb +1 -1
- data/fixtures/merge/negatives_in_between/assert.rb +1 -1
- data/fixtures/merge/random_expenses/assert.rb +1 -1
- data/fixtures/merge/simple_case/assert.rb +1 -1
- data/fixtures/merge/unconfirmed_income/assert.rb +1 -1
- data/fixtures/scripts/_head.sh +21 -1
- data/fixtures/scripts/calculate-scores.sh +19 -0
- data/fixtures/scripts/distribute-wallet.sh +19 -0
- data/fixtures/scripts/print-helps.sh +19 -0
- data/fixtures/scripts/pull-on-start.sh +19 -0
- data/fixtures/scripts/push-and-pull.sh +19 -0
- data/fixtures/scripts/redeploy-on-upgrade.sh +19 -0
- data/fixtures/scripts/spread-wallets.sh +19 -0
- data/lib/zold/age.rb +2 -2
- data/lib/zold/amount.rb +2 -2
- data/lib/zold/cached_wallets.rb +3 -3
- data/lib/zold/commands/alias.rb +20 -0
- data/lib/zold/commands/args.rb +2 -2
- data/lib/zold/commands/calculate.rb +2 -2
- data/lib/zold/commands/clean.rb +2 -2
- data/lib/zold/commands/create.rb +2 -2
- data/lib/zold/commands/diff.rb +2 -2
- data/lib/zold/commands/fetch.rb +2 -2
- data/lib/zold/commands/invoice.rb +2 -2
- data/lib/zold/commands/list.rb +2 -2
- data/lib/zold/commands/merge.rb +2 -2
- data/lib/zold/commands/next.rb +2 -2
- data/lib/zold/commands/node.rb +2 -2
- data/lib/zold/commands/pay.rb +2 -2
- data/lib/zold/commands/propagate.rb +2 -2
- data/lib/zold/commands/pull.rb +2 -2
- data/lib/zold/commands/push.rb +2 -2
- data/lib/zold/commands/remote.rb +2 -2
- data/lib/zold/commands/remove.rb +2 -2
- data/lib/zold/commands/routines/audit.rb +2 -2
- data/lib/zold/commands/routines/gc.rb +2 -2
- data/lib/zold/commands/routines/reconcile.rb +2 -2
- data/lib/zold/commands/routines/reconnect.rb +2 -2
- data/lib/zold/commands/routines/retire.rb +2 -2
- data/lib/zold/commands/routines/spread.rb +2 -2
- data/lib/zold/commands/routines.rb +2 -2
- data/lib/zold/commands/show.rb +2 -2
- data/lib/zold/commands/taxes.rb +2 -2
- data/lib/zold/commands/thread_badge.rb +3 -3
- data/lib/zold/copies.rb +2 -2
- data/lib/zold/dir_items.rb +2 -2
- data/lib/zold/endless.rb +2 -2
- data/lib/zold/gem.rb +2 -2
- data/lib/zold/hands.rb +2 -2
- data/lib/zold/head.rb +3 -3
- data/lib/zold/hexnum.rb +2 -2
- data/lib/zold/http.rb +3 -3
- data/lib/zold/hungry_wallets.rb +2 -2
- data/lib/zold/id.rb +2 -2
- data/lib/zold/json_page.rb +2 -2
- data/lib/zold/key.rb +2 -2
- data/lib/zold/log.rb +2 -2
- data/lib/zold/metronome.rb +2 -2
- data/lib/zold/node/async_entrance.rb +2 -2
- data/lib/zold/node/entrance.rb +2 -2
- data/lib/zold/node/farm.rb +2 -2
- data/lib/zold/node/farmers.rb +2 -2
- data/lib/zold/node/front.rb +3 -3
- data/lib/zold/node/journaled_pipeline.rb +2 -2
- data/lib/zold/node/nodup_entrance.rb +2 -2
- data/lib/zold/node/nospam_entrance.rb +2 -2
- data/lib/zold/node/pipeline.rb +2 -2
- data/lib/zold/node/safe_entrance.rb +2 -2
- data/lib/zold/node/soft_error.rb +2 -2
- data/lib/zold/node/spread_entrance.rb +2 -2
- data/lib/zold/node/sync_entrance.rb +2 -2
- data/lib/zold/node/trace.rb +2 -2
- data/lib/zold/patch.rb +2 -2
- data/lib/zold/prefixes.rb +2 -2
- data/lib/zold/remotes.rb +2 -2
- data/lib/zold/signature.rb +2 -2
- data/lib/zold/size.rb +2 -2
- data/lib/zold/sync_wallets.rb +2 -2
- data/lib/zold/tax.rb +2 -2
- data/lib/zold/thread_pool.rb +2 -2
- data/lib/zold/tree_wallets.rb +2 -2
- data/lib/zold/txn.rb +2 -2
- data/lib/zold/txns.rb +3 -3
- data/lib/zold/upgrades.rb +1 -1
- data/lib/zold/verbose_thread.rb +2 -2
- data/lib/zold/version.rb +3 -3
- data/lib/zold/version_file.rb +1 -1
- data/lib/zold/wallet.rb +2 -2
- data/lib/zold/wallets.rb +2 -2
- data/lib/zold.rb +2 -2
- data/test/commands/routines/test_audit.rb +4 -4
- data/test/commands/routines/test_gc.rb +8 -8
- data/test/commands/routines/test_reconcile.rb +4 -4
- data/test/commands/routines/test_reconnect.rb +3 -3
- data/test/commands/routines/test_retire.rb +3 -3
- data/test/commands/test_alias.rb +26 -6
- data/test/commands/test_calculate.rb +3 -3
- data/test/commands/test_clean.rb +10 -10
- data/test/commands/test_create.rb +3 -3
- data/test/commands/test_diff.rb +5 -5
- data/test/commands/test_fetch.rb +9 -9
- data/test/commands/test_invoice.rb +3 -3
- data/test/commands/test_list.rb +3 -3
- data/test/commands/test_merge.rb +12 -12
- data/test/commands/test_node.rb +6 -6
- data/test/commands/test_pay.rb +19 -19
- data/test/commands/test_propagate.rb +5 -5
- data/test/commands/test_pull.rb +6 -6
- data/test/commands/test_push.rb +9 -9
- data/test/commands/test_remote.rb +11 -11
- data/test/commands/test_remove.rb +10 -10
- data/test/commands/test_show.rb +3 -3
- data/test/commands/test_taxes.rb +4 -4
- data/test/fake_home.rb +2 -2
- data/test/node/fake_entrance.rb +2 -2
- data/test/node/fake_node.rb +57 -40
- data/test/node/test_async_entrance.rb +10 -10
- data/test/node/test_entrance.rb +8 -8
- data/test/node/test_farm.rb +11 -11
- data/test/node/test_farmers.rb +5 -5
- data/test/node/test_front.rb +29 -28
- data/test/node/test_nodup_entrance.rb +4 -4
- data/test/node/test_nospam_entrance.rb +3 -3
- data/test/node/test_safe_entrance.rb +4 -4
- data/test/node/test_spread_entrance.rb +8 -8
- data/test/node/test_sync_entrance.rb +4 -4
- data/test/node/test_trace.rb +2 -2
- data/test/test__helper.rb +4 -4
- data/test/test_age.rb +2 -2
- data/test/test_amount.rb +2 -2
- data/test/test_cached_wallets.rb +2 -2
- data/test/test_copies.rb +12 -12
- data/test/test_dir_items.rb +4 -4
- data/test/test_gem.rb +20 -0
- data/test/test_hands.rb +2 -2
- data/test/test_hexnum.rb +2 -2
- data/test/test_http.rb +8 -8
- data/test/test_hungry_wallets.rb +11 -11
- data/test/test_id.rb +2 -2
- data/test/test_json_page.rb +2 -2
- data/test/test_key.rb +2 -2
- data/test/test_log.rb +5 -5
- data/test/test_metronome.rb +6 -6
- data/test/test_patch.rb +14 -14
- data/test/test_prefixes.rb +3 -3
- data/test/test_remotes.rb +9 -9
- data/test/test_signature.rb +2 -2
- data/test/test_size.rb +2 -2
- data/test/test_sync_wallets.rb +3 -3
- data/test/test_tax.rb +9 -9
- data/test/test_thread_pool.rb +8 -8
- data/test/test_tree_wallets.rb +2 -2
- data/test/test_txn.rb +2 -2
- data/test/test_upgrades.rb +2 -2
- data/test/test_verbose_thread.rb +2 -2
- data/test/test_version.rb +20 -0
- data/test/test_wallet.rb +22 -22
- data/test/test_wallets.rb +5 -5
- data/test/test_zold.rb +5 -5
- data/test/upgrades/test_delete_banned_wallets.rb +4 -4
- data/test/upgrades/test_protocol_up.rb +4 -4
- data/upgrades/2.rb +1 -1
- data/upgrades/delete_banned_wallets.rb +1 -1
- data/upgrades/move_wallets_into_tree.rb +1 -1
- data/upgrades/protocol_up.rb +1 -1
- data/upgrades/rename_foreign_wallets.rb +1 -1
- data/zold.gemspec +23 -23
- metadata +7 -3
data/test/commands/test_taxes.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -34,11 +34,11 @@ require_relative '../../lib/zold/commands/taxes'
|
|
34
34
|
|
35
35
|
# TAXES test.
|
36
36
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
37
|
-
# Copyright:: Copyright (c) 2018
|
37
|
+
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
38
38
|
# License:: MIT
|
39
39
|
class TestTaxes < Zold::Test
|
40
40
|
def test_pays_taxes
|
41
|
-
FakeHome.new(log:
|
41
|
+
FakeHome.new(log: fake_log).run do |home|
|
42
42
|
wallets = home.wallets
|
43
43
|
wallet = home.create_wallet
|
44
44
|
fund = Zold::Amount.new(zld: 19.99)
|
@@ -65,7 +65,7 @@ class TestTaxes < Zold::Test
|
|
65
65
|
before = wallet.balance
|
66
66
|
tax = Zold::Tax.new(wallet, ignore_score_weakness: true)
|
67
67
|
debt = tax.debt
|
68
|
-
Zold::Taxes.new(wallets: wallets, remotes: remotes, log:
|
68
|
+
Zold::Taxes.new(wallets: wallets, remotes: remotes, log: fake_log).run(
|
69
69
|
['taxes', '--private-key=fixtures/id_rsa', '--ignore-score-weakness', 'pay', wallet.id.to_s]
|
70
70
|
)
|
71
71
|
wallet.flush
|
data/test/fake_home.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -33,7 +33,7 @@ require_relative '../lib/zold/remotes'
|
|
33
33
|
|
34
34
|
# Fake home dir.
|
35
35
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
36
|
-
# Copyright:: Copyright (c) 2018
|
36
|
+
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
37
37
|
# License:: MIT
|
38
38
|
class FakeHome
|
39
39
|
attr_reader :dir
|
data/test/node/fake_entrance.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -22,7 +22,7 @@
|
|
22
22
|
|
23
23
|
# Fake entrance.
|
24
24
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
25
|
-
# Copyright:: Copyright (c) 2018
|
25
|
+
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
26
26
|
# License:: MIT
|
27
27
|
class FakeEntrance
|
28
28
|
def initialize
|
data/test/node/fake_node.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -31,58 +31,75 @@ require_relative '../../lib/zold/node/front'
|
|
31
31
|
|
32
32
|
# Fake node.
|
33
33
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
34
|
-
# Copyright:: Copyright (c) 2018
|
34
|
+
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
35
35
|
# License:: MIT
|
36
36
|
class FakeNode
|
37
37
|
def initialize(log: Zold::Log::NULL)
|
38
38
|
@log = log
|
39
39
|
end
|
40
40
|
|
41
|
+
# This is a pretty weird situation: we have to acquire a single port
|
42
|
+
# number an reuse it for all tests. If we use different port numbers,
|
43
|
+
# acquiring them for each instance of FakeNode, we get port collisions,
|
44
|
+
# sometimes. Maybe this can be fixed sometimes.
|
45
|
+
# rubocop:disable Style/ClassVars
|
46
|
+
@@port = RandomPort::Pool::SINGLETON.acquire
|
47
|
+
# rubocop:enable Style/ClassVars
|
48
|
+
|
41
49
|
def run(args = ['--standalone', '--no-metronome'])
|
42
50
|
WebMock.allow_net_connect!
|
43
51
|
FakeHome.new(log: @log).run do |home|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
52
|
+
node = Thread.new do
|
53
|
+
Thread.current.name = 'fake_node'
|
54
|
+
Thread.current.abort_on_exception = false
|
55
|
+
Zold::VerboseThread.new(@log).run do
|
56
|
+
require_relative '../../lib/zold/commands/node'
|
57
|
+
Zold::Node.new(wallets: home.wallets, remotes: home.remotes, copies: home.copies.root, log: @log).run(
|
58
|
+
[
|
59
|
+
'--home', home.dir,
|
60
|
+
'--network=test',
|
61
|
+
'--port', @@port.to_s,
|
62
|
+
'--host=localhost',
|
63
|
+
'--bind-port', @@port.to_s,
|
64
|
+
'--threads=1',
|
65
|
+
'--dump-errors',
|
66
|
+
'--strength=2',
|
67
|
+
'--halt-code=test',
|
68
|
+
'--routine-immediately',
|
69
|
+
'--invoice=NOPREFIX@ffffffffffffffff'
|
70
|
+
] + args
|
71
|
+
)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
uri = "http://localhost:#{@@port}/"
|
75
|
+
attempt = 0
|
76
|
+
loop do
|
77
|
+
ping = Zold::Http.new(uri: uri).get
|
78
|
+
unless ping.status == 599 && node.alive?
|
79
|
+
@log.debug("The URL #{uri} is probably alive, after #{attempt} attempts")
|
80
|
+
break
|
66
81
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
ping = Zold::Http.new(uri: uri).get
|
71
|
-
break unless ping.status == 599 && node.alive?
|
72
|
-
@log.info("Waiting for #{uri} (attempt no.#{attempt}): ##{ping.status}...")
|
73
|
-
sleep 0.5
|
74
|
-
attempt += 1
|
75
|
-
break if attempt > 10
|
82
|
+
unless node.alive?
|
83
|
+
@log.debug("The URL #{uri} is dead, after #{attempt} attempts")
|
84
|
+
break
|
76
85
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
sleep 0.1 # stupid sleep to make sure all threads are terminated
|
86
|
+
@log.debug("Waiting for #{uri} (attempt no.#{attempt}): ##{ping.status}...")
|
87
|
+
sleep 0.5
|
88
|
+
attempt += 1
|
89
|
+
if attempt > 10
|
90
|
+
@log.error("Waiting for too long for #{uri} (#{attempt} attempts)")
|
91
|
+
break
|
84
92
|
end
|
85
93
|
end
|
94
|
+
raise "The node is dead at #{uri}" unless node.alive?
|
95
|
+
begin
|
96
|
+
yield @@port
|
97
|
+
ensure
|
98
|
+
Zold::Http.new(uri: "#{uri}?halt=test").get
|
99
|
+
node.join
|
100
|
+
sleep 0.1 # stupid sleep to make sure all threads are terminated
|
101
|
+
end
|
102
|
+
@log.debug("Thread with fake node stopped: #{node.alive?}")
|
86
103
|
end
|
87
104
|
end
|
88
105
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -30,25 +30,25 @@ require_relative 'fake_entrance'
|
|
30
30
|
|
31
31
|
# AsyncEntrance test.
|
32
32
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
33
|
-
# Copyright:: Copyright (c) 2018
|
33
|
+
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
34
34
|
# License:: MIT
|
35
35
|
class TestAsyncEntrance < Zold::Test
|
36
36
|
def test_renders_json
|
37
|
-
FakeHome.new(log:
|
38
|
-
Zold::AsyncEntrance.new(FakeEntrance.new, home.dir, log:
|
37
|
+
FakeHome.new(log: fake_log).run do |home|
|
38
|
+
Zold::AsyncEntrance.new(FakeEntrance.new, home.dir, log: fake_log).start do |e|
|
39
39
|
assert_equal(0, e.to_json[:queue])
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
def test_sends_through_once
|
45
|
-
FakeHome.new(log:
|
45
|
+
FakeHome.new(log: fake_log).run do |home|
|
46
46
|
wallet = home.create_wallet
|
47
47
|
amount = Zold::Amount.new(zld: 39.99)
|
48
48
|
key = Zold::Key.new(file: 'fixtures/id_rsa')
|
49
49
|
wallet.sub(amount, "NOPREFIX@#{Zold::Id.new}", key)
|
50
50
|
basic = CountingEntrance.new
|
51
|
-
Zold::AsyncEntrance.new(basic, File.join(home.dir, 'a/b/c'), log:
|
51
|
+
Zold::AsyncEntrance.new(basic, File.join(home.dir, 'a/b/c'), log: fake_log).start do |e|
|
52
52
|
e.push(wallet.id, File.read(wallet.path))
|
53
53
|
assert_equal_wait(1) { basic.count }
|
54
54
|
end
|
@@ -56,9 +56,9 @@ class TestAsyncEntrance < Zold::Test
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def test_sends_through
|
59
|
-
FakeHome.new(log:
|
59
|
+
FakeHome.new(log: fake_log).run do |home|
|
60
60
|
basic = CountingEntrance.new
|
61
|
-
Zold::AsyncEntrance.new(basic, File.join(home.dir, 'a/b/c'), log:
|
61
|
+
Zold::AsyncEntrance.new(basic, File.join(home.dir, 'a/b/c'), log: fake_log, queue_limit: 1000).start do |e|
|
62
62
|
Threads.new(20).assert do
|
63
63
|
wallet = home.create_wallet
|
64
64
|
amount = Zold::Amount.new(zld: 39.99)
|
@@ -72,11 +72,11 @@ class TestAsyncEntrance < Zold::Test
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_handles_broken_entrance_gracefully
|
75
|
-
FakeHome.new(log:
|
75
|
+
FakeHome.new(log: fake_log).run do |home|
|
76
76
|
wallet = home.create_wallet
|
77
77
|
id = wallet.id
|
78
78
|
body = File.read(wallet.path)
|
79
|
-
Zold::AsyncEntrance.new(BrokenEntrance.new, home.dir, log:
|
79
|
+
Zold::AsyncEntrance.new(BrokenEntrance.new, home.dir, log: fake_log).start do |e|
|
80
80
|
e.push(id, body)
|
81
81
|
end
|
82
82
|
end
|
data/test/node/test_entrance.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -34,16 +34,16 @@ require_relative '../../lib/zold/commands/pay'
|
|
34
34
|
|
35
35
|
# ENTRANCE test.
|
36
36
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
37
|
-
# Copyright:: Copyright (c) 2018
|
37
|
+
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
38
38
|
# License:: MIT
|
39
39
|
class TestEntrance < Zold::Test
|
40
40
|
def test_pushes_wallet
|
41
41
|
sid = Zold::Id::ROOT
|
42
42
|
tid = Zold::Id.new
|
43
|
-
body = FakeHome.new(log:
|
43
|
+
body = FakeHome.new(log: fake_log).run do |home|
|
44
44
|
source = home.create_wallet(sid)
|
45
45
|
target = home.create_wallet(tid)
|
46
|
-
Zold::Pay.new(wallets: home.wallets, copies: home.dir, remotes: home.remotes, log:
|
46
|
+
Zold::Pay.new(wallets: home.wallets, copies: home.dir, remotes: home.remotes, log: fake_log).run(
|
47
47
|
[
|
48
48
|
'pay', '--force', '--private-key=fixtures/id_rsa',
|
49
49
|
source.id.to_s, target.id.to_s, '19.99', 'testing'
|
@@ -51,14 +51,14 @@ class TestEntrance < Zold::Test
|
|
51
51
|
)
|
52
52
|
File.read(source.path)
|
53
53
|
end
|
54
|
-
FakeHome.new(log:
|
54
|
+
FakeHome.new(log: fake_log).run do |home|
|
55
55
|
source = home.create_wallet(sid)
|
56
56
|
target = home.create_wallet(tid)
|
57
57
|
ledger = File.join(home.dir, 'ledger.csv')
|
58
58
|
e = Zold::Entrance.new(
|
59
59
|
home.wallets,
|
60
60
|
Zold::Pipeline.new(home.remotes, home.copies(source).root, 'x', ledger: ledger),
|
61
|
-
log:
|
61
|
+
log: fake_log
|
62
62
|
)
|
63
63
|
modified = e.push(source.id, body)
|
64
64
|
assert_equal(2, modified.count)
|
@@ -71,9 +71,9 @@ class TestEntrance < Zold::Test
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def test_renders_json
|
74
|
-
FakeHome.new(log:
|
74
|
+
FakeHome.new(log: fake_log).run do |home|
|
75
75
|
wallet = home.create_wallet
|
76
|
-
e = Zold::Entrance.new(home.wallets, Zold::Pipeline.new(home.remotes, home.copies.root, 'x'), log:
|
76
|
+
e = Zold::Entrance.new(home.wallets, Zold::Pipeline.new(home.remotes, home.copies.root, 'x'), log: fake_log)
|
77
77
|
e.push(wallet.id, File.read(wallet.path))
|
78
78
|
assert(e.to_json[:history].include?(wallet.id.to_s))
|
79
79
|
assert(!e.to_json[:speed].negative?)
|
data/test/node/test_farm.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -30,7 +30,7 @@ require_relative '../../lib/zold/node/farm'
|
|
30
30
|
class FarmTest < Zold::Test
|
31
31
|
def test_renders_in_json
|
32
32
|
Dir.mktmpdir do |dir|
|
33
|
-
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'), log:
|
33
|
+
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'), log: fake_log, strength: 2)
|
34
34
|
farm.start('localhost', 80, threads: 2) do
|
35
35
|
assert_wait { !farm.best.empty? && !farm.best[0].value.zero? }
|
36
36
|
count = 0
|
@@ -42,7 +42,7 @@ class FarmTest < Zold::Test
|
|
42
42
|
|
43
43
|
def test_renders_in_text
|
44
44
|
Dir.mktmpdir do |dir|
|
45
|
-
farm = Zold::Farm.new('NOPREFIX7@ffffffffffffffff', File.join(dir, 'f'), log:
|
45
|
+
farm = Zold::Farm.new('NOPREFIX7@ffffffffffffffff', File.join(dir, 'f'), log: fake_log, strength: 1)
|
46
46
|
farm.start('localhost', 80, threads: 2) do
|
47
47
|
assert(!farm.to_text.nil?)
|
48
48
|
end
|
@@ -52,7 +52,7 @@ class FarmTest < Zold::Test
|
|
52
52
|
def test_makes_many_scores
|
53
53
|
Dir.mktmpdir do |dir|
|
54
54
|
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'),
|
55
|
-
log:
|
55
|
+
log: fake_log, lifetime: 10, farmer: Zold::Farmers::Plain.new, strength: 1)
|
56
56
|
farm.start('localhost', 80, threads: 4) do
|
57
57
|
assert_wait { farm.best.length == 4 }
|
58
58
|
end
|
@@ -67,7 +67,7 @@ class FarmTest < Zold::Test
|
|
67
67
|
# that it's usually a few microseconds, but sometimes over 200ms.
|
68
68
|
def test_reads_scores_at_high_speed
|
69
69
|
Dir.mktmpdir do |dir|
|
70
|
-
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'), log:
|
70
|
+
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'), log: fake_log, strength: 4)
|
71
71
|
farm.start('localhost', 80, threads: 4) do
|
72
72
|
assert_wait { !farm.best.empty? && !farm.best[0].value.zero? }
|
73
73
|
cycles = 100
|
@@ -76,14 +76,14 @@ class FarmTest < Zold::Test
|
|
76
76
|
farm.best
|
77
77
|
Time.now - start
|
78
78
|
end.inject(&:+) / cycles
|
79
|
-
|
79
|
+
fake_log.info("Average speed is #{(speed * 1000).round(2)}ms in #{cycles} cycles")
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
84
|
def test_makes_best_score_in_background
|
85
85
|
Dir.mktmpdir do |dir|
|
86
|
-
farm = Zold::Farm.new('NOPREFIX1@ffffffffffffffff', File.join(dir, 'f'), log:
|
86
|
+
farm = Zold::Farm.new('NOPREFIX1@ffffffffffffffff', File.join(dir, 'f'), log: fake_log, strength: 3)
|
87
87
|
farm.start('localhost', 80, threads: 1) do
|
88
88
|
assert_wait { !farm.best.empty? && farm.best[0].value >= 3 }
|
89
89
|
score = farm.best[0]
|
@@ -95,7 +95,7 @@ class FarmTest < Zold::Test
|
|
95
95
|
|
96
96
|
def test_correct_score_from_empty_farm
|
97
97
|
Dir.mktmpdir do |dir|
|
98
|
-
farm = Zold::Farm.new('NOPREFIX2@cccccccccccccccc', File.join(dir, 'f'), log:
|
98
|
+
farm = Zold::Farm.new('NOPREFIX2@cccccccccccccccc', File.join(dir, 'f'), log: fake_log, strength: 1)
|
99
99
|
farm.start('example.com', 8080, threads: 0) do
|
100
100
|
score = farm.best[0]
|
101
101
|
assert(!score.expired?)
|
@@ -109,7 +109,7 @@ class FarmTest < Zold::Test
|
|
109
109
|
def test_pre_loads_history
|
110
110
|
Dir.mktmpdir do |dir|
|
111
111
|
cache = File.join(dir, 'a/b/c/cache')
|
112
|
-
farm = Zold::Farm.new('NOPREFIX3@cccccccccccccccc', cache, log:
|
112
|
+
farm = Zold::Farm.new('NOPREFIX3@cccccccccccccccc', cache, log: fake_log, strength: 1)
|
113
113
|
farm.start('example.com', 8080, threads: 0) do
|
114
114
|
score = farm.best[0]
|
115
115
|
assert(!score.nil?, 'The list of best scores can\'t be empty!')
|
@@ -132,7 +132,7 @@ class FarmTest < Zold::Test
|
|
132
132
|
strength: 6
|
133
133
|
)
|
134
134
|
File.write(cache, score.to_s)
|
135
|
-
farm = Zold::Farm.new('NOPREFIX4@ffffffffffffffff', cache, log:
|
135
|
+
farm = Zold::Farm.new('NOPREFIX4@ffffffffffffffff', cache, log: fake_log, strength: score.strength)
|
136
136
|
farm.start(score.host, score.port, threads: 1) do
|
137
137
|
100.times do
|
138
138
|
sleep(0.1)
|
@@ -170,7 +170,7 @@ class FarmTest < Zold::Test
|
|
170
170
|
end
|
171
171
|
|
172
172
|
def test_terminates_farm_entirely
|
173
|
-
Zold::Farm.new('NOPREFIX4@ffffffffffffffff', log:
|
173
|
+
Zold::Farm.new('NOPREFIX4@ffffffffffffffff', log: fake_log, strength: 10).start('localhost', 4096, threads: 1) do
|
174
174
|
sleep 1
|
175
175
|
end
|
176
176
|
end
|
data/test/node/test_farmers.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -38,7 +38,7 @@ class FarmersTest < Zold::Test
|
|
38
38
|
def test_calculates_next_score
|
39
39
|
before = Zold::Score.new(host: 'some-host', port: 9999, invoice: 'NOPREFIX4@ffffffffffffffff', strength: 3)
|
40
40
|
TYPES.each do |farmer_class|
|
41
|
-
farmer = farmer_class.new(log:
|
41
|
+
farmer = farmer_class.new(log: fake_log)
|
42
42
|
after = farmer.up(before)
|
43
43
|
assert_equal(1, after.value)
|
44
44
|
assert(!after.expired?)
|
@@ -49,7 +49,7 @@ class FarmersTest < Zold::Test
|
|
49
49
|
|
50
50
|
def test_calculates_large_score
|
51
51
|
TYPES.each do |type|
|
52
|
-
log = TestLogger.new(
|
52
|
+
log = TestLogger.new(fake_log)
|
53
53
|
thread = Thread.start do
|
54
54
|
farmer = type.new(log: log)
|
55
55
|
farmer.up(Zold::Score.new(host: 'a', port: 1, invoice: 'NOPREFIX4@ffffffffffffffff', strength: 20))
|
@@ -62,9 +62,9 @@ class FarmersTest < Zold::Test
|
|
62
62
|
|
63
63
|
def test_kills_farmer
|
64
64
|
TYPES.each do |type|
|
65
|
-
farmer = type.new(log:
|
65
|
+
farmer = type.new(log: fake_log)
|
66
66
|
thread = Thread.start do
|
67
|
-
Zold::VerboseThread.new(
|
67
|
+
Zold::VerboseThread.new(fake_log).run do
|
68
68
|
farmer.up(Zold::Score.new(host: 'some-host', invoice: 'NOPREFIX4@ffffffffffffffff', strength: 32))
|
69
69
|
end
|
70
70
|
end
|
data/test/node/test_front.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -45,7 +45,7 @@ class FrontTest < Zold::Test
|
|
45
45
|
def test_memory_leakage
|
46
46
|
skip
|
47
47
|
report = MemoryProfiler.report(top: 10) do
|
48
|
-
FakeNode.new(log:
|
48
|
+
FakeNode.new(log: fake_log).run(opts('--network=foo')) do |port|
|
49
49
|
100.times do
|
50
50
|
Zold::Http.new(uri: "http://localhost:#{port}/", network: 'foo').get
|
51
51
|
end
|
@@ -55,7 +55,7 @@ class FrontTest < Zold::Test
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def test_renders_front_json
|
58
|
-
FakeNode.new(log:
|
58
|
+
FakeNode.new(log: fake_log).run(opts('--network=foo')) do |port|
|
59
59
|
res = Zold::Http.new(uri: "http://localhost:#{port}/", network: 'foo').get
|
60
60
|
json = JSON.parse(res.body)
|
61
61
|
assert_equal(Zold::VERSION, json['version'])
|
@@ -74,7 +74,7 @@ class FrontTest < Zold::Test
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def test_renders_public_pages
|
77
|
-
FakeNode.new(log:
|
77
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
78
78
|
{
|
79
79
|
200 => [
|
80
80
|
'/robots.txt',
|
@@ -117,7 +117,7 @@ class FrontTest < Zold::Test
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def test_updates_list_of_remotes
|
120
|
-
FakeNode.new(log:
|
120
|
+
FakeNode.new(log: fake_log).run(['--no-metronome', '--ignore-score-weakness', '--no-cache']) do |port|
|
121
121
|
(Zold::Remotes::MAX_NODES + 5).times do |i|
|
122
122
|
score = Zold::Score.new(
|
123
123
|
host: 'localhost', port: i + 1, invoice: 'NOPREFIX@ffffffffffffffff', strength: 1
|
@@ -138,9 +138,9 @@ class FrontTest < Zold::Test
|
|
138
138
|
end
|
139
139
|
|
140
140
|
def test_increments_score
|
141
|
-
FakeNode.new(log:
|
141
|
+
FakeNode.new(log: fake_log).run(opts('--threads=1')) do |port|
|
142
142
|
3.times do |i|
|
143
|
-
assert_equal_wait(true, max:
|
143
|
+
assert_equal_wait(true, max: 120) do
|
144
144
|
response = Zold::Http.new(uri: "http://localhost:#{port}/").get
|
145
145
|
assert_equal(200, response.status, response.body)
|
146
146
|
score = Zold::Score.parse_json(Zold::JsonPage.new(response.body).to_hash['score'])
|
@@ -159,8 +159,8 @@ class FrontTest < Zold::Test
|
|
159
159
|
].each do |p|
|
160
160
|
method = "test_wallet_page_#{p.gsub(/[^a-z]/, '_')}"
|
161
161
|
define_method(method) do
|
162
|
-
FakeHome.new(log:
|
163
|
-
FakeNode.new(log:
|
162
|
+
FakeHome.new(log: fake_log).run do |home|
|
163
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
164
164
|
wallet = home.create_wallet(txns: 2)
|
165
165
|
base = "http://localhost:#{port}"
|
166
166
|
response = Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}").put(wallet.path)
|
@@ -173,8 +173,8 @@ class FrontTest < Zold::Test
|
|
173
173
|
end
|
174
174
|
|
175
175
|
def test_renders_wallets_page
|
176
|
-
FakeHome.new(log:
|
177
|
-
FakeNode.new(log:
|
176
|
+
FakeHome.new(log: fake_log).run do |home|
|
177
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
178
178
|
wallet = home.create_wallet(txns: 2)
|
179
179
|
base = "http://localhost:#{port}"
|
180
180
|
response = Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}").put(wallet.path)
|
@@ -188,8 +188,8 @@ class FrontTest < Zold::Test
|
|
188
188
|
end
|
189
189
|
|
190
190
|
def test_fetch_in_multiple_threads
|
191
|
-
FakeNode.new(log:
|
192
|
-
FakeHome.new(log:
|
191
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
192
|
+
FakeHome.new(log: fake_log).run do |home|
|
193
193
|
wallet = home.create_wallet
|
194
194
|
base = "http://localhost:#{port}"
|
195
195
|
Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}").put(wallet.path)
|
@@ -209,8 +209,8 @@ class FrontTest < Zold::Test
|
|
209
209
|
end
|
210
210
|
|
211
211
|
def test_pushes_twice
|
212
|
-
FakeNode.new(log:
|
213
|
-
FakeHome.new(log:
|
212
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
213
|
+
FakeHome.new(log: fake_log).run do |home|
|
214
214
|
wallet = home.create_wallet
|
215
215
|
base = "http://localhost:#{port}"
|
216
216
|
assert_equal(
|
@@ -227,9 +227,9 @@ class FrontTest < Zold::Test
|
|
227
227
|
end
|
228
228
|
|
229
229
|
def test_pushes_many_wallets
|
230
|
-
FakeNode.new(log:
|
230
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
231
231
|
base = "http://localhost:#{port}"
|
232
|
-
FakeHome.new(log:
|
232
|
+
FakeHome.new(log: fake_log).run do |home|
|
233
233
|
Threads.new(5).assert do
|
234
234
|
wallet = home.create_wallet
|
235
235
|
Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}").put(wallet.path)
|
@@ -273,7 +273,7 @@ class FrontTest < Zold::Test
|
|
273
273
|
end
|
274
274
|
|
275
275
|
def test_gzip
|
276
|
-
FakeNode.new(log:
|
276
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
277
277
|
response = Zold::Http.new(uri: URI("http://localhost:#{port}/version")).get
|
278
278
|
assert_equal(200, response.status, response)
|
279
279
|
assert_operator(300, :>, response.body.length.to_i, 'Expected the content to be small')
|
@@ -282,7 +282,7 @@ class FrontTest < Zold::Test
|
|
282
282
|
|
283
283
|
def test_performance
|
284
284
|
times = Queue.new
|
285
|
-
FakeNode.new(log:
|
285
|
+
FakeNode.new(log: fake_log).run(opts('--threads=4', '--strength=6')) do |port|
|
286
286
|
Threads.new(10).assert(100) do
|
287
287
|
start = Time.now
|
288
288
|
Zold::Http.new(uri: URI("http://localhost:#{port}/")).get
|
@@ -291,7 +291,7 @@ class FrontTest < Zold::Test
|
|
291
291
|
end
|
292
292
|
all = []
|
293
293
|
all << times.pop(true) until times.empty?
|
294
|
-
|
294
|
+
fake_log.info("Average response time is #{all.inject(&:+) / all.count}")
|
295
295
|
end
|
296
296
|
|
297
297
|
# The score exposed via the HTTP header must be reduced to the value of 16.
|
@@ -299,7 +299,7 @@ class FrontTest < Zold::Test
|
|
299
299
|
# HTTP request. This value is enough to identify a valueable node, and filter
|
300
300
|
# out those that are too weak.
|
301
301
|
def test_score_is_reduced
|
302
|
-
FakeNode.new(log:
|
302
|
+
FakeNode.new(log: fake_log).run(opts('--threads=1', '--strength=1', '--farmer=plain')) do |port|
|
303
303
|
scores = []
|
304
304
|
50.times do
|
305
305
|
res = Zold::Http.new(uri: URI("http://localhost:#{port}/")).get
|
@@ -311,7 +311,7 @@ class FrontTest < Zold::Test
|
|
311
311
|
end
|
312
312
|
|
313
313
|
def test_headers_are_being_set_correctly
|
314
|
-
FakeNode.new(log:
|
314
|
+
FakeNode.new(log: fake_log).run(opts('--expose-version=9.9.9')) do |port|
|
315
315
|
response = Zold::Http.new(uri: URI("http://localhost:#{port}/")).get
|
316
316
|
assert_equal('no-cache', response.headers['Cache-Control'])
|
317
317
|
assert_equal('close', response.headers['Connection'])
|
@@ -325,7 +325,7 @@ class FrontTest < Zold::Test
|
|
325
325
|
|
326
326
|
def test_alias_parameter
|
327
327
|
name = SecureRandom.hex(4)
|
328
|
-
FakeNode.new(log:
|
328
|
+
FakeNode.new(log: fake_log).run(opts("--alias=#{name}")) do |port|
|
329
329
|
uri = URI("http://localhost:#{port}/")
|
330
330
|
response = Zold::Http.new(uri: uri).get
|
331
331
|
assert_match(
|
@@ -337,7 +337,7 @@ class FrontTest < Zold::Test
|
|
337
337
|
end
|
338
338
|
|
339
339
|
def test_default_alias_parameter
|
340
|
-
FakeNode.new(log:
|
340
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
341
341
|
uri = URI("http://localhost:#{port}/")
|
342
342
|
response = Zold::Http.new(uri: uri).get
|
343
343
|
assert_match(
|
@@ -349,8 +349,9 @@ class FrontTest < Zold::Test
|
|
349
349
|
end
|
350
350
|
|
351
351
|
def test_invalid_alias
|
352
|
+
skip
|
352
353
|
exception = assert_raises RuntimeError do
|
353
|
-
FakeNode.new(log:
|
354
|
+
FakeNode.new(log: fake_log).run(opts('--alias=invalid-alias')) do |port|
|
354
355
|
uri = URI("http://localhost:#{port}/")
|
355
356
|
Zold::Http.new(uri: uri).get
|
356
357
|
end
|
@@ -360,8 +361,8 @@ class FrontTest < Zold::Test
|
|
360
361
|
|
361
362
|
def test_push_fetch_in_multiple_threads
|
362
363
|
key = Zold::Key.new(text: File.read('fixtures/id_rsa'))
|
363
|
-
FakeNode.new(log:
|
364
|
-
FakeHome.new(log:
|
364
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
365
|
+
FakeHome.new(log: fake_log).run do |home|
|
365
366
|
wallet = home.create_wallet(Zold::Id::ROOT)
|
366
367
|
base = "http://localhost:#{port}"
|
367
368
|
Zold::Http.new(uri: "#{base}/wallet/#{wallet.id}").put(wallet.path)
|
@@ -380,7 +381,7 @@ class FrontTest < Zold::Test
|
|
380
381
|
end
|
381
382
|
|
382
383
|
def test_checksum_in_json
|
383
|
-
FakeNode.new(log:
|
384
|
+
FakeNode.new(log: fake_log).run(opts) do |port|
|
384
385
|
uri = URI("http://localhost:#{port}/")
|
385
386
|
response = Zold::Http.new(uri: uri).get
|
386
387
|
assert(
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2018-
|
3
|
+
# Copyright (c) 2018-2024 Zerocracy
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -29,13 +29,13 @@ require_relative 'fake_entrance'
|
|
29
29
|
|
30
30
|
# NoDupEntrance test.
|
31
31
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
32
|
-
# Copyright:: Copyright (c) 2018
|
32
|
+
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
33
33
|
# License:: MIT
|
34
34
|
class TestNoDupEntrance < Zold::Test
|
35
35
|
def test_ignores_dup
|
36
|
-
FakeHome.new(log:
|
36
|
+
FakeHome.new(log: fake_log).run do |home|
|
37
37
|
wallet = home.create_wallet
|
38
|
-
Zold::NoDupEntrance.new(RealEntrance.new, home.wallets, log:
|
38
|
+
Zold::NoDupEntrance.new(RealEntrance.new, home.wallets, log: fake_log).start do |e|
|
39
39
|
assert(e.push(wallet.id, File.read(wallet.path)).empty?)
|
40
40
|
end
|
41
41
|
end
|