Class: Zold::Score

Inherits:
Object
  • Object
show all
Defined in:
lib/zold/score.rb

Overview

Score

Constant Summary collapse

STRENGTH =

Default strength for the entire system, in production mode.

6
ZERO =

The default no-value score.

Score.new(time: Time.now, host: 'localhost', invoice: 'NOPREFIX@ffffffffffffffff')

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(time: Time.now, host:, port: 4096, invoice:, suffixes: [], strength: Score::STRENGTH, created: Time.now) ⇒ Score

Makes a new object of the class.



50
51
52
53
54
55
56
57
58
59
# File 'lib/zold/score.rb', line 50

def initialize(time: Time.now, host:, port: 4096, invoice:, suffixes: [],
  strength: Score::STRENGTH, created: Time.now)
  @time = time
  @host = host
  @port = port
  @invoice = invoice
  @suffixes = suffixes
  @strength = strength
  @created = created
end

Instance Attribute Details

#createdObject (readonly)

Returns the value of attribute created.



47
48
49
# File 'lib/zold/score.rb', line 47

def created
  @created
end

#hostObject (readonly)

Returns the value of attribute host.



47
48
49
# File 'lib/zold/score.rb', line 47

def host
  @host
end

#invoiceObject (readonly)

Returns the value of attribute invoice.



47
48
49
# File 'lib/zold/score.rb', line 47

def invoice
  @invoice
end

#portObject (readonly)

Returns the value of attribute port.



47
48
49
# File 'lib/zold/score.rb', line 47

def port
  @port
end

#strengthObject (readonly)

Returns the value of attribute strength.



47
48
49
# File 'lib/zold/score.rb', line 47

def strength
  @strength
end

#suffixesObject (readonly)

Returns the value of attribute suffixes.



47
48
49
# File 'lib/zold/score.rb', line 47

def suffixes
  @suffixes
end

#timeObject (readonly)

Returns the value of attribute time.



47
48
49
# File 'lib/zold/score.rb', line 47

def time
  @time
end

Class Method Details

.parse(text) ⇒ Object

Parses it back from the text generated by to_s.



92
93
94
95
96
97
98
99
100
101
# File 'lib/zold/score.rb', line 92

def self.parse(text)
  m = PTN.match(text.strip)
  raise "Invalid score '#{text}', doesn't match: #{PTN}" if m.nil?
  Score.new(
    time: Time.parse(m[:time]), host: m[:host],
    port: m[:port].to_i, invoice: m[:invoice],
    suffixes: m[:suffixes].split(' '),
    strength: m[:strength].to_i
  )
end

.parse_json(json) ⇒ Object

Parses it back from the JSON.



65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/zold/score.rb', line 65

def self.parse_json(json)
  raise "Time in JSON is broken: #{json}" unless json['time'] =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/
  raise "Host is wrong: #{json}" unless json['host'] =~ /^[0-9a-z\.\-]+$/
  raise "Port is wrong: #{json}" unless json['port'].is_a?(Integer)
  raise "Invoice is wrong: #{json}" unless json['invoice'] =~ /^[a-zA-Z0-9]{8,32}@[a-f0-9]{16}$/
  raise "Suffixes not array: #{json}" unless json['suffixes'].is_a?(Array)
  Score.new(
    time: Time.parse(json['time']), host: json['host'],
    port: json['port'], invoice: json['invoice'], suffixes: json['suffixes'],
    strength: json['strength']
  )
end

.parse_text(text) ⇒ Object

Parses it back from the text generated by to_text.



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/zold/score.rb', line 104

def self.parse_text(text)
  parts = text.split(' ', 7)
  Score.new(
    time: Time.at(parts[1].hex),
    host: parts[2],
    port: parts[3].hex,
    invoice: "#{parts[4]}@#{parts[5]}",
    suffixes: parts[6] ? parts[6].split(' ') : [],
    strength: parts[0].to_i
  )
end

Instance Method Details

#ageObject

The age of the score in seconds.



206
207
208
# File 'lib/zold/score.rb', line 206

def age
  Time.now - @time
end

#expired?(hours = 24) ⇒ Boolean

Returns TRUE if the age of the score is over 24 hours.

