zold 0.16.20 → 0.16.21

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fecaea03a1281af059406fd284d9b814fac0e4d0646ef6e65d8b4aacbf813169
4
- data.tar.gz: 5e9a58d162b1333189e6346a25e2d24c411ec4bf3a3f074ab2c0a3d3e1185a57
3
+ metadata.gz: f9ed770c6f66e7627f1c23329a2ad5723c1d9ea8dd714db3341fcb48645597c9
4
+ data.tar.gz: 4055ca5daecab2762c3155406c597550188223e2358b1908dd5ed8240a4159a4
5
5
  SHA512:
6
- metadata.gz: 9a71a411222753fc52f30ae2e4c9f7e374832840430cedfde87f5572ee7f1a67f41365bc17ac8fb708feaeb77ac8ad9e4c8c7137f61568d0734ba845f1561a47
7
- data.tar.gz: aad4fc840d9e5c87315f6a4d1c4997e326511eb94910c1aec9496b89e37ea7c7926b0ae55d69f31bc069d374a946eebf12c395060b168a992d2f9c03ddb5a809
6
+ metadata.gz: 7ebc0ae599f38f53b31fd85b30e5beb2cb97c517dff0bd4a1ddb01b3d9e4b2138ed3fa8dfdf0ec741309ba0ed0eabe95b23703d985b48870c5b305ea1966fe7f
7
+ data.tar.gz: 7fb53797974d1af0adbfa2a19d99fc6e8c31e70c326c4a4b24b231d61fad6cd58c6d6a43b574d4b6efebec3f65eb1940f72a7db3c457a31f0ce84683a3d481e0
data/README.md CHANGED
@@ -121,6 +121,12 @@ Grateful users of the system will pay "taxes" to your wallet
121
121
  for the maintenance of their wallets, and the system will occasionally
122
122
  send you bonuses for keeping the node online (approximately 1 ZLD per day).
123
123
 
124
+ If you are lost, run this:
125
+
126
+ ```bash
127
+ $ zold node --help
128
+ ```
129
+
124
130
  ## Frequently Asked Questions
125
131
 
126
132
  > Where are my RSA private/public keys?
data/bin/zold CHANGED
@@ -105,7 +105,7 @@ Available options:"
105
105
  "Home directory (default: #{Dir.pwd})",
106
106
  default: Dir.pwd
107
107
  o.string '--network',
108
- "The name of the network we work in (default: #{Zold::Wallet::MAIN_NETWORK}",
108
+ "The name of the network we work in (default: #{Zold::Wallet::MAIN_NETWORK})",
109
109
  required: true,
110
110
  default: Zold::Wallet::MAIN_NETWORK
111
111
  o.bool '-h', '--help', 'Show these instructions'
