Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* fpga-cminer 0.1, Copyright 2011 by Lazarus Long, lazarus-long@gmx.net
- This is a bitcoin FPGA miner targeted to embedded linux systems
- based on and FPGA API compatible with TheSevens pyminer.
- If you linke this tool drop in some coins into my hat:
- 16EwZRLio5ik6fshWexzuj9jWeWCoNEuHw
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <ctype.h>
- #include <string.h>
- #include <unistd.h>
- #include <termios.h>
- #include <signal.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <fcntl.h>
- #include <curl/curl.h>
- #include <json/json.h>
- #define STRSIZE 256
- struct curl_response{
- char *data;
- size_t size;
- };
- struct fpga_in_data {
- uint8_t command;
- uint8_t state[32];
- uint8_t data[12];
- } __attribute__ ((packed));
- struct mining_job {
- struct fpga_in_data in_data;
- uint8_t jobdata[128];
- uint8_t nonce[4];
- } __attribute__ ((packed));
- /* 1 indicates an LP event */
- int lp_ctrl=0;
- /* 1 indicates child has exited */
- int lp_child=0;
- void print_usage(void) {
- printf("fpga-cminer 0.1, 2011 by Lazarus Long, lazarus-long@gmx.net\n");
- printf("Usage: fpga-cminer -d <device> -u <username> -p <password> [ -j <seconds>]\n");
- printf(" i.e.: fpga-cminer -d /dev/ttyS0 -h btcguild.com -u lazarus -p heinlein\n");
- printf(" -j overwrites the job intervall to X seconds\n");
- }
- static int hex2num(char c)
- {
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- return -1;
- }
- static int hex2byte(const char *hex)
- {
- int a, b;
- a = hex2num(*hex++);
- if (a < 0)
- return -1;
- b = hex2num(*hex++);
- if (b < 0)
- return -1;
- return (a << 4) | b;
- }
- /**
- * hexstr2bin - Convert ASCII hex string into binary data
- * @hex: ASCII hex string (e.g., "01ab")
- * @buf: Buffer for the binary data
- * @len: Length of the text to convert in bytes (of buf); hex will be double
- * this size
- * Returns: 0 on success, -1 on failure (invalid hex string)
- */
- int hexstr2bin(const char *hex, uint8_t *buf, size_t len)
- {
- size_t i;
- int a;
- const char *ipos = hex;
- uint8_t *opos = buf;
- for (i = 0; i < len; i++) {
- a = hex2byte(ipos);
- if (a < 0)
- return -1;
- *opos++ = a;
- ipos += 2;
- }
- return 0;
- }
- /**
- * hexstr2binrev - Convert ASCII hex string into binary data in reverse order
- * @hex: ASCII hex string (e.g., "01ab")
- * @buf: Buffer for the binary data
- * @len: Length of the text to convert in bytes (of buf); hex will be double
- * this size
- * Returns: 0 on success, -1 on failure (invalid hex string)
- */
- int hexstr2binrev(const char *hex, uint8_t *buf, size_t len)
- {
- size_t i;
- int a;
- const char *ipos = hex;
- uint8_t *opos = buf;
- /* goto end of string */
- ipos += ((len-1)*2);
- for (i = 0; i < len; i++) {
- a = hex2byte(ipos);
- if (a < 0)
- return -1;
- *opos++ = a;
- ipos -= 2;
- }
- return 0;
- }
- void print_hex(uint8_t *data, int len) {
- int i;
- for (i=0; i<len; i++) {
- printf("%.2x",data[i]);
- }
- printf("\n");
- }
- static void
- signal_handler (int sig)
- {
- if (sig == SIGUSR1) {
- lp_ctrl=1;
- lp_child=0;
- }
- //if (sig == SIGCHLD) {
- //lp_child=0;
- //}
- }
- size_t header_callback (void *ptr, size_t size, size_t nmemb, void *data)
- {
- struct curl_response *header_res = NULL;
- int rsize = 0;
- int lp_size = 0;
- header_res = (struct curl_response *)data;
- rsize = size * nmemb;
- if (strncmp(ptr,"X-Long-Polling: ",16) ==0) {
- lp_size=rsize-16;
- header_res->data = (char *)realloc(header_res->data, header_res->size + lp_size + 1);
- if (header_res->data) {
- memcpy(&(header_res->data[header_res->size]), ptr+16, lp_size);
- header_res->size += lp_size;
- header_res->data[lp_size] = 0;
- printf("Found Long polling URL: %s\n",(char *)header_res->data);
- }
- }
- return rsize;
- }
- size_t response_callback(void *ptr,
- size_t size, size_t nmemb, void *data)
- {
- int rsize = 0;
- struct curl_response *res = NULL;
- rsize = size * nmemb;
- res = (struct curl_response *)data;
- res->data = (char *)realloc(res->data, res->size + rsize + 1);
- if (res->data) {
- memcpy(&(res->data[res->size]), ptr, rsize);
- res->size += rsize;
- res->data[res->size] = 0;
- }
- return rsize;
- }
- void wait_for_lp(char *lp_url, char *host, char *userpwd) {
- char buf[1024];
- CURL *curl;
- char url[STRSIZE];
- struct curl_slist *slist = NULL;
- struct curl_response res;
- curl = curl_easy_init();
- if(curl) {
- /* init structer for response */
- res.data = NULL;
- res.size = 0;
- sprintf(url,"http://%s:8332/LP",host);
- curl_easy_setopt(curl, CURLOPT_USERPWD, userpwd);
- curl_easy_setopt(curl, CURLOPT_URL, url);
- //curl_easy_setopt(curl, CURLOPT_VERBOSE,1);
- slist = curl_slist_append(slist, "Content-type: application/json");
- slist = curl_slist_append(slist, "Expect:");
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, response_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&res );
- curl_easy_setopt(curl, CURLOPT_USERAGENT, "fpga-cminer 0.1");
- curl_easy_perform(curl);
- curl_slist_free_all(slist);
- char *resp_data=malloc(res.size+2);
- memset(resp_data,0,res.size+2);
- snprintf(resp_data,res.size+1,"%s",res.data);
- free(res.data);
- //printf("LP: %s\n",resp_data);
- kill(getppid(),SIGUSR1);
- curl_easy_cleanup(curl);
- free(resp_data);
- /* XXX: we sould use this job response too */
- }
- }
- void send_response(struct mining_job *job, char *host, char *userpwd) {
- char buf[1024];
- struct timeval starttime;
- struct timeval endtime;
- CURL *curl;
- char url[STRSIZE];
- struct curl_slist *slist = NULL;
- struct curl_response res;
- curl = curl_easy_init();
- if(curl) {
- /* init structer for response */
- res.data = NULL;
- res.size = 0;
- sprintf(url,"http://%s:8332",host);
- curl_easy_setopt(curl, CURLOPT_USERPWD, userpwd);
- curl_easy_setopt(curl, CURLOPT_URL, url);
- //curl_easy_setopt(curl, CURLOPT_VERBOSE,1);
- slist = curl_slist_append(slist, "Content-type: application/json");
- slist = curl_slist_append(slist, "Expect:");
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, response_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&res );
- curl_easy_setopt(curl, CURLOPT_USERAGENT, "fpga-cminer 0.1");
- json_object *jobj = json_object_new_object();
- json_object *jmeth = json_object_new_string("getwork");
- json_object *jid = json_object_new_int(0);
- json_object *jparams = json_object_new_array();
- // in: 12 bytes: 75:63:-1
- //"params": [binascii.hexlify(data[:76] + nonce + data[80:])], "id": 0})
- char *responsedata;
- responsedata=malloc(1024);
- int i,j;
- for (i=0; i<76; i++) {
- sprintf(responsedata+(i*2),"%.2x",job->jobdata[i]);
- }
- sprintf(responsedata+(i*2),"%.2x%.2x%.2x%.2x",
- job->nonce[0],
- job->nonce[1],
- job->nonce[2],
- job->nonce[3]);
- i+=4;
- for (j=i; j<128; j++) {
- sprintf(responsedata+(j*2),"%.2x",job->jobdata[j]);
- }
- json_object *jdata = json_object_new_string(responsedata);
- json_object_array_add(jparams,jdata);
- json_object_object_add(jobj,"method", jmeth);
- json_object_object_add(jobj,"params", jparams);
- json_object_object_add(jobj,"id", jid);
- sprintf(buf,"%s",json_object_to_json_string(jobj));
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buf);
- //printf("Response Json: %s\n",buf);
- curl_easy_perform(curl);
- curl_slist_free_all(slist);
- char *resp_data=malloc(res.size+2);
- memset(resp_data,0,res.size+2);
- snprintf(resp_data,res.size+1,"%s",res.data);
- // Response: {"id":0,"error":null,"result":false}
- struct json_object *json_resp;
- struct json_object *json_result;
- struct json_object *json_error;
- json_resp = json_tokener_parse(resp_data);
- json_result = json_object_object_get(json_resp, "result");
- json_error = json_object_object_get(json_resp, "error");
- printf("Result:%s\n",json_object_get_string(json_result));
- free(res.data);
- free(resp_data);
- free(responsedata);
- curl_easy_cleanup(curl);
- }
- }
- struct mining_job *request_job(char *host, char *userpwd) {
- char buf[1024];
- char lp_url[1024];
- struct timeval starttime;
- struct timeval endtime;
- CURL *curl;
- char url[STRSIZE];
- struct curl_slist *slist = NULL;
- struct mining_job *job=NULL;
- struct curl_response res;
- struct curl_response header_res;
- curl = curl_easy_init();
- if(curl) {
- job = malloc(sizeof(struct mining_job));
- /* init structer for response */
- res.data = NULL;
- res.size = 0;
- header_res.data = NULL;
- header_res.size = 0;
- sprintf(url,"http://%s:8332",host);
- curl_easy_setopt(curl, CURLOPT_USERPWD, userpwd);
- curl_easy_setopt(curl, CURLOPT_URL, url);
- //curl_easy_setopt(curl, CURLOPT_VERBOSE,1);
- slist = curl_slist_append(slist, "Content-type: application/json");
- slist = curl_slist_append(slist, "Expect:");
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, response_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&res );
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&header_res);
- curl_easy_setopt(curl, CURLOPT_USERAGENT, "fpga-cminer 0.1");
- json_object *jobj = json_object_new_object();
- json_object *jmeth = json_object_new_string("getwork");
- json_object *jid = json_object_new_int(0);
- json_object *jparams = json_object_new_array();
- json_object_object_add(jobj,"method", jmeth);
- json_object_object_add(jobj,"params", jparams);
- json_object_object_add(jobj,"id", jid);
- sprintf(buf,"%s",json_object_to_json_string(jobj));
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buf);
- curl_easy_perform(curl);
- curl_slist_free_all(slist);
- char *resp_data=malloc(res.size+2);
- memset(resp_data,0,res.size+2);
- snprintf(resp_data,res.size+1,"%s",res.data);
- free(res.data);
- char *lp_url=NULL;
- lp_url=malloc(header_res.size+2);
- memset(lp_url,0,header_res.size+2);
- snprintf(lp_url,header_res.size+1,"%s",header_res.data);
- free(header_res.data);
- struct json_object *json_resp;
- struct json_object *json_result;
- struct json_object *json_midstate;
- struct json_object *json_data;
- json_resp = json_tokener_parse(resp_data);
- json_result = json_object_object_get(json_resp, "result");
- json_midstate = json_object_object_get(json_result, "midstate");
- json_data = json_object_object_get(json_result, "data");
- //printf("getwork Json:%s\n",json_object_to_json_string(json_resp));
- //printf("JSON state:%s\n",json_object_get_string(json_midstate));
- snprintf(buf,256,"%s",json_object_get_string(json_data));
- memset(job,0x0,sizeof(struct mining_job));
- job->in_data.command =0x01;
- hexstr2bin(json_object_get_string(json_data), job->jobdata, sizeof(job->jobdata));
- hexstr2binrev(json_object_get_string(json_midstate),job->in_data.state, sizeof(job->in_data.state));
- hexstr2binrev(&buf[128],job->in_data.data, sizeof(job->in_data.data));
- curl_easy_cleanup(curl);
- free(resp_data);
- /* if we do not have a LP child we fork one off now */
- if ((lp_url == NULL) && (lp_child != 1)) {
- switch (fork()) {
- case -1:
- printf("LP fork error");
- exit(1);
- case 0: /* child */
- wait_for_lp(lp_url,host,userpwd);
- exit(0);
- default: /* parent */
- printf("LP watcher forked\n");
- lp_ctrl=0;
- lp_child=1;
- }
- }
- }
- return job;
- }
- int mine(int tty_fd, struct mining_job *job, float fpgajobint) {
- int loop=1;
- int state=0;
- int len=0;
- uint8_t *data=NULL;
- data = malloc(4);
- printf("Mining:");
- print_hex((uint8_t *)&(job->in_data),sizeof(struct fpga_in_data));
- if (write (tty_fd, (uint8_t *)&(job->in_data), sizeof(struct fpga_in_data)) != sizeof(struct fpga_in_data)) {
- printf("write error\n");
- exit(1);
- }
- while(loop) {
- /* 1: starting
- * 2: done */
- len = read (tty_fd, data, 1);
- if (len > 0) {
- if (data[0]==0x1) {
- //printf("FPGA accepted\n");
- state=1;
- } else if(data[0]==0x2) {
- if (state == 0) {
- printf("Error: FPGA responded finished out of state\n");
- exit(1);
- }
- loop=0;
- len = read (tty_fd, data, 4);
- if (len==4) {
- job->nonce[0]=data[3];
- job->nonce[1]=data[2];
- job->nonce[2]=data[1];
- job->nonce[3]=data[0];
- free(data);
- return 1;
- } else {
- printf("read error in mining loop\n");
- break;
- }
- } else {
- printf("Error: FPGA responded: 0x%x\n",data[0]);
- exit(1);
- }
- } else {
- fpgajobint -= 0.1; /* VTIME 1 */
- if (fpgajobint <= 0) {
- printf("nothing found\n");
- break;
- }
- if (lp_ctrl>0) {
- lp_ctrl=0;
- printf("Long Polling indicated new block\n");
- break;
- }
- }
- }
- if (data != NULL)
- free(data);
- return(-1);
- }
- int
- main(int argc, char **argv)
- {
- char buf[1024];
- char userpwd[1024];
- struct timeval starttime;
- struct timeval endtime;
- CURL *curl;
- CURLcode res;
- extern char *optarg;
- extern int optind, opterr;
- char url[STRSIZE];
- char *dev=NULL;
- char *user=NULL;
- char *pass=NULL;
- char *host=NULL;
- int ch;
- int jobint = -1;
- int tty_fd;
- float fpgajobintval=60;
- struct curl_slist *slist = NULL;
- uint8_t result[4];
- struct mining_job *job;
- while (1) {
- ch = getopt(argc, argv, "d:u:p:h:j:");
- if (ch == -1) {
- break;
- }
- switch (ch) {
- case 'd':
- dev = optarg;
- break;
- case 'h':
- host = optarg;
- break;
- case 'u':
- user = optarg;
- break;
- case 'p':
- pass = optarg;
- break;
- case 'j':
- jobint = atoi(optarg);
- break;
- default:
- print_usage();
- exit(1);
- }
- }
- if (host == NULL) {
- print_usage();
- exit(1);
- }
- sprintf(userpwd,"%s:%s",user,pass);
- /* install sig handlers, LP chikd will send SIGUSR1 if a new block is started */
- signal (SIGCHLD, signal_handler);
- signal (SIGUSR1, signal_handler);
- /* serial port stuff */
- tty_fd = open(dev, O_RDWR | O_NOCTTY);
- if (tty_fd < 0) {
- printf("Could not open serial port: %s\n",dev);
- exit(1);
- }
- struct termios newtio;
- memset (&newtio, 0, sizeof (newtio));
- /* Set the bitrate */
- cfsetispeed (&newtio, B115200);
- cfsetospeed (&newtio, B115200);
- /* 8N1 */
- newtio.c_cflag |= CS8;
- newtio.c_cflag &= ~PARENB;
- newtio.c_cflag &= (~CSTOPB);
- /* Selects raw (non-canonical) input and output */
- newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- newtio.c_oflag &= ~OPOST;
- /* Ignore parity errors */
- newtio.c_iflag |= IGNPAR;
- /* Enable receiber, hang on close, ignore control line */
- newtio.c_cflag |= CREAD | HUPCL | CLOCAL;
- /* Read 1 byte minimun, no timeout specified */
- newtio.c_cc[VMIN] = 0;
- newtio.c_cc[VTIME] = 1; /*100ms timeout */
- if (tcsetattr (tty_fd, TCSANOW, &newtio) < 0) {
- printf("Error on tcsetattr\n");
- exit(1);
- }
- if (tcflush (tty_fd, TCIFLUSH) < 0) {
- printf("Error on tcflush\n");
- exit(1);
- }
- /* detect FPGA */
- int len;
- uint8_t *data=NULL;
- data = malloc(1024);
- job = malloc(sizeof(struct mining_job));
- memset(job,0x0,sizeof(struct mining_job));
- if (write (tty_fd, (uint8_t *)&(job->in_data), sizeof(struct fpga_in_data)) != sizeof(struct fpga_in_data)) {
- printf("write error\n");
- exit(1);
- }
- len = read (tty_fd, data, 100);
- if (len <= 0) {
- printf("FPGA did not respond\n");
- exit(1);
- }
- free(data);
- printf("FPGA OK, received: %d bytes\n",len);
- printf("Measuring FPGA performance...\n");
- job->in_data.command =0x01;
- hexstr2binrev("1625cbf1a5bc6ba648d1218441389e00a9dc79768a2fc6f2b79c70cf576febd0",
- job->in_data.state, 32);
- hexstr2binrev("4c0afa494de837d81a269421",
- job->in_data.data, 12);
- gettimeofday(&starttime,0);
- //print_hex(job->in_data.state,32);
- if ((mine(tty_fd,job,fpgajobintval)) < 0) {
- printf("mine error\n");
- exit(1);
- }
- gettimeofday(&endtime,0);
- /* test mining result */
- hexstr2bin("7bc2b302",result, 4);
- if (memcmp(result,job->nonce,4)!=0) {
- printf("recv: %d bytes: 0x%.2x%.2x%.2x%.2x\n",
- len,job->nonce[0],job->nonce[1],job->nonce[2],job->nonce[3]);
- printf("FPGA did wrong math\n");
- exit(1);
- } else {
- float delta;
- float mhps;
- delta = endtime.tv_sec-starttime.tv_sec;
- mhps = 45.335163 / delta;
- printf("Delta was: %f\n",delta);
- if (jobint > 0)
- fpgajobintval = jobint;
- else
- fpgajobintval = delta * 94.738 ; /* complete pattern takes 94.738 times the test pattern */
- printf("FPGA check passed, %f MH/s, Job intervall: %f\n",mhps,fpgajobintval);
- }
- while (1) {
- job = request_job(host,userpwd);
- if (job == NULL) {
- printf("Could not get job");
- exit(1);
- }
- if ((mine(tty_fd,job,fpgajobintval)) > 0) {
- printf("Share found: 0x%.2x%.2x%.2x%.2x\n",
- job->nonce[0],job->nonce[1],job->nonce[2],job->nonce[3]);
- send_response(job,host,userpwd);
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement