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++
18 #include <curl/curl.h>
19 #include <curl/easy.h>
20 #include "primitives/nonce.h"
21 #include "consensus/params.h"
22 #include "komodo_defs.h"
23 #include "script/standard.h"
25 int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
26 int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
27 unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
29 //#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
31 struct MemoryStruct { char *memory; size_t size; };
32 struct return_string { char *ptr; size_t len; };
34 // return data from the server
35 #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
36 #define CURL_GLOBAL_SSL (1<<0)
37 #define CURL_GLOBAL_WIN32 (1<<1)
40 /************************************************************************
42 * Initialize the string handler so that it is thread safe
44 ************************************************************************/
46 void init_string(struct return_string *s)
49 s->ptr = (char *)calloc(1,s->len+1);
52 fprintf(stderr,"init_string malloc() failed\n");
58 /************************************************************************
60 * Use the "writer" to accumulate text until done
62 ************************************************************************/
64 size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s)
66 size_t new_len = s->len + size*nmemb;
67 s->ptr = (char *)realloc(s->ptr,new_len+1);
70 fprintf(stderr, "accumulate realloc() failed\n");
73 memcpy(s->ptr+s->len,ptr,size*nmemb);
74 s->ptr[new_len] = '\0';
79 /************************************************************************
81 * return the current system time in milliseconds
83 ************************************************************************/
85 #define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field
86 #ifdef EXTRACT_BITCOIND_RESULT
88 /************************************************************************
90 * perform post processing of the results
92 ************************************************************************/
94 char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params)
96 long i,j,len; char *retstr = 0; cJSON *json,*result,*error;
97 //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
98 if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 )
100 if ( strcmp(command,"signrawtransaction") != 0 )
101 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
104 json = cJSON_Parse(rpcstr);
107 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params);
111 result = cJSON_GetObjectItem(json,"result");
112 error = cJSON_GetObjectItem(json,"error");
113 if ( error != 0 && result != 0 )
115 if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL )
117 retstr = cJSON_Print(result);
118 len = strlen(retstr);
119 if ( retstr[0] == '"' && retstr[len-1] == '"' )
121 for (i=1,j=0; i<len-1; i++,j++)
122 retstr[j] = retstr[i];
126 else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL )
128 if ( strcmp(command,"signrawtransaction") != 0 )
129 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr);
132 } else retstr = rpcstr;
134 //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr);
139 /************************************************************************
143 ************************************************************************/
145 char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params)
147 static int didinit,count,count2; static double elapsedsum,elapsedsum2;
148 struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle;
149 char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime;
153 curl_global_init(CURL_GLOBAL_ALL); //init the curl session
156 if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 )
158 else specialcase = 0;
160 strcpy(url,"http://127.0.0.1:7876/nxt");
161 if ( specialcase != 0 && 0 )
162 printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params);
166 starttime = OS_milliseconds();
167 curl_handle = curl_easy_init();
169 headers = curl_slist_append(0,"Expect:");
171 curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
172 curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers);
173 curl_easy_setopt(curl_handle,CURLOPT_URL, url);
174 curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function
175 curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback
176 curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash
177 curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback
178 if ( strncmp(url,"https",5) == 0 )
180 curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0);
181 curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0);
184 curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass);
188 if ( command != 0 && specialcase == 0 )
190 len = strlen(params);
191 if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) {
192 bracket0 = bracket1 = (char *)"";
196 bracket0 = (char *)"[";
197 bracket1 = (char *)"]";
200 databuf = (char *)malloc(256 + strlen(command) + strlen(params));
201 sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1);
202 //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf);
204 } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params);
205 curl_easy_setopt(curl_handle,CURLOPT_POST,1L);
207 curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf);
208 else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params);
210 //laststart = milliseconds();
211 res = curl_easy_perform(curl_handle);
212 curl_slist_free_all(headers);
213 curl_easy_cleanup(curl_handle);
214 if ( databuf != 0 ) // clean up temporary buffer
219 if ( res != CURLE_OK )
222 if ( specialcase != 0 )
224 printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res);
228 else if ( numretries >= 1 )
230 //printf("Maximum number of retries exceeded!\n");
234 if ( (rand() % 1000) == 0 )
235 printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries);
237 sleep((1<<numretries));
243 if ( command != 0 && specialcase == 0 )
246 elapsedsum += (OS_milliseconds() - starttime);
247 if ( (count % 1000000) == 0)
248 printf("%d: ave %9.6f | elapsed %.3f millis | bitcoind_RPC.(%s) url.(%s)\n",count,elapsedsum/count,(OS_milliseconds() - starttime),command,url);
254 return(post_process_bitcoind_RPC(debugstr,command,s.ptr,params));
258 if ( 0 && specialcase != 0 )
259 fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: BTCD.(%s) -> (%s)\n",params,s.ptr);
261 elapsedsum2 += (OS_milliseconds() - starttime);
262 if ( (count2 % 10000) == 0)
263 printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command);
267 printf("bitcoind_RPC: impossible case\n");
272 static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data)
274 size_t realsize = (size * nmemb);
275 struct MemoryStruct *mem = (struct MemoryStruct *)data;
276 mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1));
277 if ( mem->memory != 0 )
280 memcpy(&(mem->memory[mem->size]),ptr,realsize);
281 mem->size += realsize;
282 mem->memory[mem->size] = 0;
284 //printf("got %d bytes\n",(int32_t)(size*nmemb));
288 char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3)
290 struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
291 if ( (cHandle= *cHandlep) == NULL )
292 *cHandlep = cHandle = curl_easy_init();
293 else curl_easy_reset(cHandle);
295 //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
297 curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
298 curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0);
299 //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
300 curl_easy_setopt(cHandle,CURLOPT_URL,url);
301 curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
302 if ( userpass != 0 && userpass[0] != 0 )
303 curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
304 if ( postfields != 0 && postfields[0] != 0 )
306 curl_easy_setopt(cHandle,CURLOPT_POST,1);
307 curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
309 if ( hdr0 != NULL && hdr0[0] != 0 )
311 //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:"");
312 headers = curl_slist_append(headers,hdr0);
313 if ( hdr1 != 0 && hdr1[0] != 0 )
314 headers = curl_slist_append(headers,hdr1);
315 if ( hdr2 != 0 && hdr2[0] != 0 )
316 headers = curl_slist_append(headers,hdr2);
317 if ( hdr3 != 0 && hdr3[0] != 0 )
318 headers = curl_slist_append(headers,hdr3);
319 } //headers = curl_slist_append(0,"Expect:");
321 curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers);
322 //res = curl_easy_perform(cHandle);
323 memset(&chunk,0,sizeof(chunk));
324 curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback);
325 curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk);
326 curl_easy_perform(cHandle);
327 curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code);
329 curl_slist_free_all(headers);
331 printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory);
332 return(chunk.memory);
335 char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
337 //static void *cHandle;
338 char url[512],*retstr=0,*retstr2=0,postdata[8192];
339 if ( params == 0 || params[0] == 0 )
340 params = (char *)"[]";
341 if ( strlen(params) < sizeof(postdata)-128 )
343 sprintf(url,(char *)"http://127.0.0.1:%u",port);
344 sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params);
345 //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS);
346 retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params);
347 //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0);
352 int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp)
354 char *jsonstr,params[256],*userpass; uint16_t port; cJSON *json,*item; int32_t height = 0,txid_height = 0,txid_confirmations = 0;
356 *kmdnotarized_heightp = 0;
357 if ( strcmp(dest,"KMD") == 0 )
360 userpass = KMDUSERPASS;
362 else if ( strcmp(dest,"BTC") == 0 )
365 userpass = BTCUSERPASS;
368 if ( userpass[0] != 0 )
370 if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getinfo",params,port)) != 0 )
372 //printf("(%s)\n",jsonstr);
373 if ( (json= cJSON_Parse(jsonstr)) != 0 )
375 if ( (item= jobj(json,(char *)"result")) != 0 )
377 height = jint(item,(char *)"blocks");
378 *kmdnotarized_heightp = strcmp(dest,"KMD") == 0 ? jint(item,(char *)"notarized") : height;
384 sprintf(params,"[\"%s\", 1]",txidstr);
385 if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getrawtransaction",params,port)) != 0 )
387 //printf("(%s)\n",jsonstr);
388 if ( (json= cJSON_Parse(jsonstr)) != 0 )
390 if ( (item= jobj(json,(char *)"result")) != 0 )
392 txid_confirmations = jint(item,(char *)"confirmations");
393 if ( txid_confirmations > 0 && height > txid_confirmations )
394 txid_height = height - txid_confirmations;
395 else txid_height = height;
396 //printf("height.%d tconfs.%d txid_height.%d\n",height,txid_confirmations,txid_height);
406 int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH)
408 int32_t i; uint256 hash; char params[256];
410 ((uint8_t *)&hash)[i] = script[2+i];
411 if ( hash == NOTARIZED_HASH )
414 printf("%02x",((uint8_t *)&NOTARIZED_HASH)[i]);
415 printf(" notarized, ");
417 printf("%02x",((uint8_t *)&hash)[i]);
418 printf(" opreturn from [%s] ht.%d MISMATCHED\n",ASSETCHAINS_SYMBOL,height);
422 int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
424 char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
429 sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
430 strcat(params,"\", 1]");*/
431 sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
432 if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
434 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
435 printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",ASSETCHAINS_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT);
436 if ( strcmp(dest,"KMD") == 0 )
438 if ( KMDUSERPASS[0] != 0 )
440 if ( ASSETCHAINS_SYMBOL[0] != 0 )
442 jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT);
443 //printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr);
445 }//else jsonstr = _dex_getrawtransaction();
446 else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
448 else if ( strcmp(dest,"BTC") == 0 )
450 if ( BTCUSERPASS[0] != 0 )
452 //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS);
453 jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332);
455 //else jsonstr = _dex_getrawtransaction();
460 printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest);
465 if ( (json= cJSON_Parse(jsonstr)) != 0 )
467 if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 )
469 vout = jitem(vouts,n-1);
470 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
471 printf("vout.(%s)\n",jprint(vout,0));
472 if ( (skey= jobj(vout,(char *)"scriptPubKey")) != 0 )
474 if ( (hexstr= jstr(skey,(char *)"hex")) != 0 )
476 //printf("HEX.(%s) vs hash.%s\n",hexstr,NOTARIZED_HASH.ToString().c_str());
477 len = strlen(hexstr) >> 1;
478 decode_hex(script,len,hexstr);
479 if ( script[1] == 0x4c )
484 else if ( script[1] == 0x4d )
489 retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH);
500 /*uint256 komodo_getblockhash(int32_t height)
502 uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
503 memset(&hash,0,sizeof(hash));
504 sprintf(params,"[%d]",height);
505 if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_RPCPORT)) != 0 )
507 if ( (result= cJSON_Parse(jsonstr)) != 0 )
509 if ( (hexstr= jstr(result,(char *)"result")) != 0 )
511 if ( is_hexstr(hexstr,0) == 64 )
513 decode_hex(revbuf,32,hexstr);
515 ((uint8_t *)&hash)[i] = revbuf[31-i];
520 printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
526 uint256 _komodo_getblockhash(int32_t height);*/
528 uint64_t komodo_seed(int32_t height)
531 /*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
533 uint256 hash,zero; CBlockIndex *pindex;
534 memset(&hash,0,sizeof(hash));
535 memset(&zero,0,sizeof(zero));
538 if ( ASSETCHAINS_SYMBOL[0] == 0 )
539 hash = _komodo_getblockhash(height);
540 if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
541 hash = komodo_getblockhash(height);
544 printf("%02x",((uint8_t *)&hash)[i]);
545 printf(" seed.%d\n",height);
546 seed = arith_uint256(hash.GetHex()).GetLow64();
550 seed = (height << 13) ^ (height << 2);
552 seed |= (height & 0xffffffff);
553 seed ^= (seed << 17) ^ (seed << 1);
558 uint32_t komodo_txtime(uint64_t *valuep,uint256 hash, int32_t n, char *destaddr)
560 CTxDestination address; CTransaction tx; uint256 hashBlock;
562 if (!GetTransaction(hash, tx,
564 Params().GetConsensus(),
568 //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
571 //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
572 if ( n < tx.vout.size() )
574 *valuep = tx.vout[n].nValue;
575 if (ExtractDestination(tx.vout[n].scriptPubKey, address))
576 strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
578 return(tx.nLockTime);
581 uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
583 CTxDestination address; CBlockIndex *pindex; CTransaction tx; uint256 hashBlock; uint32_t txtime = 0;
585 if (!GetTransaction(hash, tx,
587 Params().GetConsensus(),
591 //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
594 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
595 txtime = pindex->nTime;
596 else txtime = tx.nLockTime;
597 //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
598 if ( n < tx.vout.size() )
600 *valuep = tx.vout[n].nValue;
601 if (ExtractDestination(tx.vout[n].scriptPubKey, address))
602 strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
607 int32_t komodo_isPoS(CBlock *pblock)
609 int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
610 if ( ASSETCHAINS_STAKED != 0 )
612 if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 )
614 txid = pblock->vtx[n-1].vin[0].prevout.hash;
615 vout = pblock->vtx[n-1].vin[0].prevout.n;
616 txtime = komodo_txtime(&value,txid,vout,destaddr);
617 if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
619 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
620 if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[n-1].vout[0].nValue == value )
622 //fprintf(stderr,"is PoS block!\n");
631 void komodo_disconnect(CBlockIndex *pindex,CBlock& block)
633 char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
634 //fprintf(stderr,"disconnect ht.%d\n",pindex->GetHeight());
635 komodo_init(pindex->GetHeight());
636 if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
638 //sp->rewinding = pindex->GetHeight();
639 //fprintf(stderr,"-%d ",pindex->GetHeight());
640 } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->GetHeight(),ASSETCHAINS_SYMBOL);
643 int32_t komodo_is_notarytx(const CTransaction& tx)
645 uint8_t *ptr; static uint8_t crypto777[33];
646 if ( tx.vout.size() > 0 )
648 ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0];
651 if ( crypto777[0] == 0 )
652 decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
653 if ( memcmp(ptr+1,crypto777,33) == 0 )
655 //printf("found notarytx\n");
663 int32_t komodo_block2height(CBlock *block)
665 static uint32_t match,mismatch;
666 int32_t i,n,height2=-1,height = 0; uint8_t *ptr; CBlockIndex *pindex;
667 if ( (pindex= mapBlockIndex[block->GetHash()]) != 0 )
669 height2 = (int32_t)pindex->GetHeight();
673 if ( block != 0 && block->vtx[0].vin.size() > 0 )
675 ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
676 if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
678 //for (i=0; i<6; i++)
679 // printf("%02x",ptr[i]);
681 for (i=0; i<n; i++) // looks strange but this works
683 //03bb81000101(bb 187) (81 48001) (00 12288256) <- coinbase.6 ht.12288256
684 height += ((uint32_t)ptr[i+1] << (i*8));
685 //printf("(%02x %x %d) ",ptr[i+1],((uint32_t)ptr[i+1] << (i*8)),height);
687 //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
689 //komodo_init(height);
691 if ( height != height2 )
693 //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch);
701 int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
704 if ( KOMODO_LOADINGBLOCKS == 0 )
705 memset(pubkey33,0xff,33);
706 else memset(pubkey33,0,33);
707 if ( block->vtx[0].vout.size() > 0 )
709 txnouttype whichType;
710 vector<vector<unsigned char>> vch = vector<vector<unsigned char>>();
711 if (Solver(block->vtx[0].vout[0].scriptPubKey, whichType, vch) && whichType == TX_PUBKEY)
713 CPubKey pubKey(vch[0]);
714 if (pubKey.IsValid())
716 memcpy(pubkey33,vch[0].data(),33);
719 else memset(pubkey33,0,33);
721 else memset(pubkey33,0,33);
726 int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
729 // Open history file to read
730 CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION);
734 try { filein >> block; }
735 catch (const std::exception& e)
737 fprintf(stderr,"readblockfromdisk err B\n");
743 uint32_t komodo_chainactive_timestamp()
745 if ( chainActive.LastTip() != 0 )
746 return((uint32_t)chainActive.LastTip()->GetBlockTime());
750 CBlockIndex *komodo_chainactive(int32_t height)
752 if ( chainActive.LastTip() != 0 )
754 if ( height <= chainActive.LastTip()->GetHeight() )
755 return(chainActive[height]);
756 // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.LastTip()->GetHeight());
758 //fprintf(stderr,"komodo_chainactive null chainActive.LastTip() height %d\n",height);
762 uint32_t komodo_heightstamp(int32_t height)
765 if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
767 //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
771 /*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted
773 int32_t i,num; uint8_t pubkeys[64][33]; CBlock block;
774 if ( pindex->didinit != 0 )
776 //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->GetHeight(),pindex->notaryid,height);
777 if ( pindex->didinit == 0 )
779 pindex->notaryid = -1;
780 if ( KOMODO_LOADINGBLOCKS == 0 )
781 memset(pindex->pubkey33,0xff,33);
782 else memset(pindex->pubkey33,0,33);
783 if ( komodo_blockload(block,pindex) == 0 )
785 komodo_block2pubkey33(pindex->pubkey33,&block);
786 //for (i=0; i<33; i++)
787 // fprintf(stderr,"%02x",pindex->pubkey33[i]);
788 //fprintf(stderr," set pubkey at height %d/%d\n",pindex->GetHeight(),height);
789 //if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 )
790 // pindex->didinit = (KOMODO_LOADINGBLOCKS == 0);
791 } // else fprintf(stderr,"error loading block at %d/%d",pindex->GetHeight(),height);
793 if ( pindex->didinit != 0 && pindex->GetHeight() >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->GetHeight(),(uint32_t)pindex->nTime)) > 0 )
795 for (i=0; i<num; i++)
797 if ( memcmp(pubkeys[i],pindex->pubkey33,33) == 0 )
799 pindex->notaryid = i;
806 fprintf(stderr,"%02x",pindex->pubkey33[i]);
807 fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->GetHeight(),height);
812 void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
814 int32_t num,i; CBlock block;
815 memset(pubkey33,0,33);
818 if ( komodo_blockload(block,pindex) == 0 )
819 komodo_block2pubkey33(pubkey33,&block);
823 /*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33)
825 int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t pubkey33[33],pubkeys[64][33];
826 if ( (pindex= chainActive[height]) != 0 )
828 if ( pindex->didinit != 0 )
830 if ( destpubkey33 != 0 )
831 memcpy(destpubkey33,pindex->pubkey33,33);
832 return(pindex->notaryid);
834 komodo_index2pubkey33(pubkey33,pindex,height);
835 if ( destpubkey33 != 0 )
836 memcpy(destpubkey33,pindex->pubkey33,33);
837 if ( pindex->didinit != 0 )
838 return(pindex->notaryid);
839 timestamp = pindex->GetBlockTime();
840 if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 )
842 for (i=0; i<num; i++)
843 if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
847 fprintf(stderr,"komodo_minerid height.%d null pindex\n",height);
848 return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp));
851 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height)
853 int32_t i,j,n,duplicate; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33];
854 memset(mids,-1,sizeof(*mids)*66);
855 n = komodo_notaries(notarypubs33,height,0);
856 for (i=duplicate=0; i<66; i++)
858 if ( (pindex= komodo_chainactive(height-i)) != 0 )
860 blocktimes[i] = pindex->nTime;
861 if ( komodo_blockload(block,pindex) == 0 )
863 komodo_block2pubkey33(pubkeys[i],&block);
866 if ( memcmp(notarypubs33[j],pubkeys[i],33) == 0 )
873 } else fprintf(stderr,"couldnt load block.%d\n",height);
874 if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
878 if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
883 int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
885 int32_t i,j,n,nonz,numnotaries; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33],pubkey33[33];
886 numnotaries = komodo_notaries(notarypubs33,height,0);
887 for (i=nonz=0; i<width; i++,n++)
891 if ( (pindex= komodo_chainactive(height-width+i+1)) != 0 )
893 if ( komodo_blockload(block,pindex) == 0 )
895 komodo_block2pubkey33(pubkey33,&block);
896 for (j=0; j<numnotaries; j++)
898 if ( memcmp(notarypubs33[j],pubkey33,33) == 0 )
900 minerids[nonz++] = j;
904 if ( j == numnotaries )
905 minerids[nonz++] = j;
906 } else fprintf(stderr,"couldnt load block.%d\n",height);
912 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)
914 int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33];
915 komodo_chosennotary(¬aryid,height,pubkey33,blocktimes[0]);
916 if ( height >= 82000 )
922 if ( mids[i] == notaryid )
924 if ( height > 792000 )
927 fprintf(stderr,"%d ",mids[j]);
928 fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
933 if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 )
935 if ( height > 807000 )
943 if ( height >= 34000 && notaryid >= 0 )
945 if ( height < 79693 )
947 else if ( height < 82000 )
950 for (i=1; i<limit; i++)
952 komodo_chosennotary(&nid,height-i,pubkey33,blocktimes[i]);
953 if ( nid == notaryid )
955 //for (j=0; j<66; j++)
956 // fprintf(stderr,"%d ",mids[j]);
957 //fprintf(stderr,"ht.%d repeat mids[%d] nid.%d notaryid.%d\n",height-i,i,nid,notaryid);
958 if ( height > 225000 )
962 //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
969 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)
971 int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
972 depth = komodo_MoMdata(¬arized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip);
973 memset(MoMp,0,sizeof(*MoMp));
974 memset(kmdtxidp,0,sizeof(*kmdtxidp));
975 *notarized_heightp = 0;
976 if ( depth != 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
979 *notarized_heightp = notarized_ht;
985 int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
987 int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
988 if ( (pindex= chainActive.LastTip()) == 0 )
990 notarized_height = komodo_notarizeddata(pindex->GetHeight(),¬arized_hash,¬arized_desttxid);
991 *notarized_heightp = notarized_height;
992 if ( notarized_height >= 0 && notarized_height <= pindex->GetHeight() && (notary= mapBlockIndex[notarized_hash]) != 0 )
994 //printf("nHeight.%d -> (%d %s)\n",pindex->Tip()->GetHeight(),notarized_height,notarized_hash.ToString().c_str());
995 if ( notary->GetHeight() == notarized_height ) // if notarized_hash not in chain, reorg
997 if ( nHeight < notarized_height )
999 //fprintf(stderr,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1002 else if ( nHeight == notarized_height && memcmp(&hash,¬arized_hash,sizeof(hash)) != 0 )
1004 fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1007 } //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->GetHeight());
1009 //else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
1010 // fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->GetHeight());
1014 uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
1017 CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
1018 *txheighttimep = *txheightp = *tiptimep = 0;
1020 if ( !GetTransaction(hash,tx,hashBlock,true) )
1022 uint32_t locktime = 0;
1023 if ( n < tx.vout.size() )
1025 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
1027 *valuep = tx.vout[n].nValue;
1028 *txheightp = pindex->GetHeight();
1029 *txheighttimep = pindex->nTime;
1030 if ( *tiptimep == 0 && (tipindex= chainActive.LastTip()) != 0 )
1031 *tiptimep = (uint32_t)tipindex->nTime;
1032 locktime = tx.nLockTime;
1033 //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
1039 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
1041 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)
1043 uint64_t value; uint32_t tiptime=0,txheighttimep; CBlockIndex *pindex;
1044 if ( (pindex= chainActive[tipheight]) != 0 )
1045 tiptime = (uint32_t)pindex->nTime;
1046 else fprintf(stderr,"cant find height[%d]\n",tipheight);
1047 if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 )
1049 if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
1050 return(komodo_interest(*txheightp,value,*locktimep,tiptime));
1051 //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);
1052 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);
1057 int32_t komodo_isrealtime(int32_t *kmdheightp)
1059 struct komodo_state *sp; CBlockIndex *pindex;
1060 if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
1061 *kmdheightp = sp->CURRENT_HEIGHT;
1062 else *kmdheightp = 0;
1063 if ( (pindex= chainActive.LastTip()) != 0 && pindex->GetHeight() >= (int32_t)komodo_longestchain() )
1068 int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
1070 if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
1072 if ( txheight > 246748 )
1074 if ( txheight < 247205 )
1076 if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
1078 if ( tx.nLockTime != 1477258935 && dispflag != 0 )
1080 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);
1084 if ( 0 && dispflag != 0 )
1085 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);
1092 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.
1094 komodo_checkPOW (slow) is called right before connecting blocks so all prior blocks can be assumed to be there and all checks must pass
1096 commission must be in coinbase.vout[1] and must be >= 10000 sats
1097 PoS stake must be without txfee and in the last tx in the block at vout[0]
1100 uint64_t komodo_commission(const CBlock *pblock)
1102 int32_t i,j,n=0,txn_count; uint64_t commission,total = 0;
1103 txn_count = pblock->vtx.size();
1104 for (i=0; i<txn_count; i++)
1106 n = pblock->vtx[i].vout.size();
1109 //fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
1110 if ( i != 0 || j != 1 )
1111 total += pblock->vtx[i].vout[j].nValue;
1114 //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN));
1115 commission = ((total * ASSETCHAINS_COMMISSION) / COIN);
1116 if ( commission < 10000 )
1121 uint32_t komodo_segid32(char *coinaddr)
1124 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
1125 return(addrhash.uints[0]);
1128 int8_t komodo_segid(int32_t nocache,int32_t height)
1130 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;
1131 if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
1133 if ( nocache == 0 && pindex->segid >= -1 )
1134 return(pindex->segid);
1135 if ( komodo_blockload(block,pindex) == 0 )
1137 txn_count = block.vtx.size();
1138 if ( txn_count > 1 && block.vtx[txn_count-1].vin.size() == 1 && block.vtx[txn_count-1].vout.size() == 1 )
1140 txid = block.vtx[txn_count-1].vin[0].prevout.hash;
1141 vout = block.vtx[txn_count-1].vin[0].prevout.n;
1142 txtime = komodo_txtime(&value,txid,vout,destaddr);
1143 if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
1145 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
1146 if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
1148 segid = komodo_segid32(voutaddr) & 0x3f;
1149 //fprintf(stderr,"komodo_segid.(%d) -> %02x\n",height,segid);
1151 } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
1158 int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
1160 static uint8_t prevhashbuf[100]; static int32_t prevheight;
1162 if ( height == prevheight && n == 100 )
1163 memcpy(hashbuf,prevhashbuf,100);
1166 memset(hashbuf,0xff,n);
1169 hashbuf[i] = (uint8_t)komodo_segid(1,height+i);
1170 //fprintf(stderr,"%02x ",hashbuf[i]);
1174 memcpy(prevhashbuf,hashbuf,100);
1175 prevheight = height;
1176 //fprintf(stderr,"prevsegids.%d\n",height+n);
1181 uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout)
1184 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
1185 memcpy(&hashbuf[100],&addrhash,sizeof(addrhash));
1186 memcpy(&hashbuf[100+sizeof(addrhash)],&txid,sizeof(txid));
1187 memcpy(&hashbuf[100+sizeof(addrhash)+sizeof(txid)],&vout,sizeof(vout));
1188 vcalc_sha256(0,(uint8_t *)hashp,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
1189 return(addrhash.uints[0]);
1192 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)
1194 bool fNegative,fOverflow; uint8_t hashbuf[256]; char address[64]; bits256 addrhash; arith_uint256 hashval,mindiff,ratio,coinage256; uint256 hash,pasthash; int32_t diff=0,segid,minage,i,iter=0; uint32_t txtime,segid32,winner = 0 ; uint64_t value,coinage;
1195 txtime = komodo_txtime2(&value,txid,vout,address);
1196 if ( validateflag == 0 )
1198 //fprintf(stderr,"blocktime.%u -> ",blocktime);
1199 if ( blocktime < prevtime+3 )
1200 blocktime = prevtime+3;
1201 if ( blocktime < GetAdjustedTime()-60 )
1202 blocktime = GetAdjustedTime()+30;
1203 //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime);
1205 if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
1207 //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
1210 if ( value < SATOSHIDEN )
1212 value /= SATOSHIDEN;
1213 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1214 ratio = (mindiff / bnTarget);
1215 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
1217 komodo_segids(hashbuf,nHeight-101,100);
1218 segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
1219 segid = ((nHeight + segid32) & 0x3f);
1220 for (iter=0; iter<600; iter++)
1222 if ( blocktime+iter+segid*2 < txtime+minage )
1224 diff = (iter + blocktime - txtime - minage);
1227 else if ( diff > 3600*24*30 )
1229 //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
1234 coinage = (value * diff);
1235 if ( blocktime+iter+segid*2 > prevtime+480 )
1236 coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
1237 coinage256 = arith_uint256(coinage+1);
1238 hashval = ratio * (UintToArith256(hash) / coinage256);
1239 if ( hashval <= bnTarget )
1242 if ( validateflag == 0 )
1244 //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid);
1246 blocktime += segid * 2;
1250 if ( validateflag != 0 )
1252 /*for (i=31; i>=24; i--)
1253 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1254 fprintf(stderr," vs ");
1255 for (i=31; i>=24; i--)
1256 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1257 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);*/
1261 //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
1262 if ( 0 && validateflag != 0 )
1264 for (i=31; i>=24; i--)
1265 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1266 fprintf(stderr," vs ");
1267 for (i=31; i>=24; i--)
1268 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1269 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);
1273 return(blocktime * winner);
1276 arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
1278 int32_t oldflag = 0;
1279 CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
1280 *percPoSp = percPoS = 0;
1281 if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
1283 sum = arith_uint256(0);
1285 easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1286 for (i=n=m=0; i<100; i++)
1288 ht = height - 100 + i;
1291 if ( (pindex= komodo_chainactive(ht)) != 0 )
1293 if ( komodo_segid(0,ht) >= 0 )
1297 if ( ASSETCHAINS_STAKED < 100 )
1298 fprintf(stderr,"0");
1302 if ( ASSETCHAINS_STAKED < 100 )
1303 fprintf(stderr,"1");
1304 sum += UintToArith256(pindex->GetBlockHash());
1308 if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
1309 fprintf(stderr," %d, ",percPoS);
1312 percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
1313 if ( ASSETCHAINS_STAKED < 100 )
1314 fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
1315 *percPoSp = percPoS;
1318 ave = (sum / arith_uint256(m));
1321 } else ave = target; //easydiff; //else return(target);
1324 if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
1326 //if ( oldflag != 0 )
1327 // bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
1329 bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
1330 else bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
1331 if ( ASSETCHAINS_STAKED < 100 )
1333 for (i=31; i>=24; i--)
1334 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1335 fprintf(stderr," increase diff -> ");
1336 for (i=31; i>=24; i--)
1337 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1338 fprintf(stderr," floor diff ");
1339 for (i=31; i>=24; i--)
1340 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1341 fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1344 else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget
1348 bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1349 //bnTarget = (bnTarget * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc);
1350 bnTarget = (bnTarget / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
1352 else bnTarget = (ave / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
1353 if ( bnTarget > easydiff )
1354 bnTarget = easydiff;
1355 else if ( bnTarget < ave ) // overflow
1357 bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1358 if ( bnTarget < ave )
1363 for (i=31; i>=24; i--)
1364 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1365 fprintf(stderr," decrease diff -> ");
1366 for (i=31; i>=24; i--)
1367 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1368 fprintf(stderr," floor diff ");
1369 for (i=31; i>=24; i--)
1370 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1371 fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1374 else bnTarget = ave; // recent ave is perfect
1378 int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget,arith_uint256 bhash)
1380 CBlockIndex *previndex,*pindex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,PoSperc,txn_count,eligible=0,isPoS = 0,segid; uint64_t value; CTxDestination voutaddress;
1381 if ( ASSETCHAINS_STAKED == 100 && height <= 10 )
1383 pindex = mapBlockIndex[pblock->GetHash()];
1384 if ( pindex != 0 && pindex->segid >= -1 )
1386 if ( pindex->segid == -1 )
1390 txn_count = pblock->vtx.size();
1391 if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 )
1393 if ( prevtime == 0 )
1395 if ( (previndex= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1396 prevtime = (uint32_t)previndex->nTime;
1398 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1399 vout = pblock->vtx[txn_count-1].vin[0].prevout.n;
1400 if ( prevtime != 0 )
1402 if ( komodo_isPoS(pblock) != 0 )
1404 eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"");
1406 if ( eligible == 0 || eligible > pblock->nTime )
1408 if ( 0 && ASSETCHAINS_STAKED < 100 )
1409 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));
1410 if ( slowflag != 0 && pindex != 0 )
1413 fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
1418 isPoS = 2; // 2 means staking utxo validated
1419 if ( slowflag != 0 && height > 100 )
1422 if ( pindex != 0 && pindex->segid == -2 && (segid= komodo_segid(1,height)) >= 0 )
1424 pindex->segid = segid;
1425 fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid);
1426 } //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid);
1430 if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx
1432 if ( komodo_isPoS(pblock) != 0 )
1435 if ( slowflag != 0 && isPoS != 0 )
1439 fprintf(stderr,"ht.%d isPoS.%d utxo not validated -> must be PoW fake\n",height,isPoS);
1444 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1445 if ( bhash < bnTarget )
1447 fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height);
1454 //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
1458 bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
1459 bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating);
1461 // for now, we will ignore slowFlag in the interest of keeping success/fail simpler for security purposes
1462 bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
1464 CBlockIndex *pastBlockIndex;
1465 uint256 txid, blkHash;
1470 CTxDestination voutaddress, destaddress, cbaddress;
1471 arith_uint256 target, hash;
1474 if (!pblock->IsVerusPOSBlock())
1476 printf("%s, height %d not POS block\n", pblock->nNonce.GetHex().c_str(), height);
1477 //pblock->nNonce.SetPOSTarget(pblock->nNonce.GetPOSTarget());
1478 //printf("%s after setting POS target\n", pblock->nNonce.GetHex().c_str());
1482 char voutaddr[64], destaddr[64], cbaddr[64];
1484 txn_count = pblock->vtx.size();
1486 if ( txn_count > 1 )
1488 target.SetCompact(pblock->GetVerusPOSTarget());
1489 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1490 voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
1491 value = pblock->vtx[txn_count-1].vout[0].nValue;
1494 bool validHash = true;
1495 bool enablePOSNonce = CPOSNonce::NewPOSActive(height);
1496 bool newPOSEnforcement = enablePOSNonce && (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= height);
1498 arith_uint256 posHash;
1499 if (newPOSEnforcement)
1501 validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1502 posHash = UintToArith256(rawHash) / value;
1503 if (!validHash || posHash > target)
1506 printf("ERROR: invalid nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1507 pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1509 for (int i = 0; validHash && i < pblock->vtx[0].vout.size(); i++)
1511 if (!ValidateMatchingStake(pblock->vtx[0], i, pblock->vtx[txn_count-1], validHash))
1517 // make sure prev block hash and block height are correct
1519 if (validHash = GetStakeParams(pblock->vtx[txn_count-1], p))
1521 if (p.prevHash != pblock->hashPrevBlock || p.blkHeight != height)
1523 printf("ERROR: invalid block data for stake tx\nblkHash: %s\ntxBlkHash: %s\nblkHeight: %d\ntxBlkHeight: %d\n",
1524 pblock->hashPrevBlock.GetHex().c_str(), p.prevHash.GetHex().c_str(), height, p.blkHeight);
1537 else if (!(pastBlockIndex = komodo_chainactive(height - 100)))
1539 fprintf(stderr,"ERROR: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str());
1542 #ifndef KOMODO_ZCASH
1543 if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
1545 if (!GetTransaction(txid, tx, blkHash, true))
1548 fprintf(stderr,"ERROR: invalid PoS block %s - no source transaction\n",blkHash.ToString().c_str());
1552 CBlockHeader bh = pastBlockIndex->GetBlockHeader();
1553 uint256 pastHash = bh.GetVerusEntropyHash(height - 100);
1555 // if height is over when Nonce is required to be the new format, we check that the new format is correct
1556 // if over when we have the new POS hash function, we validate that as well
1557 // they are 100 blocks apart
1558 CPOSNonce nonce = pblock->nNonce;
1560 //printf("before nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
1561 //validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1562 //hash = UintToArith256(rawHash) / tx.vout[voutNum].nValue;
1563 //printf("Raw POShash: %s\n", hash.GetHex().c_str());
1565 hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
1567 //printf("after nNonce: %s, height: %d\n", nonce.GetHex().c_str(), height);
1568 //printf("POShash: %s\n\n", hash.GetHex().c_str());
1570 if ((!newPOSEnforcement || posHash == hash) && hash <= target)
1572 if ((mapBlockIndex.count(blkHash) == 0) ||
1573 !(pastBlockIndex = mapBlockIndex[blkHash]) ||
1574 (height - pastBlockIndex->GetHeight()) < VERUS_MIN_STAKEAGE)
1576 fprintf(stderr,"ERROR: invalid PoS block %s - stake transaction too new\n",blkHash.ToString().c_str());
1580 // make sure we have the right target
1581 CBlockIndex *previndex;
1582 if (!(previndex = mapBlockIndex[pblock->hashPrevBlock]))
1584 fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
1588 arith_uint256 cTarget;
1589 uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
1590 cTarget.SetCompact(nBits);
1591 bool nonceOK = true;
1593 // check to see how many fail
1594 //if (nonce != pblock->nNonce)
1595 // printf("Mismatched nNonce: %s\nblkHash: %s, height: %d\n", nonce.GetHex().c_str(), pblock->GetHash().GetHex().c_str(), height);
1597 if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum))
1599 fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
1604 if (cTarget != target)
1606 fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
1610 if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) &&
1611 ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
1612 CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
1614 strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
1615 strcpy(destaddr, CBitcoinAddress(destaddress).ToString().c_str());
1616 strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
1617 if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
1623 fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n",blkHash.ToString().c_str());
1631 printf("ERROR: malformed nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1632 pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1641 int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1643 int64_t checktoshis=0; uint8_t *script;
1644 if ( ASSETCHAINS_COMMISSION != 0 )
1646 checktoshis = komodo_commission(pblock);
1647 if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1649 else if ( checktoshis != 0 )
1651 script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
1652 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1654 if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1656 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1661 return(checktoshis);
1664 bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1666 int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1668 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;
1669 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
1670 KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
1671 if ( !CheckEquihashSolution(pblock, Params()) )
1673 fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1676 hash = pblock->GetHash();
1677 bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1678 bhash = UintToArith256(hash);
1679 possible = komodo_block2pubkey33(pubkey33,pblock);
1682 if ( slowflag != 0 )
1684 fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
1687 if ( (pprev= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1688 height = pprev->GetHeight() + 1;
1692 if ( ASSETCHAINS_LWMAPOS != 0 && bhash > bnTarget )
1694 // if proof of stake is active, check if this is a valid PoS block before we fail
1695 if (verusCheckPOSBlock(slowflag, pblock, height))
1700 if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget )
1703 if ( height > 0 && ASSETCHAINS_SYMBOL[0] == 0 ) // for the fast case
1705 if ( (n= komodo_notaries(pubkeys,height,pblock->nTime)) > 0 )
1708 if ( memcmp(pubkey33,pubkeys[i],33) == 0 )
1715 else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 )
1717 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW )
1719 if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget for staked chains
1723 if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
1725 if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget,bhash)) == 0 )
1727 if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! POSTEST64
1731 if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target
1733 if ( slowflag != 0 )
1734 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1735 if ( bhash > bnTarget )
1737 for (i=31; i>=16; i--)
1738 fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]);
1739 fprintf(stderr," > ");
1740 for (i=31; i>=16; i--)
1741 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1742 fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED);
1747 else if ( is_PoSblock < 0 )
1749 fprintf(stderr,"unexpected negative is_PoSblock.%d\n",is_PoSblock);
1753 if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
1757 script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
1758 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1763 if ( komodo_checkcommission(pblock,height) < 0 )
1767 //fprintf(stderr,"komodo_checkPOW possible.%d slowflag.%d ht.%d notaryid.%d failed.%d\n",possible,slowflag,height,notaryid,failed);
1768 if ( failed != 0 && possible == 0 && notaryid < 0 )
1773 int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
1775 CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
1776 n = pblock->vtx.size();
1779 CTransaction vintx,&tx = pblock->vtx[i];
1780 zfunds += (tx.GetValueOut() - tx.GetShieldedValueIn());
1781 if ( (m= tx.vin.size()) > 0 )
1787 txid = tx.vin[j].prevout.hash;
1788 vout = tx.vin[j].prevout.n;
1789 if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
1791 fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1794 vinsum += vintx.vout[vout].nValue;
1797 if ( (m= tx.vout.size()) > 0 )
1799 for (j=0; j<m-1; j++)
1801 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1802 voutsum += tx.vout[j].nValue;
1803 else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
1805 script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
1806 if ( script == 0 || script[0] != 0x6a )
1808 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1809 voutsum += tx.vout[j].nValue;
1814 if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times
1815 return(3 * SATOSHIDEN);
1816 //if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 )
1817 //. fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
1818 return(voutsum - vinsum);
1821 int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
1823 CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
1824 //fprintf(stderr,"coinsupply %d\n",height);
1826 if ( (pindex= komodo_chainactive(height)) != 0 )
1828 while ( pindex != 0 && pindex->GetHeight() > 0 )
1830 if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
1832 if ( komodo_blockload(block,pindex) == 0 )
1833 pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->GetHeight(),&block);
1836 fprintf(stderr,"error loading block.%d\n",pindex->GetHeight());
1840 supply += pindex->newcoins;
1841 zfunds += pindex->zfunds;
1842 //printf("start ht.%d new %.8f -> supply %.8f zfunds %.8f -> %.8f\n",pindex->GetHeight(),dstr(pindex->newcoins),dstr(supply),dstr(pindex->zfunds),dstr(zfunds));
1843 pindex = pindex->pprev;