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(const CBlockIndex *pindex, const 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 = NULL;
667 BlockMap::const_iterator it = mapBlockIndex.find(block->GetHash());
668 if ( it != mapBlockIndex.end() && (pindex = it->second) != 0 )
670 height2 = (int32_t)pindex->GetHeight();
674 if ( pindex && block != 0 && block->vtx[0].vin.size() > 0 )
676 ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
677 if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
679 //for (i=0; i<6; i++)
680 // printf("%02x",ptr[i]);
682 for (i=0; i<n; i++) // looks strange but this works
684 //03bb81000101(bb 187) (81 48001) (00 12288256) <- coinbase.6 ht.12288256
685 height += ((uint32_t)ptr[i+1] << (i*8));
686 //printf("(%02x %x %d) ",ptr[i+1],((uint32_t)ptr[i+1] << (i*8)),height);
688 //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
690 //komodo_init(height);
692 if ( height != height2 )
694 //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch);
702 int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
705 if ( KOMODO_LOADINGBLOCKS == 0 )
706 memset(pubkey33,0xff,33);
707 else memset(pubkey33,0,33);
708 if ( block->vtx[0].vout.size() > 0 )
710 txnouttype whichType;
711 vector<vector<unsigned char>> vch = vector<vector<unsigned char>>();
712 if (Solver(block->vtx[0].vout[0].scriptPubKey, whichType, vch) && whichType == TX_PUBKEY)
714 CPubKey pubKey(vch[0]);
715 if (pubKey.IsValid())
717 memcpy(pubkey33,vch[0].data(),33);
720 else memset(pubkey33,0,33);
722 else memset(pubkey33,0,33);
727 int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
730 // Open history file to read
731 CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION);
735 try { filein >> block; }
736 catch (const std::exception& e)
738 fprintf(stderr,"readblockfromdisk err B\n");
744 uint32_t komodo_chainactive_timestamp()
746 if ( chainActive.LastTip() != 0 )
747 return((uint32_t)chainActive.LastTip()->GetBlockTime());
751 CBlockIndex *komodo_chainactive(int32_t height)
753 if ( chainActive.LastTip() != 0 )
755 if ( height <= chainActive.LastTip()->GetHeight() )
756 return(chainActive[height]);
757 // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.LastTip()->GetHeight());
759 //fprintf(stderr,"komodo_chainactive null chainActive.LastTip() height %d\n",height);
763 uint32_t komodo_heightstamp(int32_t height)
766 if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
768 //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
772 /*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted
774 int32_t i,num; uint8_t pubkeys[64][33]; CBlock block;
775 if ( pindex->didinit != 0 )
777 //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->GetHeight(),pindex->notaryid,height);
778 if ( pindex->didinit == 0 )
780 pindex->notaryid = -1;
781 if ( KOMODO_LOADINGBLOCKS == 0 )
782 memset(pindex->pubkey33,0xff,33);
783 else memset(pindex->pubkey33,0,33);
784 if ( komodo_blockload(block,pindex) == 0 )
786 komodo_block2pubkey33(pindex->pubkey33,&block);
787 //for (i=0; i<33; i++)
788 // fprintf(stderr,"%02x",pindex->pubkey33[i]);
789 //fprintf(stderr," set pubkey at height %d/%d\n",pindex->GetHeight(),height);
790 //if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 )
791 // pindex->didinit = (KOMODO_LOADINGBLOCKS == 0);
792 } // else fprintf(stderr,"error loading block at %d/%d",pindex->GetHeight(),height);
794 if ( pindex->didinit != 0 && pindex->GetHeight() >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->GetHeight(),(uint32_t)pindex->nTime)) > 0 )
796 for (i=0; i<num; i++)
798 if ( memcmp(pubkeys[i],pindex->pubkey33,33) == 0 )
800 pindex->notaryid = i;
807 fprintf(stderr,"%02x",pindex->pubkey33[i]);
808 fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->GetHeight(),height);
813 void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
815 int32_t num,i; CBlock block;
816 memset(pubkey33,0,33);
819 if ( komodo_blockload(block,pindex) == 0 )
820 komodo_block2pubkey33(pubkey33,&block);
824 /*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33)
826 int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t pubkey33[33],pubkeys[64][33];
827 if ( (pindex= chainActive[height]) != 0 )
829 if ( pindex->didinit != 0 )
831 if ( destpubkey33 != 0 )
832 memcpy(destpubkey33,pindex->pubkey33,33);
833 return(pindex->notaryid);
835 komodo_index2pubkey33(pubkey33,pindex,height);
836 if ( destpubkey33 != 0 )
837 memcpy(destpubkey33,pindex->pubkey33,33);
838 if ( pindex->didinit != 0 )
839 return(pindex->notaryid);
840 timestamp = pindex->GetBlockTime();
841 if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 )
843 for (i=0; i<num; i++)
844 if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
848 fprintf(stderr,"komodo_minerid height.%d null pindex\n",height);
849 return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp));
852 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height)
854 int32_t i,j,n,duplicate; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33];
855 memset(mids,-1,sizeof(*mids)*66);
856 n = komodo_notaries(notarypubs33,height,0);
857 for (i=duplicate=0; i<66; i++)
859 if ( (pindex= komodo_chainactive(height-i)) != 0 )
861 blocktimes[i] = pindex->nTime;
862 if ( komodo_blockload(block,pindex) == 0 )
864 komodo_block2pubkey33(pubkeys[i],&block);
867 if ( memcmp(notarypubs33[j],pubkeys[i],33) == 0 )
874 } else fprintf(stderr,"couldnt load block.%d\n",height);
875 if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
879 if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
884 int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
886 int32_t i,j,n,nonz,numnotaries; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33],pubkey33[33];
887 numnotaries = komodo_notaries(notarypubs33,height,0);
888 for (i=nonz=0; i<width; i++,n++)
892 if ( (pindex= komodo_chainactive(height-width+i+1)) != 0 )
894 if ( komodo_blockload(block,pindex) == 0 )
896 komodo_block2pubkey33(pubkey33,&block);
897 for (j=0; j<numnotaries; j++)
899 if ( memcmp(notarypubs33[j],pubkey33,33) == 0 )
901 minerids[nonz++] = j;
905 if ( j == numnotaries )
906 minerids[nonz++] = j;
907 } else fprintf(stderr,"couldnt load block.%d\n",height);
913 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)
915 int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33];
916 komodo_chosennotary(¬aryid,height,pubkey33,blocktimes[0]);
917 if ( height >= 82000 )
923 if ( mids[i] == notaryid )
925 if ( height > 792000 )
928 fprintf(stderr,"%d ",mids[j]);
929 fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
934 if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 )
936 if ( height > 807000 )
944 if ( height >= 34000 && notaryid >= 0 )
946 if ( height < 79693 )
948 else if ( height < 82000 )
951 for (i=1; i<limit; i++)
953 komodo_chosennotary(&nid,height-i,pubkey33,blocktimes[i]);
954 if ( nid == notaryid )
956 //for (j=0; j<66; j++)
957 // fprintf(stderr,"%d ",mids[j]);
958 //fprintf(stderr,"ht.%d repeat mids[%d] nid.%d notaryid.%d\n",height-i,i,nid,notaryid);
959 if ( height > 225000 )
963 //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
970 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)
972 int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
973 depth = komodo_MoMdata(¬arized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip);
974 memset(MoMp,0,sizeof(*MoMp));
975 memset(kmdtxidp,0,sizeof(*kmdtxidp));
976 *notarized_heightp = 0;
977 if ( depth != 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
980 *notarized_heightp = notarized_ht;
986 int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
988 int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
989 if ( (pindex= chainActive.LastTip()) == 0 )
991 notarized_height = komodo_notarizeddata(pindex->GetHeight(),¬arized_hash,¬arized_desttxid);
992 *notarized_heightp = notarized_height;
993 BlockMap::const_iterator it;
994 if ( notarized_height >= 0 && notarized_height <= pindex->GetHeight() && (it = mapBlockIndex.find(notarized_hash)) != mapBlockIndex.end() && (notary = it->second) != NULL )
996 //printf("nHeight.%d -> (%d %s)\n",pindex->Tip()->GetHeight(),notarized_height,notarized_hash.ToString().c_str());
997 if ( notary->GetHeight() == notarized_height ) // if notarized_hash not in chain, reorg
999 if ( nHeight < notarized_height )
1001 //fprintf(stderr,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1004 else if ( nHeight == notarized_height && memcmp(&hash,¬arized_hash,sizeof(hash)) != 0 )
1006 fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1009 } //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());
1011 //else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
1012 // fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->GetHeight());
1016 uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
1019 CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
1020 *txheighttimep = *txheightp = *tiptimep = 0;
1022 if ( !GetTransaction(hash,tx,hashBlock,true) )
1024 uint32_t locktime = 0;
1025 if ( n < tx.vout.size() )
1027 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
1029 *valuep = tx.vout[n].nValue;
1030 *txheightp = pindex->GetHeight();
1031 *txheighttimep = pindex->nTime;
1032 if ( *tiptimep == 0 && (tipindex= chainActive.LastTip()) != 0 )
1033 *tiptimep = (uint32_t)tipindex->nTime;
1034 locktime = tx.nLockTime;
1035 //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
1041 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
1043 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)
1045 uint64_t value; uint32_t tiptime=0,txheighttimep; CBlockIndex *pindex;
1046 if ( (pindex= chainActive[tipheight]) != 0 )
1047 tiptime = (uint32_t)pindex->nTime;
1048 else fprintf(stderr,"cant find height[%d]\n",tipheight);
1049 if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 )
1051 if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
1052 return(komodo_interest(*txheightp,value,*locktimep,tiptime));
1053 //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);
1054 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);
1059 int32_t komodo_isrealtime(int32_t *kmdheightp)
1061 struct komodo_state *sp; CBlockIndex *pindex;
1062 if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
1063 *kmdheightp = sp->CURRENT_HEIGHT;
1064 else *kmdheightp = 0;
1065 if ( (pindex= chainActive.LastTip()) != 0 && pindex->GetHeight() >= (int32_t)komodo_longestchain() )
1070 int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
1072 if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
1074 if ( txheight > 246748 )
1076 if ( txheight < 247205 )
1078 if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
1080 if ( tx.nLockTime != 1477258935 && dispflag != 0 )
1082 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);
1086 if ( 0 && dispflag != 0 )
1087 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);
1094 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.
1096 komodo_checkPOW (slow) is called right before connecting blocks so all prior blocks can be assumed to be there and all checks must pass
1098 commission must be in coinbase.vout[1] and must be >= 10000 sats
1099 PoS stake must be without txfee and in the last tx in the block at vout[0]
1102 uint64_t komodo_commission(const CBlock *pblock)
1104 int32_t i,j,n=0,txn_count; uint64_t commission,total = 0;
1105 txn_count = pblock->vtx.size();
1106 for (i=0; i<txn_count; i++)
1108 n = pblock->vtx[i].vout.size();
1111 //fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
1112 if ( i != 0 || j != 1 )
1113 total += pblock->vtx[i].vout[j].nValue;
1116 //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN));
1117 commission = ((total * ASSETCHAINS_COMMISSION) / COIN);
1118 if ( commission < 10000 )
1123 uint32_t komodo_segid32(char *coinaddr)
1126 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
1127 return(addrhash.uints[0]);
1130 int8_t komodo_segid(int32_t nocache,int32_t height)
1132 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;
1133 if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
1135 if ( nocache == 0 && pindex->segid >= -1 )
1136 return(pindex->segid);
1137 if ( komodo_blockload(block,pindex) == 0 )
1139 txn_count = block.vtx.size();
1140 if ( txn_count > 1 && block.vtx[txn_count-1].vin.size() == 1 && block.vtx[txn_count-1].vout.size() == 1 )
1142 txid = block.vtx[txn_count-1].vin[0].prevout.hash;
1143 vout = block.vtx[txn_count-1].vin[0].prevout.n;
1144 txtime = komodo_txtime(&value,txid,vout,destaddr);
1145 if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
1147 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
1148 if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
1150 segid = komodo_segid32(voutaddr) & 0x3f;
1151 //fprintf(stderr,"komodo_segid.(%d) -> %02x\n",height,segid);
1153 } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
1160 void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
1162 static uint8_t prevhashbuf[100]; static int32_t prevheight;
1164 if ( height == prevheight && n == 100 )
1165 memcpy(hashbuf,prevhashbuf,100);
1168 memset(hashbuf,0xff,n);
1171 hashbuf[i] = (uint8_t)komodo_segid(1,height+i);
1172 //fprintf(stderr,"%02x ",hashbuf[i]);
1176 memcpy(prevhashbuf,hashbuf,100);
1177 prevheight = height;
1178 //fprintf(stderr,"prevsegids.%d\n",height+n);
1183 uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout)
1186 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
1187 memcpy(&hashbuf[100],&addrhash,sizeof(addrhash));
1188 memcpy(&hashbuf[100+sizeof(addrhash)],&txid,sizeof(txid));
1189 memcpy(&hashbuf[100+sizeof(addrhash)+sizeof(txid)],&vout,sizeof(vout));
1190 vcalc_sha256(0,(uint8_t *)hashp,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
1191 return(addrhash.uints[0]);
1194 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)
1196 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;
1197 txtime = komodo_txtime2(&value,txid,vout,address);
1198 if ( validateflag == 0 )
1200 //fprintf(stderr,"blocktime.%u -> ",blocktime);
1201 if ( blocktime < prevtime+3 )
1202 blocktime = prevtime+3;
1203 if ( blocktime < GetAdjustedTime()-60 )
1204 blocktime = GetAdjustedTime()+30;
1205 //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime);
1207 if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
1209 //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
1212 if ( value < SATOSHIDEN )
1214 value /= SATOSHIDEN;
1215 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1216 ratio = (mindiff / bnTarget);
1217 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
1219 komodo_segids(hashbuf,nHeight-101,100);
1220 segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
1221 segid = ((nHeight + segid32) & 0x3f);
1222 for (iter=0; iter<600; iter++)
1224 if ( blocktime+iter+segid*2 < txtime+minage )
1226 diff = (iter + blocktime - txtime - minage);
1229 else if ( diff > 3600*24*30 )
1231 //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
1236 coinage = (value * diff);
1237 if ( blocktime+iter+segid*2 > prevtime+480 )
1238 coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
1239 coinage256 = arith_uint256(coinage+1);
1240 hashval = ratio * (UintToArith256(hash) / coinage256);
1241 if ( hashval <= bnTarget )
1244 if ( validateflag == 0 )
1246 //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid);
1248 blocktime += segid * 2;
1252 if ( validateflag != 0 )
1254 /*for (i=31; i>=24; i--)
1255 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1256 fprintf(stderr," vs ");
1257 for (i=31; i>=24; i--)
1258 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1259 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);*/
1263 //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
1264 if ( 0 && validateflag != 0 )
1266 for (i=31; i>=24; i--)
1267 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1268 fprintf(stderr," vs ");
1269 for (i=31; i>=24; i--)
1270 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1271 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);
1275 return(blocktime * winner);
1278 arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
1280 int32_t oldflag = 0;
1281 CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
1282 *percPoSp = percPoS = 0;
1283 if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
1285 sum = arith_uint256(0);
1287 easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1288 for (i=n=m=0; i<100; i++)
1290 ht = height - 100 + i;
1293 if ( (pindex= komodo_chainactive(ht)) != 0 )
1295 if ( komodo_segid(0,ht) >= 0 )
1299 if ( ASSETCHAINS_STAKED < 100 )
1300 fprintf(stderr,"0");
1304 if ( ASSETCHAINS_STAKED < 100 )
1305 fprintf(stderr,"1");
1306 sum += UintToArith256(pindex->GetBlockHash());
1310 if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
1311 fprintf(stderr," %d, ",percPoS);
1314 percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
1315 if ( ASSETCHAINS_STAKED < 100 )
1316 fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
1317 *percPoSp = percPoS;
1320 ave = (sum / arith_uint256(m));
1323 } else ave = target; //easydiff; //else return(target);
1326 if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
1328 //if ( oldflag != 0 )
1329 // bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
1331 bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
1332 else bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
1333 if ( ASSETCHAINS_STAKED < 100 )
1335 for (i=31; i>=24; i--)
1336 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1337 fprintf(stderr," increase diff -> ");
1338 for (i=31; i>=24; i--)
1339 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1340 fprintf(stderr," floor diff ");
1341 for (i=31; i>=24; i--)
1342 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1343 fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1346 else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget
1350 bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1351 //bnTarget = (bnTarget * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc);
1352 bnTarget = (bnTarget / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
1354 else bnTarget = (ave / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
1355 if ( bnTarget > easydiff )
1356 bnTarget = easydiff;
1357 else if ( bnTarget < ave ) // overflow
1359 bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1360 if ( bnTarget < ave )
1365 for (i=31; i>=24; i--)
1366 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1367 fprintf(stderr," decrease diff -> ");
1368 for (i=31; i>=24; i--)
1369 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1370 fprintf(stderr," floor diff ");
1371 for (i=31; i>=24; i--)
1372 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1373 fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1376 else bnTarget = ave; // recent ave is perfect
1380 int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget,arith_uint256 bhash)
1382 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;
1383 if ( ASSETCHAINS_STAKED == 100 && height <= 10 )
1385 BlockMap::const_iterator it = mapBlockIndex.find(pblock->GetHash());
1386 pindex = it != mapBlockIndex.end() ? it->second : NULL;
1387 if ( pindex != 0 && pindex->segid >= -1 )
1389 if ( pindex->segid == -1 )
1393 txn_count = pblock->vtx.size();
1394 if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 )
1396 it = mapBlockIndex.find(pblock->hashPrevBlock);
1397 if ( it != mapBlockIndex.end() && (previndex = it->second) != NULL )
1398 prevtime = (uint32_t)previndex->nTime;
1400 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1401 vout = pblock->vtx[txn_count-1].vin[0].prevout.n;
1402 if ( prevtime != 0 )
1404 if ( komodo_isPoS(pblock) != 0 )
1406 eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"");
1408 if ( eligible == 0 || eligible > pblock->nTime )
1410 if ( 0 && ASSETCHAINS_STAKED < 100 )
1411 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));
1412 if ( slowflag != 0 && pindex != 0 )
1415 fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
1420 isPoS = 2; // 2 means staking utxo validated
1421 if ( slowflag != 0 && height > 100 )
1424 if ( pindex != 0 && pindex->segid == -2 && (segid= komodo_segid(1,height)) >= 0 )
1426 pindex->segid = segid;
1427 fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid);
1428 } //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid);
1432 if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx
1434 if ( komodo_isPoS(pblock) != 0 )
1437 if ( slowflag != 0 && isPoS != 0 )
1441 fprintf(stderr,"ht.%d isPoS.%d utxo not validated -> must be PoW fake\n",height,isPoS);
1446 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1447 if ( bhash < bnTarget )
1449 fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height);
1456 //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
1460 bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
1461 bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating);
1462 bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams, bool validateSig = true);
1464 // for now, we will ignore slowFlag in the interest of keeping success/fail simpler for security purposes
1465 bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
1467 CBlockIndex *pastBlockIndex;
1468 uint256 txid, blkHash;
1473 CTxDestination voutaddress, destaddress, cbaddress;
1474 arith_uint256 target, hash;
1477 if (!pblock->IsVerusPOSBlock())
1479 printf("%s, height %d not POS block\n", pblock->nNonce.GetHex().c_str(), height);
1483 char voutaddr[64], destaddr[64], cbaddr[64];
1485 txn_count = pblock->vtx.size();
1487 if ( txn_count > 1 )
1489 target.SetCompact(pblock->GetVerusPOSTarget());
1490 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1491 voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
1492 value = pblock->vtx[txn_count-1].vout[0].nValue;
1495 bool validHash = (value != 0);
1496 bool enablePOSNonce = CPOSNonce::NewPOSActive(height);
1497 bool newPOSEnforcement = enablePOSNonce && (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= height);
1498 bool supportInstantSpend = !IsVerusActive() && CConstVerusSolutionVector::activationHeight.ActiveVersion(height) >= CActivationHeight::ACTIVATE_PBAAS;
1500 arith_uint256 posHash;
1502 if (validHash && newPOSEnforcement)
1504 validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1505 posHash = UintToArith256(rawHash) / value;
1506 if (!validHash || posHash > target)
1509 printf("ERROR: invalid nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1510 pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1512 // make sure prev block hash and block height are correct
1514 if (validHash && (validHash = GetStakeParams(pblock->vtx[txn_count-1], p)))
1516 for (int i = 0; validHash && i < pblock->vtx[0].vout.size(); i++)
1519 if (pblock->vtx[0].vout[i].scriptPubKey.IsInstantSpend() || ValidateMatchingStake(pblock->vtx[0], i, pblock->vtx[txn_count-1], validHash) && !validHash)
1521 if ((p.prevHash == pblock->hashPrevBlock) && (int32_t)p.blkHeight == height)
1527 printf("ERROR: invalid block data for stake tx\nblkHash: %s\ntxBlkHash: %s\nblkHeight: %d, txBlkHeight: %d\n",
1528 pblock->hashPrevBlock.GetHex().c_str(), p.prevHash.GetHex().c_str(), height, p.blkHeight);
1532 else validHash = false;
1542 else if (!(pastBlockIndex = komodo_chainactive(height - 100)))
1544 fprintf(stderr,"ERROR: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str());
1547 #ifndef KOMODO_ZCASH
1548 if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
1550 if (!GetTransaction(txid, tx, blkHash, true))
1553 fprintf(stderr,"ERROR: invalid PoS block %s - no source transaction\n",blkHash.ToString().c_str());
1557 uint256 pastHash = chainActive.GetVerusEntropyHash(height);
1558 // if height is over when Nonce is required to be the new format, we check that the new format is correct
1559 // if over when we have the new POS hash function, we validate that as well
1560 // they are 100 blocks apart
1561 CPOSNonce nonce = pblock->nNonce;
1563 //printf("before nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
1564 //validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1565 //hash = UintToArith256(rawHash) / tx.vout[voutNum].nValue;
1566 //printf("Raw POShash: %s\n", hash.GetHex().c_str());
1568 hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
1570 //printf("after nNonce: %s, height: %d\n", nonce.GetHex().c_str(), height);
1571 //printf("POShash: %s\n\n", hash.GetHex().c_str());
1573 if ((!newPOSEnforcement || posHash == hash) && hash <= target)
1575 BlockMap::const_iterator it = mapBlockIndex.find(blkHash);
1576 if ((it == mapBlockIndex.end()) ||
1577 !(pastBlockIndex = it->second) ||
1578 (height - pastBlockIndex->GetHeight()) < VERUS_MIN_STAKEAGE)
1580 fprintf(stderr,"ERROR: invalid PoS block %s - stake source too new or not found\n",blkHash.ToString().c_str());
1584 // make sure we have the right target
1585 CBlockIndex *previndex;
1586 it = mapBlockIndex.find(pblock->hashPrevBlock);
1587 if (it == mapBlockIndex.end() || !(previndex = it->second))
1589 fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
1593 arith_uint256 cTarget;
1594 uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
1595 cTarget.SetCompact(nBits);
1596 bool nonceOK = true;
1598 // check to see how many fail
1599 //if (nonce != pblock->nNonce)
1600 // printf("Mismatched nNonce: %s\nblkHash: %s, height: %d\n", nonce.GetHex().c_str(), pblock->GetHash().GetHex().c_str(), height);
1602 if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum, pblock->nVersion))
1604 fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
1609 if (cTarget != target)
1611 fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
1615 if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) &&
1616 ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
1617 CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
1619 strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
1620 strcpy(destaddr, CBitcoinAddress(destaddress).ToString().c_str());
1621 strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
1622 if (newPOSEnforcement)
1624 if (!strcmp(destaddr, voutaddr))
1626 // allow delegation of stake, but require all ouputs to be
1627 // crypto conditions
1630 // validatestake transaction sets the pubkey of the stake output
1631 // if it has no override into the pubkey
1632 if (ValidateStakeTransaction(pblock->vtx[txn_count-1], p, false))
1635 // loop through all outputs to make sure they are sent to the proper pubkey
1637 for (auto vout : pblock->vtx[0].vout)
1640 std::vector<std::vector<unsigned char>> vvch = std::vector<std::vector<unsigned char>>();
1641 // solve all outputs to check that non-instantspend destinations all go only to the pk
1642 // specified in the stake params
1643 if ((!supportInstantSpend || !vout.scriptPubKey.IsInstantSpend()) &&
1644 (!Solver(vout.scriptPubKey, tp, vvch) ||
1645 tp != TX_CRYPTOCONDITION ||
1647 p.pk != CPubKey(vvch[0])))
1656 else if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
1662 fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n",blkHash.ToString().c_str());
1670 printf("ERROR: malformed nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1671 pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1680 int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1682 int64_t checktoshis=0; uint8_t *script;
1683 if ( ASSETCHAINS_COMMISSION != 0 )
1685 checktoshis = komodo_commission(pblock);
1686 if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1688 else if ( checktoshis != 0 )
1690 script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
1691 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1693 if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1695 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1700 return(checktoshis);
1703 bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1705 int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1707 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;
1708 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
1709 KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
1710 if ( !CheckEquihashSolution(pblock, Params().GetConsensus()) )
1712 fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1715 hash = pblock->GetHash();
1716 bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1717 bhash = UintToArith256(hash);
1718 possible = komodo_block2pubkey33(pubkey33,pblock);
1721 if ( slowflag != 0 )
1723 fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
1726 BlockMap::const_iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
1727 if ( it != mapBlockIndex.end() && (pprev= it->second) != 0 )
1728 height = pprev->GetHeight() + 1;
1733 if (ASSETCHAINS_LWMAPOS != 0 && pblock->IsVerusPOSBlock())
1737 else if (bhash <= bnTarget)
1739 // tolerate variable size solutions, but ensure that we have at least 16 bytes extra space to fit the clhash at the end
1740 int modSpace = GetSerializeSize(*(CBlockHeader *)pblock, SER_NETWORK, PROTOCOL_VERSION) % 32;
1741 int solutionVer = CConstVerusSolutionVector::GetVersionByHeight(height);
1742 if (solutionVer < CActivationHeight::ACTIVATE_VERUSHASH2_1 || (modSpace >= 1 && modSpace <= 16))
1748 printf("Block header size modulo 32 must be > 1 and <= 16 for PoW blocks\n");
1753 printf("Insufficient hash result and not PoS block\n");
1759 bool IsCoinbaseTimeLocked(const CTransaction &tx, uint32_t &outUnlockHeight);
1761 void GetImmatureCoins(std::map<uint32_t, int64_t> *pimmatureBlockAmounts, CBlock &block, uint32_t &maturity, int64_t &amount, uint32_t height)
1763 std::map<uint32_t, int64_t> _unlockBlockAmounts;
1764 std::map<uint32_t, int64_t> &unlockBlockAmounts = pimmatureBlockAmounts ? *pimmatureBlockAmounts : _unlockBlockAmounts;
1767 if (block.vtx.size())
1769 const CTransaction &tx = block.vtx[0];
1770 uint32_t unlockHeight = 0;
1771 if (IsCoinbaseTimeLocked(tx, unlockHeight) && unlockHeight > (height + COINBASE_MATURITY))
1773 maturity = unlockHeight;
1777 maturity = height + COINBASE_MATURITY;
1779 for (auto &out : tx.vout)
1781 if (!out.scriptPubKey.IsInstantSpend())
1783 amount += out.nValue;
1786 unlockBlockAmounts[maturity] += amount;
1790 bool GetNewCoins(int64_t &newCoins, int64_t *pzsupplydelta, std::map<uint32_t, int64_t> *pimmatureBlockAmounts, CBlock &block, uint32_t &maturity, int64_t &amount, uint32_t height)
1793 int64_t &zfunds = pzsupplydelta ? *pzsupplydelta : _zfunds;
1794 std::map<uint32_t, int64_t> _unlockBlockAmounts;
1795 std::map<uint32_t, int64_t> &unlockBlockAmounts = pimmatureBlockAmounts ? *pimmatureBlockAmounts : _unlockBlockAmounts;
1797 for (auto &tx : block.vtx)
1799 if (tx.IsCoinBase())
1801 for (auto &out : tx.vout)
1803 newCoins += out.nValue;
1805 GetImmatureCoins(&unlockBlockAmounts, block, maturity, amount, height);
1809 int64_t vinSum = 0, voutSum = 0;
1813 for (auto &in : tx.vin)
1815 if ( !GetTransaction(in.prevout.hash, vinTx, blockHash, false) || in.prevout.n >= vinTx.vout.size() )
1817 fprintf(stderr,"ERROR: %s/v%d cant find\n", in.prevout.hash.ToString().c_str(), in.prevout.n);
1820 vinSum += vinTx.vout[in.prevout.n].nValue;
1822 for (auto &out : tx.vout)
1824 if ( !out.scriptPubKey.IsOpReturn() )
1826 voutSum += out.nValue;
1829 // this should be a negative number due to fees, which will mature when the coinbase does
1830 // all normal blocks should have negative coin emission due to maturity only
1831 // resolving the pmatureBlockAmounts map is required for an accurate mature and immature supply
1832 newCoins += voutSum - vinSum;
1836 zfunds += (chainActive[height]->nSproutValue ? chainActive[height]->nSproutValue.get() : 0) + chainActive[height]->nSaplingValue;
1841 int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
1843 CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
1844 n = pblock->vtx.size();
1847 CTransaction vintx, &tx = pblock->vtx[i];
1848 zfunds += (tx.GetShieldedValueOut() - tx.GetShieldedValueIn());
1849 if ( (m= tx.vin.size()) > 0 )
1855 txid = tx.vin[j].prevout.hash;
1856 vout = tx.vin[j].prevout.n;
1857 if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
1859 fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1862 vinsum += vintx.vout[vout].nValue;
1865 if ( (m= tx.vout.size()) > 0 )
1867 for (j=0; j<m-1; j++)
1869 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1870 voutsum += tx.vout[j].nValue;
1871 else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
1873 script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
1874 if ( script == 0 || script[0] != 0x6a )
1876 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1877 voutsum += tx.vout[j].nValue;
1882 if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times
1883 return(3 * SATOSHIDEN);
1884 //if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 )
1885 //. fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
1886 return(voutsum - vinsum);
1889 int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
1891 CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
1892 //fprintf(stderr,"coinsupply %d\n",height);
1894 if ( (pindex= komodo_chainactive(height)) != 0 )
1896 while ( pindex != 0 && pindex->GetHeight() > 0 )
1898 if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
1900 if ( komodo_blockload(block,pindex) == 0 )
1901 pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->GetHeight(),&block);
1904 fprintf(stderr,"error loading block.%d\n",pindex->GetHeight());
1908 supply += pindex->newcoins;
1909 zfunds += pindex->zfunds;
1910 //printf("start ht.%d new %.8f -> supply %.8f zfunds %.8f -> %.8f\n",pindex->GetHeight(),dstr(pindex->newcoins),dstr(supply),dstr(pindex->zfunds),dstr(zfunds));
1911 pindex = pindex->pprev;
1918 bool GetCoinSupply(int64_t &transparentSupply, int64_t *pzsupply, int64_t *pimmaturesupply, uint32_t height)
1920 int64_t _immature = 0, _zsupply = 0;
1921 int64_t &immature = pimmaturesupply ? *pimmaturesupply : _immature;
1922 int64_t &zfunds = pzsupply ? *pzsupply : _zsupply;
1924 // keep a running map of immature coin amounts and block maturity as we move forward on the block chain
1925 std::map<uint32_t, int64_t> immatureBlockAmounts;
1927 if (height > chainActive.Height())
1929 height = chainActive.Height();
1932 for (int curHeight = 1; curHeight <= height; curHeight++)
1934 CBlockIndex *pIndex;
1937 if ( (pIndex = komodo_chainactive(curHeight)) != 0 )
1939 if ( pIndex->newcoins == 0 && pIndex->zfunds == 0 )
1941 if ( !komodo_blockload(block, pIndex) == 0 || !GetNewCoins(pIndex->newcoins, &pIndex->zfunds, &immatureBlockAmounts, block, pIndex->maturity, pIndex->immature, curHeight) )
1943 fprintf(stderr,"error loading block.%d\n", pIndex->GetHeight());
1949 if (pIndex->maturity)
1951 if (immatureBlockAmounts.count(pIndex->maturity))
1953 immatureBlockAmounts[pIndex->maturity] += pIndex->immature;
1957 immatureBlockAmounts[pIndex->maturity] = pIndex->immature;
1962 transparentSupply += pIndex->newcoins;
1963 zfunds += pIndex->zfunds;
1967 // remove coins that matured this block from the map to prevent double counting
1968 auto lastIt = immatureBlockAmounts.upper_bound(height);
1969 immatureBlockAmounts.erase(immatureBlockAmounts.begin(), lastIt);
1970 for (auto &lockedAmount : immatureBlockAmounts)
1972 immature += lockedAmount.second;