zold 0.0.8 → 0.1
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/.github/ISSUE_TEMPLATE.md +12 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +11 -0
- data/.rubocop.yml +9 -1
- data/.simplecov +2 -2
- data/.travis.yml +1 -1
- data/Gemfile +1 -1
- data/LICENSE.txt +1 -1
- data/Procfile +1 -1
- data/README.md +208 -101
- data/Rakefile +2 -1
- data/bin/zold +135 -54
- data/features/cli.feature +1 -1
- data/features/step_definitions/steps.rb +1 -1
- data/features/support/env.rb +1 -1
- data/fixtures/scripts/push-and-pull.sh +35 -0
- data/lib/zold.rb +2 -2
- data/lib/zold/amount.rb +10 -2
- data/lib/zold/commands/{send.rb → clean.rb} +16 -16
- data/lib/zold/commands/create.rb +7 -5
- data/lib/zold/commands/diff.rb +59 -0
- data/lib/zold/commands/fetch.rb +74 -0
- data/lib/zold/commands/{pull.rb → list.rb} +11 -17
- data/lib/zold/commands/merge.rb +50 -0
- data/lib/zold/commands/node.rb +94 -0
- data/lib/zold/commands/pay.rb +58 -0
- data/lib/zold/commands/{check.rb → propagate.rb} +19 -20
- data/lib/zold/commands/push.rb +12 -12
- data/lib/zold/commands/remote.rb +115 -0
- data/lib/zold/commands/{balance.rb → show.rb} +11 -7
- data/lib/zold/copies.rb +126 -0
- data/lib/zold/http.rb +70 -0
- data/lib/zold/id.rb +8 -3
- data/lib/zold/key.rb +2 -2
- data/lib/zold/log.rb +51 -2
- data/lib/zold/node/farm.rb +81 -0
- data/lib/zold/node/front.rb +94 -46
- data/lib/zold/patch.rb +58 -0
- data/lib/zold/remotes.rb +106 -0
- data/lib/zold/score.rb +101 -0
- data/lib/zold/signature.rb +48 -0
- data/lib/zold/version.rb +3 -3
- data/lib/zold/wallet.rb +87 -55
- data/lib/zold/wallets.rb +13 -6
- data/resources/remotes +1 -0
- data/test/commands/test_clean.rb +41 -0
- data/test/commands/test_create.rb +2 -2
- data/test/commands/test_diff.rb +61 -0
- data/test/commands/test_fetch.rb +65 -0
- data/test/commands/test_list.rb +42 -0
- data/test/commands/test_merge.rb +62 -0
- data/test/commands/test_node.rb +56 -0
- data/test/commands/{test_send.rb → test_pay.rb} +10 -11
- data/test/commands/test_remote.rb +60 -0
- data/test/commands/{test_balance.rb → test_show.rb} +6 -8
- data/test/node/fake_node.rb +73 -0
- data/test/node/test_farm.rb +34 -0
- data/test/node/test_front.rb +26 -57
- data/test/test__helper.rb +1 -1
- data/test/test_amount.rb +10 -2
- data/test/test_copies.rb +73 -0
- data/test/test_http.rb +42 -0
- data/test/test_id.rb +2 -2
- data/test/test_key.rb +10 -10
- data/test/test_patch.rb +59 -0
- data/test/test_remotes.rb +72 -0
- data/test/test_score.rb +79 -0
- data/test/test_signature.rb +45 -0
- data/test/test_wallet.rb +18 -35
- data/test/test_wallets.rb +14 -3
- data/test/test_zold.rb +52 -5
- data/zold.gemspec +5 -3
- metadata +92 -21
- data/CONTRIBUTING.md +0 -19
- data/views/index.haml +0 -6
- data/views/layout.haml +0 -26
- data/views/not_found.haml +0 -3
@@ -0,0 +1,59 @@
|
|
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 'tempfile'
|
22
|
+
require 'diffy'
|
23
|
+
require_relative '../log.rb'
|
24
|
+
require_relative '../patch.rb'
|
25
|
+
require_relative '../wallet.rb'
|
26
|
+
|
27
|
+
# DIFF command.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
module Zold
|
32
|
+
# DIFF pulling command
|
33
|
+
class Diff
|
34
|
+
def initialize(wallet:, copies:, log: Log::Quiet.new)
|
35
|
+
@wallet = wallet
|
36
|
+
@copies = copies
|
37
|
+
@log = log
|
38
|
+
end
|
39
|
+
|
40
|
+
def run(_ = [])
|
41
|
+
raise 'There are no remote copies, try FETCH first' if @copies.all.empty?
|
42
|
+
cps = @copies.all.sort_by { |c| c[:score] }.reverse
|
43
|
+
patch = Patch.new
|
44
|
+
patch.start(Wallet.new(cps[0][:path]))
|
45
|
+
cps[1..-1].each do |c|
|
46
|
+
patch.join(Wallet.new(c[:path]))
|
47
|
+
end
|
48
|
+
before = File.read(@wallet.path)
|
49
|
+
after = ''
|
50
|
+
Tempfile.open do |f|
|
51
|
+
patch.save(f, overwrite: true)
|
52
|
+
after = File.read(f)
|
53
|
+
end
|
54
|
+
diff = Diffy::Diff.new(before, after, context: 0).to_s(:color)
|
55
|
+
@log.info(diff)
|
56
|
+
diff
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,74 @@
|
|
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 'uri'
|
22
|
+
require 'json'
|
23
|
+
require 'time'
|
24
|
+
require_relative '../log.rb'
|
25
|
+
require_relative '../http.rb'
|
26
|
+
require_relative '../score.rb'
|
27
|
+
|
28
|
+
# FETCH command.
|
29
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
31
|
+
# License:: MIT
|
32
|
+
module Zold
|
33
|
+
# FETCH pulling command
|
34
|
+
class Fetch
|
35
|
+
def initialize(wallet:, remotes:, copies:, log: Log::Quiet.new)
|
36
|
+
@wallet = wallet
|
37
|
+
@remotes = remotes
|
38
|
+
@copies = copies
|
39
|
+
@log = log
|
40
|
+
end
|
41
|
+
|
42
|
+
def run(_ = [])
|
43
|
+
total = 0
|
44
|
+
@remotes.all.each do |r|
|
45
|
+
uri = URI("#{r[:home]}wallet/#{@wallet.id}")
|
46
|
+
res = Http.new(uri).get
|
47
|
+
unless res.code == '200'
|
48
|
+
@log.error("#{r[:host]}:#{r[:port]} \
|
49
|
+
#{Rainbow(res.code).red}/#{res.message} at #{uri}")
|
50
|
+
next
|
51
|
+
end
|
52
|
+
json = JSON.parse(res.body)
|
53
|
+
score = Score.new(
|
54
|
+
Time.parse(json['score']['time']),
|
55
|
+
r[:host],
|
56
|
+
r[:port],
|
57
|
+
json['score']['suffixes']
|
58
|
+
)
|
59
|
+
unless score.valid?
|
60
|
+
@log.error("#{r[:host]}:#{r[:port]} invalid score")
|
61
|
+
next
|
62
|
+
end
|
63
|
+
total += 1
|
64
|
+
@copies.add(json['body'], r[:host], r[:port], score.value)
|
65
|
+
@log.info(
|
66
|
+
"#{r[:host]}:#{r[:port]} #{json['body'].length}b/\
|
67
|
+
#{Rainbow(score.value).green}"
|
68
|
+
)
|
69
|
+
end
|
70
|
+
@log.debug("#{total} copies fetched, \
|
71
|
+
there are #{@copies.all.count} available locally")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -20,29 +20,23 @@
|
|
20
20
|
|
21
21
|
require_relative '../log.rb'
|
22
22
|
|
23
|
-
#
|
23
|
+
# LIST command.
|
24
24
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
25
|
-
# Copyright:: Copyright (c) 2018
|
25
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
26
26
|
# License:: MIT
|
27
27
|
module Zold
|
28
|
-
#
|
29
|
-
class
|
30
|
-
def initialize(
|
31
|
-
@
|
28
|
+
# LIST command
|
29
|
+
class List
|
30
|
+
def initialize(wallets:, log: Log::Quiet.new)
|
31
|
+
@wallets = wallets
|
32
32
|
@log = log
|
33
33
|
end
|
34
34
|
|
35
|
-
def run
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
def run(_ = [])
|
36
|
+
@wallets.all.each do |id|
|
37
|
+
wallet = Wallet.new(File.join(@wallets.path, id))
|
38
|
+
@log.info("#{id}: #{wallet.balance}")
|
39
39
|
end
|
40
|
-
unless response.code.to_i == 200
|
41
|
-
raise "Failed to pull from the the node, code=#{response.code}"
|
42
|
-
end
|
43
|
-
File.write(@wallet.path, response.body)
|
44
|
-
@log.info("The #{@wallet} pulled from the server")
|
45
|
-
@wallet
|
46
40
|
end
|
47
41
|
end
|
48
42
|
end
|
@@ -0,0 +1,50 @@
|
|
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_relative '../log.rb'
|
22
|
+
require_relative '../wallet.rb'
|
23
|
+
require_relative '../patch.rb'
|
24
|
+
|
25
|
+
# MERGE command.
|
26
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
27
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
28
|
+
# License:: MIT
|
29
|
+
module Zold
|
30
|
+
# MERGE pulling command
|
31
|
+
class Merge
|
32
|
+
def initialize(wallet:, copies:, log: Log::Quiet.new)
|
33
|
+
@wallet = wallet
|
34
|
+
@copies = copies
|
35
|
+
@log = log
|
36
|
+
end
|
37
|
+
|
38
|
+
def run(_ = [])
|
39
|
+
raise 'There are no remote copies, try FETCH first' if @copies.all.empty?
|
40
|
+
cps = @copies.all.sort_by { |c| c[:score] }.reverse
|
41
|
+
patch = Patch.new
|
42
|
+
patch.start(Wallet.new(cps[0][:path]))
|
43
|
+
cps[1..-1].each do |c|
|
44
|
+
patch.join(Wallet.new(c[:path]))
|
45
|
+
end
|
46
|
+
patch.save(@wallet.path, overwrite: true)
|
47
|
+
@log.debug("Merged successfully into #{@wallet.path}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,94 @@
|
|
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 'slop'
|
22
|
+
require_relative '../node/front.rb'
|
23
|
+
require_relative '../log.rb'
|
24
|
+
require_relative '../node/front'
|
25
|
+
|
26
|
+
# NODE command.
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
module Zold
|
31
|
+
# NODE command
|
32
|
+
class Node
|
33
|
+
def initialize(log: Log::Quiet.new)
|
34
|
+
@log = log
|
35
|
+
end
|
36
|
+
|
37
|
+
def run(args = [])
|
38
|
+
opts = Slop.parse(args, help: true) do |o|
|
39
|
+
o.banner = 'Usage: zold node [options]'
|
40
|
+
o.integer '--port', 'TCP port to open for the Net (default: 80)',
|
41
|
+
default: 80
|
42
|
+
o.integer '--bind-port', 'TCP port to listen on (default: 80)',
|
43
|
+
default: 80
|
44
|
+
o.string '--host', 'Host name (default: 127.0.0.1)',
|
45
|
+
default: '127.0.0.1'
|
46
|
+
o.string '--home', 'Home directory (default: current directory)',
|
47
|
+
default: Dir.pwd
|
48
|
+
o.integer '--threads',
|
49
|
+
'How many threads to use for scores finding (default: 8)',
|
50
|
+
default: 8
|
51
|
+
o.bool '--help', 'Print instructions'
|
52
|
+
end
|
53
|
+
if opts.help?
|
54
|
+
@log.info(opts.to_s)
|
55
|
+
return
|
56
|
+
end
|
57
|
+
Zold::Front.set(:suppress_messages, true)
|
58
|
+
Zold::Front.set(:log, @log)
|
59
|
+
Zold::Front.set(:logging, @log.debug?)
|
60
|
+
Zold::Front.set(
|
61
|
+
:server_settings,
|
62
|
+
Logger: WebrickLog.new(@log),
|
63
|
+
AccessLog: []
|
64
|
+
)
|
65
|
+
Zold::Front.set(:port, opts['bind-port'])
|
66
|
+
FileUtils.mkdir_p(opts[:home])
|
67
|
+
Zold::Front.set(:home, opts[:home])
|
68
|
+
farm = Farm.new(log: @log)
|
69
|
+
farm.start(opts[:host], opts[:port], threads: opts[:threads])
|
70
|
+
Zold::Front.set(:farm, farm)
|
71
|
+
@log.debug('Starting up the web front...')
|
72
|
+
begin
|
73
|
+
Zold::Front.run!
|
74
|
+
ensure
|
75
|
+
farm.stop
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Fake logging facility for Webrick
|
80
|
+
class WebrickLog
|
81
|
+
def initialize(log)
|
82
|
+
@log = log
|
83
|
+
end
|
84
|
+
|
85
|
+
def info(msg)
|
86
|
+
@log.debug(msg)
|
87
|
+
end
|
88
|
+
|
89
|
+
def debug(msg)
|
90
|
+
@log.debug(msg)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,58 @@
|
|
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 'slop'
|
22
|
+
require_relative '../log.rb'
|
23
|
+
|
24
|
+
# PAY command.
|
25
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
26
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
27
|
+
# License:: MIT
|
28
|
+
module Zold
|
29
|
+
# Money sending command
|
30
|
+
class Pay
|
31
|
+
def initialize(payer:, receiver:, amount:,
|
32
|
+
pvtkey:, details: '-', log: Log::Quiet.new)
|
33
|
+
@payer = payer
|
34
|
+
@receiver = receiver
|
35
|
+
@amount = amount
|
36
|
+
@pvtkey = pvtkey
|
37
|
+
@details = details
|
38
|
+
@log = log
|
39
|
+
end
|
40
|
+
|
41
|
+
def run(args = [])
|
42
|
+
opts = Slop.parse(args) do |o|
|
43
|
+
o.bool '--force', 'Ignore all validations'
|
44
|
+
end
|
45
|
+
unless opts['force']
|
46
|
+
raise "The amount can't be negative: #{@amount}" if @amount.negative?
|
47
|
+
if !@payer.root? && @payer.balance < @amount
|
48
|
+
raise "There is not enough funds in #{@payer} to send #{@amount}, \
|
49
|
+
only #{@payer.balance} left"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
txn = @payer.sub(@amount, @receiver, @pvtkey, @details)
|
53
|
+
@log.debug("#{@amount} sent from #{@payer} to #{@receiver}: #{@details}")
|
54
|
+
@log.info(txn[:id])
|
55
|
+
txn
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -19,36 +19,35 @@
|
|
19
19
|
# SOFTWARE.
|
20
20
|
|
21
21
|
require_relative '../log.rb'
|
22
|
-
require_relative '../
|
23
|
-
require_relative '
|
22
|
+
require_relative '../wallet.rb'
|
23
|
+
require_relative '../wallets.rb'
|
24
24
|
|
25
|
-
#
|
25
|
+
# PROPAGATE command.
|
26
26
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
27
|
-
# Copyright:: Copyright (c) 2018
|
27
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
28
28
|
# License:: MIT
|
29
29
|
module Zold
|
30
|
-
#
|
31
|
-
class
|
30
|
+
# PROPAGATE pulling command
|
31
|
+
class Propagate
|
32
32
|
def initialize(wallet:, wallets:, log: Log::Quiet.new)
|
33
33
|
@wallet = wallet
|
34
34
|
@wallets = wallets
|
35
35
|
@log = log
|
36
36
|
end
|
37
37
|
|
38
|
-
def run
|
39
|
-
@wallet.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
def run(_ = [])
|
39
|
+
me = @wallet.id
|
40
|
+
@wallet.txns.select { |t| t[:amount].negative? }.each do |t|
|
41
|
+
target = @wallets.find(t[:bnf])
|
42
|
+
unless target.exists?
|
43
|
+
@log.debug("#{t[:amount].mul(-1)} to #{t[:bnf]}: wallet is absent")
|
44
|
+
next
|
45
|
+
end
|
46
|
+
next if target.has?(t[:id], me)
|
47
|
+
target.add(t)
|
48
|
+
@log.info("#{t[:amount].mul(-1)} to #{t[:bnf]}")
|
45
49
|
end
|
46
|
-
|
47
|
-
if balance.negative? && !@wallet.root?
|
48
|
-
raise "Negative balance of #{@wallet} is not allowed: #{balance}"
|
49
|
-
end
|
50
|
-
@log.info("The #{@wallet} is clean")
|
51
|
-
true
|
50
|
+
@log.debug('Wallet propagated successfully')
|
52
51
|
end
|
53
52
|
end
|
54
53
|
end
|
data/lib/zold/commands/push.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2018
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -20,30 +20,30 @@
|
|
20
20
|
|
21
21
|
require 'net/http'
|
22
22
|
require_relative '../log.rb'
|
23
|
+
require_relative '../http.rb'
|
23
24
|
|
24
25
|
# PUSH command.
|
25
26
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
26
|
-
# Copyright:: Copyright (c) 2018
|
27
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
27
28
|
# License:: MIT
|
28
29
|
module Zold
|
29
30
|
# Wallet pushing command
|
30
31
|
class Push
|
31
|
-
def initialize(wallet:, log: Log::Quiet.new)
|
32
|
+
def initialize(wallet:, remotes:, log: Log::Quiet.new)
|
32
33
|
@wallet = wallet
|
34
|
+
@remotes = remotes
|
33
35
|
@log = log
|
34
36
|
end
|
35
37
|
|
36
|
-
def run
|
38
|
+
def run(_ = [])
|
37
39
|
raise 'The wallet is absent' unless @wallet.exists?
|
38
|
-
|
39
|
-
|
40
|
-
response =
|
41
|
-
|
40
|
+
remote = @remotes.all[0]
|
41
|
+
uri = URI("#{remote[:home]}/wallet/#{@wallet.id}")
|
42
|
+
response = Http.new(uri).put(File.read(@wallet.path))
|
43
|
+
unless response.code == '200'
|
44
|
+
raise "Failed to push to #{uri}: #{response.code}/#{response.message}"
|
42
45
|
end
|
43
|
-
|
44
|
-
raise "Failed to push to the node, code=#{response.code}"
|
45
|
-
end
|
46
|
-
@log.info("The #{@wallet.id} pushed to the server")
|
46
|
+
@log.info("The #{@wallet.id} pushed to #{uri}")
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|