main.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198
  1. /* Copyright (C) 1883 Thomas Edison - All Rights Reserved
  2. * You may use, distribute and modify this code under the
  3. * terms of the GPLv3 license, which unfortunately won't be
  4. * written for another century.
  5. *
  6. * You should have received a copy of the LICENSE file with
  7. * this file.
  8. */
  9. #if defined(__linux__)
  10. #include <execinfo.h>
  11. #include <pwd.h>
  12. #endif
  13. #include <algorithm>
  14. #include <condition_variable>
  15. #include <string>
  16. #include <boost/algorithm/string.hpp>
  17. #include <boost/function.hpp>
  18. #include <boost/program_options.hpp>
  19. #include <openssl/crypto.h>
  20. #include <openssl/opensslv.h>
  21. #include <nsfminer/buildinfo.h>
  22. #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
  23. #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
  24. #endif
  25. #include <libeth/Farm.h>
  26. #if ETH_ETHASHCL
  27. #include <libcl/CLMiner.h>
  28. #endif
  29. #if ETH_ETHASHCUDA
  30. #include <libcuda/CUDAMiner.h>
  31. #endif
  32. #if ETH_ETHASHCPU
  33. #include <libcpu/CPUMiner.h>
  34. #endif
  35. #include <libpool/PoolManager.h>
  36. #if API_CORE
  37. #include <libapi/ApiServer.h>
  38. #include <regex>
  39. #endif
  40. #include <ethash/version.h>
  41. using namespace std;
  42. using namespace dev;
  43. using namespace dev::eth;
  44. using namespace boost::program_options;
  45. // Global vars
  46. bool g_running = false;
  47. bool g_seqDAG = false;
  48. bool g_exitOnError = false; // Whether or not miner should exit on mining threads errors
  49. mutex g_seqDAGMutex;
  50. condition_variable g_shouldstop;
  51. boost::asio::io_service g_io_service; // The IO service itself
  52. static bool should_list;
  53. static void headers(vector<string>& h, bool color) {
  54. const string yellow(color ? EthYellow : "");
  55. const string white(color ? EthWhite : "");
  56. const string reset(color ? EthReset : "");
  57. auto* bi = nsfminer_get_buildinfo();
  58. stringstream ss;
  59. ss << yellow << "nsfminer " << bi->project_version << " (No stinkin' fees edition)";
  60. h.push_back(ss.str());
  61. ss.str("");
  62. ss << white << "Copyright 2021 Jean M. Cyr, Licensed under the terms";
  63. h.push_back(ss.str());
  64. ss.str("");
  65. ss << white << " of the GNU General Public License Version 3";
  66. h.push_back(ss.str());
  67. ss.str("");
  68. ss << white << "https://github.com/no-fee-ethereum-mining/nsfminer";
  69. h.push_back(ss.str());
  70. ss.str("");
  71. ss << white << "Build: " << bi->system_name << '/' << bi->build_type << '/' << bi->compiler_id;
  72. h.push_back(ss.str());
  73. ss.str("");
  74. ss << white << "3rd Party: ";
  75. #if defined(__GNUC__)
  76. ss << "GCC " << bi->compiler_version << ", ";
  77. #else
  78. ss << "MSVC " << bi->compiler_version << ", ";
  79. #endif
  80. #if ETH_ETHASHCUDA
  81. int v;
  82. if (cudaRuntimeGetVersion(&v) == cudaSuccess)
  83. ss << "CUDA " << v / 1000 << '.' << (v % 100) / 10 << ", ";
  84. #endif
  85. ss << "Boost " << BOOST_VERSION / 100000 << '.' << BOOST_VERSION / 100 % 1000 << '.' << BOOST_VERSION % 100;
  86. h.push_back(ss.str());
  87. ss.str("");
  88. ss << white << "3rd Party: " << OPENSSL_VERSION_TEXT;
  89. h.push_back(ss.str());
  90. char username[64];
  91. #if defined(__linux__)
  92. uid_t uid = geteuid();
  93. struct passwd* pw = getpwuid(uid);
  94. strcpy(username, pw ? pw->pw_name : "unknown");
  95. #else
  96. DWORD size = sizeof(username) - 1;
  97. if (!GetUserName(username, &size))
  98. strcpy(username, "unknown");
  99. #endif
  100. ss.str("");
  101. ss << (color ? EthWhite : "") << "Running as user: " << username;
  102. h.push_back(ss.str());
  103. }
  104. static void on_help_module(string m) {
  105. static const vector<string> modules({
  106. #if ETH_ETHASHCL
  107. "cl",
  108. #endif
  109. #if ETH_ETHASHCUDA
  110. "cu",
  111. #endif
  112. #if ETH_ETHASHCPU
  113. "cp",
  114. #endif
  115. #if API_CORE
  116. "api",
  117. #endif
  118. #ifdef _WIN32
  119. "env",
  120. #endif
  121. "con", "test", "misc", "test", "conf", "reboot"
  122. });
  123. if (find(modules.begin(), modules.end(), m) != modules.end())
  124. return;
  125. string msg("The --help-module parameter must be one of the following:\n ");
  126. bool first = true;
  127. for (auto& m : modules) {
  128. msg += first ? "" : ", " + m;
  129. first = false;
  130. }
  131. throw boost::program_options::error(msg);
  132. }
  133. static void on_nonce(string n) {
  134. for (const auto& c : n)
  135. if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
  136. throw boost::program_options::error("The --nonce value must be a hex string");
  137. }
  138. static void on_verbosity(unsigned u) {
  139. if (u < LOG_NEXT)
  140. return;
  141. throw boost::program_options::error("The --verbosity value must be less than " + to_string(LOG_NEXT));
  142. }
  143. static void on_hwmon(unsigned u) {
  144. if (u < 3)
  145. return;
  146. throw boost::program_options::error("The --HWMON value must be 0, 1 or 2");
  147. }
  148. #if API_CORE
  149. static void on_api_port(int i) {
  150. if (i >= -65535 && i <= 65535)
  151. return;
  152. throw boost::program_options::error("The --api-port value is out of range");
  153. }
  154. #endif
  155. #if ETH_ETHASHCUDA
  156. static void on_cu_block_size(unsigned b) {
  157. if (b == 32 || b == 64 || b == 128 || b == 256)
  158. return;
  159. throw boost::program_options::error("The --cu-block value is out of range");
  160. }
  161. static void on_cu_streams(unsigned s) {
  162. if (s == 1 || s == 2 || s == 4)
  163. return;
  164. throw boost::program_options::error("The --cu-streams value is out of range");
  165. }
  166. #endif
  167. #if ETH_ETHASHCL
  168. static void on_cl_local_work(unsigned b) {
  169. if (b == 64 || b == 128 || b == 256)
  170. return;
  171. throw boost::program_options::error("The --cl-work value is out of range");
  172. }
  173. #endif
  174. class MinerCLI {
  175. public:
  176. enum class OperationMode { None, Simulation, Mining };
  177. MinerCLI() : m_cliDisplayTimer(g_io_service), m_io_strand(g_io_service) {
  178. // Initialize display timer as sleeper
  179. m_cliDisplayTimer.expires_from_now(boost::posix_time::pos_infin);
  180. m_cliDisplayTimer.async_wait(m_io_strand.wrap(
  181. boost::bind(&MinerCLI::cliDisplayInterval_elapsed, this, boost::asio::placeholders::error)));
  182. // Start io_service in it's own thread
  183. m_io_thread = thread{boost::bind(&boost::asio::io_service::run, &g_io_service)};
  184. // Io service is now live and running
  185. // All components using io_service should post to reference of g_io_service
  186. // and should not start/stop or even join threads (which heavily time consuming)
  187. }
  188. virtual ~MinerCLI() {
  189. m_cliDisplayTimer.cancel();
  190. g_io_service.stop();
  191. m_io_thread.join();
  192. }
  193. void cliDisplayInterval_elapsed(const boost::system::error_code& ec) {
  194. if (!ec && g_running) {
  195. if (g_logOptions & LOG_MULTI) {
  196. list<string> vs;
  197. Farm::f().Telemetry().strvec(vs);
  198. string s(vs.front());
  199. vs.pop_front();
  200. while (!vs.empty()) {
  201. cnote << s << vs.front();
  202. vs.pop_front();
  203. }
  204. } else
  205. cnote << Farm::f().Telemetry().str();
  206. // Restart timer
  207. m_cliDisplayTimer.expires_from_now(boost::posix_time::seconds(m_cliDisplayInterval));
  208. m_cliDisplayTimer.async_wait(m_io_strand.wrap(
  209. boost::bind(&MinerCLI::cliDisplayInterval_elapsed, this, boost::asio::placeholders::error)));
  210. }
  211. }
  212. static void signalHandler(int sig) {
  213. dev::setThreadName("main");
  214. switch (sig) {
  215. #if defined(__linux__)
  216. #define BACKTRACE_MAX_FRAMES 30
  217. case SIGSEGV:
  218. static bool in_handler = false;
  219. if (!in_handler) {
  220. int j, nptrs;
  221. void* buffer[BACKTRACE_MAX_FRAMES];
  222. char** symbols;
  223. in_handler = true;
  224. dev::setThreadName("main");
  225. cerr << "SIGSEGV encountered ...\n";
  226. cerr << "stack trace:\n";
  227. nptrs = backtrace(buffer, BACKTRACE_MAX_FRAMES);
  228. cerr << "backtrace() returned " << nptrs << " addresses\n";
  229. symbols = backtrace_symbols(buffer, nptrs);
  230. if (symbols == NULL) {
  231. perror("backtrace_symbols()");
  232. exit(EXIT_FAILURE); // Also exit 128 ??
  233. }
  234. for (j = 0; j < nptrs; j++)
  235. cerr << symbols[j] << "\n";
  236. free(symbols);
  237. in_handler = false;
  238. }
  239. exit(128);
  240. #undef BACKTRACE_MAX_FRAMES
  241. #endif
  242. case (999U):
  243. // Compiler complains about the lack of
  244. // a case statement in Windows
  245. // this makes it happy.
  246. break;
  247. default:
  248. cerr << endl;
  249. ccrit << "Got interrupt ...";
  250. g_running = false;
  251. g_shouldstop.notify_all();
  252. break;
  253. }
  254. }
  255. #if API_CORE
  256. static void ParseBind(const string& inaddr, string& outaddr, int& outport, bool advertise_negative_port) {
  257. regex pattern("([\\da-fA-F\\.\\:]*)\\:([\\d\\-]*)");
  258. smatch matches;
  259. if (regex_match(inaddr, matches, pattern)) {
  260. // Validate Ip address
  261. boost::system::error_code ec;
  262. outaddr = boost::asio::ip::address::from_string(matches[1], ec).to_string();
  263. if (ec)
  264. throw invalid_argument("Invalid Ip Address");
  265. // Parse port ( Let exception throw )
  266. outport = stoi(matches[2]);
  267. if (advertise_negative_port) {
  268. if (outport < -65535 || outport > 65535 || outport == 0)
  269. throw invalid_argument("Invalid port number. Allowed non zero values in range [-65535 .. 65535]");
  270. } else {
  271. if (outport < 1 || outport > 65535)
  272. throw invalid_argument("Invalid port number. Allowed non zero values in range [1 .. 65535]");
  273. }
  274. } else {
  275. throw invalid_argument("Invalid syntax");
  276. }
  277. }
  278. #endif
  279. bool validateArgs(int argc, char** argv) {
  280. queue<string> warnings;
  281. bool cl_miner, cuda_miner, cpu_miner;
  282. vector<string> pools;
  283. options_description general("General options");
  284. options_description test("Test options");
  285. options_description misc("Miscellaneous options");
  286. #if ETH_ETHASHCL
  287. options_description cl("OpenCL options");
  288. #endif
  289. #if ETH_ETHASHCUDA
  290. options_description cu("CUDA options");
  291. #endif
  292. #if ETH_ETHASHCPU
  293. options_description cp("CPU options");
  294. #endif
  295. #if API_CORE
  296. options_description api("API options");
  297. #endif
  298. // clang-format off
  299. general.add_options()
  300. ("help,h", "This help message")("help-module,H",
  301. value<string>()->notifier(on_help_module),
  302. "Help for a given module, one of: "
  303. #if ETH_ETHASHCL
  304. "cl, "
  305. #endif
  306. #if ETH_ETHASHCUDA
  307. "cu, "
  308. #endif
  309. #if ETH_ETHASHCPU
  310. "cp, "
  311. #endif
  312. #if API_CORE
  313. "api, "
  314. #endif
  315. "misc, "
  316. #ifdef _WIN32
  317. "env, "
  318. #endif
  319. "con, test, conf or reboot")
  320. ("version,V",
  321. "The version number")
  322. ("pool,P", value<vector<string>>()->multitoken(),
  323. "One or more Stratum pool or http (getWork) connection as URL(s)\n\n"
  324. "scheme://[user[.workername][:password]@]hostname:port[/...]\n\n"
  325. "For details and some samples how to fill in this value please use\n"
  326. "nsfminer --help-module con\n\n")
  327. ("config,F", value<string>(),
  328. "Configuration file name. See '-H conf' for details.")
  329. #if ETH_ETHASHCL
  330. ("opencl,G",
  331. "Mine/Benchmark using OpenCL only")
  332. #endif
  333. #if ETH_ETHASHCUDA
  334. ("cuda,U",
  335. "Mine/Benchmark using CUDA only")
  336. #endif
  337. #if ETH_ETHASHCPU
  338. ("cpu",
  339. "Development ONLY ! (NO MINING)")
  340. #endif
  341. ;
  342. misc.add_options()
  343. ("verbosity,v",
  344. value<unsigned>()->default_value(0)->notifier(on_verbosity),
  345. "Set output verbosity level. Use the sum of :\n"
  346. "1 - log per GPU status lines\n"
  347. "2 - log per GPU solutions\n"
  348. #ifdef DEV_BUILD
  349. "\n16 - log stratum messages\n"
  350. "32 - log connection events\n"
  351. "64 - log job switch times\n"
  352. "128 - log share submit times"
  353. #endif
  354. )
  355. ("getwork-recheck", value<unsigned>()->default_value(500),
  356. "Set polling interval for new work in getWork mode. "
  357. "Value expressed in milliseconds. "
  358. "It has no meaning in stratum mode")
  359. ("retry-delay", value<unsigned>()->default_value(0),
  360. "Delay in seconds before reconnection retry")
  361. ("retry-max", value<unsigned>()->default_value(3),
  362. "Set number of reconnection retries to same pool. "
  363. "Set to 0 for infinite retries.")
  364. ("work-timeout", value<unsigned>()->default_value(180),
  365. "If no new work received from pool after this "
  366. "amount of time the connection is dropped. "
  367. "Value expressed in seconds.")
  368. ("response-timeout", value<unsigned>()->default_value(2),
  369. "If no response from pool to a stratum message "
  370. "after this amount of time the connection is dropped")
  371. ("report-hashrate,R",
  372. "Report miner hash rate to the pool")
  373. ("display-interval", value<unsigned>()->default_value(5),
  374. "Statistic display interval in seconds")
  375. ("HWMON", value<unsigned>()->default_value(0)->notifier(on_hwmon),
  376. "GPU hardware monitoring level. Can be one of:\n"
  377. "0 - No monitoring\n"
  378. "1 - Monitor temperature and fan percentage\n"
  379. "2 - As 1 plus monitor power drain")
  380. ("exit",
  381. "Stop miner whenever an error is encountered")
  382. ("failover-timeout", value<unsigned>()->default_value(0),
  383. "Sets the number of minutes miner can stay "
  384. "connected to a fail-over pool before trying to "
  385. "reconnect to the primary (the first) connection.")
  386. ("nocolor",
  387. "Monochrome display log lines")
  388. ("syslog",
  389. "Use syslog appropriate output (drop timestamp "
  390. "and channel prefix)")
  391. #if ETH_ETHASHCL || ETH_ETHASHCUDA || ETH_ETHASH_CPU
  392. ("list-devices,L",
  393. "Lists the detected OpenCL/CUDA devices and "
  394. "exits. Can be combined with -G or -U flags")
  395. #endif
  396. ("tstop", value<unsigned>()->default_value(0),
  397. "Suspend mining on GPU which temperature is above "
  398. "this threshold. Implies --HWMON 1. "
  399. "If not set or zero no temp control is performed")
  400. ("tstart", value<unsigned>()->default_value(0),
  401. "Resume mining on previously overheated GPU when "
  402. "temp drops below this threshold. Implies --HWMON 1. "
  403. "Must be lower than --tstart")
  404. ("nonce,n", value<string>()->default_value("")->notifier(on_nonce),
  405. "Hex string specifying the upper bits of miner's "
  406. "start nonce. Can be used to ensure multiple miners "
  407. "are not searching overlapping nonce ranges.")
  408. ("devices", value<vector<unsigned>>()->multitoken(),
  409. "List of space separated device numbers to be used")
  410. ("seq",
  411. "Generate DAG sequentially, one GPU at a time.");
  412. #if API_CORE
  413. api.add_options()
  414. ("api-bind", value<string>()->default_value(""),
  415. "Set the API address:port the miner should listen "
  416. "on. Use negative port number for readonly mode")
  417. ("api-port", value<int>()->default_value(0)->notifier(on_api_port),
  418. "Set the API port, the miner should listen on all "
  419. "bound addresses. Use negative numbers for readonly "
  420. "mode")
  421. ("api-password", value<string>()->default_value(""),
  422. "Set the password to protect interaction with API "
  423. "server. If not set, any connection is granted access. "
  424. "Be advised passwords are sent unencrypted");
  425. #endif
  426. #if ETH_ETHASHCUDA
  427. cu.add_options()
  428. ("cu-block", value<unsigned>()->default_value(128)->notifier(on_cu_block_size),
  429. "Set the block size, valid values are 32, 64, 128, or 256")
  430. ("cu-streams", value<unsigned>()->default_value(2)->notifier(on_cu_streams),
  431. "Set the number of streams per GPU, valid values 1, 2 or 4");
  432. #endif
  433. #if ETH_ETHASHCL
  434. cl.add_options()
  435. ("cl-work", value<unsigned>()->default_value(128)->notifier(on_cl_local_work),
  436. "Set the work group size, valid values are 64 128 or 256")
  437. ("cl-split",
  438. "Force split-DAG mode. May improve performance on older GPU models.");
  439. #endif
  440. test.add_options()
  441. ("benchmark,M", value<unsigned>(),
  442. "Mining test. Used to test hashing speed. "
  443. "Specify the block number to test on.")
  444. ("simulate,Z", value<unsigned>(),
  445. "Mining test. Used to test hashing speed. "
  446. "Specify the block number to test on.");
  447. // clang-format on
  448. options_description all("All options");
  449. all.add(general)
  450. #if ETH_ETHASHCL
  451. .add(cl)
  452. #endif
  453. #if ETH_ETHASHCUDA
  454. .add(cu)
  455. #endif
  456. #if ETH_ETHASHCPU
  457. .add(cp)
  458. #endif
  459. #if API_CORE
  460. .add(api)
  461. #endif
  462. .add(test)
  463. .add(misc);
  464. options_description visible("General options");
  465. visible.add(general);
  466. variables_map vm;
  467. try {
  468. parsed_options parsed = command_line_parser(argc, argv).options(all).allow_unregistered().run();
  469. store(parsed, vm);
  470. if (vm.count("config")) {
  471. ifstream ifs(vm["config"].as<string>().c_str());
  472. if (!ifs) {
  473. string msg("Could not open file '");
  474. msg += vm["config"].as<string>() + "'.";
  475. throw boost::program_options::error(msg);
  476. }
  477. // Read the whole file into a string
  478. stringstream ss;
  479. ss << ifs.rdbuf();
  480. vector<string> args;
  481. boost::split(args, ss.str(), boost::is_any_of(" \n\r\t"), boost::token_compress_on);
  482. store(command_line_parser(args).options(all).run(), vm);
  483. }
  484. notify(vm);
  485. vector<string> unknown = collect_unrecognized(parsed.options, include_positional);
  486. if (unknown.size()) {
  487. cout << endl << "Error: Unknown parameter(s):";
  488. for (const auto& u : unknown)
  489. cout << ' ' << u;
  490. cout << endl << endl;
  491. return false;
  492. }
  493. } catch (boost::program_options::error& e) {
  494. cout << endl << "Error: " << e.what() << endl << endl;
  495. return false;
  496. }
  497. if (vm.count("help")) {
  498. cout << endl << visible << endl;
  499. return false;
  500. }
  501. if (vm.count("version")) {
  502. vector<string> vs;
  503. headers(vs, false);
  504. cout << endl;
  505. for (auto& v : vs)
  506. cout << v << endl;
  507. cout << endl;
  508. return false;
  509. }
  510. if (vm.count("help-module")) {
  511. const string& s = vm["help-module"].as<string>();
  512. if (s == "con")
  513. cout << "\n\nConnections specifications :\n\n"
  514. << " Whether you need to connect to a stratum pool or to make use of\n"
  515. << " getWork polling mode (generally used to solo mine) you need to "
  516. "specify\n"
  517. << " the connection making use of -P command line argument filling up the\n"
  518. << " URL. The URL is in the form:\n\n "
  519. << " scheme://[user[.workername][:password]@]hostname:port[/...].\n\n"
  520. << " where 'scheme' can be any of :\n\n"
  521. << " getwork for http getWork mode\n"
  522. << " stratum for tcp stratum mode\n"
  523. << " stratums for tcp encrypted stratum mode\n"
  524. << " Example 1: -P getwork://127.0.0.1:8545\n"
  525. << " Example 2: "
  526. "-P "
  527. "stratums://0x012345678901234567890234567890123.miner1@ethermine.org:5555\n"
  528. << " Example 3: "
  529. "-P stratum://0x012345678901234567890234567890123.miner1@nanopool.org:9999/"
  530. "john.doe%40gmail.com\n"
  531. << " Example 4: "
  532. "-P stratum://0x012345678901234567890234567890123@nanopool.org:9999/miner1/"
  533. "john.doe%40gmail.com\n\n"
  534. << " Please note: if your user or worker or password do contain characters\n"
  535. << " which may impair the correct parsing (namely any of . : @ # ?) you "
  536. "have\n"
  537. << " to enclose those values in backticks( ` ASCII 096) or Url Encode them\n"
  538. << " Also note that backtick has a special meaning in *nix environments "
  539. "thus\n"
  540. << " you need to further escape those backticks with backslash.\n\n"
  541. << " Example : -P stratums://\\`account.121\\`.miner1:x@ethermine.org:5555\n"
  542. << " Example : -P stratums://account%2e121.miner1:x@ethermine.org:5555\n"
  543. << " (In Windows backslashes are not needed)\n\n"
  544. << " Common url encoded chars are\n"
  545. << " . (dot) %2e\n"
  546. << " : (column) %3a\n"
  547. << " @ (at sign) %40\n"
  548. << " ? (question) %3f\n"
  549. << " # (number) %23\n"
  550. << " / (slash) %2f\n"
  551. << " + (plus) %2b\n\n"
  552. << " You can add as many -P arguments as you want. Every -P specification\n"
  553. << " after the first one behaves as fail-over connection. When also the\n"
  554. << " the fail-over disconnects miner passes to the next connection\n"
  555. << " available and so on till the list is exhausted. At that moment\n"
  556. << " miner restarts the connection cycle from the first one.\n"
  557. << " An exception to this behavior is ruled by the --failover-timeout\n"
  558. << " command line argument. See 'nsfminer -H misc' for details.\n\n"
  559. << " The special notation '-P exit' stops the failover loop.\n"
  560. << " When miner reaches this kind of connection it simply quits.\n\n"
  561. << " When using stratum mode miner tries to auto-detect the correct\n"
  562. << " flavour provided by the pool. Should be fine in 99% of the cases.\n"
  563. << " Nevertheless you might want to fine tune the stratum flavour by\n"
  564. << " any of of the following valid schemes :\n\n"
  565. << " " << URI::KnownSchemes(ProtocolFamily::STRATUM) << "\n\n"
  566. << " where a scheme is made up of two parts, the stratum variant + the tcp\n"
  567. << " transport protocol\n\n"
  568. << " Stratum variants :\n\n"
  569. << " stratum Stratum\n"
  570. << " stratum1 Eth Proxy compatible\n"
  571. << " stratum2 EthereumStratum 1.0.0 (nicehash)\n"
  572. << " stratum3 EthereumStratum 2.0.0\n\n"
  573. << " Transport variants :\n\n"
  574. << " tcp Unencrypted tcp connection\n"
  575. << " ssl Encrypted tcp connection\n\n";
  576. else if (s == "test") // Simulation
  577. cout << endl << test << endl;
  578. #if ETH_ETHASHCL
  579. else if (s == "cl") // opencl
  580. cout << endl << cl << endl;
  581. #endif
  582. #if ETH_ETHASHCUDA
  583. else if (s == "cu") // cuda
  584. cout << endl << cu << endl;
  585. #endif
  586. #if ETH_ETHASHCPU
  587. else if (s == "cp") // cpu
  588. cout << endl << cp << endl;
  589. #endif
  590. #if API_CORE
  591. else if (s == "api") // programming interface
  592. cout << endl << api << endl;
  593. #endif
  594. else if (s == "misc") // miscellaneous
  595. cout << endl << misc << endl;
  596. else if (s == "conf") // configuration
  597. cout << "\nConfiguration file details:\n\n"
  598. << "Place command line options in a file, for example:\n\n"
  599. << " --api-port 40000\n"
  600. << " --report-hashrate\n"
  601. << " --HWMON 1\n"
  602. << " -P\n"
  603. << " stratums://0x2ceCE0...b3caa0F6e86.rig0@eth-us-east.flexpool.io:5555\n"
  604. << " stratums://0x2ceCE0...b3caa0F6e86.rig0@eth-us-west.flexpool.io:5555\n"
  605. << " -v 7 --display-interval 15\n\n";
  606. #ifdef _WIN32
  607. else if (s == "env")
  608. cout << "\nEnvironment variables :\n\n"
  609. << " If you need or do feel more comfortable you can set the following\n"
  610. << " environment variables. Please respect letter casing.\n\n"
  611. << " SSL_CERT_FILE Set to the full path to of your CA certificates\n"
  612. << " file if it is not in standard path :\n"
  613. << " /etc/ssl/certs/ca-certificates.crt.\n\n";
  614. #endif
  615. else if (s == "reboot")
  616. cout << "\nMiner reboots:\n\n"
  617. << " The user may create a reboot script that will be invoked\n"
  618. << " if ever the miner deems it needs to restart. That can happen\n"
  619. << " if requested via the API, or if the miner detects a hung\n"
  620. << " GPU. The script is invoked with 1 parameter, 'api_miner_reboot'\n"
  621. << " for API reboots, and 'hung_miner_reboot' for hung GPUs\n\n"
  622. << " The script needs a specific file name and must be first in\n"
  623. << " the search path.\n\n"
  624. << " For Linux: reboot.sh\n\n"
  625. << " For Windows: reboot.bat\n\n";
  626. return false;
  627. }
  628. g_logOptions = vm["verbosity"].as<unsigned>();
  629. g_logNoColor = vm.count("nocolor");
  630. g_logSyslog = vm.count("syslog");
  631. g_exitOnError = vm.count("exit");
  632. g_seqDAG = vm.count("seq");
  633. m_PoolSettings.getWorkPollInterval = vm["getwork-recheck"].as<unsigned>();
  634. m_PoolSettings.connectionMaxRetries = vm["retry-max"].as<unsigned>();
  635. m_PoolSettings.delayBeforeRetry = vm["retry-delay"].as<unsigned>();
  636. m_PoolSettings.noWorkTimeout = vm["work-timeout"].as<unsigned>();
  637. m_PoolSettings.noResponseTimeout = vm["response-timeout"].as<unsigned>();
  638. m_PoolSettings.reportHashrate = vm.count("report-hashrate");
  639. m_PoolSettings.poolFailoverTimeout = vm["failover-timeout"].as<unsigned>();
  640. if (vm.count("simulate")) {
  641. m_bench = true;
  642. m_PoolSettings.benchmarkBlock = vm["simulate"].as<unsigned>();
  643. }
  644. if (vm.count("benchmark")) {
  645. m_bench = true;
  646. m_PoolSettings.benchmarkBlock = vm["benchmark"].as<unsigned>();
  647. }
  648. m_cliDisplayInterval = vm["display-interval"].as<unsigned>();
  649. should_list = m_shouldListDevices = vm.count("list-devices");
  650. if (vm.count("devices"))
  651. for (auto& d : vm["devices"].as<vector<unsigned>>())
  652. m_devices.push_back(d);
  653. m_FarmSettings.hwMon = vm["HWMON"].as<unsigned>();
  654. m_FarmSettings.nonce = vm["nonce"].as<string>();
  655. #if ETH_ETHASHCUDA
  656. m_FarmSettings.cuBlockSize = vm["cu-block"].as<unsigned>();
  657. m_FarmSettings.cuStreams = vm["cu-streams"].as<unsigned>();
  658. #endif
  659. #if ETH_ETHASHCL
  660. m_FarmSettings.clGroupSize = vm["cl-work"].as<unsigned>();
  661. m_FarmSettings.clSplit = vm.count("cl-split");
  662. #endif
  663. m_FarmSettings.tempStop = vm["tstop"].as<unsigned>();
  664. m_FarmSettings.tempStart = vm["tstart"].as<unsigned>();
  665. cl_miner = vm.count("opencl");
  666. cuda_miner = vm.count("cuda");
  667. cpu_miner = vm.count("cpu");
  668. if (vm.count("pool"))
  669. for (auto& p : vm["pool"].as<vector<string>>())
  670. pools.push_back(p);
  671. #if API_CORE
  672. m_api_bind = vm["api-bind"].as<string>();
  673. m_api_port = vm["api-port"].as<int>();
  674. m_api_password = vm["api-password"].as<string>();
  675. if (m_api_bind != "") {
  676. try {
  677. ParseBind(m_api_bind, m_api_address, m_api_port, true);
  678. } catch (const exception&) {
  679. cout << "Error: --api-bind address invalid\n\n";
  680. return false;
  681. }
  682. }
  683. #endif
  684. if (cl_miner)
  685. m_minerType = MinerType::CL;
  686. else if (cuda_miner)
  687. m_minerType = MinerType::CUDA;
  688. else if (cpu_miner)
  689. m_minerType = MinerType::CPU;
  690. else if (cl_miner && cuda_miner)
  691. m_minerType = MinerType::Mixed;
  692. else
  693. m_minerType = MinerType::Mixed;
  694. // Operation mode Simulation do not require pool definitions
  695. // Operation mode Stratum or GetWork do need at least one
  696. if (m_bench) {
  697. m_mode = OperationMode::Simulation;
  698. pools.clear();
  699. m_PoolSettings.connections.push_back(shared_ptr<URI>(new URI("simulation://localhost:0", true)));
  700. } else
  701. m_mode = OperationMode::Mining;
  702. if (!m_shouldListDevices && (m_mode != OperationMode::Simulation)) {
  703. if (!pools.size())
  704. throw invalid_argument("At least one pool definition required. See -P argument.");
  705. for (size_t i = 0; i < pools.size(); i++) {
  706. string url = pools.at(i);
  707. if (url == "exit") {
  708. if (i == 0)
  709. throw invalid_argument("'exit' failover directive can't be the first in -P arguments list.");
  710. else
  711. url = "stratum+tcp://-:x@exit:0";
  712. }
  713. try {
  714. shared_ptr<URI> uri = shared_ptr<URI>(new URI(url));
  715. m_PoolSettings.connections.push_back(uri);
  716. } catch (const exception& _ex) {
  717. string what = _ex.what();
  718. throw runtime_error("Bad pool URI : " + what);
  719. }
  720. }
  721. }
  722. if (m_FarmSettings.tempStop) {
  723. // If temp threshold set HWMON at least to 1
  724. m_FarmSettings.hwMon = max((unsigned int)m_FarmSettings.hwMon, 1U);
  725. if (m_FarmSettings.tempStop <= m_FarmSettings.tempStart) {
  726. string what = "-tstop must be greater than -tstart";
  727. throw invalid_argument(what);
  728. }
  729. }
  730. // Output warnings if any
  731. while (warnings.size()) {
  732. cout << warnings.front() << endl;
  733. warnings.pop();
  734. }
  735. return true;
  736. }
  737. void execute() {
  738. #if ETH_ETHASHCL
  739. if (m_minerType == MinerType::CL || m_minerType == MinerType::Mixed)
  740. CLMiner::enumDevices(m_DevicesCollection);
  741. #endif
  742. #if ETH_ETHASHCUDA
  743. if (m_minerType == MinerType::CUDA || m_minerType == MinerType::Mixed)
  744. CUDAMiner::enumDevices(m_DevicesCollection);
  745. #endif
  746. #if ETH_ETHASHCPU
  747. if (m_minerType == MinerType::CPU)
  748. CPUMiner::enumDevices(m_DevicesCollection);
  749. #endif
  750. // Can't proceed without any GPU
  751. if (!m_DevicesCollection.size())
  752. throw runtime_error("No usable mining devices found");
  753. // If requested list detected devices and exit
  754. if (should_list) {
  755. cout << setw(4) << " Id ";
  756. cout << setiosflags(ios::left) << setw(13) << "Pci Id ";
  757. cout << setw(5) << "Type ";
  758. cout << setw(30) << "Name ";
  759. #if ETH_ETHASHCUDA
  760. if (m_minerType == MinerType::CUDA || m_minerType == MinerType::Mixed) {
  761. cout << setw(5) << "CUDA ";
  762. cout << setw(4) << "SM ";
  763. }
  764. #endif
  765. #if ETH_ETHASHCL
  766. if (m_minerType == MinerType::CL || m_minerType == MinerType::Mixed)
  767. cout << setw(5) << "CL ";
  768. #endif
  769. cout << resetiosflags(ios::left) << setw(13) << "Total Memory"
  770. << " ";
  771. cout << resetiosflags(ios::left) << endl;
  772. cout << setw(4) << "--- ";
  773. cout << setiosflags(ios::left) << setw(13) << "------------";
  774. cout << setw(5) << "---- ";
  775. cout << setw(30) << "----------------------------- ";
  776. #if ETH_ETHASHCUDA
  777. if (m_minerType == MinerType::CUDA || m_minerType == MinerType::Mixed) {
  778. cout << setw(5) << "---- ";
  779. cout << setw(4) << "--- ";
  780. }
  781. #endif
  782. #if ETH_ETHASHCL
  783. if (m_minerType == MinerType::CL || m_minerType == MinerType::Mixed)
  784. cout << setw(5) << "---- ";
  785. #endif
  786. cout << resetiosflags(ios::left) << setw(13) << "------------"
  787. << " ";
  788. cout << resetiosflags(ios::left) << endl;
  789. minerMap::iterator it = m_DevicesCollection.begin();
  790. while (it != m_DevicesCollection.end()) {
  791. auto i = distance(m_DevicesCollection.begin(), it);
  792. cout << setw(3) << i << " ";
  793. cout << setiosflags(ios::left) << setw(13) << it->first;
  794. cout << setw(5);
  795. switch (it->second.type) {
  796. case DeviceTypeEnum::Cpu:
  797. cout << "Cpu";
  798. break;
  799. case DeviceTypeEnum::Gpu:
  800. cout << "Gpu";
  801. break;
  802. case DeviceTypeEnum::Accelerator:
  803. cout << "Acc";
  804. break;
  805. default:
  806. break;
  807. }
  808. cout << setw(30) << (it->second.boardName).substr(0, 28);
  809. #if ETH_ETHASHCUDA
  810. if (m_minerType == MinerType::CUDA || m_minerType == MinerType::Mixed) {
  811. cout << setw(5) << (it->second.cuDetected ? "Yes" : "");
  812. cout << setw(4) << it->second.cuCompute;
  813. }
  814. #endif
  815. #if ETH_ETHASHCL
  816. if (m_minerType == MinerType::CL || m_minerType == MinerType::Mixed)
  817. cout << setw(5) << (it->second.clDetected ? "Yes" : "");
  818. #endif
  819. cout << resetiosflags(ios::left) << setw(13) << getFormattedMemory((double)it->second.totalMemory)
  820. << " ";
  821. cout << resetiosflags(ios::left) << endl;
  822. it++;
  823. }
  824. return;
  825. }
  826. // Subscribe devices with appropriate Miner Type
  827. // Use CUDA first when available then, as second, OpenCL
  828. #if ETH_ETHASHCUDA
  829. if (m_minerType == MinerType::CUDA || m_minerType == MinerType::Mixed)
  830. for (auto it = m_DevicesCollection.begin(); it != m_DevicesCollection.end(); it++) {
  831. if (!it->second.cuDetected || it->second.subscriptionType != DeviceSubscriptionTypeEnum::None)
  832. continue;
  833. unsigned d = (unsigned)distance(m_DevicesCollection.begin(), it);
  834. if (m_devices.empty() || find(m_devices.begin(), m_devices.end(), d) != m_devices.end())
  835. it->second.subscriptionType = DeviceSubscriptionTypeEnum::Cuda;
  836. }
  837. #endif
  838. #if ETH_ETHASHCL
  839. if (m_minerType == MinerType::CL || m_minerType == MinerType::Mixed)
  840. for (auto it = m_DevicesCollection.begin(); it != m_DevicesCollection.end(); it++) {
  841. if (!it->second.clDetected || it->second.subscriptionType != DeviceSubscriptionTypeEnum::None)
  842. continue;
  843. unsigned d = (unsigned)distance(m_DevicesCollection.begin(), it);
  844. if (m_devices.empty() || find(m_devices.begin(), m_devices.end(), d) != m_devices.end())
  845. it->second.subscriptionType = DeviceSubscriptionTypeEnum::OpenCL;
  846. }
  847. #endif
  848. #if ETH_ETHASHCPU
  849. if (m_minerType == MinerType::CPU)
  850. for (auto it = m_DevicesCollection.begin(); it != m_DevicesCollection.end(); it++)
  851. it->second.subscriptionType = DeviceSubscriptionTypeEnum::Cpu;
  852. #endif
  853. // Count of subscribed devices
  854. int subscribedDevices = 0;
  855. for (auto it = m_DevicesCollection.begin(); it != m_DevicesCollection.end(); it++)
  856. if (it->second.subscriptionType != DeviceSubscriptionTypeEnum::None)
  857. subscribedDevices++;
  858. // If no OpenCL and/or CUDA devices subscribed then throw error
  859. if (!subscribedDevices)
  860. throw runtime_error("No mining device selected. Aborting ...");
  861. // Enable
  862. g_running = true;
  863. // Signal traps
  864. #if defined(__linux__)
  865. signal(SIGSEGV, MinerCLI::signalHandler);
  866. #endif
  867. signal(SIGINT, MinerCLI::signalHandler);
  868. signal(SIGTERM, MinerCLI::signalHandler);
  869. // Initialize Farm
  870. new Farm(m_DevicesCollection, m_FarmSettings);
  871. // Run Miner
  872. doMiner();
  873. }
  874. private:
  875. void doMiner() {
  876. new PoolManager(m_PoolSettings);
  877. if (m_mode != OperationMode::Simulation)
  878. for (auto conn : m_PoolSettings.connections)
  879. cnote << "Configured pool " << conn->Host() + ":" + to_string(conn->Port());
  880. #if API_CORE
  881. ApiServer api(m_api_address, m_api_port, m_api_password);
  882. if (m_api_port)
  883. api.start();
  884. #endif
  885. // Start PoolManager
  886. PoolManager::p().start();
  887. // Initialize display timer as sleeper with proper interval
  888. m_cliDisplayTimer.expires_from_now(boost::posix_time::seconds(m_cliDisplayInterval));
  889. m_cliDisplayTimer.async_wait(m_io_strand.wrap(
  890. boost::bind(&MinerCLI::cliDisplayInterval_elapsed, this, boost::asio::placeholders::error)));
  891. // Stay in non-busy wait till signals arrive
  892. unique_lock<mutex> clilock(m_climtx);
  893. while (g_running)
  894. g_shouldstop.wait(clilock);
  895. #if API_CORE
  896. // Stop Api server
  897. if (api.isRunning())
  898. api.stop();
  899. #endif
  900. if (PoolManager::p().isRunning())
  901. PoolManager::p().stop();
  902. cnote << "Terminated!";
  903. return;
  904. }
  905. // Global boost's io_service
  906. thread m_io_thread; // The IO service thread
  907. boost::asio::deadline_timer m_cliDisplayTimer; // The timer which ticks display lines
  908. boost::asio::io_service::strand m_io_strand; // A strand to serialize posts in
  909. // multithreaded environment
  910. // Physical Mining Devices descriptor
  911. minerMap m_DevicesCollection;
  912. // Mining options
  913. MinerType m_minerType = MinerType::Mixed;
  914. OperationMode m_mode = OperationMode::None;
  915. bool m_shouldListDevices = false;
  916. FarmSettings m_FarmSettings; // Operating settings for Farm
  917. PoolSettings m_PoolSettings; // Operating settings for PoolManager
  918. // -- CLI Interface related params
  919. unsigned m_cliDisplayInterval = 5; // Display stats/info interval in seconds
  920. // -- CLI Flow control
  921. mutex m_climtx;
  922. vector<unsigned> m_devices;
  923. bool m_bench = false;
  924. #if API_CORE
  925. // -- API and Http interfaces related params
  926. string m_api_bind; // API interface binding address in form <address>:<port>
  927. string m_api_address = "0.0.0.0"; // API interface binding address (Default any)
  928. int m_api_port = 0; // API interface binding port
  929. string m_api_password; // API interface write protection password
  930. #endif
  931. };
  932. int main(int argc, char** argv) {
  933. // Return values
  934. // 0 - Normal exit
  935. // 1 - Invalid/Insufficient command line arguments
  936. // 2 - Runtime error
  937. // 3 - Other exceptions
  938. // 4 - Unknown exception
  939. dev::setThreadName("miner");
  940. #if defined(_WIN32)
  941. // Need to change the code page from the default OEM code page (437) so that
  942. // UTF-8 characters are displayed correctly in the console
  943. SetConsoleOutputCP(CP_UTF8);
  944. HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  945. if (hOut != INVALID_HANDLE_VALUE) {
  946. DWORD dwMode;
  947. if (GetConsoleMode(hOut, &dwMode))
  948. SetConsoleMode(hOut, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
  949. }
  950. // prevent system sleep
  951. SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
  952. #endif
  953. if (argc < 2) {
  954. cout << "No arguments specified.";
  955. cout << "Try 'nsfminer --help' to get a list of arguments.";
  956. return 1;
  957. }
  958. try {
  959. MinerCLI cli;
  960. try {
  961. // Set env vars controlling GPU driver behavior.
  962. setenv("GPU_MAX_HEAP_SIZE", "100");
  963. setenv("GPU_MAX_ALLOC_PERCENT", "100");
  964. setenv("GPU_SINGLE_ALLOC_PERCENT", "100");
  965. setenv("GPU_USE_SYNC_OBJECTS", "1");
  966. // Argument validation either throws exception
  967. // or returns false which means do not continue
  968. if (!cli.validateArgs(argc, argv))
  969. return 0;
  970. if (g_logSyslog)
  971. g_logNoColor = true;
  972. if (!should_list) {
  973. vector<string> vs;
  974. headers(vs, !g_logNoColor);
  975. for (auto& v : vs)
  976. cnote << v;
  977. }
  978. cli.execute();
  979. cout << endl << endl;
  980. return 0;
  981. } catch (boost::program_options::error& e) {
  982. cout << "\nError: " << e.what() << "\n\n";
  983. return 1;
  984. } catch (runtime_error& e) {
  985. cout << "\nError: " << e.what() << "\n\n";
  986. return 2;
  987. } catch (exception& e) {
  988. cout << "\nError: " << e.what() << "\n\n";
  989. return 3;
  990. } catch (...) {
  991. cout << "\n\nError: Unknown failure occurred.\n\n";
  992. return 4;
  993. }
  994. } catch (const exception& e) {
  995. cout << "Could not initialize CLI interface\nError: " << e.what() << "\n\n";
  996. return 4;
  997. }
  998. }