zold 0.11.16 → 0.11.17

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 741133a152a47f10deca486c7f68ab98927cb721
4
- data.tar.gz: eecf1c370e17a0dea43cf298477234f88d6d5813
3
+ metadata.gz: c756ab9df322c31f1b31c030d2f6f56971d2ef36
4
+ data.tar.gz: c03dc1d19510c459ed571a40e60d1e47d3ececd9
5
5
  SHA512:
6
- metadata.gz: 8b91d87cf98800345481d0296514a29650df203d345acf732f87246589d92c654612d87f727864b208ba566ed93427c439305c721c1a9801c494a43797fe2c30
7
- data.tar.gz: 4b15be2214801ddf880f0686494dbe8a93c867ce60d597764aac6c3e1ba8e5232b7e289f357bf1aaf3d82575555cca9aabbb1c3b2f73da490f9116ac077ec9ee
6
+ metadata.gz: a2f402cb7258a1f85966d2f9a46e15b4a12d44eccc1150259208221a98141553511b23fbec78d93a780af64a59fe94f3c58a36ab8862e442bd1b76313406eac7
7
+ data.tar.gz: 682b3ad6c5bdec21e0eb95d94c7bac6dd04ad0776027cb96716bfef916bdbb4f4ec935e84f9832b26bc05fe684cb9b7968cd0c7ddfcd3203aabd1909a3061747
@@ -2,6 +2,7 @@ assets:
2
2
  rubygems.yml: zerocracy/home#assets/rubygems.yml
3
3
  id_rsa: zerocracy/home#assets/heroku-key
4
4
  id_rsa.pub: zerocracy/home#assets/heroku-key.pub
5
+ bonus.key: zerocracy/home#assets/zold/bonus.key
5
6
  install: |
6
7
  sudo apt-get -y update
7
8
  sudo gem install pdd
@@ -28,7 +29,8 @@ release:
28
29
  git add Gemfile.lock
29
30
  git add .gitignore
30
31
  git fetch
31
- git commit -m 'ignores' && git push -f heroku $(git symbolic-ref --short HEAD):master
32
+ cp ../bonus.key . && git add bonus.key
33
+ git commit -m 'config' && git push -f heroku $(git symbolic-ref --short HEAD):master
32
34
  curl -f --connect-timeout 15 --retry 5 --retry-delay 30 http://b1.zold.io > /dev/null
33
35
  architect:
34
36
  - yegor256
@@ -38,6 +38,7 @@ end
38
38
 
39
39
  def exec(cmd)
40
40
  Open3.popen2e(cmd) do |stdin, stdout, thr|
41
+ log("Started: #{cmd}")
41
42
  stdin.close
42
43
  loop do
43
44
  line = stdout.gets
@@ -45,6 +46,7 @@ def exec(cmd)
45
46
  log(line)
46
47
  end
47
48
  code = thr.value.exitstatus
49
+ log("Exit code is #{code}: #{cmd}")
48
50
  raise "Exit code #{code} (non zero)" unless code.zero?
49
51
  end
50
52
  end
@@ -0,0 +1,9 @@
1
+ build:
2
+ languages:
3
+ - ruby
4
+ run:
5
+ web: |
6
+ LC_ALL=UTF-8 ./bin/zold node --no-colors --verbose --trace \
7
+ --bind-port=$PORT --port=80 --host=b1.zold.io --threads=0 \
8
+ --invoice=JKFq17yipfjLtX@0000000000000000 --never-reboot \
9
+ --bonus-wallet=81c9c25789b03876 --private-key=bonus.key --bonus-amount=1
@@ -20,12 +20,15 @@
20
20
 
21
21
  require 'slop'
22
22
  require_relative '../score'
23
+ require_relative '../routines'
23
24
  require_relative '../wallets'
24
25
  require_relative '../remotes'
25
26
  require_relative '../verbose_thread'
26
27
  require_relative '../node/entrance'
27
28
  require_relative '../node/front'
28
29
  require_relative '../node/farm'
30
+ require_relative 'push'
31
+ require_relative 'pay'
29
32
 