Returns:

  • (Boolean)


211
212
213
# File 'lib/zold/score.rb', line 211

def expired?(hours = 24)
  age > hours * 60 * 60
end

#hashObject

Returns its crypto hash. Read the White Paper for more information.



117
118
119
120
121
122
# File 'lib/zold/score.rb', line 117

def hash
  raise 'Score has zero value, there is no hash' if @suffixes.empty?
  @suffixes.reduce(prefix) do |pfx, suffix|
    OpenSSL::Digest::SHA256.new("#{pfx} #{suffix}").hexdigest
  end
end

#nextObject

Calculates and returns the next score after the current one. This operation may take some time, from a few milliseconds to hours, depending on the CPU power and the strength of the current score.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/zold/score.rb', line 190

def next
  raise 'This score is not valid' unless valid?
  if expired?
    return Score.new(
      time: Time.now, host: @host, port: @port, invoice: @invoice,
      suffixes: [], strength: @strength
    )
  end
  suffix = ScoreSuffix.new(suffixes.empty? ? prefix : hash, @strength)
  Score.new(
    time: @time, host: @host, port: @port, invoice: @invoice,
    suffixes: @suffixes + [suffix.value], strength: @strength
  )
end

#prefixObject

The prefix for the hash calculating algorithm. See the White Paper for more details.



217
218
219
# File 'lib/zold/score.rb', line 217

def prefix
  "#{@time.utc.iso8601} #{@host} #{@port} #{@invoice}"
end

#reduced(max = 4) ⇒ Object

Returns a new score, which is a copy of the current one, but the amount of hash suffixes is reduced to the max provided.



178
179
180
181
182
183
184
185
# File 'lib/zold/score.rb', line 178

def reduced(max = 4)
  raise "Max can't be negative: #{max}" if max.negative?
  Score.new(
    time: @time, host: @host, port: @port, invoice: @invoice,
    suffixes: @suffixes[0..[max, suffixes.count].min - 1],
    strength: @strength
  )
end

#to_hObject

Converts the score to a hash, which can be used for JSON presentation of the score.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/zold/score.rb', line 159

def to_h
  {
    value: value,
    host: @host,
    port: @port,
    invoice: @invoice,
    time: @time.utc.iso8601,
    suffixes: @suffixes,
    strength: @strength,
    hash: value.zero? ? nil : hash,
    expired: expired?,
    valid: valid?,
    age: (age / 60).round,
    created: @created.utc.iso8601
  }
end

#to_mnemoObject

A simple mnemo of the score.



125
126
127
# File 'lib/zold/score.rb', line 125

def to_mnemo
  "#{value}:#{@time.strftime('%H%M')}"
end

#to_sObject

Converts it to a string. You can parse it back using parse().



146
147
148
149
150
151
152
153
154
155
# File 'lib/zold/score.rb', line 146

def to_s
  [
    "#{value}/#{@strength}:",
    @time.utc.iso8601,
    @host,
    @port,
    @invoice,
    @suffixes.join(' ')
  ].join(' ').strip
end

#to_textObject

Converts it to a text, which is console friendly. You can parse it back using parse_text().



131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/zold/score.rb', line 131

def to_text
  pfx, bnf = @invoice.split('@')
  [
    @strength,
    @time.to_i.to_s(16),
    @host,
    @port.to_s(16),
    pfx,
    bnf,
    @suffixes.join(' ')
  ].join(' ')
end

#valid?Boolean

Returns TRUE if the score is valid: all its suffixes correctly consistute the hash, according to the algorithm explained in the White Paper.

Returns:

  • (Boolean)


223
224
225
# File 'lib/zold/score.rb', line 223

def valid?
  @suffixes.empty? || hash.end_with?('0' * @strength)
end

#valueObject

Returns the value of the score, from zero and up. The value is basically the amount of hash suffixes inside the score.



229
230
231
# File 'lib/zold/score.rb', line 229

def value
  @suffixes.length
end

#zero?Boolean

Returns TRUE if the value of the score is zero.

Returns:

  • (Boolean)


234
235
236
# File 'lib/zold/score.rb', line 234

def zero?
  @suffixes.empty?
end