zold 0.14.17 → 0.14.18

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: 8582f56181daabcedc46abc203d1943bfda757ce
4
- data.tar.gz: e90c0622d71c5982bc1b17d77ee715aa6945bf52
3
+ metadata.gz: 5ecca17ec572da83d30874c74ad40b383e22855e
4
+ data.tar.gz: 501cc2ef09710e3bd6d578d3f8cae99895ae25e8
5
5
  SHA512:
6
- metadata.gz: 34d9806bfa3b4432ceed5edec33133e0488299c9f7265bdac939aa4676f1ed7a15107487f39da8400545fe5974f23ad8cc84a77f6ff70059b1e3d1250eef117a
7
- data.tar.gz: e56681d98fd04e4b2e9eb105036b853a871f1fe0e9d214e91d4db22078bb78f1d0f3e7197313c6162e7c3e93a2c8dbe948dc4a5c7edd1f1d72343df3fa8a9ae2
6
+ metadata.gz: 584cfab45f2f97b6d5bccaee7e285d1637ca546357bb9b08e7a7e30f85789a31ca69e59ec96e72177b6c64568284e0ab982248bc25c0ada8a13ad86580c9496b
7
+ data.tar.gz: '09553f0034eee231dbba5c6d1eccd3c2d4e8e120bb70505f741d1b20f21cd7d103baeca54259c0e5bfad66b97e4b64b62ea3fb536b5eef411b9344faf83fbbfa'
data/.gitignore CHANGED
@@ -5,3 +5,5 @@ Gemfile.lock
5
5
  .bundle/
6
6
  .DS_Store
7
7
  rdoc/
8
+ .zoldata
9
+ farm
@@ -16,7 +16,7 @@ Metrics/AbcSize:
16
16
  Metrics/BlockLength:
17
17
  Max: 100
18
18
  Metrics/ClassLength:
19
- Max: 250
19
+ Max: 300
20
20
  Layout/EndOfLine:
21
21
  EnforcedStyle: lf
22
22
  Metrics/ParameterLists:
data/bin/zold CHANGED
@@ -95,6 +95,8 @@ Available commands:
95
95
  Run node at the given TCP port
96
96
  #{Rainbow('alias').green} [alias] [wallet ID]
97
97
  Set an alias for a wallet
98
+ #{Rainbow('next').green} score
99
+ Generate next score from the provided one
98
100
  #{Rainbow('score').green} [options]
99
101
  Generate score for the given host and port
100
102
  Available options:"
@@ -149,7 +151,7 @@ Available options:"
149
151
  Zold::RenameForeignWallets.new(Dir.pwd, opts['network'], log).exec
150
152
 
151
153
  wallets = Zold::Wallets.new('.')
152
- remotes = Zold::Remotes.new('./.zoldata/remotes', network: opts['network'])
154
+ remotes = Zold::Remotes.new(file: './.zoldata/remotes', network: opts['network'])
153
155
  copies = './.zoldata/copies'
154
156
 
155
157
  case command
@@ -201,6 +203,9 @@ Available options:"
201
203
  when 'score'
202
204
  require_relative '../lib/zold/commands/calculate'
203
205
  Zold::Calculate.new(log: log).run(args)
206
+ when 'next'
207
+ require_relative '../lib/zold/commands/next'
208
+ Zold::Next.new(log: log).run(args)
204
209
  else
205
210
  raise "Command '#{command}' is not supported"
206
211
  end
@@ -5,7 +5,7 @@ shopt -s expand_aliases
5
5
 
6
6
  export RUBYOPT="-W0"
7
7
 
8
- alias zold="$1 --ignore-this-stupid-option --ignore-global-config --trace --network=test --no-colors"
8
+ alias zold="$1 --ignore-this-stupid-option --halt-code=test --ignore-global-config --trace --network=test --no-colors --dump-errors"
9
9
 
