zold 0.6.2 → 0.6.3
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 +4 -4
- data/.gitattributes +1 -0
- data/README.md +0 -38
- data/bin/zold +2 -12
- data/fixtures/scripts/calculate-scores.sh +8 -0
- data/fixtures/scripts/print-helps.sh +1 -1
- data/lib/zold/commands/calculate.rb +84 -0
- data/lib/zold/commands/push.rb +4 -0
- data/lib/zold/score.rb +16 -10
- data/lib/zold/signature.rb +1 -1
- data/lib/zold/version.rb +1 -1
- data/test/commands/test_calculate.rb +37 -0
- data/test/test_score.rb +8 -0
- data/wp/.gitignore +1 -0
- data/wp/logo.png +0 -0
- data/wp/wp.tex +147 -45
- data/zold.gemspec +1 -1
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2005a5319083f1a638f7c4764776cf02c22fec87
|
4
|
+
data.tar.gz: 9ffb162b8a5c5daa797b0c1402283d49a81f5d26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39f357589c34b08f98d405b8ee8307a8044c5809e51fce67a00e87ce53d713be7179ba2098ee548e4b7b9788aa276e9b40ebe271c4ade47cc7917d859a08079a
|
7
|
+
data.tar.gz: 18edefa475f83289160649fbfdd07df40e7c494722f5c5352650d3ae1e16d945ea269d430294a9e61e8f6f4d202c1f3efe7c66b4f72b0657dac7a9434e73e2ea
|
data/.gitattributes
CHANGED
data/README.md
CHANGED
@@ -45,8 +45,6 @@ yet, you can run:
|
|
45
45
|
$ ssh-keygen -t rsa -b 4096
|
46
46
|
```
|
47
47
|
|
48
|
-
## Operations
|
49
|
-
|
50
48
|
### Remote
|
51
49
|
|
52
50
|
Each node maintains a list of visible "remote" nodes.
|
@@ -157,42 +155,6 @@ Each HTTP response contains `Content-type` header.
|
|
157
155
|
|
158
156
|
## Files
|
159
157
|
|
160
|
-
Each wallet is a text file with the name equal to the wallet ID, for example:
|
161
|
-
|
162
|
-
```text
|
163
|
-
12345678abcdef
|
164
|
-
AAAAB3NzaC1yc2EAAAADAQABAAABAQCuLuVr4Tl2sXoN5Zb7b6SKMPrVjLxb...
|
165
|
-
|
166
|
-
34;2017-07-19T21:24:51Z;-560700;98bb82c81735c4ee;for services;SKMPrVjLxbM5oDm0IhniQQy3shF...
|
167
|
-
35;2017-07-19T21:25:07Z;-56990;98bb82c81735c4ee;;QCuLuVr4Tl2sXoN5Zb7b6SKMPrVjLxb...
|
168
|
-
134;2017-07-19T21:29:11Z;647388;18bb82dd1735b6e9;;
|
169
|
-
36;2017-07-19T22:18:43Z;-884733;38ab8fc8e735c4fc;for fun;2sXoN5Zb7b6SKMPrVjLxb7b6SKMPrVjLx...
|
170
|
-
```
|
171
|
-
|
172
|
-
Lines are separated by either CR or CRLF, doesn't matter. There is a
|
173
|
-
header and a ledger, separated by an empty line.
|
174
|
-
The header includes two lines:
|
175
|
-
|
176
|
-
* Wallet ID, a 64-bit unsigned integer;
|
177
|
-
* Public RSA key of the wallet owner.
|
178
|
-
|
179
|
-
The ledger includes transactions, one per line. Each transaction line
|
180
|
-
contains fields separated by a semi-colon:
|
181
|
-
|
182
|
-
* Transaction ID, an unsigned 16-bit integer;
|
183
|
-
* Date and time, in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601);
|
184
|
-
* Amount (integer);
|
185
|
-
* Wallet ID of the beneficiary;
|
186
|
-
* Details: `/[a-zA-Z0-9 -.]{1,128}/`;
|
187
|
-
* RSA signature of the sender of "ID;amount;beneficiary;details" text.
|
188
|
-
|
189
|
-
Transactions with positive amount don't
|
190
|
-
have RSA signatures. Their IDs point to ID fields of corresponding
|
191
|
-
beneficiaries' wallets.
|
192
|
-
|
193
|
-
The combination "ID+Beneficiary" is unique in the entire wallet.
|
194
|
-
|
195
|
-
The directory `.zold` is automatically created and contains system data.
|
196
158
|
|
197
159
|
`.zold/remotes` is a comma-separated file with a list of remote nodes with
|
198
160
|
these columns:
|
data/bin/zold
CHANGED
@@ -167,18 +167,8 @@ Available options:"
|
|
167
167
|
require_relative '../lib/zold/commands/push'
|
168
168
|
Zold::Push.new(wallets: wallets, remotes: remotes, log: log).run(args)
|
169
169
|
when 'score'
|
170
|
-
require_relative '../lib/zold/
|
171
|
-
|
172
|
-
host = args[0]
|
173
|
-
port = args[1].to_i
|
174
|
-
invoice = args[2]
|
175
|
-
strength = args[3].to_i
|
176
|
-
raise "Invalid strength: #{strength}" if strength <= 0 || strength > 8
|
177
|
-
score = Zold::Score.new(Time.now, host, port, invoice, strength: strength)
|
178
|
-
loop do
|
179
|
-
log.info(score.to_s)
|
180
|
-
score = score.next
|
181
|
-
end
|
170
|
+
require_relative '../lib/zold/commands/calculate'
|
171
|
+
Zold::Calculate.new(log: log).run(args)
|
182
172
|
else
|
183
173
|
raise "Command '#{command}' is not supported"
|
184
174
|
end
|
@@ -0,0 +1,84 @@
|
|
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 'slop'
|
22
|
+
require_relative '../log'
|
23
|
+
require_relative '../score'
|
24
|
+
|
25
|
+
# SCORE command.
|
26
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
27
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
28
|
+
# License:: MIT
|
29
|
+
module Zold
|
30
|
+
# Calculate score
|
31
|
+
class Calculate
|
32
|
+
def initialize(log: Log::Quiet.new)
|
33
|
+
@log = log
|
34
|
+
end
|
35
|
+
|
36
|
+
def run(args = [])
|
37
|
+
opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
|
38
|
+
o.banner = "Usage: zold push [ID...] [options]
|
39
|
+
Available options:"
|
40
|
+
o.string '--invoice',
|
41
|
+
'The invoice you want to collect money to'
|
42
|
+
o.integer '--port',
|
43
|
+
"TCP port to open for the Net (default: #{Remotes::PORT})",
|
44
|
+
default: Remotes::PORT
|
45
|
+
o.string '--host', 'Host name (default: 127.0.0.1)',
|
46
|
+
default: '127.0.0.1'
|
47
|
+
o.integer '--strength',
|
48
|
+
"The strength of the score (default: #{Score::STRENGTH})",
|
49
|
+
default: Score::STRENGTH
|
50
|
+
o.integer '--max',
|
51
|
+
'Maximum value to find and then stop (default: 8)',
|
52
|
+
default: 8
|
53
|
+
o.bool '--hide-hash', 'Don\'t print hash',
|
54
|
+
default: false
|
55
|
+
o.bool '--help', 'Print instructions'
|
56
|
+
end
|
57
|
+
if opts.help?
|
58
|
+
@log.info(opts.to_s)
|
59
|
+
return
|
60
|
+
end
|
61
|
+
calculate(opts)
|
62
|
+
end
|
63
|
+
|
64
|
+
def calculate(opts)
|
65
|
+
start = Time.now
|
66
|
+
strength = opts[:strength]
|
67
|
+
raise "Invalid strength: #{strength}" if strength <= 0 || strength > 8
|
68
|
+
score = Zold::Score.new(
|
69
|
+
Time.now, opts[:host], opts[:port].to_i,
|
70
|
+
opts[:invoice], strength: strength
|
71
|
+
)
|
72
|
+
loop do
|
73
|
+
msg = score.to_s
|
74
|
+
msg += (score.value > 0 ? ' ' + score.hash : '') unless opts['hide-hash']
|
75
|
+
@log.info(msg)
|
76
|
+
break if score.value >= opts[:max].to_i
|
77
|
+
score = score.next
|
78
|
+
end
|
79
|
+
seconds = (Time.now - start).round(2)
|
80
|
+
@log.info("Took #{seconds} seconds, #{seconds / score.value} per value")
|
81
|
+
score
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/zold/commands/push.rb
CHANGED
@@ -66,20 +66,24 @@ Available options:"
|
|
66
66
|
next
|
67
67
|
end
|
68
68
|
unless response.code == '200'
|
69
|
+
@remotes.error(r[:host], r[:port])
|
69
70
|
@log.error("#{uri} failed as #{response.code}/#{response.message}")
|
70
71
|
next
|
71
72
|
end
|
72
73
|
json = JSON.parse(response.body)['score']
|
73
74
|
score = Score.parse_json(json)
|
74
75
|
unless score.valid?
|
76
|
+
@remotes.error(r[:host], r[:port])
|
75
77
|
@log.error("#{uri} invalid score: #{score}")
|
76
78
|
next
|
77
79
|
end
|
78
80
|
if score.expired?
|
81
|
+
@remotes.error(r[:host], r[:port])
|
79
82
|
@log.error("#{uri} expired score: #{score}")
|
80
83
|
next
|
81
84
|
end
|
82
85
|
if score.strength < Score::STRENGTH
|
86
|
+
@remotes.error(r[:host], r[:port])
|
83
87
|
@log.error("#{uri} score is too weak")
|
84
88
|
next
|
85
89
|
end
|
data/lib/zold/score.rb
CHANGED
@@ -96,13 +96,20 @@ module Zold
|
|
96
96
|
)
|
97
97
|
end
|
98
98
|
|
99
|
+
def hash
|
100
|
+
raise 'Score has zero value, there is no hash' if @suffixes.empty?
|
101
|
+
@suffixes.reduce(prefix) do |pfx, suffix|
|
102
|
+
Digest::SHA256.hexdigest(pfx + ' ' + suffix)[0, 63]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
99
106
|
def to_text
|
100
|
-
|
107
|
+
pfx, bnf = @invoice.split('@')
|
101
108
|
[
|
102
109
|
@time.to_i.to_s(16),
|
103
110
|
@host,
|
104
111
|
@port.to_s(16),
|
105
|
-
|
112
|
+
pfx,
|
106
113
|
bnf,
|
107
114
|
@suffixes.join(' ')
|
108
115
|
].join(' ')
|
@@ -127,7 +134,8 @@ module Zold
|
|
127
134
|
invoice: @invoice,
|
128
135
|
time: @time.utc.iso8601,
|
129
136
|
suffixes: @suffixes,
|
130
|
-
strength: @strength
|
137
|
+
strength: @strength,
|
138
|
+
hash: value.zero? ? nil : hash
|
131
139
|
}
|
132
140
|
end
|
133
141
|
|
@@ -160,14 +168,12 @@ module Zold
|
|
160
168
|
@time < Time.now - 24 * 60
|
161
169
|
end
|
162
170
|
|
171
|
+
def prefix
|
172
|
+
"#{@time.utc.iso8601} #{@host} #{@port} #{@invoice}"
|
173
|
+
end
|
174
|
+
|
163
175
|
def valid?
|
164
|
-
|
165
|
-
@suffixes.reduce(start) do |prefix, suffix|
|
166
|
-
hex = Digest::SHA256.hexdigest(prefix + ' ' + suffix)
|
167
|
-
return false unless hex.end_with?('0' * @strength)
|
168
|
-
hex[0, 63]
|
169
|
-
end
|
170
|
-
true
|
176
|
+
@suffixes.empty? || hash.end_with?('0' * @strength)
|
171
177
|
end
|
172
178
|
|
173
179
|
def value
|
data/lib/zold/signature.rb
CHANGED
data/lib/zold/version.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
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 '../../lib/zold/log'
|
23
|
+
require_relative '../../lib/zold/commands/calculate'
|
24
|
+
|
25
|
+
# SCORE test.
|
26
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
27
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
28
|
+
# License:: MIT
|
29
|
+
class TestCalculate < Minitest::Test
|
30
|
+
def test_calculates_score
|
31
|
+
score = Zold::Calculate.new.run(
|
32
|
+
['score', '--strength=2', '--max=8', '--invoice=NOSUFFIX@ffffffffffffffff']
|
33
|
+
)
|
34
|
+
assert(score.valid?)
|
35
|
+
assert_equal(8, score.value)
|
36
|
+
end
|
37
|
+
end
|
data/test/test_score.rb
CHANGED
@@ -95,4 +95,12 @@ class TestScore < Minitest::Test
|
|
95
95
|
assert(score.valid?)
|
96
96
|
assert(!score.expired?)
|
97
97
|
end
|
98
|
+
|
99
|
+
def test_correct_number_of_zeroes
|
100
|
+
score = Zold::Score.new(
|
101
|
+
Time.now, 'localhost', 443,
|
102
|
+
'NOPREFIX@ffffffffffffffff', strength: 3
|
103
|
+
).next
|
104
|
+
assert(score.hash.end_with?('000'))
|
105
|
+
end
|
98
106
|
end
|
data/wp/.gitignore
CHANGED
data/wp/logo.png
ADDED
Binary file
|
data/wp/wp.tex
CHANGED
@@ -1,22 +1,28 @@
|
|
1
1
|
\documentclass[11pt,oneside]{article}
|
2
2
|
\usepackage[utf8]{inputenc}
|
3
3
|
\usepackage[american]{babel}
|
4
|
-
% \usepackage[
|
5
|
-
% paperwidth=6in, paperheight=9in,
|
6
|
-
% bindingoffset=0.25in, left=0.75in, right=0.75in, top=0.75in, bottom=1.25in
|
7
|
-
% ]{geometry}
|
8
4
|
\usepackage{setspace}
|
9
5
|
\usepackage{microtype}
|
10
6
|
\usepackage{mathpazo} % Palantino font
|
7
|
+
\usepackage{mdframed}
|
11
8
|
\usepackage{minted}
|
12
|
-
\setminted{fontsize=\
|
9
|
+
\setminted{fontsize=\small}
|
13
10
|
\setminted{breaklines}
|
14
11
|
\usemintedstyle{bw}
|
12
|
+
\BeforeBeginEnvironment{minted}{\vspace{6pt}\begin{mdframed}[topline=false,rightline=false,bottomline=false,linecolor=black,linewidth=2pt]}
|
13
|
+
\AfterEndEnvironment{minted}{\end{mdframed}}
|
14
|
+
\usepackage{xcolor}
|
15
|
+
\usepackage{graphicx}
|
16
|
+
\newcommand\dd[1]{\colorbox{gray!30}{\texttt{#1}}}
|
15
17
|
\usepackage{hyperref}
|
18
|
+
\hypersetup{colorlinks=true,allcolors=blue!40!black}
|
16
19
|
\pagestyle{empty}
|
17
20
|
\setstretch{1.2}
|
21
|
+
\setlength{\topskip}{6pt}
|
22
|
+
\setlength{\parindent}{0pt} % indent first line
|
23
|
+
\setlength{\parskip}{6pt} % before par
|
18
24
|
|
19
|
-
\title{Zold
|
25
|
+
\title{\includegraphics[scale=0.05]{logo.png}\\Zold: Lightweight Crypto Currency}
|
20
26
|
\author{Yegor Bugayenko\\\texttt{yegor@zold.io}}
|
21
27
|
|
22
28
|
\begin{document}
|
@@ -49,69 +55,101 @@ of existing digital currencies.
|
|
49
55
|
|
50
56
|
\section{Principles}
|
51
57
|
|
52
|
-
\textbf{Open
|
53
|
-
Zold is a command line tool. Its entire code base is open source
|
58
|
+
\textbf{Open Source}.
|
59
|
+
Zold is a command line tool. Its entire code base is open source
|
60
|
+
and hosted at the GitHub \href{https://github.com/yegor256/zold}{yegor256/zold}
|
61
|
+
repository.
|
62
|
+
|
63
|
+
\textbf{No Trust}.
|
64
|
+
The network of communicating nodes maintains wallets of users.
|
65
|
+
Anyone can add a node to the network.
|
66
|
+
It is assumed that any node may contain corrupted data, either by mistake or intentionally.
|
67
|
+
|
68
|
+
\textbf{Proof of work}.
|
69
|
+
Each node, in order to earn trust, must invest its CPU power
|
70
|
+
and find hash suffixes, performing certain calculations.
|
71
|
+
|
72
|
+
\textbf{No General Ledger}.
|
73
|
+
There is no central ledger, each wallet has its own personal ledger.
|
74
|
+
All transactions in each ledger are confirmed by
|
75
|
+
\href{https://en.wikipedia.org/wiki/RSA_(cryptosystem)}{RSA signatures}
|
76
|
+
of their owners;
|
54
77
|
|
55
78
|
\textbf{Capacity}.
|
56
79
|
One currency unit is called ZLD.
|
57
|
-
One ZLD by convention equals to $2^24$ (16,777,216)
|
80
|
+
One ZLD by convention equals to $2^{24}$ \emph{zents} (16,777,216).
|
58
81
|
All amounts are stored as signed 64-bit integers.
|
59
82
|
Thus, the technical capacity of the currency is 549,755,813,888 ZLD (half a trillion).
|
60
83
|
|
61
|
-
\textbf{Zero
|
62
|
-
There is no mining, the only way to get ZLD is to receive it from someone else.
|
63
|
-
The wallet with the \
|
84
|
+
\textbf{Zero Wallet}.
|
85
|
+
There is no ``mining,'' the only way to get ZLD is to receive it from someone else.
|
86
|
+
The wallet with the \dd{0x00} ID belongs to the
|
64
87
|
issuer and may have a negative balance. All other wallets
|
65
|
-
may have
|
66
|
-
|
67
|
-
\textbf{No general ledger}.
|
68
|
-
There is no central ledger, each wallet has its own personal ledger.
|
69
|
-
Each transaction in the ledger is confirmed by RSA signature;
|
70
|
-
|
71
|
-
\textbf{No trust}.
|
72
|
-
The network of communicating nodes maintains wallets of users.
|
73
|
-
Anyone can add a node to the network.
|
74
|
-
It is assumed that any node may contain corrupted data, either by mistake or intentionally.
|
88
|
+
may only have positive balances.
|
75
89
|
|
76
90
|
\section{Proof of Work}
|
77
91
|
|
78
|
-
|
79
|
-
|
92
|
+
The system consists of nodes (server machines), which maintain the data.
|
93
|
+
In order to guarantee data consistency among all distributed nodes
|
94
|
+
there has to be an algorithm of data segregation.
|
95
|
+
Corrupted data must be detected earlier and filtered out as quickly as possible.
|
96
|
+
Bitcoin introduced such an algorithm and called it \emph{proof of work}.
|
97
|
+
|
98
|
+
Its fundamental principle is that each block of data must have a special
|
99
|
+
number attached to it, known as \emph{nonce}, which is rather difficult to calculate,
|
100
|
+
because it requires a lot of CPU power. It is assumed that at any moment
|
101
|
+
of time the majority of nodes in the network invest their CPU power into
|
102
|
+
calculating the nonces for the data that is not corrupted. If and when for any reason
|
103
|
+
some data gets corrupted, the amount of CPU power a part of the network
|
104
|
+
decides to invest into its nonces calculation would be smaller than what
|
105
|
+
the other part of the network invests into legal data. The latter part
|
106
|
+
will quickly dominate the former and the nodes with corrupted data will
|
107
|
+
be ostracized and eventually ignored.
|
108
|
+
|
109
|
+
Zold has borrowed this principle, although modified it. We also require
|
110
|
+
our nodes to invest their CPU power into meaninless and repetative
|
111
|
+
calculations just to help us identify which part of the network they belong to:
|
112
|
+
corrupted or not. Each Zold node has to calculate its \emph{trust score},
|
113
|
+
which is as big as much CPU power the node has invested into its calculation.
|
114
|
+
|
115
|
+
Similar to Bitcoin nonces we repetatively calculate cryptographic hashes,
|
116
|
+
looking for consecutive zeros inside them. First, in order to calculate a score,
|
117
|
+
a node makes the \emph{prefix}, which consists of four parts,
|
80
118
|
separated by spaces:
|
81
119
|
|
82
|
-
\begin{
|
83
|
-
\item The current timestamp in UTC ISO 8601,
|
84
|
-
\item The host name or IP address, e.g. \
|
85
|
-
\item The TCP port number,
|
120
|
+
\begin{enumerate}
|
121
|
+
\item The current timestamp in UTC, in \href{https://en.wikipedia.org/wiki/ISO_8601}{ISO 8601},
|
122
|
+
\item The host name or IP address, e.g. \dd{b2.zold.io},
|
123
|
+
\item The \href{https://en.wikipedia.org/wiki/Port_(computer_networking)}{TCP port} number,
|
86
124
|
\item The invoice.
|
87
|
-
\end{
|
125
|
+
\end{enumerate}
|
88
126
|
|
89
|
-
For example, the
|
127
|
+
For example, the prefix may look like this:
|
90
128
|
|
91
129
|
\begin{minted}{text}
|
92
|
-
|
130
|
+
2018-05-17T03:50:59Z b2.zold.io 4096 THdonv1E@0000000000000000
|
93
131
|
\end{minted}
|
94
132
|
|
95
|
-
Then,
|
96
|
-
|
97
|
-
|
98
|
-
in the hexadecimal format. For example, this would be the
|
99
|
-
with \
|
133
|
+
Then, the node attempts to append any arbitrary text, which has to match
|
134
|
+
\dd{/[a-zA-Z0-9]+/} regular expression, to the end of the prefix and calculates
|
135
|
+
\href{https://en.wikipedia.org/wiki/SHA-2}{SHA-256 hash}
|
136
|
+
of the text in the hexadecimal format. For example, this would be the prefix
|
137
|
+
with the attached \dd{117b1f} suffix:
|
100
138
|
|
101
139
|
\begin{minted}{text}
|
102
|
-
|
140
|
+
2018-05-17T03:50:59Z b2.zold.io 4096 THdonv1E@0000000000000000 117b1f
|
103
141
|
\end{minted}
|
104
142
|
|
105
|
-
The
|
143
|
+
The hash of this text will be:
|
106
144
|
|
107
145
|
\begin{minted}{text}
|
108
|
-
|
146
|
+
670baa704726fe2c837c5ca764202adca5ab12c9b90c94d9fb1b8d629000000
|
109
147
|
\end{minted}
|
110
148
|
|
111
149
|
The node attempts to try different sufficies until one of them produces
|
112
|
-
|
113
|
-
|
114
|
-
(it took
|
150
|
+
a hash that ends with a few tailing zeroes. The one above ends
|
151
|
+
with six zeroes
|
152
|
+
(it took three minutes to find it on 2.3GHz Intel Core i7):
|
115
153
|
|
116
154
|
When the first suffix is found, the score is 1. Then, to
|
117
155
|
increase the score by one, the next suffix has to be found, which
|
@@ -119,18 +157,82 @@ can be added to the first 64 characters of the previous hash
|
|
119
157
|
in order to obtain a new hash with trailing zeros, for example:
|
120
158
|
|
121
159
|
\begin{minted}{text}
|
122
|
-
|
160
|
+
2018-05-17T03:50:59Z b2.zold.io 4096 THdonv1E@0000000000000000 117b1f 1546e35
|
161
|
+
\end{minted}
|
162
|
+
|
163
|
+
Produces:
|
164
|
+
|
165
|
+
\begin{minted}{text}
|
166
|
+
99dcd18e4bd03004e1205437866b5b68035cc8985240ae52cbd37640a000000
|
123
167
|
\end{minted}
|
124
168
|
|
125
169
|
And so on.
|
126
170
|
|
127
171
|
The score is valid only when the starting time point is earlier than
|
128
|
-
current time, but not earlier than 24 hours ago. The strength of the score
|
172
|
+
the current time, but not earlier than 24 hours ago. The strength of the score
|
129
173
|
is the amount of the trailing zeros in the hash. In the example above the
|
130
|
-
strength
|
174
|
+
strength is six.
|
131
175
|
|
132
176
|
\section{Wallets}
|
133
177
|
|
178
|
+
There is no central ledger in Zold.
|
179
|
+
Each user has \emph{wallets} (any number of them).
|
180
|
+
Each wallet is an ASCII-text file with the name equal to the wallet ID.
|
181
|
+
For example, the wallet in the file \dd{12345678abcdef} may include:
|
182
|
+
|
183
|
+
\begin{minted}{text}
|
184
|
+
12345678abcdef
|
185
|
+
AAAAB3NzaC1yc2EAAAADAQABAAABAQCuLuVr4Tl2sXoN5Zb7b6SKMPrVjLxb...
|
186
|
+
|
187
|
+
34;2017-07-19T21:24:51Z;-560700;Ui0wpLu7;98bb82c81735c4ee;For services;SKMPrVjLxbM5oDm0IhniQQy3shF...
|
188
|
+
35;2017-07-19T21:25:07Z;-56990;xksQuJa9;98bb82c81735c4ee;For food;QCuLuVr4Tl2sXoN5Zb7b6SKMPrVjLxb...
|
189
|
+
134;2017-07-19T21:29:11Z;647388;kkIZo09s;18bb82dd1735b6e9;-;
|
190
|
+
36;2017-07-19T22:18:43Z;-884733;pplIe28s;38ab8fc8e735c4fc;For programming;2sXoN5Zb7b6SKMPrVjLxb7b6SKMPrVjLx...
|
191
|
+
\end{minted}
|
192
|
+
|
193
|
+
Lines are separated by either CR or CRLF.
|
194
|
+
There is a header and a ledger, separated by an empty line.
|
195
|
+
The header includes two lines:
|
196
|
+
|
197
|
+
\begin{enumerate}
|
198
|
+
\item Wallet ID, a 64-bit unsigned integer in hexadecimal format;
|
199
|
+
\item Public \href{https://en.wikipedia.org/wiki/RSA_(cryptosystem)}{RSA}
|
200
|
+
key of the wallet owner, in \href{https://en.wikipedia.org/wiki/Base64}{Base64}.
|
201
|
+
\end{enumerate}
|
202
|
+
|
203
|
+
The ledger includes transactions, one per line. Each transaction line
|
204
|
+
contains fields separated by a semi-colon:
|
205
|
+
|
206
|
+
\begin{enumerate}
|
207
|
+
\item Transaction ID, an unsigned 16-bit integer;
|
208
|
+
\item Date and time, in \href{https://en.wikipedia.org/wiki/ISO_8601}{ISO 8601} format;
|
209
|
+
\item Amount, a signed 64-bit integer;
|
210
|
+
\item Payment prefix, 8-32 symbols;
|
211
|
+
\item Wallet ID of the beneficiary;
|
212
|
+
\item Details, matching \dd{/[a-zA-Z0-9 -.]\{1,128\}/};
|
213
|
+
\item \href{https://en.wikipedia.org/wiki/RSA_(cryptosystem)}{RSA} signature,
|
214
|
+
684 symbols in \href{https://en.wikipedia.org/wiki/Base64}{Base64}.
|
215
|
+
\end{enumerate}
|
216
|
+
|
217
|
+
Transactions with positive amount don't have signatures.
|
218
|
+
Their IDs point to ID fields of corresponding beneficiaries' wallets.
|
219
|
+
|
220
|
+
The combination \dd{ID+Beneficiary} is unique in the entire wallet.
|
221
|
+
|
222
|
+
The \href{https://en.wikipedia.org/wiki/RSA_(cryptosystem)}{RSA}
|
223
|
+
signature is calculated using the private RSA key of the
|
224
|
+
wallet and the following fields of transaction, separated by spaces:
|
225
|
+
|
226
|
+
\begin{enumerate}
|
227
|
+
\item Wallet ID;
|
228
|
+
\item Transaction ID, an unsigned 16-bit integer;
|
229
|
+
\item Date and time, in ISO 8601 format;
|
230
|
+
\item Amount, a signed 64-bit integer;
|
231
|
+
\item Payment prefix;
|
232
|
+
\item Wallet ID of the beneficiary;
|
233
|
+
\item Details, matching \dd{/[a-zA-Z0-9 -.]{1,128}/}.
|
234
|
+
\end{enumerate}
|
235
|
+
|
134
236
|
\section{Push}
|
135
237
|
|
136
238
|
\section{Fetch and Merge}
|
data/zold.gemspec
CHANGED
@@ -39,7 +39,7 @@ Gem::Specification.new do |s|
|
|
39
39
|
s.homepage = 'http://github.com/zerocracy/zold'
|
40
40
|
s.files = `git ls-files`.split($RS)
|
41
41
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
42
|
-
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
42
|
+
s.test_files = s.files.grep(%r{^(test|spec|features|wp)/})
|
43
43
|
s.rdoc_options = ['--charset=UTF-8']
|
44
44
|
s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
45
45
|
s.add_runtime_dependency 'concurrent-ruby', '1.0.5'
|
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.6.
|
4
|
+
version: 0.6.3
|
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-05-
|
11
|
+
date: 2018-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -271,10 +271,12 @@ files:
|
|
271
271
|
- fixtures/keys/1.pub
|
272
272
|
- fixtures/keys/2
|
273
273
|
- fixtures/keys/2.pub
|
274
|
+
- fixtures/scripts/calculate-scores.sh
|
274
275
|
- fixtures/scripts/print-helps.sh
|
275
276
|
- fixtures/scripts/push-and-pull.sh
|
276
277
|
- lib/zold.rb
|
277
278
|
- lib/zold/amount.rb
|
279
|
+
- lib/zold/commands/calculate.rb
|
278
280
|
- lib/zold/commands/clean.rb
|
279
281
|
- lib/zold/commands/create.rb
|
280
282
|
- lib/zold/commands/diff.rb
|
@@ -308,6 +310,7 @@ files:
|
|
308
310
|
- lib/zold/wallet.rb
|
309
311
|
- lib/zold/wallets.rb
|
310
312
|
- resources/remotes
|
313
|
+
- test/commands/test_calculate.rb
|
311
314
|
- test/commands/test_clean.rb
|
312
315
|
- test/commands/test_create.rb
|
313
316
|
- test/commands/test_diff.rb
|
@@ -341,6 +344,7 @@ files:
|
|
341
344
|
- test/test_zold.rb
|
342
345
|
- wp/.gitignore
|
343
346
|
- wp/Makefile
|
347
|
+
- wp/logo.png
|
344
348
|
- wp/wp.tex
|
345
349
|
- zold.gemspec
|
346
350
|
homepage: http://github.com/zerocracy/zold
|
@@ -373,6 +377,7 @@ test_files:
|
|
373
377
|
- features/gem_package.feature
|
374
378
|
- features/step_definitions/steps.rb
|
375
379
|
- features/support/env.rb
|
380
|
+
- test/commands/test_calculate.rb
|
376
381
|
- test/commands/test_clean.rb
|
377
382
|
- test/commands/test_create.rb
|
378
383
|
- test/commands/test_diff.rb
|
@@ -404,3 +409,7 @@ test_files:
|
|
404
409
|
- test/test_wallet.rb
|
405
410
|
- test/test_wallets.rb
|
406
411
|
- test/test_zold.rb
|
412
|
+
- wp/.gitignore
|
413
|
+
- wp/Makefile
|
414
|
+
- wp/logo.png
|
415
|
+
- wp/wp.tex
|