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.