zold-score 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5ad77bc5ced6810f6d1e26f8032844499b395b3df3ad4cf385e2c07803e7c98f
4
+ data.tar.gz: f5e373d1aa2886380bd3e524b5fc3d504a12dba36892099f1d414ed6962e4229
5
+ SHA512:
6
+ metadata.gz: 2927a86ebcd00fd33d404cfd6fad6a4a18cc2a9de0cfbea8b45f57a18c6b3b8c75c1fbcde32dbe37d6ad4fd7ca0f40f35657e8d709acd909336caa4ff23a99e1
7
+ data.tar.gz: 2a9194e4d45ef64ea965434ec2a6cc43879add8d4c939a963bdfb04ed05e780ad7d84f0b42083458413baae0c622854b793552691ad03727f54b476a6e1e2e33
@@ -0,0 +1,9 @@
1
+ errors:
2
+ - yegor256@gmail.com
3
+ # alerts:
4
+ # github:
5
+ # - yegor256
6
+
7
+ tags:
8
+ - pdd
9
+ - bug
@@ -0,0 +1,9 @@
1
+ # Check out all text files in UNIX format, with LF as end of line
2
+ # Don't change this file. If you have any ideas about it, please
3
+ # submit a separate issue about it and we'll discuss.
4
+
5
+ * text=auto eol=lf
6
+ *.rb ident
7
+ *.xml ident
8
+ *.png binary
9
+ *.pdf binary
@@ -0,0 +1,7 @@
1
+ coverage/
2
+ .idea/
3
+ *.gem
4
+ .bundle/
5
+ .DS_Store
6
+ rdoc/
7
+ Gemfile.lock
data/.pdd ADDED
@@ -0,0 +1,7 @@
1
+ --source=.
2
+ --verbose
3
+ --exclude target/**/*
4
+ --exclude coverage/**/*
5
+ --rule min-words:20
6
+ --rule min-estimate:15
7
+ --rule max-estimate:90
@@ -0,0 +1,16 @@
1
+ AllCops:
2
+ DisplayCopNames: true
3
+ TargetRubyVersion: 2.3.3
4
+
5
+ Metrics/LineLength:
6
+ Max: 120
7
+ Metrics/AbcSize:
8
+ Max: 25
9
+ Metrics/MethodLength:
10
+ Max: 25
11
+ Metrics/ClassLength:
12
+ Max: 150
13
+ Metrics/ParameterLists:
14
+ Max: 7
15
+ Layout/AlignParameters:
16
+ Enabled: false
@@ -0,0 +1,26 @@
1
+ assets:
2
+ rubygems.yml: zerocracy/home#assets/rubygems.yml
3
+ install: |-
4
+ export GEM_HOME=~/.ruby
5
+ export GEM_PATH=$GEM_HOME:$GEM_PATH
6
+ release:
7
+ script: |-
8
+ bundle install
9
+ rake
10
+ rm -rf *.gem
11
+ sed -i "s/0\.0\.0/${tag}/g" zold-score.gemspec
12
+ git add zold-score.gemspec
13
+ git commit -m "Version set to ${tag}"
14
+ gem build zold-score.gemspec
15
+ chmod 0600 ../rubygems.yml
16
+ gem push *.gem --config-file ../rubygems.yml
17
+ commanders:
18
+ - yegor256
19
+ architect:
20
+ - yegor256
21
+ merge:
22
+ commanders: []
23
+ script: |-
24
+ bundle install
25
+ rake
26
+ deploy: {}
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
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
+ if Gem.win_platform? then
24
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
25
+ SimpleCov::Formatter::HTMLFormatter
26
+ ]
27
+ SimpleCov.start do
28
+ add_filter "/test/"
29
+ add_filter "/features/"
30
+ end
31
+ else
32
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
33
+ [SimpleCov::Formatter::HTMLFormatter]
34
+ )
35
+ SimpleCov.start do
36
+ add_filter "/test/"
37
+ add_filter "/features/"
38
+ # minimum_coverage 30
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ - 2.3.3
5
+ cache: bundler
6
+ branches:
7
+ only:
8
+ - master
9
+ install:
10
+ - travis_retry bundle update
11
+ - gem install pdd
12
+ script:
13
+ - pdd -f /dev/null
14
+ - export RUBYOPT="-W0"
15
+ - rake --quiet
16
+ after_success:
17
+ - "bash <(curl -s https://codecov.io/bash)"
data/Gemfile ADDED
@@ -0,0 +1,24 @@
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 NONINFRINGEMENT. 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
+ source 'https://rubygems.org'
24
+ gemspec
@@ -0,0 +1,21 @@
1
+ (The MIT License)
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 NONINFRINGEMENT. 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.
@@ -0,0 +1,36 @@
1
+ <img src="http://www.zold.io/logo.svg" width="92px" height="92px"/>
2
+
3
+ [![Donate via Zerocracy](https://www.0crat.com/contrib-badge/CAZPZR9FS.svg)](https://www.0crat.com/contrib/CAZPZR9FS)
4
+
5
+ [![EO principles respected here](http://www.elegantobjects.org/badge.svg)](http://www.elegantobjects.org)
6
+ [![Managed by Zerocracy](https://www.0crat.com/badge/CAZPZR9FS.svg)](https://www.0crat.com/p/CAZPZR9FS)
7
+ [![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/zold)](http://www.rultor.com/p/yegor256/zold)
8
+ [![We recommend RubyMine](http://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
9
+
10
+ [![Build Status](https://travis-ci.org/zold-io/zold-score.svg)](https://travis-ci.org/zold-io/zold-score)
11
+ [![Build status](https://ci.appveyor.com/api/projects/status/f4ct91inx6nfb5eg?svg=true)](https://ci.appveyor.com/project/yegor256/zold-score)
12
+ [![PDD status](http://www.0pdd.com/svg?name=zold-io/zold-score)](http://www.0pdd.com/p?name=zold-io/zold-score)
13
+ [![Gem Version](https://badge.fury.io/rb/zold-score.svg)](http://badge.fury.io/rb/zold-score)
14
+ [![Test Coverage](https://img.shields.io/codecov/c/github/zold-io/zold-score.svg)](https://codecov.io/github/zold-io/zold-score?branch=master)
15
+
16
+ Here is the [White Paper](https://papers.zold.io/wp.pdf).
17
+
18
+ Join our [Telegram group](https://t.me/zold_io) to discuss it all live.
19
+
20
+ The license is [MIT](https://github.com/zold-io/zold-score/blob/master/LICENSE.txt).
21
+
22
+ This small Ruby Gem calculates the score for Zold nodes.
23
+
24
+ # How to contribute
25
+
26
+ Read [these guidelines](https://www.yegor256.com/2014/04/15/github-guidelines.html).
27
+ Make sure you build is green before you contribute
28
+ your pull request. You will need to have [Ruby](https://www.ruby-lang.org/en/) 2.3+ and
29
+ [Bundler](https://bundler.io/) installed. Then:
30
+
31
+ ```
32
+ $ bundle update
33
+ $ rake
34
+ ```
35
+
36
+ If it's clean and you don't see any error messages, submit your pull request.
@@ -0,0 +1,71 @@
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 NONINFRINGEMENT. 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 'rubygems'
24
+ require 'rake'
25
+ require 'rdoc'
26
+ require 'rake/clean'
27
+
28
+ def name
29
+ @name ||= File.basename(Dir['*.gemspec'].first, '.*')
30
+ end
31
+
32
+ def version
33
+ Gem::Specification.load(Dir['*.gemspec'].first).version
34
+ end
35
+
36
+ task default: %i[clean test rubocop copyright]
37
+
38
+ require 'rake/testtask'
39
+ desc 'Run all unit tests'
40
+ Rake::TestTask.new(:test) do |test|
41
+ ENV['TEST_QUIET_LOG'] = 'true' if ARGV.include?('--quiet')
42
+ Rake::Cleaner.cleanup_files(['coverage'])
43
+ test.libs << 'lib' << 'test'
44
+ test.pattern = 'test/**/test_*.rb'
45
+ test.verbose = true
46
+ test.warning = false
47
+ end
48
+
49
+ require 'rdoc/task'
50
+ desc 'Build RDoc documentation'
51
+ Rake::RDocTask.new do |rdoc|
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "#{name} #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
57
+
58
+ require 'rubocop/rake_task'
59
+ desc 'Run RuboCop on all directories'
60
+ RuboCop::RakeTask.new(:rubocop) do |task|
61
+ task.fail_on_error = true
62
+ task.requires << 'rubocop-rspec'
63
+ end
64
+
65
+ task :copyright do
66
+ sh "grep -q -r '#{Date.today.strftime('%Y')}' \
67
+ --include '*.rb' \
68
+ --include '*.txt' \
69
+ --include 'Rakefile' \
70
+ ."
71
+ end
@@ -0,0 +1,38 @@
1
+ version: '{build}'
2
+ skip_tags: true
3
+ clone_depth: 10
4
+ branches:
5
+ only:
6
+ - master
7
+ except:
8
+ - gh-pages
9
+ os: Windows Server 2012
10
+ environment:
11
+ matrix:
12
+ - ruby_version: "23-x64"
13
+ - ruby_version: "24-x64"
14
+ - ruby_version: "25-x64"
15
+ install:
16
+ - ps: |
17
+ $Env:PATH = "C:\Ruby${Env:ruby_version}\bin;${Env:PATH}"
18
+ if ($Env:ruby_version -match "^23" ) {
19
+ # RubyInstaller; download OpenSSL headers from OpenKnapsack Project
20
+ $Env:openssl_dir = "C:\Ruby${Env:ruby_version}"
21
+ appveyor DownloadFile http://dl.bintray.com/oneclick/OpenKnapsack/x64/openssl-1.0.2j-x64-windows.tar.lzma
22
+ 7z e openssl-1.0.2j-x64-windows.tar.lzma
23
+ 7z x -y -oC:\Ruby${Env:ruby_version} openssl-1.0.2j-x64-windows.tar
24
+ } else {
25
+ # RubyInstaller2; openssl package seems to be installed already
26
+ $Env:openssl_dir = "C:\msys64\mingw64"
27
+ }
28
+ - bundle config --local path vendor/bundle
29
+ - bundle config build.openssl --with-openssl-dir=%openssl_dir%
30
+ - ruby -v
31
+ - bundle -v
32
+ build_script:
33
+ - bundle update
34
+ - bundle install
35
+ test_script:
36
+ - bundle exec rake --quiet
37
+ cache:
38
+ - vendor/bundle
@@ -0,0 +1,239 @@
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 'openssl'
24
+ require 'time'
25
+
26
+ # Zold score.
27
+ #
28
+ # To calculate a score you first have to create a zero score and then
29
+ # call its <tt>next()</tt> method:
30
+ #
31
+ # first = Score.new(host: 'example.org', invoice: 'PREFIX@0000000000000000')
32
+ # second = first.next
33
+ #
34
+ # More information about the algorithm you can find in the
35
+ # {White Paper}[https://papers.zold.io/wp.pdf].
36
+ #
37
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
38
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
39
+ # License:: MIT
40
+ module Zold
41
+ # Score
42
+ class Score
43
+ # Default strength for the entire system, in production mode.
44
+ STRENGTH = 6
45
+
46
+ attr_reader :time, :host, :port, :invoice, :suffixes, :strength, :created
47
+
48
+ def initialize(time: Time.now, host:, port: 4096, invoice:, suffixes: [],
49
+ strength: Score::STRENGTH, created: Time.now)
50
+ @time = time
51
+ @host = host
52
+ @port = port
53
+ @invoice = invoice
54
+ @suffixes = suffixes
55
+ @strength = strength
56
+ @created = created
57
+ end
58
+
59
+ # The default no-value score.
60
+ ZERO = Score.new(time: Time.now, host: 'localhost', invoice: 'NOPREFIX@ffffffffffffffff')
61
+
62
+ # Parses it back from the JSON.
63
+ def self.parse_json(json)
64
+ raise "Time in JSON is broken: #{json}" unless json['time'] =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/
65
+ raise "Host is wrong: #{json}" unless json['host'] =~ /^[0-9a-z\.\-]+$/
66
+ raise "Port is wrong: #{json}" unless json['port'].is_a?(Integer)
67
+ raise "Invoice is wrong: #{json}" unless json['invoice'] =~ /^[a-zA-Z0-9]{8,32}@[a-f0-9]{16}$/
68
+ raise "Suffixes not array: #{json}" unless json['suffixes'].is_a?(Array)
69
+ Score.new(
70
+ time: Time.parse(json['time']), host: json['host'],
71
+ port: json['port'], invoice: json['invoice'], suffixes: json['suffixes'],
72
+ strength: json['strength']
73
+ )
74
+ end
75
+
76
+ # Parses it back from the text generated by <tt>to_s</tt>.
77
+ def self.parse(text)
78
+ re = Regexp.new(
79
+ '^' + [
80
+ '([0-9]+)/(?<strength>[0-9]+):',
81
+ ' (?<time>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z)',
82
+ ' (?<host>[0-9a-z\.\-]+)',
83
+ ' (?<port>[0-9]+)',
84
+ ' (?<invoice>[a-zA-Z0-9]{8,32}@[a-f0-9]{16})',
85
+ '(?<suffixes>( [a-zA-Z0-9]+)*)'
86
+ ].join + '$'
87
+ )
88
+ m = re.match(text.strip)
89
+ raise "Invalid score '#{text}', doesn't match: #{re}" if m.nil?
90
+ Score.new(
91
+ time: Time.parse(m[:time]), host: m[:host],
92
+ port: m[:port].to_i, invoice: m[:invoice],
93
+ suffixes: m[:suffixes].split(' '),
94
+ strength: m[:strength].to_i
95
+ )
96
+ end
97
+
98
+ # Parses it back from the text generated by <tt>to_text</tt>.
99
+ def self.parse_text(text)
100
+ parts = text.split(' ', 7)
101
+ Score.new(
102
+ time: Time.at(parts[1].hex),
103
+ host: parts[2],
104
+ port: parts[3].hex,
105
+ invoice: "#{parts[4]}@#{parts[5]}",
106
+ suffixes: parts[6] ? parts[6].split(' ') : [],
107
+ strength: parts[0].to_i
108
+ )
109
+ end
110
+
111
+ # Returns its crypto hash. Read the White Paper for more information.
112
+ def hash
113
+ raise 'Score has zero value, there is no hash' if @suffixes.empty?
114
+ @suffixes.reduce(prefix) do |pfx, suffix|
115
+ OpenSSL::Digest::SHA256.new("#{pfx} #{suffix}").hexdigest
116
+ end
117
+ end
118
+
119
+ # A simple mnemo of the score.
120
+ def to_mnemo
121
+ "#{value}:#{@time.strftime('%H%M')}"
122
+ end
123
+
124
+ # Converts it to a text, which is console friendly. You can parse it back
125
+ # using <tt>parse_text()</tt>.
126
+ def to_text
127
+ pfx, bnf = @invoice.split('@')
128
+ [
129
+ @strength,
130
+ @time.to_i.to_s(16),
131
+ @host,
132
+ @port.to_s(16),
133
+ pfx,
134
+ bnf,
135
+ @suffixes.join(' ')
136
+ ].join(' ')
137
+ end
138
+
139
+ # Converts it to a string. You can parse it back
140
+ # using <tt>parse()</tt>.
141
+ def to_s
142
+ [
143
+ "#{value}/#{@strength}:",
144
+ @time.utc.iso8601,
145
+ @host,
146
+ @port,
147
+ @invoice,
148
+ @suffixes.join(' ')
149
+ ].join(' ').strip
150
+ end
151
+
152
+ # Converts the score to a hash, which can be used for JSON presentation
153
+ # of the score.
154
+ def to_h
155
+ {
156
+ value: value,
157
+ host: @host,
158
+ port: @port,
159
+ invoice: @invoice,
160
+ time: @time.utc.iso8601,
161
+ suffixes: @suffixes,
162
+ strength: @strength,
163
+ hash: value.zero? ? nil : hash,
164
+ expired: expired?,
165
+ valid: valid?,
166
+ age: (age / 60).round,
167
+ created: @created.utc.iso8601
168
+ }
169
+ end
170
+
171
+ # Returns a new score, which is a copy of the current one, but the amount
172
+ # of hash suffixes is reduced to the <tt>max</tt> provided.
173
+ def reduced(max = 4)
174
+ raise "Max can't be negative: #{max}" if max.negative?
175
+ Score.new(
176
+ time: @time, host: @host, port: @port, invoice: @invoice,
177
+ suffixes: @suffixes[0..[max, suffixes.count].min - 1],
178
+ strength: @strength
179
+ )
180
+ end
181
+
182
+ # Calculates and returns the next score after the current one. This
183
+ # operation may take some time, from a few milliseconds to hours, depending
184
+ # on the CPU power and the <tt>strength</tt> of the current score.
185
+ def next
186
+ raise 'This score is not valid' unless valid?
187
+ idx = 0
188
+ loop do
189
+ suffix = idx.to_s(16)
190
+ score = Score.new(
191
+ time: @time, host: @host, port: @port,
192
+ invoice: @invoice, suffixes: @suffixes + [suffix],
193
+ strength: @strength
194
+ )
195
+ return score if score.valid?
196
+ if score.expired?
197
+ return Score.new(
198
+ time: Time.now, host: @host, port: @port, invoice: @invoice,
199
+ suffixes: [], strength: @strength
200
+ )
201
+ end
202
+ idx += 1
203
+ end
204
+ end
205
+
206
+ # The age of the score in seconds.
207
+ def age
208
+ Time.now - @time
209
+ end
210
+
211
+ # Returns TRUE if the age of the score is over 24 hours.
212
+ def expired?(hours = 24)
213
+ age > hours * 60 * 60
214
+ end
215
+
216
+ # The prefix for the hash calculating algorithm. See the White Paper
217
+ # for more details.
218
+ def prefix
219
+ "#{@time.utc.iso8601} #{@host} #{@port} #{@invoice}"
220
+ end
221
+
222
+ # Returns TRUE if the score is valid: all its suffixes correctly consistute
223
+ # the hash, according to the algorithm explained in the White Paper.
224
+ def valid?
225
+ @suffixes.empty? || hash.end_with?('0' * @strength)
226
+ end
227
+
228
+ # Returns the value of the score, from zero and up. The value is basically
229
+ # the amount of hash suffixes inside the score.
230
+ def value
231
+ @suffixes.length
232
+ end
233
+
234
+ # Returns TRUE if the value of the score is zero.
235
+ def zero?
236
+ @suffixes.empty?
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,160 @@
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 'minitest/autorun'
24
+ require 'tmpdir'
25
+ require 'time'
26
+ require_relative '../../lib/zold/score'
27
+
28
+ # Score test.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
31
+ # License:: MIT
32
+ class TestScore < Minitest::Test
33
+ def test_reduces_itself
34
+ score = Zold::Score.new(
35
+ time: Time.parse('2017-07-19T21:24:51Z'),
36
+ host: 'localhost', port: 443, invoice: 'NOPREFIX@ffffffffffffffff',
37
+ suffixes: %w[A B C D E F G]
38
+ ).reduced(2)
39
+ assert_equal(2, score.value)
40
+ assert_equal(64, score.hash.length)
41
+ end
42
+
43
+ def test_drops_to_zero_when_expired
44
+ score = Zold::Score.new(
45
+ time: Time.now - 24 * 60 * 60,
46
+ host: 'some-host', port: 9999, invoice: 'NOPREFIX@ffffffffffffffff',
47
+ strength: 50
48
+ ).next
49
+ assert(score.valid?)
50
+ assert(!score.expired?)
51
+ assert_equal(0, score.value)
52
+ end
53
+
54
+ def test_validates_wrong_score
55
+ score = Zold::Score.new(
56
+ time: Time.parse('2017-07-19T21:24:51Z'),
57
+ host: 'localhost', port: 443, invoice: 'NOPREFIX@ffffffffffffffff',
58
+ suffixes: %w[xxx yyy zzz]
59
+ )
60
+ assert_equal(3, score.value)
61
+ assert(!score.valid?)
62
+ end
63
+
64
+ def test_prints_mnemo
65
+ score = Zold::Score.new(
66
+ time: Time.parse('2017-07-19T22:32:51Z'),
67
+ host: 'localhost', port: 443, invoice: 'NOPREFIX@ffffffffffffffff'
68
+ )
69
+ assert_equal('0:2232', score.to_mnemo)
70
+ end
71
+
72
+ def test_prints_and_parses
73
+ time = Time.now
74
+ score = Zold::Score.parse(
75
+ Zold::Score.new(
76
+ time: time, host: 'localhost', port: 999, invoice: 'NOPREFIX@ffffffffffffffff',
77
+ strength: 1
78
+ ).next.next.to_s
79
+ )
80
+ assert_equal(2, score.value)
81
+ assert_equal(score.time.to_s, time.to_s)
82
+ assert_equal('localhost', score.host)
83
+ assert_equal(999, score.port)
84
+ end
85
+
86
+ def test_prints_and_parses_text
87
+ time = Time.now
88
+ score = Zold::Score.parse_text(
89
+ Zold::Score.new(
90
+ time: time, host: 'a.example.com', port: 999, invoice: 'NOPREFIX@ffffffffffffffff',
91
+ strength: 1
92
+ ).next.next.next.to_text
93
+ )
94
+ assert_equal(3, score.value)
95
+ assert_equal(score.time.utc.to_s, time.utc.to_s)
96
+ assert_equal('a.example.com', score.host)
97
+ assert_equal(999, score.port)
98
+ end
99
+
100
+ def test_prints_and_parses_text_zero_score
101
+ time = Time.now
102
+ score = Zold::Score.parse_text(
103
+ Zold::Score.new(
104
+ time: time, host: '192.168.0.1', port: 1, invoice: 'NOPREFIX@ffffffffffffffff', suffixes: []
105
+ ).to_text
106
+ )
107
+ assert_equal(0, score.value)
108
+ assert(!score.expired?)
109
+ end
110
+
111
+ def test_prints_and_parses_zero_score
112
+ time = Time.now
113
+ score = Zold::Score.parse(
114
+ Zold::Score.new(
115
+ time: time, host: '192.168.0.1', port: 1, invoice: 'NOPREFIX@ffffffffffffffff', suffixes: []
116
+ ).to_s
117
+ )
118
+ assert_equal(0, score.value)
119
+ assert(!score.expired?)
120
+ end
121
+
122
+ def test_finds_next_score
123
+ score = Zold::Score.new(
124
+ time: Time.now, host: 'localhost', port: 443,
125
+ invoice: 'NOPREFIX@ffffffffffffffff', strength: 2
126
+ ).next.next.next
127
+ assert_equal(3, score.value)
128
+ assert(score.valid?)
129
+ assert(!score.expired?)
130
+ end
131
+
132
+ def test_dont_expire_correctly
133
+ score = Zold::Score.new(
134
+ time: Time.now - 10 * 60 * 60, host: 'localhost', port: 443,
135
+ invoice: 'NOPREFIX@ffffffffffffffff', strength: 2
136
+ ).next.next.next
137
+ assert(!score.expired?)
138
+ end
139
+
140
+ def test_correct_number_of_zeroes
141
+ score = Zold::Score.new(
142
+ time: Time.now, host: 'localhost', port: 443,
143
+ invoice: 'NOPREFIX@ffffffffffffffff', strength: 3
144
+ ).next
145
+ assert(score.hash.end_with?('000'))
146
+ end
147
+
148
+ def test_generates_hash_correctly
149
+ score = Zold::Score.new(
150
+ time: Time.parse('2018-06-27T06:22:41Z'), host: 'b2.zold.io', port: 4096,
151
+ invoice: 'THdonv1E@abcdabcdabcdabcd', suffixes: ['3a934b']
152
+ )
153
+ assert_equal('c9c72efbf6beeea13408c5e720ec42aec017c11c3db335e05595c03755000000', score.hash)
154
+ score = Zold::Score.new(
155
+ time: Time.parse('2018-06-27T06:22:41Z'), host: 'b2.zold.io', port: 4096,
156
+ invoice: 'THdonv1E@abcdabcdabcdabcd', suffixes: %w[3a934b 1421217]
157
+ )
158
+ assert_equal('e04ab4e69f86aa17be1316a52148e7bc3187c6d3df581d885a862d8850000000', score.hash)
159
+ end
160
+ end
@@ -0,0 +1,48 @@
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 NONINFRINGEMENT. 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 'English'
24
+ Gem::Specification.new do |s|
25
+ s.specification_version = 2 if s.respond_to? :specification_version=
26
+ s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
27
+ s.rubygems_version = '2.2'
28
+ s.required_ruby_version = '>=2.3'
29
+ s.name = 'zold-score'
30
+ s.version = '0.1.0'
31
+ s.license = 'MIT'
32
+ s.summary = 'Zold score'
33
+ s.description = 'Score calculating Ruby Gem for Zold'
34
+ s.authors = ['Yegor Bugayenko']
35
+ s.email = 'yegor256@gmail.com'
36
+ s.homepage = 'http://github.com/zold-io/zold-score'
37
+ s.files = `git ls-files`.split($RS)
38
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
39
+ s.test_files = s.files.grep(%r{^(test|features)/})
40
+ s.rdoc_options = ['--charset=UTF-8']
41
+ s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
42
+ s.add_development_dependency 'codecov', '~>0'
43
+ s.add_development_dependency 'minitest', '~>5'
44
+ s.add_development_dependency 'rdoc', '~>4'
45
+ s.add_development_dependency 'rspec-rails', '~>3'
46
+ s.add_development_dependency 'rubocop', '0.58.1'
47
+ s.add_development_dependency 'rubocop-rspec', '~>1'
48
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zold-score
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yegor Bugayenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: codecov
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rdoc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 0.58.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 0.58.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1'
97
+ description: Score calculating Ruby Gem for Zold
98
+ email: yegor256@gmail.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files:
102
+ - README.md
103
+ - LICENSE.txt
104
+ files:
105
+ - ".0pdd.yml"
106
+ - ".gitattributes"
107
+ - ".gitignore"
108
+ - ".pdd"
109
+ - ".rubocop.yml"
110
+ - ".rultor.yml"
111
+ - ".simplecov"
112
+ - ".travis.yml"
113
+ - Gemfile
114
+ - LICENSE.txt
115
+ - README.md
116
+ - Rakefile
117
+ - appveyor.yml
118
+ - lib/zold/score.rb
119
+ - test/zold/test_score.rb
120
+ - zold-score.gemspec
121
+ homepage: http://github.com/zold-io/zold-score
122
+ licenses:
123
+ - MIT
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options:
127
+ - "--charset=UTF-8"
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '2.3'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.7.6
143
+ signing_key:
144
+ specification_version: 2
145
+ summary: Zold score
146
+ test_files:
147
+ - test/zold/test_score.rb