README.md in zold-0.0.8 vs README.md in zold-0.1
- old
+ new
@@ -1,49 +1,39 @@
<img src="http://www.zold.io/logo.svg" width="64px" height="64px"/>
-[![Managed by Zerocracy](http://www.0crat.com/badge/C91QJT4CF.svg)](http://www.0crat.com/p/C91QJT4CF)
+[![EO principles respected here](http://www.elegantobjects.org/badge.svg)](http://www.elegantobjects.org)
+[![Managed by Zerocracy](https://www.0crat.com/badge/C91QJT4CF.svg)](https://www.0crat.com/p/C91QJT4CF)
[![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/Zold)](http://www.rultor.com/p/yegor256/Zold)
-[![We recommend RubyMine](http://img.teamed.io/rubymine-recommend.svg)](https://www.jetbrains.com/ruby/)
+[![We recommend RubyMine](http://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
[![Build Status](https://travis-ci.org/zerocracy/zold.svg)](https://travis-ci.org/zerocracy/zold)
-[![Build status](https://ci.appveyor.com/api/projects/status/orvfo2qgmd1d7a2i?svg=true)](https://ci.appveyor.com/project/zerocracy/zold)
+[![Build status](https://ci.appveyor.com/api/projects/status/ypctxm5ohrtp2kr4?svg=true)](https://ci.appveyor.com/project/yegor256/zold)
[![PDD status](http://www.0pdd.com/svg?name=zerocracy/zold)](http://www.0pdd.com/p?name=zerocracy/zold)
[![Gem Version](https://badge.fury.io/rb/zold.svg)](http://badge.fury.io/rb/zold)
[![Test Coverage](https://img.shields.io/codecov/c/github/zerocracy/zold.svg)](https://codecov.io/github/zerocracy/zold?branch=master)
[![Dependency Status](https://gemnasium.com/zerocracy/zold.svg)](https://gemnasium.com/zerocracy/zold)
[![Maintainability](https://api.codeclimate.com/v1/badges/7489c1d2bacde40ffc09/maintainability)](https://codeclimate.com/github/zerocracy/zold/maintainability)
**NOTICE**: It's an experiment and a very early draft! Please, feel free to
submit your ideas or pull requests.
-ZOLD is a crypto currency.
-
-ZOLD is going to solve these problems:
-
- * Blockchain is slow and [doesn't scale](https://en.wikipedia.org/wiki/Bitcoin_scalability_problem)
- * Crypto mining makes irrelevant strangers rich
- * High volatility makes cryptos suitable mostly for the black market
-
-ZOLD is:
-
- * Fast
- * Scalable
- * Anonymous
-
ZOLD principles include:
- * The entire code base is open source
- * There is no mining; the only way to get ZOLD is to receive it from someone else
- * Only 2<sup>63</sup> numerals (no fractions) can technically be issued
- * The first wallet belongs to the issuer and may have a negative balance
- * A wallet is an plain text file
- * There is no central ledger, each wallet has its own personal ledger
- * Each transaction in the ledger is confirmed by [RSA](https://simple.wikipedia.org/wiki/RSA_%28algorithm%29) encryption
- * The network of communicating nodes maintains wallets of users
- * Anyone can add a node to the network
+ * The entire code base is open source;
+ * There is no mining, the only way to get ZOLD is to receive it from someone else;
+ * Only 2<sup>63</sup> numerals (no fractions) can technically be issued;
+ * The first wallet belongs to the issuer and may have a negative balance;
+ * A wallet is a plain text file;
+ * There is no central ledger, each wallet has its own personal ledger;
+ * Each transaction in the ledger is confirmed by [RSA](https://simple.wikipedia.org/wiki/RSA_%28algorithm%29) encryption;
+ * The network of communicating nodes maintains wallets of users;
+ * Anyone can add a node to the network.
+1 ZLD by convention equals to 2<sup>24</sup> (16,777,216) _zents_.
+Thus, the technical capacity of the currency is 549,755,813,888 ZLD (half a trillion).
+
## How to Use
Install Ruby 2.2+, [Rubygems](https://rubygems.org/pages/download), and then run:
```bash
@@ -56,124 +46,241 @@
$ zold start
```
Or do one of the following:
- * `zold init` creates a new wallet (you have to provide PGP keys)
- * `zold pull` pulls a wallet from the network
- * `zold balance` checks the balance of a wallet
- * `zold send` creates a new transaction
- * `zold push` pushes a wallet to the network
+ * `zold remote` manipulates the list off remote nodes;
+ * `zold create` creates a new wallet (you have to provide PGP keys);
+ * `zold fetch` downloads all copies of the wallet from the network;
+ * `zold merge` merges all copies of the wallet into the local one;
+ * `zold pull` first `fetch`, then `merge`;
+ * `zold show` prints out all known details of a wallet (incl. its balance);
+ * `zold pay` creates a new transaction;
+ * `zold push` pushes a wallet to the network.
For more options and commands just run:
```bash
$ zold --help
```
## Glossary
-A **node** is an HTTP server with a RESTful API, a maintainer of wallets.
+**Node** is an HTTP server with a RESTful API, a maintainer of wallets
+and a command line Ruby gem [`zold`](https://rubygems.org/gems/zold).
-A **client** is a command line Ruby gem [`zold`](https://rubygems.org/gems/zold).
+**Network** is a set of all nodes available online.
-A **wallet** is an XML file with a ledger of all transactions inside.
+**Score** is the amount of "hash sufficies" a node has at any given moment of time.
-A **transaction** is a money transferring operation between two wallets.
+**Wallet** is a text file with a ledger of all transactions inside.
-## Data
+**Transaction** is a money transferring operation between two wallets.
-A wallet may look like this:
+**MSS** (minimum summary score) is a summary of all scores required to trust a wallet.
+## Score
+
+Each node calculates its own score. First, it takes the current timestamp
+in UTC [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601),
+for example `2017-07-19T21:24:51Z ` (with a trailing space). Then, it appends
+its own host name or IP address to it, space, TCP port number, and a space.
+Then, it attempts to append any
+arbitrary text (has to match `[a-zA-Z0-9]+`) to the end of it and to calculate SHA-256 of the text
+in the hexadecimal format, for example:
+
+```
+Input: "2017-07-19T21:24:51Z b1.zold.io 80 the-suffix"
+SHA-256: "eba36e52e1ee674d198f486e07c8496853ffc8879e7fe25329523177646a96a0"
+```
+
+The node attempts to try different sufficies until one of them produces
+SHA-256 hash that ends with `00000000` (eight zeros). For example, this
+suffix `11edb424c` works (it took 212 minutes to find it on 2.3GHz Intel Core i7):
+
+```
+Input: "2017-07-19T21:24:51Z b1.zold.io 80 11edb424c"
+SHA-256: "34f48e0eee1ed12ad74cb39418f2f6e7442a776a7b6182697957650e00000000"
+```
+
+When the first suffix is found, the score of the node is 1. Then, to
+increase the score by one, the node has to find the next suffix, which
+can be added to the first 20 characters of the previous hash
+in order to obtain a new hash with trailing zeros, for example:
+
+```
+Input: "34f48e0eee1ed12ad74c "
+SHA-256: "..."
+```
+
+And so on.
+
+The score is valid only when the starting time point is earlier than
+current time, but not earlier than 24 hours ago.
+
+## Operations
+
+### Remote
+
+Each node maintains a list of visible "remote" nodes.
+The gem is shipped together with a hard-coded list of a few of them.
+
+ * `remote update` goes through the list of all remote nodes,
+ checks their availability, and either removes them from the list or
+ adds new nodes to the list.
+
+ * `remote add <IP>` adds a new remote node to the list.
+
+ * `remote remove <IP>` removes a remote node.
+
+ * `remote show` prints the entire list of remote nodes.
+
+The node always tries to make sure the summary of all scores in the
+list of remote nodes is right above the MSS, but not more.
+
+### Fetch
+
+The node attempts to pull the wallet from the first remote.
+The remote returns the wallet, if it exists. Otherwise, rejects the request
+and returns the list of all remotes known to it.
+
+The node stores the content of the wallet and the score of the remote
+to the local storage.
+The local storage doesn't keep all remote copies, but only their unique
+versions and summary scores for each version.
+
+Fetching stops when:
+
+ * Total score is above MSS _or_
+ * There is only one version and the total score is above ½ MSS.
+
+If not, the node attempts the next remote in the list.
+
+### Merge
+
+The remote copy is accepted "as is" without verifications if:
+
+ * All remote copies are identical _and_
+ * Their summary score is above the MSS.
+
+Otherwise, the node goes through the entire list of transactions visible in all
+remote copies and merges them one by one into the "head" copy.
+The decision is made per each transaction.
+
+If a transaction exists in the head, it remains there.
+
+Otherwise, if it's a positive transaction that increases the balance of the head copy,
+the signature is validated (in the paying wallet, which is pulled first)
+and it goes into the head. The transaction gets a new ID.
+
+If it's a negative transaction, the decision is made between all copies.
+The one with the largest score goes first, if the balance of the wallet
+is big enough. Then, the next one in the line and so on. The transactions
+that negate the balance are rejected.
+
+### Pay
+
+The node pulls both wallets. Then, say, the user makes a payment
+from the wallet `0123456789abcdef` to the wallet `4567456745674567`:
+
+```bash
+zold send 0123456789abcdef 4567456745674567 5
+```
+
+The content of both files get changed. An outgoing transaction with a negative
+amount gets added to the end of the paying wallet `0123456789abcdef`:
+
```text
-12345678abcdef
-AAAAB3NzaC1yc2EAAAADAQABAAABAQCuLuVr4Tl2sXoN5Zb7b6SKMPrVjLxb...
+500;2017-07-19T22:18:43Z;-83886080;4567456745674567;-;b6SKMPrVjLx...
+```
-35;2017-07-19T21:24:51.136Z;98bb82c81735c4ee;-560;SKMPrVjLxbM5oDm0IhniQQy3shF...
+The incoming transaction gets appended to the end of the receiving wallet
+`4567456745674567`:
+
+```text
+500;2017-07-19T22:18:43Z;83886080;0123456789abcdef;-
```
-Lines are separated by either CR or CRLF, doesn't matter.
+### Push
-The fist line is wallet ID, a 64-bit unsigned integer.
+The node sends a package of a few wallets to the biggest remote available
+(with the highest score).
+The package must also include a fee to the wallet that belongs to the
+remote.
-The second line is a public RSA key of the wallet owner.
+The remote stores them as remote copies and performs _pull_.
-The third line is empty.
+The remote sends "pull requests" to all available nodes.
+They must pull from the node for free, if their scores are lower or equal
+to the score of the node.
-Each next line is a transaction and it has four or five fields separated by a semi-colon.
+## RESTful API
-The first field is transaction ID, an unsigned 16-bit integer.
+The full list of RESTful resources:
-The second field is its date, in ISO 8601 format.
+ * `/` (GET): status page of the node, in JSON
-The third field is the wallet ID of the beneficiary.
+ * `/remotes` (GET): load all known remotes in JSON
-The forth field is the amount.
+ * `/wallet/<ID>` (GET): fetch wallet in JSON
-The fifth field is an RSA signature of "ID;beneficiary;amount" text.
+ * `/wallet/<ID>` (PUT): push wallet
-1ZLD by convention equals to 2<sup>24</sup> (16,777,216).
-Thus, the technical capacity of the currency is
-549,755,813,888 (half a trillion).
+Each HTTP response contains `Content-type` header.
-## Architecture
+## Files
-**Pull**.
-The client connects to a random closest node and pulls a wallet. If the node
-doesn't have the wallet, it tries to find it in the network.
-Then, it calculates and prints the balance to the user.
+Each wallet is a text file with the name equal to the wallet ID, for example:
-**Commit**.
-The user provides the amount and the destination wallet name.
-The client pulls the destination wallet and adds
-a new XML element `<txn/>` to both wallets.
+```text
+12345678abcdef
+AAAAB3NzaC1yc2EAAAADAQABAAABAQCuLuVr4Tl2sXoN5Zb7b6SKMPrVjLxb...
-**Push**.
-The client sends two wallets to a random closest node, which checks
-the validity of the deduction and propagates
-both wallets to _all_ other nodes in a [2PC](https://en.wikipedia.org/wiki/Two-phase_commit_protocol)
-manner: acknowledgment first, commit next.
-If a node receives a wallet that contains transactions that are younger
-than transactions in its local copy, a merge operation is
-performed. If the balance after the merge is negative, the push is rejected.
+34;2017-07-19T21:24:51Z;-560700;98bb82c81735c4ee;for services;SKMPrVjLxbM5oDm0IhniQQy3shF...
+35;2017-07-19T21:25:07Z;-56990;98bb82c81735c4ee;;QCuLuVr4Tl2sXoN5Zb7b6SKMPrVjLxb...
+134;2017-07-19T21:29:11Z;647388;18bb82dd1735b6e9;;
+36;2017-07-19T22:18:43Z;-884733;38ab8fc8e735c4fc;for fun;2sXoN5Zb7b6SKMPrVjLxb7b6SKMPrVjLx...
+```
-**Init**.
-The client creates an empty wallet XML and assigns a random `id` for it.
+Lines are separated by either CR or CRLF, doesn't matter. There is a
+header and a ledger, separated by an empty line.
+The header includes two lines:
-**Start**.
-The node manifests itself to one of the backbone nodes, which
-propagates the manifestation to other nodes, they propagate further.
-When any node goes down, the node that detected such a situation,
-notifies other nodes and they exlude the failed node from the list.
+ * Wallet ID, a 64-bit unsigned integer;
+ * Public RSA key of the wallet owner.
-## Corner Cases
+The ledger includes transactions, one per line. Each transaction line
+contains fields separated by a semi-colon:
-**Too long wallet**.
-If a wallet has too many transactions, its validation will take too long, since
-will require many cross-wallet checks. How to solve this?
+ * Transaction ID, an unsigned 16-bit integer;
+ * Date and time, in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601);
+ * Amount (integer);
+ * Wallet ID of the beneficiary;
+ * Details: `/[a-zA-Z0-9 -.]{1,128}/`;
+ * RSA signature of the sender of "ID;amount;beneficiary;details" text.
-**DDoS**.
-We may have too many simultaneous `push` operations to the network,
-which may/will cause troubles. What to do?
+Transactions with positive amount don't
+have RSA signatures. Their IDs point to ID fields of corresponding
+beneficiaries' wallets.
-## License (MIT)
+The combination "ID+Beneficiary" is unique in the entire wallet.
-Copyright (c) 2018 Zerocracy, Inc.
+The directory `.zold` is automatically created and contains system data.
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the 'Software'), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+`.zold/remotes` is a comma-separated file with a list of remote nodes with
+these columns:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+ * Address or IP;
+ * TPC port (usually 80);
+ * Score (positive integer);
+ * Time of score update, ISO 8601.
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+`.zold/copies` is a directory of directories, named after wallet IDs,
+each of which contains copies of wallets, named like `1`, `2`, `3`, etc. Also,
+each sub-directory contains a comma-separated file `scores` with these columns:
+
+ * The name of the copy, e.g. `1`;
+ * The address of the remote (host name or IP);
+ * The TCP port number of the remote;
+ * The score (positive integer);
+ * The time of fetching, in ISO 8601.