zold 0.6 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 01a2323174e903dabb35708bfd1d0f756e930035
4
- data.tar.gz: a4f6582b8e645cd480ab74e374cc5cefe3698034
3
+ metadata.gz: 42d45258927844c4cc2c07418af8b5077787731b
4
+ data.tar.gz: 508255ebe906bd0c4dd9fcb88ed12dee32a1973a
5
5
  SHA512:
6
- metadata.gz: 8e6c51f38a8f4d44c86c6cf1d2c02d3db2a1495504613c29676922a91bc03b325524b87d592dabdeb406fc9ca6906725de8666b805ea98731a7fe4271c950123
7
- data.tar.gz: '0906447919a3f02950152613a65b19d648ca46cf480405659751ab6ab4eee1d08b01f8f1dfef2a60de4c5e55b17433913637daf37c0d7451f13e8320aa33c572'
6
+ metadata.gz: 4783b3ade202e80fb6b252ed58cab12176a0bcb70cc4584e67e3e6fe49f1ec9fcd2fdb1df0020f7a2d13b20e865e99c591a14604e402b8725acc9168a6365b2b
7
+ data.tar.gz: c8c189ee8908b4479b3b9e71f73776995ddcfc407cb2bdb6e32b15339c63bbdfc86a6f5a49845ad064bbd92cc1f50c2da557be6ae9d3a2673dbe478f4c80c0cc
@@ -6,7 +6,7 @@ AllCops:
6
6
  TargetRubyVersion: 2.2
7
7
 
8
8
  Metrics/CyclomaticComplexity:
9
- Max: 15
9
+ Max: 25
10
10
  Metrics/MethodLength:
11
11
  Enabled: false
12
12
  Layout/MultilineMethodCallIndentation:
@@ -17,13 +17,13 @@ Metrics/BlockLength:
17
17
  Max: 100
18
18
  Metrics/ClassLength:
19
19
  Max: 200
20
- Style/EndOfLine:
20
+ Layout/EndOfLine:
21
21
  EnforcedStyle: lf
22
22
  Metrics/ParameterLists:
23
23
  Max: 10
24
24
  Layout/AlignParameters:
25
25
  Enabled: false
26
26
  Metrics/PerceivedComplexity:
27
- Max: 15
27
+ Max: 25
28
28
  Metrics/LineLength:
29
29
  Max: 120
data/README.md CHANGED
@@ -17,21 +17,6 @@
17
17
  **NOTICE**: It's an experiment and a very early draft! Please, feel free to
18
18
  submit your ideas or pull requests.
19
19
 