@@ -49,7 +49,7 @@ function wait_for_file {
49
49
 
50
50
  function halt_nodes {
51
51
  for p in "$@"; do
52
- pid=$(curl --silent "http://localhost:$p/pid?halt=test" || echo 'absent')
52
+ pid=$(curl --silent "http://127.0.0.1:$p/pid?halt=test" || echo 'absent')
53
53
  if [[ "${pid}" =~ ^[0-9]+$ ]]; then
54
54
  i=0
55
55
  while kill -0 ${pid}; do
@@ -5,12 +5,12 @@ function start_node {
5
5
  mkdir ${port}
6
6
  cd ${port}
7
7
  zold node --trace --invoice=DISTRWALLET@ffffffffffffffff \
8
- --host=localhost --port=${port} --bind-port=${port} \
8
+ --host=127.0.0.1 --port=${port} --bind-port=${port} \
9
9
  --threads=0 --routine-immediately --never-reboot > log.txt &
10
10
  pid=$!
11
11
  echo ${pid} > pid
12
12
  cd ..
13
- wait_for_url http://localhost:${port}/
13
+ wait_for_url http://127.0.0.1:${port}/
14
14
  echo ${port}
15
15
  }
16
16
 
@@ -24,9 +24,9 @@ trap "halt_nodes ${first} ${second}" EXIT
24
24
  # is linked to the first one. The --home argument specifies their
25
25
  # locations.
26
26
  zold --home=${first} remote clean
27
- zold --home=${first} remote add localhost ${second}
27
+ zold --home=${first} remote add 127.0.0.1 ${second}
28
28
  zold --home=${second} remote clean
29
- zold --home=${second} remote add localhost ${first}
29
+ zold --home=${second} remote add 127.0.0.1 ${first}
30
30
 
31
31
  # Locally we create a new root wallet (to avoid negative balance checking)
32
32
  # and connect our local Zold home to the first remote node. Then, we push
@@ -35,10 +35,10 @@ zold --home=${second} remote add localhost ${first}
35
35
  zold --public-key=id_rsa.pub create 0000000000000000
36
36
  zold pay --private-key=id_rsa 0000000000000000 NOPREFIX@aaaabbbbccccdddd 4.95 'For the book'
37
37
  zold remote clean
38
- zold remote add localhost ${first}
38
+ zold remote add 127.0.0.1 ${first}
39
39
  zold push 0000000000000000
40
40
  zold remote clean
41
- zold remote add localhost ${second}
41
+ zold remote add 127.0.0.1 ${second}
42
42
 
43
43
  # Here we fetch the wallet from the second remote node. The wallet has
44
44
  # to be visible there. We are doing a number of attempts with a small
@@ -58,7 +58,7 @@ done
58
58
 
59
59
  # Here we check the JSON of the first node to make sure all status
60
60
  # indicators are clean.
61
- json=$(curl --silent --show-error http://localhost:${first})
61
+ json=$(curl --silent --show-error http://127.0.0.1:${first})
62
62
  if [ ! $(echo ${json} | jq -r '.entrance.queue') == "0" ]; then
63
63
  echo "The queue is not empty after PUSH, it's a bug"
64
64
  exit 5
@@ -4,14 +4,14 @@ port=$(reserve_port)
4
4
  mkdir server
5
5
  cd server
6
6
  zold node --trace --invoice=PULLONSTART@ffffffffffffffff --no-metronome \
7
- --host=localhost --port=${port} --bind-port=${port} \
7
+ --host=127.0.0.1 --port=${port} --bind-port=${port} \
8
8
  --threads=0 --standalone &
9
9
  cd ..
10
10
 
11
11
  wait_for_port ${port}
12
12
 
13
13
  zold remote clean
14
- zold remote add localhost ${port}
14
+ zold remote add 127.0.0.1 ${port}
15
15
 
16
16
  zold --public-key=id_rsa.pub create abcdabcdabcdabcd
17
17
  zold push abcdabcdabcdabcd
@@ -22,9 +22,9 @@ second_port=$(reserve_port)
22
22
  mkdir second
23
23
  cd second
24
24
  zold remote clean
25
- zold remote add localhost ${port}
25
+ zold remote add 127.0.0.1 ${port}
26
26
  zold node --trace --invoice=abcdabcdabcdabcd --no-metronome \
27
- --host=localhost --port=${second_port} --bind-port=${second_port} \
27
+ --host=127.0.0.1 --port=${second_port} --bind-port=${second_port} \
28
28
  --threads=0 &
29
29
 
30
30
  wait_for_port ${second_port}
@@ -5,7 +5,7 @@ port=$(reserve_port)
5
5
  mkdir server
6
6
  cd server
7
7
  zold node --trace --invoice=PUSHNPULL@ffffffffffffffff \
8
- --host=localhost --port=${port} --bind-port=${port} \
8
+ --host=127.0.0.1 --port=${port} --bind-port=${port} \
9
9
  --threads=0 --standalone &
10
10
  pid=$!
11
11
  trap "halt_nodes ${port}" EXIT
@@ -14,7 +14,7 @@ cd ..
14
14
  wait_for_port ${port}
15
15
 
16
16
  zold remote clean
17
- zold remote add localhost ${port}
17
+ zold remote add 127.0.0.1 ${port}
18
18
  zold remote trim
19
19
  zold remote show
20
20
 
@@ -7,7 +7,7 @@ function start_node {
7
7
  zold node $3 --nohup --nohup-command='touch restarted' --nohup-log=log --nohup-max-cycles=0 --nohup-log-truncate=10240 \
8
8
  --expose-version=$2 --save-pid=pid --routine-immediately \
9
9
  --verbose --trace --invoice=REDEPLOY@ffffffffffffffff \
10
- --host=localhost --port=$1 --bind-port=$1 --threads=1 --strength=20 > /dev/null 2>&1
10
+ --host=127.0.0.1 --port=$1 --bind-port=$1 --threads=1 --strength=20 > /dev/null 2>&1
11
11
  wait_for_port $1
12
12
  cat pid
13
13
  cd ..
@@ -20,7 +20,7 @@ low=$(reserve_port)
20
20
  secondary=$(start_node ${low} 1.1.1)
21
21
 
22
22
  zold remote clean
23
- zold remote add localhost ${high} --home=${low} --skip-ping
23
+ zold remote add 127.0.0.1 ${high} --home=${low} --skip-ping
24
24
 
25
25
  trap "halt_nodes ${high}" EXIT
26
26
 
@@ -5,7 +5,7 @@ function start_node {
5
5
  mkdir ${port}
6
6
  cd ${port}
7
7
  zold node --trace --invoice=SPREADWALLETS@ffffffffffffffff \
8
- --host=localhost --port=${port} --bind-port=${port} \
8
+ --host=127.0.0.1 --port=${port} --bind-port=${port} \
9
9
  --threads=0 > log.txt &
10
10
  pid=$!
11
11
  echo ${pid} > pid
@@ -19,16 +19,16 @@ second=$(start_node)
19
19
  trap "halt_nodes ${first} ${second}" EXIT
20
20
 
21
21
  zold --home=${first} remote clean
22
- zold --home=${first} remote add localhost ${second}
22
+ zold --home=${first} remote add 127.0.0.1 ${second}
23
23
  zold --home=${second} remote clean
24
- zold --home=${second} remote add localhost ${first}
24
+ zold --home=${second} remote add 127.0.0.1 ${first}
25
25
 
26
26
  zold --public-key=id_rsa.pub create 0000000000000000
27
27
  zold pay --private-key=id_rsa 0000000000000000 NOPREFIX@aaaabbbbccccdddd 4.95 'To help you, dude!'
28
- zold remote add localhost ${first}
28
+ zold remote add 127.0.0.1 ${first}
29
29
  zold push 0000000000000000
30
30
  zold remote clean
31
- zold remote add localhost ${second}
31
+ zold remote add 127.0.0.1 ${second}
32
32
 
33
33
  i=0
34
34
  until zold fetch 0000000000000000 --ignore-score-weakness; do
@@ -42,7 +42,7 @@ until zold fetch 0000000000000000 --ignore-score-weakness; do
42
42
  sleep 2
43
43
  done
44
44
 
45
- json=$(curl --silent --show-error http://localhost:${first})
45
+ json=$(curl --silent --show-error http://127.0.0.1:${first})
46
46
  if [ ! $(echo ${json} | jq -r '.entrance.queue') == "0" ]; then
47
47
  echo "The queue is not empty after PUSH, it's a bug"
48
48
  exit -1
data/lib/zold/amount.rb CHANGED
@@ -29,24 +29,25 @@ require 'rainbow'
29
29
  module Zold
30
30
  # Amount
31
31
  class Amount
32
- # How many zents are in one ZLD: 2^FRACTION
33
- FRACTION = 32
34
-
35
32
  # Maximum amount of zents
36
33
  MAX = 2**63
37
34
 
35
+ # How many zents are in one ZLD: 2^FRACTION
36
+ FRACTION = 32
37
+ private_constant :FRACTION
38
+
38
39
  def initialize(zents: nil, zld: nil)
39
40
  if !zents.nil?
40
41
  raise "Integer is required, while #{zents.class} provided: #{zents}" unless zents.is_a?(Integer)
41
42
  @zents = zents
42
43
  elsif !zld.nil?
43
44
  raise "Float is required, while #{zld.class} provided: #{zld}" unless zld.is_a?(Float)
44
- @zents = (zld * 2**Amount::FRACTION).to_i
45
+ @zents = (zld * 2**FRACTION).to_i
45
46
  else
46
47
  raise 'You can\'t specify both coints and zld'
47
48
  end
48
- raise "The amount is too big: #{@zents}" if @zents > Amount::MAX
49
- raise "The amount is too small: #{@zents}" if @zents < -Amount::MAX
49
+ raise "The amount is too big: #{@zents}" if @zents > MAX
50
+ raise "The amount is too small: #{@zents}" if @zents < -MAX
50
51
  end
51
52
 
52
53
  ZERO = Amount.new(zents: 0)
@@ -56,7 +57,7 @@ module Zold
56
57
  end
57
58
 
58
59
  def to_zld(digits = 2)
59
- format("%0.#{digits}f", @zents.to_f / 2**Amount::FRACTION)
60
+ format("%0.#{digits}f", @zents.to_f / 2**FRACTION)
60
61
  end
61
62
 
62
63
  def to_s
@@ -120,7 +121,7 @@ module Zold
120
121
  def *(other)
121
122
  raise '* may only work with a number' unless other.is_a?(Integer) || other.is_a?(Float)
122
123
  c = (@zents * other).to_i
123
- raise "Overflow, can't multiply #{@zents} by #{m}" if c > Amount::MAX
124
+ raise "Overflow, can't multiply #{@zents} by #{m}" if c > MAX
124
125
  Amount.new(zents: c)
125
126
  end
126
127
 
@@ -172,9 +172,9 @@ module Zold
172
172
  Front.set(:logging, @log.debug?)
173
173
  home = File.expand_path(opts['home'])
174
174
  Front.set(:home, home)
175
- @log.info("Time: #{Time.now.utc.iso8601}")
175
+ @log.info("Time: #{Time.now.utc.iso8601}; CPUs: #{Concurrent.processor_count}")
176
176
  @log.info("Home directory: #{home}")
177
- @log.info("Ruby version: #{RUBY_VERSION}")
177
+ @log.info("Ruby version: #{RUBY_VERSION}/#{RUBY_PLATFORM}")
178
178
  @log.info("Zold gem version: #{Zold::VERSION}")
179
179
  @log.info("Zold protocol version: #{Zold::PROTOCOL}")
180
180
  @log.info("Network ID: #{opts['network']}")
@@ -182,7 +182,7 @@ module Zold
182
182
  port = opts[:port]
183
183
  address = "#{host}:#{port}".downcase
184
184
  @log.info("Node location: #{address}")
185
- @log.info("Local address: http://localhost:#{opts['bind-port']}/")
185
+ @log.info("Local address: http://127.0.0.1:#{opts['bind-port']}/")
186
186
  @log.info("Remote nodes (#{@remotes.all.count}): \
187
187
  #{@remotes.all.map { |r| "#{r[:host]}:#{r[:port]}" }.join(', ')}")
188
188
  @log.info("Wallets at: #{@wallets.path}")
@@ -48,9 +48,9 @@ module Zold
48
48
  args << "--ignore-node=#{score.host}:#{score.port}" if score
49
49
  cmd.run(args + ['defaults']) unless @opts['routine-immediately']
50
50
  return if @opts['routine-immediately'] && @remotes.all.empty?
51
+ cmd.run(args + ['update'] + (@opts['never-reboot'] ? [] : ['--reboot']))
51
52
  cmd.run(args + ['trim'])
52
53
  cmd.run(args + ['select'])
53
- cmd.run(args + ['update'] + (@opts['never-reboot'] ? [] : ['--reboot']))
54
54
  @log.info("Reconnected, there are #{@remotes.all.count} remote notes: \
55
55
  #{@remotes.all.map { |r| "#{r[:host]}:#{r[:port]}" }.join(', ')}")
56
56
  end
data/lib/zold/http.rb CHANGED
@@ -22,7 +22,6 @@
22
22
 
23
23
  require 'rainbow'
24
24
  require 'uri'
25
- require 'timeout'
26
25
  require 'net/http'
27
26
  require 'backtrace'
28
27
  require 'zold/score'
@@ -56,9 +55,11 @@ module Zold
56
55
 
57
56
  # Read timeout in seconds
58
57
  READ_TIMEOUT = 1
58
+ private_constant :READ_TIMEOUT
59
59
 
60
60
  # Connect timeout in seconds
61
61
  CONNECT_TIMEOUT = 0.4
62
+ private_constant :CONNECT_TIMEOUT
62
63
 
63
64
  def initialize(uri:, score: Score::ZERO, network: 'test')
64
65
  @uri = uri.is_a?(URI) ? uri : URI(uri)
@@ -66,36 +67,32 @@ module Zold
66
67
  @network = network
67
68
  end
68
69
 
69
- def get(timeout: Http::READ_TIMEOUT + Http::CONNECT_TIMEOUT)
70
+ def get(timeout: READ_TIMEOUT + CONNECT_TIMEOUT)
70
71
  http = Net::HTTP.new(@uri.host, @uri.port)
71
72
  http.use_ssl = @uri.scheme == 'https'
72
73
  http.read_timeout = timeout
73
- http.open_timeout = Http::CONNECT_TIMEOUT
74
+ http.open_timeout = CONNECT_TIMEOUT
74
75
  path = @uri.path
75
76
  path += '?' + @uri.query if @uri.query
76
- Timeout.timeout(timeout + Http::CONNECT_TIMEOUT) do
77
- http.request_get(path, headers)
78
- end
77
+ http.request_get(path, headers)
79
78
  rescue StandardError => e
80
79
  Error.new(e)
81
80
  end
82
81
 
83
- def put(body, timeout: Http::READ_TIMEOUT + Http::CONNECT_TIMEOUT)
82
+ def put(body, timeout: READ_TIMEOUT + CONNECT_TIMEOUT)
84
83
  http = Net::HTTP.new(@uri.host, @uri.port)
85
84
  http.use_ssl = @uri.scheme == 'https'
86
85
  http.read_timeout = timeout
87
- http.open_timeout = Http::CONNECT_TIMEOUT
86
+ http.open_timeout = CONNECT_TIMEOUT
88
87
  path = @uri.path
89
88
  path += '?' + @uri.query if @uri.query
90
- Timeout.timeout(timeout + Http::CONNECT_TIMEOUT) do
91
- http.request_put(
92
- path, body,
93
- headers.merge(
94
- 'Content-Type': 'text/plain',
95
- 'Content-Length': body.length.to_s
96
- )
89
+ http.request_put(
90
+ path, body,
91
+ headers.merge(
92
+ 'Content-Type': 'text/plain',
93
+ 'Content-Length': body.length.to_s
97
94
  )
98
- end
95
+ )
99
96
  rescue StandardError => e
100
97
  Error.new(e)
101
98
  end
data/lib/zold/id.rb CHANGED
@@ -27,12 +27,16 @@
27
27
  module Zold
28
28
  # Id of the wallet
29
29
  class Id
30
+ # Pattern to match the ID
31
+ PTN = Regexp.new('^[0-9a-fA-F]{16}$')
32
+ private_constant :PTN
33
+
30
34
  def initialize(id = nil)
31
35
  if id.nil?
32
36
  @id = rand(2**32..2**64 - 1)
33
37
  else
34
38
  raise "Invalid wallet ID type: #{id.class.name}" unless id.is_a?(String)
35
- raise "Invalid wallet ID: #{id}" unless id =~ /^[0-9a-fA-F]{16}$/
39
+ raise "Invalid wallet ID: #{id}" unless id =~ PTN
36
40
  @id = Integer("0x#{id}", 16)
37
41
  end
38
42
  end
data/lib/zold/log.rb CHANGED
@@ -21,6 +21,7 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  require 'rainbow'
24
+ require 'monitor'
24
25
 
25
26
  STDOUT.sync = true
26
27
 
@@ -50,12 +51,12 @@ module Zold
50
51
  class Sync
51
52
  def initialize(log)
52
53
  @log = log
53
- @mutex = Mutex.new
54
+ @monitor = Monitor.new
54
55
  end
55
56
 
56
57
  def debug(msg)
57
58
  return unless debug?
58
- @mutex.synchronize do
59
+ @monitor.synchronize do
59
60
  @log.debug(msg)
60
61
  end
61
62
  end
@@ -66,7 +67,7 @@ module Zold
66
67
 
67
68
  def info(msg)
68
69
  return unless info?
69
- @mutex.synchronize do
70
+ @monitor.synchronize do
70
71
  @log.info(msg)
71
72
  end
72
73
  end
@@ -76,7 +77,7 @@ module Zold
76
77
  end
77
78
 
78
79
  def error(msg)
79
- @mutex.synchronize do
80
+ @monitor.synchronize do
80
81
  @log.error(msg)
81
82
  end
82
83
  end
@@ -185,7 +185,7 @@ in #{Age.new(@start, limit: 1)}")
185
185
 
186
186
  get '/' do
187
187
  content_type('application/json')
188
- JSON.pretty_generate(
188
+ pretty(
189
189
  version: settings.opts['expose-version'],
190
190
  alias: settings.node_alias,
191
191
  network: settings.opts['network'],
@@ -222,7 +222,7 @@ in #{Age.new(@start, limit: 1)}")
222
222
  id = Id.new(params[:id])
223
223
  copy_of(id) do |wallet|
224
224
  content_type('application/json')
225
- JSON.pretty_generate(
225
+ pretty(
226
226
  version: settings.opts['expose-version'],
227
227
  alias: settings.node_alias,
228
228
  protocol: settings.protocol,
@@ -244,7 +244,7 @@ in #{Age.new(@start, limit: 1)}")
244
244
  id = Id.new(params[:id])
245
245
  copy_of(id) do |wallet|
246
246
  content_type('application/json')
247
- JSON.pretty_generate(
247
+ pretty(
248
248
  version: settings.opts['expose-version'],
249
249
  alias: settings.node_alias,
250
250
  protocol: settings.protocol,
@@ -367,7 +367,7 @@ in #{Age.new(@start, limit: 1)}")
367
367
  status(304)
368
368
  return
369
369
  end
370
- JSON.pretty_generate(
370
+ pretty(
371
371
  version: settings.opts['expose-version'],
372
372
  alias: settings.node_alias,
373
373
  score: score.to_h,
@@ -377,7 +377,7 @@ in #{Age.new(@start, limit: 1)}")
377
377
 
378
378
  get '/remotes' do
379
379
  content_type('application/json')
380
- JSON.pretty_generate(
380
+ pretty(
381
381
  version: settings.opts['expose-version'],
382
382
  alias: settings.node_alias,
383
383
  score: score.to_h,
@@ -470,6 +470,13 @@ in #{Age.new(@start, limit: 1)}")
470
470
  POSIX::Spawn::Child.new('ps', 'ax').out.split("\n").select { |t| t.include?('zold') }
471
471
  end
472
472
 
473
+ def pretty(json)
474
+ json.to_json
475
+ # There seems to be some issue with memory leakage at this line, that's
476
+ # why it's disabled for now:
477
+ # JSON.pretty_generate(json)
478
+ end
479
+
473
480
  def score
474
481
  settings.zache.get(:score, lifetime: settings.opts['network'] == Wallet::MAIN_NETWORK ? 60 : 0) do
475
482
  b = settings.farm.best
data/lib/zold/remotes.rb CHANGED
@@ -51,6 +51,7 @@ module Zold
51
51
 
52
52
  # Default nodes and their ports
53
53
  DEFS = CSV.read(File.expand_path(File.join(File.dirname(__FILE__), '../../resources/remotes')))
54
+ private_constant :DEFS
54
55
 
55
56
  # Empty, for standalone mode
56
57
  class Empty
@@ -119,7 +120,7 @@ module Zold
119
120
  end
120
121
  end
121
122
 
122
- def initialize(file:, network: 'test', timeout: Http::READ_TIMEOUT + Http::CONNECT_TIMEOUT)
123
+ def initialize(file:, network: 'test', timeout: 60)
123
124
  @file = file
124
125
  @network = network
125
126
  @timeout = timeout
@@ -141,19 +142,19 @@ module Zold
141
142
  end
142
143
 
143
144
  def defaults
144
- Remotes::DEFS.each do |r|
145
+ DEFS.each do |r|
145
146
  add(r[0], r[1].to_i)
146
147
  end
147
148
  end
148
149
 
149
- def exists?(host, port = Remotes::PORT)
150
+ def exists?(host, port = PORT)
150
151
  raise 'Port has to be of type Integer' unless port.is_a?(Integer)
151
152
  raise 'Host can\'t be nil' if host.nil?
152
153
  raise 'Port can\'t be nil' if port.nil?
153
154
  !load.find { |r| r[:host] == host.downcase && r[:port] == port }.nil?
154
155
  end
155
156
 
156
- def add(host, port = Remotes::PORT)
157
+ def add(host, port = PORT)
157
158
  raise 'Host can\'t be nil' if host.nil?
158
159
  raise 'Host can\'t be empty' if host.empty?
159
160
  raise 'Port can\'t be nil' if port.nil?
@@ -166,7 +167,7 @@ module Zold
166
167
  end
167
168
  end
168
169
 
169
- def remove(host, port = Remotes::PORT)
170
+ def remove(host, port = PORT)
170
171
  raise 'Port has to be of type Integer' unless port.is_a?(Integer)
171
172
  raise 'Host can\'t be nil' if host.nil?
172
173
  raise 'Port can\'t be nil' if port.nil?
@@ -203,7 +204,7 @@ module Zold
203
204
  error(r[:host], r[:port])
204
205
  log.info("#{Rainbow("#{r[:host]}:#{r[:port]}").red}: #{e.message} in #{Age.new(start)}")
205
206
  log.debug(Backtrace.new(e).to_s)
206
- remove(r[:host], r[:port]) if errors > Remotes::TOLERANCE
207
+ remove(r[:host], r[:port]) if errors > TOLERANCE
207
208
  end
208
209
  end
209
210
  idx += 1
@@ -212,7 +213,7 @@ module Zold
212
213
  pool.kill unless pool.wait_for_termination(5 * 60)
213
214
  end
214
215
 
215
- def error(host, port = Remotes::PORT)
216
+ def error(host, port = PORT)
216
217
  raise 'Host can\'t be nil' if host.nil?
217
218
  raise 'Port can\'t be nil' if port.nil?
218
219
  raise 'Port has to be of type Integer' unless port.is_a?(Integer)
@@ -232,7 +233,7 @@ module Zold
232
233
  end
233
234
 
234
235
  def default?(host, port)
235
- !Remotes::DEFS.find { |r| r[0] == host && r[1].to_i == port }.nil?
236
+ !DEFS.find { |r| r[0] == host && r[1].to_i == port }.nil?
236
237
  end
237
238
 
238
239
  private
data/lib/zold/tax.rb CHANGED
@@ -55,6 +55,7 @@ module Zold
55
55
 
56
56
  # Text prefix for taxes details
57
57
  PREFIX = 'TAXES'
58
+ private_constant :PREFIX
58
59
 
59
60
  def initialize(wallet, ignore_score_weakness: false)
60
61
  raise "The wallet must be of type Wallet: #{wallet.class.name}" unless wallet.is_a?(Wallet)
@@ -64,38 +65,38 @@ module Zold
64
65
 
65
66
  # Check whether this tax payment already exists in the wallet.
66
67
  def exists?(details)
67
- !@wallet.txns.find { |t| t.details.start_with?("#{Tax::PREFIX} ") && t.details == details }.nil?
68
+ !@wallet.txns.find { |t| t.details.start_with?("#{PREFIX} ") && t.details == details }.nil?
68
69
  end
69
70
 
70
71
  def details(best)
71
- "#{Tax::PREFIX} #{best.reduced(Tax::EXACT_SCORE).to_text}"
72
+ "#{PREFIX} #{best.reduced(EXACT_SCORE).to_text}"
72
73
  end
73
74
 
74
75
  def pay(pvt, best)
75
- @wallet.sub([Tax::MAX_PAYMENT, debt].min, best.invoice, pvt, details(best))
76
+ @wallet.sub([MAX_PAYMENT, debt].min, best.invoice, pvt, details(best))
76
77
  end
77
78
 
78
79
  def in_debt?
79
- debt > Tax::TRIAL
80
+ debt > TRIAL
80
81
  end
81
82
 
82
83
  def to_text
83
- "A=#{@wallet.age.round} hours, F=#{Tax::FEE.to_i}z/th, T=#{@wallet.txns.count}t, Paid=#{paid}"
84
+ "A=#{@wallet.age.round} hours, F=#{FEE.to_i}z/th, T=#{@wallet.txns.count}t, Paid=#{paid}"
84
85
  end
85
86
 
86
87
  def debt
87
- Tax::FEE * @wallet.txns.count * @wallet.age - paid
88
+ FEE * @wallet.txns.count * @wallet.age - paid
88
89
  end
89
90
 
90
91
  def paid
91
92
  txns = @wallet.txns
92
93
  scored = txns.map do |t|
93
94
  pfx, body = t.details.split(' ', 2)
94
- next if pfx != Tax::PREFIX || body.nil?
95
+ next if pfx != PREFIX || body.nil?
95
96
  score = Score.parse_text(body)
96
- next if !score.valid? || score.value != Tax::EXACT_SCORE
97
+ next if !score.valid? || score.value != EXACT_SCORE
97
98
  next if score.strength < Score::STRENGTH && !@ignore_score_weakness
98
- next if t.amount > Tax::MAX_PAYMENT
99
+ next if t.amount > MAX_PAYMENT
99
100
  t
100
101
  end.compact.uniq(&:details)
101
102
  scored.empty? ? Amount::ZERO : scored.map(&:amount).inject(&:+) * -1
data/lib/zold/txn.rb CHANGED
@@ -36,9 +36,11 @@ module Zold
36
36
  class Txn
37
37
  # Regular expression for details
38
38
  RE_DETAILS = '[a-zA-Z0-9 @\!\?\*_\-\.:,\']+'
39
+ private_constant :RE_DETAILS
39
40
 
40
41
  # Regular expression for prefix
41
42
  RE_PREFIX = '[a-zA-Z0-9]+'
43
+ private_constant :RE_PREFIX
42
44
 
43
45
  attr_reader :id, :date, :amount, :prefix, :bnf, :details, :sign
44
46
  attr_writer :sign, :amount, :bnf
@@ -60,12 +62,12 @@ module Zold
60
62
  raise 'Prefix can\'t be NIL' if prefix.nil?
61
63
  raise "Prefix is too short: \"#{prefix}\"" if prefix.length < 8
62
64
  raise "Prefix is too long: \"#{prefix}\"" if prefix.length > 32
63
- raise "Prefix is wrong: \"#{prefix}\" (#{Txn::RE_PREFIX})" unless prefix =~ Regexp.new("^#{Txn::RE_PREFIX}$")
65
+ raise "Prefix is wrong: \"#{prefix}\" (#{RE_PREFIX})" unless prefix =~ Regexp.new("^#{RE_PREFIX}$")
64
66
  @prefix = prefix
65
67
  raise 'Details can\'t be NIL' if details.nil?
66
68
  raise 'Details can\'t be empty' if details.empty?
67
69
  raise "Details are too long: \"#{details}\"" if details.length > 512
68
- raise "Wrong details \"#{details}\" (#{Txn::RE_DETAILS})" unless details =~ Regexp.new("^#{Txn::RE_DETAILS}$")
70
+ raise "Wrong details \"#{details}\" (#{RE_DETAILS})" unless details =~ Regexp.new("^#{RE_DETAILS}$")
69
71
  @details = details
70
72
  end
71
73
 
@@ -115,20 +117,23 @@ module Zold
115
117
  t
116
118
  end
117
119
 
120
+ # Pattern to match the transaction from text
121
+ PTN = Regexp.new(
122
+ '^' + [
123
+ '(?<id>[0-9a-f]{4})',
124
+ '(?<date>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z)',
125
+ '(?<amount>[0-9a-f]{16})',
126
+ "(?<prefix>#{RE_PREFIX})",
127
+ '(?<bnf>[0-9a-f]{16})',
128
+ "(?<details>#{RE_DETAILS})",
129
+ '(?<sign>[A-Za-z0-9+/]+={0,3})?'
130
+ ].join(';') + '$'
131
+ )
132
+ private_constant :PTN
133
+
118
134
  def self.parse(line, idx = 0)
119
- regex = Regexp.new(
120
- '^' + [
121
- '(?<id>[0-9a-f]{4})',
122
- '(?<date>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z)',
123
- '(?<amount>[0-9a-f]{16})',
124
- "(?<prefix>#{Txn::RE_PREFIX})",
125
- '(?<bnf>[0-9a-f]{16})',
126
- "(?<details>#{Txn::RE_DETAILS})",
127
- '(?<sign>[A-Za-z0-9+/]+={0,3})?'
128
- ].join(';') + '$'
129
- )
130
135
  clean = line.strip
131
- parts = regex.match(clean)
136
+ parts = PTN.match(clean)
132
137
  raise "Invalid line ##{idx}: #{line.inspect} #{regex}" unless parts
133
138
  txn = Txn.new(
134
139
  Hexnum.parse(parts[:id]).to_i,
data/lib/zold/version.rb CHANGED
@@ -25,6 +25,6 @@
25
25
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.16.20'
28
+ VERSION = '0.16.21'
29
29
  PROTOCOL = 2
30
30
  end
@@ -54,7 +54,7 @@ class TestTaxes < Zold::Test
54
54
  end
55
55
  remotes = home.remotes
56
56
  score = Zold::Score.new(host: 'localhost', port: 80, strength: 1, invoice: 'NOPREFIX@0000000000000000')
57
- Zold::Tax::EXACT_SCORE.times { score = score.next }
57
+ 10.times { score = score.next }
58
58
  remotes.add(score.host, score.port)
59
59
  stub_request(:get, "http://#{score.host}:#{score.port}/").to_return(
60
60
  status: 200,
@@ -164,7 +164,7 @@ class FarmTest < Zold::Test
164
164
  end
165
165
  farm = Zold::Farm.new('NOPREFIX5@ffffffffffffffff', file, log: log)
166
166
  assert_equal(1, farm.best.count)
167
- assert(log.msgs.find { |m| m.include?('Invalid score') })
167
+ assert(log.msgs.find { |m| m.include?('Invalid score') }, log.msgs)
168
168
  end
169
169
  end
170
170
  end
@@ -26,6 +26,7 @@ require 'time'
26
26
  require 'securerandom'
27
27
  require 'threads'
28
28
  require 'zold/score'
29
+ require 'memory_profiler'
29
30
  require_relative '../test__helper'
30
31
  require_relative 'fake_node'
31
32
  require_relative '../fake_home'
@@ -38,6 +39,21 @@ class FrontTest < Zold::Test
38
39
  Zold::Front
39
40
  end
40
41
 
42
+ # Use this test to check how much memory is being used after doing a large
43
+ # number of routine operations. There should be no suspicious information
44
+ # in the report, which will be printed to the console.
45
+ def test_memory_leakage
46
+ skip
47
+ report = MemoryProfiler.report(top: 10) do
48
+ FakeNode.new(log: test_log).run(['--no-metronome', '--network=foo', '--threads=0']) do |port|
49
+ 100.times do
50
+ Zold::Http.new(uri: "http://localhost:#{port}/", network: 'foo').get
51
+ end
52
+ end
53
+ end
54
+ report.pretty_print
55
+ end
56
+
41
57
  def test_renders_front_json
42
58
  FakeNode.new(log: test_log).run(['--no-metronome', '--network=foo', '--threads=0']) do |port|
43
59
  res = Zold::Http.new(uri: "http://localhost:#{port}/", network: 'foo').get
data/test/test_http.rb CHANGED
@@ -25,8 +25,10 @@ require 'tmpdir'
25
25
  require 'uri'
26
26
  require 'webmock/minitest'
27
27
  require 'zold/score'
28
+ require 'random-port'
28
29
  require_relative 'test__helper'
29
30
  require_relative '../lib/zold/http'
31
+ require_relative '../lib/zold/verbose_thread'
30
32
 
31
33
  # Http test.
32
34
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -70,35 +72,45 @@ class TestHttp < Zold::Test
70
72
  assert_equal('200', res.code)
71
73
  end
72
74
 
73
- def test_terminates_on_timeout
74
- stub_request(:get, 'http://the-fake-host-99/').to_return do
75
- sleep 100
76
- { body: 'This should never be returned!' }
77
- end
78
- res = Zold::Http.new(uri: 'http://the-fake-host-99/').get
79
- assert_equal('599', res.code)
80
- end
81
-
82
75
  def test_doesnt_terminate_on_long_call
83
- require 'random-port'
84
76
  WebMock.allow_net_connect!
85
77
  RandomPort::Pool::SINGLETON.acquire do |port|
86
78
  thread = Thread.start do
87
- server = TCPServer.new(port)
88
- loop do
79
+ Zold::VerboseThread.new(test_log).run do
80
+ server = TCPServer.new(port)
89
81
  client = server.accept
82
+ client.puts("HTTP/1.1 200 OK\nContent-Length: 4\n\n")
90
83
  sleep 1
91
- client.puts("HTTP/1.1 200 OK\nContent-Length: 4\n\nGood")
84
+ client.puts('Good')
92
85
  client.close
93
86
  end
94
87
  end
95
- res = Zold::Http.new(uri: "http://localhost:#{port}/").get(timeout: 2)
88
+ sleep 0.25
89
+ res = Zold::Http.new(uri: "http://127.0.0.1:#{port}/").get(timeout: 2)
96
90
  assert_equal('200', res.code, res)
97
91
  thread.kill
98
92
  thread.join
99
93
  end
100
94
  end
101
95
 
96
+ def test_terminates_on_timeout
97
+ WebMock.allow_net_connect!
98
+ RandomPort::Pool::SINGLETON.acquire do |port|
99
+ thread = Thread.start do
100
+ Zold::VerboseThread.new(test_log).run do
101
+ server = TCPServer.new(port)
102
+ server.accept
103
+ sleep 400
104
+ end
105
+ end
106
+ sleep 0.25
107
+ res = Zold::Http.new(uri: "http://127.0.0.1:#{port}/").get(timeout: 0.1)
108
+ assert_equal('599', res.code, res)
109
+ thread.kill
110
+ thread.join
111
+ end
112
+ end
113
+
102
114
  def test_sends_valid_version_header
103
115
  stub_request(:get, 'http://some-host-3/')
104
116
  .with(headers: { 'X-Zold-Version' => Zold::VERSION })
data/zold.gemspec CHANGED
@@ -76,11 +76,12 @@ and suggests a different architecture for digital wallet maintenance.'
76
76
  s.add_runtime_dependency 'usagewatch_ext', '0.2.1'
77
77
  s.add_runtime_dependency 'xcop', '0.6'
78
78
  s.add_runtime_dependency 'zache', '0.3.1'
79
- s.add_runtime_dependency 'zold-score', '0.2.0'
79
+ s.add_runtime_dependency 'zold-score', '0.2.2'
80
80
  s.add_development_dependency 'codecov', '0.1.13'
81
+ s.add_development_dependency 'memory_profiler', '0.9.12'
81
82
  s.add_development_dependency 'minitest', '5.11.3'
82
83
  s.add_development_dependency 'minitest-hooks', '1.5.0'
83
- s.add_development_dependency 'random-port', '0.3.0'
84
+ s.add_development_dependency 'random-port', '0.3.1'
84
85
  s.add_development_dependency 'rdoc', '4.3.0'
85
86
  s.add_development_dependency 'rspec-rails', '3.8.1'
86
87
  s.add_development_dependency 'webmock', '3.4.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.20
4
+ version: 0.16.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-11 00:00:00.000000000 Z
11
+ date: 2018-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -324,14 +324,14 @@ dependencies:
324
324
  requirements:
325
325
  - - '='
326
326
  - !ruby/object:Gem::Version
327
- version: 0.2.0
327
+ version: 0.2.2
328
328
  type: :runtime
329
329
  prerelease: false
330
330
  version_requirements: !ruby/object:Gem::Requirement
331
331
  requirements:
332
332
  - - '='
333
333
  - !ruby/object:Gem::Version
334
- version: 0.2.0
334
+ version: 0.2.2
335
335
  - !ruby/object:Gem::Dependency
336
336
  name: codecov
337
337
  requirement: !ruby/object:Gem::Requirement
@@ -346,6 +346,20 @@ dependencies:
346
346
  - - '='
347
347
  - !ruby/object:Gem::Version
348
348
  version: 0.1.13
349
+ - !ruby/object:Gem::Dependency
350
+ name: memory_profiler
351
+ requirement: !ruby/object:Gem::Requirement
352
+ requirements:
353
+ - - '='
354
+ - !ruby/object:Gem::Version
355
+ version: 0.9.12
356
+ type: :development
357
+ prerelease: false
358
+ version_requirements: !ruby/object:Gem::Requirement
359
+ requirements:
360
+ - - '='
361
+ - !ruby/object:Gem::Version
362
+ version: 0.9.12
349
363
  - !ruby/object:Gem::Dependency
350
364
  name: minitest
351
365
  requirement: !ruby/object:Gem::Requirement
@@ -380,14 +394,14 @@ dependencies:
380
394
  requirements:
381
395
  - - '='
382
396
  - !ruby/object:Gem::Version
383
- version: 0.3.0
397
+ version: 0.3.1
384
398
  type: :development
385
399
  prerelease: false
386
400
  version_requirements: !ruby/object:Gem::Requirement
387
401
  requirements:
388
402
  - - '='
389
403
  - !ruby/object:Gem::Version
390
- version: 0.3.0
404
+ version: 0.3.1
391
405
  - !ruby/object:Gem::Dependency
392
406
  name: rdoc
393
407
  requirement: !ruby/object:Gem::Requirement