30
33
  # NODE command.
31
34
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -68,6 +71,14 @@ module Zold
68
71
  o.bool '--never-reboot',
69
72
  'Don\'t reboot when a new version shows up in the network',
70
73
  default: false
74
+ o.string '--bonus-wallet',
75
+ 'The ID of the wallet to regularly send bonuses from (for nodes online)'
76
+ o.string '--bonus-amount',
77
+ 'The amount of ZLD to pay to each remote as a bonus',
78
+ default: '1'
79
+ o.string '--private-key',
80
+ 'The location of RSA private key (default: ~/.ssh/id_rsa)',
81
+ default: '~/.ssh/id_rsa'
71
82
  o.bool '--help', 'Print instructions'
72
83
  end
73
84
  if opts.help?
@@ -117,25 +128,51 @@ module Zold
117
128
  threads: opts[:threads], strength: opts[:strength]
118
129
  )
119
130
  Front.set(:farm, farm)
120
- update = Thread.start do
121
- VerboseThread.new(@log).run(true) do
122
- loop do
123
- sleep(60)
124
- require_relative 'remote'
125
- Remote.new(remotes: remotes, log: @log, farm: farm).run(%w[remote add b1.zold.io 80 --force])
126
- Remote.new(remotes: remotes, log: @log, farm: farm).run(%w[remote trim])
127
- Remote.new(remotes: remotes, log: @log, farm: farm).run(%w[remote update --reboot])
128
- @log.info("Regular update of remote nodes succeeded, total=#{remotes.all.count}")
129
- end
130
- end
131
- end
131
+ routines = routines(wallets, remotes, farm, opts)
132
132
  @log.debug("Starting up the web front at http://#{opts[:host]}:#{opts[:port]}...")
133
133
  begin
134
134
  Front.run!
135
135
  ensure
136
136
  farm.stop
137
- update.exit
137
+ routines.stop
138
+ end
139
+ end
140
+
141
+ private
142
+
143
+ def routines(wallets, remotes, farm, opts)
144
+ routines = Routines.new(@log)
145
+ routines.add do
146
+ require_relative 'remote'
147
+ Remote.new(remotes: remotes, log: @log, farm: farm).run(%w[remote add b1.zold.io 80 --force])
148
+ Remote.new(remotes: remotes, log: @log, farm: farm).run(%w[remote trim])
149
+ Remote.new(remotes: remotes, log: @log, farm: farm).run(%w[remote update --reboot])
150
+ end
151
+ if opts['bonus-wallet']
152
+ routines.add do
153
+ require_relative 'remote'
154
+ winners = Remote.new(remotes: remotes, log: @log, farm: farm).run(
155
+ ['remote', 'elect', opts['bonus-wallet'], '--private-key', opts['private-key']]
156
+ )
157
+ if winners.empty?
158
+ @log.info('No winners elected, won\'t pay any bonuses')
159
+ else
160
+ winners.each do |score|
161
+ Pay.new(wallets: wallets, remotes: remotes, log: @log).run(
162
+ [
163
+ 'pay', opts['bonus-wallet'], score.invoice, opts['bonus-amount'],
164
+ "Hosting bonus for #{score.host}:#{score.port} #{score.value}",
165
+ '--private-key', opts['private-key']
166
+ ]
167
+ )
168
+ Push.new(wallets: wallets, remotes: remotes, log: @log).run(
169
+ ['push', opts['bonus-wallet']]
170
+ )
171
+ end
172
+ end
173
+ end
138
174
  end
175
+ routines
139
176
  end
140
177
 
141
178
  # Fake logging facility for Webrick
@@ -58,6 +58,8 @@ Available commands:
58
58
  Add a new remote node
59
59
  #{Rainbow('remote remove').green} host [port]
60
60
  Remove the remote node
61
+ #{Rainbow('remote elect').green}
62
+ Pick a random remote node as a target for a bonus awarding
61
63
  #{Rainbow('remote trim').green}
62
64
  Remote the least reliable nodes
