zold 0.29.27 → 0.29.28
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODE_OF_CONDUCT.md +76 -0
- data/.github/CONTRIBUTING.md +11 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.rubocop.yml +6 -2
- data/README.md +107 -6
- data/fixtures/merge/legacy_negatives_stay/copies/0123456789abcdef/scores.zc +1 -1
- data/fixtures/merge/negative_overwriting/0123456789abcdef.z +6 -0
- data/fixtures/merge/negative_overwriting/146b852f2d9ad984.z +6 -0
- data/fixtures/merge/negative_overwriting/assert.rb +25 -0
- data/fixtures/merge/negative_overwriting/copies/0123456789abcdef/1.zc +6 -0
- data/fixtures/merge/negative_overwriting/copies/0123456789abcdef/scores.zc +1 -0
- data/fixtures/merge/negative_overwriting/opts +2 -0
- data/lib/zold/commands/fetch.rb +1 -1
- data/lib/zold/commands/merge.rb +6 -6
- data/lib/zold/commands/node.rb +4 -0
- data/lib/zold/commands/pay.rb +1 -0
- data/lib/zold/commands/push.rb +5 -1
- data/lib/zold/commands/remote.rb +7 -3
- data/lib/zold/commands/routines/reconcile.rb +7 -2
- data/lib/zold/commands/routines/reconnect.rb +20 -5
- data/lib/zold/commands/routines/retire.rb +48 -0
- data/lib/zold/gem.rb +1 -1
- data/lib/zold/node/farm.rb +1 -1
- data/lib/zold/node/farmers.rb +1 -1
- data/lib/zold/node/front.rb +1 -0
- data/lib/zold/patch.rb +10 -2
- data/lib/zold/remotes.rb +10 -4
- data/lib/zold/version.rb +1 -1
- data/test/commands/routines/test_reconnect.rb +2 -1
- data/test/commands/routines/test_retire.rb +40 -0
- data/test/commands/test_node.rb +1 -1
- data/test/commands/test_pay.rb +2 -1
- data/test/node/test_front.rb +1 -0
- data/zold.gemspec +13 -13
- metadata +42 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fc5f47657b08c4e98a026b0b71def6da39a322e3f24666614a4f35d7f4580aa
|
4
|
+
data.tar.gz: da6bac2fdec7446e025e96ba6df2ada4a41122152eabf1f3748a0c80628d4fec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5c081dd571630428327bc2ae02ff0a47bab44e4d288f6ca6bfe9852cad9dd1c5300183f8c00b26de7e167af62281dcb3fc1c38691e1f656e02a3405d54fac44
|
7
|
+
data.tar.gz: 787d7d4d98ff67a4b26297ed3e1a3ec7dd5993e012585f2ac4755e5c69543cfb70f328497801cedb100576b3f1d70fb6ef13e71564c88d766ecb54659662d63d
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
9
|
+
level of experience, education, socio-economic status, nationality, personal
|
10
|
+
appearance, race, religion, or sexual identity and orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at github@zold.io. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
72
|
+
|
73
|
+
[homepage]: https://www.contributor-covenant.org
|
74
|
+
|
75
|
+
For answers to common questions about this code of conduct, see
|
76
|
+
https://www.contributor-covenant.org/faq
|
@@ -0,0 +1,38 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Describe the bug**
|
11
|
+
A clear and concise description of what the bug is.
|
12
|
+
|
13
|
+
**To Reproduce**
|
14
|
+
Steps to reproduce the behavior:
|
15
|
+
1. Go to '...'
|
16
|
+
2. Click on '....'
|
17
|
+
3. Scroll down to '....'
|
18
|
+
4. See error
|
19
|
+
|
20
|
+
**Expected behavior**
|
21
|
+
A clear and concise description of what you expected to happen.
|
22
|
+
|
23
|
+
**Screenshots**
|
24
|
+
If applicable, add screenshots to help explain your problem.
|
25
|
+
|
26
|
+
**Desktop (please complete the following information):**
|
27
|
+
- OS: [e.g. iOS]
|
28
|
+
- Browser [e.g. chrome, safari]
|
29
|
+
- Version [e.g. 22]
|
30
|
+
|
31
|
+
**Smartphone (please complete the following information):**
|
32
|
+
- Device: [e.g. iPhone6]
|
33
|
+
- OS: [e.g. iOS8.1]
|
34
|
+
- Browser [e.g. stock browser, safari]
|
35
|
+
- Version [e.g. 22]
|
36
|
+
|
37
|
+
**Additional context**
|
38
|
+
Add any other context about the problem here.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
name: Feature request
|
3
|
+
about: Suggest an idea for this project
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Is your feature request related to a problem? Please describe.**
|
11
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
12
|
+
|
13
|
+
**Describe the solution you'd like**
|
14
|
+
A clear and concise description of what you want to happen.
|
15
|
+
|
16
|
+
**Describe alternatives you've considered**
|
17
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
18
|
+
|
19
|
+
**Additional context**
|
20
|
+
Add any other context or screenshots about the feature request here.
|
data/.rubocop.yml
CHANGED
@@ -5,12 +5,16 @@ AllCops:
|
|
5
5
|
DisplayCopNames: true
|
6
6
|
TargetRubyVersion: 2.5
|
7
7
|
|
8
|
+
Lint/ToJSON:
|
9
|
+
Enabled: false
|
10
|
+
Layout/AlignArguments:
|
11
|
+
Enabled: false
|
8
12
|
Style/ClassAndModuleChildren:
|
9
13
|
Enabled: false
|
10
14
|
Layout/EmptyLineAfterGuardClause:
|
11
15
|
Enabled: false
|
12
16
|
Metrics/CyclomaticComplexity:
|
13
|
-
Max:
|
17
|
+
Max: 33
|
14
18
|
Metrics/MethodLength:
|
15
19
|
Enabled: false
|
16
20
|
Layout/MultilineMethodCallIndentation:
|
@@ -30,7 +34,7 @@ Metrics/ParameterLists:
|
|
30
34
|
Layout/AlignParameters:
|
31
35
|
Enabled: false
|
32
36
|
Metrics/PerceivedComplexity:
|
33
|
-
Max:
|
37
|
+
Max: 36
|
34
38
|
Metrics/LineLength:
|
35
39
|
Max: 120
|
36
40
|
Style/MultilineBlockChain:
|
data/README.md
CHANGED
@@ -15,20 +15,39 @@
|
|
15
15
|
|
16
16
|
[![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/zold-io/zold/master/frames)
|
17
17
|
[![Maintainability](https://api.codeclimate.com/v1/badges/2861728929db934eb376/maintainability)](https://codeclimate.com/github/zold-io/zold/maintainability)
|
18
|
+
[![Hits-of-Code](https://hitsofcode.com/github/zold-io/zold)](https://hitsofcode.com/github/zold-io/zold)
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
To understand what Zold cryptocurrency is about you may want
|
21
|
+
to watch [this video](https://youtu.be/5A9uBwMow0M) first. Then, you may
|
22
|
+
want to read [this blog](https://blog.zold.io/2018/07/08/mission.html) post.
|
23
|
+
Then, you have to read the [Green Paper](https://papers.zold.io/green-paper.pdf)
|
24
|
+
(just four pages). In a nutshell, Zold is a cryptocurrency with the following
|
25
|
+
features:
|
21
26
|
|
22
|
-
|
27
|
+
* No Blockchain
|
28
|
+
* No General Ledger
|
29
|
+
* Very fast, because de-centralized
|
30
|
+
* 100 times cheaper than Bitcoin
|
31
|
+
* Proof-of-work
|
32
|
+
* Unique consensus protocol
|
33
|
+
* Pre-mined with total capacity of 2 billion ZLD
|
34
|
+
* Anonymous
|
35
|
+
* Written in Ruby
|
36
|
+
|
37
|
+
More details you can find in the [White Paper](https://papers.zold.io/wp.pdf).
|
38
|
+
|
39
|
+
You can also find us at the [Bitcointalk](https://bitcointalk.org/index.php?topic=5095078) forum.
|
23
40
|
|
24
41
|
Join our [Telegram group](https://t.me/zold_io) to discuss it all live.
|
25
42
|
|
26
43
|
The license is [MIT](https://github.com/zold-io/zold/blob/master/LICENSE.txt).
|
27
44
|
|
28
|
-
The web wallet is here: [wts.zold.io](https://wts.zold.io).
|
29
|
-
|
30
45
|
## How to Use
|
31
46
|
|
47
|
+
You can try the web wallet [here](https://wts.zold.io), but the best way
|
48
|
+
to use Zold is through the command line tool, which has all the features
|
49
|
+
and should remind you Git, if you are a programmer.
|
50
|
+
|
32
51
|
First, install [Ruby 2.3+](https://www.ruby-lang.org/en/documentation/installation/),
|
33
52
|
[Rubygems](https://rubygems.org/pages/download), and
|
34
53
|
the [gem](https://rubygems.org/gems/zold).
|
@@ -190,7 +209,7 @@ Yes, you can run many nodes with the same wallet ID.
|
|
190
209
|
Yes, you can use `--threads` command line argument for your node
|
191
210
|
and the number of threads will be as big as you wish.
|
192
211
|
|
193
|
-
## JSON Details
|
212
|
+
## Front-end JSON Details
|
194
213
|
|
195
214
|
When you open up the front web page of your node, you will see a JSON document
|
196
215
|
with a lot of technical details. Here is the explanation of the majority of them:
|
@@ -271,6 +290,88 @@ To be continued...
|
|
271
290
|
|
272
291
|
`hours_alive` is the time in hours your server is alive without a reboot.
|
273
292
|
|
293
|
+
## HTTP RESTful API
|
294
|
+
|
295
|
+
Well, maybe it's not purely RESTful, but each node has a simple
|
296
|
+
set of HTTP entry points, which you can use to retrieve information
|
297
|
+
about wallets, node status, log details, and some other things. Here
|
298
|
+
is a more or less complete list of them:
|
299
|
+
|
300
|
+
* `GET /`: returns the JSON explained above
|
301
|
+
|
302
|
+
* `GET /score`: returns the text presentation of the current Score
|
303
|
+
|
304
|
+
* `GET /version`: returns the version of the software
|
305
|
+
|
306
|
+
* `GET /protocol`: returns the protocol ID
|
307
|
+
|
308
|
+
* `GET /wallet/ID`: returns the JSON with wallet details
|
309
|
+
|
310
|
+
* `GET /wallet/ID/balance`: returns wallet balance in zents (text/plain)
|
311
|
+
|
312
|
+
* `GET /wallet/ID/key`: returns wallet public RSA key
|
313
|
+
|
314
|
+
* `GET /wallet/ID/mtime`: returns ISO-8601 time of wallet file modification
|
315
|
+
|
316
|
+
* `GET /wallet/ID/size`: returns the size of the wallet file in bytes
|
317
|
+
|
318
|
+
* `GET /wallet/ID/age`: returns the age of the wallet, in seconds
|
319
|
+
|
320
|
+
* `GET /wallet/ID/txns`: returns the amount of transactions in the wallet
|
321
|
+
|
322
|
+
* `GET /wallet/ID/debt`: returns the tax debt of the wallet in zents
|
323
|
+
|
324
|
+
* `GET /wallet/ID/digest`: returns SHA-256 digest of the wallet file
|
325
|
+
|
326
|
+
* `GET /wallet/ID/mnemo`: returns the mnemo short string of the wallet
|
327
|
+
|
328
|
+
* `GET /wallet/ID/txns.json`: returns the full list of transactions in the wallet in JSON document
|
329
|
+
|
330
|
+
* `GET /wallet/ID.txt`: returns the text presentation of the wallet
|
331
|
+
|
332
|
+
* `GET /wallet/ID.html`: returns the HTML presentation of the wallet
|
333
|
+
|
334
|
+
* `GET /wallet/ID.bin`: returns the entire wallet file
|
335
|
+
|
336
|
+
* `GET /wallet/ID/copies`: returns the list of copies of the wallet
|
337
|
+
|
338
|
+
* `GET /wallet/ID/copy/NAME`: returns the entire content of a single copy of the wallet
|
339
|
+
|
340
|
+
* `PUT /wallet/ID`: accepts a new content of the wallet, in order to
|
341
|
+
modify the one stored on the server (PUSH operation)
|
342
|
+
|
343
|
+
* `GET /wallets`: returns the list of all wallets maintained by the node,
|
344
|
+
in plain text, separated by EOL
|
345
|
+
|
346
|
+
* `GET /remotes`: returns the list of remote nodes in JSON
|
347
|
+
|
348
|
+
* `GET /ledger`: returns the list of recently visible transactions
|
349
|
+
|
350
|
+
* `GET /ledger.json`: returns the list of recently visible transactions, in JSON
|
351
|
+
|
352
|
+
There are a few other entry points, which exist most for debugging purposes,
|
353
|
+
they may not be supported by alternative implementations of the node software:
|
354
|
+
|
355
|
+
* `GET /pid`: returns the process ID of the software
|
356
|
+
|
357
|
+
* `GET /trace`: returns the entire log of the node
|
358
|
+
|
359
|
+
* `GET /farm`: returns the statistics of the Farm
|
360
|
+
|
361
|
+
* `GET /metronome`: returns the statistics of the Metronome
|
362
|
+
|
363
|
+
* `GET /threads`: returns the statistics of all Ruby threads
|
364
|
+
|
365
|
+
* `GET /ps`: returns the statistics of all currently running Unix processes
|
366
|
+
|
367
|
+
* `GET /queue`: returns the statistics of the node queue
|
368
|
+
|
369
|
+
* `GET /journal`: returns the journal, in HTML
|
370
|
+
|
371
|
+
* `GET /journal/item?id=ID`: returns the content of a single journal entry
|
372
|
+
|
373
|
+
There could be other entry points, not documented here.
|
374
|
+
|
274
375
|
## SDK
|
275
376
|
|
276
377
|
Here is how you use Zold SDK from your Ruby app. First, you should
|
@@ -1 +1 @@
|
|
1
|
-
1,0.0.0.0,4096,10,NOW,
|
1
|
+
1,0.0.0.0,4096,10,NOW,
|
@@ -0,0 +1,6 @@
|
|
1
|
+
test
|
2
|
+
2
|
3
|
+
0123456789abcdef
|
4
|
+
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnppnkzrCreiKaHF09XKS6bO+2274+wSGo+F8KHvVrNbqear/e09r9PB/P6bFdLoMh4Xc7p/7+NSEZLeu2Eg/dBkQLEb8M/zgkT4gBDGyETW/zusYHIznX/lgf0f8qleIQIIB/3Y7QpDztkamWYTKWlnmlrcQvCVB0uRRPm4ZMcMJouKR9n7E2DpL9eolKyOwr/JY08iJOuK3HuW6tRdvE+0x7I+wDprM65OH/PoArlfO5qnIGbeXwsEGRXt0w6a/ubPpeadFjPXotE7cT1SA4YSD1tWTIVm1ZWppOE967XoDIum6tzt5KfzDNRfs9GbCfO0BL235HxbO8I9rTlVLTKcNAiEe0CWolY9HR5pMaosOgZ6PB54InJEZJs4L2b10c+IlVUX1RSnwfFYg0vy5oqrYyqt7gnipl/06YW4PKIYc7TljogsEHf9Cz/kpEKzqDtsH2LrmjMNsbWiousvNHM+MPgcuMg8ZnwLKwDy9NWdI4XLTpg6hVRJNH9erZdfAO5tg/3ub3JLeJbyNo4Bd5f/Bnr5YN/9ahZ87kSpI7v0Qk94dR4hDPjstEcghyZ9RVUoN52+h1g83cd3cIqksJd0kifMCoBmObD013RSPQqNwr9GGU2JaJEm25Vq35dy2DHAkOQpUZVT8GNg9IM4qUDV0yagTN3bZyvuLWIgufb0CAwEAAQ==
|
5
|
+
|
6
|
+
0001;2018-01-01T01:01:01Z;ffffffe000000000;qJkKMWUC;146b852f2d9ad984;test;j9ozyBTjJ90TK1u3o4m6ueLWspbXCgEWhLYNQ8B9EonQ9bIsl19DbdsPwyY5M3o8dSefDOwsA9OE48x9ncyh3n/BSYKSUHzSrU1RmVLR2+hveEzwGKPZleUzurDbKZA06MuuP46KDv3uhJ9OjX6szVwBqHorxoJ0zyqRtRdjKop7gqTVbyIIGOM5fu4lx3KhdWJLzD0sN75rdCmuF2yw/V2D+AdkB+84C+rTjp4x9bUr5zIinQtAYn8AJbdpk/3CLHWR/RhqFdUmQrQlgLile016bfkKg8l2S7HufrKdGNVThuoOrpTKZV+prctV2f8/2XANrHoVrtT5y3aENXfvlvYMQYqJsOl8wvLtQEts4pwtQBOdKUC4i82aZW/3lkQr9T8JPoyIthmm8AoOAx6RU0ccDckarDYAg1t5nYA/wK+fBDFkwIwUoI6zkvmwpUCI6/Wf9smF69H+FQNi8OrH0MaO0nzh7zFxgpFKaJAGumEvGPtA7rY3zYZ0P4lK9QnIa887p8WgA7YCN9/WieY71DINfMjVRwC7kxCa7LqNtOlXyp2pMJzWGWGbZH/SF6HpeIMbq7J0yUrdyLz8OwgLk5Wzuv/mht+mvhbI54mZixs4MawAXs9kTPmqGIRpMFvqLmD6GtKEltKuHGnAs4QSFjMmWbGG0WS98TztzFMpLG0=
|
@@ -0,0 +1,6 @@
|
|
1
|
+
test
|
2
|
+
2
|
3
|
+
146b852f2d9ad984
|
4
|
+
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyevqT0h4CcDkA4jeC+u0ITqULIyKD4HlUTyoOl8QK6BqDZ5oc4jCIGHgVfwdRVhKdUukWb7AUIVPVf76qepNZLwQ8UGtEwk+nCfq0/4u4zlCr78ZMmpIbdme5a6rXjiB3TE8UVgTPROx5EecazKXcvgmqfl7o98QBkqSKVqvIHzED5wADQzxjmGMmLWP8aTs0/6v4NG7wXJnMEJ0QYf845HMjpiXlNgldU1M1gTCM/8RJJaGjbEOax8HWj4n7LnqPHL5wtSe0CI6BzQsm9lEHUyywMW+SleCc5yponz5ZPzVkMYIzvO36BqykeZ0AXJyE5JfMoljJXG5bJX4tMhvIDVlZDlDh07vd11x3qJEtKB0c/hYcUmrUMAr0jZXBjv+MVq3WMVMClrMDyc1LMmrGh7Jp4hyugYRmrRAiTiZvmd2MaVB16sU91aiDHo90MefQ+RTwGO0YDNDzW1jW0qEYlfXZQGALWDWnyP1h1qzu4SaWrp4Chnt5OmwV67gxUw/VKQekTaiN7/ApeB5wXakrZiuIITi39865qqkkjDWVrRneqF0YDZz1S7eOIZ3OJvCi5OMU1nTTxaycVofolVmfGZlWROS9ENj2gVk9RQLX9xBXC1Vk4C/U7bIPDhk+nMHaDriuTNlmRPwMa6Flj1A9cLDUFPu7F0rDv3iqJkKMWUCAwEAAQ==
|
5
|
+
|
6
|
+
0001;2019-05-14T14:34:56Z;0000001000000000;v4NG7wXJ;0123456789abcdef;test;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2019 Zerocracy, Inc.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require_relative 'asserts'
|
24
|
+
wallet = Zold::Wallet.new('0123456789abcdef.z')
|
25
|
+
assert_equal(Zold::Amount.new(zld: -16.0), wallet.balance)
|
@@ -0,0 +1,6 @@
|
|
1
|
+
test
|
2
|
+
1
|
3
|
+
0123456789abcdef
|
4
|
+
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnppnkzrCreiKaHF09XKS6bO+2274+wSGo+F8KHvVrNbqear/e09r9PB/P6bFdLoMh4Xc7p/7+NSEZLeu2Eg/dBkQLEb8M/zgkT4gBDGyETW/zusYHIznX/lgf0f8qleIQIIB/3Y7QpDztkamWYTKWlnmlrcQvCVB0uRRPm4ZMcMJouKR9n7E2DpL9eolKyOwr/JY08iJOuK3HuW6tRdvE+0x7I+wDprM65OH/PoArlfO5qnIGbeXwsEGRXt0w6a/ubPpeadFjPXotE7cT1SA4YSD1tWTIVm1ZWppOE967XoDIum6tzt5KfzDNRfs9GbCfO0BL235HxbO8I9rTlVLTKcNAiEe0CWolY9HR5pMaosOgZ6PB54InJEZJs4L2b10c+IlVUX1RSnwfFYg0vy5oqrYyqt7gnipl/06YW4PKIYc7TljogsEHf9Cz/kpEKzqDtsH2LrmjMNsbWiousvNHM+MPgcuMg8ZnwLKwDy9NWdI4XLTpg6hVRJNH9erZdfAO5tg/3ub3JLeJbyNo4Bd5f/Bnr5YN/9ahZ87kSpI7v0Qk94dR4hDPjstEcghyZ9RVUoN52+h1g83cd3cIqksJd0kifMCoBmObD013RSPQqNwr9GGU2JaJEm25Vq35dy2DHAkOQpUZVT8GNg9IM4qUDV0yagTN3bZyvuLWIgufb0CAwEAAQ==
|
5
|
+
|
6
|
+
0001;2019-05-14T14:34:56Z;fffffff000000000;v4NG7wXJ;146b852f2d9ad984;test;NSOdJUTYidOne3T0VranU9H8Lb4weJQ1KYhMu7MfFTIiUWXc56O4c/cRIikjQ+EFsneFtYBEHs0TH2oevndGyrHcHkBkmsMRWD0ujYFD27oWEuOX828dYM/vjn7q1ggb9XTJN3kEKnrP8zbfVzJotsh2I9ctNByGoy33ecGfYtv7pFfcUItjd6SbYmGGOCt/Jf4/I5p+pgW2xGjG75jRMQ1Gh40aWGHfOxi38HyUqSr9pcymerbUaEKpFrk8+CJ3LbCUN9Ve2WYIwIZd9POpN2PH+aF+syzEv2Yj7LDTfkLQHLzIJJqtCJvSXeqKgVKQLmtkjgHDX6aTyb8w7+NJ2Mkjq6mREny8qbJnwLi+d7Pl+fFCArP3kFBULKQDzqe7sA8+xew6Dq8kVZWoBtuPFusMhBu7rq573waOcj6ZiW7tKww0abTGe96KUNssMhyF4alHvXQ0b7orK6l2DOBV/JDlgP5mEu2mOJ8Y81peCMNa1m8Y+AgrGijrm5aqk0JHjGH2hVRrHPZcyyO+msoLe7vP5umpf4DuMBMPgGZQc5Sqpc8wuSgD+XaiSVKv1Nr/gQYp2oZbGXnGl47reCvy1lJr2kBzLIWIPdrZIGh7iVy/DFcvw+t7wvoOm1fEfVfDgl04yHwNOiUOLKNlfGFliWJoCJ+sJv5DztHpDEKLBv4=
|
@@ -0,0 +1 @@
|
|
1
|
+
1,0.0.0.0,4096,50,NOW,M
|
data/lib/zold/commands/fetch.rb
CHANGED
@@ -138,7 +138,7 @@ run 'zold remote update' or use --tolerate-quorum=1"
|
|
138
138
|
end
|
139
139
|
end
|
140
140
|
@log.info("#{done.value} copies of #{id} fetched in #{Age.new(start)} with the total score of \
|
141
|
-
#{total.value} from #{nodes.value
|
141
|
+
#{total.value} from #{nodes.value - masters.value}+#{masters.value}m nodes")
|
142
142
|
list = cps.all.map do |c|
|
143
143
|
" ##{c[:name]}: #{c[:score]} #{c[:total]}n #{Wallet.new(c[:path]).mnemo} \
|
144
144
|
#{Size.new(File.size(c[:path]))}/#{Age.new(File.mtime(c[:path]))}#{c[:master] ? ' master' : ''}"
|
data/lib/zold/commands/merge.rb
CHANGED
@@ -65,7 +65,7 @@ Available options:"
|
|
65
65
|
default: false
|
66
66
|
o.integer '--depth',
|
67
67
|
'How many levels down we try to pull other wallets if their confirmations are required (default: 0)',
|
68
|
-
default:
|
68
|
+
default: 0
|
69
69
|
o.bool '--allow-negative-balance',
|
70
70
|
'Don\'t check for the negative balance of the wallet after the merge',
|
71
71
|
default: false
|
@@ -124,7 +124,7 @@ Available options:"
|
|
124
124
|
wallet = Wallet.new(c[:path])
|
125
125
|
baseline = idx.zero? && (c[:master] || opts['edge-baseline']) && !opts['no-baseline']
|
126
126
|
name = "#{c[:name]}/#{idx}/#{c[:score]}#{baseline ? '/baseline' : ''}"
|
127
|
-
merge_one(opts, patch, wallet, name, baseline: baseline)
|
127
|
+
merge_one(opts, patch, wallet, name, baseline: baseline, master: c[:master])
|
128
128
|
score += c[:score]
|
129
129
|
end
|
130
130
|
@wallets.acq(id) do |w|
|
@@ -152,11 +152,11 @@ into #{@wallets.acq(id, &:mnemo)} in #{Age.new(start, limit: 0.1 + cps.count * 0
|
|
152
152
|
modified
|
153
153
|
end
|
154
154
|
|
155
|
-
def merge_one(opts, patch, wallet, name, baseline: false)
|
155
|
+
def merge_one(opts, patch, wallet, name, baseline: false, master: false)
|
156
156
|
start = Time.now
|
157
|
-
@log.debug("
|
157
|
+
@log.debug("Adding copy ##{name}#{master ? ' (master)' : ''} to the patch #{wallet.mnemo}...")
|
158
158
|
if opts['depth'].positive?
|
159
|
-
patch.join(wallet, ledger: opts['ledger'], baseline: baseline) do |txn|
|
159
|
+
patch.join(wallet, ledger: opts['ledger'], baseline: baseline, master: master) do |txn|
|
160
160
|
trusted = IO.read(opts['trusted']).split(',')
|
161
161
|
if trusted.include?(txn.bnf.to_s)
|
162
162
|
@log.debug("Won't PULL #{txn.bnf} since it is already trusted, among #{trusted.count} others")
|
@@ -176,7 +176,7 @@ into #{@wallets.acq(id, &:mnemo)} in #{Age.new(start, limit: 0.1 + cps.count * 0
|
|
176
176
|
true
|
177
177
|
end
|
178
178
|
else
|
179
|
-
patch.join(wallet, ledger: opts['ledger'], baseline: baseline) do |txn|
|
179
|
+
patch.join(wallet, ledger: opts['ledger'], baseline: baseline, master: master) do |txn|
|
180
180
|
@log.debug("Paying wallet #{txn.bnf} is incomplete but there is not enough depth to PULL: #{txn.to_text}")
|
181
181
|
false
|
182
182
|
end
|
data/lib/zold/commands/node.rb
CHANGED
@@ -457,9 +457,13 @@ the node won\'t connect to the network like that; try to do "zold remote reset"
|
|
457
457
|
end
|
458
458
|
require_relative 'routines/spread'
|
459
459
|
metronome.add(Routines::Spread.new(opts, @wallets, @remotes, @copies, log: @log))
|
460
|
+
require_relative 'routines/retire'
|
461
|
+
metronome.add(Routines::Retire.new(opts, log: @log))
|
460
462
|
if @remotes.master?(host, port)
|
461
463
|
require_relative 'routines/reconcile'
|
462
464
|
metronome.add(Routines::Reconcile.new(opts, @wallets, @remotes, @copies, "#{host}:#{port}", log: @log))
|
465
|
+
else
|
466
|
+
@log.info('This is not master, no need to reconcile')
|
463
467
|
end
|
464
468
|
@log.info('Metronome started (use --no-metronome to disable it)')
|
465
469
|
metronome
|
data/lib/zold/commands/pay.rb
CHANGED
@@ -148,6 +148,7 @@ the difference is #{(amount - from.balance).to_i} zents"
|
|
148
148
|
@log.debug("Keygap \"#{'*' * opts['keygap'].length}\" injected into the RSA private key")
|
149
149
|
end
|
150
150
|
key = Zold::Key.new(text: pem)
|
151
|
+
from.refurbish
|
151
152
|
txn = from.sub(amount, invoice, key, details, time: Txn.parse_time(opts['time']))
|
152
153
|
@log.debug("#{amount} sent from #{from} to #{txn.bnf}: #{details}")
|
153
154
|
@log.debug("Don't forget to do 'zold push #{from}'")
|
data/lib/zold/commands/push.rb
CHANGED
@@ -31,6 +31,7 @@ require_relative '../thread_pool'
|
|
31
31
|
require_relative '../hands'
|
32
32
|
require_relative '../age'
|
33
33
|
require_relative '../size'
|
34
|
+
require_relative '../tax'
|
34
35
|
require_relative '../log'
|
35
36
|
require_relative '../id'
|
36
37
|
require_relative '../http'
|
@@ -98,6 +99,9 @@ Available options:"
|
|
98
99
|
@wallets.acq(id) do |wallet|
|
99
100
|
raise "The wallet #{id} is absent at #{wallet.path}" unless wallet.exists?
|
100
101
|
end
|
102
|
+
if @wallets.acq(id) { |w| Tax.new(w).in_debt? }
|
103
|
+
@log.info("Taxes in #{id} are not paid, most likely the wallet won't be accepted by any node")
|
104
|
+
end
|
101
105
|
start = Time.now
|
102
106
|
total = Concurrent::AtomicFixnum.new
|
103
107
|
nodes = Concurrent::AtomicFixnum.new
|
@@ -121,7 +125,7 @@ Available options:"
|
|
121
125
|
run 'zold remote update' or use --tolerate-quorum=1"
|
122
126
|
end
|
123
127
|
end
|
124
|
-
@log.info("Push finished to #{done.value
|
128
|
+
@log.info("Push finished to #{done.value - masters.value}+#{masters.value}m nodes \
|
125
129
|
out of #{nodes.value} in #{Age.new(start)}, total score for #{id} is #{total.value}")
|
126
130
|
end
|
127
131
|
|
data/lib/zold/commands/remote.rb
CHANGED
@@ -261,7 +261,8 @@ Available options:"
|
|
261
261
|
@remotes.remove(r[:host], r[:port]) if !opts['masters-too'] || !r[:master]
|
262
262
|
@log.debug("#{r[:host]}:#{r[:port]} removed because of #{r[:errors]} errors (over #{opts['tolerate']})")
|
263
263
|
end
|
264
|
-
@log.info("The list of #{all.count} remotes trimmed down to #{@remotes.all.count} nodes
|
264
|
+
@log.info("The list of #{all.count} remotes trimmed down to #{@remotes.all.count} nodes \
|
265
|
+
(#{@remotes.all.count { |r| r[:master] }} masters)")
|
265
266
|
end
|
266
267
|
|
267
268
|
def update(opts)
|
@@ -299,7 +300,9 @@ Available options:"
|
|
299
300
|
if total.zero?
|
300
301
|
@log.info("The list of remotes is #{Rainbow('empty').red}, run 'zold remote reset'!")
|
301
302
|
else
|
302
|
-
@log.info("There are #{total} known remotes
|
303
|
+
@log.info("There are #{total} known remotes \
|
304
|
+
(#{@remotes.all.count { |r| r[:master] }} masters) \
|
305
|
+
with the overall score of \
|
303
306
|
#{@remotes.all.map { |r| r[:score] }.inject(&:+)}, after update in #{Age.new(st)}")
|
304
307
|
end
|
305
308
|
end
|
@@ -354,7 +357,8 @@ it's recommended to reboot, but I don't do it because of --never-reboot")
|
|
354
357
|
@remotes.remove(r[:host], r[:port])
|
355
358
|
@log.debug("Remote #{r[:host]}:#{r[:port]}/#{r[:score]}/#{r[:errors]}e removed from the list")
|
356
359
|
end
|
357
|
-
@log.info("#{@remotes.all.count} best remote nodes were selected to stay in the list
|
360
|
+
@log.info("#{@remotes.all.count} best remote nodes were selected to stay in the list \
|
361
|
+
(#{@remotes.all.count { |r| r[:master] }} masters)")
|
358
362
|
end
|
359
363
|
|
360
364
|
def terminate
|
@@ -48,10 +48,15 @@ class Zold::Routines::Reconcile
|
|
48
48
|
next if r.to_mnemo == @address
|
49
49
|
res = r.http('/wallets').get
|
50
50
|
r.assert_code(200, res)
|
51
|
-
res.body.strip.split("\n").compact
|
51
|
+
missing = res.body.strip.split("\n").compact
|
52
52
|
.select { |i| /^[a-f0-9]{16}$/.match?(i) }
|
53
53
|
.reject { |i| @wallets.acq(Zold::Id.new(i), &:exists?) }
|
54
|
-
|
54
|
+
missing.each { |i| pull(i) }
|
55
|
+
if missing.empty?
|
56
|
+
log.info("Nothing to reconcile with #{r}, we are good at #{@address}")
|
57
|
+
else
|
58
|
+
@log.info("Reconcile routine pulled #{missing.count} wallets from #{r}")
|
59
|
+
end
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
@@ -44,16 +44,31 @@ class Zold::Routines::Reconnect
|
|
44
44
|
score = @farm.best[0]
|
45
45
|
args << "--ignore-node=#{Shellwords.escape("#{score.host}:#{score.port}")}" if score
|
46
46
|
cmd.run(args + ['masters']) unless @opts['routine-immediately']
|
47
|
-
|
48
|
-
return if @opts['routine-immediately'] && all.empty?
|
47
|
+
return if @opts['routine-immediately'] && @remotes.all.empty?
|
49
48
|
cmd.run(args + ['select'])
|
50
|
-
if
|
51
|
-
|
52
|
-
|
49
|
+
if (step % 10).zero?
|
50
|
+
@log.info("It is round ##{step}, time to update the list of remotes")
|
51
|
+
update(cmd, args)
|
52
|
+
end
|
53
|
+
if @remotes.all.any? { |r| r[:errors] > Zold::Remotes::TOLERANCE }
|
54
|
+
@log.info('There are a few remote nodes with too many errors, it\'s time to update')
|
55
|
+
update(cmd, args)
|
56
|
+
else
|
57
|
+
@log.debug("All #{@remotes.all.count} remote nodes are still more or less error-free, won't update")
|
58
|
+
end
|
59
|
+
if @remotes.all.count < Zold::Remotes::MAX_NODES / 2
|
60
|
+
@log.info("There are just #{@remotes.all.count} remotes in the list, time to update")
|
61
|
+
update(cmd, args)
|
53
62
|
end
|
54
63
|
cmd.run(args + ['trim'])
|
55
64
|
cmd.run(args + ['select'])
|
56
65
|
@log.info("Reconnected, there are #{@remotes.all.count} remote notes: \
|
57
66
|
#{@remotes.all.map { |r| "#{r[:host]}:#{r[:port]}/#{r[:score]}/#{r[:errors]}" }.join(', ')}")
|
58
67
|
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def update(cmd, args)
|
72
|
+
cmd.run(args + ['update'] + (@opts['never-reboot'] ? [] : ['--reboot']))
|
73
|
+
end
|
59
74
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2019 Zerocracy, Inc.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require 'shellwords'
|
24
|
+
require_relative '../routines'
|
25
|
+
require_relative '../remote'
|
26
|
+
require_relative '../../node/farm'
|
27
|
+
|
28
|
+
# Kill the node if it's too old.
|
29
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
31
|
+
# License:: MIT
|
32
|
+
class Zold::Routines::Retire
|
33
|
+
def initialize(opts, log: Log::NULL)
|
34
|
+
@opts = opts
|
35
|
+
@log = log
|
36
|
+
@start = Time.now
|
37
|
+
end
|
38
|
+
|
39
|
+
def exec(step = 0)
|
40
|
+
sleep(60) unless @opts['routine-immediately']
|
41
|
+
days = 4
|
42
|
+
return if step < days * 24 * 60 && Time.now - @start < days * 24 * 60 * 60
|
43
|
+
return if @opts['never-reboot']
|
44
|
+
@log.info("We are too old, step ##{step}, it's time to retire (use --never-reboot to avoid this)")
|
45
|
+
require_relative '../../node/front'
|
46
|
+
Zold::Front.stop!
|
47
|
+
end
|
48
|
+
end
|
data/lib/zold/gem.rb
CHANGED
data/lib/zold/node/farm.rb
CHANGED
data/lib/zold/node/farmers.rb
CHANGED
@@ -111,7 +111,7 @@ for #{score.value}/#{score.strength} at #{score.host}:#{score.port}")
|
|
111
111
|
begin
|
112
112
|
buffer << stdout.read_nonblock(16 * 1024)
|
113
113
|
# rubocop:disable Lint/HandleExceptions
|
114
|
-
rescue IO::WaitReadable
|
114
|
+
rescue IO::WaitReadable
|
115
115
|
# rubocop:enable Lint/HandleExceptions
|
116
116
|
# nothing to do here
|
117
117
|
rescue StandardError => e
|
data/lib/zold/node/front.rb
CHANGED
@@ -232,6 +232,7 @@ this is not a normal behavior, you may want to report a bug to our GitHub reposi
|
|
232
232
|
total_mem: total_mem,
|
233
233
|
threads: "#{Thread.list.select { |t| t.status == 'run' }.count}/#{Thread.list.count}",
|
234
234
|
wallets: total_wallets,
|
235
|
+
journal: DirItems.new(settings.journal_dir).fetch.count,
|
235
236
|
remotes: all_remotes.count,
|
236
237
|
nscore: all_remotes.map { |r| r[:score] }.inject(&:+) || 0,
|
237
238
|
farm: settings.farm.to_json,
|
data/lib/zold/patch.rb
CHANGED
@@ -69,7 +69,10 @@ module Zold
|
|
69
69
|
# The "baseline" flag, when set to TRUE, means that we should NOT validate
|
70
70
|
# the presence of positive incoming transactions in their correspondent
|
71
71
|
# wallets. We shall just trust them.
|
72
|
-
|
72
|
+
#
|
73
|
+
# If the "master" flag is set, this copy is coming from a master node
|
74
|
+
# and we should allow it to overwrite negative transactions.
|
75
|
+
def join(wallet, ledger: '/dev/null', baseline: false, master: false)
|
73
76
|
if @id.nil?
|
74
77
|
@id = wallet.id
|
75
78
|
@key = wallet.key
|
@@ -95,11 +98,16 @@ module Zold
|
|
95
98
|
seen += 1
|
96
99
|
if txn.amount.negative?
|
97
100
|
dup = @txns.find { |t| t.id == txn.id && t.amount.negative? }
|
98
|
-
if dup
|
101
|
+
if dup && !master
|
99
102
|
@log.error("An attempt to overwrite existing transaction #{dup.to_text.inspect} \
|
100
103
|
with a new one #{txn.to_text.inspect} from #{wallet.mnemo}")
|
101
104
|
next
|
102
105
|
end
|
106
|
+
if dup && master
|
107
|
+
@log.debug("An overwrite to the existing transaction #{dup.to_text.inspect} \
|
108
|
+
is coming from a master node: #{txn.to_text.inspect} from #{wallet.mnemo}")
|
109
|
+
@txns.reject! { |t| t.id == txn.id && t.amount.negative? }
|
110
|
+
end
|
103
111
|
unless Signature.new(@network).valid?(@key, wallet.id, txn)
|
104
112
|
@log.error("Invalid RSA signature at the transaction ##{txn.id} of #{wallet.id}: #{txn.to_text.inspect}")
|
105
113
|
next
|
data/lib/zold/remotes.rb
CHANGED
@@ -34,6 +34,7 @@ require_relative 'http'
|
|
34
34
|
require_relative 'hands'
|
35
35
|
require_relative 'thread_pool'
|
36
36
|
require_relative 'node/farm'
|
37
|
+
require_relative 'commands/fetch'
|
37
38
|
|
38
39
|
# The list of remotes.
|
39
40
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -118,7 +119,12 @@ at #{response.headers['X-Zold-Path']}"
|
|
118
119
|
MAX_NODES = 16
|
119
120
|
|
120
121
|
# Default nodes and their ports
|
121
|
-
MASTERS = CSV.read(File.expand_path(File.join(File.dirname(__FILE__), '../../resources/masters')))
|
122
|
+
MASTERS = CSV.read(File.expand_path(File.join(File.dirname(__FILE__), '../../resources/masters'))).map do |r|
|
123
|
+
{
|
124
|
+
host: r[0].strip,
|
125
|
+
port: r[1].to_i
|
126
|
+
}
|
127
|
+
end.freeze
|
122
128
|
private_constant :MASTERS
|
123
129
|
|
124
130
|
# Empty, for standalone mode
|
@@ -168,9 +174,9 @@ at #{response.headers['X-Zold-Path']}"
|
|
168
174
|
def masters
|
169
175
|
MASTERS.each do |r|
|
170
176
|
if block_given?
|
171
|
-
next unless yield(r[
|
177
|
+
next unless yield(r[:host], r[:port])
|
172
178
|
end
|
173
|
-
add(r[
|
179
|
+
add(r[:host], r[:port])
|
174
180
|
end
|
175
181
|
end
|
176
182
|
|
@@ -255,7 +261,7 @@ at #{response.headers['X-Zold-Path']}"
|
|
255
261
|
end
|
256
262
|
|
257
263
|
def master?(host, port)
|
258
|
-
!MASTERS.find { |r| r[
|
264
|
+
!MASTERS.find { |r| r[:host] == host && r[:port] == port }.nil?
|
259
265
|
end
|
260
266
|
|
261
267
|
private
|
data/lib/zold/version.rb
CHANGED
@@ -36,7 +36,8 @@ class TestReconnect < Zold::Test
|
|
36
36
|
Dir.mktmpdir do |dir|
|
37
37
|
remotes = Zold::Remotes.new(file: File.join(dir, 'remotes.csv'))
|
38
38
|
remotes.clean
|
39
|
-
|
39
|
+
remotes.add('localhost', 4096)
|
40
|
+
stub_request(:get, 'http://localhost:4096/remotes').to_return(status: 404)
|
40
41
|
opts = { 'never-reboot' => true, 'routine-immediately' => true }
|
41
42
|
routine = Zold::Routines::Reconnect.new(opts, remotes, log: test_log)
|
42
43
|
routine.exec
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2019 Zerocracy, Inc.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require 'minitest/autorun'
|
24
|
+
require 'tmpdir'
|
25
|
+
require 'webmock/minitest'
|
26
|
+
require_relative '../../test__helper'
|
27
|
+
require_relative '../../../lib/zold/remotes'
|
28
|
+
require_relative '../../../lib/zold/commands/routines/retire.rb'
|
29
|
+
|
30
|
+
# Retire test.
|
31
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
32
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
33
|
+
# License:: MIT
|
34
|
+
class TestRetire < Zold::Test
|
35
|
+
def test_retires
|
36
|
+
opts = { 'never-reboot' => false, 'routine-immediately' => true }
|
37
|
+
routine = Zold::Routines::Retire.new(opts, log: test_log)
|
38
|
+
routine.exec(10 * 24 * 60)
|
39
|
+
end
|
40
|
+
end
|
data/test/commands/test_node.rb
CHANGED
@@ -56,7 +56,7 @@ class TestNode < Zold::Test
|
|
56
56
|
wallets: wallets, copies: copies.root,
|
57
57
|
remotes: remotes, log: test_log
|
58
58
|
).run(['fetch', '--ignore-score-weakness', '--tolerate-edges', '--tolerate-quorum=1'])
|
59
|
-
rescue StandardError =>
|
59
|
+
rescue StandardError => _e
|
60
60
|
sleep 1
|
61
61
|
retry if (retries += 1) < 3
|
62
62
|
end
|
data/test/commands/test_pay.rb
CHANGED
@@ -107,8 +107,9 @@ class TestPay < Zold::Test
|
|
107
107
|
FakeHome.new(log: test_log).run do |home|
|
108
108
|
wallet = home.create_wallet
|
109
109
|
amount = Zold::Amount.new(zld: 2.0)
|
110
|
+
wallets = home.wallets
|
110
111
|
Threads.new(10).assert do
|
111
|
-
Zold::Pay.new(wallets:
|
112
|
+
Zold::Pay.new(wallets: wallets, copies: home.dir, remotes: home.remotes, log: test_log).run(
|
112
113
|
[
|
113
114
|
'pay', '--force', '--private-key=fixtures/id_rsa',
|
114
115
|
wallet.id.to_s, 'NOPREFIX@dddd0000dddd0000', amount.to_zld, '-'
|
data/test/node/test_front.rb
CHANGED
@@ -64,6 +64,7 @@ class FrontTest < Zold::Test
|
|
64
64
|
assert_equal('zold-io/zold', json['repo'])
|
65
65
|
assert(json['pid'].positive?, json)
|
66
66
|
assert(json['cpus'].positive?, json)
|
67
|
+
assert(!json['journal'].negative?, json)
|
67
68
|
assert(json['memory'].positive?, json)
|
68
69
|
assert(!json['load'].negative?, json)
|
69
70
|
assert(json['wallets'].positive?, json)
|
data/zold.gemspec
CHANGED
@@ -62,18 +62,18 @@ and suggests a different architecture for digital wallet maintenance.'
|
|
62
62
|
s.rdoc_options = ['--charset=UTF-8']
|
63
63
|
s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
64
64
|
s.add_runtime_dependency 'backtrace', '>=0.3'
|
65
|
-
s.add_runtime_dependency 'concurrent-ruby', '1.1.
|
66
|
-
s.add_runtime_dependency 'diffy', '3.
|
65
|
+
s.add_runtime_dependency 'concurrent-ruby', '1.1.5'
|
66
|
+
s.add_runtime_dependency 'diffy', '3.3.0'
|
67
67
|
s.add_runtime_dependency 'futex', '>=0.8.5'
|
68
68
|
s.add_runtime_dependency 'get_process_mem', '~>0.2'
|
69
69
|
s.add_runtime_dependency 'haml', '5.0.4'
|
70
|
-
s.add_runtime_dependency 'json', '2.
|
71
|
-
s.add_runtime_dependency 'memory_profiler', '0.9.
|
72
|
-
s.add_runtime_dependency 'mimic', '0.4.
|
70
|
+
s.add_runtime_dependency 'json', '2.2.0'
|
71
|
+
s.add_runtime_dependency 'memory_profiler', '0.9.13'
|
72
|
+
s.add_runtime_dependency 'mimic', '0.4.4'
|
73
73
|
s.add_runtime_dependency 'openssl', '2.1.2'
|
74
74
|
s.add_runtime_dependency 'rainbow', '3.0.0'
|
75
75
|
s.add_runtime_dependency 'semantic', '1.6.1'
|
76
|
-
s.add_runtime_dependency 'sinatra', '2.0.
|
76
|
+
s.add_runtime_dependency 'sinatra', '2.0.5'
|
77
77
|
s.add_runtime_dependency 'slop', '4.6.2'
|
78
78
|
s.add_runtime_dependency 'sys-proctable', '1.2.1'
|
79
79
|
s.add_runtime_dependency 'thin', '1.7.2'
|
@@ -83,19 +83,19 @@ and suggests a different architecture for digital wallet maintenance.'
|
|
83
83
|
s.add_runtime_dependency 'usagewatch_ext', '0.2.1'
|
84
84
|
s.add_runtime_dependency 'zache', '>=0.12'
|
85
85
|
s.add_runtime_dependency 'zold-score', '0.4.6'
|
86
|
-
s.add_development_dependency 'codecov', '0.1.
|
86
|
+
s.add_development_dependency 'codecov', '0.1.14'
|
87
87
|
s.add_development_dependency 'cucumber', '3.1.2'
|
88
88
|
s.add_development_dependency 'guard', '2.15.0'
|
89
89
|
s.add_development_dependency 'guard-minitest', '2.4.6'
|
90
90
|
s.add_development_dependency 'minitest', '5.11.3'
|
91
91
|
s.add_development_dependency 'minitest-fail-fast', '0.1.0'
|
92
92
|
s.add_development_dependency 'minitest-hooks', '1.5.0'
|
93
|
-
s.add_development_dependency 'rake', '12.3.
|
93
|
+
s.add_development_dependency 'rake', '12.3.2'
|
94
94
|
s.add_development_dependency 'random-port', '0.3.1'
|
95
|
-
s.add_development_dependency 'rdoc', '
|
96
|
-
s.add_development_dependency 'rspec-rails', '3.8.
|
97
|
-
s.add_development_dependency 'rubocop', '0.
|
98
|
-
s.add_development_dependency 'rubocop-rspec', '1.
|
99
|
-
s.add_development_dependency 'webmock', '3.
|
95
|
+
s.add_development_dependency 'rdoc', '6.1.1'
|
96
|
+
s.add_development_dependency 'rspec-rails', '3.8.2'
|
97
|
+
s.add_development_dependency 'rubocop', '0.69.0'
|
98
|
+
s.add_development_dependency 'rubocop-rspec', '1.33.0'
|
99
|
+
s.add_development_dependency 'webmock', '3.5.1'
|
100
100
|
s.add_development_dependency 'xcop', '>=0.6'
|
101
101
|
end
|
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.29.
|
4
|
+
version: 0.29.28
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: backtrace
|
@@ -30,28 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.1.
|
33
|
+
version: 1.1.5
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 1.1.
|
40
|
+
version: 1.1.5
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: diffy
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - '='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 3.
|
47
|
+
version: 3.3.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 3.
|
54
|
+
version: 3.3.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: futex
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,42 +100,42 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - '='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 2.
|
103
|
+
version: 2.2.0
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - '='
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 2.
|
110
|
+
version: 2.2.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: memory_profiler
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - '='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.9.
|
117
|
+
version: 0.9.13
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - '='
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.9.
|
124
|
+
version: 0.9.13
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: mimic
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - '='
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.4.
|
131
|
+
version: 0.4.4
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - '='
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.4.
|
138
|
+
version: 0.4.4
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: openssl
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,14 +184,14 @@ dependencies:
|
|
184
184
|
requirements:
|
185
185
|
- - '='
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: 2.0.
|
187
|
+
version: 2.0.5
|
188
188
|
type: :runtime
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - '='
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: 2.0.
|
194
|
+
version: 2.0.5
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: slop
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -324,14 +324,14 @@ dependencies:
|
|
324
324
|
requirements:
|
325
325
|
- - '='
|
326
326
|
- !ruby/object:Gem::Version
|
327
|
-
version: 0.1.
|
327
|
+
version: 0.1.14
|
328
328
|
type: :development
|
329
329
|
prerelease: false
|
330
330
|
version_requirements: !ruby/object:Gem::Requirement
|
331
331
|
requirements:
|
332
332
|
- - '='
|
333
333
|
- !ruby/object:Gem::Version
|
334
|
-
version: 0.1.
|
334
|
+
version: 0.1.14
|
335
335
|
- !ruby/object:Gem::Dependency
|
336
336
|
name: cucumber
|
337
337
|
requirement: !ruby/object:Gem::Requirement
|
@@ -422,14 +422,14 @@ dependencies:
|
|
422
422
|
requirements:
|
423
423
|
- - '='
|
424
424
|
- !ruby/object:Gem::Version
|
425
|
-
version: 12.3.
|
425
|
+
version: 12.3.2
|
426
426
|
type: :development
|
427
427
|
prerelease: false
|
428
428
|
version_requirements: !ruby/object:Gem::Requirement
|
429
429
|
requirements:
|
430
430
|
- - '='
|
431
431
|
- !ruby/object:Gem::Version
|
432
|
-
version: 12.3.
|
432
|
+
version: 12.3.2
|
433
433
|
- !ruby/object:Gem::Dependency
|
434
434
|
name: random-port
|
435
435
|
requirement: !ruby/object:Gem::Requirement
|
@@ -450,70 +450,70 @@ dependencies:
|
|
450
450
|
requirements:
|
451
451
|
- - '='
|
452
452
|
- !ruby/object:Gem::Version
|
453
|
-
version:
|
453
|
+
version: 6.1.1
|
454
454
|
type: :development
|
455
455
|
prerelease: false
|
456
456
|
version_requirements: !ruby/object:Gem::Requirement
|
457
457
|
requirements:
|
458
458
|
- - '='
|
459
459
|
- !ruby/object:Gem::Version
|
460
|
-
version:
|
460
|
+
version: 6.1.1
|
461
461
|
- !ruby/object:Gem::Dependency
|
462
462
|
name: rspec-rails
|
463
463
|
requirement: !ruby/object:Gem::Requirement
|
464
464
|
requirements:
|
465
465
|
- - '='
|
466
466
|
- !ruby/object:Gem::Version
|
467
|
-
version: 3.8.
|
467
|
+
version: 3.8.2
|
468
468
|
type: :development
|
469
469
|
prerelease: false
|
470
470
|
version_requirements: !ruby/object:Gem::Requirement
|
471
471
|
requirements:
|
472
472
|
- - '='
|
473
473
|
- !ruby/object:Gem::Version
|
474
|
-
version: 3.8.
|
474
|
+
version: 3.8.2
|
475
475
|
- !ruby/object:Gem::Dependency
|
476
476
|
name: rubocop
|
477
477
|
requirement: !ruby/object:Gem::Requirement
|
478
478
|
requirements:
|
479
479
|
- - '='
|
480
480
|
- !ruby/object:Gem::Version
|
481
|
-
version: 0.
|
481
|
+
version: 0.69.0
|
482
482
|
type: :development
|
483
483
|
prerelease: false
|
484
484
|
version_requirements: !ruby/object:Gem::Requirement
|
485
485
|
requirements:
|
486
486
|
- - '='
|
487
487
|
- !ruby/object:Gem::Version
|
488
|
-
version: 0.
|
488
|
+
version: 0.69.0
|
489
489
|
- !ruby/object:Gem::Dependency
|
490
490
|
name: rubocop-rspec
|
491
491
|
requirement: !ruby/object:Gem::Requirement
|
492
492
|
requirements:
|
493
493
|
- - '='
|
494
494
|
- !ruby/object:Gem::Version
|
495
|
-
version: 1.
|
495
|
+
version: 1.33.0
|
496
496
|
type: :development
|
497
497
|
prerelease: false
|
498
498
|
version_requirements: !ruby/object:Gem::Requirement
|
499
499
|
requirements:
|
500
500
|
- - '='
|
501
501
|
- !ruby/object:Gem::Version
|
502
|
-
version: 1.
|
502
|
+
version: 1.33.0
|
503
503
|
- !ruby/object:Gem::Dependency
|
504
504
|
name: webmock
|
505
505
|
requirement: !ruby/object:Gem::Requirement
|
506
506
|
requirements:
|
507
507
|
- - '='
|
508
508
|
- !ruby/object:Gem::Version
|
509
|
-
version: 3.
|
509
|
+
version: 3.5.1
|
510
510
|
type: :development
|
511
511
|
prerelease: false
|
512
512
|
version_requirements: !ruby/object:Gem::Requirement
|
513
513
|
requirements:
|
514
514
|
- - '='
|
515
515
|
- !ruby/object:Gem::Version
|
516
|
-
version: 3.
|
516
|
+
version: 3.5.1
|
517
517
|
- !ruby/object:Gem::Dependency
|
518
518
|
name: xcop
|
519
519
|
requirement: !ruby/object:Gem::Requirement
|
@@ -550,7 +550,11 @@ extra_rdoc_files:
|
|
550
550
|
files:
|
551
551
|
- ".0pdd.yml"
|
552
552
|
- ".gitattributes"
|
553
|
+
- ".github/CODE_OF_CONDUCT.md"
|
554
|
+
- ".github/CONTRIBUTING.md"
|
553
555
|
- ".github/ISSUE_TEMPLATE.md"
|
556
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
557
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
554
558
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
555
559
|
- ".gitignore"
|
556
560
|
- ".pdd"
|
@@ -600,6 +604,12 @@ files:
|
|
600
604
|
- fixtures/merge/missed_wallets/copies/0123456789abcdef/1.zc
|
601
605
|
- fixtures/merge/missed_wallets/copies/0123456789abcdef/scores.zc
|
602
606
|
- fixtures/merge/missed_wallets/opts
|
607
|
+
- fixtures/merge/negative_overwriting/0123456789abcdef.z
|
608
|
+
- fixtures/merge/negative_overwriting/146b852f2d9ad984.z
|
609
|
+
- fixtures/merge/negative_overwriting/assert.rb
|
610
|
+
- fixtures/merge/negative_overwriting/copies/0123456789abcdef/1.zc
|
611
|
+
- fixtures/merge/negative_overwriting/copies/0123456789abcdef/scores.zc
|
612
|
+
- fixtures/merge/negative_overwriting/opts
|
603
613
|
- fixtures/merge/negatives_in_between/0000000000000000.z
|
604
614
|
- fixtures/merge/negatives_in_between/0123456789abcdef.z
|
605
615
|
- fixtures/merge/negatives_in_between/assert.rb
|
@@ -664,6 +674,7 @@ files:
|
|
664
674
|
- lib/zold/commands/routines/gc.rb
|
665
675
|
- lib/zold/commands/routines/reconcile.rb
|
666
676
|
- lib/zold/commands/routines/reconnect.rb
|
677
|
+
- lib/zold/commands/routines/retire.rb
|
667
678
|
- lib/zold/commands/routines/spread.rb
|
668
679
|
- lib/zold/commands/show.rb
|
669
680
|
- lib/zold/commands/taxes.rb
|
@@ -721,6 +732,7 @@ files:
|
|
721
732
|
- test/commands/routines/test_gc.rb
|
722
733
|
- test/commands/routines/test_reconcile.rb
|
723
734
|
- test/commands/routines/test_reconnect.rb
|
735
|
+
- test/commands/routines/test_retire.rb
|
724
736
|
- test/commands/test_alias.rb
|
725
737
|
- test/commands/test_calculate.rb
|
726
738
|
- test/commands/test_clean.rb
|
@@ -801,7 +813,7 @@ licenses:
|
|
801
813
|
- MIT
|
802
814
|
metadata: {}
|
803
815
|
post_install_message: |-
|
804
|
-
Thanks for installing Zold 0.29.
|
816
|
+
Thanks for installing Zold 0.29.28!
|
805
817
|
Study our White Paper: https://papers.zold.io/wp.pdf
|
806
818
|
Read our blog posts: https://blog.zold.io
|
807
819
|
Try ZLD online wallet at: https://wts.zold.io
|
@@ -836,6 +848,7 @@ test_files:
|
|
836
848
|
- test/commands/routines/test_gc.rb
|
837
849
|
- test/commands/routines/test_reconcile.rb
|
838
850
|
- test/commands/routines/test_reconnect.rb
|
851
|
+
- test/commands/routines/test_retire.rb
|
839
852
|
- test/commands/test_alias.rb
|
840
853
|
- test/commands/test_calculate.rb
|
841
854
|
- test/commands/test_clean.rb
|