miner.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. #include "miner.h"
  2. #include "configure.h"
  3. #include "../src/cppcodec/base32_rfc4648.hpp"
  4. #include <QFile>
  5. #include <QDebug>
  6. #include <QRegularExpression>
  7. #include <iomanip>
  8. #include <iostream>
  9. #include <sstream>
  10. #include <sodium.h>
  11. QMutex Miner::m_mtx;
  12. std::time_t Miner::m_sygstartedin = std::time(NULL);
  13. int Miner::m_countsize = 0;
  14. std::atomic<quint64> Miner::m_totalcount (0);
  15. std::atomic<quint64> Miner::m_countfortune (0);
  16. std::chrono::steady_clock::duration Miner::m_blocks_duration;
  17. Miner::Miner(Widget *w): window(w)
  18. {
  19. m_countsize = 30000 * window->conf.proc; // Периодичность обновления счетчиков
  20. window->conf.mode == 0 ? window->conf.outputfile = "syg-ipv6-pattern.txt" :
  21. window->conf.mode == 1 ? window->conf.outputfile = "syg-ipv6-high.txt" :
  22. window->conf.mode == 2 ? window->conf.outputfile = "syg-ipv6-pattern-high.txt" :
  23. window->conf.mode == 3 ? window->conf.outputfile = "syg-ipv6-regexp.txt" :
  24. window->conf.mode == 4 ? window->conf.outputfile = "syg-ipv6-regexp-high.txt" :
  25. window->conf.mode == 5 ? window->conf.outputfile = "syg-meshname-pattern.txt" :
  26. /* 6 */ window->conf.outputfile = "syg-meshname-regexp.txt" ;
  27. initializeLogFile();
  28. if (window->conf.mode == 6)
  29. {
  30. // поиск по сырому base32, где конец - это паддинг "====".
  31. for (auto it = window->conf.str.begin(); it != window->conf.str.end(); ++it)
  32. {
  33. if (*it == '$') *it = '=';
  34. }
  35. }
  36. if (window->conf.mode == 5) // meshname pattern
  37. {
  38. window->conf.str = pickupStringForMeshname(window->conf.str);
  39. }
  40. QObject::connect(this, &Miner::setLog, window, &Widget::setLog, Qt::QueuedConnection);
  41. QObject::connect(this, &Miner::setAddr, window, &Widget::setAddr, Qt::QueuedConnection);
  42. }
  43. void Miner::dropCounters()
  44. {
  45. m_sygstartedin = std::time(NULL);
  46. m_countsize = 0;
  47. m_totalcount = 0;
  48. m_countfortune = 0;
  49. m_blocks_duration = std::chrono::steady_clock::duration::zero();
  50. }
  51. void Miner::initializeLogFile()
  52. {
  53. QFile output(window->conf.outputfile);
  54. if (output.exists())
  55. {
  56. return;
  57. }
  58. if (not output.open(QIODevice::WriteOnly))
  59. {
  60. qDebug() << __PRETTY_FUNCTION__ << "can't initialize output file";
  61. return;
  62. }
  63. output.write("******************************************************\n"
  64. "Change PublicKey and PrivateKey to your yggdrasil.conf\n"
  65. "Windows: C:\\ProgramData\\Yggdrasil\\yggdrasil.conf\n"
  66. "Debian: /etc/yggdrasil.conf\n"
  67. "******************************************************\n");
  68. output.close();
  69. }
  70. void Miner::logStatistics()
  71. {
  72. if (m_totalcount % m_countsize == 0)
  73. {
  74. auto timedays = (std::time(NULL) - m_sygstartedin) / 86400;
  75. auto timehours = ((std::time(NULL) - m_sygstartedin) - (timedays * 86400)) / 3600;
  76. auto timeminutes = ((std::time(NULL) - m_sygstartedin) - (timedays * 86400) - (timehours * 3600)) / 60;
  77. auto timeseconds = (std::time(NULL) - m_sygstartedin) - (timedays * 86400) - (timehours * 3600) - (timeminutes * 60);
  78. std::chrono::duration<double, std::milli> df = m_blocks_duration;
  79. m_blocks_duration = std::chrono::steady_clock::duration::zero();
  80. quint64 khs = window->conf.proc * m_countsize / df.count();
  81. std::stringstream ss;
  82. ss << std::setw(2) << std::setfill('0') << timedays << ":" << std::setw(2) << std::setfill('0')
  83. << timehours << ":" << std::setw(2) << timeminutes << ":" << std::setw(2) << timeseconds;
  84. emit setLog(QString::fromStdString(ss.str()), m_totalcount, m_countfortune, khs);
  85. }
  86. }
  87. void Miner::logKeys(const Address& raw, const KeysBox keys)
  88. {
  89. QString base32 = getBase32(raw);
  90. if (window->conf.mode == 5 || window->conf.mode == 6) emit setAddr(pickupMeshnameForOutput(base32));
  91. else emit setAddr(getAddress(raw));
  92. m_mtx.lock();
  93. QFile output(window->conf.outputfile);
  94. if (not output.open(QIODevice::WriteOnly | QIODevice::Append))
  95. {
  96. qDebug() << __PRETTY_FUNCTION__ << "can't write log file";
  97. return;
  98. }
  99. const QByteArray publicKey = keyToString(keys.PublicKey).toUtf8();
  100. const QByteArray data = "\n"
  101. "Domain: " + pickupMeshnameForOutput(base32).toUtf8() + "\n"
  102. "Address: " + getAddress(raw).toUtf8() + "\n"
  103. "PublicKey: " + publicKey + "\n"
  104. "PrivateKey: " + keyToString(keys.PrivateKey).toUtf8() + publicKey + "\n";
  105. output.write(data);
  106. output.close();
  107. m_mtx.unlock();
  108. }
  109. QString Miner::getBase32(const Address& rawAddr)
  110. {
  111. return QString::fromStdString(cppcodec::base32_rfc4648::encode(rawAddr.data(), 16));
  112. }
  113. /**
  114. * pickupStringForMeshname получает человекочитаемую строку
  115. * типа fsdasdaklasdgdas.meship и возвращает значение, пригодное
  116. * для поиска по meshname-строке: удаляет возможную доменную зону
  117. * (всё после точки и саму точку), а также делает все буквы
  118. * заглавными.
  119. */
  120. QString Miner::pickupStringForMeshname(QString str)
  121. {
  122. str = str.toUpper();
  123. qsizetype dotPos = str.indexOf('.');
  124. if (dotPos >= 0)
  125. {
  126. str.remove(dotPos, str.size()-dotPos);
  127. }
  128. return str;
  129. }
  130. /**
  131. * pickupMeshnameForOutput получает сырое base32 значение
  132. * типа KLASJFHASSA7979====== и возвращает meshname-домен:
  133. * делает все символы строчными и удаляет паддинги ('='),
  134. * а также добавляет доменную зону ".meship".
  135. */
  136. QString Miner::pickupMeshnameForOutput(QString str)
  137. {
  138. str = str.toLower();
  139. str.remove('=');
  140. return str + ".meship";
  141. }
  142. QString Miner::keyToString(const Key& key)
  143. {
  144. return hexArrayToString(key.data(), KEYSIZE);
  145. }
  146. QString Miner::hexArrayToString(const uint8_t* bytes, int length)
  147. {
  148. std::stringstream ss;
  149. for (int i = 0; i < length; i++)
  150. {
  151. ss << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(bytes[i]);
  152. }
  153. return QString::fromStdString(ss.str());
  154. }
  155. QString Miner::getAddress(const Address& rawAddr)
  156. {
  157. char ipStrBuf[46];
  158. inet_ntop(AF_INET6, rawAddr.data(), ipStrBuf, 46);
  159. return ipStrBuf;
  160. }
  161. KeysBox Miner::getKeyPair()
  162. {
  163. KeysBox keys;
  164. uint8_t sk[64];
  165. crypto_sign_ed25519_keypair(keys.PublicKey.data(), sk);
  166. memcpy(keys.PrivateKey.data(), sk, 32);
  167. return keys;
  168. }
  169. void Miner::getRawAddress(int lErase, Key InvertedPublicKey, Address& rawAddr)
  170. {
  171. ++lErase; // лидирующие единицы + первый ноль
  172. int bitsToShift = lErase % 8;
  173. int start = lErase / 8;
  174. for(int i = start; i < start + 15; ++i)
  175. {
  176. InvertedPublicKey[i] <<= bitsToShift;
  177. InvertedPublicKey[i] |= (InvertedPublicKey[i + 1] >> (8 - bitsToShift));
  178. }
  179. rawAddr[0] = 0x02;
  180. rawAddr[1] = lErase - 1;
  181. for (int i = 0; i < 14; ++i)
  182. {
  183. rawAddr[i + 2] = InvertedPublicKey[i+start];
  184. }
  185. }
  186. Key Miner::bitwiseInverse(const Key& key)
  187. {
  188. Key inverted;
  189. for(size_t i = 0; i < key.size(); ++i)
  190. {
  191. inverted[i] = ~key[i];
  192. }
  193. return inverted;
  194. }
  195. int Miner::getOnes(const Key& value)
  196. {
  197. const int zeroBytesMap[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
  198. int leadOnes = 0; // кол-во лидирующих единиц
  199. for (int i = 0; i < 17; ++i) // 32B(ключ) - 15B(IPv6 без 0x02) = 17B(возможных лидирующих единиц)
  200. {
  201. for (int j = 0; j < 8; ++j)
  202. {
  203. if (value[i] & zeroBytesMap[j]) ++leadOnes;
  204. else return leadOnes;
  205. }
  206. }
  207. return 0; // никогда не случится
  208. }
  209. void Miner::run()
  210. {
  211. Address rawAddr;
  212. const QRegularExpression regx(window->conf.str);
  213. int ones = 0;
  214. for (;;) // основной цикл майнинга
  215. {
  216. if (window->conf.stop) break;
  217. auto start_time = std::chrono::steady_clock::now();
  218. KeysBox keys = getKeyPair();
  219. Key invKey = bitwiseInverse(keys.PublicKey);
  220. ones = getOnes(invKey);
  221. if (window->conf.mode == 0) // IPv6 pattern mining
  222. {
  223. getRawAddress(ones, invKey, rawAddr);
  224. if (getAddress(rawAddr).contains(window->conf.str))
  225. {
  226. processFortuneKey(keys);
  227. }
  228. }
  229. if (window->conf.mode == 1) // high mining
  230. {
  231. if (ones > window->conf.high)
  232. {
  233. if (window->conf.letsup) window->conf.high = ones;
  234. processFortuneKey(keys);
  235. }
  236. }
  237. if (window->conf.mode == 2) // pattern & high mining
  238. {
  239. getRawAddress(ones, invKey, rawAddr);
  240. if (ones > window->conf.high and getAddress(rawAddr).contains(window->conf.str))
  241. {
  242. if (window->conf.letsup) window->conf.high = ones;
  243. processFortuneKey(keys);
  244. }
  245. }
  246. if (window->conf.mode == 3) // IPv6 regexp mining
  247. {
  248. getRawAddress(ones, invKey, rawAddr);
  249. if (getAddress(rawAddr).contains(regx))
  250. {
  251. processFortuneKey(keys);
  252. }
  253. }
  254. if (window->conf.mode == 4) // IPv6 regexp & high mining
  255. {
  256. getRawAddress(ones, invKey, rawAddr);
  257. if (ones > window->conf.high and getAddress(rawAddr).contains(regx))
  258. {
  259. if (window->conf.letsup) window->conf.high = ones;
  260. processFortuneKey(keys);
  261. }
  262. }
  263. if (window->conf.mode == 5) // meshname pattern mining
  264. {
  265. getRawAddress(ones, invKey, rawAddr);
  266. if (getBase32(rawAddr).contains(window->conf.str))
  267. {
  268. processFortuneKey(keys);
  269. }
  270. }
  271. if (window->conf.mode == 6) // meshname regexp mining
  272. {
  273. getRawAddress(ones, invKey, rawAddr);
  274. if (getBase32(rawAddr).contains(regx))
  275. {
  276. processFortuneKey(keys);
  277. }
  278. }
  279. auto stop_time = std::chrono::steady_clock::now();
  280. ++m_totalcount;
  281. m_blocks_duration += stop_time - start_time;
  282. logStatistics();
  283. }
  284. }
  285. void Miner::processFortuneKey(const KeysBox& keys)
  286. {
  287. Key invKey = bitwiseInverse(keys.PublicKey);
  288. int ones = getOnes(invKey);
  289. Address rawAddr;
  290. getRawAddress(ones, invKey, rawAddr);
  291. ++m_countfortune;
  292. logKeys(rawAddr, keys);
  293. logStatistics();
  294. }