63
65
  #{Rainbow('remote update').green}
@@ -66,6 +68,9 @@ Available options:"
66
68
  o.bool '--ignore-score-weakness',
67
69
  'Don\'t complain when their score is too weak',
68
70
  default: false
71
+ o.bool '--ignore-score-value',
72
+ 'Don\'t complain when their score is too small',
73
+ default: false
69
74
  o.bool '--force',
70
75
  'Add/remove if if this operation is not possible',
71
76
  default: false
@@ -88,6 +93,8 @@ Available options:"
88
93
  add(mine[1], mine[2] ? mine[2].to_i : Remotes::PORT, opts)
89
94
  when 'remove'
90
95
  remove(mine[1], mine[2] ? mine[2].to_i : Remotes::PORT, opts)
96
+ when 'elect'
97
+ elect(opts)
91
98
  when 'trim'
92
99
  trim(opts)
93
100
  when 'update'
@@ -139,6 +146,26 @@ Available options:"
139
146
  @log.info("There are #{@remotes.all.count} remote nodes in the list")
140
147
  end
141
148
 
149
+ # Returns an array of Zold::Score
150
+ def elect(opts)
151
+ scores = []
152
+ @remotes.all.sample(1).each do |winner|
153
+ @remotes.iterate(@log, farm: @farm) do |r|
154
+ next if r.host != winner[:host] || r.port != winner[:port]
155
+ res = r.http('/').get
156
+ r.assert_code(200, res)
157
+ score = Score.parse_json(JSON.parse(res.body)['score'])
158
+ r.assert_valid_score(score)
159
+ r.assert_score_ownership(score)
160
+ r.assert_score_strength(score) unless opts['ignore-score-weakness']
161
+ r.assert_score_value(score, Tax::EXACT_SCORE) unless opts['ignore-score-value']
162
+ @log.info("Elected: #{score}")
163
+ scores << score
164
+ end
165
+ end
166
+ scores
167
+ end
168
+
142
169
  def trim(opts)
143
170
  @remotes.all.each do |r|
144
171
  remove(r[:host], r[:port], opts) if r[:errors] > Remotes::TOLERANCE
@@ -124,7 +124,7 @@ Available options:"
124
124
  score = Score.parse_json(json['score'])
125
125
  r.assert_valid_score(score)
126
126
  r.assert_score_strength(score)
127
- raise "Score is too small (<#{Tax::EXACT_SCORE})" if score.value < Tax::EXACT_SCORE
127
+ r.assert_score_value(score, Tax::EXACT_SCORE)
128
128
  @log.info("#{r}: #{Rainbow(score.value).green}")
129
129
  best << score
130
130
  end
@@ -87,7 +87,11 @@ module Zold
87
87
  end
88
88
 
89
89
  def assert_score_strength(score)
90
- raise "Score is too weak #{score.strength}" if score.strength < Score::STRENGTH
90
+ raise "Score is too weak #{score.strength}: #{score}" if score.strength < Score::STRENGTH
91
+ end
92
+
93
+ def assert_score_value(score, min)
94
+ raise "Score is too small (<#{min}): #{score}" if score.value < min
91
95
  end
92
96
  end
93
97
 
@@ -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_relative 'log'
22
+ require_relative 'verbose_thread'
23
+
24
+ # Background routines.
25
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
26
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
27
+ # License:: MIT
28
+ module Zold
29
+ # NODE command
30
+ class Routines
31
+ def initialize(log = Log::Quiet.new)
32
+ @log = log
33
+ @threads = []
34
+ end
35
+
36
+ def add(seconds = 60)
37
+ @threads << Thread.start do
38
+ VerboseThread.new(@log).run(true) do
39
+ Thread.current.name = 'routines'
40
+ count = 0
41
+ loop do
42
+ sleep(seconds)
43
+ yield count
44
+ count += 1
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def stop
51
+ @threads.each do |t|
52
+ t.exit
53
+ @log.debug("#{t.name} thread stopped")
54
+ end
55
+ @log.info("#{@threads.count} routine threads stopped")
56
+ end
57
+ end
58
+ end
@@ -23,5 +23,5 @@
23
23
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
24
24
  # License:: MIT
