├── README.md
├── arionum-benchmark
├── .gitignore
├── LICENSE.md
├── README.md
├── hasher-tests
│ ├── README.md
│ ├── Results-Summary-24hrs-php_vs_java.xlsx
│ ├── java-miner-24hrs.log
│ ├── php-miner-1-24hrs.log
│ └── php-miner-2-24hrs.log
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── programmerdan
│ └── arionum
│ └── arionum_benchmark
│ ├── AdvMode.java
│ ├── BasicHasher.java
│ ├── ExperimentalHasher.java
│ ├── Hasher.java
│ └── StableHasher.java
└── arionum-miner
├── .gitignore
├── DOCS.md
├── LICENSE.md
├── README.md
├── WINDOWS_COMPILE_GUIDE.md
├── pom-arm.xml
├── pom.xml
└── src
└── main
├── bin
├── build-argon-arm.sh
├── build-argon.sh
├── pick-argon.bat
├── pick-argon.ps1
├── run.bat
└── run.sh
├── java
└── com
│ └── programmerdan
│ └── arionum
│ └── arionum_miner
│ ├── AdvMode.java
│ ├── AggressiveAffinityThreadFactory.java
│ ├── CPrint.java
│ ├── ExperimentalHasher.java
│ ├── GPUHasher.java
│ ├── Hasher.java
│ ├── HasherFactory.java
│ ├── HasherStats.java
│ ├── MappedHasher.java
│ ├── Miner.java
│ ├── MinerType.java
│ ├── Profile.java
│ ├── Report.java
│ ├── SafeMappedHasher.java
│ ├── Utility.java
│ └── jna
│ ├── Argon2Library.java
│ ├── Argon2_Context.java
│ ├── Argon2_type.java
│ ├── JnaUint32.java
│ ├── JnaUint8.java
│ └── Size_t.java
└── resources
├── darwin
└── libargon2.dylib
├── linux-x86-64
└── libargon2.so
└── win32-x86-64
├── argon2-avx.dll
├── argon2-avx2.dll
├── argon2-avx512f.dll
├── argon2-generic.dll
└── argon2.dll
/README.md:
--------------------------------------------------------------------------------
1 | Arionum-Java
2 | ------------------
3 | Arionum is a pretty new cryptocurrency that's largely CPU bound, resisting ASIC and GPU optimizations. This is a perfect coin to mine for people with GPU hardware doing other mining but low utilization of CPU resources.
4 |
5 | It caught my eye and as part of code-vetting I figured I might as well do a port to Java and see if I can get some more efficiency out of the code or better interfacing. I'll try as I'm able (pretty rusty with PHP) to also contribute back to the PHP reference implementations.
6 |
7 | Learn more here: http://arionum.com
8 |
9 | Bitcointalk: https://bitcointalk.org/index.php?topic=2710248.0
10 |
11 | Block explorer: https://arionum.info/
12 |
13 | Send Arionum donations here: 4SxMLLWRCxoL42gqgf2C2x5T5Q1BJhgfQvMsfwrcFAu4owsBYncsvVnBBVqtxVrkqHVZ8nJGrcJB7yWnV92j5Rca
14 |
15 | Send BTC donations here: bc1qucem39g0lamacevmvj7qnkfjh3mqkr0jmlnlt3 (segwit) or 1MXcQyo1jbaTYdWUqeAQumsKUDnytiFAe5 (standard)
16 |
17 | Send CureCoin donations here: BFDK84Z29zb4caNMArKBZVBXAxGqGMRMfq (get involved here: https://curecoin.net/ -- works great alongside Arionum)
18 |
19 | Send FoldingCoin donations here: 1HH3SQNf1KPfsAGC5BAvDj849oHoAsYEms (get involved here: https://foldingcoin.net/ -- mergefold w/ curecoin!)
20 |
21 | Thanks, this looks to be a super fun project.
22 |
23 | ---------------
24 | # Arionum-miner
25 |
26 | This is a slightly optimized miner, coded in Java, and based very strongly on the php reference version.
27 |
28 | Major differentiators:
29 |
30 | * One JVM can run multiple hashers and share the same "update" requests to the pool, reducing traffic to the core
31 |
32 | * The hashers never stop -- the reference PHP implementation pauses the hasher during update requests and nonce submissions. The java hashers never stop.
33 |
34 | * Optimizations -- the Java miner has easy swap support for alternate "core" types, with "standard", "experimental" and "legacy" for now; standard (or "enhanced") is the current strong recommendation, it has better adaptive behavior and some optimizations to reduce rejections, identify bad or reduced capability memory sectors and generally focus on accepted hashes, not just hashrate (although hashrate is great too). All other cores represent prior or lower performing cores.
35 |
36 | For more details, see the arionum forum thread here: https://forum.arionum.com/viewtopic.php?f=11&t=28
37 |
38 | I hope you enjoy. See the README.md in the arionum-miner subfolder for details on compiling and running.
39 |
--------------------------------------------------------------------------------
/arionum-benchmark/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | *.exe
3 | *.jar
4 | *.sh
5 | *.bat
6 | *.cfg
7 | **/dependency-reduced-pom.xml
8 | dependency-reduced-pom.xml
9 | .project
10 | .classpath
11 | .settings/
12 |
--------------------------------------------------------------------------------
/arionum-benchmark/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
3 |
4 | www.arionum.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of
15 | the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
23 | OR OTHER DEALINGS IN THE SOFTWARE.
24 |
25 |
26 | Libraries used (such as argon2-jvm and json-simple) are covered by their own licenses, I use them as-is without warranty.
27 |
--------------------------------------------------------------------------------
/arionum-benchmark/README.md:
--------------------------------------------------------------------------------
1 | Arionum Benchmark for Java
2 | ====================
3 | by ProgrammerDan, Jan 2018
4 | based on https://github.com/arionum/miner a work by AroDev
5 |
6 | For advanced system benchmarking. Compile using `mvn clean package` and run using `java -jar target/argon-benchmark-0.0.1-SNAPSHOT.jar`. It will run until forcibly stopped.
7 |
8 |
--------------------------------------------------------------------------------
/arionum-benchmark/hasher-tests/README.md:
--------------------------------------------------------------------------------
1 | These are data files and an xlsx showing results from a 24 hr side by side test of php reference miner and java multithreaded.
2 |
3 | Full results summary here:
4 |
5 | https://docs.google.com/spreadsheets/d/e/2PACX-1vSfq_6E935nj3Uek1kF1nENIFMTk7I9-EsxBrKRRyaZo03nEktzMlBV6ZHVOXvc6I8oUhhRYMOOiidS/pubhtml?gid=105959191&single=true
6 |
--------------------------------------------------------------------------------
/arionum-benchmark/hasher-tests/Results-Summary-24hrs-php_vs_java.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProgrammerDan/arionum-java/17d3ecedfbf6106e66b7a1b19702604df53f764d/arionum-benchmark/hasher-tests/Results-Summary-24hrs-php_vs_java.xlsx
--------------------------------------------------------------------------------
/arionum-benchmark/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.programmerdan.arionum
6 | arionum-benchmark
7 | 0.0.1-SNAPSHOT
8 | jar
9 |
10 | arionum-benchmark-java
11 | https://github.com/ProgrammerDan/arionum-java/arionum-benchmark
12 |
13 |
14 | UTF-8
15 | 1.8
16 | 1.8
17 |
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-compiler-plugin
24 | 3.5.1
25 |
26 | 1.8
27 | 1.8
28 |
29 |
30 |
31 | org.apache.maven.plugins
32 | maven-shade-plugin
33 | 2.4.3
34 |
35 |
36 | package
37 |
38 | shade
39 |
40 |
41 |
42 |
43 |
44 |
46 |
47 | com.programmerdan.arionum.arionum_benchmark.Hasher
48 |
49 |
50 |
52 | META-INF/README.md
53 | README.md
54 |
55 |
57 | META-INF/LICENSE.md
58 | LICENSE.md
59 |
60 |
61 |
62 |
63 | junit:junit
64 |
65 |
66 |
67 |
68 | de.mkammerer:*
69 |
70 | **
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | junit
82 | junit
83 | 3.8.1
84 | test
85 |
86 |
87 | de.mkammerer
88 | argon2-jvm
89 | 2.3
90 |
91 |
92 | a java benchmark of arionum's argon2i function. DOES NOT MINE
93 |
94 |
--------------------------------------------------------------------------------
/arionum-benchmark/src/main/java/com/programmerdan/arionum/arionum_benchmark/AdvMode.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_benchmark;
28 |
29 | public enum AdvMode {
30 | basic,
31 | experimental,
32 | stable
33 | }
34 |
--------------------------------------------------------------------------------
/arionum-benchmark/src/main/java/com/programmerdan/arionum/arionum_benchmark/BasicHasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_benchmark;
28 |
29 | import java.math.BigInteger;
30 | import java.security.MessageDigest;
31 | import java.security.NoSuchAlgorithmException;
32 | import java.security.SecureRandom;
33 | import java.util.Base64;
34 |
35 | import de.mkammerer.argon2.Argon2;
36 | import de.mkammerer.argon2.Argon2Factory;
37 | import de.mkammerer.argon2.Argon2Factory.Argon2Types;
38 |
39 | public class BasicHasher extends Hasher {
40 | public BasicHasher() {
41 | super();
42 | }
43 |
44 | @Override
45 | public void run() {
46 | active = true;
47 | long start = System.currentTimeMillis();
48 | long lastUpdate = start;
49 |
50 | byte[] nonce = new byte[32];
51 | String encNonce = null;
52 |
53 | StringBuilder hashBase = new StringBuilder();
54 | String base = null;
55 | byte[] byteBase = null;
56 | String argon = null;
57 |
58 | StringBuilder hashedHash = new StringBuilder();
59 |
60 | SecureRandom random = new SecureRandom();
61 |
62 | Argon2 argon2 = Argon2Factory.create(Argon2Types.ARGON2i);
63 |
64 | MessageDigest sha512 = null;
65 | try {
66 | sha512 = MessageDigest.getInstance("SHA-512");
67 | } catch (NoSuchAlgorithmException e1) {
68 | System.err.println("Unable to find SHA-512 algorithm! Fatal error.");
69 | e1.printStackTrace();
70 | System.exit(1);
71 | active = false;
72 | }
73 | if (active) {
74 | System.out.println("Spun up php-parity hashing worker in " + (System.currentTimeMillis() - start) + "ms");
75 | start = System.currentTimeMillis();
76 | }
77 |
78 | long statCycle = 0l;
79 | long statBegin = 0l;
80 | long statArgonBegin = 0l;
81 | long statArgonEnd = 0l;
82 | long statEnd = 0l;
83 |
84 | int cCount = 0;
85 | double speed = 0d;
86 | double avgSpeed = 0d;
87 |
88 | statCycle = System.currentTimeMillis();
89 |
90 | while (active) {
91 |
92 | if (System.currentTimeMillis()-lastUpdate > 2000) {
93 | System.out.println("--> Last hash rate: " + speed + " H/s Average: " + avgSpeed + " H/s Total hashes: " + hashCount + " Mining Time: " + ((System.currentTimeMillis() - start) / 1000d) +
94 | " Shares: " + shares + " Finds: " + finds);
95 | lastUpdate = System.currentTimeMillis();
96 | }
97 |
98 | statBegin = System.nanoTime();
99 | try {
100 | random.nextBytes(nonce);
101 | encNonce = Base64.getEncoder().encodeToString(nonce);
102 | encNonce = encNonce.replaceAll("[^a-zA-Z0-9]", ""); // TODO: static test vs other impls
103 | hashBase = new StringBuilder();
104 | hashBase.append(this.publicKey).append("-");
105 | hashBase.append(encNonce).append("-");
106 | hashBase.append(this.data).append("-");
107 | hashBase.append(this.difficultyString);
108 | statArgonBegin = System.nanoTime();
109 | argon = argon2.hash(4, 16384, 4, hashBase.toString());
110 | statArgonEnd = System.nanoTime();
111 | hashBase.append(argon);
112 |
113 | base = hashBase.toString();
114 | byteBase = base.getBytes();
115 | for (int i = 0; i < 5; i++) {
116 | byteBase = sha512.digest(byteBase);
117 | }
118 | byteBase = sha512.digest(byteBase);
119 | // see https://stackoverflow.com/a/33085670
120 | hashedHash = new StringBuilder(); // TODO: Timing tests.
121 | // for (int j = 0; j < byteBase.length; j++) {
122 | // hashedHash.append(Integer.toString((byteBase[j] & 0xff) +
123 | // 0x100, 16).substring(1));
124 | // }
125 | // or see https://stackoverflow.com/a/19722967
126 | BigInteger bi = new BigInteger(1, byteBase);
127 | hashedHash.append(String.format("%0" + (byteBase.length << 1) + "x", bi));
128 |
129 | StringBuilder duration = new StringBuilder();
130 | duration.append(hexdec_equiv(hashedHash, 10)).append(hexdec_equiv(hashedHash, 15))
131 | .append(hexdec_equiv(hashedHash, 20)).append(hexdec_equiv(hashedHash, 23))
132 | .append(hexdec_equiv(hashedHash, 31)).append(hexdec_equiv(hashedHash, 40))
133 | .append(hexdec_equiv(hashedHash, 45)).append(hexdec_equiv(hashedHash, 55));
134 |
135 | // TODO: Bypass double ended conversion; no reason to go from
136 | // binary to hex to dec; go straight from bin to dec for max
137 | // eff.
138 |
139 | long finalDuration = new BigInteger(duration.toString()).divide(this.difficulty).longValue();
140 | if (finalDuration > 0 && finalDuration <= this.limit) {
141 | if (finalDuration <= 240) {
142 | finds++;
143 | } else {
144 | shares++;
145 | }
146 | }
147 |
148 | //parent.bestDL.getAndUpdate( (dl) -> {if (finalDuration < dl) return finalDuration; else return dl;} );
149 |
150 | hashCount++;
151 | cCount++;
152 | //parent.hashes.incrementAndGet();
153 | //parent.currentHashes.incrementAndGet();
154 | statEnd = System.nanoTime();
155 | //parent.workerHash(this.id, finalDuration, statArgonEnd - statArgonBegin, (statArgonBegin - statBegin) + (statEnd - statArgonEnd));
156 |
157 | if (cCount == 100) {
158 | cCount = 0;
159 | long cycleEnd = System.currentTimeMillis();
160 | speed = 100d / ((cycleEnd - statCycle)/ 1000d);
161 | avgSpeed = (double) hashCount / ((cycleEnd - start) / 1000d);
162 | statCycle = cycleEnd;
163 | }
164 |
165 | } catch (Exception e) {
166 | System.err.println("This worker failed somehow. Killing it.");
167 | e.printStackTrace();
168 | active = false;
169 | }
170 | }
171 | System.out.println("This worker is now inactive.");
172 | }
173 |
174 | public int hexdec_equiv(StringBuilder m, int index) {
175 | return Integer.parseInt(m.substring(index * 2, index * 2 + 2), 16);
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/arionum-benchmark/src/main/java/com/programmerdan/arionum/arionum_benchmark/ExperimentalHasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_benchmark;
28 |
29 | import java.math.BigInteger;
30 | import java.security.MessageDigest;
31 | import java.security.NoSuchAlgorithmException;
32 | import java.security.SecureRandom;
33 | import java.util.Base64;
34 | import java.util.Base64.Encoder;
35 |
36 | import de.mkammerer.argon2.Argon2;
37 | import de.mkammerer.argon2.Argon2Factory;
38 | import de.mkammerer.argon2.Argon2Factory.Argon2Types;
39 |
40 | /**
41 | * The intent for this hasher is deeper self-inspection of running times of various components.
42 | * It can be used as a testbed for comparative performance. It is not meant to be used for general use
43 | *
44 | * This particular experimental hasher takes advantage of an observation: namely, that
45 | * we're doing double the randomness minimally necessary for the scheme, since the argon2i
46 | * implementation here and in the php reference internally salts the "password" with 32 bytes of
47 | * random data. So the nonce itself can be considered just a payload, fixed entity, and allow the
48 | * salting of the argon2i to control uniformly random generation of SHA-512 DL outcomes.
49 | *
50 | * This gives me 5-10% H/s speedups on isolated testing with no increase in rejections. Block
51 | * finds and shares remain as expected for H/s observed.
52 | *
53 | * Another indicator of improved performance is tracking reveals 99.97% of time is spent in argon2i
54 | * codepath, vs. between 99.8 and 99.9% for other cores. This might sound small but adds up in a big way
55 | * over time, as its a per-hash improvement.
56 | *
57 | * Once a nonce is submitted, it is discarded and a new one generated, as the pool does not allow
58 | * resubmission of prior nonces.
59 | *
60 | *
61 | * @author ProgrammerDan (Daniel Boston)
62 | *
63 | */
64 | public class ExperimentalHasher extends Hasher {
65 |
66 | public ExperimentalHasher() {
67 | }
68 |
69 | private SecureRandom random = new SecureRandom();
70 | private Encoder encoder = Base64.getEncoder();
71 | private String rawHashBase;
72 | private byte[] nonce = new byte[32];
73 | private String rawNonce;
74 |
75 | private long bestDL;
76 |
77 | /**
78 | */
79 | private void genNonce() {
80 | String encNonce = null;
81 | StringBuilder hashBase;
82 | random.nextBytes(nonce);
83 | encNonce = encoder.encodeToString(nonce);
84 |
85 | char[] nonceChar = encNonce.toCharArray();
86 |
87 | // shaves a bit off vs regex -- for this operation, about 50% savings
88 | StringBuilder nonceSb = new StringBuilder(encNonce.length());
89 | for (char ar : nonceChar) {
90 | if (ar >= '0' && ar <= '9' || ar >= 'a' && ar <= 'z' || ar >= 'A' && ar <= 'Z') {
91 | nonceSb.append(ar);
92 | }
93 | }
94 |
95 | // prealloc probably saves us 10% on this op sequence
96 | hashBase = new StringBuilder(hashBufferSize); // size of key + nonce + difficult + argon + data + spacers
97 | hashBase.append(this.publicKey).append("-");
98 | hashBase.append(nonceSb).append("-");
99 | hashBase.append(this.data).append("-");
100 | hashBase.append(this.difficultyString);
101 |
102 | rawNonce = nonceSb.toString();
103 | rawHashBase = hashBase.toString();
104 | bestDL = Long.MAX_VALUE;
105 | }
106 |
107 |
108 | @Override
109 | public void run() {
110 | active = true;
111 | long start = System.currentTimeMillis();
112 | long lastUpdate = start;
113 |
114 | StringBuilder hashBase = null;
115 | byte[] byteBase = null;
116 |
117 | String argon = null;
118 | Argon2 argon2 = Argon2Factory.create(Argon2Types.ARGON2i);
119 |
120 | MessageDigest sha512 = null;
121 | try {
122 | sha512 = MessageDigest.getInstance("SHA-512");
123 | } catch (NoSuchAlgorithmException e1) {
124 | System.err.println("Unable to find SHA-512 algorithm! Fatal error.");
125 | e1.printStackTrace();
126 | System.exit(1);
127 | active = false;
128 | }
129 | if (active) {
130 | System.out.println("Spun up EXPERIMENTAL hashing worker in " + (System.currentTimeMillis() - start) + "ms");
131 | start = System.currentTimeMillis();
132 | genNonce();
133 | }
134 |
135 | long statCycle = 0l;
136 | long statBegin = 0l;
137 | long statArgonBegin = 0l;
138 | long statArgonEnd = 0l;
139 | long statEnd = 0l;
140 | long stuck = 0;
141 |
142 | int cCount = 0;
143 | double speed = 0d;
144 | double avgSpeed = 0d;
145 |
146 | statCycle = System.currentTimeMillis();
147 |
148 | while (active) {
149 |
150 | if (System.currentTimeMillis()-lastUpdate > 2000) {
151 | System.out.println("--> Last hash rate: " + speed + " H/s Average: " + avgSpeed + " H/s Total hashes: " + hashCount + " Mining Time: " + ((System.currentTimeMillis() - start) / 1000d) +
152 | " Shares: " + shares + " Finds: " + finds);
153 | lastUpdate = System.currentTimeMillis();
154 | }
155 |
156 | statBegin = System.nanoTime();
157 | try {
158 | hashBase = new StringBuilder(this.hashBufferSize);
159 | statArgonBegin = System.nanoTime();
160 | argon = argon2.hash(4, 16384, 4, rawHashBase);
161 | statArgonEnd = System.nanoTime();
162 | hashBase.append(rawHashBase).append(argon);
163 |
164 | byteBase = hashBase.toString().getBytes();
165 | for (int i = 0; i < 5; i++) {
166 | byteBase = sha512.digest(byteBase);
167 | }
168 | byteBase = sha512.digest(byteBase);
169 |
170 | StringBuilder duration = new StringBuilder(25);
171 | duration.append(byteBase[10] & 0xFF).append(byteBase[15] & 0xFF).append(byteBase[20] & 0xFF)
172 | .append(byteBase[23] & 0xFF).append(byteBase[31] & 0xFF).append(byteBase[40] & 0xFF)
173 | .append(byteBase[45] & 0xFF).append(byteBase[55] & 0xFF);
174 |
175 | long finalDuration = new BigInteger(duration.toString()).divide(this.difficulty).longValue();
176 | if (finalDuration > 0 && finalDuration <= this.limit) {
177 | if (finalDuration <= 240) {
178 | finds++;
179 | } else {
180 | shares++;
181 | }
182 | genNonce(); // only gen a new nonce once we exhaust the one we had
183 | }
184 |
185 | hashCount++;
186 | cCount++;
187 | statEnd = System.nanoTime();
188 |
189 | if (finalDuration < this.bestDL) { // split the difference; if we're not getting movement after a while, just move on
190 | this.bestDL = finalDuration;
191 | stuck = 0;
192 | } else {
193 | stuck++;
194 | if (stuck > avgSpeed * 15) {
195 | genNonce();
196 | stuck = 0;
197 | }
198 | }
199 |
200 |
201 | if (cCount == 100) {
202 | cCount = 0;
203 | long cycleEnd = System.currentTimeMillis();
204 | speed = 100d / ((cycleEnd - statCycle)/ 1000d);
205 | avgSpeed = (double) hashCount / ((cycleEnd - start) / 1000d);
206 | statCycle = cycleEnd;
207 | }
208 |
209 | } catch (Exception e) {
210 | System.err.println("This worker failed somehow. Killing it.");
211 | e.printStackTrace();
212 | active = false;
213 | }
214 | }
215 | System.out.println("This worker is now inactive.");
216 | }
217 |
218 | }
219 |
--------------------------------------------------------------------------------
/arionum-benchmark/src/main/java/com/programmerdan/arionum/arionum_benchmark/Hasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_benchmark;
28 |
29 | import java.math.BigInteger;
30 |
31 | /**
32 | * Abstraction layer to allow multiple miner definitions.
33 | *
34 | *
35 | * @author ProgrammerDan (Daniel Boston)
36 | *
37 | */
38 | public class Hasher implements Runnable {
39 |
40 | protected BigInteger difficulty = BigInteger.valueOf(100000000);
41 | protected String difficultyString = "100000000";
42 | protected String data = "sampledatafornode";
43 | protected int hashBufferSize;
44 | protected long limit = 50000;
45 | protected String publicKey = "4SxMLLWRCxoL42gqgf2C2x5T5Q1BJhgfQvMsfwrcFAu4owsBYncsvVnBBVqtxVrkqHVZ8nJGrcJB7yWnV92j5Rca";
46 |
47 | // local stats stores, retrieved "off thread"
48 | protected long shares;
49 | protected long finds;
50 |
51 | /* Timing Stats, current */
52 | protected long hashCount;
53 |
54 | protected boolean active;
55 |
56 | public static void main(String[] args) {
57 | if (args == null && args.length < 1) {
58 | System.err.println("Pass in core to test: stable | experimental | basic");
59 | System.err.println();
60 | System.exit(1);
61 | }
62 |
63 | Hasher hasher = null;
64 | AdvMode which = AdvMode.valueOf(args[0]);
65 | switch (which) {
66 | case basic:
67 | hasher = new BasicHasher();
68 | break;
69 | case experimental:
70 | hasher = new ExperimentalHasher();
71 | break;
72 | case stable:
73 | hasher = new StableHasher();
74 | break;
75 | }
76 |
77 | hasher.run();
78 |
79 | }
80 |
81 | @Override
82 | public void run() {}
83 |
84 | public Hasher() {
85 | this.hashCount = 0l;
86 | }
87 |
88 | public long getHashes() {
89 | return this.hashCount;
90 | }
91 |
92 | public boolean isActive() {
93 | return active;
94 | }
95 |
96 | }
--------------------------------------------------------------------------------
/arionum-benchmark/src/main/java/com/programmerdan/arionum/arionum_benchmark/StableHasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_benchmark;
28 |
29 | import java.math.BigInteger;
30 | import java.security.MessageDigest;
31 | import java.security.NoSuchAlgorithmException;
32 | import java.security.SecureRandom;
33 | import java.util.Base64;
34 | import java.util.Base64.Encoder;
35 |
36 | import de.mkammerer.argon2.Argon2;
37 | import de.mkammerer.argon2.Argon2Factory;
38 | import de.mkammerer.argon2.Argon2Factory.Argon2Types;
39 |
40 | /**
41 | * The intent for this hasher is deeper self-inspection of running times of various components.
42 | * It can be used as a testbed for comparative performance. It is not meant to be used for general use
43 | *
44 | * @author ProgrammerDan (Daniel Boston)
45 | *
46 | */
47 | public class StableHasher extends Hasher {
48 |
49 | public StableHasher() {
50 |
51 | }
52 |
53 |
54 | @Override
55 | public void run() {
56 | active = true;
57 | long start = System.currentTimeMillis();
58 | long lastUpdate = start;
59 |
60 | byte[] nonce = new byte[32];
61 | String encNonce = null;
62 |
63 | StringBuilder hashBase = new StringBuilder();
64 | String base = null;
65 | byte[] byteBase = null;
66 | String argon = null;
67 |
68 | Encoder encoder = Base64.getEncoder();
69 | char[] nonceChar = null;
70 | StringBuilder nonceSb = null;
71 |
72 | SecureRandom random = new SecureRandom();
73 |
74 | Argon2 argon2 = Argon2Factory.create(Argon2Types.ARGON2i);
75 |
76 | MessageDigest sha512 = null;
77 | try {
78 | sha512 = MessageDigest.getInstance("SHA-512");
79 | } catch (NoSuchAlgorithmException e1) {
80 | System.err.println("Unable to find SHA-512 algorithm! Fatal error.");
81 | e1.printStackTrace();
82 | System.exit(1);
83 | active = false;
84 | }
85 | if (active) {
86 | System.out.println("Spun up Stable hashing worker in " + (System.currentTimeMillis() - start) + "ms");
87 | start = System.currentTimeMillis();
88 | }
89 |
90 | long statCycle = 0l;
91 | long statBegin = 0l;
92 | long statArgonBegin = 0l;
93 | long statArgonEnd = 0l;
94 | long statEnd = 0l;
95 |
96 | int cCount = 0;
97 | double speed = 0d;
98 | double avgSpeed = 0d;
99 |
100 | statCycle = System.currentTimeMillis();
101 |
102 | while (active) {
103 |
104 | if (System.currentTimeMillis()-lastUpdate > 2000) {
105 | System.out.println("--> Last hash rate: " + speed + " H/s Average: " + avgSpeed + " H/s Total hashes: " + hashCount + " Mining Time: " + ((System.currentTimeMillis() - start) / 1000d) +
106 | " Shares: " + shares + " Finds: " + finds);
107 | lastUpdate = System.currentTimeMillis();
108 | }
109 |
110 | statBegin = System.nanoTime();
111 | try {
112 | random.nextBytes(nonce);
113 | encNonce = encoder.encodeToString(nonce);
114 |
115 | // shaves a bit off vs regex -- for this operation, about 50% savings
116 | nonceSb = new StringBuilder(encNonce.length());
117 | nonceChar = encNonce.toCharArray();
118 | for (char ar : nonceChar) {
119 | if (ar >= '0' && ar <= '9' || ar >= 'a' && ar <= 'z' || ar >= 'A' && ar <= 'Z') {
120 | nonceSb.append(ar);
121 | }
122 | }
123 |
124 | // prealloc probably saves us 10% on this op sequence
125 | // TODO: precompute this length when data is received
126 | hashBase = new StringBuilder(hashBufferSize); // size of key + none + difficult + argon + data + spacers
127 | hashBase.append(this.publicKey).append("-");
128 | hashBase.append(nonceSb).append("-");
129 | hashBase.append(this.data).append("-");
130 | // TODO: precompute difficulty as string
131 | hashBase.append(this.difficultyString);
132 | statArgonBegin = System.nanoTime();
133 | argon = argon2.hash(4, 16384, 4, hashBase.toString());
134 | statArgonEnd = System.nanoTime();
135 | hashBase.append(argon);
136 |
137 | base = hashBase.toString();
138 | byteBase = base.getBytes();
139 | for (int i = 0; i < 5; i++) {
140 | byteBase = sha512.digest(byteBase);
141 | }
142 | byteBase = sha512.digest(byteBase);
143 |
144 | StringBuilder duration = new StringBuilder(25);
145 | duration.append(byteBase[10] & 0xFF).append(byteBase[15] & 0xFF).append(byteBase[20] & 0xFF)
146 | .append(byteBase[23] & 0xFF).append(byteBase[31] & 0xFF).append(byteBase[40] & 0xFF)
147 | .append(byteBase[45] & 0xFF).append(byteBase[55] & 0xFF);
148 |
149 | long finalDuration = new BigInteger(duration.toString()).divide(this.difficulty).longValue();
150 | if (finalDuration > 0 && finalDuration <= this.limit) {
151 | if (finalDuration < 240) {
152 | finds++;
153 | } else {
154 | shares++;
155 | }
156 | }
157 |
158 | hashCount++;
159 | cCount++;
160 | statEnd = System.nanoTime();
161 |
162 | if (cCount == 100) {
163 | cCount = 0;
164 | long cycleEnd = System.currentTimeMillis();
165 | speed = 100d / ((cycleEnd - statCycle)/ 1000d);
166 | avgSpeed = (double) hashCount / ((cycleEnd - start) / 1000d);
167 | statCycle = cycleEnd;
168 | }
169 |
170 | } catch (Exception e) {
171 | System.err.println("This worker failed somehow. Killing it.");
172 | e.printStackTrace();
173 | active = false;
174 | }
175 | }
176 | System.out.println("This worker is now inactive.");
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/arionum-miner/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | *.exe
3 | *.jar
4 | /*.sh
5 | /*.bat
6 | *.cfg
7 | **/dependency-reduced-pom.xml
8 | dependency-reduced-pom.xml
9 | .project
10 | .classpath
11 | .settings/
12 |
--------------------------------------------------------------------------------
/arionum-miner/DOCS.md:
--------------------------------------------------------------------------------
1 | Extended Documentation for Java port of Arionum-miner
2 | ==========================
3 |
4 | # Installation
5 |
6 | Choose which image you want to install from the downloads below.
7 |
8 | If your hardware supports AVX or AVX2 and you are a Windows user, download the correctly named EXE and run. If your system does not support it, you will know on launch as it will fail noisily. If you know your system supports AVX512F, please contact me on Discord. All prior testing of AVX512F builds on Windows were unsuccessful, but I can work with you to see what we can accomplish.
9 |
10 | If you see crazy high hashrates, you are using 32bit java and these programs will _not_ function. Immediately shut off miner and go here: http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html and download a 64 bit jre.
11 |
12 | # Release details:
13 |
14 | * Replaced `standard` and `enhanced` hashers with a hasher that trades a very small (0.1% or so) hashrate for significantly improved accept rate, as the method of creating salts and nonces matches the code that will verify them. In addition, improved affinity and memory handling quickly moves away from memory that results in rejected hashes; only "successful" memory is kept, and its kept for a long time.
15 |
16 | * Better handling in general of the differences in affinity and memory handling between Windows and Linux
17 |
18 | # General Details:
19 |
20 | * Auto-adapt to block 10800-hf-resistance to remain compliance with primary node code.
21 |
22 | * Re-architected to use CPU affinity and single-threaded argon, so that each core can be pegged individually.
23 |
24 | * Improved stats, including colorized display for Windows and \*nix
25 |
26 | * Advanced installation options for maximizing performance.
27 |
28 | ## Advanced installation:
29 |
30 | ### Windows:
31 |
32 | 1. Install Maven, git, and Java 8 JDK (minimum).
33 |
34 | 2. Clone this repository locally, and navigate to `arionum-miner` folder.
35 |
36 | 3. Run `mvn clean package`
37 |
38 | 4. Run in a Command Prompt: `pick-argon.bat` -- it will ask for Administrator escalation, this is to check for hardware features, please accept.
39 |
40 | 5. Run miner using `run.bat`.
41 |
42 | Alternatively, if you know that your CPU supports AVX2 or AVX instructions, download the appropriate pre-built .exe here.
43 |
44 | If you are truly a glutton for punishment, you can download Visual Studio, import the argon2i library that I host here: http://github.com/ProgrammerDan/arionum-argon2 import it into visual studio, and build it locally. No warrantees, but you can use the Static Release profiles.
45 |
46 |
47 | ### Linux:
48 |
49 | 1. Install Maven, git, 64bit Java 8 JDK, make, and gcc.
50 |
51 | 2. Clone this repository locally, and navigate to `arionum-miner` folder.
52 |
53 | 3. Run `mvn clean package`
54 |
55 | 4. Run `chmod +x build-argon.sh`
56 |
57 | 5. Run `build-argon.sh`
58 |
59 | 6. Run miner using `run.sh` -- this will use the locally built high-performance argon2i libraries automatically.
60 |
61 | For Linux users, I _strongly_ recommend using these instructions.
62 |
63 | ---------------------------
64 |
65 | # Advanced Runtime Support
66 |
67 | New as of 0.1.0 and later versions, just run the miner! Don't mess with command line flags.
68 |
69 | If you want to use command line flags, however, follow along:
70 |
71 | ----------------------------
72 |
73 | For multi-preconfigs, simply pass the name of the config file as the first and only command line flag:
74 |
75 | ``` java -jar arionum-miner-java.jar my-custom-config.cfg```
76 |
77 | And if that config doesn't exist, it will create it with the answers you give to the prompts. If it does exist, it will load it and use it.
78 |
79 |
80 | ----------------------------
81 |
82 | For pool-based mining, full command line flags:
83 |
84 | ``` java -jar arionum-miner-java.jar pool [pool address] [wallet address] [# hashers] [hasher core] [colored output]```
85 |
86 | **pool address**: If you use the main pool, http://aropool.com -- if you host your own pool, use that pool's address.
87 |
88 | **wallet address**: Your Wallet address, or the wallet address you want to gain credit for your mining.
89 |
90 | **# hashers**: A number greater then 0 indicating how many hashers to run within this single miner instance. Be warned, more hashers does not always lead to higher Hr/s -- experiment with this value to find the best for your system.
91 |
92 | **hasher core**: Currently, one of:
93 |
94 | `standard`: Stable, best, most improved with best speed AND acceptance.
95 |
96 | `experimental`: Less handling for affinity and memory, use standard.
97 |
98 | **colored output**: Only supported in linux, set to true to add some color to the output of the statistic updates. Note, this isn't working yet.
99 |
100 | --------------------
101 |
102 | For solo mining, full command line flags:
103 |
104 | ``` java -jar arionum-miner-java.jar solo [node address] [public-key] [private-key] [# hashers] [hasher core] [colored output]```
105 |
106 | **node address**: The address of the node you want to directly send discovered blocks
107 |
108 | **public key**: Your Wallet address, or the wallet address you want to gain credit for your mining.
109 |
110 | **private key**: Private key to use to sign the payout transaction.
111 |
112 | **# hashers**: A number greater then 0 indicating how many hashers to run within this single miner instance. Be warned, more hashers does not always lead to higher Hr/s -- experiment with this value to find the best for your system.
113 |
114 | **hasher core**: Currently, one of:
115 |
116 | `standard`: Stable, best, most improved with best speed AND acceptance.
117 |
118 | `experimental`: Less handling for affinity and memory, use standard.
119 |
120 | **colored output**: Only supported in linux, set to true to add some color to the output of the statistic updates.
121 |
122 | Be sure you trust the node you are using; and be aware that the hasher's host needs to be specifically allowed by the node you are connecting to.
123 |
124 | Be aware that at present, all data is sent in the clear -- you might want to use a secure VPN or exclusively mine towards local network nodes.
125 |
--------------------------------------------------------------------------------
/arionum-miner/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
3 |
4 | www.arionum.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of
15 | the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
23 | OR OTHER DEALINGS IN THE SOFTWARE.
24 |
25 |
26 | Libraries used (such as argon2-jvm and json-simple) are covered by their own licenses, I use them as-is without warranty.
27 |
--------------------------------------------------------------------------------
/arionum-miner/README.md:
--------------------------------------------------------------------------------
1 | Arionum Miner port for Java
2 | ====================
3 | by ProgrammerDan, Jan 2018
4 | based on https://github.com/arionum/miner a work by AroDev
5 |
6 | Originally a fun evening project to port the PHP miner to Java that has become a bit of a passion.
7 |
8 | Confirmed working, has been used to find blocks.
9 |
10 | Includes a few improvements over the reference implementation, mostly with threaded handling of update requests and submit requests.
11 |
12 | That way, the miner threads can keep on mining, and aren't held up by the update / submit cycles.
13 |
14 | Please note this release includes at-your-own-risk 80k hardfork support. This is a work in progress! It will likely do weird things!
15 | As always, refer back to reference PHP miner if issues emerge.
16 |
17 | Enjoy!
18 |
19 | #### How to run
20 |
21 | Get dependency:
22 |
23 | * 64bit Java 8 JRE (OpenJRE 8 and Oracle Java 8 both work just fine)
24 |
25 | * On Linux or MacOSX, download the latest ".jar" release file
26 |
27 | * If you've got it on your desktop, you should be able to doubleclick it.
28 |
29 | * If that doesn't work, open a shell, go to the download folder, and run `./jar -java arionum-miner-java.jar`
30 |
31 | * On Windows, download the latest ".exe" release file
32 |
33 | * Double click the .exe to run
34 |
35 | * For some advanced systems, a special, optimized version is available. Check if your CPU supports AVX or AVX2 and use that version if supported.
36 |
37 | * Follow interactive prompt -- if a default is offered, press "enter" key to accept it. I recommend using defaults.
38 |
39 | * Configuration is automatically saved and used again when you open the miner up next
40 |
41 | * Default config is `config.cfg` in the same folder as the .jar or .exe -- open it in any text editor to modify
42 |
43 | #### To compile on Linux
44 |
45 | Get depencies
46 |
47 | * Maven
48 |
49 | * git
50 |
51 | * 64bit Java 8 SDK (OpenJDK8 and Oracle Java 8 both work just fine)
52 |
53 | Clone this repository, change directory into ```arionum-miner```
54 |
55 | Execute ```mvn clean package``` -- this will build the miner
56 |
57 | Run ```./build-argon.sh``` -- this will build the argon and run shell
58 |
59 | Launch with ```./run.sh``` -- follow interactive prompts to set up.
60 |
61 | For windows build instructions, check DOCS.md
62 |
63 | ##### Summary:
64 |
65 | Pick a place to install. For linux:
66 |
67 | `sudo apt-get install maven git openjdk-8-jdk`
68 |
69 | `git clone git://github.com/ProgrammerDan/arionum-java`
70 |
71 | `cd arionum-java/arionum-miner`
72 |
73 | `mvn clean package`
74 |
75 | `./run.sh`
76 |
77 | #### To run
78 |
79 | ##### For Linux / Mac OS:
80 |
81 | Execute `java -jar arionum-miner-java.jar` and follow the prompts on screen
82 |
83 | ##### For Windows:
84 |
85 | Execute `arionum-miner-java.exe` and follow the prompts on screen
86 |
87 | ##### For All:
88 |
89 | Take the defaults to run the pool, pointing at http://aropool.com , using your wallet address. If you take the defaults, the "standard" miner will run, using cores - 1.
90 |
91 |
92 | ##### For solo mining in Linux:
93 |
94 | Execute `java -jar arionum-miner-java.jar` and follow the prompts on screen, choose "solo" instead of pool.
95 |
96 | Please note solo hasn't been tested, but it's 99.9% the same code so should be fine. Pool has been extensively tested.
97 |
98 |
99 | ##### General advice:
100 |
101 | Rule of thumb is no more then 1 miner per core/vcore.
102 |
103 | ----------------------
104 | # Comparison to php-miner
105 |
106 | Similarities:
107 |
108 | * Can be used for solo or pool mining
109 |
110 | * Checks for valid address (on pool) before activating
111 |
112 | * Command Line tool
113 |
114 | * Same hashing functions, same CPU bounds -- both bind to a C library version of argon2i hashing, so both are fast
115 |
116 | * Can run multiple instances if desired -- I recommend you use screen, tmux, or byobu for better monitoring
117 |
118 | Differences:
119 |
120 | * One JVM can run multiple hashers and share the same "update" requests to the pool, reducing traffic to the pool or node
121 |
122 | * The hashers never stop -- the reference PHP implementation pauses the hasher during update requests and nonce submissions. The java hashers never stop.
123 |
124 | * Hasher threads will try to affine to CPU cores -- "reserve" the core all to themselves.
125 |
126 | * Small to significant optimizations -- some "micro", some significant via cpu instruction sets. See release instructions for more details.
127 |
128 | * More information on active hashing activity -- screen updates every few seconds with details on active hashers, how many hashes they have checked, and how close to finding shares or blocks
129 |
130 | * Visual notice when a new block has started, with the "difficulty" for the new block, and your personal best DL for the prior block. Note that difficulty is inverse -- smaller is harder, larger is easier.
131 |
132 | ---------------------
133 | ### TODO
134 |
135 | * ~~Add address checking as here: https://github.com/arionum/miner/commit/e14b696362fb79d60c4ff8bc651185740b8021d9~~ Done in commit dd5388c
136 |
137 | * ~~Colored screen output to better see labels / stats and keep track of hashers~~
138 |
139 | * Auto-adaptive hashing -- automatically add more hasher instances until peak rate is achieved
140 |
141 | * Variable intensity -- allow hashing to take a back seat to other computer activity
142 |
143 | ---------------------
144 | ### Known caveates
145 |
146 | * For multi-socket systems, try running a single full instance of the Java miner per socket. Use operating system tools to bind to the socket.
147 |
148 | * Hash Rate is "best effort", and might be imprecise. Pool Hash Rate is based on self-reporting, so minor inaccuracies are not an issue. Difficulty is based on median time between block discovery.
149 |
150 | ---------------------
151 | ### Testing
152 |
153 | If you encounter any problems, open an issue here or email me at programmerdan@gmail.com -- I'm also ProgrammerDan#7586 in the Arionum discord -- feel free to PM me.
154 |
155 | ---------------------
156 | ### Advanced Use
157 |
158 | See DOCS.md for advanced use, compilation, and other instructions.
159 |
--------------------------------------------------------------------------------
/arionum-miner/WINDOWS_COMPILE_GUIDE.md:
--------------------------------------------------------------------------------
1 | ## Compile guide for Windows 10 for using ProgrammerDan's Java mining tool
2 |
3 | ### Do you need to compile?
4 |
5 | Only use these steps if the release `.exe` doesn't work for you, otherwise, prefer to use the release as it will be most stable, most tested, and easiest to run. If it fails, follow the steps below.
6 |
7 | ### Necessary program's
8 | - [Maven](https://maven.apache.org/)
9 | - [Git](https://desktop.github.com/)
10 | - [64Bit JavaSDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
11 |
12 | ### Installation
13 | 1. Install all above programs
14 | 2. Create a [GitHub account](https://github.com/join?source=header-repo)
15 | 3. Log in with GitHub Desktop client.
16 | 4. Via File → Clone Repository go to tab URL and paste the following URL https://github.com/ProgrammerDan/arionum-java.
17 |
18 | You'll now have a clone of the Aronium-miner on your PC.
19 |
20 | 5. **Important**: Check system variables and see whether JAVA_HOME is registered as a system variable.
21 | - Windows 10: Press windows key, go to “Edit the system environment variables” . If prior to Windows 10, check this guide instead: https://www.java.com/en/download/help/path.xml
22 | - On the bottom click “Environment variables”
23 | - Bottom variables are the “System variables”
24 | - Check whether JAVA_HOME is in there, else;
25 | - Click new
26 | - In “Name of” fill in JAVA_HOME
27 | - In “Value of” put in the directory of the JavaSDK
28 | 6. Start up a command prompt
29 | 7. Navigate towards the aronium-miner directory (the one with the POM.xml file)
30 | 8. Execute “mvn clean package” (do not used quotes)
31 | 9. Run "pick-argon.bat" and follow the prompts to choose a pre-built argon2i library.
32 | 10. **Run the run.bat file.** Follow on screen prompts to configure your miner.
33 | 11. **Rename the aronium-java folder** to arionum-miner to avoid conflicts with GitHub Desktop if you want to catch the latest release.
34 |
35 | Need help? Contact Rezegen or ProgrammerDan for more help!
36 |
37 | Do not forget to donate ProgrammerDan for his awesome program:
38 | 4SxMLLWRCxoL42gqgf2C2x5T5Q1BJhgfQvMsfwrcFAu4owsBYncsvVnBBVqtxVrkqHVZ8nJGrcJB7yWnV92j5Rca
39 |
40 |
--------------------------------------------------------------------------------
/arionum-miner/pom-arm.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.programmerdan.arionum
6 | arionum-miner
7 | 0.2.6.1-SNAPSHOT
8 | jar
9 |
10 | arionum-miner-java
11 | https://github.com/ProgrammerDan/arionum-java/arionum-miner
12 |
13 |
14 | UTF-8
15 | 1.8
16 | 1.8
17 |
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-compiler-plugin
24 | 3.5.1
25 |
26 | 1.8
27 | 1.8
28 |
29 |
30 |
31 | org.apache.maven.plugins
32 | maven-shade-plugin
33 | 2.4.3
34 |
35 |
36 | package
37 |
38 | shade
39 |
40 |
41 |
42 |
43 | true
44 |
45 |
47 |
48 | com.programmerdan.arionum.arionum_miner.Miner
49 |
50 |
51 |
53 | META-INF/README.md
54 | README.md
55 |
56 |
58 | META-INF/LICENSE.md
59 | LICENSE.md
60 |
61 |
62 |
63 |
64 | junit:junit
65 |
66 |
67 |
68 |
69 | com.googlecode.json-simple:*
70 |
71 | **
72 |
73 |
74 |
75 |
76 |
77 |
78 | org.apache.maven.plugins
79 | maven-antrun-plugin
80 |
81 |
82 | Generate Executions
83 | prepare-package
84 |
85 | run
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | Forward one-clicks
102 | package
103 |
104 | run
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | net.java.dev.jna
124 | jna
125 | 4.5.0
126 | compile
127 |
128 |
129 | junit
130 | junit
131 | 3.8.1
132 | test
133 |
134 |
135 | com.googlecode.json-simple
136 | json-simple
137 | 1.1.1
138 |
139 |
140 | net.openhft
141 | affinity
142 | 3.1.7
143 |
144 |
145 | com.diogonunes
146 | JCDP
147 | 2.0.3.1
148 |
149 |
150 | org.slf4j
151 | slf4j-nop
152 | 1.7.25
153 |
154 |
155 | A full featured Java implementation of the Arionum miner. Portions derived from the php reference miner.
156 |
157 |
--------------------------------------------------------------------------------
/arionum-miner/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.programmerdan.arionum
6 | arionum-miner
7 | 0.2.6.1-SNAPSHOT
8 | jar
9 |
10 | arionum-miner-java
11 | https://github.com/ProgrammerDan/arionum-java/arionum-miner
12 |
13 |
14 | UTF-8
15 | 1.8
16 | 1.8
17 |
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-compiler-plugin
24 | 3.5.1
25 |
26 | 1.8
27 | 1.8
28 |
29 |
30 |
31 | org.apache.maven.plugins
32 | maven-shade-plugin
33 | 2.4.3
34 |
35 |
36 | package
37 |
38 | shade
39 |
40 |
41 |
42 |
43 | true
44 |
45 |
47 |
48 | com.programmerdan.arionum.arionum_miner.Miner
49 |
50 |
51 |
53 | META-INF/README.md
54 | README.md
55 |
56 |
58 | META-INF/LICENSE.md
59 | LICENSE.md
60 |
61 |
62 |
63 |
64 | junit:junit
65 |
66 |
67 |
68 |
69 | com.googlecode.json-simple:*
70 |
71 | **
72 |
73 |
74 |
75 |
76 |
77 |
78 | com.akathist.maven.plugins.launch4j
79 | launch4j-maven-plugin
80 | 1.7.21
81 |
82 |
83 | l4j-cli-pkg
84 | package
85 |
86 | launch4j
87 |
88 |
89 | false
90 | console
91 | target/${project.build.finalName}-shaded.jar
92 | target/arionum-java-miner-${project.version}.exe
93 |
94 |
95 | .
96 | normal
97 | http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html
98 |
99 | true
100 | false
101 |
102 |
103 |
104 |
105 | false
106 | false
107 | 1.8.0
108 |
109 | preferJre
110 | 64
111 |
112 |
113 | 0.2.5.0
114 | ${project.version}
115 | Arionum Miner in Java
116 | 2018 AroDev, portions ProgrammerDan (MIT license)
117 | 0.2.5.0
118 | ${project.version}
119 | Arionum Miner in Java
120 |
121 | Arionum Miner
122 | ${project.name}.exe
123 |
124 | ENGLISH_US
125 |
126 |
127 | An error occurred while starting the application.
128 | This application was configured to use a bundled
129 | Java Runtime Environment but the runtime is missing or
130 | corrupted.
131 | This application requires a Java 8 Runtime
132 | Environment
133 | The registry refers to a nonexistent Java Runtime
134 | Environment installation or the runtime is corrupted.
135 | An application instance is already
136 | running.
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | org.apache.maven.plugins
145 | maven-antrun-plugin
146 |
147 |
148 | Generate Executions
149 | prepare-package
150 |
151 | run
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 | Forward one-clicks
184 | package
185 |
186 | run
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 | net.java.dev.jna
211 | jna
212 | 4.5.0
213 | compile
214 |
215 |
216 | junit
217 | junit
218 | 3.8.1
219 | test
220 |
221 |
222 | com.googlecode.json-simple
223 | json-simple
224 | 1.1.1
225 |
226 |
227 | net.openhft
228 | affinity
229 | 3.1.7
230 |
231 |
232 | com.diogonunes
233 | JCDP
234 | 2.0.3.1
235 |
236 |
237 | org.slf4j
238 | slf4j-nop
239 | 1.7.25
240 |
241 |
242 | A full featured Java implementation of the Arionum miner. Portions derived from the php reference miner.
243 |
244 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/bin/build-argon-arm.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo This runscript will attempt to clone and build a custom version of argon2i for use with this miner.
4 | echo It will also modify the run.sh file to use the built version of argon2i.
5 | echo It requires git, make, and gcc to be installed. It assumes you have a 64 bit cpu.
6 |
7 | git clone git://github.com/ProgrammerDan/arionum-argon2 arionum-argon
8 |
9 | cd arionum-argon
10 |
11 | git remote set-url origin git://github.com/ProgrammerDan/arionum-argon2
12 |
13 | git pull
14 |
15 | echo "We will use master branch, as it is the most stable arionum-focused trimmed release of argon2i available."
16 |
17 | git checkout master
18 |
19 | git pull
20 |
21 | echo "For ARM, we remove the 64bit target"
22 | echo " You will need to customize these flags if on other architectures."
23 |
24 | make clean && CFLAGS="" OPTTARGET=native NO_THREADS=1 make
25 |
26 | echo "#! /bin/bash
27 | java -Djna.library.path=\"`pwd`\" -jar arionum-miner-java.jar" > ../run.sh
28 |
29 | chmod +x ../run.sh
30 |
31 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/bin/build-argon.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo This runscript will attempt to clone and build a custom version of argon2i for use with this miner.
4 | echo It will also modify the run.sh file to use the built version of argon2i.
5 | echo It requires git, make, and gcc to be installed. It assumes you have a 64 bit cpu.
6 |
7 | git clone git://github.com/ProgrammerDan/arionum-argon2 arionum-argon
8 |
9 | cd arionum-argon
10 |
11 | git remote set-url origin git://github.com/ProgrammerDan/arionum-argon2
12 |
13 | git pull
14 |
15 | echo "We will use master branch, as it is the most stable arionum-focused trimmed release of argon2i available."
16 |
17 | git checkout master
18 |
19 | git pull
20 |
21 | echo "By default we will use a variety of flags to ensure best build for 64 bit x86 compatible hardware."
22 | echo " You will need to customize these flags if on other architectures."
23 |
24 | make clean && CFLAGS="-m64" OPTTARGET=native NO_THREADS=1 make
25 |
26 | case "$OSTYPE" in
27 | darwin*) cp libargon2.1.dylib libargon2.dylib;;
28 | *) cp libargon2.so.1 libargon2.so;;
29 | esac
30 |
31 | echo "#! /bin/bash
32 | java -Djna.library.path=\"`pwd`\" -jar arionum-miner-java.jar" > ../run.sh
33 |
34 | chmod +x ../run.sh
35 |
36 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/bin/pick-argon.bat:
--------------------------------------------------------------------------------
1 | @Echo OFF
2 | echo This runscript will attempt to pick the best custom version of argon2i for use with this miner.
3 | echo It will also modify the run.bat file to use the built version of argon2i.
4 | echo Note that this script will launch a powershell in administrator mode. Please give it permission.
5 |
6 | pause
7 |
8 | set scriptFileName=%~n0
9 | set scriptFolderPath=%~dp0
10 | set powershellScriptFileName=%scriptFileName%.ps1
11 |
12 | powershell -Command "Start-Process powershell \"-ExecutionPolicy Bypass -NoProfile -Command `\"cd \`\"%scriptFolderPath%`\"; & \`\".\%powershellScriptFileName%\`\"`\"\" -Verb RunAs"
13 |
14 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/bin/pick-argon.ps1:
--------------------------------------------------------------------------------
1 | If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
2 |
3 | {
4 | $arguments = "& '" + $myinvocation.mycommand.definition + "'"
5 | Start-Process powershell -Verb runAs -ArgumentList $arguments
6 | Break
7 | }
8 |
9 | $source = "https://download.sysinternals.com/files/Coreinfo.zip"
10 |
11 | rmdir -Force -Recurse Coreinfo
12 |
13 | curl $source -OutFile Coreinfo.zip
14 |
15 | Expand-Archive Coreinfo.zip
16 |
17 | cd Coreinfo
18 |
19 | $extensions = .\Coreinfo.exe /accepteula
20 |
21 | $avx512f = select-string -Pattern "AVX512F" -InputObject $extensions
22 | $avx2 = select-string -Pattern "AVX2" -InputObject $extensions
23 | $avx = select-string -Pattern "AVX" -InputObject $extensions
24 |
25 | cd ..
26 |
27 | if (-not ([string]::IsNullOrEmpty($avx512f)))
28 | {
29 | echo "Found AVX512F extensions."
30 | cp src\main\resources\win32-x86-64\argon2-avx512f.dll argon2.dll
31 | }
32 | elseif (-not ([string]::IsNullOrEmpty($avx2)))
33 | {
34 | echo "Found AVX2 extensions."
35 | cp src\main\resources\win32-x86-64\argon2-avx2.dll argon2.dll
36 | }
37 | elseif (-not ([string]::IsNullOrEmpty($avx)))
38 | {
39 | echo "Found AVX extensions."
40 | cp src\main\resources\win32-x86-64\argon2-avx.dll argon2.dll
41 | }
42 | else
43 | {
44 | echo "Did not find any CPU acceleration."
45 | cp src\main\resources\win32-x86-64\argon2.dll argon2.dll
46 | }
47 |
48 | echo "Run the run.bat file to launch java using the best discovered argon2 library."
49 |
50 | sleep 8
51 | exit
52 |
53 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/bin/run.bat:
--------------------------------------------------------------------------------
1 | java -Djna.library.path="%cd%" -jar arionum-miner-java.jar
2 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/bin/run.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | java -jar arionum-miner-java.jar
4 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/AdvMode.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | /**
30 | * Controls runmode
31 | *
32 | * @author ProgrammerDan
33 | *
34 | */
35 | public enum AdvMode {
36 |
37 | standard(true),
38 | enhanced(true),
39 | legacy(false),
40 | experimental(false),
41 | basic(false),
42 | stable(false),
43 | auto(false),
44 | gpu(false),
45 | mixed(false);
46 |
47 | boolean use;
48 |
49 | AdvMode(boolean use) {
50 | this.use = use;
51 | }
52 |
53 | public boolean useThis() {
54 | return use;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/AggressiveAffinityThreadFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | import java.util.ArrayList;
30 | import java.util.concurrent.ConcurrentHashMap;
31 |
32 | import java.util.concurrent.ThreadFactory;
33 |
34 | import net.openhft.affinity.AffinityLock;
35 | import net.openhft.affinity.AffinityStrategies;
36 | import net.openhft.affinity.AffinitySupport;
37 | import net.openhft.affinity.CpuLayout;
38 | import net.openhft.affinity.Affinity;
39 |
40 | public class AggressiveAffinityThreadFactory implements ThreadFactory {
41 |
42 | /**
43 | * Windows apparently allows the affine but fails to properly report the affine later...
44 | */
45 | public static ConcurrentHashMap AffineMap = new ConcurrentHashMap<>();
46 |
47 | private final String name;
48 | private final boolean daemon;
49 |
50 | private int id = 1;
51 |
52 | private AffinityLock lastLock = null;
53 |
54 | private ArrayList plan = new ArrayList();
55 | private int planFailures = 0;
56 |
57 | public AggressiveAffinityThreadFactory(String name) {
58 | this(name, true);
59 | }
60 |
61 | public AggressiveAffinityThreadFactory(String name, boolean daemon) {
62 | this.name = name;
63 | this.daemon = daemon;
64 |
65 | // make a CPU layout plan.
66 | try {
67 | CpuLayout layout = AffinityLock.cpuLayout();
68 | if (layout != null) {
69 | // we want to fill out each socket's cores, then do virtualized threads if any.
70 | System.out.println("Using Affinity Plan Socket / Core / Thread by CPU: ");
71 | for (int t = 0; t < layout.threadsPerCore(); t++) {
72 | for (int s = 0; s < layout.sockets(); s++) {
73 | for (int c = 0; c < layout.coresPerSocket(); c++) {
74 | for (int i = 0; i < layout.cpus(); i++) {
75 | if (layout.socketId(i) == s &&
76 | layout.coreId(i) == c &&
77 | layout.threadId(i) == t) {
78 | plan.add(i);
79 | System.out.println(String.format("%d: Socket %d, Core %d, Thread %d",
80 | plan.size(), s, c, t));
81 | break;
82 | }
83 | }
84 | }
85 | }
86 | }
87 | } else {
88 | plan = null;
89 | }
90 | } catch (Exception e) {
91 | System.err.println("Unable to determine CPU layout, disabling affinity just to be safe.");
92 | Miner.disableAffinity();
93 | }
94 |
95 | }
96 |
97 | @Override
98 | public synchronized Thread newThread(final Runnable r) {
99 | final int myid = id;
100 | String name2 = myid <= 1 ? name : (name + '-' + myid);
101 | id++;
102 | // System.err.println("Creating a new thread: " + name2);
103 | Thread t = new Thread(new Runnable() {
104 | @Override
105 | public void run() {
106 | if (Miner.PERMIT_AFINITY) {
107 | try {
108 | if (plan == null || myid > plan.size() || planFailures * 2 > plan.size()) {
109 | if (myid < AffinityLock.cpuLayout().cpus()) {
110 | AffinityLock lock = lastLock == null ? AffinityLock.acquireLock() : lastLock.acquireLock(AffinityStrategies.SAME_SOCKET, AffinityStrategies.DIFFERENT_CORE, AffinityStrategies.ANY);
111 | if (!lock.isBound()) {
112 | lock = AffinityLock.acquireCore();
113 | }
114 | if (!lock.isBound()) {
115 | lock = AffinityLock.acquireLock(myid);
116 | }
117 | if (!lock.isBound()) {
118 | System.err.println("Not a problem, but thread " + name2
119 | + " could not immediately reserve a core, it may experience decayed performance.");
120 | AffineMap.put(Affinity.getThreadId(), -1);
121 | } else {
122 | System.out.println("Awesome! Thread " + name2 + " affined! CPU ID " + lock.cpuId() + " Process Thread ID "
123 | + Affinity.getThreadId());
124 | AffineMap.put(Affinity.getThreadId(), lock.cpuId());
125 | lastLock = lock;
126 | }
127 |
128 | r.run();
129 |
130 | lock.close();
131 | } else {
132 | System.err.println("Not a problem, but thread " + name2
133 | + " could not immediately reserve a core, as there are no more cores to assign to. If performance is degraded, attempt with fewer hashers.");
134 |
135 | AffineMap.put(Affinity.getThreadId(), -1);
136 |
137 | r.run();
138 | }
139 | } else {
140 | System.out.println("The plan: Affine Thread " + name2 + " to CPU ID " + plan.get(myid - 1) + ". Note: Process Thread ID "
141 | + Affinity.getThreadId());
142 | AffinityLock lock = AffinityLock.acquireLock(plan.get(myid - 1));
143 |
144 | if (!lock.isBound()) {
145 | System.err.println("Our plan failed :(. Thread " + name2 + " did not affine to CPU ID " + plan.get(myid - 1) + " as we had hoped. Note: Process Thread ID "
146 | + Affinity.getThreadId());
147 | AffineMap.put(Affinity.getThreadId(), -1);
148 | } else {
149 | System.out.println("Awesome! Thread " + name2 + " affined! CPU ID " + lock.cpuId() + " Process Thread ID "
150 | + Affinity.getThreadId());
151 | AffineMap.put(Affinity.getThreadId(), lock.cpuId());
152 | lastLock = lock;
153 | }
154 |
155 | r.run();
156 |
157 | lock.close();
158 | }
159 | } catch (Throwable e) {
160 | System.err.println("Ouch: thread " + name2 + " died with error:");
161 | e.printStackTrace();
162 | System.err.println("Depending on the error, you might consider shutting this down.");
163 | System.err.println("For now though, we're disabling affinity.");
164 | Miner.disableAffinity();
165 | }
166 | }
167 |
168 | if (!Miner.PERMIT_AFINITY) {
169 | r.run();
170 |
171 | System.out.println("Awesome! Thread " + name2 + " running in affinity-free mode!");
172 | }
173 | }
174 | }, name2);
175 | t.setDaemon(daemon);
176 | return t;
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/CPrint.java:
--------------------------------------------------------------------------------
1 | package com.programmerdan.arionum.arionum_miner;
2 |
3 | import com.diogonunes.jcdp.color.ColoredPrinter;
4 | import com.diogonunes.jcdp.color.api.Ansi.Attribute;
5 | import com.diogonunes.jcdp.color.api.Ansi.BColor;
6 | import com.diogonunes.jcdp.color.api.Ansi.FColor;
7 |
8 | public class CPrint {
9 | private ColoredPrinter coPrint = new ColoredPrinter.Builder(2, false).build();
10 | private boolean color = false;
11 |
12 | private Attribute attr = Attribute.NONE;
13 | private FColor fore = FColor.WHITE;
14 | private BColor back = BColor.BLACK;
15 |
16 | public CPrint(boolean color) {
17 | this.color = color;
18 | }
19 |
20 | public CPrint p(Object msg) {
21 | if (color) {
22 | coPrint.print(msg, attr, fore, back);
23 | } else {
24 | System.out.print(msg);
25 | }
26 | return this;
27 | }
28 |
29 | public CPrint fp(String format, Object msg) {
30 | if (color) {
31 | coPrint.print(String.format(format, msg), attr, fore, back);
32 | } else {
33 | System.out.print(String.format(format, msg));
34 | }
35 | return this;
36 | }
37 |
38 | public CPrint fs(Object msg) {
39 | if (color) {
40 | coPrint.print(String.format("%s", msg), attr, fore, back);
41 | } else {
42 | System.out.print(String.format("%s", msg));
43 | }
44 | return this;
45 | }
46 |
47 | public CPrint fd(Object msg) {
48 | if (color) {
49 | coPrint.print(String.format("%d", msg), attr, fore, back);
50 | } else {
51 | System.out.print(String.format("%d", msg));
52 | }
53 | return this;
54 | }
55 |
56 | public CPrint ff(Object msg) {
57 | if (color) {
58 | coPrint.print(String.format("%f", msg), attr, fore, back);
59 | } else {
60 | System.out.print(String.format("%f", msg));
61 | }
62 | return this;
63 | }
64 |
65 | public CPrint ln(Object msg) {
66 | if (color) {
67 | coPrint.println(msg, attr, fore, back);
68 | } else {
69 | System.out.println(msg);
70 | }
71 | return this;
72 | }
73 |
74 | public CPrint ln() {
75 | if (color) {
76 | coPrint.println("", attr, fore, back);
77 | } else {
78 | System.out.println();
79 | }
80 | return this;
81 | }
82 |
83 | public CPrint a(Attribute attr) {
84 | if (color) coPrint.setAttribute(attr);
85 | this.attr = attr;
86 | return this;
87 | }
88 |
89 | public CPrint f(FColor color) {
90 | if (this.color) coPrint.setForegroundColor(color);
91 | this.fore = color;
92 | return this;
93 | }
94 |
95 | public CPrint b(BColor color) {
96 | if (this.color) coPrint.setBackgroundColor(color);
97 | this.back = color;
98 | return this;
99 | }
100 |
101 | public CPrint clr() {
102 | if (color) coPrint.clear();
103 | this.attr = Attribute.NONE;
104 | this.fore = FColor.WHITE;
105 | this.back = BColor.BLACK;
106 | return this;
107 | }
108 |
109 | public CPrint updateLabel() {
110 | return this.clr().a(Attribute.BOLD).f(FColor.CYAN).b(BColor.BLACK);
111 | }
112 |
113 | public CPrint updateMsg() {
114 | return this.clr().a(Attribute.NONE).f(FColor.CYAN).b(BColor.BLACK);
115 | }
116 |
117 | public CPrint info() {
118 | return this.clr().a(Attribute.DARK).f(FColor.CYAN).b(BColor.BLACK);
119 | }
120 |
121 | public CPrint statusLabel() {
122 | return this.clr().a(Attribute.NONE).f(FColor.CYAN).b(BColor.BLACK);
123 | }
124 |
125 | public CPrint normData() {
126 | return this.clr().a(Attribute.BOLD).f(FColor.GREEN).b(BColor.BLACK);
127 | }
128 |
129 | public CPrint dlData() {
130 | return this.clr().a(Attribute.BOLD).f(FColor.YELLOW).b(BColor.BLACK);
131 | }
132 |
133 | public CPrint unitLabel() {
134 | return this.clr().a(Attribute.NONE).f(FColor.WHITE).b(BColor.BLACK);
135 | }
136 |
137 | public CPrint textData() {
138 | return this.clr().a(Attribute.DARK).f(FColor.WHITE).b(BColor.BLACK);
139 | }
140 |
141 | public CPrint headers() {
142 | return this.clr().f(FColor.CYAN).a(Attribute.LIGHT).b(BColor.BLACK);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/ExperimentalHasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | import java.math.BigInteger;
30 | import java.security.MessageDigest;
31 | import java.security.NoSuchAlgorithmException;
32 | import java.security.SecureRandom;
33 | import java.util.Base64;
34 | import java.util.Base64.Encoder;
35 | import java.util.Random;
36 | import java.util.BitSet;
37 |
38 | import net.openhft.affinity.Affinity;
39 | import net.openhft.affinity.AffinityLock;
40 |
41 | import com.programmerdan.arionum.arionum_miner.jna.*;
42 |
43 | /**
44 | * The intent for this hasher is deeper self-inspection of running times of various components. It can be used as a testbed for comparative performance. It is not meant to be used for general use
45 | *
46 | * This particular experimental hasher takes advantage of an observation: namely, that we're doing double the randomness minimally necessary for the scheme, since the argon2i implementation here and in the php reference internally salts the
47 | * "password" with 32 bytes of random data. So the nonce itself can be considered just a payload, fixed entity, and allow the salting of the argon2i to control uniformly random generation of SHA-512 DL outcomes.
48 | *
49 | * This gives me 5-10% H/s speedups on isolated testing with no increase in rejections. Block finds and shares remain as expected for H/s observed.
50 | *
51 | * Another indicator of improved performance is tracking reveals 99.97% of time is spent in argon2i codepath, vs. between 99.8 and 99.9% for other cores. This might sound small but adds up in a big way over time, as its a per-hash
52 | * improvement.
53 | *
54 | * Once a nonce is submitted, it is discarded and a new one generated, as the pool does not allow resubmission of prior nonces.
55 | *
56 | * This is deprecated; use MappedHasher instead.
57 | *
58 | * @author ProgrammerDan (Daniel Boston)
59 | *
60 | */
61 | public class ExperimentalHasher extends Hasher {
62 |
63 | private final JnaUint32 iterations = new JnaUint32(1);
64 | private final JnaUint32 memory = new JnaUint32(524288);
65 | private final JnaUint32 parallelism = new JnaUint32(1);
66 | private final JnaUint32 saltLenI = new JnaUint32(16);
67 | private final JnaUint32 hashLenI = new JnaUint32(32);
68 | private final Size_t saltLen = new Size_t(16l);
69 | private final Size_t hashLen = new Size_t(32l);
70 | private final Size_t encLen;
71 | private byte[] encoded;
72 | private final Argon2Library argonlib;
73 | private final Argon2_type argonType = new Argon2_type(1l);
74 |
75 | public ExperimentalHasher(Miner parent, String id, long target, long maxTime) {
76 | super(parent, id, target, maxTime);
77 |
78 | // SET UP ARGON FOR DIRECT-TO-JNA-WRAPPER-EXEC
79 | argonlib = Argon2Library.INSTANCE;
80 | encLen = argonlib.argon2_encodedlen(iterations, memory, parallelism, saltLenI, hashLenI,
81 | argonType);
82 | encoded = new byte[encLen.intValue()];
83 | }
84 |
85 | private SecureRandom random = new SecureRandom();
86 | private Random insRandom = new Random(random.nextLong());
87 | private Encoder encoder = Base64.getEncoder();
88 | private String rawHashBase;
89 | private byte[] nonce = new byte[32];
90 | private byte[] salt = new byte[16];
91 | private String rawNonce;
92 | private byte[] hashBaseBuffer;
93 | private Size_t hashBaseBufferSize;
94 | private byte[] fullHashBaseBuffer;
95 |
96 | @Override
97 | public void update(BigInteger difficulty, String data, long limit, String publicKey, long blockHeight,
98 | boolean pause, int iters, int mem, int threads) {
99 | super.update(difficulty, data, limit, publicKey, blockHeight, pause, iters, mem, threads);
100 |
101 | genNonce();
102 | }
103 |
104 | @Override
105 | public void newHeight(long oldBlockHeight, long newBlockHeight) {
106 | // no-op, we are locked into 10800 > territory now
107 | }
108 |
109 | private void genNonce() {
110 | insRandom = new Random(random.nextLong());
111 | String encNonce = null;
112 | StringBuilder hashBase;
113 | random.nextBytes(nonce);
114 | encNonce = encoder.encodeToString(nonce);
115 |
116 | char[] nonceChar = encNonce.toCharArray();
117 |
118 | // shaves a bit off vs regex -- for this operation, about 50% savings
119 | StringBuilder nonceSb = new StringBuilder(encNonce.length());
120 | for (char ar : nonceChar) {
121 | if (ar >= '0' && ar <= '9' || ar >= 'a' && ar <= 'z' || ar >= 'A' && ar <= 'Z') {
122 | nonceSb.append(ar);
123 | }
124 | }
125 |
126 | // prealloc probably saves us 10% on this op sequence
127 | hashBase = new StringBuilder(hashBufferSize); // size of key + nonce + difficult + argon + data + spacers
128 | hashBase.append(this.publicKey).append("-");
129 | hashBase.append(nonceSb).append("-");
130 | hashBase.append(this.data).append("-");
131 | hashBase.append(this.difficultyString);
132 |
133 | rawNonce = nonceSb.toString();
134 | rawHashBase = hashBase.toString();
135 |
136 | hashBaseBuffer = rawHashBase.getBytes();
137 | hashBaseBufferSize = new Size_t(hashBaseBuffer.length);
138 | fullHashBaseBuffer = new byte[hashBaseBuffer.length + encLen.intValue()];
139 |
140 | System.arraycopy(hashBaseBuffer, 0, fullHashBaseBuffer, 0, hashBaseBuffer.length);
141 | }
142 |
143 | @Override
144 | public void go() {
145 | boolean doLoop = true;
146 | this.hashBegin = System.currentTimeMillis();
147 |
148 | this.parent.hasherCount.getAndIncrement();
149 | byte[] byteBase = null;
150 |
151 | MessageDigest sha512 = null;
152 | try {
153 | sha512 = MessageDigest.getInstance("SHA-512");
154 | } catch (NoSuchAlgorithmException e1) {
155 | System.err.println("Unable to find SHA-512 algorithm! Fatal error.");
156 | e1.printStackTrace();
157 | active = false;
158 | doLoop = false;
159 | System.exit(1);
160 | }
161 | if (active) {
162 | parent.workerInit(id);
163 | }
164 |
165 | long statCycle = 0l;
166 | long statBegin = 0l;
167 | long statArgonBegin = 0l;
168 | long statArgonEnd = 0l;
169 | long statShaBegin = 0l;
170 | long statShaEnd = 0l;
171 | long statEnd = 0l;
172 |
173 | try {
174 | boolean bound = Miner.PERMIT_AFINITY;
175 | if (Miner.PERMIT_AFINITY) {
176 | BitSet affinity = Affinity.getAffinity();
177 | if (affinity == null || affinity.isEmpty() || affinity.cardinality() > 1) { // no affinity?
178 | Integer lastChance = AggressiveAffinityThreadFactory.AffineMap.get(Affinity.getThreadId());
179 | if (lastChance == null || lastChance < 0) {
180 | bound = false;
181 | }
182 | }
183 | }
184 | while (doLoop && active) {
185 | statCycle = System.currentTimeMillis();
186 | statBegin = System.nanoTime();
187 | try {
188 | insRandom.nextBytes(salt); // 47 ns
189 |
190 | statArgonBegin = System.nanoTime();
191 |
192 | int res = argonlib.argon2i_hash_encoded(iterations, memory, parallelism, hashBaseBuffer, hashBaseBufferSize, salt,
193 | saltLen, hashLen, encoded, encLen); // refactor saves like 30,000-200,000 ns per hash // 34.2 ms
194 | // -- 34,200,000 ns
195 | if (res != Argon2Library.ARGON2_OK) {
196 | System.out.println("HASH FAILURE!" + res);
197 | System.out.println(" hashes: " + hashCount);
198 | System.exit(res);
199 | }
200 | statArgonEnd = System.nanoTime();
201 |
202 | System.arraycopy(encoded, 0, fullHashBaseBuffer, hashBaseBufferSize.intValue(), encLen.intValue());
203 | // 10-20ns (vs. 1200ns of strings in former StableHasher)
204 |
205 | statShaBegin = System.nanoTime();
206 |
207 | byteBase = sha512.digest(fullHashBaseBuffer);
208 | for (int i = 0; i < 5; i++) {
209 | byteBase = sha512.digest(byteBase);
210 | }
211 |
212 | statShaEnd = System.nanoTime();
213 | // shas total 4900-5000ns for all 6 digests, or < 1000ns ea
214 |
215 | StringBuilder duration = new StringBuilder(25);
216 | duration.append(byteBase[10] & 0xFF).append(byteBase[15] & 0xFF).append(byteBase[20] & 0xFF)
217 | .append(byteBase[23] & 0xFF).append(byteBase[31] & 0xFF).append(byteBase[40] & 0xFF)
218 | .append(byteBase[45] & 0xFF).append(byteBase[55] & 0xFF);
219 |
220 | long finalDuration = new BigInteger(duration.toString()).divide(this.difficulty).longValue();
221 | // 385 ns for duration
222 |
223 | if (finalDuration > 0 && finalDuration <= this.limit) {
224 |
225 | parent.submit(rawNonce, new String(encoded), finalDuration, this.difficulty.longValue(), this.getType(), this.blockHeight, this);
226 | if (finalDuration <= 240) {
227 | finds++;
228 | } else {
229 | shares++;
230 | }
231 | genNonce(); // only gen a new nonce once we exhaust the one we had
232 | }
233 |
234 | hashCount++;
235 | statEnd = System.nanoTime();
236 |
237 | if (finalDuration < this.bestDL) {
238 | this.bestDL = finalDuration;
239 | }
240 |
241 | this.argonTime += statArgonEnd - statArgonBegin;
242 | this.shaTime += statShaEnd - statShaBegin;
243 | this.nonArgonTime += (statArgonBegin - statBegin) + (statEnd - statArgonEnd);
244 |
245 | } catch (Exception e) {
246 | System.err.println(id + "] This worker failed somehow. Killing it.");
247 | e.printStackTrace();
248 | doLoop = false;
249 | }
250 | this.loopTime += System.currentTimeMillis() - statCycle;
251 |
252 | if (this.hashCount > this.targetHashCount || this.loopTime > this.maxTime) {
253 | if (!bound) { // no affinity?
254 | if (Miner.PERMIT_AFINITY) {
255 | // make an attempt to grab affinity.
256 | AffinityLock lock = AffinityLock.acquireLock(false); //myid);
257 | if (!lock.isBound()) {
258 | lock = AffinityLock.acquireLock();
259 | }
260 | if (!lock.isBound()) {
261 | lock = AffinityLock.acquireCore();
262 | }
263 | if (!lock.isBound()) {
264 | bound = false;
265 | } else {
266 | bound = true;
267 | }
268 | }
269 | }
270 | if (!bound) {
271 | doLoop = false;
272 | } else {
273 | this.hashEnd = System.currentTimeMillis();
274 | this.hashTime = this.hashEnd - this.hashBegin;
275 | this.hashBegin = System.currentTimeMillis();
276 | completeSession();
277 | this.loopTime = 0l;
278 | }
279 | }
280 | }
281 | } catch (Throwable e) {
282 | e.printStackTrace();
283 | }
284 | this.hashEnd = System.currentTimeMillis();
285 | this.hashTime = this.hashEnd - this.hashBegin;
286 | this.parent.hasherCount.decrementAndGet();
287 | }
288 |
289 | public String getType() {
290 | return "Legacy";
291 | }
292 |
293 | public void kill() {
294 | active = false;
295 | }
296 | }
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/GPUHasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | import java.math.BigInteger;
30 | import java.security.MessageDigest;
31 | import java.security.NoSuchAlgorithmException;
32 | import java.security.SecureRandom;
33 | import java.util.Base64;
34 | import java.util.Base64.Encoder;
35 |
36 | //import com.programmerdan.arionum.arionum_miner.jna.*;
37 |
38 | /**
39 | * Proof of concept GPU miner. Once I figure out how.
40 | * Someday...
41 | *
42 | * @author ProgrammerDan (Daniel Boston)
43 | *
44 | */
45 | public class GPUHasher extends Hasher {
46 |
47 | public GPUHasher(Miner parent, String id, long target, long maxTime) {
48 | super(parent, id, target, maxTime);
49 | }
50 |
51 | private SecureRandom random = new SecureRandom();
52 | private Encoder encoder = Base64.getEncoder();
53 | private String rawHashBase;
54 | private byte[] nonce = new byte[32];
55 | private String rawNonce;
56 |
57 | @Override
58 | public void update(BigInteger difficulty, String data, long limit, String publicKey, long blockHeight,
59 | boolean pause, int iters, int mem, int threads) {
60 | super.update(difficulty, data, limit, publicKey, blockHeight, pause, iters, mem, threads);
61 |
62 | genNonce();
63 | }
64 |
65 | @Override
66 | public void newHeight(long oldH, long newH) {}
67 |
68 | /**
69 | */
70 | private void genNonce() {
71 | String encNonce = null;
72 | StringBuilder hashBase;
73 | random.nextBytes(nonce);
74 | encNonce = encoder.encodeToString(nonce);
75 |
76 | char[] nonceChar = encNonce.toCharArray();
77 |
78 | // shaves a bit off vs regex -- for this operation, about 50% savings
79 | StringBuilder nonceSb = new StringBuilder(encNonce.length());
80 | for (char ar : nonceChar) {
81 | if (ar >= '0' && ar <= '9' || ar >= 'a' && ar <= 'z' || ar >= 'A' && ar <= 'Z') {
82 | nonceSb.append(ar);
83 | }
84 | }
85 |
86 | // prealloc probably saves us 10% on this op sequence
87 | hashBase = new StringBuilder(hashBufferSize); // size of key + nonce + difficult + argon + data + spacers
88 | hashBase.append(this.publicKey).append("-");
89 | hashBase.append(nonceSb).append("-");
90 | hashBase.append(this.data).append("-");
91 | hashBase.append(this.difficultyString);
92 |
93 | rawNonce = nonceSb.toString();
94 | rawHashBase = hashBase.toString();
95 | }
96 |
97 | @Override
98 | public void go() {
99 | this.parent.hasherCount.incrementAndGet();
100 | active = true;
101 | long start = System.currentTimeMillis();
102 |
103 | StringBuilder hashBase = null;
104 | byte[] byteBase = null;
105 |
106 | String argon = null;
107 | //Argon2 argon2 = Argon2Factory.create(Argon2Types.ARGON2i);
108 |
109 | MessageDigest sha512 = null;
110 | try {
111 | sha512 = MessageDigest.getInstance("SHA-512");
112 | } catch (NoSuchAlgorithmException e1) {
113 | System.err.println("Unable to find SHA-512 algorithm! Fatal error.");
114 | e1.printStackTrace();
115 | System.exit(1);
116 | active = false;
117 | }
118 | if (active) {
119 | parent.workerInit(id);
120 | System.out.println(id + "] Spun up EXPERIMENTAL hashing worker in " + (System.currentTimeMillis() - start) + "ms");
121 | }
122 |
123 | long statCycle = 0l;
124 | long statBegin = 0l;
125 | long statArgonBegin = 0l;
126 | long statArgonEnd = 0l;
127 | long statShaBegin = 0l;
128 | long statShaEnd = 0l;
129 | long statEnd = 0l;
130 |
131 | while (active) {
132 | statCycle = System.currentTimeMillis();
133 | statBegin = System.nanoTime();
134 | try {
135 | hashBase = new StringBuilder(this.hashBufferSize);
136 | statArgonBegin = System.nanoTime();
137 | // this is all TODO: argon = argon2.hash(4, 16384, 4, rawHashBase);
138 | statArgonEnd = System.nanoTime();
139 | hashBase.append(rawHashBase).append(argon);
140 |
141 | byteBase = hashBase.toString().getBytes();
142 | statShaBegin = System.nanoTime();
143 | for (int i = 0; i < 5; i++) {
144 | byteBase = sha512.digest(byteBase);
145 | }
146 | byteBase = sha512.digest(byteBase);
147 | statShaEnd = System.nanoTime();
148 |
149 | StringBuilder duration = new StringBuilder(25);
150 | duration.append(byteBase[10] & 0xFF).append(byteBase[15] & 0xFF).append(byteBase[20] & 0xFF)
151 | .append(byteBase[23] & 0xFF).append(byteBase[31] & 0xFF).append(byteBase[40] & 0xFF)
152 | .append(byteBase[45] & 0xFF).append(byteBase[55] & 0xFF);
153 |
154 | long finalDuration = new BigInteger(duration.toString()).divide(this.difficulty).longValue();
155 | if (finalDuration > 0 && finalDuration <= this.limit) {
156 | parent.submit(rawNonce, argon, finalDuration, this.difficulty.longValue(), this.getType(), this.blockHeight, this);
157 | if (finalDuration <= 240) {
158 | finds++;
159 | } else {
160 | shares++;
161 | }
162 | genNonce(); // only gen a new nonce once we exhaust the one we had
163 | }
164 |
165 | hashCount++;
166 | statEnd = System.nanoTime();
167 |
168 | if (finalDuration < this.bestDL) { // split the difference; if we're not getting movement after a while, just move on
169 | this.bestDL = finalDuration;
170 | }
171 |
172 |
173 | this.argonTime += statArgonEnd - statArgonBegin;
174 | this.shaTime += statShaEnd - statShaBegin;
175 | this.nonArgonTime += (statArgonBegin - statBegin) + (statEnd - statArgonEnd);
176 | } catch (Exception e) {
177 | System.err.println(id + "] This worker failed somehow. Killing it.");
178 | e.printStackTrace();
179 | active = false;
180 | }
181 | this.loopTime += System.currentTimeMillis() - statCycle;
182 |
183 | if (this.hashCount > this.targetHashCount || this.loopTime > this.maxTime) {
184 | this.active = false;
185 | }
186 | }
187 | System.out.println(id + "] This worker is now inactive.");
188 | this.parent.hasherCount.decrementAndGet();
189 | }
190 |
191 | public String getType() {
192 | return "GPU";
193 | }
194 |
195 | public void kill() {
196 | active = false;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/Hasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | import java.math.BigInteger;
30 |
31 | /**
32 | * Abstraction layer to allow multiple miner definitions.
33 | *
34 | * @author ProgrammerDan (Daniel Boston)
35 | */
36 | public abstract class Hasher implements Runnable{
37 |
38 | protected Miner parent;
39 |
40 | public void run() {
41 | try {
42 | active = true;
43 | go();
44 | active = false;
45 | } catch (Throwable e) {
46 | System.err.println("Detected thread " + Thread.currentThread().getName() + " death due to error: " + e.getMessage());
47 | e.printStackTrace();
48 |
49 | System.err.println("\n\nThis is probably fatal, so exiting now.");
50 | System.exit(1);
51 | }
52 | HasherStats stats = new HasherStats(id, argonTime, shaTime, nonArgonTime, hashTime, hashCount, bestDL, shares, finds, getType());
53 | parent.workerFinish(stats, this);
54 | }
55 |
56 | /**
57 | * Instead of run, go -- since we now wrap run() into a catch block since our Executors don't support UncaughtExceptions in an intuitive way
58 | */
59 | public abstract void go();
60 |
61 | /**
62 | * If some condition exists where this should die, kill it.
63 | */
64 | public abstract void kill();
65 |
66 | protected boolean active;
67 | protected String id;
68 | protected long hashCount;
69 | protected long targetHashCount;
70 | protected long hashBegin;
71 | protected long hashEnd;
72 | protected long hashTime;
73 | protected long maxTime;
74 | protected long blockHeight;
75 |
76 | // local copy of data, updated "off thread"
77 | protected BigInteger difficulty;
78 | protected String difficultyString;
79 | protected String data;
80 | protected int hashBufferSize;
81 | protected long limit;
82 | protected String publicKey;
83 | protected String argonString;
84 | protected boolean pause;
85 | protected int iters;
86 | protected int mem;
87 | protected int threads;
88 |
89 | // local stats stores, retrieved "off thread"
90 | protected long bestDL;
91 | protected long shares;
92 | protected long finds;
93 |
94 | /* Timing Stats, current */
95 | protected long loopTime;
96 | protected long argonTime;
97 | protected long shaTime;
98 | protected long nonArgonTime;
99 |
100 | public Hasher(Miner parent, String id, long target, long maxTime) {
101 | super();
102 | this.parent = parent;
103 | this.id = id;
104 | this.active = false;
105 | this.hashCount = 0l;
106 | this.targetHashCount = target;
107 | this.maxTime = maxTime;
108 | }
109 |
110 | public void completeSession() {
111 | // emulate shutdown / restart, but on dedi thread so don't.
112 | HasherStats stats = new HasherStats(id, argonTime, shaTime, nonArgonTime, hashTime, hashCount, bestDL, shares, finds, getType());
113 | argonTime = 0l;
114 | shaTime = 0l;
115 | nonArgonTime = 0l;
116 | hashTime = 0l;
117 | hashCount = 0l;
118 | bestDL = Long.MAX_VALUE;
119 | shares = 0l;
120 | finds = 0l;
121 | long[] sessionUpd = parent.sessionFinish(stats, this);
122 | this.targetHashCount = sessionUpd[0];
123 | this.maxTime = sessionUpd[1];
124 | }
125 |
126 | public String getID() {
127 | return this.id;
128 | }
129 |
130 | public long getBestDL() {
131 | return bestDL;
132 | }
133 |
134 | public long getShares() {
135 | return shares;
136 | }
137 |
138 | public long getFinds() {
139 | return finds;
140 | }
141 |
142 | public long getArgonTime() {
143 | return argonTime;
144 | }
145 |
146 | public long getShaTime() {
147 | return shaTime;
148 | }
149 |
150 | public long getNonArgonTime() {
151 | return nonArgonTime;
152 | }
153 |
154 | public long getLoopTime() {
155 | return loopTime;
156 | }
157 |
158 | public long getHashTime() {
159 | return this.hashTime;
160 | }
161 |
162 | public void update(BigInteger difficulty, String data, long limit, String publicKey, long blockHeight,
163 | boolean pause, int iters, int mem, int threads) {
164 | this.difficulty = difficulty;
165 | this.difficultyString = difficulty.toString();
166 | if (!data.equals(this.data)) {
167 | bestDL = Long.MAX_VALUE;
168 | }
169 | this.data = data;
170 | this.hashBufferSize = 280 + this.data.length();
171 | this.limit = limit;
172 | this.publicKey = publicKey;
173 | if (blockHeight != this.blockHeight) {
174 | newHeight(this.blockHeight, blockHeight);
175 | }
176 | this.blockHeight = blockHeight;
177 |
178 | boolean doreinit = false;
179 |
180 | if (this.iters != iters || this.mem != mem || this.threads != threads) {
181 | //System.out.println("hasher: reinit to " + mem);
182 | doreinit = true;
183 | }
184 | this.pause = pause;
185 | this.iters = iters;
186 | this.mem = mem;
187 | this.threads = threads;
188 | }
189 |
190 | /**
191 | * Called to let hashers handle new block heights in a flexible fashion. This will allow
192 | * us to accommodate hard forks easily.
193 | *
194 | * @param oldBlockHeight
195 | * @param newBlockHeight
196 | *
197 | */
198 | public abstract void newHeight(long oldBlockHeight, long newBlockHeight);
199 |
200 | /**
201 | * Lets the hasher return a "type" classification. Should NOT be null.
202 | * @return
203 | */
204 | public abstract String getType();
205 |
206 | public long getHashes() {
207 | return this.hashCount;
208 | }
209 |
210 | public boolean isActive() {
211 | return active;
212 | }
213 |
214 | }
215 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/HasherFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | /**
30 | * Straightforward factory-esque pattern, tied to optional AdvMod enum.
31 | *
32 | * @author ProgrammerDan (Daniel Boston)
33 | *
34 | */
35 | public class HasherFactory {
36 |
37 | /* Generate a new hasher */
38 | public static Hasher createHasher(AdvMode mode, Miner parent, String id, long lifeTime, long maxSession) {
39 | switch(mode) {
40 | case experimental:
41 | return new MappedHasher(parent, id, lifeTime, maxSession);
42 | case standard:
43 | return new SafeMappedHasher(parent, id, lifeTime, maxSession);
44 | case enhanced:
45 | return new SafeMappedHasher(parent, id, lifeTime, maxSession);
46 | case legacy:
47 | return new ExperimentalHasher(parent, id, lifeTime, maxSession);
48 | case gpu:
49 | return new GPUHasher(parent, id, lifeTime, maxSession);
50 | default:
51 | return new MappedHasher(parent, id, lifeTime, maxSession);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/HasherStats.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | /**
30 | * Offload container for hasher runtime statistics
31 | *
32 | * @author ProgrammerDan (Daniel Boston)
33 | */
34 | public class HasherStats {
35 | public long argonTime;
36 | public long shaTime;
37 | public long nonArgonTime;
38 | public long hashes;
39 | public long bestDL;
40 | public long shares;
41 | public long finds;
42 | public long hashTime;
43 | public long scheduledTime;
44 | public String id;
45 | public String type;
46 |
47 | public HasherStats(String id, long argonTime, long shaTime, long nonArgonTime, long hashTime, long hashes, long bestDL, long shares, long finds, String type) {
48 | this.id = id;
49 | this.argonTime = argonTime;
50 | this.shaTime = shaTime;
51 | this.nonArgonTime = nonArgonTime;
52 | this.hashTime = hashTime;
53 | this.hashes = hashes;
54 | this.bestDL = bestDL;
55 | this.shares = shares;
56 | this.finds = finds;
57 | this.type = type;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/MappedHasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | import java.lang.reflect.Method;
30 | import java.math.BigInteger;
31 | import java.security.MessageDigest;
32 | import java.security.NoSuchAlgorithmException;
33 | import java.security.SecureRandom;
34 | import java.util.Base64;
35 | import java.util.Base64.Encoder;
36 | import java.util.BitSet;
37 | import java.util.LinkedList;
38 |
39 | import com.sun.jna.Memory;
40 | import com.sun.jna.Pointer;
41 | import com.sun.jna.ptr.PointerByReference;
42 |
43 | import net.openhft.affinity.Affinity;
44 | import net.openhft.affinity.AffinityLock;
45 |
46 | import com.programmerdan.arionum.arionum_miner.jna.*;
47 |
48 | /**
49 | * This function means serious business.
50 | * With the Hard Fork in Arionum increasing by nearly two orders of magnitude the per-hash memory requirements,
51 | * the allocation of memory became a serious performance bottleneck for most normal CPU miners.
52 | * This hasher attempts to address that, by generating a pool of massive memory "blocks" that are passed
53 | * to the argon2 function and reused. It is conservative, keeping a static "scratch" pool of available memory
54 | * blocks and passing them to new Hashers as needed, who (should) return them to the scratch pool when they are
55 | * done. New memory blocks are only allocated if the scratch pool is exhausted, but then again, those new
56 | * blocks are then preserved within the pool.
57 | * Initial testing showed about 25% performance gain by removing the bulk of memory alloc and dealloc calls in this
58 | * fashion.
59 | *
60 | * @author ProgrammerDan (Daniel Boston)
61 | *
62 | */
63 | public class MappedHasher extends Hasher implements Argon2Library.AllocateFunction, Argon2Library.DeallocateFunction {
64 | /* Scratch "pool" of massive memory pages. */
65 | private static LinkedList scratches = new LinkedList<>();
66 | private static Memory getScratch() {
67 | Memory mem = scratches.poll();
68 | if (mem == null) {
69 | return new Memory(524288l*1024l);
70 | } else {
71 | return mem;
72 | }
73 | }
74 | private static void returnScratch(Memory mem) {
75 | scratches.push(mem);
76 | }
77 |
78 | /*Local Hasher vars*/
79 | private Memory scratch = null;
80 |
81 | private boolean kill = false;
82 |
83 | private final Argon2_Context context;
84 |
85 | private final JnaUint32 iterations = new JnaUint32(1);
86 | private final JnaUint32 memory = new JnaUint32(524288);
87 | private final JnaUint32 parallelism = new JnaUint32(1);
88 | private final JnaUint32 saltLenI = new JnaUint32(16);
89 | private final JnaUint32 hashLenI = new JnaUint32(32);
90 | private final Size_t saltLen = new Size_t(16l);
91 | private final Size_t hashLen = new Size_t(32l);
92 | private final Size_t encLen;
93 | private byte[] encoded;
94 | private final Argon2Library argonlib;
95 | private final Argon2_type argonType = new Argon2_type(1l);
96 |
97 | private final JnaUint32 iterations2 = new JnaUint32(4);
98 | private final JnaUint32 memory2 = new JnaUint32(16384);
99 | private final JnaUint32 parallelism2 = new JnaUint32(4);
100 | private final Size_t encLen2;
101 | private byte[] encoded2;
102 |
103 | private int mode = 1;
104 |
105 | public MappedHasher(Miner parent, String id, long target, long maxTime) {
106 | super(parent, id, target, maxTime);
107 |
108 | // SET UP ARGON FOR DIRECT-TO-JNA-WRAPPER-EXEC
109 | argonlib = Argon2Library.INSTANCE;
110 | context = new Argon2_Context();
111 | context.outlen = new JnaUint32(32);
112 | context.out = new Memory(32l);
113 | // assigned per hash context.pwdLen
114 | context.saltlen = new JnaUint32(16);
115 | context.secret = null;
116 | context.secretlen = new JnaUint32(0);
117 | context.ad = null;
118 | context.adlen = new JnaUint32(0);
119 |
120 | context.t_cost = iterations;
121 | context.m_cost = memory;
122 | context.lanes = parallelism;
123 | context.threads = parallelism;
124 | context.flags = Argon2Library.ARGON2_DEFAULT_FLAGS;
125 | context.version = new JnaUint32(0x13);
126 |
127 | encLen = argonlib.argon2_encodedlen(iterations, memory, parallelism, saltLenI, hashLenI,
128 | argonType);
129 |
130 | encoded = new byte[encLen.intValue() - 1];
131 |
132 | encLen2 = argonlib.argon2_encodedlen(iterations2, memory2, parallelism2, saltLenI, hashLenI,
133 | argonType);
134 | encoded2 = new byte[encLen2.intValue() - 1];
135 | }
136 |
137 | private SecureRandom random = new SecureRandom();
138 | private Encoder encoder = Base64.getEncoder();
139 | private String rawHashBase;
140 | private byte[] nonce = new byte[32];
141 | private byte[] salt = new byte[16];
142 | private Memory m_salt = new Memory(16l);
143 | private String rawNonce;
144 | private byte[] hashBaseBuffer;
145 | private Memory m_hashBaseBuffer;
146 | private Size_t hashBaseBufferSize;
147 | private byte[] fullHashBaseBuffer;
148 |
149 | @Override
150 | public void update(BigInteger difficulty, String data, long limit, String publicKey, long blockHeight,
151 | boolean pause, int iters, int mem, int threads) {
152 | super.update(difficulty, data, limit, publicKey, blockHeight, pause, iters, mem, threads);
153 |
154 | if (this.mem == 16384) {
155 | mode = 2;
156 | } else {
157 | mode = 1; // assume only the two modes for now.
158 | }
159 |
160 | genNonce();
161 | }
162 |
163 | @Override
164 | public void newHeight(long oldBlockHeight, long newBlockHeight) {
165 | // no-op, we are locked into 10800 > territory now
166 | }
167 |
168 | private void genNonce() {
169 | String encNonce = null;
170 | StringBuilder hashBase;
171 | random.nextBytes(nonce);
172 | encNonce = encoder.encodeToString(nonce);
173 |
174 | char[] nonceChar = encNonce.toCharArray();
175 |
176 | // shaves a bit off vs regex -- for this operation, about 50% savings
177 | StringBuilder nonceSb = new StringBuilder(encNonce.length());
178 | for (char ar : nonceChar) {
179 | if (ar >= '0' && ar <= '9' || ar >= 'a' && ar <= 'z' || ar >= 'A' && ar <= 'Z') {
180 | nonceSb.append(ar);
181 | }
182 | }
183 |
184 | // prealloc probably saves us 10% on this op sequence
185 | hashBase = new StringBuilder(hashBufferSize); // size of key + nonce + difficult + argon + data + spacers
186 | hashBase.append(this.publicKey).append("-");
187 | hashBase.append(nonceSb).append("-");
188 | hashBase.append(this.data).append("-");
189 | hashBase.append(this.difficultyString);
190 |
191 | rawNonce = nonceSb.toString();
192 | rawHashBase = hashBase.toString();
193 |
194 | hashBaseBuffer = rawHashBase.getBytes();
195 | hashBaseBufferSize = new Size_t(hashBaseBuffer.length);
196 | m_hashBaseBuffer = new Memory(hashBaseBuffer.length);
197 |
198 | if (mode == 1) {
199 | fullHashBaseBuffer = new byte[hashBaseBuffer.length + encLen.intValue() - 1];
200 | } else if (mode == 2) {
201 | fullHashBaseBuffer = new byte[hashBaseBuffer.length + encLen2.intValue() - 1];
202 | }
203 |
204 | m_hashBaseBuffer.write(0, hashBaseBuffer, 0, hashBaseBuffer.length);
205 | System.arraycopy(hashBaseBuffer, 0, fullHashBaseBuffer, 0, hashBaseBuffer.length);
206 | }
207 |
208 | @Override
209 | public void go() {
210 | try {
211 | scratch = MappedHasher.getScratch();
212 | } catch (OutOfMemoryError oome) {
213 | System.err.println("Please reduce the number of requested hashing workers. Your system lacks sufficient memory to run this many!");
214 | System.err.println("Regrettably, this is a fatal error.");
215 | oome.printStackTrace();
216 | active = false;
217 | System.exit(1);
218 | }
219 | context.allocate_cbk = this;
220 | context.free_cbk = this;
221 |
222 | boolean doLoop = true;
223 | this.hashBegin = System.currentTimeMillis();
224 |
225 | this.parent.hasherCount.getAndIncrement();
226 | byte[] byteBase = null;
227 |
228 | MessageDigest sha512 = null;
229 | try {
230 | sha512 = MessageDigest.getInstance("SHA-512");
231 | } catch (NoSuchAlgorithmException e1) {
232 | System.err.println("Unable to find SHA-512 algorithm! Fatal error.");
233 | e1.printStackTrace();
234 | active = false;
235 | doLoop = false;
236 | System.exit(1);
237 | }
238 | if (active) {
239 | parent.workerInit(id);
240 | }
241 |
242 | long statCycle = 0l;
243 | long statBegin = 0l;
244 | long statArgonBegin = 0l;
245 | long statArgonEnd = 0l;
246 | long statShaBegin = 0l;
247 | long statShaEnd = 0l;
248 | long statEnd = 0l;
249 |
250 | try {
251 | boolean bound = Miner.PERMIT_AFINITY;
252 | if (Miner.PERMIT_AFINITY) {
253 | BitSet affinity = Affinity.getAffinity();
254 | if (affinity == null || affinity.isEmpty() || affinity.cardinality() > 1) { // no affinity?
255 | Integer lastChance = AggressiveAffinityThreadFactory.AffineMap.get(Affinity.getThreadId());
256 | if (lastChance == null || lastChance < 0) {
257 | bound = false;
258 | }
259 | }
260 | }
261 | while (doLoop && active) {
262 | if (this.pause) {
263 | try {
264 | Thread.sleep(50);
265 | } catch (InterruptedException e) {
266 | // ok, moving on.
267 | }
268 | continue;
269 | }
270 | statCycle = System.currentTimeMillis();
271 | statBegin = System.nanoTime();
272 | try {
273 | random.nextBytes(salt);
274 | m_salt.write(0, salt, 0, 16);
275 |
276 | statArgonBegin = System.nanoTime();
277 | // set argon params in context..
278 |
279 | int smode = mode;
280 | if (mode == 2) {
281 | context.t_cost = iterations2;
282 | context.m_cost = memory2;
283 | context.lanes = parallelism2;
284 | context.threads = parallelism2;
285 | } else {
286 | context.t_cost = iterations;
287 | context.m_cost = memory;
288 | context.lanes = parallelism;
289 | context.threads = parallelism;
290 | }
291 | context.out = new Memory(32l);
292 | context.salt = m_salt;
293 | context.pwdlen = new JnaUint32(hashBaseBuffer.length);
294 | m_hashBaseBuffer.write(0, hashBaseBuffer, 0, hashBaseBuffer.length);
295 | context.pwd = m_hashBaseBuffer;
296 | int res = argonlib.argon2_ctx(context, argonType);
297 | if (res != Argon2Library.ARGON2_OK) {
298 | System.out.println("HASH FAILURE!" + res);
299 | System.out.println(" hashes: " + hashCount);
300 | System.exit(res);
301 | }
302 | int res2 = 0;
303 | long finalDuration = 0;
304 | if (smode == mode) { // check if mode changed
305 | if (mode == 1) {
306 | res2 = argonlib.encode_ctx(encoded, encLen, context, argonType);
307 | } else if (mode == 2) {
308 | res2 = argonlib.encode_ctx(encoded2, encLen2, context, argonType);
309 | }
310 | if (res2 != Argon2Library.ARGON2_OK) {
311 | System.out.println("ENCODE FAILURE! " + res2);
312 | }
313 | statArgonEnd = System.nanoTime();
314 |
315 | if (mode == 1) {
316 | if (encoded[encoded.length - 1] == 0) {
317 | System.out.print("Encoded length failure.");
318 | }
319 |
320 | System.arraycopy(encoded, 0, fullHashBaseBuffer, hashBaseBufferSize.intValue(), encLen.intValue() - 1);
321 | } else if (mode == 2) {
322 | if (encoded2[encoded2.length - 1] == 0) {
323 | System.out.print("Encoded length failure.");
324 | }
325 |
326 | System.arraycopy(encoded2, 0, fullHashBaseBuffer, hashBaseBufferSize.intValue(), encLen2.intValue() - 1);
327 | }
328 |
329 | // 10-20ns (vs. 1200ns of strings in former StableHasher)
330 |
331 | statShaBegin = System.nanoTime();
332 |
333 | byteBase = sha512.digest(fullHashBaseBuffer);
334 | for (int i = 0; i < 5; i++) {
335 | byteBase = sha512.digest(byteBase);
336 | }
337 |
338 | statShaEnd = System.nanoTime();
339 | // shas total 4900-5000ns for all 6 digests, or < 1000ns ea
340 |
341 | StringBuilder duration = new StringBuilder(25);
342 | duration.append(byteBase[10] & 0xFF).append(byteBase[15] & 0xFF).append(byteBase[20] & 0xFF)
343 | .append(byteBase[23] & 0xFF).append(byteBase[31] & 0xFF).append(byteBase[40] & 0xFF)
344 | .append(byteBase[45] & 0xFF).append(byteBase[55] & 0xFF);
345 |
346 | finalDuration = new BigInteger(duration.toString()).divide(this.difficulty).longValue();
347 | // 385 ns for duration
348 |
349 | if (finalDuration > 0 && finalDuration <= this.limit) {
350 |
351 | if (mode == 1 ) {
352 | // why trim? the raw encoded has a trailing \x00 null char. Trim will remove it, same as we do in the arraycopy by doing encLen - 1.
353 | parent.submit(rawNonce, new String(encoded).trim(), finalDuration, this.difficulty.longValue(), this.getType(), this.blockHeight, this);
354 | } else if (mode == 2) {
355 | parent.submit(rawNonce, new String(encoded2).trim(), finalDuration, this.difficulty.longValue(), this.getType(), this.blockHeight, this);
356 | }
357 |
358 | if (finalDuration <= 240) {
359 | finds++;
360 | } else {
361 | shares++;
362 | }
363 | genNonce(); // only gen a new nonce once we exhaust the one we had
364 | }
365 | }
366 |
367 | hashCount++;
368 | statEnd = System.nanoTime();
369 |
370 | if (finalDuration < this.bestDL) {
371 | this.bestDL = finalDuration;
372 | }
373 |
374 | this.argonTime += statArgonEnd - statArgonBegin;
375 | this.shaTime += statShaEnd - statShaBegin;
376 | this.nonArgonTime += (statArgonBegin - statBegin) + (statEnd - statArgonEnd);
377 |
378 | } catch (Exception e) {
379 | System.err.println(id + "] This worker failed somehow. Killing it.");
380 | e.printStackTrace();
381 | System.err.println("Please report this to ProgrammerDan");
382 | doLoop = false;
383 | }
384 | this.loopTime += System.currentTimeMillis() - statCycle;
385 |
386 | if (this.hashCount > this.targetHashCount || this.loopTime > this.maxTime) {
387 | if (!bound) { // no affinity?
388 | if (Miner.PERMIT_AFINITY) {
389 | // make an attempt to grab affinity.
390 | AffinityLock lock = AffinityLock.acquireLock(false); //myid);
391 | if (!lock.isBound()) {
392 | lock = AffinityLock.acquireLock();
393 | }
394 | if (!lock.isBound()) {
395 | lock = AffinityLock.acquireCore();
396 | }
397 | if (!lock.isBound()) {
398 | bound = false;
399 | } else {
400 | bound = true;
401 | }
402 | }
403 | }
404 | if (!bound) {
405 | //System.out.println("Ending worker " + this.id);
406 | doLoop = false;
407 | } else {
408 | //System.out.println("Ending a session for worker " + this.id);
409 | this.hashEnd = System.currentTimeMillis();
410 | this.hashTime = this.hashEnd - this.hashBegin;
411 | this.hashBegin = System.currentTimeMillis();
412 | completeSession();
413 | this.loopTime = 0l;
414 | }
415 | }
416 | }
417 | } catch (Throwable e) {
418 | e.printStackTrace();
419 | }
420 |
421 | if (kill) {
422 | scratch.clear(); // we don't return it. Let's clear it, and let it be GC'd. The Scratch will gen a new one.
423 | try {
424 | Method dispose = scratch.getClass().getDeclaredMethod("dispose");
425 | dispose.setAccessible(true);
426 | dispose.invoke(scratch);
427 | } catch (Throwable t) {
428 | System.err.println("After a potential memory failure was identified, our attempt to release this memory buffer has failed.");
429 | t.printStackTrace();
430 | }
431 | scratch = null;
432 | Memory.purge();
433 | } else {
434 | MappedHasher.returnScratch(scratch);
435 | }
436 | this.hashEnd = System.currentTimeMillis();
437 | this.hashTime = this.hashEnd - this.hashBegin;
438 | this.parent.hasherCount.decrementAndGet();
439 | }
440 |
441 | // allocate
442 | public int invoke(PointerByReference memory, Size_t byte_to_allocate) {
443 |
444 | if (byte_to_allocate.intValue() > this.scratch.size()) {
445 | return -22; // memory allocation error
446 | }
447 |
448 | memory.setValue(this.scratch);
449 |
450 | return 0;
451 | }
452 |
453 | // no-op deallcate, wipe?
454 | public void invoke(Pointer memory, Size_t byte_to_allocate) {
455 | // we ignore this, since we manage memory on our own.
456 | }
457 |
458 | public String getType() {
459 | return "CPU";
460 | }
461 |
462 | public void kill() {
463 | kill = true;
464 | active = false;
465 | }
466 | }
467 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/MinerType.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | public enum MinerType {
30 | solo,
31 | pool,
32 | benchmark,
33 | test
34 | }
35 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/Profile.java:
--------------------------------------------------------------------------------
1 | package com.programmerdan.arionum.arionum_miner;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Lightweight tracking profile to keep track of how well a particular configuration did
7 | *
8 | * @author ProgrammerDan
9 | *
10 | */
11 | public class Profile implements Comparable {
12 | AdvMode[] workerTypes;
13 | long hashes;
14 | long sampleBegin;
15 | long samplePlannedEnd;
16 | long sampleTime;
17 | double rate;
18 | double TiC;
19 |
20 | public Profile(int workers) {
21 | workerTypes = new AdvMode[workers];
22 | hashes = 0l; //new long[workers];
23 | sampleTime = 0;
24 | rate = 0.0d;
25 | this.sampleBegin = 0l;
26 | this.samplePlannedEnd = 0l;
27 | }
28 |
29 | public Profile(AdvMode ...workers) {
30 | workerTypes = workers;
31 | hashes = 0l;//new long[ workers.length ];
32 | sampleTime = 0;
33 | rate = 0.0d;
34 | this.sampleBegin = 0;
35 | this.samplePlannedEnd = 0;
36 | }
37 |
38 | public void begin() {
39 | long now = System.currentTimeMillis();
40 | this.sampleBegin = now + Miner.INIT_DELAY;
41 | this.samplePlannedEnd = this.sampleBegin + Miner.TEST_PERIOD;
42 | }
43 |
44 | public Status getStatus() {
45 | if (this.sampleBegin == 0) {
46 | return Status.QUEUED;
47 | }
48 | long now = System.currentTimeMillis();
49 | if (now < this.sampleBegin) {
50 | return Status.WAITING;
51 | } else if (now > this.samplePlannedEnd) {
52 | return Status.DONE;
53 | } else {
54 | return Status.PROFILING;
55 | }
56 | }
57 |
58 | public AdvMode[] getWorkers() {
59 | return workerTypes;
60 | }
61 |
62 | public void register(int idx, AdvMode worker) {
63 | this.workerTypes[idx] = worker;
64 | }
65 |
66 | public void update(long hashes, long time) {
67 | this.hashes += hashes; //[idx] = hashes;
68 | if (time > this.sampleTime)
69 | this.sampleTime = time;
70 | }
71 |
72 | public double getHashSec() {
73 | return getRawRate() / 1000d;
74 | }
75 | public double getRawRate() {
76 | /*long accumulate = 0l;
77 | for (long hash : hashes) {
78 | accumulate += hash;
79 | }*/
80 | if (this.sampleTime > 0 ) {
81 | rate = (double) hashes / (double) this.sampleTime; //accumulate / this.sampleTime;
82 | } else {
83 | rate = 0d;
84 | }
85 | return rate;
86 | }
87 |
88 | public long getHashes() {
89 | /*long accumulate = 0l;
90 | for (long hash : hashes) {
91 | accumulate += hash;
92 | }
93 | return accumulate;*/
94 | return hashes;
95 | }
96 |
97 | @Override
98 | public boolean equals(Object o) {
99 | if (o instanceof Profile) {
100 | Profile p = (Profile) o;
101 | return p == this || (Arrays.deepEquals(p.workerTypes, this.workerTypes));
102 | }
103 |
104 | return false;
105 | }
106 |
107 | @Override
108 | public int compareTo(Profile o) {
109 | return Double.compare(this.getRawRate(), o.getRawRate());
110 | }
111 |
112 | enum Status {
113 | QUEUED,
114 | WAITING,
115 | PROFILING,
116 | DONE
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/Report.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | /**
30 | * A run statistics package
31 | *
32 | * @author ProgrammerDan (Daniel Boston)
33 | *
34 | */
35 | public class Report {
36 | /**
37 | * When report was run
38 | */
39 | long reportTime = System.currentTimeMillis();
40 |
41 | /**
42 | * Number of active streams/threads
43 | */
44 | long streams;
45 |
46 | /**
47 | * Number of microtasks run
48 | */
49 | long runs;
50 |
51 | /**
52 | * Number of hashes
53 | */
54 | long hashes;
55 |
56 | /**
57 | * Hashes per run
58 | */
59 | double hashPerRun;
60 |
61 | double curHashPerSecond;
62 | double curTimeInCore;
63 | double curWaitLoss;
64 |
65 | double shaEff;
66 | double argonEff;
67 |
68 | long totalTime;
69 | long argonTime;
70 | long nonArgontime;
71 | long shaTime;
72 | long shares;
73 | long finds;
74 | long rejects;
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/SafeMappedHasher.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | import java.lang.reflect.Method;
30 | import java.math.BigInteger;
31 | import java.security.MessageDigest;
32 | import java.security.NoSuchAlgorithmException;
33 | import java.security.SecureRandom;
34 | import java.util.Base64;
35 | import java.util.Base64.Encoder;
36 | import java.util.Random;
37 | import java.util.BitSet;
38 | import java.util.LinkedList;
39 |
40 | import com.sun.jna.Memory;
41 | import com.sun.jna.Pointer;
42 | import com.sun.jna.ptr.PointerByReference;
43 |
44 | import net.openhft.affinity.Affinity;
45 | import net.openhft.affinity.AffinityLock;
46 |
47 | import com.programmerdan.arionum.arionum_miner.jna.*;
48 |
49 | /**
50 | * This function means serious business.
51 | * With the Hard Fork in Arionum increasing by nearly two orders of magnitude the per-hash memory requirements,
52 | * the allocation of memory became a serious performance bottleneck for most normal CPU miners.
53 | * This hasher attempts to address that, by generating a pool of massive memory "blocks" that are passed
54 | * to the argon2 function and reused. It is conservative, keeping a static "scratch" pool of available memory
55 | * blocks and passing them to new Hashers as needed, who (should) return them to the scratch pool when they are
56 | * done. New memory blocks are only allocated if the scratch pool is exhausted, but then again, those new
57 | * blocks are then preserved within the pool.
58 | * Initial testing showed about 25% performance gain by removing the bulk of memory alloc and dealloc calls in this
59 | * fashion.
60 | *
61 | * This version uses a PHP-esque "safe" salt, for easier verification and to avoid verification problems against the
62 | * reference implementation. As a consequence of the loss of byte space (2/3 reduction possibly) in the salt, I've added
63 | * in a hopefully clever NONCE rotation scheme, that will mutate the nonce along with the salt.
64 | *
65 | * @author ProgrammerDan (Daniel Boston)
66 | *
67 | */
68 | public class SafeMappedHasher extends Hasher implements Argon2Library.AllocateFunction, Argon2Library.DeallocateFunction {
69 | /* Scratch "pool" of massive memory pages. */
70 | private static LinkedList scratches = new LinkedList<>();
71 | private static Memory getScratch() {
72 | Memory mem = scratches.poll();
73 | if (mem == null) {
74 | return new Memory(524288l*1024l);
75 | } else {
76 | return mem;
77 | }
78 | }
79 | private static void returnScratch(Memory mem) {
80 | scratches.push(mem);
81 | }
82 |
83 | /*Local Hasher vars*/
84 | private Memory scratch = null;
85 |
86 | private boolean kill = false;
87 |
88 | private final Argon2_Context context;
89 |
90 | private final JnaUint32 iterations = new JnaUint32(1);
91 | private final JnaUint32 memory = new JnaUint32(524288);
92 | private final JnaUint32 parallelism = new JnaUint32(1);
93 | private final JnaUint32 saltLenI = new JnaUint32(16);
94 | private final JnaUint32 hashLenI = new JnaUint32(32);
95 | private final Size_t saltLen = new Size_t(16l);
96 | private final Size_t hashLen = new Size_t(32l);
97 | private final Size_t encLen;
98 | private byte[] encoded;
99 | private final Argon2Library argonlib;
100 | private final Argon2_type argonType = new Argon2_type(1l);
101 |
102 | private final JnaUint32 iterations2 = new JnaUint32(4);
103 | private final JnaUint32 memory2 = new JnaUint32(16384);
104 | private final JnaUint32 parallelism2 = new JnaUint32(4);
105 | private final Size_t encLen2;
106 | private byte[] encoded2;
107 |
108 | private int mode = 1;
109 |
110 | public SafeMappedHasher(Miner parent, String id, long target, long maxTime) {
111 | super(parent, id, target, maxTime);
112 |
113 | // SET UP ARGON FOR DIRECT-TO-JNA-WRAPPER-EXEC
114 | argonlib = Argon2Library.INSTANCE;
115 | context = new Argon2_Context();
116 | context.outlen = new JnaUint32(32);
117 | context.out = new Memory(32l);
118 | // assigned per hash context.pwdLen
119 | context.saltlen = new JnaUint32(16);
120 | context.secret = null;
121 | context.secretlen = new JnaUint32(0);
122 | context.ad = null;
123 | context.adlen = new JnaUint32(0);
124 |
125 | context.t_cost = iterations;
126 | context.m_cost = memory;
127 | context.lanes = parallelism;
128 | context.threads = parallelism;
129 | context.flags = Argon2Library.ARGON2_DEFAULT_FLAGS;
130 | context.version = new JnaUint32(0x13);
131 |
132 | encLen = argonlib.argon2_encodedlen(iterations, memory, parallelism, saltLenI, hashLenI,
133 | argonType);
134 | encoded = new byte[encLen.intValue() - 1];
135 |
136 | encLen2 = argonlib.argon2_encodedlen(iterations2, memory2, parallelism2, saltLenI, hashLenI,
137 | argonType);
138 | encoded2 = new byte[encLen2.intValue() - 1];
139 | }
140 |
141 | private SecureRandom random = new SecureRandom();
142 | private Random insRandom = new Random(random.nextLong());
143 | private Encoder encoder = Base64.getEncoder();
144 | private String rawHashBase;
145 | private byte[] nonce = new byte[32];
146 | private byte[] salt = new byte[16];
147 | private Memory m_salt = new Memory(16l);
148 | private String rawNonce;
149 | private int rawNonceOffset;
150 | private int rawNonceLen = 42;
151 | private byte[] hashBaseBuffer;
152 | private Memory m_hashBaseBuffer;
153 | private Size_t hashBaseBufferSize;
154 | private byte[] fullHashBaseBuffer;
155 |
156 | private static final char[] safeEncode = {
157 | 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
158 | 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
159 | '0','1','2','3','4','5','6','7','8','9','.','/'};
160 |
161 | @Override
162 | public void update(BigInteger difficulty, String data, long limit, String publicKey, long blockHeight,
163 | boolean pause, int iters, int mem, int threads) {
164 | super.update(difficulty, data, limit, publicKey, blockHeight, pause, iters, mem, threads);
165 |
166 | if (this.mem == 16384) {
167 | mode = 2;
168 | } else {
169 | mode = 1; // assume only the two modes for now.
170 | }
171 |
172 | genNonce();
173 | }
174 |
175 | @Override
176 | public void newHeight(long oldBlockHeight, long newBlockHeight) {
177 | // no-op, we are locked into 10800 > territory now
178 | }
179 |
180 | private byte[] safeBase64Random(int bytes) {
181 | char[] buffer = new char[bytes];
182 | for (int i = 0; i < bytes; i++) {
183 | buffer[i] = safeEncode[random.nextInt(64)];
184 | }
185 | return String.valueOf(buffer).getBytes();
186 | }
187 |
188 | private byte[] safeBase64Random(byte[] buffer) {
189 | for (int i = 0; i < buffer.length;) {
190 | byte[] buff = Character.valueOf(safeEncode[random.nextInt(64)]).toString().getBytes();
191 | buffer[i++] = buff[0];
192 | if (buff.length>1) buffer[i++] = buff[1];
193 | if (buff.length>2) buffer[i++] = buff[2];
194 | if (buff.length>3) buffer[i++] = buff[3];
195 | }
196 | return buffer;
197 | }
198 |
199 | private String safeAlphaNumericRandom(int bytes) {
200 | char[] buffer = new char[bytes];
201 | for (int i = 0; i < bytes; i++) {
202 | buffer[i] = safeEncode[random.nextInt(62)];
203 | }
204 | return new String(buffer);
205 | }
206 |
207 |
208 | private void genNonce() {
209 | StringBuilder hashBase;
210 |
211 | rawNonce = safeAlphaNumericRandom(rawNonceLen);
212 |
213 | // prealloc probably saves us 10% on this op sequence
214 | hashBase = new StringBuilder(hashBufferSize); // size of key + nonce + difficult + argon + data + spacers
215 | hashBase.append(this.publicKey).append("-");
216 | rawNonceOffset = hashBase.length();
217 | hashBase.append(rawNonce).append("-");
218 | hashBase.append(this.data).append("-");
219 | hashBase.append(this.difficultyString);
220 |
221 | rawHashBase = hashBase.toString();
222 |
223 | hashBaseBuffer = rawHashBase.getBytes();
224 | hashBaseBufferSize = new Size_t(hashBaseBuffer.length);
225 | m_hashBaseBuffer = new Memory(hashBaseBuffer.length);
226 |
227 | if (mode == 1) {
228 | fullHashBaseBuffer = new byte[hashBaseBuffer.length + encLen.intValue() - 1];
229 | } else if (mode == 2) {
230 | fullHashBaseBuffer = new byte[hashBaseBuffer.length + encLen2.intValue() - 1];
231 | }
232 |
233 | m_hashBaseBuffer.write(0, hashBaseBuffer, 0, hashBaseBuffer.length);
234 | System.arraycopy(hashBaseBuffer, 0, fullHashBaseBuffer, 0, hashBaseBuffer.length);
235 | }
236 |
237 | /* Replace nonce in-place instead of regenerating the entirety. */
238 | private void regenNonce() {
239 | rawNonce = safeAlphaNumericRandom(rawNonceLen);
240 | byte[] rawNonceBytes = rawNonce.getBytes();
241 | m_hashBaseBuffer.write(rawNonceOffset, rawNonceBytes, 0, rawNonceBytes.length);
242 | System.arraycopy(rawNonceBytes, 0, hashBaseBuffer, rawNonceOffset, rawNonceBytes.length);
243 | System.arraycopy(rawNonceBytes, 0, fullHashBaseBuffer, rawNonceOffset, rawNonceBytes.length);
244 | }
245 |
246 | @Override
247 | public void go() {
248 | try {
249 | scratch = SafeMappedHasher.getScratch();
250 | } catch (OutOfMemoryError oome) {
251 | System.err.println("Please reduce the number of requested hashing workers. Your system lacks sufficient memory to run this many!");
252 | //System.err.println("Regrettably, this is a fatal error.");
253 | //oome.printStackTrace();
254 | active = false;
255 | //System.exit(1);
256 | return;
257 | }
258 | context.allocate_cbk = this;
259 | context.free_cbk = this;
260 |
261 | boolean doLoop = true;
262 | this.hashBegin = System.currentTimeMillis();
263 |
264 | this.parent.hasherCount.getAndIncrement();
265 | byte[] byteBase = null;
266 |
267 | MessageDigest sha512 = null;
268 | try {
269 | sha512 = MessageDigest.getInstance("SHA-512");
270 | } catch (NoSuchAlgorithmException e1) {
271 | System.err.println("Unable to find SHA-512 algorithm! Fatal error.");
272 | e1.printStackTrace();
273 | active = false;
274 | doLoop = false;
275 | System.exit(1);
276 | }
277 | if (active) {
278 | parent.workerInit(id);
279 | }
280 |
281 | long statCycle = 0l;
282 | long statBegin = 0l;
283 | long statArgonBegin = 0l;
284 | long statArgonEnd = 0l;
285 | long statShaBegin = 0l;
286 | long statShaEnd = 0l;
287 | long statEnd = 0l;
288 |
289 | try {
290 | boolean bound = Miner.PERMIT_AFINITY;
291 | if (Miner.PERMIT_AFINITY && Miner.CHECK_BIND) { // for some systems, this doesn't work, so we don't check.
292 | int activeCpu = Affinity.getCpu();
293 | BitSet affinity = Affinity.getAffinity();
294 | if (affinity == null || affinity.isEmpty() || affinity.cardinality() > 1) { // no affinity?
295 | Integer lastChance = AggressiveAffinityThreadFactory.AffineMap.get(Affinity.getThreadId());
296 | if (lastChance == null || lastChance < 0) {
297 | bound = false;
298 | } else { // see if lastChance equals actual CPU binding
299 | if (!lastChance.equals(activeCpu)) {
300 | // try to alter!
301 | AffinityLock.acquireLock(lastChance.intValue());
302 | System.out.println("We had locked on to " + lastChance.intValue() + " but lost it and are running on " + activeCpu);
303 | }
304 | }
305 | } else { // see if BitSet affinity equals actual CPU binding
306 | //BigInteger singleAffine = new BigInteger(affinity.toByteArray());
307 | //if (singleAffine.intValue() != activeCpu) {
308 | if (affinity.nextSetBit(0) != activeCpu) {
309 | // try to alter!
310 | AffinityLock.acquireLock(affinity.nextSetBit(0));
311 | System.out.println("We had locked on to " + affinity.nextSetBit(0) + " but lost it and are running on " + activeCpu);
312 | }
313 | }
314 | }
315 | while (doLoop && active) {
316 | if (this.pause) {
317 | try {
318 | Thread.sleep(50);
319 | } catch (InterruptedException e) {
320 | // ok, moving on.
321 | }
322 | continue;
323 | }
324 | statCycle = System.currentTimeMillis();
325 | statBegin = System.nanoTime();
326 | try {
327 | regenNonce();
328 |
329 | this.safeBase64Random(salt); //random.nextBytes(salt);
330 | m_salt.write(0, salt, 0, 16);
331 |
332 | /*System.out.println(String.format("%s\n%s\n%s\n", new String(hashBaseBuffer),
333 | new String(fullHashBaseBuffer), encoder.encodeToString(salt)));
334 | Thread.sleep(500l);*/
335 |
336 | statArgonBegin = System.nanoTime();
337 |
338 | int smode = mode;
339 | if (mode == 2) {
340 | context.t_cost = iterations2;
341 | context.m_cost = memory2;
342 | context.lanes = parallelism2;
343 | context.threads = parallelism2;
344 | } else {
345 | context.t_cost = iterations;
346 | context.m_cost = memory;
347 | context.lanes = parallelism;
348 | context.threads = parallelism;
349 | }
350 |
351 | // set argon params in context..
352 | context.out = new Memory(32l);
353 | context.salt = m_salt;
354 | context.pwdlen = new JnaUint32(hashBaseBuffer.length);
355 | m_hashBaseBuffer.write(0, hashBaseBuffer, 0, hashBaseBuffer.length);
356 | context.pwd = m_hashBaseBuffer;
357 | int res = argonlib.argon2_ctx(context, argonType);
358 | if (res != Argon2Library.ARGON2_OK) {
359 | System.out.println("HASH FAILURE!" + res);
360 | System.out.println(" hashes: " + hashCount);
361 | System.exit(res);
362 | }
363 | int res2 = 0;
364 | long finalDuration = 0;
365 | if (smode == mode) { // check if mode changed
366 | if (mode == 1) {
367 | res2 = argonlib.encode_ctx(encoded, encLen, context, argonType);
368 | } else if (mode == 2) {
369 | res2 = argonlib.encode_ctx(encoded2, encLen2, context, argonType);
370 | }
371 | if (res2 != Argon2Library.ARGON2_OK) {
372 | System.out.println("ENCODE FAILURE! " + res2);
373 | }
374 | statArgonEnd = System.nanoTime();
375 |
376 | if (mode == 1) {
377 | if (encoded[encoded.length - 1] == 0) {
378 | System.out.print("Encoded length failure.");
379 | }
380 |
381 | System.arraycopy(encoded, 0, fullHashBaseBuffer, hashBaseBufferSize.intValue(), encLen.intValue() - 1);
382 | } else if (mode == 2) {
383 | if (encoded2[encoded2.length - 1] == 0) {
384 | System.out.print("Encoded length failure.");
385 | }
386 |
387 | System.arraycopy(encoded2, 0, fullHashBaseBuffer, hashBaseBufferSize.intValue(), encLen2.intValue() - 1);
388 | }
389 |
390 | // 10-20ns (vs. 1200ns of strings in former StableHasher)
391 |
392 | statShaBegin = System.nanoTime();
393 |
394 | byteBase = sha512.digest(fullHashBaseBuffer);
395 | for (int i = 0; i < 5; i++) {
396 | byteBase = sha512.digest(byteBase);
397 | }
398 |
399 | statShaEnd = System.nanoTime();
400 | // shas total 4900-5000ns for all 6 digests, or < 1000ns ea
401 |
402 | StringBuilder duration = new StringBuilder(25);
403 | duration.append(byteBase[10] & 0xFF).append(byteBase[15] & 0xFF).append(byteBase[20] & 0xFF)
404 | .append(byteBase[23] & 0xFF).append(byteBase[31] & 0xFF).append(byteBase[40] & 0xFF)
405 | .append(byteBase[45] & 0xFF).append(byteBase[55] & 0xFF);
406 |
407 | finalDuration = new BigInteger(duration.toString()).divide(this.difficulty).longValue();
408 | // 385 ns for duration
409 |
410 | if (finalDuration > 0 && finalDuration <= this.limit) {
411 |
412 | if (mode == 1 ) {
413 | // why trim? the raw encoded has a trailing \x00 null char. Trim will remove it, same as we do in the arraycopy by doing encLen - 1.
414 | parent.submit(rawNonce, new String(encoded).trim(), finalDuration, this.difficulty.longValue(), this.getType(), this.blockHeight, this);
415 | } else if (mode == 2) {
416 | parent.submit(rawNonce, new String(encoded2).trim(), finalDuration, this.difficulty.longValue(), this.getType(), this.blockHeight, this);
417 | }
418 |
419 | if (finalDuration <= 240) {
420 | finds++;
421 | } else {
422 | shares++;
423 | }
424 | //genNonce(); // only gen a new nonce once we exhaust the one we had
425 | }
426 | }
427 |
428 | hashCount++;
429 | statEnd = System.nanoTime();
430 |
431 | if (finalDuration < this.bestDL) {
432 | this.bestDL = finalDuration;
433 | }
434 |
435 | this.argonTime += statArgonEnd - statArgonBegin;
436 | this.shaTime += statShaEnd - statShaBegin;
437 | this.nonArgonTime += (statArgonBegin - statBegin) + (statEnd - statArgonEnd);
438 |
439 | /*System.out.print(String.format("- r%d a%d s%d -",
440 | (statArgonBegin - statBegin),
441 | (statArgonEnd - statArgonBegin),
442 | (statShaEnd - statShaBegin)));*/
443 |
444 | } catch (Exception e) {
445 | System.err.println(id + "] This worker failed somehow. Killing it.");
446 | e.printStackTrace();
447 | System.err.println("Please report this to ProgrammerDan");
448 | doLoop = false;
449 | kill = true;
450 | }
451 | this.loopTime += System.currentTimeMillis() - statCycle;
452 |
453 | if (this.hashCount > this.targetHashCount || this.loopTime > this.maxTime) {
454 | if (Miner.PERMIT_AFINITY && Miner.CHECK_BIND) { // for some systems, this doesn't work, so we don't check.
455 | int activeCpu = Affinity.getCpu();
456 | BitSet affinity = Affinity.getAffinity();
457 | if (affinity == null || affinity.isEmpty() || affinity.cardinality() > 1) { // no affinity?
458 | Integer lastChance = AggressiveAffinityThreadFactory.AffineMap.get(Affinity.getThreadId());
459 | if (lastChance == null || lastChance < 0) {
460 | bound = false;
461 | } else { // see if lastChance equals actual CPU binding
462 | if (!lastChance.equals(activeCpu)) {
463 | // try to alter!
464 | AffinityLock.acquireLock(lastChance.intValue());
465 | System.out.println("We had locked on to " + lastChance.intValue() + " but lost it and are running on " + activeCpu);
466 | }
467 | }
468 | } else { // see if BitSet affinity equals actual CPU binding
469 | if (affinity.nextSetBit(0) != activeCpu) {
470 | // try to alter!
471 | AffinityLock.acquireLock(affinity.nextSetBit(0));
472 | System.out.println("We had locked on to " + affinity.nextSetBit(0) + " but lost it and are running on " + activeCpu);
473 | }
474 | }
475 | }
476 | this.hashEnd = System.currentTimeMillis();
477 | this.hashTime = this.hashEnd - this.hashBegin;
478 | this.hashBegin = System.currentTimeMillis();
479 | completeSession();
480 | this.loopTime = 0l;
481 | }
482 | }
483 | } catch (Throwable e) {
484 | e.printStackTrace();
485 | }
486 |
487 | if (kill) {
488 | scratch.clear(); // we don't return it. Let's clear it, and let it be GC'd. The Scratch will gen a new one.
489 | try {
490 | Method dispose = scratch.getClass().getDeclaredMethod("dispose");
491 | dispose.setAccessible(true);
492 | dispose.invoke(scratch);
493 | } catch (Throwable t) {
494 | System.err.println("After a potential memory failure was identified, our attempt to release this memory buffer has failed.");
495 | t.printStackTrace();
496 | }
497 | scratch = null;
498 | Memory.purge();
499 | } else {
500 | SafeMappedHasher.returnScratch(scratch);
501 | }
502 | this.hashEnd = System.currentTimeMillis();
503 | this.hashTime = this.hashEnd - this.hashBegin;
504 | this.parent.hasherCount.decrementAndGet();
505 | }
506 |
507 | // allocate
508 | public int invoke(PointerByReference memory, Size_t byte_to_allocate) {
509 |
510 | if (byte_to_allocate.intValue() > this.scratch.size()) {
511 | return -22; // memory allocation error
512 | }
513 |
514 | memory.setValue(this.scratch);
515 |
516 | return 0;
517 | }
518 |
519 | // no-op deallcate, wipe?
520 | public void invoke(Pointer memory, Size_t byte_to_allocate) {
521 | // we ignore this, since we manage memory on our own.
522 | }
523 |
524 | public String getType() {
525 | return "CPU";
526 | }
527 |
528 | public void kill() {
529 | kill = true;
530 | active = false;
531 | }
532 | }
533 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/Utility.java:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 | Copyright (c) 2018 AroDev, adaptation portions (c) 2018 ProgrammerDan (Daniel Boston)
4 |
5 | www.arionum.com
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of
16 | the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24 | OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | */
27 | package com.programmerdan.arionum.arionum_miner;
28 |
29 | import java.math.BigInteger;
30 | import java.nio.charset.Charset;
31 | import java.util.LinkedList;
32 |
33 | /**
34 | * Low efficiency port of base58 conversion utils from
35 | * commit e14b696362fb79d60c4ff8bc651185740b8021d9 on https://github.com/arionum/miner
36 | *
37 | * Credit to AroDev, and for base58 functions: https://github.com/tuupola/base58/
38 | *
39 | * @author ProgrammerDan (Daniel Boston)
40 | *
41 | */
42 | public class Utility {
43 | public static String base58_chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
44 |
45 | public static byte[] baseConvert(byte[] _source, int sourceBase, int targetBase) {
46 | LinkedList source = new LinkedList();
47 | for (byte sourceByte : _source ) {
48 | source.add(sourceByte);
49 | }
50 | LinkedList result = new LinkedList();
51 |
52 | int count = 0;
53 |
54 | while ((count = source.size()) > 0) {
55 | LinkedList quotient = new LinkedList();
56 | int remainder = 0;
57 | for (int i = 0; i != count; i++) {
58 | int accum = source.get(i) + remainder * sourceBase;
59 | int digit = (int) (accum / targetBase);
60 | remainder = accum % targetBase;
61 | if (quotient.size() > 0 || digit != 0) {
62 | quotient.add((byte) digit);
63 | }
64 | }
65 | result.addFirst((byte) remainder);
66 | source = quotient;
67 | }
68 |
69 | byte[] _result = new byte[result.size()];
70 | int i = 0;
71 | for(Byte resultByte : result) {
72 | _result[i] = resultByte;
73 | i++;
74 | }
75 |
76 | return _result;
77 | }
78 |
79 | public static String base58_decode(String data) {
80 | char[] dat = data.toCharArray();
81 | byte[] map = new byte[dat.length];
82 | for (int i = 0; i < dat.length; i++) {
83 | map[i] = (byte) base58_chars.indexOf(dat[i]);
84 | }
85 |
86 | byte[] converted = baseConvert(map, 58, 256);
87 | return new String(converted, Charset.forName("ASCII"));
88 | }
89 |
90 | /**
91 | * Be aware that php and java deal with number conversion pretty
92 | * divergently. More testing and figurin' needs doing to get this to
93 | * match the output of the php function.
94 | *
95 | * Use base58_decode string variant, where parity is achieved.
96 | *
97 | * @param data
98 | * @return
99 | */
100 | public static BigInteger base58_decodeInt(String data) {
101 | char[] dat = data.toCharArray();
102 | byte[] map = new byte[dat.length];
103 | for (int i = 0; i < dat.length; i++) {
104 | map[i] = (byte) base58_chars.indexOf(dat[i]);
105 | }
106 |
107 | byte[] converted = baseConvert(map, 58, 10);
108 | StringBuilder sb = new StringBuilder();
109 | for (byte a : converted) {
110 | sb.append(a);
111 | }
112 | return new BigInteger(sb.toString());
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/jna/Argon2Library.java:
--------------------------------------------------------------------------------
1 | package com.programmerdan.arionum.arionum_miner.jna;
2 |
3 | /*
4 | Included from de.mkammerer's library.
5 | de.mkammerer.argon2.jna
6 |
7 | This library is GPL3
8 |
9 |
10 | */
11 | import com.sun.jna.Library;
12 | import com.sun.jna.Native;
13 | import com.sun.jna.Pointer;
14 | import com.sun.jna.Callback;
15 | import com.sun.jna.ptr.PointerByReference;
16 |
17 | /**
18 | * JNA bindings for Argon2.
19 | */
20 | public interface Argon2Library extends Library {
21 | /**
22 | * Singleton instance.
23 | */
24 | Argon2Library INSTANCE = (Argon2Library) Native.loadLibrary("argon2", Argon2Library.class);
25 |
26 | /**
27 | * Return code if everything is okay.
28 | */
29 | int ARGON2_OK = 0;
30 |
31 | JnaUint32 ARGON2_DEFAULT_FLAGS = new JnaUint32(0);
32 |
33 |
34 | /*
35 | * Uses an Argon Context to generate a hash. The hash is in the "out" field.
36 | */
37 | int argon2_ctx(Argon2_Context context, Argon2_type type);
38 |
39 |
40 | /*
41 | * Uses an argon context to render a fully encoded Argon2 hash string in a
42 | * standard form. This is an Arionum-specific addition to the library header.
43 | */
44 | int encode_ctx(byte[] dst, Size_t dst_len, Argon2_Context ctx, Argon2_type type);
45 |
46 | /*
47 | int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
48 | const uint32_t parallelism, const void *pwd,
49 | const size_t pwdlen, const void *salt,
50 | const size_t saltlen, const size_t hashlen,
51 | char *encoded, const size_t encodedlen);
52 | */
53 |
54 | /**
55 | * Hashes a password with Argon2i, producing an encoded hash.
56 | *
57 | * @param t_cost Number of iterations
58 | * @param m_cost Sets memory usage to m_cost kibibytes
59 | * @param parallelism Number of threads and compute lanes
60 | * @param pwd Pointer to password
61 | * @param pwdlen Password size in bytes
62 | * @param salt Pointer to salt
63 | * @param saltlen Salt size in bytes
64 | * @param hashlen Desired length of the hash in bytes
65 | * @param encoded Buffer where to write the encoded hash
66 | * @param encodedlen Size of the buffer (thus max size of the encoded hash)
67 | * @return {@link #ARGON2_OK} if successful
68 | */
69 | int argon2i_hash_encoded(JnaUint32 t_cost, JnaUint32 m_cost, JnaUint32 parallelism, byte[] pwd, Size_t pwdlen, byte[] salt, Size_t saltlen, Size_t hashlen, byte[] encoded, Size_t encodedlen);
70 |
71 | /**
72 | * Hashes a password with Argon2i, producing an encoded hash.
73 | *
74 | * @param t_cost Number of iterations
75 | * @param m_cost Sets memory usage to m_cost kibibytes
76 | * @param parallelism Number of threads and compute lanes
77 | * @param pwd Pointer to password
78 | * @param pwdlen Password size in bytes
79 | * @param salt Pointer to salt
80 | * @param saltlen Salt size in bytes
81 | * @param hash Buffer where to write the raw hash
82 | * @param hashlen Desired length of the hash in bytes
83 | * @return {@link #ARGON2_OK} if successful
84 | */
85 | int argon2i_hash_raw(JnaUint32 t_cost, JnaUint32 m_cost, JnaUint32 parallelism, byte[] pwd, Size_t pwdlen, byte[] salt, Size_t saltlen, byte[] hash, Size_t hashlen);
86 |
87 | /**
88 | * Verifies a password against an Argon2i encoded string.
89 | *
90 | * @param encoded String encoding parameters, salt, hash
91 | * @param pwd Pointer to password
92 | * @param pwdlen Password size in bytes
93 | * @return ARGON2_OK if successful
94 | */
95 | /*
96 | int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen);
97 | */
98 | int argon2i_verify(byte[] encoded, byte[] pwd, Size_t pwdlen);
99 |
100 |
101 | /**
102 | * Returns the encoded hash length for the given input parameters.
103 | *
104 | * @param t_cost Number of iterations.
105 | * @param m_cost Memory usage in kibibytes.
106 | * @param parallelism Number of threads; used to compute lanes.
107 | * @param saltlen Salt size in bytes.
108 | * @param hashlen Hash size in bytes.
109 | * @param type The argon2 type.
110 | * @return The encoded hash length in bytes.
111 | */
112 | Size_t argon2_encodedlen(JnaUint32 t_cost, JnaUint32 m_cost, JnaUint32 parallelism, JnaUint32 saltlen, JnaUint32 hashlen, Argon2_type type);
113 |
114 | /**
115 | * Get the associated error message for given error code.
116 | *
117 | * @param error_code Numeric error code.
118 | * @return The error message associated with the given error code.
119 | */
120 | String argon2_error_message(int error_code);
121 |
122 |
123 | public interface AllocateFunction extends Callback {
124 | int invoke(PointerByReference memory, Size_t byte_to_allocate);
125 | }
126 |
127 | public interface DeallocateFunction extends Callback {
128 | void invoke(Pointer memory, Size_t byte_to_allocate);
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/jna/Argon2_Context.java:
--------------------------------------------------------------------------------
1 | package com.programmerdan.arionum.arionum_miner.jna;
2 |
3 | /*
4 |
5 | JNA wraps for argon context so I can pin memory
6 |
7 | MIT License, Copyright ProgrammerDan 2018
8 | */
9 |
10 | import java.util.List;
11 | import java.util.Arrays;
12 |
13 | import com.sun.jna.Structure;
14 | import com.sun.jna.Pointer;
15 |
16 | /**
17 | * argon2_context type for C interaction.
18 | */
19 | public class Argon2_Context extends Structure {
20 | public Pointer out;
21 | public JnaUint32 outlen;
22 |
23 | public Pointer pwd;
24 | public JnaUint32 pwdlen;
25 |
26 | public Pointer salt;
27 | public JnaUint32 saltlen;
28 |
29 | public Pointer secret;
30 | public JnaUint32 secretlen;
31 |
32 | public Pointer ad;
33 | public JnaUint32 adlen;
34 |
35 | public JnaUint32 t_cost;
36 | public JnaUint32 m_cost;
37 | public JnaUint32 lanes;
38 | public JnaUint32 threads;
39 |
40 | public JnaUint32 version;
41 |
42 | public Argon2Library.AllocateFunction allocate_cbk;
43 | public Argon2Library.DeallocateFunction free_cbk;
44 |
45 | public JnaUint32 flags;
46 |
47 | public List getFieldOrder() {
48 | return Arrays.asList( new String[] {
49 | "out", "outlen",
50 | "pwd", "pwdlen",
51 | "salt", "saltlen",
52 | "secret", "secretlen",
53 | "ad", "adlen",
54 | "t_cost", "m_cost",
55 | "lanes", "threads",
56 | "version",
57 | "allocate_cbk", "free_cbk",
58 | "flags"
59 | });
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/jna/Argon2_type.java:
--------------------------------------------------------------------------------
1 | package com.programmerdan.arionum.arionum_miner.jna;
2 |
3 | /*
4 | Included from de.mkammerer's library.
5 | de.mkammerer.argon2.jna
6 |
7 | This library is GPL3
8 |
9 |
10 | */
11 |
12 | import com.sun.jna.NativeLong;
13 |
14 | /**
15 | * argon2_type type for C interaction.
16 | */
17 | public class Argon2_type extends NativeLong {
18 | /**
19 | * Constructor.
20 | */
21 | public Argon2_type() {
22 | this(0);
23 | }
24 |
25 | /**
26 | * Constructor.
27 | *
28 | * @param value Value.
29 | */
30 | public Argon2_type(long value) {
31 | super(value);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/jna/JnaUint32.java:
--------------------------------------------------------------------------------
1 | package com.programmerdan.arionum.arionum_miner.jna;
2 |
3 | /*
4 | Included from de.mkammerer's library.
5 | de.mkammerer.argon2.jna
6 |
7 | This library is GPL3
8 |
9 |
10 | */
11 |
12 | import com.sun.jna.IntegerType;
13 |
14 | /**
15 | * uint32_t type for C interaction.
16 | */
17 | public class JnaUint32 extends IntegerType {
18 | /**
19 | * Constructor.
20 | */
21 | public JnaUint32() {
22 | this(0);
23 | }
24 |
25 | /**
26 | * Constructor.
27 | *
28 | * @param value Value.
29 | */
30 | public JnaUint32(int value) {
31 | super(4, value, true);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/jna/JnaUint8.java:
--------------------------------------------------------------------------------
1 | package com.programmerdan.arionum.arionum_miner.jna;
2 |
3 | /*
4 | Included from de.mkammerer's library.
5 | de.mkammerer.argon2.jna
6 |
7 | This library is GPL3
8 |
9 |
10 | */
11 |
12 | import com.sun.jna.IntegerType;
13 |
14 | /**
15 | * uint8_t type for C interaction.
16 | */
17 | public class JnaUint8 extends IntegerType {
18 | /**
19 | * Constructor.
20 | */
21 | public JnaUint8() {
22 | this(0);
23 | }
24 |
25 | /**
26 | * Constructor.
27 | *
28 | * @param value Value.
29 | */
30 | public JnaUint8(int value) {
31 | super(1, value, true);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/java/com/programmerdan/arionum/arionum_miner/jna/Size_t.java:
--------------------------------------------------------------------------------
1 | package com.programmerdan.arionum.arionum_miner.jna;
2 |
3 | /*
4 | Included from de.mkammerer's library.
5 | de.mkammerer.argon2.jna
6 |
7 | This library is GPL3
8 |
9 |
10 | */
11 |
12 | import com.sun.jna.IntegerType;
13 | import com.sun.jna.Native;
14 |
15 | /**
16 | * size_t type for C interaction.
17 | */
18 | public class Size_t extends IntegerType {
19 | /**
20 | * Constructor.
21 | */
22 | public Size_t() {
23 | this(0);
24 | }
25 |
26 | /**
27 | * Constructor.
28 | *
29 | * @param value Value.
30 | */
31 | public Size_t(long value) {
32 | super(Native.SIZE_T_SIZE, value);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/arionum-miner/src/main/resources/darwin/libargon2.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProgrammerDan/arionum-java/17d3ecedfbf6106e66b7a1b19702604df53f764d/arionum-miner/src/main/resources/darwin/libargon2.dylib
--------------------------------------------------------------------------------
/arionum-miner/src/main/resources/linux-x86-64/libargon2.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProgrammerDan/arionum-java/17d3ecedfbf6106e66b7a1b19702604df53f764d/arionum-miner/src/main/resources/linux-x86-64/libargon2.so
--------------------------------------------------------------------------------
/arionum-miner/src/main/resources/win32-x86-64/argon2-avx.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProgrammerDan/arionum-java/17d3ecedfbf6106e66b7a1b19702604df53f764d/arionum-miner/src/main/resources/win32-x86-64/argon2-avx.dll
--------------------------------------------------------------------------------
/arionum-miner/src/main/resources/win32-x86-64/argon2-avx2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProgrammerDan/arionum-java/17d3ecedfbf6106e66b7a1b19702604df53f764d/arionum-miner/src/main/resources/win32-x86-64/argon2-avx2.dll
--------------------------------------------------------------------------------
/arionum-miner/src/main/resources/win32-x86-64/argon2-avx512f.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProgrammerDan/arionum-java/17d3ecedfbf6106e66b7a1b19702604df53f764d/arionum-miner/src/main/resources/win32-x86-64/argon2-avx512f.dll
--------------------------------------------------------------------------------
/arionum-miner/src/main/resources/win32-x86-64/argon2-generic.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProgrammerDan/arionum-java/17d3ecedfbf6106e66b7a1b19702604df53f764d/arionum-miner/src/main/resources/win32-x86-64/argon2-generic.dll
--------------------------------------------------------------------------------
/arionum-miner/src/main/resources/win32-x86-64/argon2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProgrammerDan/arionum-java/17d3ecedfbf6106e66b7a1b19702604df53f764d/arionum-miner/src/main/resources/win32-x86-64/argon2.dll
--------------------------------------------------------------------------------