10
10
  function reserve_port {
11
11
  python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'
@@ -13,33 +13,53 @@ function reserve_port {
13
13
 
14
14
  function wait_for_url {
15
15
  while ! curl --silent --fail $1 > /dev/null; do
16
- ((p++)) || sleep 1
16
+ ((p++)) || sleep 5
17
17
  if ((p==30)); then
18
- echo URL $1 is not available after $p seconds of waiting
19
- exit -1
18
+ echo "URL $1 is not available after $p seconds of waiting"
19
+ exit 12
20
20
  fi
21
- sleep 1
21
+ sleep 5
22
22
  done
23
23
  }
24
24
 
25
25
  function wait_for_port {
26
26
  while ! nc -z localhost $1; do
27
- ((p++)) || sleep 1
27
+ ((p++)) || sleep 5
28
28
  if ((p==30)); then
29
- echo Port $1 is not available after $p seconds of waiting
30
- exit -1
29
+ echo "Port $1 is not available after $p seconds of waiting"
30
+ exit 13
31
31
  fi
32
- sleep 1
32
+ sleep 5
33
33
  done
34
34
  }
35
35
 
36
36
  function wait_for_file {
37
37
  while [ ! -f $1 ]; do
38
- ((c++)) || sleep 1
38
+ ((c++)) || sleep 5
39
39
  if ((c==30)); then
40
- echo File $1 not found, giving up after $c seconds of waiting
41
- exit -1
40
+ echo "File $1 not found, giving up after $c seconds of waiting"
41
+ exit 14
42
42
  fi
43
- sleep 1
43
+ sleep 5
44
44
  done
45
45
  }
46
+
47
+ function halt_nodes {
48
+ for p in "$@"; do
49
+ pid=$(curl --silent "http://localhost:$p/pid?halt=test" || echo 'absent')
50
+ if [[ "${pid}" =~ ^[0-9]+$ ]]; then
51
+ while kill -0 ${pid}; do
52
+ ((c++)) || sleep 5
53
+ if ((c==30)); then
54
+ echo "Waiting for process ${pid} to die"
55
+ exit 15
56
+ fi
57
+ echo "Still waiting for process ${pid} to die, cycle no.${c}"
58
+ sleep 5
59
+ done
60
+ echo "Process ${pid} is dead!"
61
+ fi
62
+ echo "Node at TCP port ${p} stopped!"
63
+ done
64
+ }
65
+
@@ -1,3 +1,3 @@
1
1
  #!/bin/bash
2
2
 
3
- zold score --host=zold.io --port=4096 --invoice=NOSUFFIX@ffffffffffffffff --strength=2 --max=5
3
+ zold score --host=zold.io --port=4096 --invoice=CALCSCORE@ffffffffffffffff --strength=2 --max=5
@@ -4,7 +4,7 @@ function start_node {
4
4
  port=$(reserve_port)
5
5
  mkdir ${port}
6
6
  cd ${port}
7
- zold node --trace --invoice=NOPREFIX@ffffffffffffffff \
7
+ zold node --trace --invoice=DISTRWALLET@ffffffffffffffff \
8
8
  --host=localhost --port=${port} --bind-port=${port} \
9
9
  --threads=0 --routine-immediately > log.txt &
10
10
  pid=$!
@@ -18,7 +18,7 @@ function start_node {
18
18
  # don't do the TRAP for killing, the test will never end.
19
19
  first=$(start_node)
20
20
  second=$(start_node)
21
- trap "kill -9 $(cat ${first}/pid) $(cat ${second}/pid)" EXIT
21
+ trap "halt_nodes ${first} ${second}" EXIT
22
22
 
23
23
  # The first node is linked to the second one and the second one
24
24
  # is linked to the first one. The --home argument specifies their
@@ -4,11 +4,11 @@ port=$(reserve_port)
4
4
 
5
5
  mkdir server
6
6
  cd server
7
- zold node --trace --invoice=NOPREFIX@ffffffffffffffff \
7
+ zold node --trace --invoice=PUSHNPULL@ffffffffffffffff \
8
8
  --host=localhost --port=${port} --bind-port=${port} \
9
9
  --threads=0 --standalone &
10
10
  pid=$!
11
- trap "kill -9 $pid" EXIT
11
+ trap "halt_nodes ${port}" EXIT
12
12
  cd ..
13
13
 
14
14
  wait_for_port ${port}
@@ -4,9 +4,9 @@ function start_node {
4
4
  mkdir $1
5
5
  cd $1
6
6
  zold remote clean
7
- zold node $3 --nohup --nohup-command='touch restarted' --nohup-log=log \
7
+ zold node $3 --nohup --nohup-command='touch restarted' --nohup-log=log --nohup-max-cycles=0 \
8
8
  --expose-version=$2 --save-pid=pid --routine-immediately \
9
- --verbose --trace --invoice=NOPREFIX@ffffffffffffffff \
9
+ --verbose --trace --invoice=REDEPLOY@ffffffffffffffff \
10
10
  --host=localhost --port=$1 --bind-port=$1 --threads=0 > /dev/null 2>&1
11
11
  wait_for_port $1
12
12
  cat pid
@@ -20,7 +20,7 @@ low=$(reserve_port)
20
20
  secondary=$(start_node ${low} 1.1.1)
21
21
  zold remote add localhost ${high} --home=${low} --skip-ping
22
22
 
23
- trap "kill -9 ${primary} ${secondary}" EXIT
23
+ trap "halt_nodes ${high}" EXIT
24
24
 
25
25
  wait_for_file ${low}/restarted
26
26
 
@@ -6,7 +6,7 @@ zold node --trace --invoice=NOPREFIX@ffffffffffffffff \
6
6
  --host=localhost --port=${port} --bind-port=${port} \
7
7
  --threads=0 --standalone &
8
8
  pid=$!
9
- trap "kill -9 $pid" EXIT
9
+ trap "halt_nodes ${port}" EXIT
10
10
 
11
11
  wait_for_port ${port}
12
12
 
@@ -4,7 +4,7 @@ function start_node {
4
4
  port=$(reserve_port)
5
5
  mkdir ${port}
6
6
  cd ${port}
7
- zold node --trace --invoice=NOPREFIX@ffffffffffffffff \
7
+ zold node --trace --invoice=SPREADWALLETS@ffffffffffffffff \
8
8
  --host=localhost --port=${port} --bind-port=${port} \
9
9
  --threads=0 > log.txt &
10
10
  pid=$!
@@ -16,7 +16,7 @@ function start_node {
16
16
 
17
17
  first=$(start_node)
18
18
  second=$(start_node)
19
- trap "kill -9 $(cat ${first}/pid) $(cat ${second}/pid)" EXIT
19
+ trap "halt_nodes ${first} ${second}" EXIT
20
20
 
21
21
  zold --home=${first} remote clean
22
22
  zold --home=${first} remote add localhost ${second}
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'slop'
24
+ require_relative '../log'
25
+ require_relative '../score'
26
+
27
+ # NEXT command.
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
30
+ # License:: MIT
31
+ module Zold
32
+ # Calculate next score
33
+ class Next
34
+ def initialize(log: Log::Quiet.new)
35
+ @log = log
36
+ end
37
+
38
+ def run(args = [])
39
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
40
+ o.banner = "Usage: zold next [options] score
41
+ Available options:"
42
+ o.bool '--help', 'Print instructions'
43
+ end
44
+ if opts.help?
45
+ @log.info(opts.to_s)
46
+ return
47
+ end
48
+ calculate(opts)
49
+ end
50
+
51
+ private
52
+
53
+ def calculate(opts)
54
+ @log.info(Score.parse(opts.arguments[1]).next.to_s)
55
+ end
56
+ end
57
+ end
@@ -93,6 +93,9 @@ module Zold
93
93
  o.string '--nohup-log',
94
94
  'The file to log output into (default: zold.log)',
95
95
  default: 'zold.log'
96
+ o.string '--halt-code',
97
+ 'The value of HTTP query parameter "halt," which will cause the front-end immediate termination',
98
+ default: ''
96
99
  o.string '--save-pid',
97
100
  'The file to save process ID into right after start (only in NOHUP mode)'
98
101
  o.bool '--never-reboot',
@@ -111,6 +114,10 @@ module Zold
111
114
  "The name of the network (default: #{Wallet::MAIN_NETWORK})",
112
115
  require: true,
113
116
  default: Wallet::MAIN_NETWORK
117
+ o.integer '--nohup-max-cycles',
118
+ 'Maximum amount of nohup re-starts (-1 by default, which means forever)',
119
+ require: true,
120
+ default: -1
114
121
  o.bool '--help', 'Print instructions'
115
122
  end
116
123
  if opts.help?
@@ -129,6 +136,7 @@ module Zold
129
136
  Front.set(:version, opts['expose-version'])
130
137
  Front.set(:protocol, Zold::PROTOCOL)
131
138
  Front.set(:logging, @log.debug?)
139
+ Front.set(:halt, opts['halt-code'])
132
140
  Front.set(:home, Dir.pwd)
133
141
  @log.info("Home directory: #{Dir.pwd}")
134
142
  @log.info("Ruby version: #{RUBY_VERSION}")
@@ -145,7 +153,7 @@ module Zold
145
153
  AccessLog: []
146
154
  )
147
155
  if opts['standalone']
148
- @remotes = Remotes::Empty.new
156
+ @remotes = Zold::Remotes::Empty.new(file: '/tmp/standalone')
149
157
  @log.debug('Running in standalone mode! (will never talk to other remotes)')
150
158
  end
151
159
  Front.set(:ignore_score_weakness, opts['ignore-score-weakness'])
@@ -196,10 +204,10 @@ module Zold
196
204
  @log.info("Starting up the web front at http://#{host}:#{opts[:port]}...")
197
205
  Front.run!
198
206
  @log.info("The web front stopped at http://#{host}:#{opts[:port]}")
207
+ @log.info('Thanks for helping Zold network!')
199
208
  end
200
209
  end
201
210
  end
202
- @log.info("The node #{host}:#{opts[:port]} is shut down, thanks for helping Zold network!")
203
211
  end
204
212
 
205
213
  private
@@ -238,19 +246,26 @@ module Zold
238
246
  end
239
247
  myself = File.expand_path($PROGRAM_NAME)
240
248
  args = ARGV.delete_if { |a| a.start_with?('--nohup', '--home') }
249
+ cycle = 0
241
250
  loop do
242
251
  begin
243
252
  code = exec("#{myself} #{args.join(' ')}", nohup_log)
244
- if code != 0
245
- nohup_log.print("Let's wait for a minute, because of the failure...")
246
- sleep(60)
247
- end
253
+ raise "Exit code is #{code}" if code != 0
248
254
  exec(opts['nohup-command'], nohup_log)
249
255
  rescue StandardError => e
250
256
  nohup_log.print(Backtrace.new(e).to_s)
251
- nohup_log.print("Let's wait for a minutes, because of the exception...")
252
- sleep(60)
257
+ if cycle < opts['nohup-max-cycles']
258
+ nohup_log.print("Let's wait for a minutes, because of the exception...")
259
+ sleep(60)
260
+ end
261
+ end
262
+ next if opts['nohup-max-cycles'].negative?
263
+ cycle += 1
264
+ if cycle > opts['nohup-max-cycles']
265
+ nohup_log.print("There are no more nohup cycles left, after the cycle no.#{cycle}")
266
+ break
253
267
  end
268
+ nohup_log.print("Going for nohup cycle no.#{cycle}")
254
269
  end
255
270
  end
256
271
  Process.detach(pid)
@@ -207,10 +207,13 @@ Available options:"
207
207
  end
208
208
 
209
209
  def trim(opts)
210
- @remotes.all.each do |r|
211
- remove(r[:host], r[:port], opts) if r[:errors] > opts['tolerate']
210
+ all = @remotes.all
211
+ all.each do |r|
212
+ next if r[:errors] <= opts['tolerate']
213
+ remove(r[:host], r[:port], opts)
214
+ @log.info("#{r[:host]}:#{r[:port]} removed because of #{r[:errors]} errors (over #{opts['tolerate']})")
212
215
  end
213
- @log.info("The list of remotes trimmed, #{@remotes.all.count} nodes left there")
216
+ @log.info("The list of #{all.count} remotes trimmed, #{@remotes.all.count} nodes left there")
214
217
  end
215
218
 
216
219
  def update(opts, deep = true)
@@ -256,7 +259,7 @@ in #{(Time.now - start).round(2)}s")
256
259
  end
257
260
 
258
261
  def select(opts)
259
- selected = @remotes.all.sort_by { |r| r[:score] }.first(opts['max-nodes'])
262
+ selected = @remotes.all.sort_by { |r| r[:score] }.reverse.first(opts['max-nodes'])
260
263
  (@remotes.all - selected).each do |r|
261
264
  @remotes.remove(r[:host], r[:port])
262
265
  end
@@ -55,7 +55,6 @@ module Zold
55
55
  @threads << Thread.start do
56
56
  Thread.current.abort_on_exception = true
57
57
  Thread.current.name = r.class.name
58
- Thread.current.priority = -100
59
58
  step = 0
60
59
  while alive
61
60
  start = Time.now
@@ -78,7 +78,6 @@ module Zold
78
78
  Thread.new do
79
79
  Thread.current.abort_on_exception = true
80
80
  Thread.current.name = "f#{t}"
81
- Thread.current.priority = -100
82
81
  loop do
83
82
  VerboseThread.new(@log).run do
84
83
  cycle(host, port, strength, threads)
@@ -90,7 +89,6 @@ module Zold
90
89
  @cleanup = Thread.new do
91
90
  Thread.current.abort_on_exception = true
92
91
  Thread.current.name = 'cleanup'
93
- Thread.current.priority = -100
94
92
  while alive
95
93
  sleep(60) unless strength == 1 # which will only happen in tests
96
94
  VerboseThread.new(@log).run do
@@ -147,6 +145,9 @@ module Zold
147
145
  return unless s.strength >= strength
148
146
  Thread.current.name = s.to_mnemo
149
147
  save(threads, [s.next])
148
+ # score = Score.parse(`ruby #{File.join(File.dirname(__FILE__), '../../../bin/zold')} next "#{s}"`)
149
+ # @log.debug("New score discovered: #{score}")
150
+ # save(threads, [score])
150
151
  cleanup(host, port, strength, threads)
151
152
  end
152
153
 
@@ -49,6 +49,7 @@ module Zold
49
49
  set :lock, false
50
50
  set :show_exceptions, false
51
51
  set :server, 'webrick'
52
+ set :halt, '' # to be injected at node.rb
52
53
  set :dump_errors, false # to be injected at node.rb
53
54
  set :version, VERSION # to be injected at node.rb
54
55
  set :protocol, PROTOCOL # to be injected at node.rb
@@ -69,6 +70,10 @@ module Zold
69
70
  use Rack::Deflater
70
71
 
71
72
  before do
73
+ if !settings.halt.empty? && params[:halt] && params[:halt] == settings.halt
74
+ settings.log.error('Halt signal received, shutting the front end down...')
75
+ Front.stop!
76
+ end
72
77
  check_header(Http::NETWORK_HEADER) do |header|
73
78
  if header != settings.network
74
79
  raise "Network name mismatch at #{request.url}, #{request.ip} is in '#{header}', \
@@ -119,6 +124,11 @@ while #{settings.address} is in '#{settings.network}'"
119
124
  settings.version
120
125
  end
121
126
 
127
+ get '/pid' do
128
+ content_type 'text/plain'
129
+ Process.pid.to_s
130
+ end
131
+
122
132
  get '/score' do
123
133
  content_type 'text/plain'
124
134
  score.to_s
@@ -143,6 +153,7 @@ while #{settings.address} is in '#{settings.network}'"
143
153
  score: score.to_h,
144
154
  pid: Process.pid,
145
155
  cpus: Concurrent.processor_count,
156
+ platform: RUBY_PLATFORM,
146
157
  uptime: `uptime`.strip,
147
158
  threads: "#{Thread.list.select { |t| t.status == 'run' }.count}/#{Thread.list.count}",
148
159
  wallets: settings.wallets.all.count,