/****************************************************************************** * Copyright © 2014-2016 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ // komodo functions that interact with bitcoind C++ #ifdef _WIN32 #include #include #else #include #include #endif struct MemoryStruct { char *memory; size_t size; }; struct return_string { char *ptr; size_t len; }; // return data from the server #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) #define CURL_GLOBAL_SSL (1<<0) #define CURL_GLOBAL_WIN32 (1<<1) /************************************************************************ * * Initialize the string handler so that it is thread safe * ************************************************************************/ void init_string(struct return_string *s) { s->len = 0; s->ptr = (char *)calloc(1,s->len+1); if ( s->ptr == NULL ) { fprintf(stderr,"init_string malloc() failed\n"); exit(-1); } s->ptr[0] = '\0'; } /************************************************************************ * * Use the "writer" to accumulate text until done * ************************************************************************/ size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s) { size_t new_len = s->len + size*nmemb; s->ptr = (char *)realloc(s->ptr,new_len+1); if ( s->ptr == NULL ) { fprintf(stderr, "accumulate realloc() failed\n"); exit(-1); } memcpy(s->ptr+s->len,ptr,size*nmemb); s->ptr[new_len] = '\0'; s->len = new_len; return(size * nmemb); } /************************************************************************ * * return the current system time in milliseconds * ************************************************************************/ #define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field #ifdef EXTRACT_BITCOIND_RESULT /************************************************************************ * * perform post processing of the results * ************************************************************************/ char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params) { long i,j,len; char *retstr = 0; cJSON *json,*result,*error; //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) { if ( strcmp(command,"signrawtransaction") != 0 ) printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); return(rpcstr); } json = cJSON_Parse(rpcstr); if ( json == 0 ) { printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params); free(rpcstr); return(0); } result = cJSON_GetObjectItem(json,"result"); error = cJSON_GetObjectItem(json,"error"); if ( error != 0 && result != 0 ) { if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL ) { retstr = cJSON_Print(result); len = strlen(retstr); if ( retstr[0] == '"' && retstr[len-1] == '"' ) { for (i=1,j=0; itype&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) { if ( strcmp(command,"signrawtransaction") != 0 ) printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr); } free(rpcstr); } else retstr = rpcstr; free_json(json); //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr); return(retstr); } #endif /************************************************************************ * * perform the query * ************************************************************************/ char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params) { static int didinit,count,count2; static double elapsedsum,elapsedsum2; struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle; char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime; if ( didinit == 0 ) { didinit = 1; curl_global_init(CURL_GLOBAL_ALL); //init the curl session } numretries = 0; if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) specialcase = 1; else specialcase = 0; if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7876/nxt"); if ( specialcase != 0 && 0 ) printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params); try_again: if ( retstrp != 0 ) *retstrp = 0; starttime = OS_milliseconds(); curl_handle = curl_easy_init(); init_string(&s); headers = curl_slist_append(0,"Expect:"); curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl_handle,CURLOPT_URL, url); curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback if ( strncmp(url,"https",5) == 0 ) { curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); } if ( userpass != 0 ) curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); databuf = 0; if ( params != 0 ) { if ( command != 0 && specialcase == 0 ) { len = strlen(params); if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) { bracket0 = bracket1 = (char *)""; } else { bracket0 = (char *)"["; bracket1 = (char *)"]"; } databuf = (char *)malloc(256 + strlen(command) + strlen(params)); sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1); //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); // } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params); curl_easy_setopt(curl_handle,CURLOPT_POST,1L); if ( databuf != 0 ) curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf); else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params); } //laststart = milliseconds(); res = curl_easy_perform(curl_handle); curl_slist_free_all(headers); curl_easy_cleanup(curl_handle); if ( databuf != 0 ) // clean up temporary buffer { free(databuf); databuf = 0; } if ( res != CURLE_OK ) { numretries++; if ( specialcase != 0 ) { printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); free(s.ptr); return(0); } else if ( numretries >= 1 ) { //printf("Maximum number of retries exceeded!\n"); free(s.ptr); return(0); } if ( (rand() % 1000) == 0 ) printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); free(s.ptr); sleep((1< (%s)\n",params,s.ptr); count2++; elapsedsum2 += (OS_milliseconds() - starttime); if ( (count2 % 10000) == 0) printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command); return(s.ptr); } } printf("bitcoind_RPC: impossible case\n"); free(s.ptr); return(0); } static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data) { size_t realsize = (size * nmemb); struct MemoryStruct *mem = (struct MemoryStruct *)data; mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1)); if ( mem->memory != 0 ) { if ( ptr != 0 ) memcpy(&(mem->memory[mem->size]),ptr,realsize); mem->size += realsize; mem->memory[mem->size] = 0; } //printf("got %d bytes\n",(int32_t)(size*nmemb)); return(realsize); } char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) { struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0; if ( (cHandle= *cHandlep) == NULL ) *cHandlep = cHandle = curl_easy_init(); else curl_easy_reset(cHandle); //#ifdef DEBUG //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1); //#endif curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0); //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1); curl_easy_setopt(cHandle,CURLOPT_URL,url); curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10); if ( userpass != 0 && userpass[0] != 0 ) curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass); if ( postfields != 0 && postfields[0] != 0 ) { curl_easy_setopt(cHandle,CURLOPT_POST,1); curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields); } if ( hdr0 != NULL && hdr0[0] != 0 ) { //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:""); headers = curl_slist_append(headers,hdr0); if ( hdr1 != 0 && hdr1[0] != 0 ) headers = curl_slist_append(headers,hdr1); if ( hdr2 != 0 && hdr2[0] != 0 ) headers = curl_slist_append(headers,hdr2); if ( hdr3 != 0 && hdr3[0] != 0 ) headers = curl_slist_append(headers,hdr3); } //headers = curl_slist_append(0,"Expect:"); if ( headers != 0 ) curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers); //res = curl_easy_perform(cHandle); memset(&chunk,0,sizeof(chunk)); curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback); curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk); curl_easy_perform(cHandle); curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code); if ( headers != 0 ) curl_slist_free_all(headers); if ( code != 200 ) printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory); return(chunk.memory); } char *komodo_issuemethod(char *method,char *params,uint16_t port) { //static void *cHandle; char url[512],*retstr=0,*retstr2=0,postdata[8192]; if ( params == 0 || params[0] == 0 ) params = (char *)"[]"; if ( strlen(params) < sizeof(postdata)-128 ) { sprintf(url,(char *)"http://127.0.0.1:%u",port); sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); //printf("postdata.(%s) USERPASS.(%s)\n",postdata,KMDUSERPASS); retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,KMDUSERPASS,method,params); //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); } return(retstr2); } //curl --url "http://127.0.0.1:13033" --user "user1557335368:pass111720054" --data "{\"method\":\"getinfo\",\"params\":[]}" uint32_t komodo_txtime(uint256 hash) { CTransaction tx; uint256 hashBlock; if (!GetTransaction(hash, tx, #ifndef KOMODO_ZCASH Params().GetConsensus(), #endif hashBlock, true)) { //printf("null GetTransaction\n"); return(tx.nLockTime); } return(0); } void komodo_disconnect(CBlockIndex *pindex,CBlock& block) { //int32_t i; uint256 hash; komodo_init(); //hash = block.GetHash(); //for (i=0; i<32; i++) // printf("%02x",((uint8_t *)&hash)[i]); //printf(" <- disconnect block\n"); //uint256 zero; //printf("disconnect ht.%d\n",pindex->nHeight); //memset(&zero,0,sizeof(zero)); //komodo_stateupdate(-pindex->nHeight,0,0,0,zero,0,0,0,0,0,0,0); } int32_t komodo_block2height(CBlock *block) { int32_t i,n,height = 0; uint8_t *ptr; komodo_init(); #ifdef KOMODO_ZCASH ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data(); #else ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0]; #endif if ( block->vtx[0].vin[0].scriptSig.size() > 5 ) { //for (i=0; i<6; i++) // printf("%02x",ptr[i]); n = ptr[0]; for (i=0; ivtx[0].vin[0].scriptSig.size(),height); } return(height); } void komodo_block2pubkey33(uint8_t *pubkey33,CBlock& block) { #ifdef KOMODO_ZCASH uint8_t *ptr = (uint8_t *)block.vtx[0].vout[0].scriptPubKey.data(); #else uint8_t *ptr = (uint8_t *)&block.vtx[0].vout[0].scriptPubKey[0]; #endif komodo_init(); memcpy(pubkey33,ptr+1,33); } void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height) { CBlock block; komodo_init(); memset(pubkey33,0,33); if ( pindex != 0 ) { if ( ReadBlockFromDisk(block,(const CBlockIndex *)pindex #ifndef KOMODO_ZCASH ,Params().GetConsensus() #endif ) != 0 ) { komodo_block2pubkey33(pubkey33,block); } } else { // height -> pubkey33 //printf("extending chaintip komodo_index2pubkey33 height.%d need to get pubkey33\n",height); } } int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash) { int32_t notarized_height; uint256 notarized_hash,notarized_desttxid; CBlockIndex *notary; notarized_height = komodo_notarizeddata(chainActive.Tip()->nHeight,¬arized_hash,¬arized_desttxid); *notarized_heightp = notarized_height; if ( notarized_height >= 0 && notarized_height <= chainActive.Tip()->nHeight && (notary= mapBlockIndex[notarized_hash]) != 0 ) { //printf("nHeight.%d -> (%d %s)\n",chainActive.Tip()->nHeight,notarized_height,notarized_hash.ToString().c_str()); if ( notary->nHeight == notarized_height ) // if notarized_hash not in chain, reorg { if ( nHeight < notarized_height ) { fprintf(stderr,"nHeight.%d < NOTARIZED_HEIGHT.%d\n",nHeight,notarized_height); return(-1); } else if ( nHeight == notarized_height && memcmp(&hash,¬arized_hash,sizeof(hash)) != 0 ) { fprintf(stderr,"nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",nHeight,notarized_height); return(-1); } } else fprintf(stderr,"unexpected error notary_hash %s ht.%d at ht.%d\n",notarized_hash.ToString().c_str(),notarized_height,notary->nHeight); } else if ( notarized_height > 0 ) fprintf(stderr,"couldnt find notary_hash %s ht.%d\n",notarized_hash.ToString().c_str(),notarized_height); return(0); }