cpu-miner.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. /*
  2. * Copyright 2010 Jeff Garzik
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the Free
  6. * Software Foundation; either version 2 of the License, or (at your option)
  7. * any later version. See COPYING for more details.
  8. */
  9. #include "cpuminer-config.h"
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <stdbool.h>
  14. #include <stdint.h>
  15. #include <unistd.h>
  16. #include <sys/time.h>
  17. #include <time.h>
  18. #ifndef WIN32
  19. #include <sys/resource.h>
  20. #endif
  21. #include <getopt.h>
  22. #include <jansson.h>
  23. #include <curl/curl.h>
  24. #include "compat.h"
  25. #include "miner.h"
  26. #define PROGRAM_NAME "minerd"
  27. #define DEF_RPC_URL "http://127.0.0.1:8332/"
  28. #define DEF_RPC_USERPASS "rpcuser:rpcpass"
  29. enum workio_commands {
  30. WC_GET_WORK,
  31. WC_SUBMIT_WORK,
  32. };
  33. struct workio_cmd {
  34. enum workio_commands cmd;
  35. struct thr_info *thr;
  36. union {
  37. struct work *work;
  38. } u;
  39. };
  40. enum sha256_algos {
  41. ALGO_C, /* plain C */
  42. ALGO_4WAY, /* parallel SSE2 */
  43. ALGO_VIA, /* VIA padlock */
  44. ALGO_CRYPTOPP, /* Crypto++ (C) */
  45. ALGO_CRYPTOPP_ASM32, /* Crypto++ 32-bit assembly */
  46. ALGO_SSE2_64, /* SSE2 for x86_64 */
  47. };
  48. static const char *algo_names[] = {
  49. [ALGO_C] = "c",
  50. #ifdef WANT_SSE2_4WAY
  51. [ALGO_4WAY] = "4way",
  52. #endif
  53. #ifdef WANT_VIA_PADLOCK
  54. [ALGO_VIA] = "via",
  55. #endif
  56. [ALGO_CRYPTOPP] = "cryptopp",
  57. #ifdef WANT_CRYPTOPP_ASM32
  58. [ALGO_CRYPTOPP_ASM32] = "cryptopp_asm32",
  59. #endif
  60. #ifdef WANT_X8664_SSE2
  61. [ALGO_SSE2_64] = "sse2_64",
  62. #endif
  63. };
  64. bool opt_debug = false;
  65. bool opt_protocol = false;
  66. bool want_longpoll = true;
  67. bool have_longpoll = false;
  68. static bool opt_quiet = false;
  69. static int opt_retries = 10;
  70. static int opt_fail_pause = 30;
  71. int opt_scantime = 5;
  72. static json_t *opt_config;
  73. static const bool opt_time = true;
  74. static enum sha256_algos opt_algo = ALGO_C;
  75. static int opt_n_threads = 1;
  76. static char *rpc_url;
  77. static char *userpass;
  78. struct thr_info *thr_info;
  79. static int work_thr_id;
  80. int longpoll_thr_id;
  81. struct work_restart *work_restart = NULL;
  82. struct option_help {
  83. const char *name;
  84. const char *helptext;
  85. };
  86. static struct option_help options_help[] = {
  87. { "help",
  88. "(-h) Display this help text" },
  89. { "config FILE",
  90. "(-c FILE) JSON-format configuration file (default: none)\n"
  91. "See example-cfg.json for an example configuration." },
  92. { "algo XXX",
  93. "(-a XXX) Specify sha256 implementation:\n"
  94. "\tc\t\tLinux kernel sha256, implemented in C (default)"
  95. #ifdef WANT_SSE2_4WAY
  96. "\n\t4way\t\ttcatm's 4-way SSE2 implementation"
  97. #endif
  98. #ifdef WANT_VIA_PADLOCK
  99. "\n\tvia\t\tVIA padlock implementation"
  100. #endif
  101. "\n\tcryptopp\tCrypto++ C/C++ implementation"
  102. #ifdef WANT_CRYPTOPP_ASM32
  103. "\n\tcryptopp_asm32\tCrypto++ 32-bit assembler implementation"
  104. #endif
  105. #ifdef WANT_X8664_SSE2
  106. "\n\tsse2_64\t\tSSE2 implementation for x86_64 machines"
  107. #endif
  108. },
  109. { "quiet",
  110. "(-q) Disable per-thread hashmeter output (default: off)" },
  111. { "debug",
  112. "(-D) Enable debug output (default: off)" },
  113. { "no-longpoll",
  114. "Disable X-Long-Polling support (default: enabled)" },
  115. { "protocol-dump",
  116. "(-P) Verbose dump of protocol-level activities (default: off)" },
  117. { "retries N",
  118. "(-r N) Number of times to retry, if JSON-RPC call fails\n"
  119. "\t(default: 10; use -1 for \"never\")" },
  120. { "retry-pause N",
  121. "(-R N) Number of seconds to pause, between retries\n"
  122. "\t(default: 30)" },
  123. { "scantime N",
  124. "(-s N) Upper bound on time spent scanning current work,\n"
  125. "\tin seconds. (default: 5)" },
  126. { "threads N",
  127. "(-t N) Number of miner threads (default: 1)" },
  128. { "url URL",
  129. "URL for bitcoin JSON-RPC server "
  130. "(default: " DEF_RPC_URL ")" },
  131. { "userpass USERNAME:PASSWORD",
  132. "Username:Password pair for bitcoin JSON-RPC server "
  133. "(default: " DEF_RPC_USERPASS ")" },
  134. };
  135. static struct option options[] = {
  136. { "help", 0, NULL, 'h' },
  137. { "algo", 1, NULL, 'a' },
  138. { "config", 1, NULL, 'c' },
  139. { "quiet", 0, NULL, 'q' },
  140. { "debug", 0, NULL, 'D' },
  141. { "protocol-dump", 0, NULL, 'P' },
  142. { "threads", 1, NULL, 't' },
  143. { "retries", 1, NULL, 'r' },
  144. { "retry-pause", 1, NULL, 'R' },
  145. { "scantime", 1, NULL, 's' },
  146. { "url", 1, NULL, 1001 },
  147. { "userpass", 1, NULL, 1002 },
  148. { "no-longpoll", 0, NULL, 1003 },
  149. { }
  150. };
  151. struct work {
  152. unsigned char data[128];
  153. unsigned char hash1[64];
  154. unsigned char midstate[32];
  155. unsigned char target[32];
  156. unsigned char hash[32];
  157. };
  158. static bool jobj_binary(const json_t *obj, const char *key,
  159. void *buf, size_t buflen)
  160. {
  161. const char *hexstr;
  162. json_t *tmp;
  163. tmp = json_object_get(obj, key);
  164. if (!tmp) {
  165. fprintf(stderr, "JSON key '%s' not found\n", key);
  166. return false;
  167. }
  168. hexstr = json_string_value(tmp);
  169. if (!hexstr) {
  170. fprintf(stderr, "JSON key '%s' is not a string\n", key);
  171. return false;
  172. }
  173. if (!hex2bin(buf, hexstr, buflen))
  174. return false;
  175. return true;
  176. }
  177. static bool work_decode(const json_t *val, struct work *work)
  178. {
  179. if (!jobj_binary(val, "midstate",
  180. work->midstate, sizeof(work->midstate))) {
  181. fprintf(stderr, "JSON inval midstate\n");
  182. goto err_out;
  183. }
  184. if (!jobj_binary(val, "data", work->data, sizeof(work->data))) {
  185. fprintf(stderr, "JSON inval data\n");
  186. goto err_out;
  187. }
  188. if (!jobj_binary(val, "hash1", work->hash1, sizeof(work->hash1))) {
  189. fprintf(stderr, "JSON inval hash1\n");
  190. goto err_out;
  191. }
  192. if (!jobj_binary(val, "target", work->target, sizeof(work->target))) {
  193. fprintf(stderr, "JSON inval target\n");
  194. goto err_out;
  195. }
  196. memset(work->hash, 0, sizeof(work->hash));
  197. return true;
  198. err_out:
  199. return false;
  200. }
  201. static bool submit_upstream_work(CURL *curl, const struct work *work)
  202. {
  203. char *hexstr = NULL;
  204. json_t *val, *res;
  205. char s[345], timestr[64];
  206. time_t now;
  207. struct tm *tm;
  208. bool rc = false;
  209. now = time(NULL);
  210. /* build hex string */
  211. hexstr = bin2hex(work->data, sizeof(work->data));
  212. if (!hexstr) {
  213. fprintf(stderr, "submit_upstream_work OOM\n");
  214. goto out;
  215. }
  216. /* build JSON-RPC request */
  217. sprintf(s,
  218. "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n",
  219. hexstr);
  220. if (opt_debug)
  221. fprintf(stderr, "DBG: sending RPC call:\n%s", s);
  222. /* issue JSON-RPC request */
  223. val = json_rpc_call(curl, rpc_url, userpass, s, false, false);
  224. if (!val) {
  225. fprintf(stderr, "submit_upstream_work json_rpc_call failed\n");
  226. goto out;
  227. }
  228. res = json_object_get(val, "result");
  229. tm = localtime(&now);
  230. strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
  231. printf("[%s] PROOF OF WORK RESULT: %s\n",
  232. timestr, json_is_true(res) ? "true (yay!!!)" : "false (booooo)");
  233. json_decref(val);
  234. rc = true;
  235. out:
  236. free(hexstr);
  237. return rc;
  238. }
  239. static const char *rpc_req =
  240. "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
  241. static bool get_upstream_work(CURL *curl, struct work *work)
  242. {
  243. json_t *val;
  244. bool rc;
  245. val = json_rpc_call(curl, rpc_url, userpass, rpc_req,
  246. want_longpoll, false);
  247. if (!val)
  248. return false;
  249. rc = work_decode(json_object_get(val, "result"), work);
  250. json_decref(val);
  251. return rc;
  252. }
  253. static void workio_cmd_free(struct workio_cmd *wc)
  254. {
  255. if (!wc)
  256. return;
  257. switch (wc->cmd) {
  258. case WC_SUBMIT_WORK:
  259. free(wc->u.work);
  260. break;
  261. default: /* do nothing */
  262. break;
  263. }
  264. memset(wc, 0, sizeof(*wc)); /* poison */
  265. free(wc);
  266. }
  267. static bool workio_get_work(struct workio_cmd *wc, CURL *curl)
  268. {
  269. struct work *ret_work;
  270. int failures = 0;
  271. ret_work = calloc(1, sizeof(*ret_work));
  272. if (!ret_work)
  273. return false;
  274. /* obtain new work from bitcoin via JSON-RPC */
  275. while (!get_upstream_work(curl, ret_work)) {
  276. fprintf(stderr, "json_rpc_call failed, ");
  277. if ((opt_retries >= 0) && (++failures > opt_retries)) {
  278. fprintf(stderr, "terminating workio thread\n");
  279. free(ret_work);
  280. return false;
  281. }
  282. /* pause, then restart work-request loop */
  283. fprintf(stderr, "retry after %d seconds\n",
  284. opt_fail_pause);
  285. sleep(opt_fail_pause);
  286. }
  287. /* send work to requesting thread */
  288. if (!tq_push(wc->thr->q, ret_work))
  289. free(ret_work);
  290. return true;
  291. }
  292. static bool workio_submit_work(struct workio_cmd *wc, CURL *curl)
  293. {
  294. int failures = 0;
  295. /* submit solution to bitcoin via JSON-RPC */
  296. while (!submit_upstream_work(curl, wc->u.work)) {
  297. if ((opt_retries >= 0) && (++failures > opt_retries)) {
  298. fprintf(stderr, "...terminating workio thread\n");
  299. return false;
  300. }
  301. /* pause, then restart work-request loop */
  302. fprintf(stderr, "...retry after %d seconds\n",
  303. opt_fail_pause);
  304. sleep(opt_fail_pause);
  305. }
  306. return true;
  307. }
  308. static void *workio_thread(void *userdata)
  309. {
  310. struct thr_info *mythr = userdata;
  311. CURL *curl;
  312. bool ok = true;
  313. curl = curl_easy_init();
  314. if (!curl) {
  315. fprintf(stderr, "CURL initialization failed\n");
  316. return NULL;
  317. }
  318. while (ok) {
  319. struct workio_cmd *wc;
  320. /* wait for workio_cmd sent to us, on our queue */
  321. wc = tq_pop(mythr->q, NULL);
  322. if (!wc) {
  323. ok = false;
  324. break;
  325. }
  326. /* process workio_cmd */
  327. switch (wc->cmd) {
  328. case WC_GET_WORK:
  329. ok = workio_get_work(wc, curl);
  330. break;
  331. case WC_SUBMIT_WORK:
  332. ok = workio_submit_work(wc, curl);
  333. break;
  334. default: /* should never happen */
  335. ok = false;
  336. break;
  337. }
  338. workio_cmd_free(wc);
  339. }
  340. tq_freeze(mythr->q);
  341. curl_easy_cleanup(curl);
  342. return NULL;
  343. }
  344. static void hashmeter(int thr_id, const struct timeval *diff,
  345. unsigned long hashes_done)
  346. {
  347. double khashes, secs;
  348. khashes = hashes_done / 1000.0;
  349. secs = (double)diff->tv_sec + ((double)diff->tv_usec / 1000000.0);
  350. if (!opt_quiet)
  351. printf("HashMeter(%d): %lu hashes, %.2f khash/sec\n",
  352. thr_id, hashes_done,
  353. khashes / secs);
  354. }
  355. static bool get_work(struct thr_info *thr, struct work *work)
  356. {
  357. struct workio_cmd *wc;
  358. struct work *work_heap;
  359. /* fill out work request message */
  360. wc = calloc(1, sizeof(*wc));
  361. if (!wc)
  362. return false;
  363. wc->cmd = WC_GET_WORK;
  364. wc->thr = thr;
  365. /* send work request to workio thread */
  366. if (!tq_push(thr_info[work_thr_id].q, wc)) {
  367. workio_cmd_free(wc);
  368. return false;
  369. }
  370. /* wait for response, a unit of work */
  371. work_heap = tq_pop(thr->q, NULL);
  372. if (!work_heap)
  373. return false;
  374. /* copy returned work into storage provided by caller */
  375. memcpy(work, work_heap, sizeof(*work));
  376. free(work_heap);
  377. return true;
  378. }
  379. static bool submit_work(struct thr_info *thr, const struct work *work_in)
  380. {
  381. struct workio_cmd *wc;
  382. /* fill out work request message */
  383. wc = calloc(1, sizeof(*wc));
  384. if (!wc)
  385. return false;
  386. wc->u.work = malloc(sizeof(*work_in));
  387. if (!wc->u.work)
  388. goto err_out;
  389. wc->cmd = WC_SUBMIT_WORK;
  390. wc->thr = thr;
  391. memcpy(wc->u.work, work_in, sizeof(*work_in));
  392. /* send solution to workio thread */
  393. if (!tq_push(thr_info[work_thr_id].q, wc))
  394. goto err_out;
  395. return true;
  396. err_out:
  397. workio_cmd_free(wc);
  398. return false;
  399. }
  400. static void *miner_thread(void *userdata)
  401. {
  402. struct thr_info *mythr = userdata;
  403. int thr_id = mythr->id;
  404. uint32_t max_nonce = 0xffffff;
  405. while (1) {
  406. struct work work __attribute__((aligned(128)));
  407. unsigned long hashes_done;
  408. struct timeval tv_start, tv_end, diff;
  409. uint64_t max64;
  410. bool rc;
  411. /* obtain new work from internal workio thread */
  412. if (!get_work(mythr, &work)) {
  413. fprintf(stderr, "work retrieval failed, exiting "
  414. "mining thread %d\n", mythr->id);
  415. goto out;
  416. }
  417. hashes_done = 0;
  418. gettimeofday(&tv_start, NULL);
  419. /* scan nonces for a proof-of-work hash */
  420. switch (opt_algo) {
  421. case ALGO_C:
  422. rc = scanhash_c(thr_id, work.midstate, work.data + 64,
  423. work.hash1, work.hash, work.target,
  424. max_nonce, &hashes_done);
  425. break;
  426. #ifdef WANT_X8664_SSE2
  427. case ALGO_SSE2_64: {
  428. unsigned int rc5 =
  429. scanhash_sse2_64(thr_id, work.midstate, work.data + 64,
  430. work.hash1, work.hash,
  431. work.target,
  432. max_nonce, &hashes_done);
  433. rc = (rc5 == -1) ? false : true;
  434. }
  435. break;
  436. #endif
  437. #ifdef WANT_SSE2_4WAY
  438. case ALGO_4WAY: {
  439. unsigned int rc4 =
  440. ScanHash_4WaySSE2(thr_id, work.midstate, work.data + 64,
  441. work.hash1, work.hash,
  442. work.target,
  443. max_nonce, &hashes_done);
  444. rc = (rc4 == -1) ? false : true;
  445. }
  446. break;
  447. #endif
  448. #ifdef WANT_VIA_PADLOCK
  449. case ALGO_VIA:
  450. rc = scanhash_via(thr_id, work.data, work.target,
  451. max_nonce, &hashes_done);
  452. break;
  453. #endif
  454. case ALGO_CRYPTOPP:
  455. rc = scanhash_cryptopp(thr_id, work.midstate, work.data + 64,
  456. work.hash1, work.hash, work.target,
  457. max_nonce, &hashes_done);
  458. break;
  459. #ifdef WANT_CRYPTOPP_ASM32
  460. case ALGO_CRYPTOPP_ASM32:
  461. rc = scanhash_asm32(thr_id, work.midstate, work.data + 64,
  462. work.hash1, work.hash, work.target,
  463. max_nonce, &hashes_done);
  464. break;
  465. #endif
  466. default:
  467. /* should never happen */
  468. goto out;
  469. }
  470. /* record scanhash elapsed time */
  471. gettimeofday(&tv_end, NULL);
  472. timeval_subtract(&diff, &tv_end, &tv_start);
  473. hashmeter(thr_id, &diff, hashes_done);
  474. /* adjust max_nonce to meet target scan time */
  475. max64 = ((uint64_t)hashes_done * opt_scantime) / diff.tv_sec;
  476. if (max64 > 0xfffffffaULL)
  477. max64 = 0xfffffffaULL;
  478. max_nonce = max64;
  479. /* if nonce found, submit work */
  480. if (rc && !submit_work(mythr, &work))
  481. break;
  482. }
  483. out:
  484. tq_freeze(mythr->q);
  485. return NULL;
  486. }
  487. static void restart_threads(void)
  488. {
  489. int i;
  490. for (i = 0; i < opt_n_threads; i++)
  491. work_restart[i].restart = 1;
  492. }
  493. static void *longpoll_thread(void *userdata)
  494. {
  495. struct thr_info *mythr = userdata;
  496. CURL *curl = NULL;
  497. char *copy_start, *hdr_path, *lp_url = NULL;
  498. bool need_slash = false;
  499. int failures = 0;
  500. hdr_path = tq_pop(mythr->q, NULL);
  501. if (!hdr_path)
  502. goto out;
  503. copy_start = (*hdr_path == '/') ? (hdr_path + 1) : hdr_path;
  504. if (rpc_url[strlen(rpc_url) - 1] != '/')
  505. need_slash = true;
  506. lp_url = malloc(strlen(rpc_url) + strlen(copy_start) + 2);
  507. if (!lp_url)
  508. goto out;
  509. sprintf(lp_url, "%s%s%s", rpc_url, need_slash ? "/" : "", copy_start);
  510. fprintf(stderr, "Long-polling activated for %s\n", lp_url);
  511. curl = curl_easy_init();
  512. if (!curl) {
  513. fprintf(stderr, "CURL initialization failed\n");
  514. goto out;
  515. }
  516. while (1) {
  517. json_t *val;
  518. val = json_rpc_call(curl, lp_url, userpass, rpc_req,
  519. false, true);
  520. if (val) {
  521. failures = 0;
  522. json_decref(val);
  523. fprintf(stderr, "LONGPOLL detected new block\n");
  524. restart_threads();
  525. } else {
  526. if (failures++ < 10) {
  527. sleep(30);
  528. fprintf(stderr,
  529. "longpoll failed, sleeping for 30s\n");
  530. } else {
  531. fprintf(stderr,
  532. "longpoll failed, ending thread\n");
  533. goto out;
  534. }
  535. }
  536. }
  537. out:
  538. free(hdr_path);
  539. free(lp_url);
  540. tq_freeze(mythr->q);
  541. if (curl)
  542. curl_easy_cleanup(curl);
  543. return NULL;
  544. }
  545. static void show_usage(void)
  546. {
  547. int i;
  548. printf("minerd version %s\n\n", VERSION);
  549. printf("Usage:\tminerd [options]\n\nSupported options:\n");
  550. for (i = 0; i < ARRAY_SIZE(options_help); i++) {
  551. struct option_help *h;
  552. h = &options_help[i];
  553. printf("--%s\n%s\n\n", h->name, h->helptext);
  554. }
  555. exit(1);
  556. }
  557. static void parse_arg (int key, char *arg)
  558. {
  559. int v, i;
  560. switch(key) {
  561. case 'a':
  562. for (i = 0; i < ARRAY_SIZE(algo_names); i++) {
  563. if (algo_names[i] &&
  564. !strcmp(arg, algo_names[i])) {
  565. opt_algo = i;
  566. break;
  567. }
  568. }
  569. if (i == ARRAY_SIZE(algo_names))
  570. show_usage();
  571. break;
  572. case 'c': {
  573. json_error_t err;
  574. if (opt_config)
  575. json_decref(opt_config);
  576. opt_config = json_load_file(arg, &err);
  577. if (!json_is_object(opt_config)) {
  578. fprintf(stderr, "JSON decode of %s failed\n", arg);
  579. show_usage();
  580. }
  581. break;
  582. }
  583. case 'q':
  584. opt_quiet = true;
  585. break;
  586. case 'D':
  587. opt_debug = true;
  588. break;
  589. case 'P':
  590. opt_protocol = true;
  591. break;
  592. case 'r':
  593. v = atoi(arg);
  594. if (v < -1 || v > 9999) /* sanity check */
  595. show_usage();
  596. opt_retries = v;
  597. break;
  598. case 'R':
  599. v = atoi(arg);
  600. if (v < 1 || v > 9999) /* sanity check */
  601. show_usage();
  602. opt_fail_pause = v;
  603. break;
  604. case 's':
  605. v = atoi(arg);
  606. if (v < 1 || v > 9999) /* sanity check */
  607. show_usage();
  608. opt_scantime = v;
  609. break;
  610. case 't':
  611. v = atoi(arg);
  612. if (v < 1 || v > 9999) /* sanity check */
  613. show_usage();
  614. opt_n_threads = v;
  615. break;
  616. case 1001: /* --url */
  617. if (strncmp(arg, "http://", 7) &&
  618. strncmp(arg, "https://", 8))
  619. show_usage();
  620. free(rpc_url);
  621. rpc_url = strdup(arg);
  622. break;
  623. case 1002: /* --userpass */
  624. if (!strchr(arg, ':'))
  625. show_usage();
  626. free(userpass);
  627. userpass = strdup(arg);
  628. break;
  629. case 1003:
  630. want_longpoll = false;
  631. break;
  632. default:
  633. show_usage();
  634. }
  635. }
  636. static void parse_config(void)
  637. {
  638. int i;
  639. json_t *val;
  640. if (!json_is_object(opt_config))
  641. return;
  642. for (i = 0; i < ARRAY_SIZE(options); i++) {
  643. if (!options[i].name)
  644. break;
  645. if (!strcmp(options[i].name, "config"))
  646. continue;
  647. val = json_object_get(opt_config, options[i].name);
  648. if (!val)
  649. continue;
  650. if (options[i].has_arg && json_is_string(val)) {
  651. char *s = strdup(json_string_value(val));
  652. if (!s)
  653. break;
  654. parse_arg(options[i].val, s);
  655. free(s);
  656. } else if (!options[i].has_arg && json_is_true(val))
  657. parse_arg(options[i].val, "");
  658. else
  659. fprintf(stderr, "JSON option %s invalid\n",
  660. options[i].name);
  661. }
  662. }
  663. static void parse_cmdline(int argc, char *argv[])
  664. {
  665. int key;
  666. while (1) {
  667. key = getopt_long(argc, argv, "a:c:qDPr:s:t:h?", options, NULL);
  668. if (key < 0)
  669. break;
  670. parse_arg(key, optarg);
  671. }
  672. parse_config();
  673. }
  674. int main (int argc, char *argv[])
  675. {
  676. struct thr_info *thr;
  677. int i;
  678. rpc_url = strdup(DEF_RPC_URL);
  679. userpass = strdup(DEF_RPC_USERPASS);
  680. /* parse command line */
  681. parse_cmdline(argc, argv);
  682. /* set our priority to the highest (aka "nicest, least intrusive") */
  683. if (setpriority(PRIO_PROCESS, 0, 19))
  684. perror("setpriority");
  685. work_restart = calloc(opt_n_threads, sizeof(*work_restart));
  686. if (!work_restart)
  687. return 1;
  688. thr_info = calloc(opt_n_threads + 2, sizeof(*thr));
  689. if (!thr_info)
  690. return 1;
  691. /* init workio thread info */
  692. work_thr_id = opt_n_threads;
  693. thr = &thr_info[work_thr_id];
  694. thr->id = work_thr_id;
  695. thr->q = tq_new();
  696. if (!thr->q)
  697. return 1;
  698. /* start work I/O thread */
  699. if (pthread_create(&thr->pth, NULL, workio_thread, thr)) {
  700. fprintf(stderr, "workio thread create failed\n");
  701. return 1;
  702. }
  703. /* init longpoll thread info */
  704. if (want_longpoll) {
  705. longpoll_thr_id = opt_n_threads + 1;
  706. thr = &thr_info[longpoll_thr_id];
  707. thr->id = longpoll_thr_id;
  708. thr->q = tq_new();
  709. if (!thr->q)
  710. return 1;
  711. /* start longpoll thread */
  712. if (pthread_create(&thr->pth, NULL, longpoll_thread, thr)) {
  713. fprintf(stderr, "longpoll thread create failed\n");
  714. return 1;
  715. }
  716. } else
  717. longpoll_thr_id = -1;
  718. /* start mining threads */
  719. for (i = 0; i < opt_n_threads; i++) {
  720. thr = &thr_info[i];
  721. thr->id = i;
  722. thr->q = tq_new();
  723. if (!thr->q)
  724. return 1;
  725. if (pthread_create(&thr->pth, NULL, miner_thread, thr)) {
  726. fprintf(stderr, "thread %d create failed\n", i);
  727. return 1;
  728. }
  729. sleep(1); /* don't pound RPC server all at once */
  730. }
  731. fprintf(stderr, "%d miner threads started, "
  732. "using SHA256 '%s' algorithm.\n",
  733. opt_n_threads,
  734. algo_names[opt_algo]);
  735. /* main loop - simply wait for workio thread to exit */
  736. pthread_join(thr_info[work_thr_id].pth, NULL);
  737. fprintf(stderr, "workio thread dead, exiting.\n");
  738. return 0;
  739. }