1 /******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
4 * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
5 * the top-level directory of this distribution for the individual copyright *
6 * holder information and the developer policies on copyright and licensing. *
8 * Unless otherwise agreed in a custom licensing agreement, no part of the *
9 * SuperNET software, including this file may be copied, modified, propagated *
10 * or distributed except according to the terms contained in the LICENSE file *
12 * Removal or modification of this copyright notice is prohibited. *
14 ******************************************************************************/
16 // komodo functions that interact with bitcoind C++
19 #include <curl/curl.h>
20 #include <curl/easy.h>
22 #include <curl/curl.h>
23 #include <curl/easy.h>
26 #include "komodo_defs.h"
28 int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
29 int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
31 //#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
33 struct MemoryStruct { char *memory; size_t size; };
34 struct return_string { char *ptr; size_t len; };
36 // return data from the server
37 #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
38 #define CURL_GLOBAL_SSL (1<<0)
39 #define CURL_GLOBAL_WIN32 (1<<1)
42 /************************************************************************
44 * Initialize the string handler so that it is thread safe
46 ************************************************************************/
48 void init_string(struct return_string *s)
51 s->ptr = (char *)calloc(1,s->len+1);
54 fprintf(stderr,"init_string malloc() failed\n");
60 /************************************************************************
62 * Use the "writer" to accumulate text until done
64 ************************************************************************/
66 size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s)
68 size_t new_len = s->len + size*nmemb;
69 s->ptr = (char *)realloc(s->ptr,new_len+1);
72 fprintf(stderr, "accumulate realloc() failed\n");
75 memcpy(s->ptr+s->len,ptr,size*nmemb);
76 s->ptr[new_len] = '\0';
81 /************************************************************************
83 * return the current system time in milliseconds
85 ************************************************************************/
87 #define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field
88 #ifdef EXTRACT_BITCOIND_RESULT
90 /************************************************************************
92 * perform post processing of the results
94 ************************************************************************/
96 char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params)
98 long i,j,len; char *retstr = 0; cJSON *json,*result,*error;
99 //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
100 if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 )
102 if ( strcmp(command,"signrawtransaction") != 0 )
103 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
106 json = cJSON_Parse(rpcstr);
109 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params);
113 result = cJSON_GetObjectItem(json,"result");
114 error = cJSON_GetObjectItem(json,"error");
115 if ( error != 0 && result != 0 )
117 if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL )
119 retstr = cJSON_Print(result);
120 len = strlen(retstr);
121 if ( retstr[0] == '"' && retstr[len-1] == '"' )
123 for (i=1,j=0; i<len-1; i++,j++)
124 retstr[j] = retstr[i];
128 else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL )
130 if ( strcmp(command,"signrawtransaction") != 0 )
131 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr);
134 } else retstr = rpcstr;
136 //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr);
141 /************************************************************************
145 ************************************************************************/
147 char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params)
149 static int didinit,count,count2; static double elapsedsum,elapsedsum2;
150 struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle;
151 char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime;
155 curl_global_init(CURL_GLOBAL_ALL); //init the curl session
158 if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 )
160 else specialcase = 0;
162 strcpy(url,"http://127.0.0.1:7876/nxt");
163 if ( specialcase != 0 && 0 )
164 printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params);
168 starttime = OS_milliseconds();
169 curl_handle = curl_easy_init();
171 headers = curl_slist_append(0,"Expect:");
173 curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
174 curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers);
175 curl_easy_setopt(curl_handle,CURLOPT_URL, url);
176 curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function
177 curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback
178 curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash
179 curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback
180 if ( strncmp(url,"https",5) == 0 )
182 curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0);
183 curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0);
186 curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass);
190 if ( command != 0 && specialcase == 0 )
192 len = strlen(params);
193 if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) {
194 bracket0 = bracket1 = (char *)"";
198 bracket0 = (char *)"[";
199 bracket1 = (char *)"]";
202 databuf = (char *)malloc(256 + strlen(command) + strlen(params));
203 sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1);
204 //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf);
206 } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params);
207 curl_easy_setopt(curl_handle,CURLOPT_POST,1L);
209 curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf);
210 else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params);
212 //laststart = milliseconds();
213 res = curl_easy_perform(curl_handle);
214 curl_slist_free_all(headers);
215 curl_easy_cleanup(curl_handle);
216 if ( databuf != 0 ) // clean up temporary buffer
221 if ( res != CURLE_OK )
224 if ( specialcase != 0 )
226 printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res);
230 else if ( numretries >= 1 )
232 //printf("Maximum number of retries exceeded!\n");
236 if ( (rand() % 1000) == 0 )
237 printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries);
239 sleep((1<<numretries));
245 if ( command != 0 && specialcase == 0 )
248 elapsedsum += (OS_milliseconds() - starttime);
249 if ( (count % 1000000) == 0)
250 printf("%d: ave %9.6f | elapsed %.3f millis | bitcoind_RPC.(%s) url.(%s)\n",count,elapsedsum/count,(OS_milliseconds() - starttime),command,url);
256 return(post_process_bitcoind_RPC(debugstr,command,s.ptr,params));
260 if ( 0 && specialcase != 0 )
261 fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: BTCD.(%s) -> (%s)\n",params,s.ptr);
263 elapsedsum2 += (OS_milliseconds() - starttime);
264 if ( (count2 % 10000) == 0)
265 printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command);
269 printf("bitcoind_RPC: impossible case\n");
274 static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data)
276 size_t realsize = (size * nmemb);
277 struct MemoryStruct *mem = (struct MemoryStruct *)data;
278 mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1));
279 if ( mem->memory != 0 )
282 memcpy(&(mem->memory[mem->size]),ptr,realsize);
283 mem->size += realsize;
284 mem->memory[mem->size] = 0;
286 //printf("got %d bytes\n",(int32_t)(size*nmemb));
290 char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3)
292 struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
293 if ( (cHandle= *cHandlep) == NULL )
294 *cHandlep = cHandle = curl_easy_init();
295 else curl_easy_reset(cHandle);
297 //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
299 curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
300 curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0);
301 //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
302 curl_easy_setopt(cHandle,CURLOPT_URL,url);
303 curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
304 if ( userpass != 0 && userpass[0] != 0 )
305 curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
306 if ( postfields != 0 && postfields[0] != 0 )
308 curl_easy_setopt(cHandle,CURLOPT_POST,1);
309 curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
311 if ( hdr0 != NULL && hdr0[0] != 0 )
313 //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:"");
314 headers = curl_slist_append(headers,hdr0);
315 if ( hdr1 != 0 && hdr1[0] != 0 )
316 headers = curl_slist_append(headers,hdr1);
317 if ( hdr2 != 0 && hdr2[0] != 0 )
318 headers = curl_slist_append(headers,hdr2);
319 if ( hdr3 != 0 && hdr3[0] != 0 )
320 headers = curl_slist_append(headers,hdr3);
321 } //headers = curl_slist_append(0,"Expect:");
323 curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers);
324 //res = curl_easy_perform(cHandle);
325 memset(&chunk,0,sizeof(chunk));
326 curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback);
327 curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk);
328 curl_easy_perform(cHandle);
329 curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code);
331 curl_slist_free_all(headers);
333 printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory);
334 return(chunk.memory);
337 char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
339 //static void *cHandle;
340 char url[512],*retstr=0,*retstr2=0,postdata[8192];
341 if ( params == 0 || params[0] == 0 )
342 params = (char *)"[]";
343 if ( strlen(params) < sizeof(postdata)-128 )
345 sprintf(url,(char *)"http://127.0.0.1:%u",port);
346 sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params);
347 //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS);
348 retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params);
349 //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0);
354 int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp)
356 char *jsonstr,params[256],*userpass; uint16_t port; cJSON *json,*item; int32_t height = 0,txid_height = 0,txid_confirmations = 0;
358 *kmdnotarized_heightp = 0;
359 if ( strcmp(dest,"KMD") == 0 )
362 userpass = KMDUSERPASS;
364 else if ( strcmp(dest,"BTC") == 0 )
367 userpass = BTCUSERPASS;
370 if ( userpass[0] != 0 )
372 if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getinfo",params,port)) != 0 )
374 //printf("(%s)\n",jsonstr);
375 if ( (json= cJSON_Parse(jsonstr)) != 0 )
377 if ( (item= jobj(json,(char *)"result")) != 0 )
379 height = jint(item,(char *)"blocks");
380 *kmdnotarized_heightp = strcmp(dest,"KMD") == 0 ? jint(item,(char *)"notarized") : height;
386 sprintf(params,"[\"%s\", 1]",txidstr);
387 if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getrawtransaction",params,port)) != 0 )
389 //printf("(%s)\n",jsonstr);
390 if ( (json= cJSON_Parse(jsonstr)) != 0 )
392 if ( (item= jobj(json,(char *)"result")) != 0 )
394 txid_confirmations = jint(item,(char *)"confirmations");
395 if ( txid_confirmations > 0 && height > txid_confirmations )
396 txid_height = height - txid_confirmations;
397 else txid_height = height;
398 //printf("height.%d tconfs.%d txid_height.%d\n",height,txid_confirmations,txid_height);
408 int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH)
410 int32_t i; uint256 hash; char params[256];
412 ((uint8_t *)&hash)[i] = script[2+i];
413 if ( hash == NOTARIZED_HASH )
416 printf("%02x",((uint8_t *)&NOTARIZED_HASH)[i]);
417 printf(" notarized, ");
419 printf("%02x",((uint8_t *)&hash)[i]);
420 printf(" opreturn from [%s] ht.%d MISMATCHED\n",ASSETCHAINS_SYMBOL,height);
424 int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
426 char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
431 sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
432 strcat(params,"\", 1]");*/
433 sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
434 if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
436 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
437 printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",ASSETCHAINS_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT);
438 if ( strcmp(dest,"KMD") == 0 )
440 if ( KMDUSERPASS[0] != 0 )
442 if ( ASSETCHAINS_SYMBOL[0] != 0 )
444 jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT);
445 //printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr);
447 }//else jsonstr = _dex_getrawtransaction();
448 else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
450 else if ( strcmp(dest,"BTC") == 0 )
452 if ( BTCUSERPASS[0] != 0 )
454 //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS);
455 jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332);
457 //else jsonstr = _dex_getrawtransaction();
462 printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest);
467 if ( (json= cJSON_Parse(jsonstr)) != 0 )
469 if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 )
471 vout = jitem(vouts,n-1);
472 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
473 printf("vout.(%s)\n",jprint(vout,0));
474 if ( (skey= jobj(vout,(char *)"scriptPubKey")) != 0 )
476 if ( (hexstr= jstr(skey,(char *)"hex")) != 0 )
478 //printf("HEX.(%s) vs hash.%s\n",hexstr,NOTARIZED_HASH.ToString().c_str());
479 len = strlen(hexstr) >> 1;
480 decode_hex(script,len,hexstr);
481 if ( script[1] == 0x4c )
486 else if ( script[1] == 0x4d )
491 retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH);
502 /*uint256 komodo_getblockhash(int32_t height)
504 uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
505 memset(&hash,0,sizeof(hash));
506 sprintf(params,"[%d]",height);
507 if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_RPCPORT)) != 0 )
509 if ( (result= cJSON_Parse(jsonstr)) != 0 )
511 if ( (hexstr= jstr(result,(char *)"result")) != 0 )
513 if ( is_hexstr(hexstr,0) == 64 )
515 decode_hex(revbuf,32,hexstr);
517 ((uint8_t *)&hash)[i] = revbuf[31-i];
522 printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
528 uint256 _komodo_getblockhash(int32_t height);*/
530 uint64_t komodo_seed(int32_t height)
533 /*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
535 uint256 hash,zero; CBlockIndex *pindex;
536 memset(&hash,0,sizeof(hash));
537 memset(&zero,0,sizeof(zero));
540 if ( ASSETCHAINS_SYMBOL[0] == 0 )
541 hash = _komodo_getblockhash(height);
542 if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
543 hash = komodo_getblockhash(height);
546 printf("%02x",((uint8_t *)&hash)[i]);
547 printf(" seed.%d\n",height);
548 seed = arith_uint256(hash.GetHex()).GetLow64();
552 seed = (height << 13) ^ (height << 2);
554 seed |= (height & 0xffffffff);
555 seed ^= (seed << 17) ^ (seed << 1);
560 uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
562 CTxDestination address; CTransaction tx; uint256 hashBlock;
564 if (!GetTransaction(hash, tx,
566 Params().GetConsensus(),
570 //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
573 //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
574 if ( n < tx.vout.size() )
576 *valuep = tx.vout[n].nValue;
577 if (ExtractDestination(tx.vout[n].scriptPubKey, address))
578 strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
580 return(tx.nLockTime);
583 uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
585 CTxDestination address; CBlockIndex *pindex; CTransaction tx; uint256 hashBlock; uint32_t txtime = 0;
587 if (!GetTransaction(hash, tx,
589 Params().GetConsensus(),
593 //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
596 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
597 txtime = pindex->nTime;
598 else txtime = tx.nLockTime;
599 //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
600 if ( n < tx.vout.size() )
602 *valuep = tx.vout[n].nValue;
603 if (ExtractDestination(tx.vout[n].scriptPubKey, address))
604 strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
609 int32_t komodo_isPoS(CBlock *pblock)
611 int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
612 if ( ASSETCHAINS_STAKED != 0 )
614 if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 )
616 txid = pblock->vtx[n-1].vin[0].prevout.hash;
617 vout = pblock->vtx[n-1].vin[0].prevout.n;
618 txtime = komodo_txtime(&value,txid,vout,destaddr);
619 if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
621 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
622 if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[n-1].vout[0].nValue == value )
624 //fprintf(stderr,"is PoS block!\n");
633 void komodo_disconnect(CBlockIndex *pindex,CBlock& block)
635 char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
636 //fprintf(stderr,"disconnect ht.%d\n",pindex->nHeight);
637 komodo_init(pindex->nHeight);
638 if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
640 //sp->rewinding = pindex->nHeight;
641 //fprintf(stderr,"-%d ",pindex->nHeight);
642 } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->nHeight,ASSETCHAINS_SYMBOL);
645 int32_t komodo_is_notarytx(const CTransaction& tx)
647 uint8_t *ptr; static uint8_t crypto777[33];
648 if ( tx.vout.size() > 0 )
651 ptr = (uint8_t *)tx.vout[0].scriptPubKey.data();
653 ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0];
657 if ( crypto777[0] == 0 )
658 decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
659 if ( memcmp(ptr+1,crypto777,33) == 0 )
661 //printf("found notarytx\n");
669 int32_t komodo_block2height(CBlock *block)
671 static uint32_t match,mismatch;
672 int32_t i,n,height2=-1,height = 0; uint8_t *ptr; CBlockIndex *pindex;
673 if ( (pindex= mapBlockIndex[block->GetHash()]) != 0 )
675 height2 = (int32_t)pindex->nHeight;
679 if ( block->vtx[0].vin.size() > 0 )
682 ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data();
684 ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
686 if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
688 //for (i=0; i<6; i++)
689 // printf("%02x",ptr[i]);
691 for (i=0; i<n; i++) // looks strange but this works
693 //03bb81000101(bb 187) (81 48001) (00 12288256) <- coinbase.6 ht.12288256
694 height += ((uint32_t)ptr[i+1] << (i*8));
695 //printf("(%02x %x %d) ",ptr[i+1],((uint32_t)ptr[i+1] << (i*8)),height);
697 //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
699 //komodo_init(height);
701 if ( height != height2 )
703 //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch);
711 int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
714 if ( KOMODO_LOADINGBLOCKS == 0 )
715 memset(pubkey33,0xff,33);
716 else memset(pubkey33,0,33);
717 if ( block->vtx[0].vout.size() > 0 )
720 uint8_t *ptr = (uint8_t *)block->vtx[0].vout[0].scriptPubKey.data();
722 uint8_t *ptr = (uint8_t *)&block->vtx[0].vout[0].scriptPubKey[0];
725 n = block->vtx[0].vout[0].scriptPubKey.size();
728 memcpy(pubkey33,ptr+1,33);
735 int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
738 // Open history file to read
739 CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION);
743 try { filein >> block; }
744 catch (const std::exception& e)
746 fprintf(stderr,"readblockfromdisk err B\n");
752 uint32_t komodo_chainactive_timestamp()
754 if ( chainActive.Tip() != 0 )
755 return((uint32_t)chainActive.Tip()->GetBlockTime());
759 CBlockIndex *komodo_chainactive(int32_t height)
761 if ( chainActive.Tip() != 0 )
763 if ( height <= chainActive.Tip()->nHeight )
764 return(chainActive[height]);
765 // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.Tip()->nHeight);
767 //fprintf(stderr,"komodo_chainactive null chainActive.Tip() height %d\n",height);
771 uint32_t komodo_heightstamp(int32_t height)
774 if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
776 //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
780 /*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted
782 int32_t i,num; uint8_t pubkeys[64][33]; CBlock block;
783 if ( pindex->didinit != 0 )
785 //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->nHeight,pindex->notaryid,height);
786 if ( pindex->didinit == 0 )
788 pindex->notaryid = -1;
789 if ( KOMODO_LOADINGBLOCKS == 0 )
790 memset(pindex->pubkey33,0xff,33);
791 else memset(pindex->pubkey33,0,33);
792 if ( komodo_blockload(block,pindex) == 0 )
794 komodo_block2pubkey33(pindex->pubkey33,&block);
795 //for (i=0; i<33; i++)
796 // fprintf(stderr,"%02x",pindex->pubkey33[i]);
797 //fprintf(stderr," set pubkey at height %d/%d\n",pindex->nHeight,height);
798 //if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 )
799 // pindex->didinit = (KOMODO_LOADINGBLOCKS == 0);
800 } // else fprintf(stderr,"error loading block at %d/%d",pindex->nHeight,height);
802 if ( pindex->didinit != 0 && pindex->nHeight >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->nHeight,(uint32_t)pindex->nTime)) > 0 )
804 for (i=0; i<num; i++)
806 if ( memcmp(pubkeys[i],pindex->pubkey33,33) == 0 )
808 pindex->notaryid = i;
815 fprintf(stderr,"%02x",pindex->pubkey33[i]);
816 fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->nHeight,height);
821 void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
823 int32_t num,i; CBlock block;
824 memset(pubkey33,0,33);
827 if ( komodo_blockload(block,pindex) == 0 )
828 komodo_block2pubkey33(pubkey33,&block);
832 /*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33)
834 int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t pubkey33[33],pubkeys[64][33];
835 if ( (pindex= chainActive[height]) != 0 )
837 if ( pindex->didinit != 0 )
839 if ( destpubkey33 != 0 )
840 memcpy(destpubkey33,pindex->pubkey33,33);
841 return(pindex->notaryid);
843 komodo_index2pubkey33(pubkey33,pindex,height);
844 if ( destpubkey33 != 0 )
845 memcpy(destpubkey33,pindex->pubkey33,33);
846 if ( pindex->didinit != 0 )
847 return(pindex->notaryid);
848 timestamp = pindex->GetBlockTime();
849 if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 )
851 for (i=0; i<num; i++)
852 if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
856 fprintf(stderr,"komodo_minerid height.%d null pindex\n",height);
857 return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp));
860 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height)
862 int32_t i,j,n,duplicate; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33];
863 memset(mids,-1,sizeof(*mids)*66);
864 n = komodo_notaries(notarypubs33,height,0);
865 for (i=duplicate=0; i<66; i++)
867 if ( (pindex= komodo_chainactive(height-i)) != 0 )
869 blocktimes[i] = pindex->nTime;
870 if ( komodo_blockload(block,pindex) == 0 )
872 komodo_block2pubkey33(pubkeys[i],&block);
875 if ( memcmp(notarypubs33[j],pubkeys[i],33) == 0 )
882 } else fprintf(stderr,"couldnt load block.%d\n",height);
883 if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
887 if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
892 int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
894 int32_t i,j,n,nonz,numnotaries; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33],pubkey33[33];
895 numnotaries = komodo_notaries(notarypubs33,height,0);
896 for (i=nonz=0; i<width; i++,n++)
900 if ( (pindex= komodo_chainactive(height-width+i+1)) != 0 )
902 if ( komodo_blockload(block,pindex) == 0 )
904 komodo_block2pubkey33(pubkey33,&block);
905 for (j=0; j<numnotaries; j++)
907 if ( memcmp(notarypubs33[j],pubkey33,33) == 0 )
909 minerids[nonz++] = j;
913 if ( j == numnotaries )
914 minerids[nonz++] = j;
915 } else fprintf(stderr,"couldnt load block.%d\n",height);
921 int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],uint32_t blocktimes[66],int32_t height,uint8_t pubkey33[33],uint32_t blocktime)
923 int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33];
924 komodo_chosennotary(¬aryid,height,pubkey33,blocktimes[0]);
925 if ( height >= 82000 )
931 if ( mids[i] == notaryid )
933 if ( height > 792000 )
936 fprintf(stderr,"%d ",mids[j]);
937 fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
942 if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 )
944 if ( height > 807000 )
952 if ( height >= 34000 && notaryid >= 0 )
954 if ( height < 79693 )
956 else if ( height < 82000 )
959 for (i=1; i<limit; i++)
961 komodo_chosennotary(&nid,height-i,pubkey33,blocktimes[i]);
962 if ( nid == notaryid )
964 //for (j=0; j<66; j++)
965 // fprintf(stderr,"%d ",mids[j]);
966 //fprintf(stderr,"ht.%d repeat mids[%d] nid.%d notaryid.%d\n",height-i,i,nid,notaryid);
967 if ( height > 225000 )
971 //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
978 int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip)
980 int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
981 depth = komodo_MoMdata(¬arized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip);
982 memset(MoMp,0,sizeof(*MoMp));
983 memset(kmdtxidp,0,sizeof(*kmdtxidp));
984 *notarized_heightp = 0;
985 if ( depth != 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
988 *notarized_heightp = notarized_ht;
994 int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
996 int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
997 if ( (pindex= chainActive.Tip()) == 0 )
999 notarized_height = komodo_notarizeddata(pindex->nHeight,¬arized_hash,¬arized_desttxid);
1000 *notarized_heightp = notarized_height;
1001 if ( notarized_height >= 0 && notarized_height <= pindex->nHeight && (notary= mapBlockIndex[notarized_hash]) != 0 )
1003 //printf("nHeight.%d -> (%d %s)\n",pindex->Tip()->nHeight,notarized_height,notarized_hash.ToString().c_str());
1004 if ( notary->nHeight == notarized_height ) // if notarized_hash not in chain, reorg
1006 if ( nHeight < notarized_height )
1008 //fprintf(stderr,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1011 else if ( nHeight == notarized_height && memcmp(&hash,¬arized_hash,sizeof(hash)) != 0 )
1013 fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1016 } //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);
1018 //else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
1019 // fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight);
1023 uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
1026 CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
1027 *txheighttimep = *txheightp = *tiptimep = 0;
1029 if ( !GetTransaction(hash,tx,hashBlock,true) )
1031 uint32_t locktime = 0;
1032 if ( n < tx.vout.size() )
1034 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
1036 *valuep = tx.vout[n].nValue;
1037 *txheightp = pindex->nHeight;
1038 *txheighttimep = pindex->nTime;
1039 if ( *tiptimep == 0 && (tipindex= chainActive.Tip()) != 0 )
1040 *tiptimep = (uint32_t)tipindex->nTime;
1041 locktime = tx.nLockTime;
1042 //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
1048 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
1050 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight)
1052 uint64_t value; uint32_t tiptime=0,txheighttimep; CBlockIndex *pindex;
1053 if ( (pindex= chainActive[tipheight]) != 0 )
1054 tiptime = (uint32_t)pindex->nTime;
1055 else fprintf(stderr,"cant find height[%d]\n",tipheight);
1056 if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 )
1058 if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
1059 return(komodo_interest(*txheightp,value,*locktimep,tiptime));
1060 //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);
1061 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);
1066 int32_t komodo_isrealtime(int32_t *kmdheightp)
1068 struct komodo_state *sp; CBlockIndex *pindex;
1069 if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
1070 *kmdheightp = sp->CURRENT_HEIGHT;
1071 else *kmdheightp = 0;
1072 if ( (pindex= chainActive.Tip()) != 0 && pindex->nHeight >= (int32_t)komodo_longestchain() )
1077 int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
1079 if ( KOMODO_REWIND == 0 && (ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED != 0) && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
1081 if ( txheight > 246748 || ASSETCHAINS_STAKED != 0 )
1083 if ( txheight < 247205 && ASSETCHAINS_STAKED == 0 )
1085 if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
1087 if ( tx.nLockTime != 1477258935 && dispflag != 0 )
1089 fprintf(stderr,"komodo_validate_interest.%d reject.%d [%d] locktime %u cmp2.%u\n",dispflag,txheight,(int32_t)(tx.nLockTime - (cmptime-KOMODO_MAXMEMPOOLTIME)),(uint32_t)tx.nLockTime,cmptime);
1093 if ( 0 && dispflag != 0 )
1094 fprintf(stderr,"validateinterest.%d accept.%d [%d] locktime %u cmp2.%u\n",dispflag,(int32_t)txheight,(int32_t)(tx.nLockTime - (cmptime-KOMODO_MAXMEMPOOLTIME)),(int32_t)tx.nLockTime,cmptime);
1101 komodo_checkPOW (fast) is called early in the process and should only refer to data immediately available. it is a filter to prevent bad blocks from going into the local DB. The more blocks we can filter out at this stage, the less junk in the local DB that will just get purged later on.
1103 komodo_checkPOW (slow) is called right before connecting blocks so all prior blocks can be assumed to be there and all checks must pass
1105 commission must be in coinbase.vout[1] and must be >= 10000 sats
1106 PoS stake must be without txfee and in the last tx in the block at vout[0]
1108 //#define KOMODO_POWMINMULT 16
1110 uint64_t komodo_commission(const CBlock *pblock)
1112 int32_t i,j,n=0,txn_count; uint64_t commission,total = 0;
1113 txn_count = pblock->vtx.size();
1114 for (i=0; i<txn_count; i++)
1116 n = pblock->vtx[i].vout.size();
1119 //fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
1120 if ( i != 0 || j != 1 )
1121 total += pblock->vtx[i].vout[j].nValue;
1124 //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN));
1125 commission = ((total * ASSETCHAINS_COMMISSION) / COIN);
1126 if ( commission < 10000 )
1131 uint32_t komodo_segid32(char *coinaddr)
1134 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
1135 return(addrhash.uints[0]);
1138 int8_t komodo_segid(int32_t height)
1140 CTxDestination voutaddress; CBlock block; CBlockIndex *pindex; uint64_t value; uint32_t txtime; char voutaddr[64],destaddr[64]; int32_t txn_count,vout; uint256 txid; int8_t segid = -1;
1141 if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
1143 if ( komodo_blockload(block,pindex) == 0 )
1145 txn_count = block.vtx.size();
1146 if ( txn_count > 1 && block.vtx[txn_count-1].vin.size() == 1 && block.vtx[txn_count-1].vout.size() == 1 )
1148 txid = block.vtx[txn_count-1].vin[0].prevout.hash;
1149 vout = block.vtx[txn_count-1].vin[0].prevout.n;
1150 txtime = komodo_txtime(&value,txid,vout,destaddr);
1151 if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
1153 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
1154 if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
1156 segid = komodo_segid32(voutaddr) & 0x3f;
1158 } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
1165 int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
1167 static uint8_t prevhashbuf[100]; static int32_t prevheight;
1169 if ( height == prevheight && n == 100 )
1170 memcpy(hashbuf,prevhashbuf,100);
1173 memset(hashbuf,0xff,n);
1176 hashbuf[i] = (uint8_t)komodo_segid(height+i);
1177 //fprintf(stderr,"%02x ",hashbuf[i]);
1181 memcpy(prevhashbuf,hashbuf,100);
1182 prevheight = height;
1183 //fprintf(stderr,"prevsegids.%d\n",height+n);
1188 uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr)
1190 bool fNegative,fOverflow; uint8_t hashbuf[256]; char address[64]; bits256 addrhash; arith_uint256 hashval,mindiff,ratio; uint256 hash,pasthash; int32_t diff=0,segid,minage,i,iter=0; uint32_t txtime,winner = 0 ; uint64_t value,coinage;
1191 txtime = komodo_txtime2(&value,txid,vout,address);
1192 if ( validateflag == 0 && blocktime < GetAdjustedTime() )
1193 blocktime = GetAdjustedTime();
1194 if ( blocktime < prevtime+3 )
1195 blocktime = prevtime+3;
1196 if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
1198 //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
1201 if ( value < SATOSHIDEN )
1203 value /= SATOSHIDEN;
1204 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1205 ratio = (mindiff / bnTarget);
1206 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
1208 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
1209 segid = ((nHeight + addrhash.uints[0]) & 0x3f);
1210 komodo_segids(hashbuf,nHeight-101,100);
1211 memcpy(&hashbuf[100],&addrhash,sizeof(addrhash));
1212 memcpy(&hashbuf[100+sizeof(addrhash)],&txid,sizeof(txid));
1213 memcpy(&hashbuf[100+sizeof(addrhash)+sizeof(txid)],&vout,sizeof(vout));
1214 vcalc_sha256(0,(uint8_t *)&hash,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
1215 for (iter=0; iter<3600; iter++)
1217 diff = (iter + blocktime - txtime - minage);
1220 else if ( diff > 3600*24*30 )
1222 //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
1227 if ( blocktime+iter+segid*2 < txtime+minage )
1229 coinage = (value * diff);
1230 hashval = ratio * (UintToArith256(hash) / arith_uint256(coinage+1));
1231 if ( hashval <= bnTarget )
1234 if ( validateflag == 0 )
1237 blocktime += segid * 2;
1241 if ( validateflag != 0 )
1243 /*for (i=31; i>=24; i--)
1244 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1245 fprintf(stderr," vs ");
1246 for (i=31; i>=24; i--)
1247 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1248 fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff);*/
1252 //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
1253 if ( 0 && validateflag != 0 )
1255 for (i=31; i>=24; i--)
1256 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1257 fprintf(stderr," vs ");
1258 for (i=31; i>=24; i--)
1259 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1260 fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d ht.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff,nHeight);
1264 return(blocktime * winner);
1267 arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
1269 CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
1270 *percPoSp = percPoS = 0;
1271 if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
1273 sum = arith_uint256(0);
1275 easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1276 for (i=n=m=0; i<100; i++)
1278 ht = height - 100 + i;
1281 if ( (pindex= komodo_chainactive(ht)) != 0 )
1283 if ( komodo_segid(ht) >= 0 )
1287 if ( ASSETCHAINS_STAKED < 100 )
1288 fprintf(stderr,"0");
1292 if ( ASSETCHAINS_STAKED < 100 )
1293 fprintf(stderr,"1");
1294 sum += UintToArith256(pindex->GetBlockHash());
1298 /*if ( (pindex= komodo_chainactive(ht)) != 0 )
1300 bnTarget.SetCompact(pindex->nBits,&fNegative,&fOverflow);
1301 bnTarget = (bnTarget / arith_uint256(KOMODO_POWMINMULT));
1302 hashval = UintToArith256(pindex->GetBlockHash());
1303 if ( hashval <= bnTarget ) // PoW is never as easy as PoS/16, some PoS will be counted as PoW
1305 if ( ASSETCHAINS_STAKED < 100 )
1306 fprintf(stderr,"1");
1314 if ( ASSETCHAINS_STAKED < 100 )
1315 fprintf(stderr,"0");
1318 if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
1319 fprintf(stderr," %d, ",percPoS);
1322 percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
1323 if ( ASSETCHAINS_STAKED < 100 )
1324 fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
1325 *percPoSp = percPoS;
1326 //target = (target / arith_uint256(KOMODO_POWMINMULT));
1329 ave = (sum / arith_uint256(m));
1332 } else ave = easydiff; //else return(target);
1333 if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
1335 bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
1336 if ( ASSETCHAINS_STAKED < 100 )
1338 for (i=31; i>=24; i--)
1339 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1340 fprintf(stderr," increase diff -> ");
1341 for (i=31; i>=24; i--)
1342 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1343 fprintf(stderr," floor diff ");
1344 for (i=31; i>=24; i--)
1345 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1346 fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1349 else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget
1351 bnTarget = (ave * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc);
1352 if ( bnTarget > easydiff )
1353 bnTarget = easydiff;
1354 else if ( bnTarget < ave ) // overflow
1356 bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1357 if ( bnTarget < ave )
1362 for (i=31; i>=24; i--)
1363 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1364 fprintf(stderr," decrease diff -> ");
1365 for (i=31; i>=24; i--)
1366 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1367 fprintf(stderr," floor diff ");
1368 for (i=31; i>=24; i--)
1369 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1370 fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1373 else bnTarget = ave; // recent ave is perfect
1377 int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget)
1379 CBlockIndex *previndex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,txn_count,eligible=0,isPoS = 0; uint64_t value; CTxDestination voutaddress;
1380 if ( ASSETCHAINS_STAKED == 100 && height <= 10 )
1382 txn_count = pblock->vtx.size();
1383 if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 )
1385 if ( prevtime == 0 )
1387 if ( (previndex= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1388 prevtime = (uint32_t)previndex->nTime;
1390 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1391 vout = pblock->vtx[txn_count-1].vin[0].prevout.n;
1392 if ( prevtime != 0 )
1394 if ( komodo_isPoS(pblock) != 0 )
1395 eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime,(char *)"");
1396 if ( eligible == 0 || eligible > pblock->nTime )
1398 fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime));
1401 if ( slowflag == 0 ) // maybe previous block is not seen yet, do the best approx
1403 if ( komodo_isPoS(pblock) != 0 )
1405 /*txtime = komodo_txtime(&value,txid,vout,destaddr);
1406 if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
1408 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
1409 if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[txn_count-1].vout[0].nValue == value )
1410 isPoS = 1; // close enough for a pre-filter
1411 //else fprintf(stderr,"komodo_is_PoSblock ht.%d (%s) != (%s) or %.8f != %.8f\n",height,destaddr,voutaddr,dstr(value),dstr(pblock->vtx[txn_count-1].vout[0].nValue));
1412 } else fprintf(stderr,"komodo_is_PoSblock ht.%d couldnt extract voutaddress\n",height);*/
1413 } //else return(-1);
1415 //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
1419 int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1421 int64_t checktoshis=0; uint8_t *script;
1422 if ( ASSETCHAINS_COMMISSION != 0 )
1424 checktoshis = komodo_commission(pblock);
1425 if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1427 else if ( checktoshis != 0 )
1429 script = (uint8_t *)pblock->vtx[0].vout[1].scriptPubKey.data();
1430 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1432 if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1434 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1439 return(checktoshis);
1442 bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1444 int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1446 uint256 hash; arith_uint256 bnTarget,bhash; bool fNegative,fOverflow; uint8_t *script,pubkey33[33],pubkeys[64][33]; int32_t i,possible,PoSperc,is_PoSblock=0,n,failed = 0,notaryid = -1; int64_t checktoshis,value; CBlockIndex *pprev;
1447 if ( !CheckEquihashSolution(pblock, Params()) )
1449 fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1452 hash = pblock->GetHash();
1453 bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1454 bhash = UintToArith256(hash);
1455 possible = komodo_block2pubkey33(pubkey33,pblock);
1456 //fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
1459 if ( slowflag != 0 )
1461 if ( (pprev= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1462 height = pprev->nHeight + 1;
1466 if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget )
1469 if ( height > 0 && ASSETCHAINS_SYMBOL[0] == 0 ) // for the fast case
1471 if ( (n= komodo_notaries(pubkeys,height,pblock->nTime)) > 0 )
1474 if ( memcmp(pubkey33,pubkeys[i],33) == 0 )
1481 else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 )
1483 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW )
1485 if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget
1489 if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
1491 if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget)) == 0 )
1493 if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! POSTEST64
1497 if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target
1499 if ( slowflag != 0 )
1500 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1501 if ( bhash > bnTarget )
1503 for (i=31; i>=16; i--)
1504 fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]);
1505 fprintf(stderr," > ");
1506 for (i=31; i>=16; i--)
1507 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1508 fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED);
1512 } else if ( is_PoSblock < 0 )
1515 if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
1519 script = (uint8_t *)pblock->vtx[0].vout[0].scriptPubKey.data();
1520 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1525 if ( komodo_checkcommission(pblock,height) < 0 )
1529 //fprintf(stderr,"komodo_checkPOW possible.%d slowflag.%d ht.%d notaryid.%d failed.%d\n",possible,slowflag,height,notaryid,failed);
1530 if ( failed != 0 && possible == 0 && notaryid < 0 )
1535 int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
1537 int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
1538 n = pblock->vtx.size();
1541 CTransaction vintx,&tx = pblock->vtx[i];
1542 zfunds += (tx.GetJoinSplitValueOut() - tx.GetJoinSplitValueIn());
1543 if ( (m= tx.vin.size()) > 0 )
1549 txid = tx.vin[j].prevout.hash;
1550 vout = tx.vin[j].prevout.n;
1551 if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
1553 fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1556 vinsum += vintx.vout[vout].nValue;
1559 if ( (m= tx.vout.size()) > 0 )
1561 for (j=0; j<m-1; j++)
1562 voutsum += tx.vout[j].nValue;
1563 script = (uint8_t *)tx.vout[j].scriptPubKey.data();
1564 if ( script == 0 || script[0] != 0x6a )
1565 voutsum += tx.vout[j].nValue;
1569 if ( voutsum-vinsum > 100000*SATOSHIDEN || voutsum-vinsum < 0 )
1570 fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
1571 return(voutsum - vinsum);
1574 int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
1576 CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
1577 //fprintf(stderr,"coinsupply %d\n",height);
1579 if ( (pindex= komodo_chainactive(height)) != 0 )
1581 while ( pindex != 0 && pindex->nHeight > 0 )
1583 if ( pindex->newcoins == 0 )
1585 if ( komodo_blockload(block,pindex) == 0 )
1586 pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->nHeight,&block);
1589 fprintf(stderr,"error loading block.%d\n",pindex->nHeight);
1593 supply += pindex->newcoins;
1594 zfunds += pindex->zfunds;
1595 //printf("start ht.%d new %.8f -> supply %.8f\n",pindex->nHeight,dstr(pindex->newcoins),dstr(supply));
1596 pindex = pindex->pprev;