zold 0.5 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -2
- data/bin/zold +34 -48
- data/features/cli.feature +1 -1
- data/features/step_definitions/steps.rb +1 -3
- data/features/support/env.rb +2 -0
- data/fixtures/scripts/push-and-pull.sh +6 -4
- data/lib/zold/amount.rb +17 -3
- data/lib/zold/commands/create.rb +9 -6
- data/lib/zold/commands/fetch.rb +11 -21
- data/lib/zold/commands/node.rb +7 -9
- data/lib/zold/commands/pay.rb +9 -6
- data/lib/zold/commands/propagate.rb +4 -5
- data/lib/zold/commands/push.rb +10 -5
- data/lib/zold/commands/remote.rb +22 -24
- data/lib/zold/commands/show.rb +1 -2
- data/lib/zold/commands/taxes.rb +154 -0
- data/lib/zold/http.rb +1 -3
- data/lib/zold/key.rb +1 -3
- data/lib/zold/node/entrance.rb +8 -3
- data/lib/zold/node/farm.rb +8 -6
- data/lib/zold/node/front.rb +0 -1
- data/lib/zold/patch.rb +1 -1
- data/lib/zold/remotes.rb +4 -0
- data/lib/zold/score.rb +85 -10
- data/lib/zold/signature.rb +7 -7
- data/lib/zold/tax.rb +79 -0
- data/lib/zold/txn.rb +12 -7
- data/lib/zold/version.rb +1 -1
- data/lib/zold/wallet.rb +2 -2
- data/test/commands/test_create.rb +3 -4
- data/test/commands/test_diff.rb +2 -3
- data/test/commands/test_merge.rb +4 -6
- data/test/commands/test_pay.rb +7 -5
- data/test/commands/test_remote.rb +5 -3
- data/test/commands/test_taxes.rb +66 -0
- data/test/node/fake_node.rb +1 -0
- data/test/node/test_farm.rb +2 -1
- data/test/node/test_front.rb +1 -0
- data/test/test__helper.rb +2 -0
- data/test/test_remotes.rb +0 -1
- data/test/test_score.rb +40 -21
- data/test/test_signature.rb +6 -3
- data/test/test_tax.rb +53 -0
- data/test/test_txn.rb +46 -0
- data/test/test_wallet.rb +2 -2
- data/test/test_zold.rb +1 -1
- data/wp/.gitignore +6 -0
- data/wp/wp.tex +38 -0
- data/zold.gemspec +1 -3
- metadata +12 -2
data/lib/zold/score.rb
CHANGED
@@ -30,30 +30,93 @@ module Zold
|
|
30
30
|
# Score
|
31
31
|
class Score
|
32
32
|
STRENGTH = 6
|
33
|
-
attr_reader :time, :host, :port, :strength
|
33
|
+
attr_reader :time, :host, :port, :invoice, :strength
|
34
34
|
# time: UTC ISO 8601 string
|
35
|
-
def initialize(time, host, port, suffixes = [], strength: STRENGTH)
|
35
|
+
def initialize(time, host, port, invoice, suffixes = [], strength: STRENGTH)
|
36
|
+
raise "Invalid host name: #{host}" unless host =~ /^[a-z0-9\.-]+$/
|
36
37
|
raise 'Time must be of type Time' unless time.is_a?(Time)
|
37
38
|
raise 'Port must be of type Integer' unless port.is_a?(Integer)
|
39
|
+
raise "Invalid TCP port: #{port}" if port <= 0 || port > 65_535
|
40
|
+
raise "Invoice '#{invoice}' has wrong format" unless invoice =~ /^[a-zA-Z0-9]{8,32}@[a-f0-9]{16}$/
|
38
41
|
@time = time
|
39
42
|
@host = host
|
40
43
|
@port = port
|
44
|
+
@invoice = invoice
|
41
45
|
@suffixes = suffixes
|
42
46
|
@strength = strength
|
43
47
|
end
|
44
48
|
|
45
|
-
ZERO = Score.new(
|
49
|
+
ZERO = Score.new(
|
50
|
+
Time.now, 'localhost',
|
51
|
+
Remotes::PORT, 'NOPREFIX@ffffffffffffffff'
|
52
|
+
)
|
53
|
+
|
54
|
+
def self.parse_json(json)
|
55
|
+
raise "Time in JSON is broken: #{json}" unless json['time'] =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/
|
56
|
+
raise "Host is wrong: #{json}" unless json['host'] =~ /^[0-9a-z\.\-]+$/
|
57
|
+
raise "Port is wrong: #{json}" unless json['port'].is_a?(Integer)
|
58
|
+
raise "Invoice is wrong: #{json}" unless json['invoice'] =~ /^[a-zA-Z0-9]{8,32}@[a-f0-9]{16}$/
|
59
|
+
raise "Suffixes not array: #{json}" unless json['suffixes'].is_a?(Array)
|
60
|
+
Score.new(
|
61
|
+
Time.parse(json['time']), json['host'],
|
62
|
+
json['port'], json['invoice'], json['suffixes'],
|
63
|
+
strength: json['strength']
|
64
|
+
)
|
65
|
+
end
|
46
66
|
|
47
67
|
def self.parse(text, strength: STRENGTH)
|
48
|
-
|
68
|
+
m = Regexp.new(
|
69
|
+
'^' + [
|
70
|
+
'([0-9]+:)',
|
71
|
+
'(?<time>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z)',
|
72
|
+
'(?<host>[0-9a-z\.\-]+)',
|
73
|
+
'(?<port>[0-9]+)',
|
74
|
+
'(?<invoice>[a-zA-Z0-9]{8,32}@[a-f0-9]{16})',
|
75
|
+
'(?<suffixes>[a-zA-Z0-9 ]+)'
|
76
|
+
].join(' ') + '$'
|
77
|
+
).match(text)
|
78
|
+
raise "Invalid score '#{text}'" if m.nil?
|
79
|
+
Score.new(
|
80
|
+
Time.parse(m[:time]), m[:host],
|
81
|
+
m[:port].to_i, m[:invoice],
|
82
|
+
m[:suffixes].split(' '),
|
83
|
+
strength: strength
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.parse_text(text, strength: STRENGTH)
|
88
|
+
parts = text.split(' ', 6)
|
49
89
|
Score.new(
|
50
|
-
Time.
|
51
|
-
|
90
|
+
Time.at(parts[0].hex),
|
91
|
+
parts[1],
|
92
|
+
parts[2].hex,
|
93
|
+
"#{parts[3]}@#{parts[4]}",
|
94
|
+
parts[5].split(' '),
|
95
|
+
strength: strength
|
52
96
|
)
|
53
97
|
end
|
54
98
|
|
99
|
+
def to_text
|
100
|
+
prefix, bnf = @invoice.split('@')
|
101
|
+
[
|
102
|
+
@time.to_i.to_s(16),
|
103
|
+
@host,
|
104
|
+
@port.to_s(16),
|
105
|
+
prefix,
|
106
|
+
bnf,
|
107
|
+
@suffixes.join(' ')
|
108
|
+
].join(' ')
|
109
|
+
end
|
110
|
+
|
55
111
|
def to_s
|
56
|
-
|
112
|
+
[
|
113
|
+
"#{value}:",
|
114
|
+
@time.utc.iso8601,
|
115
|
+
@host,
|
116
|
+
@port,
|
117
|
+
@invoice,
|
118
|
+
@suffixes.join(' ')
|
119
|
+
].join(' ')
|
57
120
|
end
|
58
121
|
|
59
122
|
def to_h
|
@@ -61,6 +124,7 @@ module Zold
|
|
61
124
|
value: value,
|
62
125
|
host: @host,
|
63
126
|
port: @port,
|
127
|
+
invoice: @invoice,
|
64
128
|
time: @time.utc.iso8601,
|
65
129
|
suffixes: @suffixes,
|
66
130
|
strength: @strength
|
@@ -68,7 +132,10 @@ module Zold
|
|
68
132
|
end
|
69
133
|
|
70
134
|
def reduced(max = 4)
|
71
|
-
Score.new(
|
135
|
+
Score.new(
|
136
|
+
@time, @host, @port, @invoice,
|
137
|
+
@suffixes[0..max - 1], strength: @strength
|
138
|
+
)
|
72
139
|
end
|
73
140
|
|
74
141
|
def next
|
@@ -77,7 +144,7 @@ module Zold
|
|
77
144
|
loop do
|
78
145
|
suffix = idx.to_s(16)
|
79
146
|
score = Score.new(
|
80
|
-
@time, @host, @port, @suffixes + [suffix],
|
147
|
+
@time, @host, @port, @invoice, @suffixes + [suffix],
|
81
148
|
strength: @strength
|
82
149
|
)
|
83
150
|
return score if score.valid?
|
@@ -85,8 +152,16 @@ module Zold
|
|
85
152
|
end
|
86
153
|
end
|
87
154
|
|
155
|
+
def age_hours
|
156
|
+
(Time.now - @time) / 60
|
157
|
+
end
|
158
|
+
|
159
|
+
def expired?
|
160
|
+
@time < Time.now - 24 * 60
|
161
|
+
end
|
162
|
+
|
88
163
|
def valid?
|
89
|
-
start = "#{@time.utc.iso8601} #{@host} #{@port}"
|
164
|
+
start = "#{@time.utc.iso8601} #{@host} #{@port} #{@invoice}"
|
90
165
|
@suffixes.reduce(start) do |prefix, suffix|
|
91
166
|
hex = Digest::SHA256.hexdigest(prefix + ' ' + suffix)
|
92
167
|
return false unless hex.end_with?('0' * @strength)
|
data/lib/zold/signature.rb
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
19
|
# SOFTWARE.
|
20
20
|
|
21
|
-
require '
|
21
|
+
require 'digest'
|
22
22
|
require_relative 'key'
|
23
23
|
require_relative 'id'
|
24
24
|
require_relative 'amount'
|
@@ -31,18 +31,18 @@ require_relative 'amount'
|
|
31
31
|
module Zold
|
32
32
|
# A signature
|
33
33
|
class Signature
|
34
|
-
def sign(pvt, t)
|
35
|
-
pvt.sign(
|
34
|
+
def sign(pvt, id, t)
|
35
|
+
pvt.sign(body(id, t))
|
36
36
|
end
|
37
37
|
|
38
|
-
def valid?(pub, t)
|
39
|
-
pub.verify(t.sign,
|
38
|
+
def valid?(pub, id, t)
|
39
|
+
pub.verify(t.sign, body(id, t))
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
|
-
def
|
45
|
-
[t.id, t.amount.to_i, t.prefix, t.bnf, t.details].join('
|
44
|
+
def body(id, t)
|
45
|
+
[id, t.id, t.amount.to_i, t.prefix, t.bnf, t.details].join(' ')
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
data/lib/zold/tax.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'digest'
|
22
|
+
require_relative 'key'
|
23
|
+
require_relative 'id'
|
24
|
+
require_relative 'amount'
|
25
|
+
|
26
|
+
# Tax transaction.
|
27
|
+
#
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
module Zold
|
32
|
+
# A single tax payment
|
33
|
+
class Tax
|
34
|
+
# The minimum score a wallet can buy in order to pay taxes.
|
35
|
+
MIN_SCORE = 16
|
36
|
+
|
37
|
+
# This is how much we charge per one transaction per hour
|
38
|
+
# of storage. A wallet of 4096 transactions will pay
|
39
|
+
# approximately 16ZLD per year.
|
40
|
+
FEE_TXN_HOUR = Amount.new(zld: 16.0 / (365 * 24) / 4096)
|
41
|
+
|
42
|
+
# The maximum debt we can tolerate at the wallet. If the debt
|
43
|
+
# is bigger than this threshold, nodes must stop accepting PUSH.
|
44
|
+
TRIAL = Amount.new(zld: 1.0)
|
45
|
+
|
46
|
+
# For how many days to pay at once.
|
47
|
+
DAYS_INCREMENT = 32
|
48
|
+
|
49
|
+
def initialize(wallet)
|
50
|
+
@wallet = wallet
|
51
|
+
end
|
52
|
+
|
53
|
+
def pay(pvt, best)
|
54
|
+
fee = Tax::FEE * @wallet.txns.count * Tax::DAYS_INCREMENT * 24
|
55
|
+
@wallet.sub(fee, best.invoice, pvt, "TAXES #{best.to_text}")
|
56
|
+
end
|
57
|
+
|
58
|
+
def debt
|
59
|
+
txns = @wallet.txns
|
60
|
+
return Amount::ZERO if txns.empty?
|
61
|
+
paid = txns.map do |t|
|
62
|
+
pfx, body = t.details.split(' ')
|
63
|
+
if pfx != 'TAXES' || body.nil?
|
64
|
+
Amount::ZERO
|
65
|
+
else
|
66
|
+
score = Score.parse_text(body)
|
67
|
+
if score.valid? && score.value >= MIN_SCORE
|
68
|
+
t.amount
|
69
|
+
else
|
70
|
+
Amount::ZERO
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end.inject(&:+) * -1
|
74
|
+
age_hours = (Time.now - txns.sort_by(&:date)[0].date) / 60
|
75
|
+
owned = Tax::FEE_TXN_HOUR * txns.count * age_hours
|
76
|
+
owned - paid
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/zold/txn.rb
CHANGED
@@ -49,6 +49,7 @@ module Zold
|
|
49
49
|
@prefix = prefix
|
50
50
|
raise 'Details can\'t be empty' if details.empty?
|
51
51
|
raise "Details are too long: \"#{details}\"" if details.length > 128
|
52
|
+
raise "Details are wrong: \"#{details}\"" unless details =~ /^[a-zA-Z0-9 -\.,]{1,128}$/
|
52
53
|
@details = details
|
53
54
|
end
|
54
55
|
|
@@ -68,30 +69,34 @@ module Zold
|
|
68
69
|
].join(';')
|
69
70
|
end
|
70
71
|
|
72
|
+
def to_text
|
73
|
+
"##{@id} #{@date.utc.iso8601} #{@amount} #{@bnf} #{@details}"
|
74
|
+
end
|
75
|
+
|
71
76
|
def inverse(bnf)
|
72
77
|
t = clone
|
73
|
-
t.amount = amount
|
78
|
+
t.amount = amount * -1
|
74
79
|
t.bnf = bnf
|
75
80
|
t
|
76
81
|
end
|
77
82
|
|
78
|
-
def signed(pvt)
|
83
|
+
def signed(pvt, id)
|
79
84
|
t = clone
|
80
|
-
t.sign = Signature.new.sign(pvt, self)
|
85
|
+
t.sign = Signature.new.sign(pvt, id, self)
|
81
86
|
t
|
82
87
|
end
|
83
88
|
|
84
|
-
def self.parse(line, idx)
|
89
|
+
def self.parse(line, idx = 0)
|
85
90
|
regex = Regexp.new(
|
86
|
-
[
|
91
|
+
'^' + [
|
87
92
|
'([0-9]+)',
|
88
93
|
'([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z)',
|
89
94
|
'(-?[0-9]+)',
|
90
95
|
'([A-Za-z0-9]{8,32})',
|
91
96
|
'([a-f0-9]{16})',
|
92
|
-
'([a-zA-Z0-9
|
97
|
+
'([a-zA-Z0-9 -\.,]{1,128})',
|
93
98
|
'([A-Za-z0-9+/]+={0,3})?'
|
94
|
-
].join(';')
|
99
|
+
].join(';') + '$'
|
95
100
|
)
|
96
101
|
clean = line.strip
|
97
102
|
raise "Invalid line ##{idx}: #{line.inspect}" unless regex.match(clean)
|
data/lib/zold/version.rb
CHANGED
data/lib/zold/wallet.rb
CHANGED
@@ -31,10 +31,9 @@ require_relative '../../lib/zold/commands/create'
|
|
31
31
|
class TestCreate < Minitest::Test
|
32
32
|
def test_creates_wallet
|
33
33
|
Dir.mktmpdir 'test' do |dir|
|
34
|
-
wallet = Zold::Create.new(
|
35
|
-
|
36
|
-
|
37
|
-
).run
|
34
|
+
wallet = Zold::Create.new(wallets: Zold::Wallets.new(dir)).run(
|
35
|
+
['--public-key=fixtures/id_rsa.pub']
|
36
|
+
)
|
38
37
|
assert wallet.balance.zero?
|
39
38
|
assert(
|
40
39
|
File.exist?(File.join(dir, wallet.id.to_s)),
|
data/test/commands/test_diff.rb
CHANGED
@@ -46,9 +46,8 @@ class TestDiff < Minitest::Test
|
|
46
46
|
second = Zold::Wallet.new(File.join(dir, 'copy-2'))
|
47
47
|
File.write(second.path, File.read(wallet.path))
|
48
48
|
Zold::Pay.new(
|
49
|
-
wallets: Zold::Wallets.new(dir)
|
50
|
-
|
51
|
-
).run([id.to_s, second.id.to_s, '14.95', '--force'])
|
49
|
+
wallets: Zold::Wallets.new(dir)
|
50
|
+
).run([id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
|
52
51
|
copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
|
53
52
|
copies.add(File.read(first.path), 'host-1', 80, 5)
|
54
53
|
copies.add(File.read(second.path), 'host-2', 80, 5)
|
data/test/commands/test_merge.rb
CHANGED
@@ -48,9 +48,8 @@ class TestMerge < Minitest::Test
|
|
48
48
|
second = Zold::Wallet.new(File.join(dir, 'copy-2'))
|
49
49
|
File.write(second.path, File.read(wallet.path))
|
50
50
|
Zold::Pay.new(
|
51
|
-
wallets: Zold::Wallets.new(dir)
|
52
|
-
|
53
|
-
).run([id.to_s, second.id.to_s, '14.95', '--force'])
|
51
|
+
wallets: Zold::Wallets.new(dir)
|
52
|
+
).run([id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
|
54
53
|
copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
|
55
54
|
copies.add(File.read(first.path), 'host-1', 80, 5)
|
56
55
|
copies.add(File.read(second.path), 'host-2', 80, 5)
|
@@ -74,9 +73,8 @@ class TestMerge < Minitest::Test
|
|
74
73
|
second = Zold::Wallet.new(File.join(dir, 'copy-2'))
|
75
74
|
File.write(second.path, File.read(wallet.path))
|
76
75
|
Zold::Pay.new(
|
77
|
-
wallets: Zold::Wallets.new(dir)
|
78
|
-
|
79
|
-
).run([id.to_s, second.id.to_s, '14.95', '--force'])
|
76
|
+
wallets: Zold::Wallets.new(dir)
|
77
|
+
).run([id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
|
80
78
|
copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
|
81
79
|
copies.add(File.read(first.path), 'host-1', 80, 5)
|
82
80
|
copies.add(File.read(second.path), 'host-2', 80, 5)
|
data/test/commands/test_pay.rb
CHANGED
@@ -39,11 +39,13 @@ class TestPay < Minitest::Test
|
|
39
39
|
source.init(id, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
|
40
40
|
target = Zold::Id.new
|
41
41
|
amount = Zold::Amount.new(zld: 14.95)
|
42
|
-
Zold::Pay.new(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
Zold::Pay.new(wallets: wallets).run(
|
43
|
+
[
|
44
|
+
'--force', '--private-key=fixtures/id_rsa',
|
45
|
+
id.to_s, target.to_s, amount.to_zld, 'For the car'
|
46
|
+
]
|
47
|
+
)
|
48
|
+
assert_equal(amount * -1, source.balance)
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
@@ -24,6 +24,7 @@ require 'webmock/minitest'
|
|
24
24
|
require_relative '../../lib/zold/wallets'
|
25
25
|
require_relative '../../lib/zold/remotes'
|
26
26
|
require_relative '../../lib/zold/key'
|
27
|
+
require_relative '../../lib/zold/log'
|
27
28
|
require_relative '../../lib/zold/score'
|
28
29
|
require_relative '../../lib/zold/commands/remote'
|
29
30
|
|
@@ -35,10 +36,11 @@ class TestRemote < Minitest::Test
|
|
35
36
|
def test_updates_remote
|
36
37
|
Dir.mktmpdir 'test' do |dir|
|
37
38
|
remotes = Zold::Remotes.new(File.join(dir, 'a/b/c/remotes'))
|
38
|
-
|
39
|
+
zero = Zold::Score::ZERO
|
40
|
+
stub_request(:get, "http://#{zero.host}:#{zero.port}/remotes").to_return(
|
39
41
|
status: 200,
|
40
42
|
body: {
|
41
|
-
score:
|
43
|
+
score: zero.to_h,
|
42
44
|
all: [
|
43
45
|
{ host: 'localhost', port: 888 },
|
44
46
|
{ host: 'localhost', port: 999 }
|
@@ -56,7 +58,7 @@ class TestRemote < Minitest::Test
|
|
56
58
|
)
|
57
59
|
cmd = Zold::Remote.new(remotes: remotes)
|
58
60
|
cmd.run(['clean'])
|
59
|
-
cmd.run(
|
61
|
+
cmd.run(['add', zero.host, zero.port.to_s])
|
60
62
|
cmd.run(%w[add localhost 2])
|
61
63
|
assert_equal(2, remotes.all.count)
|
62
64
|
cmd.run(['update', '--ignore-score-weakness'])
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'minitest/autorun'
|
22
|
+
require 'tmpdir'
|
23
|
+
require 'webmock/minitest'
|
24
|
+
require_relative '../../lib/zold/wallets'
|
25
|
+
require_relative '../../lib/zold/amount'
|
26
|
+
require_relative '../../lib/zold/key'
|
27
|
+
require_relative '../../lib/zold/log'
|
28
|
+
require_relative '../../lib/zold/id'
|
29
|
+
require_relative '../../lib/zold/commands/taxes'
|
30
|
+
|
31
|
+
# TAXES test.
|
32
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
33
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
34
|
+
# License:: MIT
|
35
|
+
class TestTaxes < Minitest::Test
|
36
|
+
def test_pays_taxes
|
37
|
+
Dir.mktmpdir 'test' do |dir|
|
38
|
+
id = Zold::Id.new
|
39
|
+
wallets = Zold::Wallets.new(dir)
|
40
|
+
wallet = wallets.find(id)
|
41
|
+
wallet.init(id, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
|
42
|
+
wallet.add(
|
43
|
+
Zold::Txn.new(
|
44
|
+
1,
|
45
|
+
Time.now - 24 * 60 * 365 * 20,
|
46
|
+
Zold::Amount.new(zld: 19.99),
|
47
|
+
'NOPREFIX', Zold::Id.new, '-'
|
48
|
+
)
|
49
|
+
)
|
50
|
+
remotes = Zold::Remotes.new(File.join(dir, 'a/remotes'))
|
51
|
+
remotes.clean
|
52
|
+
zero = Zold::Score::ZERO
|
53
|
+
remotes.add(zero.host, zero.port)
|
54
|
+
stub_request(:get, "http://#{zero.host}:#{zero.port}/").to_return(
|
55
|
+
status: 200,
|
56
|
+
body: {
|
57
|
+
score: zero.to_h
|
58
|
+
}.to_json
|
59
|
+
)
|
60
|
+
Zold::Taxes.new(
|
61
|
+
wallets: wallets, remotes: remotes
|
62
|
+
).run(['pay', '--private-key=fixtures/id_rsa', id.to_s])
|
63
|
+
assert_equal(Zold::Amount.new(coins: 335_376_547), wallet.balance)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|