20
- ZOLD principles include:
21
-
22
- * The entire code base is open source;
23
- * There is no mining, the only way to get ZOLD is to receive it from someone else;
24
- * Only 2<sup>63</sup> numerals (no fractions) can technically be issued;
25
- * The first wallet belongs to the issuer and may have a negative balance;
26
- * A wallet is a plain text file;
27
- * There is no central ledger, each wallet has its own personal ledger;
28
- * Each transaction in the ledger is confirmed by [RSA](https://simple.wikipedia.org/wiki/RSA_%28algorithm%29) encryption;
29
- * The network of communicating nodes maintains wallets of users;
30
- * Anyone can add a node to the network.
31
-
32
- 1 ZLD by convention equals to 2<sup>24</sup> (16,777,216) _zents_.
33
- Thus, the technical capacity of the currency is 549,755,813,888 ZLD (half a trillion).
34
-
35
20
  ## How to Use
36
21
 
37
22
  Install Ruby 2.2+, [Rubygems](https://rubygems.org/pages/download), and then run:
@@ -44,20 +29,9 @@ $ gem install zold
44
29
  Then, either run it as a node:
45
30
 
46
31
  ```bash
47
- $ zold start
32
+ $ zold node
48
33
  ```
49
34
 
50
- Or do one of the following:
51
-
52
- * `zold remote` manipulates the list off remote nodes;
53
- * `zold create` creates a new wallet (you have to provide PGP keys);
54
- * `zold fetch` downloads all copies of the wallet from the network;
55
- * `zold merge` merges all copies of the wallet into the local one;
56
- * `zold pull` first `fetch`, then `merge`;
57
- * `zold show` prints out all known details of a wallet (incl. its balance);
58
- * `zold pay` creates a new transaction;
59
- * `zold push` pushes a wallet to the network.
60
-
61
35
  For more options and commands just run:
62
36
 
63
37
  ```bash
@@ -71,60 +45,6 @@ yet, you can run:
71
45
  $ ssh-keygen -t rsa -b 4096
72
46
  ```
73
47
 
74
- ## Glossary
75
-
76
- **Node** is an HTTP server with a RESTful API, a maintainer of wallets
77
- and a command line Ruby gem [`zold`](https://rubygems.org/gems/zold).
78
-
79
- **Network** is a set of all nodes available online.
80
-
81
- **Score** is the amount of "hash sufficies" a node has at any given moment of time.
82
-
83
- **Wallet** is a text file with a ledger of all transactions inside.
84
-
85
- **Transaction** is a money transferring operation between two wallets.
86
-
87
- **MSS** (minimum summary score) is a summary of all scores required to trust a wallet.
88
-
89
- ## Score
90
-
91
- Each node calculates its own score. First, it takes the current timestamp
92
- in UTC [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601),
93
- for example `2017-07-19T21:24:51Z ` (with a trailing space). Then, it appends
94
- its own host name or IP address to it, space, TCP port number, and a space.
95
- Then, it attempts to append any
96
- arbitrary text (has to match `[a-zA-Z0-9]+`) to the end of it and to calculate SHA-256 of the text
97
- in the hexadecimal format, for example:
98
-
99
- ```
100
- Input: "2017-07-19T21:24:51Z b1.zold.io 4096 the-suffix"
101
- SHA-256: "eba36e52e1ee674d198f486e07c8496853ffc8879e7fe25329523177646a96a0"
102
- ```
103
-
104
- The node attempts to try different sufficies until one of them produces
105
- SHA-256 hash that ends with `0000000` (seven zeros). For example, this
106
- suffix `11edb424c` works (it took 212 minutes to find it on 2.3GHz Intel Core i7):
107
-
108
- ```
109
- Input: "2017-07-19T21:24:51Z b1.zold.io 4096 11edb424c"
110
- SHA-256: "34f48e0eee1ed12ad74cb39418f2f6e7442a776a7b6182697957650e00000000"
111
- ```
112
-
113
- When the first suffix is found, the score of the node is 1. Then, to
114
- increase the score by one, the node has to find the next suffix, which
115
- can be added to the first 20 characters of the previous hash
116
- in order to obtain a new hash with trailing zeros, for example:
117
-
118
- ```
119
- Input: "34f48e0eee1ed12ad74c "
120
- SHA-256: "..."
121
- ```
122
-
123
- And so on.
124
-
125
- The score is valid only when the starting time point is earlier than
126
- current time, but not earlier than 24 hours ago.
127
-
128
48
  ## Operations
129
49
 
130
50
  ### Remote
data/bin/zold CHANGED
@@ -41,7 +41,7 @@ Encoding.default_internal = Encoding::UTF_8
41
41
  log = Zold::Log.new
42
42
 
43
43
  args = []
44
- unless ENV['RACK_ENV'] == 'test'
44
+ unless ENV['RACK_ENV'] == 'test' || ARGV.find { |a| a == '--ignore-global-config' }
45
45
  config = File.expand_path('~/.zold')
46
46
  if File.exist?(config)
47
47
  body = File.read(config)
@@ -92,6 +92,7 @@ Available options:"
92
92
  default: Dir.pwd
93
93
  o.bool '-h', '--help', 'Show these instructions'
94
94
  o.bool '--trace', 'Show full stack trace in case of a problem'
95
+ o.bool '--ignore-global-config', 'Don\'t read options from the ~/.zold file'
95
96
  o.on '--no-colors', 'Disable colors in the ouput' do
96
97
  Rainbow.enabled = false
97
98
  end
@@ -104,16 +105,17 @@ Available options:"
104
105
  end
105
106
  end
106
107
 
107
- raise 'Try --help' if opts.arguments.empty? && !opts.help?
108
+ commands = opts.arguments.reject { |a| a.start_with?('-') }
109
+ command = commands[0]
108
110
 
109
- if opts.help? && opts.arguments.empty?
111
+ if command.nil?
112
+ raise 'A command required, try --help' unless opts.help?
110
113
  log.info(opts.to_s)
111
114
  exit
112
115
  end
113
116
 
114
- command = opts.arguments[0]
115
-
116
- args = args[(args.index(command) + 1)..-1]
117
+ args = opts.arguments
118
+ args << '--help' if opts.help?
117
119
 
118
120
  wallets = Zold::Wallets.new(opts['dir'])
119
121
  remotes = Zold::Remotes.new(File.join(opts['dir'], '.zoldata/remotes'))
@@ -12,6 +12,6 @@ Feature: Command Line Processing
12
12
  Then Exit code is zero
13
13
 
14
14
  Scenario: Wallet can be created
15
- When I run bin/zold with "--trace create --public-key=id_rsa.pub"
15
+ When I run bin/zold with "--trace --public-key=id_rsa.pub create"
16
16
  Then Exit code is zero
17
17
 
@@ -9,5 +9,5 @@ zold --help
9
9
  declare -a commands=(node create invoice remote pay show fetch clean diff merge propagate pull push)
10
10
  for c in "${commands[@]}"
11
11
  do
12
- zold --trace $c --help
12
+ zold --ignore-global-config --trace $c --help
13
13
  done
@@ -3,7 +3,7 @@ set -x
3
3
  set -e
4
4
  shopt -s expand_aliases
5
5
 
6
- alias zold="$1"
6
+ alias zold="$1 --ignore-global-config --trace"
7
7
 
8
8
  port=`python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'`
9
9
 
@@ -21,21 +21,21 @@ while ! nc -z localhost ${port}; do
21
21
  ((c++)) && ((c==20)) && break
22
22
  done
23
23
 
24
- zold --trace remote clean
25
- zold --trace remote add localhost ${port}
26
- zold --trace remote show
24
+ zold remote clean
25
+ zold remote add localhost ${port}
26
+ zold remote show
27
27
 
28
- zold --trace create --public-key=id_rsa.pub 0000000000000000
28
+ zold create --public-key=id_rsa.pub 0000000000000000
29
29
  target=`zold create --public-key=id_rsa.pub`
30
30
  invoice=`zold invoice ${target}`
31
- zold --trace pay --private-key=id_rsa 0000000000000000 ${invoice} 14.99 'To save the world!'
32
- zold --trace propagate 0000000000000000
33
- zold --trace show
34
- zold --trace show 0000000000000000
31
+ zold pay --private-key=id_rsa 0000000000000000 ${invoice} 14.99 'To save the world!'
32
+ zold propagate 0000000000000000
33
+ zold show
34
+ zold show 0000000000000000
35
35
 
36
- zold --trace remote show
37
- zold --trace push 0000000000000000
38
- zold --trace fetch 0000000000000000 --ignore-score-weakness
39
- zold --trace diff 0000000000000000
40
- zold --trace merge 0000000000000000
41
- zold --trace clean 0000000000000000
36
+ zold remote show
37
+ zold push 0000000000000000
38
+ zold fetch 0000000000000000 --ignore-score-weakness
39
+ zold diff 0000000000000000
40
+ zold merge 0000000000000000
41
+ zold clean 0000000000000000
@@ -39,7 +39,7 @@ module Zold
39
39
  end
40
40
 
41
41
  def run(args = [])
42
- opts = Slop.parse(args, help: true) do |o|
42
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
43
43
  o.banner = "Usage: zold clean [ID...] [options]
44
44
  Available options:"
45
45
  o.bool '--help', 'Print instructions'
@@ -48,8 +48,9 @@ Available options:"
48
48
  @log.info(opts.to_s)
49
49
  return
50
50
  end
51
- raise 'At least one wallet ID is required' if opts.arguments.empty?
52
- opts.arguments.each do |id|
51
+ mine = opts.arguments[1..-1]
52
+ raise 'At least one wallet ID is required' if mine.empty?
53
+ mine.each do |id|
53
54
  clean(Copies.new(File.join(@copies, id)), opts)
54
55
  end
55
56
  end
@@ -35,7 +35,7 @@ module Zold
35
35
  end
36
36
 
37
37
  def run(args = [])
38
- opts = Slop.parse(args, help: true) do |o|
38
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
39
39
  o.banner = "Usage: zold create [options]
40
40
  Available options:"
41
41
  o.string '--public-key',
@@ -48,7 +48,8 @@ Available options:"
48
48
  @log.info(opts.to_s)
49
49
  return
50
50
  end
51
- create(opts.arguments.empty? ? Id.new : Id.new(opts.arguments[0]), opts)
51
+ mine = opts.arguments[1..-1]
52
+ create(mine.empty? ? Id.new : Id.new(mine[0]), opts)
52
53
  end
53
54
 
54
55
  def create(id, opts)
@@ -39,7 +39,7 @@ module Zold
39
39
  end
40
40
 
41
41
  def run(args = [])
42
- opts = Slop.parse(args, help: true) do |o|
42
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
43
43
  o.banner = "Usage: zold diff [ID...] [options]
44
44
  Available options:"
45
45
  o.bool '--help', 'Print instructions'
@@ -48,9 +48,10 @@ Available options:"
48
48
  @log.info(opts.to_s)
49
49
  return
50
50
  end
51
- raise 'At least one wallet ID is required' if opts.arguments.empty?
51
+ mine = opts.arguments[1..-1]
52
+ raise 'At least one wallet ID is required' if mine.empty?
52
53
  stdout = ''
53
- opts.arguments.each do |id|
54
+ mine.each do |id|
54
55
  stdout += diff(
55
56
  @wallets.find(Id.new(id)),
56
57
  Copies.new(File.join(@copies, id)),
@@ -41,7 +41,7 @@ module Zold
41
41
  end
42
42
 
43
43
  def run(args = [])
44
- opts = Slop.parse(args, help: true) do |o|
44
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
45
45
  o.banner = "Usage: zold fetch [ID...] [options]
46
46
  Available options:"
47
47
  o.bool '--ignore-score-weakness',
@@ -56,8 +56,9 @@ Available options:"
56
56
  @log.info(opts.to_s)
57
57
  return
58
58
  end
59
- raise 'At least one wallet ID is required' if opts.arguments.empty?
60
- opts.arguments.each do |id|
59
+ mine = opts.arguments[1..-1]
60
+ raise 'At least one wallet ID is required' if mine.empty?
61
+ mine.each do |id|
61
62
  fetch(id, Copies.new(File.join(@copies, id)), opts)
62
63
  end
63
64
  end
@@ -35,7 +35,7 @@ module Zold
35
35
  end
36
36
 
37
37
  def run(args = [])
38
- opts = Slop.parse(args, help: true) do |o|
38
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
39
39
  o.banner = "Usage: zold invoice ID [options]
40
40
  Where:
41
41
  'ID' is the wallet ID of the money receiver
@@ -49,8 +49,9 @@ Available options:"
49
49
  @log.info(opts.to_s)
50
50
  return
51
51
  end
52
- raise 'Receiver wallet ID is required' if opts.arguments[0].nil?
53
- wallet = @wallets.find(Zold::Id.new(opts.arguments[0]))
52
+ mine = opts.arguments[1..-1]
53
+ raise 'Receiver wallet ID is required' if mine[0].nil?
54
+ wallet = @wallets.find(Zold::Id.new(mine[0]))
54
55
  raise 'Wallet doesn\'t exist, do \'fetch\' first' unless wallet.exists?
55
56
  invoice(wallet, opts)
56
57
  end
@@ -39,7 +39,7 @@ module Zold
39
39
 
40
40
  # Returns the array of modified wallets (IDs)
41
41
  def run(args = [])
42
- opts = Slop.parse(args, help: true) do |o|
42
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
43
43
  o.banner = "Usage: zold merge [ID...] [options]
44
44
  Available options:"
45
45
  o.bool '--help', 'Print instructions'
@@ -48,9 +48,10 @@ Available options:"
48
48
  @log.info(opts.to_s)
49
49
  return
50
50
  end
51
- raise 'At least one wallet ID is required' if opts.arguments.empty?
51
+ mine = opts.arguments[1..-1]
52
+ raise 'At least one wallet ID is required' if mine.empty?
52
53
  modified = []
53
- opts.arguments.each do |id|
54
+ mine.each do |id|
54
55
  wallet = @wallets.find(Id.new(id))
55
56
  next unless merge(wallet, Copies.new(File.join(@copies, id)), opts)
56
57
  modified << Id.new(id)
@@ -38,7 +38,7 @@ module Zold
38
38
  end
39
39
 
40
40
  def run(args = [])
41
- opts = Slop.parse(args, help: true) do |o|
41
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
42
42
  o.banner = 'Usage: zold node [options]'
43
43
  o.string '--invoice',
44
44
  'The invoice you want to collect money to'
@@ -34,7 +34,7 @@ module Zold
34
34
  end
35
35
 
36
36
  def run(args = [])
37
- opts = Slop.parse(args, help: true) do |o|
37
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
38
38
  o.banner = "Usage: zold pay wallet invoice amount [details] [options]
39
39
  Where:
40
40
  'wallet' is the sender's wallet ID
@@ -55,14 +55,15 @@ Available options:"
55
55
  @log.info(opts.to_s)
56
56
  return
57
57
  end
58
- raise 'Payer wallet ID is required' if opts.arguments[0].nil?
59
- from = @wallets.find(Zold::Id.new(opts.arguments[0]))
58
+ mine = opts.arguments[1..-1]
59
+ raise 'Payer wallet ID is required as the first argument' if mine[0].nil?
60
+ from = @wallets.find(Zold::Id.new(mine[0]))
60
61
  raise 'Wallet doesn\'t exist, do \'fetch\' first' unless from.exists?
61
- raise 'Recepient\'s invoice is required' if opts.arguments[1].nil?
62
- invoice = opts.arguments[1]
63
- raise 'Amount is required (in ZLD)' if opts.arguments[2].nil?
64
- amount = Zold::Amount.new(zld: opts.arguments[2].to_f)
65
- details = opts.arguments[3] ? opts.arguments[3] : '-'
62
+ raise 'Recepient\'s invoice is required as the second argument' if mine[1].nil?
63
+ invoice = mine[1]
64
+ raise 'Amount is required (in ZLD) as the third argument' if mine[2].nil?
65
+ amount = Zold::Amount.new(zld: mine[2].to_f)
66
+ details = mine[3] ? mine[3] : '-'
66
67
  pay(from, invoice, amount, details, opts)
67
68
  end
68
69
 
@@ -37,7 +37,7 @@ module Zold
37
37
 
38
38
  # Returns list of Wallet IDs which were affected
39
39
  def run(args = [])
40
- opts = Slop.parse(args, help: true) do |o|
40
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
41
41
  o.banner = "Usage: zold propagate [ID...] [options]
42
42
  Available options:"
43
43
  o.bool '--help', 'Print instructions'
@@ -46,9 +46,10 @@ Available options:"
46
46
  @log.info(opts.to_s)
47
47
  return
48
48
  end
49
- raise 'At least one wallet ID is required' if opts.arguments.empty?
49
+ mine = opts.arguments[1..-1]
50
+ raise 'At least one wallet ID is required' if mine.empty?
50
51
  modified = []
51
- opts.arguments.each do |id|
52
+ mine.each do |id|
52
53
  modified += propagate(@wallets.find(id), opts)
53
54
  end
54
55
  modified
@@ -39,7 +39,7 @@ module Zold
39
39
  end
40
40
 
41
41
  def run(args = [])
42
- opts = Slop.parse(args, help: true) do |o|
42
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
43
43
  o.banner = "Usage: zold push [ID...] [options]
44
44
  Available options:"
45
45
  o.bool '--help', 'Print instructions'
@@ -48,8 +48,9 @@ Available options:"
48
48
  @log.info(opts.to_s)
49
49
  return
50
50
  end
51
- raise 'At least one wallet ID is required' if opts.arguments.empty?
52
- opts.arguments.each do |id|
51
+ mine = opts.arguments[1..-1]
52
+ raise 'At least one wallet ID is required' if mine.empty?
53
+ mine.each do |id|
53
54
  push(@wallets.find(Id.new(id)), opts)
54
55
  end
55
56
  end
@@ -41,7 +41,7 @@ module Zold
41
41
  end
42
42
 
43
43
  def run(args = [])
44
- opts = Slop.parse(args, help: true) do |o|
44
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
45
45
  o.banner = "Usage: zold remote <command> [options]
46
46
  Available commands:
47
47
  #{Rainbow('remote show').green}
@@ -62,7 +62,12 @@ Available options:"
62
62
  default: false
63
63
  o.bool '--help', 'Print instructions'
64
64
  end
65
- command = opts.arguments[0]
65
+ if opts.help?
66
+ @log.info(opts.to_s)
67
+ return
68
+ end
69
+ mine = opts.arguments[1..-1]
70
+ command = mine[0]
66
71
  case command
67
72
  when 'show'
68
73
  show
@@ -71,14 +76,14 @@ Available options:"
71
76
  when 'reset'
72
77
  reset
73
78
  when 'add'
74
- add(opts.arguments[1], opts.arguments[2] ? opts.arguments[2].to_i : Remotes::PORT)
79
+ add(mine[1], mine[2] ? mine[2].to_i : Remotes::PORT)
75
80
  when 'remove'
76
- remove(opts.arguments[1], opts.arguments[2] ? opts.arguments[2].to_i : Remotes::PORT)
81
+ remove(mine[1], mine[2] ? mine[2].to_i : Remotes::PORT)
77
82
  when 'update'
78
83
  update(opts)
79
84
  update(opts, false)
80
85
  else
81
- @log.info(opts.to_s)
86
+ raise "Unknown command '#{command}'"
82
87
  end
83
88
  end
84
89
 
@@ -36,7 +36,7 @@ module Zold
36
36
  end
37
37
 
38
38
  def run(args = [])
39
- opts = Slop.parse(args, help: true) do |o|
39
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
40
40
  o.banner = "Usage: zold show [ID...] [options]
41
41
  Available options:"
42
42
  o.bool '--help', 'Print instructions'
@@ -45,12 +45,13 @@ Available options:"
45
45
  @log.info(opts.to_s)
46
46
  return
47
47
  end
48
- if opts.arguments.empty?
48
+ mine = opts.arguments[1..-1]
49
+ if mine.empty?
49
50
  require_relative 'list'
50
51
  List.new(wallets: @wallets, log: @log).run(args)
51
52
  else
52
53
  total = Amount::ZERO
53
- opts.arguments.each do |id|
54
+ mine.each do |id|
54
55
  total += show(@wallets.find(Id.new(id)), opts)
55
56
  end
56
57
  total
@@ -41,7 +41,7 @@ module Zold
41
41
  end
42
42
 
43
43
  def run(args = [])
44
- opts = Slop.parse(args, help: true) do |o|
44
+ opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
45
45
  o.banner = "Usage: zold taxes command [options]
46
46
  Available commands:
47
47
  #{Rainbow('taxes pay').green} wallet
@@ -57,21 +57,22 @@ Available options:"
57
57
  default: '~/.ssh/id_rsa'
58
58
  o.bool '--help', 'Print instructions'
59
59
  end
60
- command = opts.arguments[0]
60
+ mine = opts.arguments[1..-1]
61
+ command = mine[0]
61
62
  case command
62
63
  when 'show'
63
- raise 'At least one wallet ID is required' unless opts.arguments[1]
64
- opts.arguments[1..-1].each do |id|
64
+ raise 'At least one wallet ID is required' unless mine[1]
65
+ mine[1..-1].each do |id|
65
66
  show(@wallets.find(Id.new(id), opts))
66
67
  end
67
68
  when 'debt'
68
- raise 'At least one wallet ID is required' unless opts.arguments[1]
69
- opts.arguments[1..-1].each do |id|
69
+ raise 'At least one wallet ID is required' unless mine[1]
70
+ mine[1..-1].each do |id|
70
71
  debt(@wallets.find(Id.new(id), opts))
71
72
  end
72
73
  when 'pay'
73
- raise 'At least one wallet ID is required' unless opts.arguments[1]
74
- opts.arguments[1..-1].each do |id|
74
+ raise 'At least one wallet ID is required' unless mine[1]
75
+ mine[1..-1].each do |id|
75
76
  pay(@wallets.find(Id.new(id)), opts)
76
77
  end
77
78
  else
@@ -55,10 +55,10 @@ module Zold
55
55
  copies.add(body, 'remote', Remotes::PORT, 0)
56
56
  Fetch.new(
57
57
  remotes: @remotes, copies: copies.root, log: @log
58
- ).run([id.to_s, "--ignore-node=#{@address}"])
58
+ ).run(['fetch', id.to_s, "--ignore-node=#{@address}"])
59
59
  modified = Merge.new(
60
60
  wallets: @wallets, copies: copies.root, log: @log
61
- ).run([id.to_s])
61
+ ).run(['merge', id.to_s])
62
62
  debt = Tax.new(@wallets.find(id)).debt
63
63
  if debt > Tax::TRIAL
64
64
  raise "Taxes are not paid, the debt is #{debt} (#{debt.to_i} zents), won't promote the wallet"
@@ -67,7 +67,7 @@ module Zold
67
67
  modified.each do |m|
68
68
  Push.new(
69
69
  wallets: @wallets, remotes: @remotes, log: @log
70
- ).run([m.to_s])
70
+ ).run(['push', m.to_s])
71
71
  end
72
72
  modified
73
73
  end
@@ -165,7 +165,7 @@ module Zold
165
165
  @suffixes.reduce(start) do |prefix, suffix|
166
166
  hex = Digest::SHA256.hexdigest(prefix + ' ' + suffix)
167
167
  return false unless hex.end_with?('0' * @strength)
168
- hex[0, 19]
168
+ hex[0, 63]
169
169
  end
170
170
  true
171
171
  end
@@ -34,19 +34,25 @@ module Zold
34
34
  attr_reader :id, :date, :amount, :prefix, :bnf, :details, :sign
35
35
  attr_writer :sign, :amount, :bnf
36
36
  def initialize(id, date, amount, prefix, bnf, details)
37
+ raise 'The ID can\'t be NIL' if id.nil?
37
38
  raise "ID of transaction can't be negative: #{id}" if id < 1
38
39
  @id = id
40
+ raise 'The time can\'t be NIL' if date.nil?
39
41
  raise 'Time have to be of type Time' unless date.is_a?(Time)
40
42
  raise "Time can't be in the future: #{date}" if date > Time.now
41
43
  @date = date
44
+ raise 'The amount can\'t be NIL' if amount.nil?
42
45
  raise 'The amount has to be of type Amount' unless amount.is_a?(Amount)
43
46
  raise 'The amount can\'t be zero' if amount.zero?
44
47
  @amount = amount
48
+ raise 'The bnf can\'t be NIL' if bnf.nil?
45
49
  raise 'The bnf has to be of type Id' unless bnf.is_a?(Id)
46
50
  @bnf = bnf
51
+ raise 'Prefix can\'t be NIL' if prefix.nil?
47
52
  raise "Prefix is too short: \"#{prefix}\"" if prefix.length < 8
48
53
  raise "Prefix is too long: \"#{prefix}\"" if prefix.length > 32
49
54
  @prefix = prefix
55
+ raise 'Details can\'t be NIL' if details.nil?
50
56
  raise 'Details can\'t be empty' if details.empty?
51
57
  raise "Details are too long: \"#{details}\"" if details.length > 128
52
58
  raise "Details are wrong: \"#{details}\"" unless details =~ /^[a-zA-Z0-9 -\.,]{1,128}$/
@@ -23,5 +23,5 @@
23
23
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
24
24
  # License:: MIT
25
25
  module Zold
26
- VERSION = '0.6'.freeze
26
+ VERSION = '0.6.1'.freeze
27
27
  end
@@ -35,7 +35,7 @@ class TestClean < Minitest::Test
35
35
  copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
36
36
  copies.add('a1', 'host-1', 80, 1, Time.now - 26 * 60)
37
37
  copies.add('a2', 'host-2', 80, 2, Time.now - 26 * 60)
38
- Zold::Clean.new(copies: copies.root).run([id.to_s])
38
+ Zold::Clean.new(copies: copies.root).run(['clean', id.to_s])
39
39
  assert(copies.all.empty?)
40
40
  end
41
41
  end
@@ -32,7 +32,7 @@ class TestCreate < Minitest::Test
32
32
  def test_creates_wallet
33
33
  Dir.mktmpdir 'test' do |dir|
34
34
  wallet = Zold::Create.new(wallets: Zold::Wallets.new(dir)).run(
35
- ['--public-key=fixtures/id_rsa.pub']
35
+ ['create', '--public-key=fixtures/id_rsa.pub']
36
36
  )
37
37
  assert wallet.balance.zero?
38
38
  assert(
@@ -47,14 +47,14 @@ class TestDiff < Minitest::Test
47
47
  File.write(second.path, File.read(wallet.path))
48
48
  Zold::Pay.new(
49
49
  wallets: Zold::Wallets.new(dir)
50
- ).run([id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
50
+ ).run(['pay', id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
51
51
  copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
52
52
  copies.add(File.read(first.path), 'host-1', 80, 5)
53
53
  copies.add(File.read(second.path), 'host-2', 80, 5)
54
54
  diff = Zold::Diff.new(
55
55
  wallets: Zold::Wallets.new(dir),
56
56
  copies: copies.root
57
- ).run([id.to_s])
57
+ ).run(['diff', id.to_s])
58
58
  assert(diff.include?('-1;'))
59
59
  end
60
60
  end
@@ -58,7 +58,7 @@ class TestFetch < Minitest::Test
58
58
  remotes.add('fake-2', 80)
59
59
  copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
60
60
  Zold::Fetch.new(copies: copies.root, remotes: remotes).run(
61
- ['--ignore-score-weakness', id.to_s]
61
+ ['fetch', '--ignore-score-weakness', id.to_s]
62
62
  )
63
63
  assert_equal(copies.all[0][:name], '1')
64
64
  assert_equal(copies.all[0][:score], 0)
@@ -79,7 +79,7 @@ class TestFetch < Minitest::Test
79
79
  )
80
80
  remotes.add('fake-1', 80)
81
81
  copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
82
- Zold::Fetch.new(copies: copies.root, remotes: remotes).run([id.to_s])
82
+ Zold::Fetch.new(copies: copies.root, remotes: remotes).run(['fetch', id.to_s])
83
83
  assert_equal(copies.all[0][:name], '1')
84
84
  assert_equal(copies.all[0][:score], 0)
85
85
  end
@@ -38,7 +38,7 @@ class TestInvoice < Minitest::Test
38
38
  source = wallets.find(id)
39
39
  source.init(id, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
40
40
  invoice = Zold::Invoice.new(wallets: wallets).run(
41
- [id.to_s, '--length=16']
41
+ ['invoice', id.to_s, '--length=16']
42
42
  )
43
43
  assert_equal(33, invoice.length)
44
44
  end
@@ -24,6 +24,7 @@ require 'json'
24
24
  require 'time'
25
25
  require 'webmock/minitest'
26
26
  require_relative '../../lib/zold/wallet'
27
+ require_relative '../../lib/zold/wallets'
27
28
  require_relative '../../lib/zold/id'
28
29
  require_relative '../../lib/zold/copies'
29
30
  require_relative '../../lib/zold/key'
@@ -49,14 +50,14 @@ class TestMerge < Minitest::Test
49
50
  File.write(second.path, File.read(wallet.path))
50
51
  Zold::Pay.new(
51
52
  wallets: Zold::Wallets.new(dir)
52
- ).run([id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
53
+ ).run(['pay', id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
53
54
  copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
54
55
  copies.add(File.read(first.path), 'host-1', 80, 5)
55
56
  copies.add(File.read(second.path), 'host-2', 80, 5)
56
57
  modified = Zold::Merge.new(
57
58
  wallets: Zold::Wallets.new(dir),
58
59
  copies: copies.root
59
- ).run([id.to_s])
60
+ ).run(['merge', id.to_s])
60
61
  assert(1, modified.count)
61
62
  assert(id, modified[0])
62
63
  end
@@ -74,14 +75,14 @@ class TestMerge < Minitest::Test
74
75
  File.write(second.path, File.read(wallet.path))
75
76
  Zold::Pay.new(
76
77
  wallets: Zold::Wallets.new(dir)
77
- ).run([id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
78
+ ).run(['pay', id.to_s, second.id.to_s, '14.95', '--force', '--private-key=fixtures/id_rsa'])
78
79
  copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
79
80
  copies.add(File.read(first.path), 'host-1', 80, 5)
80
81
  copies.add(File.read(second.path), 'host-2', 80, 5)
81
82
  modified = Zold::Merge.new(
82
83
  wallets: Zold::Wallets.new(dir),
83
84
  copies: copies.root
84
- ).run([id.to_s])
85
+ ).run(['merge', id.to_s])
85
86
  assert(1, modified.count)
86
87
  assert(id, modified[0])
87
88
  end
@@ -46,8 +46,8 @@ class TestNode < Minitest::Test
46
46
  remotes = Zold::Remotes.new(File.join(dir, 'remotes.csv'))
47
47
  remotes.clean
48
48
  remotes.add('localhost', port)
49
- Zold::Push.new(wallet: wallet, remotes: remotes).run
50
- Zold::Fetch.new(wallet: wallet, copies: copies, remotes: remotes).run
49
+ Zold::Push.new(wallet: wallet, remotes: remotes).run(['push'])
50
+ Zold::Fetch.new(wallet: wallet, copies: copies, remotes: remotes).run(['fetch'])
51
51
  assert_equal(copies.all[0][:name], '1')
52
52
  assert_equal(copies.all[0][:score], 0)
53
53
  end
@@ -41,7 +41,7 @@ class TestPay < Minitest::Test
41
41
  amount = Zold::Amount.new(zld: 14.95)
42
42
  Zold::Pay.new(wallets: wallets).run(
43
43
  [
44
- '--force', '--private-key=fixtures/id_rsa',
44
+ 'pay', '--force', '--private-key=fixtures/id_rsa',
45
45
  id.to_s, target.to_s, amount.to_zld, 'For the car'
46
46
  ]
47
47
  )
@@ -57,11 +57,11 @@ class TestRemote < Minitest::Test
57
57
  status: 404
58
58
  )
59
59
  cmd = Zold::Remote.new(remotes: remotes)
60
- cmd.run(['clean'])
61
- cmd.run(['add', zero.host, zero.port.to_s])
62
- cmd.run(%w[add localhost 2])
60
+ cmd.run(%w[remote clean])
61
+ cmd.run(['remote', 'add', zero.host, zero.port.to_s])
62
+ cmd.run(%w[remote add localhost 2])
63
63
  assert_equal(2, remotes.all.count)
64
- cmd.run(['update', '--ignore-score-weakness'])
64
+ cmd.run(['remote', 'update', '--ignore-score-weakness'])
65
65
  assert_equal(1, remotes.all.count)
66
66
  end
67
67
  end
@@ -37,7 +37,7 @@ class TestShow < Minitest::Test
37
37
  wallets = Zold::Wallets.new(dir)
38
38
  wallet = wallets.find(id)
39
39
  wallet.init(Zold::Id.new, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
40
- balance = Zold::Show.new(wallets: wallets).run([id.to_s])
40
+ balance = Zold::Show.new(wallets: wallets).run(['show', id.to_s])
41
41
  assert_equal(Zold::Amount::ZERO, balance)
42
42
  end
43
43
  end
@@ -59,7 +59,7 @@ class TestTaxes < Minitest::Test
59
59
  )
60
60
  Zold::Taxes.new(
61
61
  wallets: wallets, remotes: remotes
62
- ).run(['pay', '--private-key=fixtures/id_rsa', id.to_s])
62
+ ).run(['taxes', '--private-key=fixtures/id_rsa', id.to_s])
63
63
  assert_equal(Zold::Amount.new(coins: 335_376_547), wallet.balance)
64
64
  end
65
65
  end
@@ -0,0 +1,8 @@
1
+ OPTS=-shell-escape -halt-on-error -interaction=errorstopmode -output-directory=.
2
+
3
+ wp.pdf: wp.tex
4
+ pdflatex ${OPTS} wp.tex
5
+
6
+ clean:
7
+ rm -rf wp.log wp.pdf wp.out wp.aux
8
+
data/wp/wp.tex CHANGED
@@ -1,37 +1,141 @@
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}
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
8
  \usepackage{setspace}
9
- \usepackage{indentfirst}
10
-
11
- \pagestyle{empty}
12
- \setlength{\topskip}{6pt}
13
- \setlength{\parindent}{0pt} % indent first line
14
- \setlength{\parskip}{0pt} % before par
15
- \interfootnotelinepenalty=10000
16
- \setstretch{1.1}
17
-
9
+ \usepackage{microtype}
18
10
  \usepackage{mathpazo} % Palantino font
19
-
11
+ \usepackage{minted}
12
+ \setminted{fontsize=\footnotesize}
13
+ \setminted{breaklines}
14
+ \usemintedstyle{bw}
20
15
  \usepackage{hyperref}
21
- \usepackage[style=authoryear,sorting=nyt,backend=biber,
22
- hyperref=true,abbreviate=true,
23
- maxcitenames=1,maxbibnames=1]{biblatex}
24
- \addbibresource{main.bib}
16
+ \pagestyle{empty}
17
+ \setstretch{1.2}
25
18
 
26
19
  \title{Zold, Lightweight Crypto Currency}
27
- \author{Yegor Bugayenko\\
28
- CEO of Zerocracy, Inc.\\
29
- 555 Bryant, Ste 470, Palo Alto, CA 94301\\
30
- \texttt{yegor@zerocracy.com}\\
31
- 408.692.4742}
32
- \begin{document}
20
+ \author{Yegor Bugayenko\\\texttt{yegor@zold.io}}
33
21
 
22
+ \begin{document}
34
23
  \raggedbottom
24
+ \maketitle
25
+ \begin{abstract}
26
+ Works for you?
27
+ \end{abstract}
28
+
29
+ \section{Motivation}
30
+
31
+ Bitcoin, the first decentralized digital currency, was released in
32
+ January 2009. Since then a number of similar Blockchain-based products have been
33
+ created, including Etherium, Litecoin, and others.
34
+
35
+ Zold is also a decentralized digital currency that maintains its transactions
36
+ in an unpredicable amount of zero-trust server nodes, trying to guarantee
37
+ data consistency. However, the architecture of Zold is not based on Blockchain
38
+ principles. The development of Zold was motivated by the desire to overcome
39
+ a few obvious disadvantages of existing solutions.
40
+
41
+ First, the speed of transaction processing is rather low.
42
+
43
+ Second, mining commissions are high.
44
+
45
+ Third, the technology is too complex.
46
+
47
+ Zold was created as an attempt to resolve these mentioned problems
48
+ of existing digital currencies.
49
+
50
+ \section{Principles}
51
+
52
+ \textbf{Open source}.
53
+ Zold is a command line tool. Its entire code base is open source.
54
+
55
+ \textbf{Capacity}.
56
+ One currency unit is called ZLD.
57
+ One ZLD by convention equals to $2^24$ (16,777,216) \emph{zents}.
58
+ All amounts are stored as signed 64-bit integers.
59
+ Thus, the technical capacity of the currency is 549,755,813,888 ZLD (half a trillion).
60
+
61
+ \textbf{Zero wallet}.
62
+ There is no mining, the only way to get ZLD is to receive it from someone else.
63
+ The wallet with the \texttt{0x00} ID belongs to the
64
+ issuer and may have a negative balance. All other wallets
65
+ may have only positive balances.
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.
75
+
76
+ \section{Proof of Work}
77
+
78
+ Each node calculates its own score.
79
+ First, it builds the initial text body, which consists of four parts,
80
+ separated by spaces:
81
+
82
+ \begin{itemize}
83
+ \item The current timestamp in UTC ISO 8601,
84
+ \item The host name or IP address, e.g. \texttf{b2.zold.io},
85
+ \item The TCP port number,
86
+ \item The invoice.
87
+ \end{itemize}
88
+
89
+ For example, the body may look like this:
90
+
91
+ \begin{minted}{text}
92
+ 2017-07-19T21:24:51Z b2.zold.io 4096 Yt0lOy6Rgf@0000000000000000
93
+ \end{minted}
94
+
95
+ Then, it attempts to append any
96
+ arbitrary text (has to match \texttt{[a-zA-Z0-9]+} regular expression)
97
+ to the end of it and to calculate SHA-256 of the text
98
+ in the hexadecimal format. For example, this would be the body
99
+ with \texttt{abcdef} suffix:
100
+
101
+ \begin{minted}{text}
102
+ 2017-07-19T21:24:51Z b2.zold.io 4096 Yt0lOy6Rgf@0000000000000000 abcdef
103
+ \end{minted}
104
+
105
+ The SHA-256 of this body will be:
106
+
107
+ \begin{minted}{text}
108
+ 2017-07-19T21:24:51Z b2.zold.io 4096 Yt0lOy6Rgf@0000000000000000 abcdef
109
+ \end{minted}
110
+
111
+ The node attempts to try different sufficies until one of them produces
112
+ SHA-256 hash that ends with \texttt{000000} (six zeros). For example, this
113
+ suffix \texttt{...} works
114
+ (it took about an hour to find it on 2.3GHz Intel Core i7):
115
+
116
+ When the first suffix is found, the score is 1. Then, to
117
+ increase the score by one, the next suffix has to be found, which
118
+ can be added to the first 64 characters of the previous hash
119
+ in order to obtain a new hash with trailing zeros, for example:
120
+
121
+ \begin{minted}{text}
122
+ 2017-07-19T21:24:51Z b2.zold.io 4096 Yt0lOy6Rgf@0000000000000000 abcdef abcdef
123
+ \end{minted}
124
+
125
+ And so on.
126
+
127
+ 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
129
+ is the amount of the trailing zeros in the hash. In the example above the
130
+ strength was equal to six.
131
+
132
+ \section{Wallets}
133
+
134
+ \section{Push}
135
+
136
+ \section{Fetch and Merge}
137
+
138
+ \section{Threats Analysis}
35
139
 
36
140
  how are you?
37
141
 
metadata CHANGED
@@ -1,7 +1,7 @@
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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -340,6 +340,7 @@ files:
340
340
  - test/test_wallets.rb
341
341
  - test/test_zold.rb
342
342
  - wp/.gitignore
343
+ - wp/Makefile
343
344
  - wp/wp.tex
344
345
  - zold.gemspec
345
346
  homepage: http://github.com/zerocracy/zold