]> Git Repo - VerusCoin.git/blob - src/komodo_bitcoind.h
Test
[VerusCoin.git] / src / komodo_bitcoind.h
1 /******************************************************************************
2  * Copyright © 2014-2018 The SuperNET Developers.                             *
3  *                                                                            *
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.  *
7  *                                                                            *
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 *
11  *                                                                            *
12  * Removal or modification of this copyright notice is prohibited.            *
13  *                                                                            *
14  ******************************************************************************/
15
16 // komodo functions that interact with bitcoind C++
17
18 #ifdef _WIN32
19 #include <curl/curl.h>
20 #include <curl/easy.h>
21 #else
22 #include <curl/curl.h>
23 #include <curl/easy.h>
24 #endif
25
26 #include "komodo_defs.h"
27
28 int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
29 int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
30
31 //#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
32
33 struct MemoryStruct { char *memory; size_t size; };
34 struct return_string { char *ptr; size_t len; };
35
36 // return data from the server
37 #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
38 #define CURL_GLOBAL_SSL (1<<0)
39 #define CURL_GLOBAL_WIN32 (1<<1)
40
41
42 /************************************************************************
43  *
44  * Initialize the string handler so that it is thread safe
45  *
46  ************************************************************************/
47
48 void init_string(struct return_string *s)
49 {
50     s->len = 0;
51     s->ptr = (char *)calloc(1,s->len+1);
52     if ( s->ptr == NULL )
53     {
54         fprintf(stderr,"init_string malloc() failed\n");
55         exit(-1);
56     }
57     s->ptr[0] = '\0';
58 }
59
60 /************************************************************************
61  *
62  * Use the "writer" to accumulate text until done
63  *
64  ************************************************************************/
65
66 size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s)
67 {
68     size_t new_len = s->len + size*nmemb;
69     s->ptr = (char *)realloc(s->ptr,new_len+1);
70     if ( s->ptr == NULL )
71     {
72         fprintf(stderr, "accumulate realloc() failed\n");
73         exit(-1);
74     }
75     memcpy(s->ptr+s->len,ptr,size*nmemb);
76     s->ptr[new_len] = '\0';
77     s->len = new_len;
78     return(size * nmemb);
79 }
80
81 /************************************************************************
82  *
83  * return the current system time in milliseconds
84  *
85  ************************************************************************/
86
87 #define EXTRACT_BITCOIND_RESULT  // if defined, ensures error is null and returns the "result" field
88 #ifdef EXTRACT_BITCOIND_RESULT
89
90 /************************************************************************
91  *
92  * perform post processing of the results
93  *
94  ************************************************************************/
95
96 char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params)
97 {
98     long i,j,len; char *retstr = 0; cJSON *json,*result,*error;
99     //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
100     if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 )
101     {
102         if ( strcmp(command,"signrawtransaction") != 0 )
103             printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
104         return(rpcstr);
105     }
106     json = cJSON_Parse(rpcstr);
107     if ( json == 0 )
108     {
109         printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params);
110         free(rpcstr);
111         return(0);
112     }
113     result = cJSON_GetObjectItem(json,"result");
114     error = cJSON_GetObjectItem(json,"error");
115     if ( error != 0 && result != 0 )
116     {
117         if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL )
118         {
119             retstr = cJSON_Print(result);
120             len = strlen(retstr);
121             if ( retstr[0] == '"' && retstr[len-1] == '"' )
122             {
123                 for (i=1,j=0; i<len-1; i++,j++)
124                     retstr[j] = retstr[i];
125                 retstr[j] = 0;
126             }
127         }
128         else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL )
129         {
130             if ( strcmp(command,"signrawtransaction") != 0 )
131                 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr);
132         }
133         free(rpcstr);
134     } else retstr = rpcstr;
135     free_json(json);
136     //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr);
137     return(retstr);
138 }
139 #endif
140
141 /************************************************************************
142  *
143  * perform the query
144  *
145  ************************************************************************/
146
147 char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params)
148 {
149     static int didinit,count,count2; static double elapsedsum,elapsedsum2;
150     struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle;
151     char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime;
152     if ( didinit == 0 )
153     {
154         didinit = 1;
155         curl_global_init(CURL_GLOBAL_ALL); //init the curl session
156     }
157     numretries = 0;
158     if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") ==  0 )
159         specialcase = 1;
160     else specialcase = 0;
161     if ( url[0] == 0 )
162         strcpy(url,"http://127.0.0.1:7876/nxt");
163     if ( specialcase != 0 && 0 )
164         printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params);
165 try_again:
166     if ( retstrp != 0 )
167         *retstrp = 0;
168     starttime = OS_milliseconds();
169     curl_handle = curl_easy_init();
170     init_string(&s);
171     headers = curl_slist_append(0,"Expect:");
172     
173     curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
174     curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER,    headers);
175     curl_easy_setopt(curl_handle,CURLOPT_URL,           url);
176     curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes);               // send all data to this function
177     curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA,             &s);                    // we pass our 's' struct to the callback
178     curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL,              1L);                    // supposed to fix "Alarm clock" and long jump crash
179     curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS,    1L);                    // no progress callback
180     if ( strncmp(url,"https",5) == 0 )
181     {
182         curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0);
183         curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0);
184     }
185     if ( userpass != 0 )
186         curl_easy_setopt(curl_handle,CURLOPT_USERPWD,   userpass);
187     databuf = 0;
188     if ( params != 0 )
189     {
190         if ( command != 0 && specialcase == 0 )
191         {
192             len = strlen(params);
193             if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) {
194                 bracket0 = bracket1 = (char *)"";
195             }
196             else
197             {
198                 bracket0 = (char *)"[";
199                 bracket1 = (char *)"]";
200             }
201             
202             databuf = (char *)malloc(256 + strlen(command) + strlen(params));
203             sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1);
204             //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf);
205             //
206         } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params);
207         curl_easy_setopt(curl_handle,CURLOPT_POST,1L);
208         if ( databuf != 0 )
209             curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf);
210         else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params);
211     }
212     //laststart = milliseconds();
213     res = curl_easy_perform(curl_handle);
214     curl_slist_free_all(headers);
215     curl_easy_cleanup(curl_handle);
216     if ( databuf != 0 ) // clean up temporary buffer
217     {
218         free(databuf);
219         databuf = 0;
220     }
221     if ( res != CURLE_OK )
222     {
223         numretries++;
224         if ( specialcase != 0 )
225         {
226             printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res);
227             free(s.ptr);
228             return(0);
229         }
230         else if ( numretries >= 1 )
231         {
232             //printf("Maximum number of retries exceeded!\n");
233             free(s.ptr);
234             return(0);
235         }
236         if ( (rand() % 1000) == 0 )
237             printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries);
238         free(s.ptr);
239         sleep((1<<numretries));
240         goto try_again;
241         
242     }
243     else
244     {
245         if ( command != 0 && specialcase == 0 )
246         {
247             count++;
248             elapsedsum += (OS_milliseconds() - starttime);
249             if ( (count % 1000000) == 0)
250                 printf("%d: ave %9.6f | elapsed %.3f millis | bitcoind_RPC.(%s) url.(%s)\n",count,elapsedsum/count,(OS_milliseconds() - starttime),command,url);
251             if ( retstrp != 0 )
252             {
253                 *retstrp = s.ptr;
254                 return(s.ptr);
255             }
256             return(post_process_bitcoind_RPC(debugstr,command,s.ptr,params));
257         }
258         else
259         {
260             if ( 0 && specialcase != 0 )
261                 fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: BTCD.(%s) -> (%s)\n",params,s.ptr);
262             count2++;
263             elapsedsum2 += (OS_milliseconds() - starttime);
264             if ( (count2 % 10000) == 0)
265                 printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command);
266             return(s.ptr);
267         }
268     }
269     printf("bitcoind_RPC: impossible case\n");
270     free(s.ptr);
271     return(0);
272 }
273
274 static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data)
275 {
276     size_t realsize = (size * nmemb);
277     struct MemoryStruct *mem = (struct MemoryStruct *)data;
278     mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1));
279     if ( mem->memory != 0 )
280     {
281         if ( ptr != 0 )
282             memcpy(&(mem->memory[mem->size]),ptr,realsize);
283         mem->size += realsize;
284         mem->memory[mem->size] = 0;
285     }
286     //printf("got %d bytes\n",(int32_t)(size*nmemb));
287     return(realsize);
288 }
289
290 char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3)
291 {
292     struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
293     if ( (cHandle= *cHandlep) == NULL )
294         *cHandlep = cHandle = curl_easy_init();
295     else curl_easy_reset(cHandle);
296     //#ifdef DEBUG
297     //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
298     //#endif
299     curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
300     curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0);
301     //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
302     curl_easy_setopt(cHandle,CURLOPT_URL,url);
303     curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
304     if ( userpass != 0 && userpass[0] != 0 )
305         curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
306     if ( postfields != 0 && postfields[0] != 0 )
307     {
308         curl_easy_setopt(cHandle,CURLOPT_POST,1);
309         curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
310     }
311     if ( hdr0 != NULL && hdr0[0] != 0 )
312     {
313         //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:"");
314         headers = curl_slist_append(headers,hdr0);
315         if ( hdr1 != 0 && hdr1[0] != 0 )
316             headers = curl_slist_append(headers,hdr1);
317         if ( hdr2 != 0 && hdr2[0] != 0 )
318             headers = curl_slist_append(headers,hdr2);
319         if ( hdr3 != 0 && hdr3[0] != 0 )
320             headers = curl_slist_append(headers,hdr3);
321     } //headers = curl_slist_append(0,"Expect:");
322     if ( headers != 0 )
323         curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers);
324     //res = curl_easy_perform(cHandle);
325     memset(&chunk,0,sizeof(chunk));
326     curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback);
327     curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk);
328     curl_easy_perform(cHandle);
329     curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code);
330     if ( headers != 0 )
331         curl_slist_free_all(headers);
332     if ( code != 200 )
333         printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory);
334     return(chunk.memory);
335 }
336
337 char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
338 {
339     //static void *cHandle;
340     char url[512],*retstr=0,*retstr2=0,postdata[8192];
341     if ( params == 0 || params[0] == 0 )
342         params = (char *)"[]";
343     if ( strlen(params) < sizeof(postdata)-128 )
344     {
345         sprintf(url,(char *)"http://127.0.0.1:%u",port);
346         sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params);
347         //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS);
348         retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params);
349         //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0);
350     }
351     return(retstr2);
352 }
353
354 int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp)
355 {
356     char *jsonstr,params[256],*userpass; uint16_t port; cJSON *json,*item; int32_t height = 0,txid_height = 0,txid_confirmations = 0;
357     params[0] = 0;
358     *kmdnotarized_heightp = 0;
359     if ( strcmp(dest,"KMD") == 0 )
360     {
361         port = KMD_PORT;
362         userpass = KMDUSERPASS;
363     }
364     else if ( strcmp(dest,"BTC") == 0 )
365     {
366         port = 8332;
367         userpass = BTCUSERPASS;
368     }
369     else return(0);
370     if ( userpass[0] != 0 )
371     {
372         if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getinfo",params,port)) != 0 )
373         {
374             //printf("(%s)\n",jsonstr);
375             if ( (json= cJSON_Parse(jsonstr)) != 0 )
376             {
377                 if ( (item= jobj(json,(char *)"result")) != 0 )
378                 {
379                     height = jint(item,(char *)"blocks");
380                     *kmdnotarized_heightp = strcmp(dest,"KMD") == 0 ? jint(item,(char *)"notarized") : height;
381                 }
382                 free_json(json);
383             }
384             free(jsonstr);
385         }
386         sprintf(params,"[\"%s\", 1]",txidstr);
387         if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getrawtransaction",params,port)) != 0 )
388         {
389             //printf("(%s)\n",jsonstr);
390             if ( (json= cJSON_Parse(jsonstr)) != 0 )
391             {
392                 if ( (item= jobj(json,(char *)"result")) != 0 )
393                 {
394                     txid_confirmations = jint(item,(char *)"confirmations");
395                     if ( txid_confirmations > 0 && height > txid_confirmations )
396                         txid_height = height - txid_confirmations;
397                     else txid_height = height;
398                     //printf("height.%d tconfs.%d txid_height.%d\n",height,txid_confirmations,txid_height);
399                 }
400                 free_json(json);
401             }
402             free(jsonstr);
403         }
404     }
405     return(txid_height);
406 }
407
408 int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH)
409 {
410     int32_t i; uint256 hash; char params[256];
411     for (i=0; i<32; i++)
412         ((uint8_t *)&hash)[i] = script[2+i];
413     if ( hash == NOTARIZED_HASH )
414         return(1);
415     for (i=0; i<32; i++)
416         printf("%02x",((uint8_t *)&NOTARIZED_HASH)[i]);
417     printf(" notarized, ");
418     for (i=0; i<32; i++)
419         printf("%02x",((uint8_t *)&hash)[i]);
420     printf(" opreturn from [%s] ht.%d MISMATCHED\n",ASSETCHAINS_SYMBOL,height);
421     return(-1);
422 }
423
424 int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
425 {
426     char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
427     script = _script;
428     /*params[0] = '[';
429      params[1] = '"';
430      for (i=0; i<32; i++)
431      sprintf(&params[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
432      strcat(params,"\", 1]");*/
433     sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
434     if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
435         return(0);
436     if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
437         printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",ASSETCHAINS_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT);
438     if ( strcmp(dest,"KMD") == 0 )
439     {
440         if ( KMDUSERPASS[0] != 0 )
441         {
442             if ( ASSETCHAINS_SYMBOL[0] != 0 )
443             {
444                 jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT);
445                 //printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr);
446             }
447         }//else jsonstr = _dex_getrawtransaction();
448         else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
449     }
450     else if ( strcmp(dest,"BTC") == 0 )
451     {
452         if ( BTCUSERPASS[0] != 0 )
453         {
454             //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS);
455             jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332);
456         }
457         //else jsonstr = _dex_getrawtransaction();
458         else return(0);
459     }
460     else
461     {
462         printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest);
463         return(-1);
464     }
465     if ( jsonstr != 0 )
466     {
467         if ( (json= cJSON_Parse(jsonstr)) != 0 )
468         {
469             if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 )
470             {
471                 vout = jitem(vouts,n-1);
472                 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
473                     printf("vout.(%s)\n",jprint(vout,0));
474                 if ( (skey= jobj(vout,(char *)"scriptPubKey")) != 0 )
475                 {
476                     if ( (hexstr= jstr(skey,(char *)"hex")) != 0 )
477                     {
478                         //printf("HEX.(%s) vs hash.%s\n",hexstr,NOTARIZED_HASH.ToString().c_str());
479                         len = strlen(hexstr) >> 1;
480                         decode_hex(script,len,hexstr);
481                         if ( script[1] == 0x4c )
482                         {
483                             script++;
484                             len--;
485                         }
486                         else if ( script[1] == 0x4d )
487                         {
488                             script += 2;
489                             len -= 2;
490                         }
491                         retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH);
492                     }
493                 }
494             }
495             free_json(txjson);
496         }
497         free(jsonstr);
498     }
499     return(retval);
500 }
501
502 /*uint256 komodo_getblockhash(int32_t height)
503  {
504  uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
505  memset(&hash,0,sizeof(hash));
506  sprintf(params,"[%d]",height);
507  if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_RPCPORT)) != 0 )
508  {
509  if ( (result= cJSON_Parse(jsonstr)) != 0 )
510  {
511  if ( (hexstr= jstr(result,(char *)"result")) != 0 )
512  {
513  if ( is_hexstr(hexstr,0) == 64 )
514  {
515  decode_hex(revbuf,32,hexstr);
516  for (i=0; i<32; i++)
517  ((uint8_t *)&hash)[i] = revbuf[31-i];
518  }
519  }
520  free_json(result);
521  }
522  printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
523  free(jsonstr);
524  }
525  return(hash);
526  }
527  
528  uint256 _komodo_getblockhash(int32_t height);*/
529
530 uint64_t komodo_seed(int32_t height)
531 {
532     uint64_t seed = 0;
533     /*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
534      {
535      uint256 hash,zero; CBlockIndex *pindex;
536      memset(&hash,0,sizeof(hash));
537      memset(&zero,0,sizeof(zero));
538      if ( height > 10 )
539      height -= 10;
540      if ( ASSETCHAINS_SYMBOL[0] == 0 )
541      hash = _komodo_getblockhash(height);
542      if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
543      hash = komodo_getblockhash(height);
544      int32_t i;
545      for (i=0; i<32; i++)
546      printf("%02x",((uint8_t *)&hash)[i]);
547      printf(" seed.%d\n",height);
548      seed = arith_uint256(hash.GetHex()).GetLow64();
549      }
550      else*/
551     {
552         seed = (height << 13) ^ (height << 2);
553         seed <<= 21;
554         seed |= (height & 0xffffffff);
555         seed ^= (seed << 17) ^ (seed << 1);
556     }
557     return(seed);
558 }
559
560 uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
561 {
562     CTxDestination address; CTransaction tx; uint256 hashBlock;
563     *valuep = 0;
564     if (!GetTransaction(hash, tx,
565 #ifndef KOMODO_ZCASH
566                         Params().GetConsensus(),
567 #endif
568                         hashBlock, true))
569     {
570         //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
571         return(0);
572     }
573     //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
574     if ( n < tx.vout.size() )
575     {
576         *valuep = tx.vout[n].nValue;
577         if (ExtractDestination(tx.vout[n].scriptPubKey, address))
578             strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
579     }
580     return(tx.nLockTime);
581 }
582
583 uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
584 {
585     CTxDestination address; CBlockIndex *pindex; CTransaction tx; uint256 hashBlock; uint32_t txtime = 0;
586     *valuep = 0;
587     if (!GetTransaction(hash, tx,
588 #ifndef KOMODO_ZCASH
589                         Params().GetConsensus(),
590 #endif
591                         hashBlock, true))
592     {
593         //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
594         return(0);
595     }
596     if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
597         txtime = pindex->nTime;
598     else txtime = tx.nLockTime;
599     //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
600     if ( n < tx.vout.size() )
601     {
602         *valuep = tx.vout[n].nValue;
603         if (ExtractDestination(tx.vout[n].scriptPubKey, address))
604             strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
605     }
606     return(txtime);
607 }
608
609 int32_t komodo_isPoS(CBlock *pblock)
610 {
611     int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
612     if ( ASSETCHAINS_STAKED != 0 )
613     {
614         if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 )
615         {
616             txid = pblock->vtx[n-1].vin[0].prevout.hash;
617             vout = pblock->vtx[n-1].vin[0].prevout.n;
618             txtime = komodo_txtime(&value,txid,vout,destaddr);
619             if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
620             {
621                 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
622                 if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[n-1].vout[0].nValue == value )
623                 {
624                     //fprintf(stderr,"is PoS block!\n");
625                     return(1);
626                 }
627             }
628         }
629     }
630     return(0);
631 }
632
633 void komodo_disconnect(CBlockIndex *pindex,CBlock& block)
634 {
635     char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
636     //fprintf(stderr,"disconnect ht.%d\n",pindex->nHeight);
637     komodo_init(pindex->nHeight);
638     if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
639     {
640         //sp->rewinding = pindex->nHeight;
641         //fprintf(stderr,"-%d ",pindex->nHeight);
642     } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->nHeight,ASSETCHAINS_SYMBOL);
643 }
644
645 int32_t komodo_is_notarytx(const CTransaction& tx)
646 {
647     uint8_t *ptr; static uint8_t crypto777[33];
648     if ( tx.vout.size() > 0 )
649     {
650 #ifdef KOMODO_ZCASH
651         ptr = (uint8_t *)tx.vout[0].scriptPubKey.data();
652 #else
653         ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0];
654 #endif
655         if ( ptr != 0 )
656         {
657             if ( crypto777[0] == 0 )
658                 decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
659             if ( memcmp(ptr+1,crypto777,33) == 0 )
660             {
661                 //printf("found notarytx\n");
662                 return(1);
663             }
664         }
665     }
666     return(0);
667 }
668
669 int32_t komodo_block2height(CBlock *block)
670 {
671     static uint32_t match,mismatch;
672     int32_t i,n,height2=-1,height = 0; uint8_t *ptr; CBlockIndex *pindex;
673     if ( (pindex= mapBlockIndex[block->GetHash()]) != 0 )
674     {
675         height2 = (int32_t)pindex->nHeight;
676         if ( height2 >= 0 )
677             return(height2);
678     }
679     if ( block->vtx[0].vin.size() > 0 )
680     {
681 #ifdef KOMODO_ZCASH
682         ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data();
683 #else
684         ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
685 #endif
686         if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
687         {
688             //for (i=0; i<6; i++)
689             //    printf("%02x",ptr[i]);
690             n = ptr[0];
691             for (i=0; i<n; i++) // looks strange but this works
692             {
693                 //03bb81000101(bb 187) (81 48001) (00 12288256)  <- coinbase.6 ht.12288256
694                 height += ((uint32_t)ptr[i+1] << (i*8));
695                 //printf("(%02x %x %d) ",ptr[i+1],((uint32_t)ptr[i+1] << (i*8)),height);
696             }
697             //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
698         }
699         //komodo_init(height);
700     }
701     if ( height != height2 )
702     {
703         //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch);
704         mismatch++;
705         if ( height2 >= 0 )
706             height = height2;
707     } else match++;
708     return(height);
709 }
710
711 int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
712 {
713     int32_t n;
714     if ( KOMODO_LOADINGBLOCKS == 0 )
715         memset(pubkey33,0xff,33);
716     else memset(pubkey33,0,33);
717     if ( block->vtx[0].vout.size() > 0 )
718     {
719 #ifdef KOMODO_ZCASH
720         uint8_t *ptr = (uint8_t *)block->vtx[0].vout[0].scriptPubKey.data();
721 #else
722         uint8_t *ptr = (uint8_t *)&block->vtx[0].vout[0].scriptPubKey[0];
723 #endif
724         //komodo_init(0);
725         n = block->vtx[0].vout[0].scriptPubKey.size();
726         if ( n == 35 )
727         {
728             memcpy(pubkey33,ptr+1,33);
729             return(1);
730         }
731     }
732     return(0);
733 }
734
735 int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
736 {
737     block.SetNull();
738     // Open history file to read
739     CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION);
740     if (filein.IsNull())
741         return(-1);
742     // Read block
743     try { filein >> block; }
744     catch (const std::exception& e)
745     {
746         fprintf(stderr,"readblockfromdisk err B\n");
747         return(-1);
748     }
749     return(0);
750 }
751
752 uint32_t komodo_chainactive_timestamp()
753 {
754     if ( chainActive.Tip() != 0 )
755         return((uint32_t)chainActive.Tip()->GetBlockTime());
756     else return(0);
757 }
758
759 CBlockIndex *komodo_chainactive(int32_t height)
760 {
761     if ( chainActive.Tip() != 0 )
762     {
763         if ( height <= chainActive.Tip()->nHeight )
764             return(chainActive[height]);
765         // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.Tip()->nHeight);
766     }
767     //fprintf(stderr,"komodo_chainactive null chainActive.Tip() height %d\n",height);
768     return(0);
769 }
770
771 uint32_t komodo_heightstamp(int32_t height)
772 {
773     CBlockIndex *ptr;
774     if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
775         return(ptr->nTime);
776     //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
777     return(0);
778 }
779
780 /*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted
781 {
782     int32_t i,num; uint8_t pubkeys[64][33]; CBlock block;
783     if ( pindex->didinit != 0 )
784         return;
785     //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->nHeight,pindex->notaryid,height);
786     if ( pindex->didinit == 0 )
787     {
788         pindex->notaryid = -1;
789         if ( KOMODO_LOADINGBLOCKS == 0 )
790             memset(pindex->pubkey33,0xff,33);
791         else memset(pindex->pubkey33,0,33);
792         if ( komodo_blockload(block,pindex) == 0 )
793         {
794             komodo_block2pubkey33(pindex->pubkey33,&block);
795             //for (i=0; i<33; i++)
796             //    fprintf(stderr,"%02x",pindex->pubkey33[i]);
797             //fprintf(stderr," set pubkey at height %d/%d\n",pindex->nHeight,height);
798             //if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 )
799             //    pindex->didinit = (KOMODO_LOADINGBLOCKS == 0);
800         } // else fprintf(stderr,"error loading block at %d/%d",pindex->nHeight,height);
801     }
802     if ( pindex->didinit != 0 && pindex->nHeight >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->nHeight,(uint32_t)pindex->nTime)) > 0 )
803     {
804         for (i=0; i<num; i++)
805         {
806             if ( memcmp(pubkeys[i],pindex->pubkey33,33) == 0 )
807             {
808                 pindex->notaryid = i;
809                 break;
810             }
811         }
812         if ( 0 && i == num )
813         {
814             for (i=0; i<33; i++)
815                 fprintf(stderr,"%02x",pindex->pubkey33[i]);
816             fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->nHeight,height);
817         }
818     }
819 }*/
820
821 void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
822 {
823     int32_t num,i; CBlock block;
824     memset(pubkey33,0,33);
825     if ( pindex != 0 )
826     {
827         if ( komodo_blockload(block,pindex) == 0 )
828             komodo_block2pubkey33(pubkey33,&block);
829     }
830 }
831
832 /*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33)
833 {
834     int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t pubkey33[33],pubkeys[64][33];
835     if ( (pindex= chainActive[height]) != 0 )
836     {
837         if ( pindex->didinit != 0 )
838         {
839             if ( destpubkey33 != 0 )
840                 memcpy(destpubkey33,pindex->pubkey33,33);
841             return(pindex->notaryid);
842         }
843         komodo_index2pubkey33(pubkey33,pindex,height);
844         if ( destpubkey33 != 0 )
845             memcpy(destpubkey33,pindex->pubkey33,33);
846         if ( pindex->didinit != 0 )
847             return(pindex->notaryid);
848         timestamp = pindex->GetBlockTime();
849         if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 )
850         {
851             for (i=0; i<num; i++)
852                 if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
853                     return(i);
854         }
855     }
856     fprintf(stderr,"komodo_minerid height.%d null pindex\n",height);
857     return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp));
858 }*/
859
860 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height)
861 {
862     int32_t i,j,n,duplicate; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33];
863     memset(mids,-1,sizeof(*mids)*66);
864     n = komodo_notaries(notarypubs33,height,0);
865     for (i=duplicate=0; i<66; i++)
866     {
867         if ( (pindex= komodo_chainactive(height-i)) != 0 )
868         {
869             blocktimes[i] = pindex->nTime;
870             if ( komodo_blockload(block,pindex) == 0 )
871             {
872                 komodo_block2pubkey33(pubkeys[i],&block);
873                 for (j=0; j<n; j++)
874                 {
875                     if ( memcmp(notarypubs33[j],pubkeys[i],33) == 0 )
876                     {
877                         mids[i] = j;
878                         (*nonzpkeysp)++;
879                         break;
880                     }
881                 }
882             } else fprintf(stderr,"couldnt load block.%d\n",height);
883             if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
884                 duplicate++;
885         }
886     }
887     if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
888         return(1);
889     else return(0);
890 }
891
892 int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
893 {
894     int32_t i,j,n,nonz,numnotaries; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33],pubkey33[33];
895     numnotaries = komodo_notaries(notarypubs33,height,0);
896     for (i=nonz=0; i<width; i++,n++)
897     {
898         if ( height-i <= 0 )
899             continue;
900         if ( (pindex= komodo_chainactive(height-width+i+1)) != 0 )
901         {
902             if ( komodo_blockload(block,pindex) == 0 )
903             {
904                 komodo_block2pubkey33(pubkey33,&block);
905                 for (j=0; j<numnotaries; j++)
906                 {
907                     if ( memcmp(notarypubs33[j],pubkey33,33) == 0 )
908                     {
909                         minerids[nonz++] = j;
910                         break;
911                     }
912                 }
913                 if ( j == numnotaries )
914                     minerids[nonz++] = j;
915             } else fprintf(stderr,"couldnt load block.%d\n",height);
916         }
917     }
918     return(nonz);
919 }
920
921 int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],uint32_t blocktimes[66],int32_t height,uint8_t pubkey33[33],uint32_t blocktime)
922 {
923     int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33];
924     komodo_chosennotary(&notaryid,height,pubkey33,blocktimes[0]);
925     if ( height >= 82000 )
926     {
927         if ( notaryid >= 0 )
928         {
929             for (i=1; i<66; i++)
930             {
931                 if ( mids[i] == notaryid )
932                 {
933                     if ( height > 792000 )
934                     {
935                         for (j=0; j<66; j++)
936                             fprintf(stderr,"%d ",mids[j]);
937                         fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
938                         return(-1);
939                     } else break;
940                 }
941             }
942             if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 )
943             {
944                 if ( height > 807000 )
945                     return(-2);
946             }
947             return(1);
948         } else return(0);
949     }
950     else
951     {
952         if ( height >= 34000 && notaryid >= 0 )
953         {
954             if ( height < 79693 )
955                 limit = 64;
956             else if ( height < 82000 )
957                 limit = 8;
958             else limit = 66;
959             for (i=1; i<limit; i++)
960             {
961                 komodo_chosennotary(&nid,height-i,pubkey33,blocktimes[i]);
962                 if ( nid == notaryid )
963                 {
964                     //for (j=0; j<66; j++)
965                     //    fprintf(stderr,"%d ",mids[j]);
966                     //fprintf(stderr,"ht.%d repeat mids[%d] nid.%d notaryid.%d\n",height-i,i,nid,notaryid);
967                     if ( height > 225000 )
968                         return(-1);
969                 }
970             }
971             //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
972             return(1);
973         }
974     }
975     return(0);
976 }
977
978 int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip)
979 {
980     int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
981     depth = komodo_MoMdata(&notarized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip);
982     memset(MoMp,0,sizeof(*MoMp));
983     memset(kmdtxidp,0,sizeof(*kmdtxidp));
984     *notarized_heightp = 0;
985     if ( depth != 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
986     {
987         *MoMp = MoM;
988         *notarized_heightp = notarized_ht;
989         *kmdtxidp = kmdtxid;
990     }
991     return(depth);
992 }
993
994 int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
995 {
996     int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
997     if ( (pindex= chainActive.Tip()) == 0 )
998         return(-1);
999     notarized_height = komodo_notarizeddata(pindex->nHeight,&notarized_hash,&notarized_desttxid);
1000     *notarized_heightp = notarized_height;
1001     if ( notarized_height >= 0 && notarized_height <= pindex->nHeight && (notary= mapBlockIndex[notarized_hash]) != 0 )
1002     {
1003         //printf("nHeight.%d -> (%d %s)\n",pindex->Tip()->nHeight,notarized_height,notarized_hash.ToString().c_str());
1004         if ( notary->nHeight == notarized_height ) // if notarized_hash not in chain, reorg
1005         {
1006             if ( nHeight < notarized_height )
1007             {
1008                 //fprintf(stderr,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1009                 return(-1);
1010             }
1011             else if ( nHeight == notarized_height && memcmp(&hash,&notarized_hash,sizeof(hash)) != 0 )
1012             {
1013                 fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1014                 return(-1);
1015             }
1016         } //else fprintf(stderr,"[%s] unexpected error notary_hash %s ht.%d at ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,notary->nHeight);
1017     }
1018     //else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
1019     //    fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight);
1020     return(0);
1021 }
1022
1023 uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
1024 {
1025     LOCK(cs_main);
1026     CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
1027     *txheighttimep = *txheightp = *tiptimep = 0;
1028     *valuep = 0;
1029     if ( !GetTransaction(hash,tx,hashBlock,true) )
1030         return(0);
1031     uint32_t locktime = 0;
1032     if ( n < tx.vout.size() )
1033     {
1034         if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
1035         {
1036             *valuep = tx.vout[n].nValue;
1037             *txheightp = pindex->nHeight;
1038             *txheighttimep = pindex->nTime;
1039             if ( *tiptimep == 0 && (tipindex= chainActive.Tip()) != 0 )
1040                 *tiptimep = (uint32_t)tipindex->nTime;
1041             locktime = tx.nLockTime;
1042             //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
1043         }
1044     }
1045     return(locktime);
1046 }
1047
1048 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
1049
1050 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight)
1051 {
1052     uint64_t value; uint32_t tiptime=0,txheighttimep; CBlockIndex *pindex;
1053     if ( (pindex= chainActive[tipheight]) != 0 )
1054         tiptime = (uint32_t)pindex->nTime;
1055     else fprintf(stderr,"cant find height[%d]\n",tipheight);
1056     if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 )
1057     {
1058         if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
1059             return(komodo_interest(*txheightp,value,*locktimep,tiptime));
1060         //fprintf(stderr,"nValue %llu lock.%u:%u nTime.%u -> %llu\n",(long long)coins.vout[n].nValue,coins.nLockTime,timestamp,pindex->nTime,(long long)interest);
1061         else fprintf(stderr,"komodo_accrued_interest value mismatch %llu vs %llu or height mismatch %d vs %d\n",(long long)value,(long long)checkvalue,*txheightp,checkheight);
1062     }
1063     return(0);
1064 }
1065
1066 int32_t komodo_isrealtime(int32_t *kmdheightp)
1067 {
1068     struct komodo_state *sp; CBlockIndex *pindex;
1069     if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
1070         *kmdheightp = sp->CURRENT_HEIGHT;
1071     else *kmdheightp = 0;
1072     if ( (pindex= chainActive.Tip()) != 0 && pindex->nHeight >= (int32_t)komodo_longestchain() )
1073         return(1);
1074     else return(0);
1075 }
1076
1077 int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
1078 {
1079     if ( KOMODO_REWIND == 0 && (ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED != 0) && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
1080     {
1081         if ( txheight > 246748 || ASSETCHAINS_STAKED != 0 )
1082         {
1083             if ( txheight < 247205 && ASSETCHAINS_STAKED == 0 )
1084                 cmptime -= 16000;
1085             if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
1086             {
1087                 if ( tx.nLockTime != 1477258935 && dispflag != 0 )
1088                 {
1089                     fprintf(stderr,"komodo_validate_interest.%d reject.%d [%d] locktime %u cmp2.%u\n",dispflag,txheight,(int32_t)(tx.nLockTime - (cmptime-KOMODO_MAXMEMPOOLTIME)),(uint32_t)tx.nLockTime,cmptime);
1090                 }
1091                 return(-1);
1092             }
1093             if ( 0 && dispflag != 0 )
1094                 fprintf(stderr,"validateinterest.%d accept.%d [%d] locktime %u cmp2.%u\n",dispflag,(int32_t)txheight,(int32_t)(tx.nLockTime - (cmptime-KOMODO_MAXMEMPOOLTIME)),(int32_t)tx.nLockTime,cmptime);
1095         }
1096     }
1097     return(0);
1098 }
1099
1100 /*
1101  komodo_checkPOW (fast) is called early in the process and should only refer to data immediately available. it is a filter to prevent bad blocks from going into the local DB. The more blocks we can filter out at this stage, the less junk in the local DB that will just get purged later on.
1102  
1103  komodo_checkPOW (slow) is called right before connecting blocks so all prior blocks can be assumed to be there and all checks must pass
1104  
1105  commission must be in coinbase.vout[1] and must be >= 10000 sats
1106  PoS stake must be without txfee and in the last tx in the block at vout[0]
1107  */
1108 //#define KOMODO_POWMINMULT 16
1109
1110 uint64_t komodo_commission(const CBlock *pblock)
1111 {
1112     int32_t i,j,n=0,txn_count; uint64_t commission,total = 0;
1113     txn_count = pblock->vtx.size();
1114     for (i=0; i<txn_count; i++)
1115     {
1116         n = pblock->vtx[i].vout.size();
1117         for (j=0; j<n; j++)
1118         {
1119             //fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
1120             if ( i != 0 || j != 1 )
1121                 total += pblock->vtx[i].vout[j].nValue;
1122         }
1123     }
1124     //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN));
1125     commission = ((total * ASSETCHAINS_COMMISSION) / COIN);
1126     if ( commission < 10000 )
1127         commission = 0;
1128     return(commission);
1129 }
1130
1131 uint32_t komodo_segid32(char *coinaddr)
1132 {
1133     bits256 addrhash;
1134     vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
1135     return(addrhash.uints[0]);
1136 }
1137
1138 int8_t komodo_segid(int32_t height)
1139 {
1140     CTxDestination voutaddress; CBlock block; CBlockIndex *pindex; uint64_t value; uint32_t txtime; char voutaddr[64],destaddr[64]; int32_t txn_count,vout; uint256 txid; int8_t segid = -1;
1141     if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
1142     {
1143         if ( komodo_blockload(block,pindex) == 0 )
1144         {
1145             txn_count = block.vtx.size();
1146             if ( txn_count > 1 && block.vtx[txn_count-1].vin.size() == 1 && block.vtx[txn_count-1].vout.size() == 1 )
1147             {
1148                 txid = block.vtx[txn_count-1].vin[0].prevout.hash;
1149                 vout = block.vtx[txn_count-1].vin[0].prevout.n;
1150                 txtime = komodo_txtime(&value,txid,vout,destaddr);
1151                 if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
1152                 {
1153                     strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
1154                     if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
1155                     {
1156                         segid = komodo_segid32(voutaddr) & 0x3f;
1157                     }
1158                 } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
1159             }
1160         }
1161     }
1162     return(segid);
1163 }
1164
1165 int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
1166 {
1167     static uint8_t prevhashbuf[100]; static int32_t prevheight;
1168     int32_t i;
1169     if ( height == prevheight && n == 100 )
1170         memcpy(hashbuf,prevhashbuf,100);
1171     else
1172     {
1173         memset(hashbuf,0xff,n);
1174         for (i=0; i<n; i++)
1175         {
1176             hashbuf[i] = (uint8_t)komodo_segid(height+i);
1177             //fprintf(stderr,"%02x ",hashbuf[i]);
1178         }
1179         if ( n == 100 )
1180         {
1181             memcpy(prevhashbuf,hashbuf,100);
1182             prevheight = height;
1183             //fprintf(stderr,"prevsegids.%d\n",height+n);
1184         }
1185     }
1186 }
1187
1188 uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr)
1189 {
1190     bool fNegative,fOverflow; uint8_t hashbuf[256]; char address[64]; bits256 addrhash; arith_uint256 hashval,mindiff,ratio; uint256 hash,pasthash; int32_t diff=0,segid,minage,i,iter=0; uint32_t txtime,winner = 0 ; uint64_t value,coinage;
1191     txtime = komodo_txtime2(&value,txid,vout,address);
1192     if ( validateflag == 0 && blocktime < GetAdjustedTime() )
1193         blocktime = GetAdjustedTime();
1194     if ( blocktime < prevtime+3 )
1195         blocktime = prevtime+3;
1196     if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
1197     {
1198         //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
1199         return(0);
1200     }
1201     if ( value < SATOSHIDEN )
1202         return(0);
1203     value /= SATOSHIDEN;
1204     mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1205     ratio = (mindiff / bnTarget);
1206     if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
1207         minage = 6000;
1208     vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
1209     segid = ((nHeight + addrhash.uints[0]) & 0x3f);
1210     komodo_segids(hashbuf,nHeight-101,100);
1211     memcpy(&hashbuf[100],&addrhash,sizeof(addrhash));
1212     memcpy(&hashbuf[100+sizeof(addrhash)],&txid,sizeof(txid));
1213     memcpy(&hashbuf[100+sizeof(addrhash)+sizeof(txid)],&vout,sizeof(vout));
1214     vcalc_sha256(0,(uint8_t *)&hash,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
1215     for (iter=0; iter<3600; iter++)
1216     {
1217         diff = (iter + blocktime - txtime - minage);
1218         if ( diff < 0 )
1219             diff = 60;
1220         else if ( diff > 3600*24*30 )
1221         {
1222             //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
1223             diff = 3600*24*30;
1224         }
1225         if ( iter > 0 )
1226             diff += segid*2;
1227         if ( blocktime+iter+segid*2 < txtime+minage )
1228             continue;
1229         coinage = (value * diff);
1230         hashval = ratio * (UintToArith256(hash) / arith_uint256(coinage+1));
1231         if ( hashval <= bnTarget )
1232         {
1233             winner = 1;
1234             if ( validateflag == 0 )
1235             {
1236                 blocktime += iter;
1237                 blocktime += segid * 2;
1238             }
1239             break;
1240         }
1241         if ( validateflag != 0 )
1242         {
1243             /*for (i=31; i>=24; i--)
1244                 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1245             fprintf(stderr," vs ");
1246             for (i=31; i>=24; i--)
1247                 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1248             fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff);*/
1249             break;
1250         }
1251     }
1252     //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
1253     if ( 0 && validateflag != 0 )
1254     {
1255         for (i=31; i>=24; i--)
1256             fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1257         fprintf(stderr," vs ");
1258         for (i=31; i>=24; i--)
1259             fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1260         fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d ht.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff,nHeight);
1261     }
1262     if ( nHeight < 10 )
1263         return(blocktime);
1264     return(blocktime * winner);
1265 }
1266
1267 arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
1268 {
1269     CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
1270     *percPoSp = percPoS = 0;
1271     if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
1272         return(target);
1273     sum = arith_uint256(0);
1274     ave = sum;
1275     easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1276     for (i=n=m=0; i<100; i++)
1277     {
1278         ht = height - 100 + i;
1279         if ( ht <= 1 )
1280             continue;
1281         if ( (pindex= komodo_chainactive(ht)) != 0 )
1282         {
1283             if ( komodo_segid(ht) >= 0 )
1284             {
1285                 n++;
1286                 percPoS++;
1287                 if ( ASSETCHAINS_STAKED < 100 )
1288                     fprintf(stderr,"0");
1289             }
1290             else
1291             {
1292                 if ( ASSETCHAINS_STAKED < 100 )
1293                     fprintf(stderr,"1");
1294                 sum += UintToArith256(pindex->GetBlockHash());
1295                 m++;
1296             }
1297         }
1298         /*if ( (pindex= komodo_chainactive(ht)) != 0 )
1299         {
1300             bnTarget.SetCompact(pindex->nBits,&fNegative,&fOverflow);
1301             bnTarget = (bnTarget / arith_uint256(KOMODO_POWMINMULT));
1302             hashval = UintToArith256(pindex->GetBlockHash());
1303             if ( hashval <= bnTarget ) // PoW is never as easy as PoS/16, some PoS will be counted as PoW
1304             {
1305                 if ( ASSETCHAINS_STAKED < 100 )
1306                     fprintf(stderr,"1");
1307                 sum += hashval;
1308                 n++;
1309             }
1310             else
1311             {
1312                 n++;
1313                 percPoS++;
1314                 if ( ASSETCHAINS_STAKED < 100 )
1315                     fprintf(stderr,"0");
1316             }
1317         }*/
1318         if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
1319             fprintf(stderr," %d, ",percPoS);
1320     }
1321     if ( m+n < 100 )
1322         percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
1323     if ( ASSETCHAINS_STAKED < 100 )
1324         fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
1325     *percPoSp = percPoS;
1326     //target = (target / arith_uint256(KOMODO_POWMINMULT));
1327     if ( m > 0 )
1328     {
1329         ave = (sum / arith_uint256(m));
1330         if ( ave > target )
1331             ave = target;
1332     } else ave = easydiff; //else return(target);
1333     if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
1334     {
1335         bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
1336         if ( ASSETCHAINS_STAKED < 100 )
1337         {
1338             for (i=31; i>=24; i--)
1339                 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1340             fprintf(stderr," increase diff -> ");
1341             for (i=31; i>=24; i--)
1342                 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1343             fprintf(stderr," floor diff ");
1344             for (i=31; i>=24; i--)
1345                 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1346             fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1347         }
1348     }
1349     else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget
1350     {
1351         bnTarget = (ave * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc);
1352         if ( bnTarget > easydiff )
1353             bnTarget = easydiff;
1354         else if ( bnTarget < ave ) // overflow
1355         {
1356             bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1357             if ( bnTarget < ave )
1358                 bnTarget = ave;
1359         }
1360         if ( 1 )
1361         {
1362             for (i=31; i>=24; i--)
1363                 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1364             fprintf(stderr," decrease diff -> ");
1365             for (i=31; i>=24; i--)
1366                 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1367             fprintf(stderr," floor diff ");
1368             for (i=31; i>=24; i--)
1369                 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1370             fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1371         }
1372     }
1373     else bnTarget = ave; // recent ave is perfect
1374     return(bnTarget);
1375 }
1376
1377 int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget)
1378 {
1379     CBlockIndex *previndex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,txn_count,eligible=0,isPoS = 0; uint64_t value; CTxDestination voutaddress;
1380     if ( ASSETCHAINS_STAKED == 100 && height <= 10 )
1381         return(1);
1382     txn_count = pblock->vtx.size();
1383     if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 )
1384     {
1385         if ( prevtime == 0 )
1386         {
1387             if ( (previndex= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1388                 prevtime = (uint32_t)previndex->nTime;
1389         }
1390         txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1391         vout = pblock->vtx[txn_count-1].vin[0].prevout.n;
1392         if ( prevtime != 0 )
1393         {
1394             if ( komodo_isPoS(pblock) != 0 )
1395                 eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime,(char *)"");
1396             if ( eligible == 0 || eligible > pblock->nTime )
1397             {
1398                 fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime));
1399             } else isPoS = 1;
1400         }
1401         if ( slowflag == 0 ) // maybe previous block is not seen yet, do the best approx
1402         {
1403             if ( komodo_isPoS(pblock) != 0 )
1404                 isPoS = 1;
1405             /*txtime = komodo_txtime(&value,txid,vout,destaddr);
1406             if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
1407             {
1408                 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
1409                 if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[txn_count-1].vout[0].nValue == value )
1410                     isPoS = 1; // close enough for a pre-filter
1411                 //else fprintf(stderr,"komodo_is_PoSblock ht.%d (%s) != (%s) or %.8f != %.8f\n",height,destaddr,voutaddr,dstr(value),dstr(pblock->vtx[txn_count-1].vout[0].nValue));
1412             } else fprintf(stderr,"komodo_is_PoSblock ht.%d couldnt extract voutaddress\n",height);*/
1413         } //else return(-1);
1414     }
1415     //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
1416     return(isPoS);
1417 }
1418
1419 int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1420 {
1421     int64_t checktoshis=0; uint8_t *script;
1422     if ( ASSETCHAINS_COMMISSION != 0 )
1423     {
1424         checktoshis = komodo_commission(pblock);
1425         if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1426             return(-1);
1427         else if ( checktoshis != 0 )
1428         {
1429             script = (uint8_t *)pblock->vtx[0].vout[1].scriptPubKey.data();
1430             if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1431                 return(-1);
1432             if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1433             {
1434                 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1435                 return(-1);
1436             }
1437         }
1438     }
1439     return(checktoshis);
1440 }
1441
1442 bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1443
1444 int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1445 {
1446     uint256 hash; arith_uint256 bnTarget,bhash; bool fNegative,fOverflow; uint8_t *script,pubkey33[33],pubkeys[64][33]; int32_t i,possible,PoSperc,is_PoSblock=0,n,failed = 0,notaryid = -1; int64_t checktoshis,value; CBlockIndex *pprev;
1447     if ( !CheckEquihashSolution(pblock, Params()) )
1448     {
1449         fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1450         return(-1);
1451     }
1452     hash = pblock->GetHash();
1453     bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1454     bhash = UintToArith256(hash);
1455     possible = komodo_block2pubkey33(pubkey33,pblock);
1456     //fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
1457     if ( height == 0 )
1458     {
1459         if ( slowflag != 0 )
1460             return(0);
1461         if ( (pprev= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1462             height = pprev->nHeight + 1;
1463         if ( height == 0 )
1464             return(0);
1465     }
1466     if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget )
1467     {
1468         failed = 1;
1469         if ( height > 0 && ASSETCHAINS_SYMBOL[0] == 0 ) // for the fast case
1470         {
1471             if ( (n= komodo_notaries(pubkeys,height,pblock->nTime)) > 0 )
1472             {
1473                 for (i=0; i<n; i++)
1474                     if ( memcmp(pubkey33,pubkeys[i],33) == 0 )
1475                     {
1476                         notaryid = i;
1477                         break;
1478                     }
1479             }
1480         }
1481         else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 )
1482         {
1483             if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW )
1484                 return(0);
1485             if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget
1486                 return(-1);
1487         }
1488     }
1489     if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
1490     {
1491         if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget)) == 0 )
1492         {
1493             if ( ASSETCHAINS_STAKED == 100 && height > 100 )  // only PoS allowed! POSTEST64
1494                 return(-1);
1495             else
1496             {
1497                 if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target
1498                     return(0);
1499                 if ( slowflag != 0 )
1500                     bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1501                 if ( bhash > bnTarget )
1502                 {
1503                     for (i=31; i>=16; i--)
1504                         fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]);
1505                     fprintf(stderr," > ");
1506                     for (i=31; i>=16; i--)
1507                         fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1508                     fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED);
1509                     return(-1);
1510                 }
1511             }
1512         } else if ( is_PoSblock < 0 )
1513             return(-1);
1514     }
1515     if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
1516     {
1517         if ( height == 1 )
1518         {
1519             script = (uint8_t *)pblock->vtx[0].vout[0].scriptPubKey.data();
1520             if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1521                 return(-1);
1522         }
1523         else
1524         {
1525             if ( komodo_checkcommission(pblock,height) < 0 )
1526                 return(-1);
1527         }
1528     }
1529     //fprintf(stderr,"komodo_checkPOW possible.%d slowflag.%d ht.%d notaryid.%d failed.%d\n",possible,slowflag,height,notaryid,failed);
1530     if ( failed != 0 && possible == 0 && notaryid < 0 )
1531         return(-1);
1532     else return(0);
1533 }
1534
1535 int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
1536 {
1537     int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
1538     n = pblock->vtx.size();
1539     for (i=0; i<n; i++)
1540     {
1541         CTransaction vintx,&tx = pblock->vtx[i];
1542         zfunds += (tx.GetJoinSplitValueOut() - tx.GetJoinSplitValueIn());
1543         if ( (m= tx.vin.size()) > 0 )
1544         {
1545             for (j=0; j<m; j++)
1546             {
1547                 if ( i == 0 )
1548                     continue;
1549                 txid = tx.vin[j].prevout.hash;
1550                 vout = tx.vin[j].prevout.n;
1551                 if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
1552                 {
1553                     fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1554                     return(0);
1555                 }
1556                 vinsum += vintx.vout[vout].nValue;
1557             }
1558         }
1559         if ( (m= tx.vout.size()) > 0 )
1560         {
1561             for (j=0; j<m-1; j++)
1562                 voutsum += tx.vout[j].nValue;
1563             script = (uint8_t *)tx.vout[j].scriptPubKey.data();
1564             if ( script == 0 || script[0] != 0x6a )
1565                 voutsum += tx.vout[j].nValue;
1566         }
1567     }
1568     *zfundsp = zfunds;
1569     if ( voutsum-vinsum > 100000*SATOSHIDEN || voutsum-vinsum < 0 )
1570         fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
1571     return(voutsum - vinsum);
1572 }
1573
1574 int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
1575 {
1576     CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
1577     //fprintf(stderr,"coinsupply %d\n",height);
1578     *zfundsp = 0;
1579     if ( (pindex= komodo_chainactive(height)) != 0 )
1580     {
1581         while ( pindex != 0 && pindex->nHeight > 0 )
1582         {
1583             if ( pindex->newcoins == 0 )
1584             {
1585                 if ( komodo_blockload(block,pindex) == 0 )
1586                     pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->nHeight,&block);
1587                 else
1588                 {
1589                     fprintf(stderr,"error loading block.%d\n",pindex->nHeight);
1590                     return(0);
1591                 }
1592             }
1593             supply += pindex->newcoins;
1594             zfunds += pindex->zfunds;
1595             //printf("start ht.%d new %.8f -> supply %.8f\n",pindex->nHeight,dstr(pindex->newcoins),dstr(supply));
1596             pindex = pindex->pprev;
1597         }
1598     }
1599     *zfundsp = zfunds;
1600     return(supply);
1601 }
This page took 0.117085 seconds and 4 git commands to generate.