/****************************************************************************** * Copyright © 2014-2017 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 #include "komodo_defs.h" int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp); //#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr)) 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 *userpass,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("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS); retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); } return(retstr2); } int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp) { char *jsonstr,params[256],*userpass; uint16_t port; cJSON *json,*item; int32_t height = 0,txid_height = 0,txid_confirmations = 0; params[0] = 0; *kmdnotarized_heightp = 0; if ( strcmp(dest,"KMD") == 0 ) { port = KMD_PORT; userpass = KMDUSERPASS; } else if ( strcmp(dest,"BTC") == 0 ) { port = 8332; userpass = BTCUSERPASS; } else return(0); if ( userpass[0] != 0 ) { if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getinfo",params,port)) != 0 ) { //printf("(%s)\n",jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { if ( (item= jobj(json,(char *)"result")) != 0 ) { height = jint(item,(char *)"blocks"); *kmdnotarized_heightp = strcmp(dest,"KMD") == 0 ? jint(item,(char *)"notarized") : height; } free_json(json); } free(jsonstr); } sprintf(params,"[\"%s\", 1]",txidstr); if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getrawtransaction",params,port)) != 0 ) { //printf("(%s)\n",jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { if ( (item= jobj(json,(char *)"result")) != 0 ) { txid_confirmations = jint(item,(char *)"confirmations"); if ( txid_confirmations > 0 && height > txid_confirmations ) txid_height = height - txid_confirmations; else txid_height = height; //printf("height.%d tconfs.%d txid_height.%d\n",height,txid_confirmations,txid_height); } free_json(json); } free(jsonstr); } } return(txid_height); } int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH) { int32_t i; uint256 hash; char params[256]; for (i=0; i<32; i++) ((uint8_t *)&hash)[i] = script[2+i]; if ( hash == NOTARIZED_HASH ) return(0); for (i=0; i<32; i++) printf("%02x",((uint8_t *)&NOTARIZED_HASH)[i]); printf(" notarized, "); for (i=0; i<32; i++) printf("%02x",((uint8_t *)&hash)[i]); printf(" opreturn from [%s] ht.%d MISMATCHED\n",ASSETCHAINS_SYMBOL,height); return(-1); } int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID) { char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey; script = _script; /*params[0] = '['; params[1] = '"'; for (i=0; i<32; i++) sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]); strcat(params,"\", 1]");*/ sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str()); if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 ) return(0); if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",ASSETCHAINS_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT); if ( strcmp(dest,"KMD") == 0 ) { if ( KMDUSERPASS[0] != 0 ) { if ( ASSETCHAINS_SYMBOL[0] != 0 ) { jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT); //printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr); } }//else jsonstr = _dex_getrawtransaction(); else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok } else if ( strcmp(dest,"BTC") == 0 ) { if ( BTCUSERPASS[0] != 0 ) { //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS); jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332); } //else jsonstr = _dex_getrawtransaction(); else return(0); } else { printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest); return(-1); } if ( jsonstr != 0 ) { if ( (json= cJSON_Parse(jsonstr)) != 0 ) { if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 ) { vout = jitem(vouts,n-1); if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) printf("vout.(%s)\n",jprint(vout,0)); if ( (skey= jobj(vout,(char *)"scriptPubKey")) != 0 ) { if ( (hexstr= jstr(skey,(char *)"hex")) != 0 ) { //printf("HEX.(%s) vs hash.%s\n",hexstr,NOTARIZED_HASH.ToString().c_str()); len = strlen(hexstr) >> 1; decode_hex(script,len,hexstr); if ( script[1] == 0x4c ) { script++; len--; } else if ( script[1] == 0x4d ) { script += 2; len -= 2; } retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH); } } } free_json(txjson); } free(jsonstr); } return(retval); } /*uint256 komodo_getblockhash(int32_t height) { uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32]; memset(&hash,0,sizeof(hash)); sprintf(params,"[%d]",height); if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_PORT)) != 0 ) { if ( (result= cJSON_Parse(jsonstr)) != 0 ) { if ( (hexstr= jstr(result,(char *)"result")) != 0 ) { if ( is_hexstr(hexstr,0) == 64 ) { decode_hex(revbuf,32,hexstr); for (i=0; i<32; i++) ((uint8_t *)&hash)[i] = revbuf[31-i]; } } free_json(result); } printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash); free(jsonstr); } return(hash); } uint256 _komodo_getblockhash(int32_t height);*/ uint64_t komodo_seed(int32_t height) { uint64_t seed = 0; /*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds... { uint256 hash,zero; CBlockIndex *pindex; memset(&hash,0,sizeof(hash)); memset(&zero,0,sizeof(zero)); if ( height > 10 ) height -= 10; if ( ASSETCHAINS_SYMBOL[0] == 0 ) hash = _komodo_getblockhash(height); if ( memcmp(&hash,&zero,sizeof(hash)) == 0 ) hash = komodo_getblockhash(height); int32_t i; for (i=0; i<32; i++) printf("%02x",((uint8_t *)&hash)[i]); printf(" seed.%d\n",height); seed = arith_uint256(hash.GetHex()).GetLow64(); } else*/ { seed = (height << 13) ^ (height << 2); seed <<= 21; seed |= (height & 0xffffffff); seed ^= (seed << 17) ^ (seed << 1); } return(seed); } 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) { char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; //fprintf(stderr,"disconnect ht.%d\n",pindex->nHeight); komodo_init(pindex->nHeight); if ( (sp= komodo_stateptr(symbol,dest)) != 0 ) { //sp->rewinding = pindex->nHeight; //fprintf(stderr,"-%d ",pindex->nHeight); } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->nHeight,ASSETCHAINS_SYMBOL); } int32_t komodo_is_notarytx(const CTransaction& tx) { uint8_t *ptr; static uint8_t crypto777[33]; if ( tx.vout.size() > 0 ) { #ifdef KOMODO_ZCASH ptr = (uint8_t *)tx.vout[0].scriptPubKey.data(); #else ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0]; #endif if ( ptr != 0 ) { if ( crypto777[0] == 0 ) decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR); if ( memcmp(ptr+1,crypto777,33) == 0 ) { //printf("found notarytx\n"); return(1); } } } return(0); } int32_t komodo_block2height(CBlock *block) { int32_t i,n,height = 0; uint8_t *ptr; if ( block->vtx[0].vin.size() > 0 ) { #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 ( ptr != 0 && 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); } //komodo_init(height); } return(height); } void komodo_block2pubkey33(uint8_t *pubkey33,CBlock& block) { int32_t n; memset(pubkey33,0,33); if ( block.vtx[0].vout.size() > 0 ) { #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(0); n = block.vtx[0].vout[0].scriptPubKey.size(); if ( n == 35 ) memcpy(pubkey33,ptr+1,33); } } int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex) { block.SetNull(); // Open history file to read CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION); if (filein.IsNull()) return(-1); // Read block try { filein >> block; } catch (const std::exception& e) { fprintf(stderr,"readblockfromdisk err B\n"); return(-1); } return(0); } uint32_t komodo_chainactive_timestamp() { if ( chainActive.Tip() != 0 ) return((uint32_t)chainActive.Tip()->GetBlockTime()); else return(0); } CBlockIndex *komodo_chainactive(int32_t height) { if ( chainActive.Tip() != 0 ) { if ( height <= chainActive.Tip()->nHeight ) return(chainActive[height]); // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.Tip()->nHeight); } //fprintf(stderr,"komodo_chainactive null chainActive.Tip() height %d\n",height); return(0); } uint32_t komodo_heightstamp(int32_t height) { CBlockIndex *ptr; if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 ) return(ptr->nTime); //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height); return(0); } void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height) { CBlock block; int32_t num,i; uint8_t pubkeys[64][33]; //komodo_init(height); memset(pubkey33,0,33); if ( pindex != 0 ) { if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 ) { memcpy(pubkey33,pindex->pubkey33,33); return; } if ( komodo_blockload(block,pindex) == 0 ) { komodo_block2pubkey33(pubkey33,block); if ( pubkey33[0] == 2 || pubkey33[0] == 3 ) { memcpy(pindex->pubkey33,pubkey33,33); if ( (num= komodo_notaries(pubkeys,(int32_t)pindex->nHeight,(uint32_t)pindex->nTime)) > 0 ) { pindex->notaryid = -1; for (i=0; inotaryid = i; break; } } } } else pindex->notaryid = -1; } } else { // height -> pubkey33 //printf("extending chaintip komodo_index2pubkey33 height.%d need to get pubkey33\n",height); } } /*void komodo_connectpindex(CBlockIndex *pindex) { CBlock block; if ( komodo_blockload(block,pindex) == 0 ) komodo_connectblock(pindex,block); }*/ int8_t komodo_minerid(int32_t height,uint8_t *pubkey33) { int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t _pubkey33[33],pubkeys[64][33]; if ( (pindex= chainActive[height]) != 0 ) { timestamp = pindex->GetBlockTime(); if ( pubkey33 == 0 ) { pubkey33 = _pubkey33; komodo_index2pubkey33(pubkey33,pindex,height); } if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 ) return(pindex->notaryid); if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 ) { for (i=0; ipubkey33[0] != 0 && (memcmp(pindex->pubkey33,pubkey33,33) != 0 || pindex->notaryid != i) ) printf("mismatched notaryid.%d\n",pindex->notaryid); return(i); } } } return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp)); } int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *nonzpkeysp,int32_t height) { int32_t i,j,duplicate; CBlockIndex *pindex; uint8_t pubkey33[33]; memset(mids,-1,sizeof(*mids)*66); for (i=duplicate=0; i<66; i++) { if ( (pindex= komodo_chainactive(height-i)) != 0 ) { komodo_index2pubkey33(pubkey33,pindex,height-i); memcpy(pubkeys[i],pubkey33,33); if ( (mids[i]= komodo_minerid(height-i,pubkey33)) >= 0 ) { //mids[i] = *(int32_t *)pubkey33; (*nonzpkeysp)++; } if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] ) duplicate++; } } if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) ) return(1); else return(0); } int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) { int32_t i,n=0; for (i=0; i= 225000 ) komodo_chosennotary(¬aryid,height,pubkey33,timestamp); if ( height >= 34000 && notaryid >= 0 ) { if ( height < 79693 ) limit = 64; else if ( height < 82000 ) limit = 8; else limit = 66; for (i=1; i 0 ) fprintf(stderr,"ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid); if ( height > 225000 ) return(-1); } } //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit); return(1); } return(0); } int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight) { int32_t depth,notarized_ht; uint256 MoM,kmdtxid; depth = komodo_MoMdata(¬arized_ht,&MoM,&kmdtxid,nHeight); memset(MoMp,0,sizeof(*MoMp)); memset(kmdtxidp,0,sizeof(*kmdtxidp)); *notarized_heightp = 0; if ( depth > 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht ) { *MoMp = MoM; *notarized_heightp = notarized_ht; *kmdtxidp = kmdtxid; } return(depth); } int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash) { int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary; CBlockIndex *pindex; if ( (pindex= chainActive.Tip()) == 0 ) return(-1); notarized_height = komodo_notarizeddata(pindex->nHeight,¬arized_hash,¬arized_desttxid); *notarized_heightp = notarized_height; if ( notarized_height >= 0 && notarized_height <= pindex->nHeight && (notary= mapBlockIndex[notarized_hash]) != 0 ) { //printf("nHeight.%d -> (%d %s)\n",pindex->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,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height); return(-1); } else if ( nHeight == notarized_height && memcmp(&hash,¬arized_hash,sizeof(hash)) != 0 ) { fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height); return(-1); } } else fprintf(stderr,"[%s] unexpected error notary_hash %s ht.%d at ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,notary->nHeight); } else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 ) fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight); return(0); } uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n) { LOCK(cs_main); CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex; *txheighttimep = *txheightp = *tiptimep = 0; *valuep = 0; if ( !GetTransaction(hash,tx,hashBlock,true) ) return(0); uint32_t locktime = 0; if ( n < tx.vout.size() ) { if ( (pindex= mapBlockIndex[hashBlock]) != 0 && (tipindex= chainActive.Tip()) != 0 ) { *valuep = tx.vout[n].nValue; *txheightp = pindex->nHeight; *txheighttimep = pindex->nTime; *tiptimep = tipindex->nTime; locktime = tx.nLockTime; //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep); } } return(locktime); } uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue) { uint64_t value; uint32_t tiptime,txheighttimep; if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 ) { if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) ) return(komodo_interest(*txheightp,value,*locktimep,tiptime)); //fprintf(stderr,"nValue %llu lock.%u:%u nTime.%u -> %llu\n",(long long)coins.vout[n].nValue,coins.nLockTime,timestamp,pindex->nTime,(long long)interest); else fprintf(stderr,"komodo_accrued_interest value mismatch %llu vs %llu or height mismatch %d vs %d\n",(long long)value,(long long)checkvalue,*txheightp,checkheight); } return(0); } int32_t komodo_isrealtime(int32_t *kmdheightp) { struct komodo_state *sp; CBlockIndex *pindex; if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 ) *kmdheightp = sp->CURRENT_HEIGHT; else *kmdheightp = 0; if ( (pindex= chainActive.Tip()) != 0 && pindex->nHeight >= (int32_t)komodo_longestchain() ) return(1); else return(0); } int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag) { uint32_t cmptime = nTime; if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 ) { if ( txheight > 246748 ) { if ( txheight < 247205 ) cmptime -= 16000; if ( (int64_t)tx.nLockTime < cmptime-3600 ) { if ( tx.nLockTime != 1477258935 || dispflag != 0 ) { fprintf(stderr,"komodo_validate_interest.%d reject.%d [%d] locktime %u cmp2.%u\n",dispflag,txheight,(int32_t)(tx.nLockTime - (cmptime-3600)),(uint32_t)tx.nLockTime,cmptime); } return(-1); } if ( 0 && dispflag != 0 ) fprintf(stderr,"validateinterest.%d accept.%d [%d] locktime %u cmp2.%u\n",dispflag,(int32_t)txheight,(int32_t)(tx.nLockTime - (cmptime-3600)),(int32_t)tx.nLockTime,cmptime); } } return(0); }