]> Git Repo - VerusCoin.git/blob - src/komodo_bitcoind.h
Fix stakeguard validation
[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 #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"
24
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);
28
29 //#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
30
31 struct MemoryStruct { char *memory; size_t size; };
32 struct return_string { char *ptr; size_t len; };
33
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)
38
39
40 /************************************************************************
41  *
42  * Initialize the string handler so that it is thread safe
43  *
44  ************************************************************************/
45
46 void init_string(struct return_string *s)
47 {
48     s->len = 0;
49     s->ptr = (char *)calloc(1,s->len+1);
50     if ( s->ptr == NULL )
51     {
52         fprintf(stderr,"init_string malloc() failed\n");
53         exit(-1);
54     }
55     s->ptr[0] = '\0';
56 }
57
58 /************************************************************************
59  *
60  * Use the "writer" to accumulate text until done
61  *
62  ************************************************************************/
63
64 size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s)
65 {
66     size_t new_len = s->len + size*nmemb;
67     s->ptr = (char *)realloc(s->ptr,new_len+1);
68     if ( s->ptr == NULL )
69     {
70         fprintf(stderr, "accumulate realloc() failed\n");
71         exit(-1);
72     }
73     memcpy(s->ptr+s->len,ptr,size*nmemb);
74     s->ptr[new_len] = '\0';
75     s->len = new_len;
76     return(size * nmemb);
77 }
78
79 /************************************************************************
80  *
81  * return the current system time in milliseconds
82  *
83  ************************************************************************/
84
85 #define EXTRACT_BITCOIND_RESULT  // if defined, ensures error is null and returns the "result" field
86 #ifdef EXTRACT_BITCOIND_RESULT
87
88 /************************************************************************
89  *
90  * perform post processing of the results
91  *
92  ************************************************************************/
93
94 char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params)
95 {
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 )
99     {
100         if ( strcmp(command,"signrawtransaction") != 0 )
101             printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
102         return(rpcstr);
103     }
104     json = cJSON_Parse(rpcstr);
105     if ( json == 0 )
106     {
107         printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params);
108         free(rpcstr);
109         return(0);
110     }
111     result = cJSON_GetObjectItem(json,"result");
112     error = cJSON_GetObjectItem(json,"error");
113     if ( error != 0 && result != 0 )
114     {
115         if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL )
116         {
117             retstr = cJSON_Print(result);
118             len = strlen(retstr);
119             if ( retstr[0] == '"' && retstr[len-1] == '"' )
120             {
121                 for (i=1,j=0; i<len-1; i++,j++)
122                     retstr[j] = retstr[i];
123                 retstr[j] = 0;
124             }
125         }
126         else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL )
127         {
128             if ( strcmp(command,"signrawtransaction") != 0 )
129                 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr);
130         }
131         free(rpcstr);
132     } else retstr = rpcstr;
133     free_json(json);
134     //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr);
135     return(retstr);
136 }
137 #endif
138
139 /************************************************************************
140  *
141  * perform the query
142  *
143  ************************************************************************/
144
145 char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params)
146 {
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;
150     if ( didinit == 0 )
151     {
152         didinit = 1;
153         curl_global_init(CURL_GLOBAL_ALL); //init the curl session
154     }
155     numretries = 0;
156     if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") ==  0 )
157         specialcase = 1;
158     else specialcase = 0;
159     if ( url[0] == 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);
163 try_again:
164     if ( retstrp != 0 )
165         *retstrp = 0;
166     starttime = OS_milliseconds();
167     curl_handle = curl_easy_init();
168     init_string(&s);
169     headers = curl_slist_append(0,"Expect:");
170     
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 )
179     {
180         curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0);
181         curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0);
182     }
183     if ( userpass != 0 )
184         curl_easy_setopt(curl_handle,CURLOPT_USERPWD,   userpass);
185     databuf = 0;
186     if ( params != 0 )
187     {
188         if ( command != 0 && specialcase == 0 )
189         {
190             len = strlen(params);
191             if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) {
192                 bracket0 = bracket1 = (char *)"";
193             }
194             else
195             {
196                 bracket0 = (char *)"[";
197                 bracket1 = (char *)"]";
198             }
199             
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);
203             //
204         } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params);
205         curl_easy_setopt(curl_handle,CURLOPT_POST,1L);
206         if ( databuf != 0 )
207             curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf);
208         else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params);
209     }
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
215     {
216         free(databuf);
217         databuf = 0;
218     }
219     if ( res != CURLE_OK )
220     {
221         numretries++;
222         if ( specialcase != 0 )
223         {
224             printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res);
225             free(s.ptr);
226             return(0);
227         }
228         else if ( numretries >= 1 )
229         {
230             //printf("Maximum number of retries exceeded!\n");
231             free(s.ptr);
232             return(0);
233         }
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);
236         free(s.ptr);
237         sleep((1<<numretries));
238         goto try_again;
239         
240     }
241     else
242     {
243         if ( command != 0 && specialcase == 0 )
244         {
245             count++;
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);
249             if ( retstrp != 0 )
250             {
251                 *retstrp = s.ptr;
252                 return(s.ptr);
253             }
254             return(post_process_bitcoind_RPC(debugstr,command,s.ptr,params));
255         }
256         else
257         {
258             if ( 0 && specialcase != 0 )
259                 fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: BTCD.(%s) -> (%s)\n",params,s.ptr);
260             count2++;
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);
264             return(s.ptr);
265         }
266     }
267     printf("bitcoind_RPC: impossible case\n");
268     free(s.ptr);
269     return(0);
270 }
271
272 static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data)
273 {
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 )
278     {
279         if ( ptr != 0 )
280             memcpy(&(mem->memory[mem->size]),ptr,realsize);
281         mem->size += realsize;
282         mem->memory[mem->size] = 0;
283     }
284     //printf("got %d bytes\n",(int32_t)(size*nmemb));
285     return(realsize);
286 }
287
288 char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3)
289 {
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);
294     //#ifdef DEBUG
295     //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
296     //#endif
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 )
305     {
306         curl_easy_setopt(cHandle,CURLOPT_POST,1);
307         curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
308     }
309     if ( hdr0 != NULL && hdr0[0] != 0 )
310     {
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:");
320     if ( headers != 0 )
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);
328     if ( headers != 0 )
329         curl_slist_free_all(headers);
330     if ( code != 200 )
331         printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory);
332     return(chunk.memory);
333 }
334
335 char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
336 {
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 )
342     {
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);
348     }
349     return(retstr2);
350 }
351
352 int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp)
353 {
354     char *jsonstr,params[256],*userpass; uint16_t port; cJSON *json,*item; int32_t height = 0,txid_height = 0,txid_confirmations = 0;
355     params[0] = 0;
356     *kmdnotarized_heightp = 0;
357     if ( strcmp(dest,"KMD") == 0 )
358     {
359         port = KMD_PORT;
360         userpass = KMDUSERPASS;
361     }
362     else if ( strcmp(dest,"BTC") == 0 )
363     {
364         port = 8332;
365         userpass = BTCUSERPASS;
366     }
367     else return(0);
368     if ( userpass[0] != 0 )
369     {
370         if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getinfo",params,port)) != 0 )
371         {
372             //printf("(%s)\n",jsonstr);
373             if ( (json= cJSON_Parse(jsonstr)) != 0 )
374             {
375                 if ( (item= jobj(json,(char *)"result")) != 0 )
376                 {
377                     height = jint(item,(char *)"blocks");
378                     *kmdnotarized_heightp = strcmp(dest,"KMD") == 0 ? jint(item,(char *)"notarized") : height;
379                 }
380                 free_json(json);
381             }
382             free(jsonstr);
383         }
384         sprintf(params,"[\"%s\", 1]",txidstr);
385         if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getrawtransaction",params,port)) != 0 )
386         {
387             //printf("(%s)\n",jsonstr);
388             if ( (json= cJSON_Parse(jsonstr)) != 0 )
389             {
390                 if ( (item= jobj(json,(char *)"result")) != 0 )
391                 {
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);
397                 }
398                 free_json(json);
399             }
400             free(jsonstr);
401         }
402     }
403     return(txid_height);
404 }
405
406 int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH)
407 {
408     int32_t i; uint256 hash; char params[256];
409     for (i=0; i<32; i++)
410         ((uint8_t *)&hash)[i] = script[2+i];
411     if ( hash == NOTARIZED_HASH )
412         return(1);
413     for (i=0; i<32; i++)
414         printf("%02x",((uint8_t *)&NOTARIZED_HASH)[i]);
415     printf(" notarized, ");
416     for (i=0; i<32; i++)
417         printf("%02x",((uint8_t *)&hash)[i]);
418     printf(" opreturn from [%s] ht.%d MISMATCHED\n",ASSETCHAINS_SYMBOL,height);
419     return(-1);
420 }
421
422 int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
423 {
424     char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
425     script = _script;
426     /*params[0] = '[';
427      params[1] = '"';
428      for (i=0; i<32; i++)
429      sprintf(&params[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 )
433         return(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 )
437     {
438         if ( KMDUSERPASS[0] != 0 )
439         {
440             if ( ASSETCHAINS_SYMBOL[0] != 0 )
441             {
442                 jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT);
443                 //printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr);
444             }
445         }//else jsonstr = _dex_getrawtransaction();
446         else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
447     }
448     else if ( strcmp(dest,"BTC") == 0 )
449     {
450         if ( BTCUSERPASS[0] != 0 )
451         {
452             //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS);
453             jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332);
454         }
455         //else jsonstr = _dex_getrawtransaction();
456         else return(0);
457     }
458     else
459     {
460         printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest);
461         return(-1);
462     }
463     if ( jsonstr != 0 )
464     {
465         if ( (json= cJSON_Parse(jsonstr)) != 0 )
466         {
467             if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 )
468             {
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 )
473                 {
474                     if ( (hexstr= jstr(skey,(char *)"hex")) != 0 )
475                     {
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 )
480                         {
481                             script++;
482                             len--;
483                         }
484                         else if ( script[1] == 0x4d )
485                         {
486                             script += 2;
487                             len -= 2;
488                         }
489                         retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH);
490                     }
491                 }
492             }
493             free_json(txjson);
494         }
495         free(jsonstr);
496     }
497     return(retval);
498 }
499
500 /*uint256 komodo_getblockhash(int32_t height)
501  {
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 )
506  {
507  if ( (result= cJSON_Parse(jsonstr)) != 0 )
508  {
509  if ( (hexstr= jstr(result,(char *)"result")) != 0 )
510  {
511  if ( is_hexstr(hexstr,0) == 64 )
512  {
513  decode_hex(revbuf,32,hexstr);
514  for (i=0; i<32; i++)
515  ((uint8_t *)&hash)[i] = revbuf[31-i];
516  }
517  }
518  free_json(result);
519  }
520  printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
521  free(jsonstr);
522  }
523  return(hash);
524  }
525  
526  uint256 _komodo_getblockhash(int32_t height);*/
527
528 uint64_t komodo_seed(int32_t height)
529 {
530     uint64_t seed = 0;
531     /*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
532      {
533      uint256 hash,zero; CBlockIndex *pindex;
534      memset(&hash,0,sizeof(hash));
535      memset(&zero,0,sizeof(zero));
536      if ( height > 10 )
537      height -= 10;
538      if ( ASSETCHAINS_SYMBOL[0] == 0 )
539      hash = _komodo_getblockhash(height);
540      if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
541      hash = komodo_getblockhash(height);
542      int32_t i;
543      for (i=0; i<32; i++)
544      printf("%02x",((uint8_t *)&hash)[i]);
545      printf(" seed.%d\n",height);
546      seed = arith_uint256(hash.GetHex()).GetLow64();
547      }
548      else*/
549     {
550         seed = (height << 13) ^ (height << 2);
551         seed <<= 21;
552         seed |= (height & 0xffffffff);
553         seed ^= (seed << 17) ^ (seed << 1);
554     }
555     return(seed);
556 }
557
558 uint32_t komodo_txtime(uint64_t *valuep,uint256 hash, int32_t n, char *destaddr)
559 {
560     CTxDestination address; CTransaction tx; uint256 hashBlock;
561     *valuep = 0;
562     if (!GetTransaction(hash, tx,
563 #ifndef KOMODO_ZCASH
564                         Params().GetConsensus(),
565 #endif
566                         hashBlock, true))
567     {
568         //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
569         return(0);
570     }
571     //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
572     if ( n < tx.vout.size() )
573     {
574         *valuep = tx.vout[n].nValue;
575         if (ExtractDestination(tx.vout[n].scriptPubKey, address))
576             strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
577     }
578     return(tx.nLockTime);
579 }
580
581 uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
582 {
583     CTxDestination address; CBlockIndex *pindex; CTransaction tx; uint256 hashBlock; uint32_t txtime = 0;
584     *valuep = 0;
585     if (!GetTransaction(hash, tx,
586 #ifndef KOMODO_ZCASH
587                         Params().GetConsensus(),
588 #endif
589                         hashBlock, true))
590     {
591         //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
592         return(0);
593     }
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() )
599     {
600         *valuep = tx.vout[n].nValue;
601         if (ExtractDestination(tx.vout[n].scriptPubKey, address))
602             strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
603     }
604     return(txtime);
605 }
606
607 int32_t komodo_isPoS(CBlock *pblock)
608 {
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 )
611     {
612         if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 )
613         {
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) )
618             {
619                 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
620                 if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[n-1].vout[0].nValue == value )
621                 {
622                     //fprintf(stderr,"is PoS block!\n");
623                     return(1);
624                 }
625             }
626         }
627     }
628     return(0);
629 }
630
631 void komodo_disconnect(const CBlockIndex *pindex, const CBlock& block)
632 {
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 )
637     {
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);
641 }
642
643 int32_t komodo_is_notarytx(const CTransaction& tx)
644 {
645     uint8_t *ptr; static uint8_t crypto777[33];
646     if ( tx.vout.size() > 0 )
647     {
648         ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0];
649         if ( ptr != 0 )
650         {
651             if ( crypto777[0] == 0 )
652                 decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
653             if ( memcmp(ptr+1,crypto777,33) == 0 )
654             {
655                 //printf("found notarytx\n");
656                 return(1);
657             }
658         }
659     }
660     return(0);
661 }
662
663 int32_t komodo_block2height(CBlock *block)
664 {
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 )
669     {
670         height2 = (int32_t)pindex->GetHeight();
671         if ( height2 >= 0 )
672             return(height2);
673     }
674     if ( pindex && block != 0 && block->vtx[0].vin.size() > 0 )
675     {
676         ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
677         if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
678         {
679             //for (i=0; i<6; i++)
680             //    printf("%02x",ptr[i]);
681             n = ptr[0];
682             for (i=0; i<n; i++) // looks strange but this works
683             {
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);
687             }
688             //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
689         }
690         //komodo_init(height);
691     }
692     if ( height != height2 )
693     {
694         //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch);
695         mismatch++;
696         if ( height2 >= 0 )
697             height = height2;
698     } else match++;
699     return(height);
700 }
701
702 int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
703 {
704     int32_t n;
705     if ( KOMODO_LOADINGBLOCKS == 0 )
706         memset(pubkey33,0xff,33);
707     else memset(pubkey33,0,33);
708     if ( block->vtx[0].vout.size() > 0 )
709     {
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)
713         {
714             CPubKey pubKey(vch[0]);
715             if (pubKey.IsValid())
716             {
717                 memcpy(pubkey33,vch[0].data(),33);
718                 return true;
719             }
720             else memset(pubkey33,0,33);
721         }
722         else memset(pubkey33,0,33);
723     }
724     return(0);
725 }
726
727 int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
728 {
729     block.SetNull();
730     // Open history file to read
731     CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION);
732     if (filein.IsNull())
733         return(-1);
734     // Read block
735     try { filein >> block; }
736     catch (const std::exception& e)
737     {
738         fprintf(stderr,"readblockfromdisk err B\n");
739         return(-1);
740     }
741     return(0);
742 }
743
744 uint32_t komodo_chainactive_timestamp()
745 {
746     if ( chainActive.LastTip() != 0 )
747         return((uint32_t)chainActive.LastTip()->GetBlockTime());
748     else return(0);
749 }
750
751 CBlockIndex *komodo_chainactive(int32_t height)
752 {
753     if ( chainActive.LastTip() != 0 )
754     {
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());
758     }
759     //fprintf(stderr,"komodo_chainactive null chainActive.LastTip() height %d\n",height);
760     return(0);
761 }
762
763 uint32_t komodo_heightstamp(int32_t height)
764 {
765     CBlockIndex *ptr;
766     if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
767         return(ptr->nTime);
768     //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
769     return(0);
770 }
771
772 /*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted
773 {
774     int32_t i,num; uint8_t pubkeys[64][33]; CBlock block;
775     if ( pindex->didinit != 0 )
776         return;
777     //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->GetHeight(),pindex->notaryid,height);
778     if ( pindex->didinit == 0 )
779     {
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 )
785         {
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);
793     }
794     if ( pindex->didinit != 0 && pindex->GetHeight() >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->GetHeight(),(uint32_t)pindex->nTime)) > 0 )
795     {
796         for (i=0; i<num; i++)
797         {
798             if ( memcmp(pubkeys[i],pindex->pubkey33,33) == 0 )
799             {
800                 pindex->notaryid = i;
801                 break;
802             }
803         }
804         if ( 0 && i == num )
805         {
806             for (i=0; i<33; i++)
807                 fprintf(stderr,"%02x",pindex->pubkey33[i]);
808             fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->GetHeight(),height);
809         }
810     }
811 }*/
812
813 void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
814 {
815     int32_t num,i; CBlock block;
816     memset(pubkey33,0,33);
817     if ( pindex != 0 )
818     {
819         if ( komodo_blockload(block,pindex) == 0 )
820             komodo_block2pubkey33(pubkey33,&block);
821     }
822 }
823
824 /*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33)
825 {
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 )
828     {
829         if ( pindex->didinit != 0 )
830         {
831             if ( destpubkey33 != 0 )
832                 memcpy(destpubkey33,pindex->pubkey33,33);
833             return(pindex->notaryid);
834         }
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 )
842         {
843             for (i=0; i<num; i++)
844                 if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
845                     return(i);
846         }
847     }
848     fprintf(stderr,"komodo_minerid height.%d null pindex\n",height);
849     return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp));
850 }*/
851
852 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height)
853 {
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++)
858     {
859         if ( (pindex= komodo_chainactive(height-i)) != 0 )
860         {
861             blocktimes[i] = pindex->nTime;
862             if ( komodo_blockload(block,pindex) == 0 )
863             {
864                 komodo_block2pubkey33(pubkeys[i],&block);
865                 for (j=0; j<n; j++)
866                 {
867                     if ( memcmp(notarypubs33[j],pubkeys[i],33) == 0 )
868                     {
869                         mids[i] = j;
870                         (*nonzpkeysp)++;
871                         break;
872                     }
873                 }
874             } else fprintf(stderr,"couldnt load block.%d\n",height);
875             if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
876                 duplicate++;
877         }
878     }
879     if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
880         return(1);
881     else return(0);
882 }
883
884 int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
885 {
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++)
889     {
890         if ( height-i <= 0 )
891             continue;
892         if ( (pindex= komodo_chainactive(height-width+i+1)) != 0 )
893         {
894             if ( komodo_blockload(block,pindex) == 0 )
895             {
896                 komodo_block2pubkey33(pubkey33,&block);
897                 for (j=0; j<numnotaries; j++)
898                 {
899                     if ( memcmp(notarypubs33[j],pubkey33,33) == 0 )
900                     {
901                         minerids[nonz++] = j;
902                         break;
903                     }
904                 }
905                 if ( j == numnotaries )
906                     minerids[nonz++] = j;
907             } else fprintf(stderr,"couldnt load block.%d\n",height);
908         }
909     }
910     return(nonz);
911 }
912
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)
914 {
915     int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33];
916     komodo_chosennotary(&notaryid,height,pubkey33,blocktimes[0]);
917     if ( height >= 82000 )
918     {
919         if ( notaryid >= 0 )
920         {
921             for (i=1; i<66; i++)
922             {
923                 if ( mids[i] == notaryid )
924                 {
925                     if ( height > 792000 )
926                     {
927                         for (j=0; j<66; j++)
928                             fprintf(stderr,"%d ",mids[j]);
929                         fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
930                         return(-1);
931                     } else break;
932                 }
933             }
934             if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 )
935             {
936                 if ( height > 807000 )
937                     return(-2);
938             }
939             return(1);
940         } else return(0);
941     }
942     else
943     {
944         if ( height >= 34000 && notaryid >= 0 )
945         {
946             if ( height < 79693 )
947                 limit = 64;
948             else if ( height < 82000 )
949                 limit = 8;
950             else limit = 66;
951             for (i=1; i<limit; i++)
952             {
953                 komodo_chosennotary(&nid,height-i,pubkey33,blocktimes[i]);
954                 if ( nid == notaryid )
955                 {
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 )
960                         return(-1);
961                 }
962             }
963             //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
964             return(1);
965         }
966     }
967     return(0);
968 }
969
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)
971 {
972     int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
973     depth = komodo_MoMdata(&notarized_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 )
978     {
979         *MoMp = MoM;
980         *notarized_heightp = notarized_ht;
981         *kmdtxidp = kmdtxid;
982     }
983     return(depth);
984 }
985
986 int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
987 {
988     int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
989     if ( (pindex= chainActive.LastTip()) == 0 )
990         return(-1);
991     notarized_height = komodo_notarizeddata(pindex->GetHeight(),&notarized_hash,&notarized_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 )
995     {
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
998         {
999             if ( nHeight < notarized_height )
1000             {
1001                 //fprintf(stderr,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1002                 return(-1);
1003             }
1004             else if ( nHeight == notarized_height && memcmp(&hash,&notarized_hash,sizeof(hash)) != 0 )
1005             {
1006                 fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1007                 return(-1);
1008             }
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());
1010     }
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());
1013     return(0);
1014 }
1015
1016 uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
1017 {
1018     LOCK(cs_main);
1019     CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
1020     *txheighttimep = *txheightp = *tiptimep = 0;
1021     *valuep = 0;
1022     if ( !GetTransaction(hash,tx,hashBlock,true) )
1023         return(0);
1024     uint32_t locktime = 0;
1025     if ( n < tx.vout.size() )
1026     {
1027         if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
1028         {
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);
1036         }
1037     }
1038     return(locktime);
1039 }
1040
1041 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
1042
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)
1044 {
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 )
1050     {
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);
1055     }
1056     return(0);
1057 }
1058
1059 int32_t komodo_isrealtime(int32_t *kmdheightp)
1060 {
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() )
1066         return(1);
1067     else return(0);
1068 }
1069
1070 int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
1071 {
1072     if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
1073     {
1074         if ( txheight > 246748 )
1075         {
1076             if ( txheight < 247205 )
1077                 cmptime -= 16000;
1078             if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
1079             {
1080                 if ( tx.nLockTime != 1477258935 && dispflag != 0 )
1081                 {
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);
1083                 }
1084                 return(-1);
1085             }
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);
1088         }
1089     }
1090     return(0);
1091 }
1092
1093 /*
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.
1095  
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
1097  
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]
1100  */
1101
1102 uint64_t komodo_commission(const CBlock *pblock)
1103 {
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++)
1107     {
1108         n = pblock->vtx[i].vout.size();
1109         for (j=0; j<n; j++)
1110         {
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;
1114         }
1115     }
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 )
1119         commission = 0;
1120     return(commission);
1121 }
1122
1123 uint32_t komodo_segid32(char *coinaddr)
1124 {
1125     bits256 addrhash;
1126     vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
1127     return(addrhash.uints[0]);
1128 }
1129
1130 int8_t komodo_segid(int32_t nocache,int32_t height)
1131 {
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 )
1134     {
1135         if ( nocache == 0 && pindex->segid >= -1 )
1136             return(pindex->segid);
1137         if ( komodo_blockload(block,pindex) == 0 )
1138         {
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 )
1141             {
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) )
1146                 {
1147                     strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
1148                     if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
1149                     {
1150                         segid = komodo_segid32(voutaddr) & 0x3f;
1151                         //fprintf(stderr,"komodo_segid.(%d) -> %02x\n",height,segid);
1152                     }
1153                 } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
1154             }
1155         }
1156     }
1157     return(segid);
1158 }
1159
1160 void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
1161 {
1162     static uint8_t prevhashbuf[100]; static int32_t prevheight;
1163     int32_t i;
1164     if ( height == prevheight && n == 100 )
1165         memcpy(hashbuf,prevhashbuf,100);
1166     else
1167     {
1168         memset(hashbuf,0xff,n);
1169         for (i=0; i<n; i++)
1170         {
1171             hashbuf[i] = (uint8_t)komodo_segid(1,height+i);
1172             //fprintf(stderr,"%02x ",hashbuf[i]);
1173         }
1174         if ( n == 100 )
1175         {
1176             memcpy(prevhashbuf,hashbuf,100);
1177             prevheight = height;
1178             //fprintf(stderr,"prevsegids.%d\n",height+n);
1179         }
1180     }
1181 }
1182
1183 uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout)
1184 {
1185     bits256 addrhash;
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]);
1192 }
1193
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)
1195 {
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 )
1199     {
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);
1206     }
1207     if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
1208     {
1209         //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
1210         return(0);
1211     }
1212     if ( value < SATOSHIDEN )
1213         return(0);
1214     value /= SATOSHIDEN;
1215     mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1216     ratio = (mindiff / bnTarget);
1217     if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
1218         minage = 6000;
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++)
1223     {
1224         if ( blocktime+iter+segid*2 < txtime+minage )
1225             continue;
1226         diff = (iter + blocktime - txtime - minage);
1227         if ( diff < 0 )
1228             diff = 60;
1229         else if ( diff > 3600*24*30 )
1230         {
1231             //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
1232             diff = 3600*24*30;
1233         }
1234         if ( iter > 0 )
1235             diff += segid*2;
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 )
1242         {
1243             winner = 1;
1244             if ( validateflag == 0 )
1245             {
1246                 //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid);
1247                 blocktime += iter;
1248                 blocktime += segid * 2;
1249             }
1250             break;
1251         }
1252         if ( validateflag != 0 )
1253         {
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);*/
1260             break;
1261         }
1262     }
1263     //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
1264     if ( 0 && validateflag != 0 )
1265     {
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);
1272     }
1273     if ( nHeight < 10 )
1274         return(blocktime);
1275     return(blocktime * winner);
1276 }
1277
1278 arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
1279 {
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) )
1284         return(target);
1285     sum = arith_uint256(0);
1286     ave = sum;
1287     easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1288     for (i=n=m=0; i<100; i++)
1289     {
1290         ht = height - 100 + i;
1291         if ( ht <= 1 )
1292             continue;
1293         if ( (pindex= komodo_chainactive(ht)) != 0 )
1294         {
1295             if ( komodo_segid(0,ht) >= 0 )
1296             {
1297                 n++;
1298                 percPoS++;
1299                 if ( ASSETCHAINS_STAKED < 100 )
1300                     fprintf(stderr,"0");
1301             }
1302             else
1303             {
1304                 if ( ASSETCHAINS_STAKED < 100 )
1305                     fprintf(stderr,"1");
1306                 sum += UintToArith256(pindex->GetBlockHash());
1307                 m++;
1308             }
1309         }
1310         if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
1311             fprintf(stderr," %d, ",percPoS);
1312     }
1313     if ( m+n < 100 )
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;
1318     if ( m > 0 )
1319     {
1320         ave = (sum / arith_uint256(m));
1321         if ( ave > target )
1322             ave = target;
1323     } else ave = target; //easydiff; //else return(target);
1324     if ( percPoS == 0 )
1325         percPoS = 1;
1326     if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
1327     {
1328         //if ( oldflag != 0 )
1329         //    bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
1330         if ( oldflag != 0 )
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 )
1334         {
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);
1344         }
1345     }
1346     else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget
1347     {
1348         if ( oldflag != 0 )
1349         {
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);
1353         }
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
1358         {
1359             bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1360             if ( bnTarget < ave )
1361                 bnTarget = ave;
1362         }
1363         if ( 1 )
1364         {
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);
1374         }
1375     }
1376     else bnTarget = ave; // recent ave is perfect
1377     return(bnTarget);
1378 }
1379
1380 int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget,arith_uint256 bhash)
1381 {
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 )
1384         return(1);
1385     BlockMap::const_iterator it = mapBlockIndex.find(pblock->GetHash());
1386     pindex = it != mapBlockIndex.end() ? it->second : NULL;
1387     if ( pindex != 0 && pindex->segid >= -1 )
1388     {
1389         if ( pindex->segid == -1 )
1390             return(0);
1391         else return(1);
1392     }
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 )
1395     {
1396         it = mapBlockIndex.find(pblock->hashPrevBlock);
1397         if ( it != mapBlockIndex.end() && (previndex = it->second) != NULL )
1398             prevtime = (uint32_t)previndex->nTime;
1399
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 )
1403         {
1404             if ( komodo_isPoS(pblock) != 0 )
1405             {
1406                 eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"");
1407             }
1408             if ( eligible == 0 || eligible > pblock->nTime )
1409             {
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 )
1413                 {
1414                     pindex->segid = -1;
1415                     fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
1416                 }
1417             }
1418             else
1419             {
1420                 isPoS = 2; // 2 means staking utxo validated
1421                 if ( slowflag != 0 && height > 100 )
1422                 {
1423                     segid = -3;
1424                     if ( pindex != 0 && pindex->segid == -2 && (segid= komodo_segid(1,height)) >= 0 )
1425                     {
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);
1429                 }
1430             }
1431         }
1432         if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx
1433         {
1434             if ( komodo_isPoS(pblock) != 0 )
1435                 isPoS = 1;
1436         }
1437         if ( slowflag != 0 && isPoS != 0 )
1438         {
1439             if ( isPoS != 2 )
1440             {
1441                 fprintf(stderr,"ht.%d isPoS.%d utxo not validated -> must be PoW fake\n",height,isPoS);
1442                 isPoS = 0;
1443             }
1444             else
1445             {
1446                 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1447                 if ( bhash < bnTarget )
1448                 {
1449                     fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height);
1450                     isPoS = 0;
1451                 }
1452             }
1453         }
1454         //else return(-1);
1455     }
1456     //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
1457     return(isPoS != 0);
1458 }
1459
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);
1463
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)
1466 {
1467     CBlockIndex *pastBlockIndex;
1468     uint256 txid, blkHash;
1469     int32_t txn_count;
1470     uint32_t voutNum;
1471     CAmount value;
1472     bool isPOS = false;
1473     CTxDestination voutaddress, destaddress, cbaddress;
1474     arith_uint256 target, hash;
1475     CTransaction tx;
1476
1477     if (!pblock->IsVerusPOSBlock())
1478     {
1479         printf("%s, height %d not POS block\n", pblock->nNonce.GetHex().c_str(), height);
1480         return false;
1481     }
1482
1483     char voutaddr[64], destaddr[64], cbaddr[64];
1484
1485     txn_count = pblock->vtx.size();
1486
1487     if ( txn_count > 1 )
1488     {
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;
1493
1494         {
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;
1499             uint256 rawHash;
1500             arith_uint256 posHash;
1501
1502             if (validHash && newPOSEnforcement)
1503             {
1504                 validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1505                 posHash = UintToArith256(rawHash) / value;
1506                 if (!validHash || posHash > target)
1507                 {
1508                     validHash = false;
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);
1511                 }
1512                 // make sure prev block hash and block height are correct
1513                 CStakeParams p;
1514                 if (validHash && (validHash = GetStakeParams(pblock->vtx[txn_count-1], p)))
1515                 {
1516                     for (int i = 0; validHash && i < pblock->vtx[0].vout.size(); i++)
1517                     {
1518                         validHash = false;
1519                         if (pblock->vtx[0].vout[i].scriptPubKey.IsInstantSpend() || ValidateMatchingStake(pblock->vtx[0], i, pblock->vtx[txn_count-1], validHash) && !validHash)
1520                         {
1521                             if ((p.prevHash == pblock->hashPrevBlock) && (int32_t)p.blkHeight == height)
1522                             {
1523                                 validHash = true;
1524                             }
1525                             else
1526                             {
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);
1529                                 validHash = false;
1530                             }
1531                         }
1532                         else validHash = false;
1533                     }
1534                 }
1535             }
1536             if (validHash)
1537             {
1538                 if (slowflag == 0)
1539                 {
1540                     isPOS = true;
1541                 }
1542                 else if (!(pastBlockIndex = komodo_chainactive(height - 100)))
1543                 {
1544                     fprintf(stderr,"ERROR: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str());
1545                 }
1546                 else 
1547 #ifndef KOMODO_ZCASH
1548                 if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
1549 #else
1550                 if (!GetTransaction(txid, tx, blkHash, true))
1551 #endif
1552                 {
1553                     fprintf(stderr,"ERROR: invalid PoS block %s - no source transaction\n",blkHash.ToString().c_str());
1554                 }
1555                 else
1556                 {
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;
1562
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());
1567
1568                     hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
1569
1570                     //printf("after nNonce:  %s, height: %d\n", nonce.GetHex().c_str(), height);
1571                     //printf("POShash:       %s\n\n", hash.GetHex().c_str());
1572
1573                     if ((!newPOSEnforcement || posHash == hash) && hash <= target)
1574                     {
1575                         BlockMap::const_iterator it = mapBlockIndex.find(blkHash);
1576                         if ((it == mapBlockIndex.end()) ||
1577                             !(pastBlockIndex = it->second) || 
1578                             (height - pastBlockIndex->GetHeight()) < VERUS_MIN_STAKEAGE)
1579                         {
1580                             fprintf(stderr,"ERROR: invalid PoS block %s - stake source too new or not found\n",blkHash.ToString().c_str());
1581                         }
1582                         else
1583                         {
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))
1588                             {
1589                                 fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
1590                             }
1591                             else
1592                             {
1593                                 arith_uint256 cTarget;
1594                                 uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
1595                                 cTarget.SetCompact(nBits);
1596                                 bool nonceOK = true;
1597
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);
1601
1602                                 if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum, pblock->nVersion))
1603                                 {
1604                                     fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
1605                                     nonceOK = false;
1606                                 }
1607                                 else
1608                                 {
1609                                     if (cTarget != target)
1610                                     {
1611                                         fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
1612                                         nonceOK = false;
1613                                     }
1614                                 }
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) )
1618                                 {
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)
1623                                     {
1624                                         if (!strcmp(destaddr, voutaddr))
1625                                         {
1626                                             // allow delegation of stake, but require all ouputs to be
1627                                             // crypto conditions
1628                                             CStakeParams p;
1629
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))
1633                                             {
1634                                                 COptCCParams cpp;
1635                                                 // loop through all outputs to make sure they are sent to the proper pubkey
1636                                                 isPOS = true;
1637                                                 for (auto vout : pblock->vtx[0].vout)
1638                                                 {
1639                                                     txnouttype tp;
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 || 
1646                                                         vvch.size() < 2 || 
1647                                                         p.pk != CPubKey(vvch[0])))
1648                                                     {
1649                                                         isPOS = false;
1650                                                         break;
1651                                                     }
1652                                                 }
1653                                             }
1654                                         }
1655                                     }
1656                                     else if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
1657                                     {
1658                                         isPOS = true;
1659                                     }
1660                                     else
1661                                     {
1662                                         fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n",blkHash.ToString().c_str());
1663                                     }
1664                                 }
1665                             }
1666                         }
1667                     }
1668                     else
1669                     {
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);
1672                     }
1673                 }
1674             }
1675         }
1676     }
1677     return(isPOS);
1678 }
1679
1680 int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1681 {
1682     int64_t checktoshis=0; uint8_t *script;
1683     if ( ASSETCHAINS_COMMISSION != 0 )
1684     {
1685         checktoshis = komodo_commission(pblock);
1686         if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1687             return(-1);
1688         else if ( checktoshis != 0 )
1689         {
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 )
1692                 return(-1);
1693             if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1694             {
1695                 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1696                 return(-1);
1697             }
1698         }
1699     }
1700     return(checktoshis);
1701 }
1702
1703 bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1704
1705 int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1706 {
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()) )
1711     {
1712         fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1713         return -1;
1714     }
1715     hash = pblock->GetHash();
1716     bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1717     bhash = UintToArith256(hash);
1718     possible = komodo_block2pubkey33(pubkey33,pblock);
1719     if ( height == 0 )
1720     {
1721         if ( slowflag != 0 )
1722         {
1723             fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
1724             return 0;
1725         }
1726         BlockMap::const_iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
1727         if ( it != mapBlockIndex.end() && (pprev= it->second) != 0 )
1728             height = pprev->GetHeight() + 1;
1729         if ( height == 0 )
1730             return 0;
1731     }
1732
1733     if (ASSETCHAINS_LWMAPOS != 0 && pblock->IsVerusPOSBlock())
1734     {
1735         return 0;
1736     }
1737     else if (bhash <= bnTarget)
1738     {
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))
1743         {
1744             return 0;
1745         }
1746         else
1747         {
1748             printf("Block header size modulo 32 must be > 1 and <= 16 for PoW blocks\n");
1749         }
1750     }
1751     else
1752     {
1753         printf("Insufficient hash result and not PoS block\n");
1754     }
1755     
1756     return -1;
1757 }
1758
1759 bool IsCoinbaseTimeLocked(const CTransaction &tx, uint32_t &outUnlockHeight);
1760
1761 void GetImmatureCoins(std::map<uint32_t, int64_t> *pimmatureBlockAmounts, CBlock &block, uint32_t &maturity, int64_t &amount, uint32_t height)
1762 {
1763     std::map<uint32_t, int64_t> _unlockBlockAmounts;
1764     std::map<uint32_t, int64_t> &unlockBlockAmounts = pimmatureBlockAmounts ? *pimmatureBlockAmounts : _unlockBlockAmounts;
1765     amount = 0;
1766
1767     if (block.vtx.size())
1768     {
1769         const CTransaction &tx = block.vtx[0];
1770         uint32_t unlockHeight = 0;
1771         if (IsCoinbaseTimeLocked(tx, unlockHeight) && unlockHeight > (height + COINBASE_MATURITY))
1772         {
1773             maturity = unlockHeight;
1774         }
1775         else
1776         {
1777             maturity = height + COINBASE_MATURITY;
1778         }
1779         for (auto &out : tx.vout)
1780         {
1781             if (!out.scriptPubKey.IsInstantSpend())
1782             {
1783                 amount += out.nValue;
1784             }
1785         }
1786         unlockBlockAmounts[maturity] += amount;
1787     }
1788 }
1789
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)
1791 {
1792     int64_t _zfunds;
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;
1796
1797     for (auto &tx : block.vtx)
1798     {
1799         if (tx.IsCoinBase())
1800         {
1801             for (auto &out : tx.vout)
1802             {
1803                 newCoins += out.nValue;
1804             }
1805             GetImmatureCoins(&unlockBlockAmounts, block, maturity, amount, height);
1806         }
1807         else
1808         {
1809             int64_t vinSum = 0, voutSum = 0;
1810             CTransaction vinTx;
1811             uint256 blockHash;
1812
1813             for (auto &in : tx.vin)
1814             {
1815                 if ( !GetTransaction(in.prevout.hash, vinTx, blockHash, false) || in.prevout.n >= vinTx.vout.size() )
1816                 {
1817                     fprintf(stderr,"ERROR: %s/v%d cant find\n", in.prevout.hash.ToString().c_str(), in.prevout.n);
1818                     return false;
1819                 }
1820                 vinSum += vinTx.vout[in.prevout.n].nValue;
1821             }
1822             for (auto &out : tx.vout)
1823             {
1824                 if ( !out.scriptPubKey.IsOpReturn() )
1825                 {
1826                     voutSum += out.nValue;
1827                 }
1828             }
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;
1833         }
1834     }
1835
1836     zfunds += (chainActive[height]->nSproutValue ? chainActive[height]->nSproutValue.get() : 0) + chainActive[height]->nSaplingValue;
1837
1838     return true;
1839 }
1840
1841 int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
1842 {
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();
1845     for (i=0; i<n; i++)
1846     {
1847         CTransaction vintx, &tx = pblock->vtx[i];
1848         zfunds += (tx.GetShieldedValueOut() - tx.GetShieldedValueIn());
1849         if ( (m= tx.vin.size()) > 0 )
1850         {
1851             for (j=0; j<m; j++)
1852             {
1853                 if ( i == 0 )
1854                     continue;
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() )
1858                 {
1859                     fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1860                     return(0);
1861                 }
1862                 vinsum += vintx.vout[vout].nValue;
1863             }
1864         }
1865         if ( (m= tx.vout.size()) > 0 )
1866         {
1867             for (j=0; j<m-1; j++)
1868             {
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());
1872             }
1873             script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
1874             if ( script == 0 || script[0] != 0x6a )
1875             {
1876                 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1877                     voutsum += tx.vout[j].nValue;
1878             }
1879         }
1880     }
1881     *zfundsp = zfunds;
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);
1887 }
1888
1889 int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
1890 {
1891     CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
1892     //fprintf(stderr,"coinsupply %d\n",height);
1893     *zfundsp = 0;
1894     if ( (pindex= komodo_chainactive(height)) != 0 )
1895     {
1896         while ( pindex != 0 && pindex->GetHeight() > 0 )
1897         {
1898             if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
1899             {
1900                 if ( komodo_blockload(block,pindex) == 0 )
1901                     pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->GetHeight(),&block);
1902                 else
1903                 {
1904                     fprintf(stderr,"error loading block.%d\n",pindex->GetHeight());
1905                     return(0);
1906                 }
1907             }
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;
1912         }
1913     }
1914     *zfundsp = zfunds;
1915     return(supply);
1916 }
1917
1918 bool GetCoinSupply(int64_t &transparentSupply, int64_t *pzsupply, int64_t *pimmaturesupply, uint32_t height)
1919 {
1920     int64_t _immature = 0, _zsupply = 0;
1921     int64_t &immature = pimmaturesupply ? *pimmaturesupply : _immature;
1922     int64_t &zfunds = pzsupply ? *pzsupply : _zsupply;
1923
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;
1926
1927     if (height > chainActive.Height())
1928     {
1929         height = chainActive.Height();
1930     }
1931
1932     for (int curHeight = 1; curHeight <= height; curHeight++)
1933     {
1934         CBlockIndex *pIndex;
1935         CBlock block;
1936         LOCK(cs_main);
1937         if ( (pIndex = komodo_chainactive(curHeight)) != 0 )
1938         {
1939             if ( pIndex->newcoins == 0 && pIndex->zfunds == 0 )
1940             {
1941                 if ( !komodo_blockload(block, pIndex) == 0 || !GetNewCoins(pIndex->newcoins, &pIndex->zfunds, &immatureBlockAmounts, block, pIndex->maturity, pIndex->immature, curHeight) )
1942                 {
1943                     fprintf(stderr,"error loading block.%d\n", pIndex->GetHeight());
1944                     return false;
1945                 }
1946             }
1947             else
1948             {
1949                 if (pIndex->maturity)
1950                 {
1951                     if (immatureBlockAmounts.count(pIndex->maturity))
1952                     {
1953                         immatureBlockAmounts[pIndex->maturity] += pIndex->immature;
1954                     }
1955                     else
1956                     {
1957                         immatureBlockAmounts[pIndex->maturity] = pIndex->immature;
1958                     }
1959                 }
1960             }
1961             
1962             transparentSupply += pIndex->newcoins;
1963             zfunds += pIndex->zfunds;
1964         }
1965     }
1966
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)
1971     {
1972         immature += lockedAmount.second;
1973     }
1974
1975     return true;
1976 }
This page took 0.138144 seconds and 4 git commands to generate.