25
25
  module Zold
26
- VERSION = '0.11.16'.freeze
26
+ VERSION = '0.11.17'.freeze
27
27
  end
@@ -1,2 +1 @@
1
1
  b1.zold.io,80,0,0
2
- b2.zold.io,4096,0,0
@@ -69,4 +69,23 @@ class TestRemote < Minitest::Test
69
69
  assert_equal(4, remotes.all.count)
70
70
  end
71
71
  end
72
+
73
+ def test_elects_a_remote
74
+ Dir.mktmpdir 'test' do |dir|
75
+ zero = Zold::Score::ZERO
76
+ remotes = Zold::Remotes.new(File.join(dir, 'remotes.txt'))
77
+ remotes.clean
78
+ remotes.add(zero.host, zero.port)
79
+ stub_request(:get, "http://#{zero.host}:#{zero.port}/").to_return(
80
+ status: 200,
81
+ body: {
82
+ version: Zold::VERSION,
83
+ score: zero.to_h
84
+ }.to_json
85
+ )
86
+ cmd = Zold::Remote.new(remotes: remotes, log: test_log)
87
+ winners = cmd.run(%w[remote elect --ignore-score-value])
88
+ assert_equal(1, winners.count)
89
+ end
90
+ end
72
91
  end
@@ -0,0 +1,41 @@
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_relative 'test__helper'
23
+ require_relative '../lib/zold/routines'
24
+
25
+ # Routines test.
26
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
28
+ # License:: MIT
29
+ class TestRoutines < Minitest::Test
30
+ def test_start_and_stop
31
+ routines = Zold::Routines.new
32
+ list = []
33
+ routines.add(0) do |i|
34
+ list << i
35
+ sleep(6000)
36
+ end
37
+ sleep 0.1 while list.empty?
38
+ routines.stop
39
+ assert_equal(1, list.count)
40
+ end
41
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.16
4
+ version: 0.11.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -296,7 +296,6 @@ files:
296
296
  - Gemfile
297
297
  - INSTALL.md
298
298
  - LICENSE.txt
299
- - Procfile
300
299
  - README.md
301
300
  - Rakefile
302
301
  - appveyor.yml
@@ -318,6 +317,7 @@ files:
318
317
  - fixtures/scripts/calculate-scores.sh
319
318
  - fixtures/scripts/print-helps.sh
320
319
  - fixtures/scripts/push-and-pull.sh
320
+ - heroku.yml
321
321
  - lib/zold.rb
322
322
  - lib/zold/amount.rb
323
323
  - lib/zold/atomic_file.rb
@@ -351,6 +351,7 @@ files:
351
351
  - lib/zold/patch.rb
352
352
  - lib/zold/prefixes.rb
353
353
  - lib/zold/remotes.rb
354
+ - lib/zold/routines.rb
354
355
  - lib/zold/score.rb
355
356
  - lib/zold/signature.rb
356
357
  - lib/zold/tax.rb
@@ -392,6 +393,7 @@ files:
392
393
  - test/test_patch.rb
393
394
  - test/test_prefixes.rb
394
395
  - test/test_remotes.rb
396
+ - test/test_routines.rb
395
397
  - test/test_score.rb
396
398
  - test/test_signature.rb
397
399
  - test/test_tax.rb
@@ -463,6 +465,7 @@ test_files:
463
465
  - test/test_patch.rb
464
466
  - test/test_prefixes.rb
465
467
  - test/test_remotes.rb
468
+ - test/test_routines.rb
466
469
  - test/test_score.rb
467
470
  - test/test_signature.rb
468
471
  - test/test_tax.rb
data/Procfile DELETED
@@ -1 +0,0 @@
1
- web: LC_ALL=UTF-8 ./bin/zold node --no-colors --verbose --trace --bind-port=$PORT --port=80 --host=b1.zold.io --threads=0 --invoice=JKFq17yipfjLtX@0000000000000000 --never-reboot