Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
samr7
GitHub Repository: samr7/vanitygen
Path: blob/master/oclvanityminer.c
239 views
1
/*
2
* Vanitygen, vanity bitcoin address generator
3
* Copyright (C) 2011 <[email protected]>
4
*
5
* Vanitygen is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU Affero General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* any later version.
9
*
10
* Vanitygen is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU Affero General Public License for more details.
14
*
15
* You should have received a copy of the GNU Affero General Public License
16
* along with Vanitygen. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <stdio.h>
20
#include <string.h>
21
#include <math.h>
22
#include <assert.h>
23
24
#include <pthread.h>
25
26
#include <openssl/ec.h>
27
#include <openssl/bn.h>
28
#include <openssl/rand.h>
29
30
#include <curl/curl.h>
31
32
#include "oclengine.h"
33
#include "pattern.h"
34
#include "util.h"
35
#include "avl.h"
36
37
38
const char *version = VANITYGEN_VERSION;
39
const int debug = 0;
40
41
42
/*
43
* Bounty work item, which includes a pattern and a public key
44
* Indexed in an AVL tree by pattern
45
*/
46
47
typedef struct workitem_s {
48
avl_item_t avlent;
49
const char *pattern;
50
const char *comment;
51
EC_POINT *pubkey;
52
int addrtype;
53
double difficulty;
54
double reward;
55
double value;
56
} workitem_t;
57
58
59
static int
60
workitem_cmp(workitem_t *a, workitem_t *b)
61
{
62
int cmpres;
63
cmpres = strcmp(a->pattern, b->pattern);
64
if (!cmpres)
65
cmpres = (a->reward < b->reward) ? -1 :
66
((a->reward > b->reward) ? 1 : 0);
67
return cmpres;
68
}
69
70
static workitem_t *
71
workitem_avl_search(avl_root_t *rootp, const char *pattern)
72
{
73
workitem_t *vp;
74
avl_item_t *itemp = rootp->ar_root;
75
76
while (itemp) {
77
int cmpres;
78
vp = avl_item_entry(itemp, workitem_t, avlent);
79
cmpres = strcmp(vp->pattern, pattern);
80
if (cmpres > 0) {
81
itemp = itemp->ai_left;
82
} else {
83
if (cmpres < 0) {
84
itemp = itemp->ai_right;
85
} else
86
return vp;
87
}
88
}
89
return NULL;
90
}
91
92
static workitem_t *
93
workitem_avl_insert(avl_root_t *rootp, workitem_t *vpnew)
94
{
95
workitem_t *vp;
96
avl_item_t *itemp = NULL;
97
avl_item_t **ptrp = &rootp->ar_root;
98
while (*ptrp) {
99
int cmpres;
100
itemp = *ptrp;
101
vp = avl_item_entry(itemp, workitem_t, avlent);
102
cmpres = workitem_cmp(vp, vpnew);
103
if (cmpres > 0) {
104
ptrp = &itemp->ai_left;
105
} else {
106
if (cmpres < 0) {
107
ptrp = &itemp->ai_right;
108
} else
109
return vp;
110
}
111
}
112
vpnew->avlent.ai_up = itemp;
113
itemp = &vpnew->avlent;
114
*ptrp = itemp;
115
avl_insert_fix(rootp, itemp);
116
return NULL;
117
}
118
119
static workitem_t *
120
workitem_avl_first(avl_root_t *rootp)
121
{
122
avl_item_t *itemp;
123
itemp = avl_first(rootp);
124
if (itemp)
125
return avl_item_entry(itemp, workitem_t, avlent);
126
return NULL;
127
}
128
129
static workitem_t *
130
workitem_avl_next(workitem_t *vp)
131
{
132
avl_item_t *itemp = &vp->avlent;
133
itemp = avl_next(itemp);
134
if (itemp)
135
return avl_item_entry(itemp, workitem_t, avlent);
136
return NULL;
137
}
138
139
void
140
server_workitem_free(workitem_t *wip)
141
{
142
if (wip->pubkey)
143
EC_POINT_free(wip->pubkey);
144
free(wip);
145
}
146
147
148
/*
149
* pubkeybatch, which includes a set of pattern bounties with the same
150
* base public key. Patterns may be searched for concurrently due to
151
* having the same base public key.
152
*
153
* Indexed in an AVL tree by public key.
154
*/
155
156
typedef struct pubkeybatch_s {
157
avl_item_t avlent;
158
EC_POINT *pubkey;
159
const char *pubkey_hex;
160
avl_root_t items;
161
int nitems;
162
double total_value;
163
} pubkeybatch_t;
164
165
void
166
server_batch_free(pubkeybatch_t *pbatch)
167
{
168
workitem_t *wip;
169
while ((wip = workitem_avl_first(&pbatch->items)) != NULL) {
170
if (wip->pubkey == pbatch->pubkey)
171
wip->pubkey = NULL;
172
avl_remove(&pbatch->items, &wip->avlent);
173
server_workitem_free(wip);
174
}
175
if (pbatch->pubkey)
176
EC_POINT_free(pbatch->pubkey);
177
if (pbatch->pubkey_hex)
178
OPENSSL_free((char*)pbatch->pubkey_hex);
179
free(pbatch);
180
}
181
182
static int
183
pubkeybatch_cmp(pubkeybatch_t *a, pubkeybatch_t *b)
184
{
185
return strcmp(a->pubkey_hex, b->pubkey_hex);
186
}
187
188
static pubkeybatch_t *
189
pubkeybatch_avl_search(avl_root_t *rootp, const EC_POINT *pubkey,
190
const EC_GROUP *pgroup)
191
{
192
char *pubkey_hex;
193
pubkeybatch_t *vp;
194
avl_item_t *itemp = rootp->ar_root;
195
pubkey_hex = EC_POINT_point2hex(pgroup,
196
pubkey,
197
POINT_CONVERSION_UNCOMPRESSED,
198
NULL);
199
while (itemp) {
200
int cmpres;
201
vp = avl_item_entry(itemp, pubkeybatch_t, avlent);
202
cmpres = strcmp(pubkey_hex, vp->pubkey_hex);
203
if (cmpres > 0) {
204
itemp = itemp->ai_left;
205
} else {
206
if (cmpres < 0) {
207
itemp = itemp->ai_right;
208
} else {
209
OPENSSL_free(pubkey_hex);
210
return vp;
211
}
212
}
213
}
214
OPENSSL_free(pubkey_hex);
215
return NULL;
216
}
217
218
static pubkeybatch_t *
219
pubkeybatch_avl_insert(avl_root_t *rootp, pubkeybatch_t *vpnew)
220
{
221
pubkeybatch_t *vp;
222
avl_item_t *itemp = NULL;
223
avl_item_t **ptrp = &rootp->ar_root;
224
while (*ptrp) {
225
int cmpres;
226
itemp = *ptrp;
227
vp = avl_item_entry(itemp, pubkeybatch_t, avlent);
228
cmpres = pubkeybatch_cmp(vpnew, vp);
229
if (cmpres > 0) {
230
ptrp = &itemp->ai_left;
231
} else {
232
if (cmpres < 0) {
233
ptrp = &itemp->ai_right;
234
} else
235
return vp;
236
}
237
}
238
vpnew->avlent.ai_up = itemp;
239
itemp = &vpnew->avlent;
240
*ptrp = itemp;
241
avl_insert_fix(rootp, itemp);
242
return NULL;
243
}
244
245
static pubkeybatch_t *
246
pubkeybatch_avl_first(avl_root_t *rootp)
247
{
248
avl_item_t *itemp;
249
itemp = avl_first(rootp);
250
if (itemp)
251
return avl_item_entry(itemp, pubkeybatch_t, avlent);
252
return NULL;
253
}
254
255
static pubkeybatch_t *
256
pubkeybatch_avl_next(pubkeybatch_t *vp)
257
{
258
avl_item_t *itemp = &vp->avlent;
259
itemp = avl_next(itemp);
260
if (itemp)
261
return avl_item_entry(itemp, pubkeybatch_t, avlent);
262
return NULL;
263
}
264
265
266
typedef struct server_request_s {
267
int request_status;
268
const EC_GROUP *group;
269
270
char *part_buf;
271
size_t part_off;
272
size_t part_end;
273
size_t part_size;
274
275
avl_root_t items;
276
int nitems;
277
} server_request_t;
278
279
280
static workitem_t *
281
server_workitem_new(server_request_t *reqp,
282
const char *pfx, const char *pubkey_s,
283
const char *addrtype_s, const char *reward_s,
284
const char *comment)
285
{
286
workitem_t *wip;
287
EC_POINT *pubkey;
288
int addrtype;
289
double reward;
290
double difficulty;
291
292
addrtype = atoi(addrtype_s);
293
if ((addrtype < 0) || (addrtype > 255))
294
return NULL;
295
296
reward = strtod(reward_s, NULL);
297
if (reward < 0.0)
298
return NULL;
299
300
difficulty = vg_prefix_get_difficulty(addrtype, pfx);
301
if (difficulty == 0.0)
302
return NULL;
303
304
pubkey = EC_POINT_hex2point(reqp->group, pubkey_s, NULL, NULL);
305
if (pubkey == NULL)
306
return NULL;
307
308
309
wip = (workitem_t *) malloc(sizeof(*wip) +
310
strlen(pfx) +
311
strlen(comment) + 2);
312
memset(wip, 0, sizeof(*wip));
313
avl_item_init(&wip->avlent);
314
wip->pattern = (char *) (wip + 1);
315
strcpy((char *)wip->pattern, pfx);
316
wip->comment = wip->pattern + (strlen(wip->pattern) + 1);
317
strcpy((char *) wip->comment, comment);
318
wip->pubkey = pubkey;
319
wip->addrtype = addrtype;
320
wip->difficulty = difficulty;
321
wip->reward = reward;
322
wip->value = (reward * 1000000000.0) / difficulty;
323
324
return wip;
325
}
326
327
328
typedef struct server_context_s {
329
EC_KEY *dummy_key;
330
const char *url;
331
const char *credit_addr;
332
char *getwork;
333
char *submit;
334
int verbose;
335
avl_root_t items;
336
int nitems;
337
} server_context_t;
338
339
340
static int
341
server_workitem_equal(workitem_t *a, workitem_t *b)
342
{
343
return (a->reward == b->reward) && !strcmp(a->pattern, b->pattern);
344
}
345
346
static int
347
server_pubkeybatch_equal(server_context_t *ctxp,
348
pubkeybatch_t *a, pubkeybatch_t *b)
349
{
350
workitem_t *wipa, *wipb;
351
352
if (a->nitems != b->nitems)
353
return 0;
354
if (EC_POINT_cmp(EC_KEY_get0_group(ctxp->dummy_key),
355
a->pubkey, b->pubkey, NULL))
356
return 0;
357
358
for (wipa = workitem_avl_first(&a->items),
359
wipb = workitem_avl_first(&b->items);
360
wipa && wipb;
361
wipa = workitem_avl_next(wipa), wipb = workitem_avl_next(wipb)) {
362
if (!server_workitem_equal(wipa, wipb))
363
return 0;
364
}
365
return 1;
366
}
367
368
void
369
server_context_free(server_context_t *ctxp)
370
{
371
if (ctxp->dummy_key)
372
EC_KEY_free(ctxp->dummy_key);
373
if (ctxp->getwork)
374
free(ctxp->getwork);
375
if (ctxp->submit)
376
free(ctxp->submit);
377
free(ctxp);
378
}
379
380
server_context_t *
381
server_context_new(const char *url, const char *credit_addr)
382
{
383
server_context_t *ctxp;
384
int urllen = strlen(url);
385
int addrlen = strlen(credit_addr);
386
ctxp = (server_context_t *)
387
malloc(sizeof(*ctxp) + urllen + addrlen + 2);
388
memset(ctxp, 0, sizeof(*ctxp));
389
avl_root_init(&ctxp->items);
390
ctxp->url = (const char *) (ctxp + 1);
391
ctxp->credit_addr = (const char *) (ctxp->url + urllen + 1);
392
strcpy((char *) ctxp->url, url);
393
strcpy((char *) ctxp->credit_addr, credit_addr);
394
395
ctxp->dummy_key = vg_exec_context_new_key();
396
ctxp->getwork = (char *) malloc(urllen + 9);
397
ctxp->submit = (char *) malloc(urllen + 7);
398
if (url[urllen - 1] == '/') {
399
snprintf(ctxp->getwork, urllen + 9, "%sgetWork", url);
400
snprintf(ctxp->submit, urllen + 7, "%ssolve", url);
401
} else {
402
snprintf(ctxp->getwork, urllen + 9, "%s/getWork", url);
403
snprintf(ctxp->submit, urllen + 7, "%s/solve", url);
404
}
405
406
return ctxp;
407
}
408
409
410
int
411
server_workitem_add(server_request_t *reqp, workitem_t *wip)
412
{
413
workitem_t *xwip;
414
pubkeybatch_t *pbatch = NULL;
415
416
pbatch = pubkeybatch_avl_search(&reqp->items, wip->pubkey, reqp->group);
417
if (pbatch == NULL) {
418
pbatch = (pubkeybatch_t *) malloc(sizeof(*pbatch));
419
if (pbatch == NULL)
420
return -1;
421
memset(pbatch, 0, sizeof(*pbatch));
422
avl_item_init(&pbatch->avlent);
423
avl_root_init(&pbatch->items);
424
pbatch->total_value = 0;
425
pbatch->pubkey = wip->pubkey;
426
pbatch->pubkey_hex = EC_POINT_point2hex(reqp->group,
427
wip->pubkey,
428
POINT_CONVERSION_UNCOMPRESSED,
429
NULL);
430
pubkeybatch_avl_insert(&reqp->items, pbatch);
431
reqp->nitems++;
432
}
433
434
/* Make sure there isn't an overlap */
435
xwip = workitem_avl_insert(&pbatch->items, wip);
436
if (xwip)
437
return -1;
438
439
if (wip->pubkey && wip->pubkey != pbatch->pubkey)
440
EC_POINT_free(wip->pubkey);
441
wip->pubkey = pbatch->pubkey;
442
443
pbatch->nitems++;
444
pbatch->total_value += wip->value;
445
return 0;
446
}
447
448
449
static size_t
450
server_body_reader(const char *buf, size_t elemsize, size_t len, void *param)
451
{
452
server_request_t *reqp = (server_request_t *) param;
453
char *line, *sep, *pfx, *pubkey_s, *addrtype_s, *reward_s, *comment;
454
workitem_t *wip;
455
456
if (!len)
457
return 0;
458
459
if ((reqp->part_size < (reqp->part_end + len + 1)) &&
460
(reqp->part_off > 0)) {
461
memmove(reqp->part_buf,
462
reqp->part_buf + reqp->part_off,
463
reqp->part_end - reqp->part_off);
464
reqp->part_end -= reqp->part_off;
465
reqp->part_off = 0;
466
}
467
468
if (reqp->part_size < (reqp->part_end + len + 1)) {
469
if (reqp->part_size == 0)
470
reqp->part_size = 4096;
471
while (reqp->part_size < (reqp->part_end + len + 1)) {
472
reqp->part_size *= 2;
473
if (reqp->part_size > (1024*1024)) {
474
fprintf(stderr, "Line too long from server");
475
reqp->request_status = 0;
476
return 0;
477
}
478
}
479
reqp->part_buf = (char *) realloc(reqp->part_buf,
480
reqp->part_size);
481
if (!reqp->part_buf) {
482
fprintf(stderr, "Out of memory");
483
return 0;
484
}
485
}
486
487
memcpy(reqp->part_buf + reqp->part_end, buf, len);
488
reqp->part_end += len;
489
reqp->part_buf[reqp->part_end] = '\0';
490
491
line = reqp->part_buf + reqp->part_off;
492
while (1) {
493
sep = strchr(line, '\n');
494
if (!sep)
495
break;
496
pfx = line;
497
*sep = '\0';
498
line = sep + 1;
499
sep = strchr(pfx, ':');
500
if (!sep)
501
goto bad_line;
502
*sep = '\0'; sep += 1;
503
pubkey_s = sep;
504
sep = strchr(sep, ':');
505
if (!sep)
506
goto bad_line;
507
*sep = '\0'; sep += 1;
508
addrtype_s = sep;
509
sep = strchr(sep, ':');
510
if (!sep)
511
goto bad_line;
512
*sep = '\0'; sep += 1;
513
reward_s = sep;
514
sep = strchr(sep, ';');
515
if (!sep)
516
goto bad_line;
517
*sep = '\0'; sep += 1;
518
comment = sep;
519
520
wip = server_workitem_new(reqp, pfx, pubkey_s, addrtype_s,
521
reward_s, comment);
522
if (!wip)
523
goto bad_line;
524
if (server_workitem_add(reqp, wip)) {
525
server_workitem_free(wip);
526
goto bad_line;
527
}
528
continue;
529
530
bad_line:
531
;
532
}
533
534
reqp->part_off = line - reqp->part_buf;
535
if (reqp->part_off == reqp->part_end) {
536
reqp->part_off = 0;
537
reqp->part_end = 0;
538
}
539
540
return len;
541
}
542
543
void
544
dump_work(avl_root_t *work)
545
{
546
pubkeybatch_t *pbatch;
547
workitem_t *wip;
548
printf("Available bounties:\n");
549
for (pbatch = pubkeybatch_avl_first(work);
550
pbatch != NULL;
551
pbatch = pubkeybatch_avl_next(pbatch)) {
552
553
for (wip = workitem_avl_first(&pbatch->items);
554
wip != NULL;
555
wip = workitem_avl_next(wip)) {
556
printf("Pattern: \"%s\" Reward: %f "
557
"Value: %f BTC/Gkey\n",
558
wip->pattern,
559
wip->reward,
560
wip->value);
561
}
562
if (pbatch->nitems > 1)
563
printf("Batch of %d, total value: %f BTC/Gkey\n",
564
pbatch->nitems, pbatch->total_value);
565
}
566
}
567
568
void
569
free_pkb_tree(avl_root_t *rootp, pubkeybatch_t *save_pkb)
570
{
571
pubkeybatch_t *pkb;
572
while ((pkb = pubkeybatch_avl_first(rootp)) != NULL) {
573
avl_remove(rootp, &pkb->avlent);
574
if (pkb != save_pkb)
575
server_batch_free(pkb);
576
}
577
}
578
579
void
580
server_request_free(server_request_t *reqp)
581
{
582
if (reqp->part_buf != NULL)
583
free(reqp->part_buf);
584
if (!avl_root_empty(&reqp->items))
585
free_pkb_tree(&reqp->items, NULL);
586
free(reqp);
587
}
588
589
int
590
server_context_getwork(server_context_t *ctxp)
591
{
592
CURLcode res;
593
server_request_t *reqp;
594
CURL *creq;
595
596
reqp = (server_request_t *) malloc(sizeof(*reqp));
597
memset(reqp, 0, sizeof(*reqp));
598
599
reqp->group = EC_KEY_get0_group(ctxp->dummy_key);
600
601
creq = curl_easy_init();
602
if (curl_easy_setopt(creq, CURLOPT_URL, ctxp->getwork) ||
603
curl_easy_setopt(creq, CURLOPT_VERBOSE, ctxp->verbose > 1) ||
604
curl_easy_setopt(creq, CURLOPT_WRITEFUNCTION,
605
server_body_reader) ||
606
curl_easy_setopt(creq, CURLOPT_FOLLOWLOCATION, 1) ||
607
curl_easy_setopt(creq, CURLOPT_WRITEDATA, reqp)) {
608
fprintf(stderr, "Failed to set up libcurl\n");
609
exit(1);
610
}
611
612
res = curl_easy_perform(creq);
613
curl_easy_cleanup(creq);
614
615
if (res != CURLE_OK) {
616
fprintf(stderr, "Get work request failed: %s\n",
617
curl_easy_strerror(res));
618
server_request_free(reqp);
619
return -1;
620
}
621
622
ctxp->items.ar_root = reqp->items.ar_root;
623
return 0;
624
}
625
626
627
int
628
server_context_submit_solution(server_context_t *ctxp,
629
workitem_t *work,
630
const char *privkey)
631
{
632
char urlbuf[8192];
633
char *pubhex;
634
CURL *creq;
635
CURLcode res;
636
637
pubhex = EC_POINT_point2hex(EC_KEY_get0_group(ctxp->dummy_key),
638
work->pubkey,
639
POINT_CONVERSION_UNCOMPRESSED,
640
NULL);
641
snprintf(urlbuf, sizeof(urlbuf),
642
"%s?key=%s%%3A%s&privateKey=%s&bitcoinAddress=%s",
643
ctxp->submit,
644
work->pattern,
645
pubhex,
646
privkey,
647
ctxp->credit_addr);
648
OPENSSL_free(pubhex);
649
creq = curl_easy_init();
650
if (curl_easy_setopt(creq, CURLOPT_URL, urlbuf) ||
651
curl_easy_setopt(creq, CURLOPT_VERBOSE, ctxp->verbose > 1) ||
652
curl_easy_setopt(creq, CURLOPT_FOLLOWLOCATION, 1)) {
653
fprintf(stderr, "Failed to set up libcurl\n");
654
exit(1);
655
}
656
657
res = curl_easy_perform(creq);
658
if (res != CURLE_OK) {
659
fprintf(stderr, "Submission failed: %s\n",
660
curl_easy_strerror(res));
661
curl_easy_cleanup(creq);
662
return -1;
663
}
664
665
curl_easy_cleanup(creq);
666
return 0;
667
}
668
669
static pthread_mutex_t soln_lock;
670
static pthread_cond_t soln_cond;
671
static char *soln_pattern = NULL;
672
static char *soln_private_key = NULL;
673
674
void
675
free_soln()
676
{
677
if (soln_pattern) {
678
free(soln_pattern);
679
soln_pattern = NULL;
680
}
681
if (soln_private_key) {
682
OPENSSL_free(soln_private_key);
683
soln_private_key = NULL;
684
}
685
}
686
687
void
688
output_match_work_complete(vg_context_t *vcp, EC_KEY *pkey, const char *pattern)
689
{
690
vg_output_match_console(vcp, pkey, pattern);
691
pthread_mutex_lock(&soln_lock);
692
free_soln();
693
soln_pattern = strdup(pattern);
694
soln_private_key = BN_bn2hex(EC_KEY_get0_private_key(pkey));
695
696
/* Signal the generator to stop */
697
vcp->vc_halt = 1;
698
699
/* Wake up the main thread, if it's sleeping */
700
pthread_cond_broadcast(&soln_cond);
701
pthread_mutex_unlock(&soln_lock);
702
}
703
704
int
705
check_solution(server_context_t *scp, pubkeybatch_t *pbatch)
706
{
707
int res = 0;
708
pthread_mutex_lock(&soln_lock);
709
if (soln_private_key != NULL) {
710
workitem_t *wip = workitem_avl_search(&pbatch->items,
711
soln_pattern);
712
assert(wip != NULL);
713
avl_remove(&pbatch->items, &wip->avlent);
714
pbatch->nitems--;
715
pbatch->total_value -= wip->value;
716
server_context_submit_solution(scp, wip, soln_private_key);
717
if (wip->pubkey == pbatch->pubkey)
718
wip->pubkey = NULL;
719
server_workitem_free(wip);
720
free_soln();
721
res = 1;
722
}
723
pthread_mutex_unlock(&soln_lock);
724
return res;
725
}
726
727
pubkeybatch_t *
728
most_valuable_pkb(server_context_t *scp)
729
{
730
pubkeybatch_t *pbatch, *res = NULL;
731
for (pbatch = pubkeybatch_avl_first(&scp->items);
732
pbatch != NULL;
733
pbatch = pubkeybatch_avl_next(pbatch)) {
734
if (!res || (res->total_value < pbatch->total_value))
735
res = pbatch;
736
}
737
return res;
738
}
739
740
void
741
usage(const char *name)
742
{
743
fprintf(stderr,
744
"oclVanityMiner %s (" OPENSSL_VERSION_TEXT ")\n"
745
"Usage: %s -u <URL> -a <credit address>\n"
746
"Organized vanity address mining client using OpenCL. Contacts the specified\n"
747
"bounty pool server, downloads a list of active bounties, and attempts to\n"
748
"generate the address with the best difficulty to reward ratio. Maintains\n"
749
"contact with the bounty pool server and periodically refreshes the bounty\n"
750
"list.\n"
751
"By default, if no device is specified, and the system has exactly one OpenCL\n"
752
"device, it will be selected automatically, otherwise if the system has\n"
753
"multiple OpenCL devices and no device is specified, an error will be\n"
754
"reported. To use multiple devices simultaneously, specify the -D option for\n"
755
"each device.\n"
756
"\n"
757
"Options:\n"
758
"-u <URL> Bounty pool URL\n"
759
"-a <address> Credit address for completed work\n"
760
"-i <interval> Set server polling interval in seconds (default 90)\n"
761
"-v Verbose output\n"
762
"-q Quiet output\n"
763
"-p <platform> Select OpenCL platform\n"
764
"-d <device> Select OpenCL device\n"
765
"-D <devstr> Use OpenCL device, identified by device string\n"
766
" Form: <platform>:<devicenumber>[,<options>]\n"
767
" Example: 0:0,grid=1024x1024\n"
768
"-S Safe mode, disable OpenCL loop unrolling optimizations\n"
769
"-w <worksize> Set work items per thread in a work unit\n"
770
"-t <threads> Set target thread count per multiprocessor\n"
771
"-g <x>x<y> Set grid size\n"
772
"-b <invsize> Set modular inverse ops per thread\n"
773
"-V Enable kernel/OpenCL/hardware verification (SLOW)\n",
774
version, name);
775
}
776
777
#define MAX_DEVS 32
778
779
int
780
main(int argc, char **argv)
781
{
782
const char *url = NULL;
783
const char *credit_addr = NULL;
784
int opt;
785
int platformidx = -1, deviceidx = -1;
786
char *pend;
787
int verbose = 1;
788
int interval = 90;
789
int nthreads = 0;
790
int worksize = 0;
791
int nrows = 0, ncols = 0;
792
int invsize = 0;
793
int verify_mode = 0;
794
int safe_mode = 0;
795
796
char *devstrs[MAX_DEVS];
797
int ndevstrs = 0;
798
799
vg_context_t *vcp = NULL;
800
vg_ocl_context_t *vocp = NULL;
801
802
int res;
803
int thread_started = 0;
804
pubkeybatch_t *active_pkb = NULL;
805
float active_pkb_value = 0;
806
807
server_context_t *scp = NULL;
808
pubkeybatch_t *pkb;
809
int was_sleeping = 0;
810
811
struct timeval tv;
812
struct timespec sleepy;
813
814
pthread_mutex_init(&soln_lock, NULL);
815
pthread_cond_init(&soln_cond, NULL);
816
817
if (argc == 1) {
818
usage(argv[0]);
819
return 1;
820
}
821
822
while ((opt = getopt(argc, argv,
823
"u:a:vqp:d:w:t:g:b:VD:Sh?i:")) != -1) {
824
switch (opt) {
825
case 'u':
826
url = optarg;
827
break;
828
case 'a':
829
credit_addr = optarg;
830
break;
831
case 'v':
832
verbose = 2;
833
break;
834
case 'q':
835
verbose = 0;
836
break;
837
case 'i':
838
interval = atoi(optarg);
839
if (interval < 10) {
840
fprintf(stderr,
841
"Invalid interval '%s'\n", optarg);
842
return 1;
843
}
844
break;
845
case 'p':
846
platformidx = atoi(optarg);
847
break;
848
case 'd':
849
deviceidx = atoi(optarg);
850
break;
851
case 'w':
852
worksize = atoi(optarg);
853
if (worksize == 0) {
854
fprintf(stderr,
855
"Invalid work size '%s'\n", optarg);
856
return 1;
857
}
858
break;
859
case 't':
860
nthreads = atoi(optarg);
861
if (nthreads == 0) {
862
fprintf(stderr,
863
"Invalid thread count '%s'\n", optarg);
864
return 1;
865
}
866
break;
867
case 'g':
868
nrows = 0;
869
ncols = strtol(optarg, &pend, 0);
870
if (pend && *pend == 'x') {
871
nrows = strtol(pend+1, NULL, 0);
872
}
873
if (!nrows || !ncols) {
874
fprintf(stderr,
875
"Invalid grid size '%s'\n", optarg);
876
return 1;
877
}
878
break;
879
case 'b':
880
invsize = atoi(optarg);
881
if (!invsize) {
882
fprintf(stderr,
883
"Invalid modular inverse size '%s'\n",
884
optarg);
885
return 1;
886
}
887
if (invsize & (invsize - 1)) {
888
fprintf(stderr,
889
"Modular inverse size must be "
890
"a power of 2\n");
891
return 1;
892
}
893
break;
894
case 'V':
895
verify_mode = 1;
896
break;
897
case 'S':
898
safe_mode = 1;
899
break;
900
case 'D':
901
if (ndevstrs >= MAX_DEVS) {
902
fprintf(stderr,
903
"Too many OpenCL devices (limit %d)\n",
904
MAX_DEVS);
905
return 1;
906
}
907
devstrs[ndevstrs++] = optarg;
908
break;
909
default:
910
usage(argv[0]);
911
return 1;
912
}
913
}
914
915
#if OPENSSL_VERSION_NUMBER < 0x10000000L
916
/* Complain about older versions of OpenSSL */
917
if (verbose > 0) {
918
fprintf(stderr,
919
"WARNING: Built with " OPENSSL_VERSION_TEXT "\n"
920
"WARNING: Use OpenSSL 1.0.0d+ for best performance\n");
921
}
922
#endif
923
curl_easy_init();
924
925
vcp = vg_prefix_context_new(0, 128, 0);
926
927
vcp->vc_verbose = verbose;
928
929
vcp->vc_output_match = output_match_work_complete;
930
vcp->vc_output_timing = vg_output_timing_console;
931
932
933
if (!url) {
934
fprintf(stderr, "ERROR: No server URL specified\n");
935
return 1;
936
}
937
if (!credit_addr) {
938
fprintf(stderr, "ERROR: No reward address specified\n");
939
return 1;
940
}
941
if (!vg_b58_decode_check(credit_addr, NULL, 0)) {
942
fprintf(stderr, "ERROR: Invalid reward address specified\n");
943
return 1;
944
}
945
946
scp = server_context_new(url, credit_addr);
947
scp->verbose = verbose;
948
949
/* Get the initial bounty list, abort on failure */
950
if (server_context_getwork(scp))
951
return 1;
952
953
/* Set up OpenCL */
954
res = 0;
955
if (ndevstrs) {
956
for (opt = 0; opt < ndevstrs; opt++) {
957
vocp = vg_ocl_context_new_from_devstr(vcp, devstrs[opt],
958
safe_mode,
959
verify_mode);
960
if (!vocp) {
961
fprintf(stderr,
962
"Could not open device '%s', ignoring\n",
963
devstrs[opt]);
964
} else {
965
res++;
966
}
967
}
968
} else {
969
vocp = vg_ocl_context_new(vcp, platformidx, deviceidx,
970
safe_mode, verify_mode,
971
worksize, nthreads,
972
nrows, ncols, invsize);
973
if (vocp)
974
res++;
975
}
976
if (!res) {
977
vg_ocl_enumerate_devices();
978
return 1;
979
}
980
981
if (verbose > 1)
982
dump_work(&scp->items);
983
984
while (1) {
985
if (avl_root_empty(&scp->items))
986
server_context_getwork(scp);
987
988
pkb = most_valuable_pkb(scp);
989
990
/* If the work item is the same as the one we're executing,
991
keep it */
992
if (pkb && active_pkb &&
993
server_pubkeybatch_equal(scp, active_pkb, pkb))
994
pkb = active_pkb;
995
996
if (thread_started && (!active_pkb || (pkb != active_pkb))) {
997
/* If a thread is running, stop it */
998
vg_context_stop_threads(vcp);
999
thread_started = 0;
1000
if (active_pkb) {
1001
check_solution(scp, active_pkb);
1002
active_pkb = NULL;
1003
}
1004
vg_context_clear_all_patterns(vcp);
1005
1006
if (verbose > 1)
1007
dump_work(&scp->items);
1008
}
1009
1010
if (!pkb) {
1011
if (!was_sleeping) {
1012
fprintf(stderr,
1013
"No work available, sleeping\n");
1014
was_sleeping = 1;
1015
}
1016
1017
} else if (!active_pkb) {
1018
workitem_t *wip;
1019
was_sleeping = 0;
1020
active_pkb_value = 0;
1021
vcp->vc_pubkey_base = pkb->pubkey;
1022
for (wip = workitem_avl_first(&pkb->items);
1023
wip != NULL;
1024
wip = workitem_avl_next(wip)) {
1025
fprintf(stderr,
1026
"Searching for pattern: \"%s\" "
1027
"Reward: %f Value: %f BTC/Gkey\n",
1028
wip->pattern,
1029
wip->reward,
1030
wip->value);
1031
vcp->vc_addrtype = wip->addrtype;
1032
if (!vg_context_add_patterns(vcp,
1033
&wip->pattern,
1034
1)) {
1035
fprintf(stderr,
1036
"WARNING: could not add pattern\n");
1037
}
1038
else {
1039
active_pkb_value += wip->value;
1040
}
1041
1042
assert(vcp->vc_npatterns);
1043
}
1044
1045
fprintf(stderr,
1046
"\nTotal value for current work: %f BTC/Gkey\n",
1047
active_pkb_value);
1048
res = vg_context_start_threads(vcp);
1049
if (res)
1050
return 1;
1051
thread_started = 1;
1052
active_pkb = pkb;
1053
}
1054
1055
/* Wait for something to happen */
1056
gettimeofday(&tv, NULL);
1057
sleepy.tv_sec = tv.tv_sec;
1058
sleepy.tv_nsec = tv.tv_usec * 1000;
1059
sleepy.tv_sec += interval;
1060
1061
pthread_mutex_lock(&soln_lock);
1062
res = 0;
1063
if (!soln_private_key)
1064
res = pthread_cond_timedwait(&soln_cond,
1065
&soln_lock, &sleepy);
1066
pthread_mutex_unlock(&soln_lock);
1067
1068
if (res == 0) {
1069
if (check_solution(scp, active_pkb))
1070
active_pkb = NULL;
1071
}
1072
else if (res == ETIMEDOUT) {
1073
free_pkb_tree(&scp->items, active_pkb);
1074
}
1075
}
1076
1077
return 0;
1078
}
1079
1080