]> Git Repo - VerusCoin.git/blob - src/komodo_bitcoind.h
move things around and some debugging code for odd issues
[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(CBlockIndex *pindex,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;
667     if ( (pindex= mapBlockIndex[block->GetHash()]) != 0 )
668     {
669         height2 = (int32_t)pindex->GetHeight();
670         if ( height2 >= 0 )
671             return(height2);
672     }
673     if ( block != 0 && block->vtx[0].vin.size() > 0 )
674     {
675         ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
676         if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
677         {
678             //for (i=0; i<6; i++)
679             //    printf("%02x",ptr[i]);
680             n = ptr[0];
681             for (i=0; i<n; i++) // looks strange but this works
682             {
683                 //03bb81000101(bb 187) (81 48001) (00 12288256)  <- coinbase.6 ht.12288256
684                 height += ((uint32_t)ptr[i+1] << (i*8));
685                 //printf("(%02x %x %d) ",ptr[i+1],((uint32_t)ptr[i+1] << (i*8)),height);
686             }
687             //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
688         }
689         //komodo_init(height);
690     }
691     if ( height != height2 )
692     {
693         //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch);
694         mismatch++;
695         if ( height2 >= 0 )
696             height = height2;
697     } else match++;
698     return(height);
699 }
700
701 int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
702 {
703     int32_t n;
704     if ( KOMODO_LOADINGBLOCKS == 0 )
705         memset(pubkey33,0xff,33);
706     else memset(pubkey33,0,33);
707     if ( block->vtx[0].vout.size() > 0 )
708     {
709         txnouttype whichType;
710         vector<vector<unsigned char>> vch = vector<vector<unsigned char>>();
711         if (Solver(block->vtx[0].vout[0].scriptPubKey, whichType, vch) && whichType == TX_PUBKEY)
712         {
713             CPubKey pubKey(vch[0]);
714             if (pubKey.IsValid())
715             {
716                 memcpy(pubkey33,vch[0].data(),33);
717                 return true;
718             }
719             else memset(pubkey33,0,33);
720         }
721         else memset(pubkey33,0,33);
722     }
723     return(0);
724 }
725
726 int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
727 {
728     block.SetNull();
729     // Open history file to read
730     CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION);
731     if (filein.IsNull())
732         return(-1);
733     // Read block
734     try { filein >> block; }
735     catch (const std::exception& e)
736     {
737         fprintf(stderr,"readblockfromdisk err B\n");
738         return(-1);
739     }
740     return(0);
741 }
742
743 uint32_t komodo_chainactive_timestamp()
744 {
745     if ( chainActive.LastTip() != 0 )
746         return((uint32_t)chainActive.LastTip()->GetBlockTime());
747     else return(0);
748 }
749
750 CBlockIndex *komodo_chainactive(int32_t height)
751 {
752     if ( chainActive.LastTip() != 0 )
753     {
754         if ( height <= chainActive.LastTip()->GetHeight() )
755             return(chainActive[height]);
756         // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.LastTip()->GetHeight());
757     }
758     //fprintf(stderr,"komodo_chainactive null chainActive.LastTip() height %d\n",height);
759     return(0);
760 }
761
762 uint32_t komodo_heightstamp(int32_t height)
763 {
764     CBlockIndex *ptr;
765     if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
766         return(ptr->nTime);
767     //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
768     return(0);
769 }
770
771 /*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted
772 {
773     int32_t i,num; uint8_t pubkeys[64][33]; CBlock block;
774     if ( pindex->didinit != 0 )
775         return;
776     //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->GetHeight(),pindex->notaryid,height);
777     if ( pindex->didinit == 0 )
778     {
779         pindex->notaryid = -1;
780         if ( KOMODO_LOADINGBLOCKS == 0 )
781             memset(pindex->pubkey33,0xff,33);
782         else memset(pindex->pubkey33,0,33);
783         if ( komodo_blockload(block,pindex) == 0 )
784         {
785             komodo_block2pubkey33(pindex->pubkey33,&block);
786             //for (i=0; i<33; i++)
787             //    fprintf(stderr,"%02x",pindex->pubkey33[i]);
788             //fprintf(stderr," set pubkey at height %d/%d\n",pindex->GetHeight(),height);
789             //if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 )
790             //    pindex->didinit = (KOMODO_LOADINGBLOCKS == 0);
791         } // else fprintf(stderr,"error loading block at %d/%d",pindex->GetHeight(),height);
792     }
793     if ( pindex->didinit != 0 && pindex->GetHeight() >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->GetHeight(),(uint32_t)pindex->nTime)) > 0 )
794     {
795         for (i=0; i<num; i++)
796         {
797             if ( memcmp(pubkeys[i],pindex->pubkey33,33) == 0 )
798             {
799                 pindex->notaryid = i;
800                 break;
801             }
802         }
803         if ( 0 && i == num )
804         {
805             for (i=0; i<33; i++)
806                 fprintf(stderr,"%02x",pindex->pubkey33[i]);
807             fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->GetHeight(),height);
808         }
809     }
810 }*/
811
812 void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
813 {
814     int32_t num,i; CBlock block;
815     memset(pubkey33,0,33);
816     if ( pindex != 0 )
817     {
818         if ( komodo_blockload(block,pindex) == 0 )
819             komodo_block2pubkey33(pubkey33,&block);
820     }
821 }
822
823 /*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33)
824 {
825     int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t pubkey33[33],pubkeys[64][33];
826     if ( (pindex= chainActive[height]) != 0 )
827     {
828         if ( pindex->didinit != 0 )
829         {
830             if ( destpubkey33 != 0 )
831                 memcpy(destpubkey33,pindex->pubkey33,33);
832             return(pindex->notaryid);
833         }
834         komodo_index2pubkey33(pubkey33,pindex,height);
835         if ( destpubkey33 != 0 )
836             memcpy(destpubkey33,pindex->pubkey33,33);
837         if ( pindex->didinit != 0 )
838             return(pindex->notaryid);
839         timestamp = pindex->GetBlockTime();
840         if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 )
841         {
842             for (i=0; i<num; i++)
843                 if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
844                     return(i);
845         }
846     }
847     fprintf(stderr,"komodo_minerid height.%d null pindex\n",height);
848     return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp));
849 }*/
850
851 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height)
852 {
853     int32_t i,j,n,duplicate; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33];
854     memset(mids,-1,sizeof(*mids)*66);
855     n = komodo_notaries(notarypubs33,height,0);
856     for (i=duplicate=0; i<66; i++)
857     {
858         if ( (pindex= komodo_chainactive(height-i)) != 0 )
859         {
860             blocktimes[i] = pindex->nTime;
861             if ( komodo_blockload(block,pindex) == 0 )
862             {
863                 komodo_block2pubkey33(pubkeys[i],&block);
864                 for (j=0; j<n; j++)
865                 {
866                     if ( memcmp(notarypubs33[j],pubkeys[i],33) == 0 )
867                     {
868                         mids[i] = j;
869                         (*nonzpkeysp)++;
870                         break;
871                     }
872                 }
873             } else fprintf(stderr,"couldnt load block.%d\n",height);
874             if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
875                 duplicate++;
876         }
877     }
878     if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
879         return(1);
880     else return(0);
881 }
882
883 int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
884 {
885     int32_t i,j,n,nonz,numnotaries; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33],pubkey33[33];
886     numnotaries = komodo_notaries(notarypubs33,height,0);
887     for (i=nonz=0; i<width; i++,n++)
888     {
889         if ( height-i <= 0 )
890             continue;
891         if ( (pindex= komodo_chainactive(height-width+i+1)) != 0 )
892         {
893             if ( komodo_blockload(block,pindex) == 0 )
894             {
895                 komodo_block2pubkey33(pubkey33,&block);
896                 for (j=0; j<numnotaries; j++)
897                 {
898                     if ( memcmp(notarypubs33[j],pubkey33,33) == 0 )
899                     {
900                         minerids[nonz++] = j;
901                         break;
902                     }
903                 }
904                 if ( j == numnotaries )
905                     minerids[nonz++] = j;
906             } else fprintf(stderr,"couldnt load block.%d\n",height);
907         }
908     }
909     return(nonz);
910 }
911
912 int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],uint32_t blocktimes[66],int32_t height,uint8_t pubkey33[33],uint32_t blocktime)
913 {
914     int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33];
915     komodo_chosennotary(&notaryid,height,pubkey33,blocktimes[0]);
916     if ( height >= 82000 )
917     {
918         if ( notaryid >= 0 )
919         {
920             for (i=1; i<66; i++)
921             {
922                 if ( mids[i] == notaryid )
923                 {
924                     if ( height > 792000 )
925                     {
926                         for (j=0; j<66; j++)
927                             fprintf(stderr,"%d ",mids[j]);
928                         fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
929                         return(-1);
930                     } else break;
931                 }
932             }
933             if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 )
934             {
935                 if ( height > 807000 )
936                     return(-2);
937             }
938             return(1);
939         } else return(0);
940     }
941     else
942     {
943         if ( height >= 34000 && notaryid >= 0 )
944         {
945             if ( height < 79693 )
946                 limit = 64;
947             else if ( height < 82000 )
948                 limit = 8;
949             else limit = 66;
950             for (i=1; i<limit; i++)
951             {
952                 komodo_chosennotary(&nid,height-i,pubkey33,blocktimes[i]);
953                 if ( nid == notaryid )
954                 {
955                     //for (j=0; j<66; j++)
956                     //    fprintf(stderr,"%d ",mids[j]);
957                     //fprintf(stderr,"ht.%d repeat mids[%d] nid.%d notaryid.%d\n",height-i,i,nid,notaryid);
958                     if ( height > 225000 )
959                         return(-1);
960                 }
961             }
962             //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
963             return(1);
964         }
965     }
966     return(0);
967 }
968
969 int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip)
970 {
971     int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
972     depth = komodo_MoMdata(&notarized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip);
973     memset(MoMp,0,sizeof(*MoMp));
974     memset(kmdtxidp,0,sizeof(*kmdtxidp));
975     *notarized_heightp = 0;
976     if ( depth != 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
977     {
978         *MoMp = MoM;
979         *notarized_heightp = notarized_ht;
980         *kmdtxidp = kmdtxid;
981     }
982     return(depth);
983 }
984
985 int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
986 {
987     int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
988     if ( (pindex= chainActive.LastTip()) == 0 )
989         return(-1);
990     notarized_height = komodo_notarizeddata(pindex->GetHeight(),&notarized_hash,&notarized_desttxid);
991     *notarized_heightp = notarized_height;
992     if ( notarized_height >= 0 && notarized_height <= pindex->GetHeight() && (notary= mapBlockIndex[notarized_hash]) != 0 )
993     {
994         //printf("nHeight.%d -> (%d %s)\n",pindex->Tip()->GetHeight(),notarized_height,notarized_hash.ToString().c_str());
995         if ( notary->GetHeight() == notarized_height ) // if notarized_hash not in chain, reorg
996         {
997             if ( nHeight < notarized_height )
998             {
999                 //fprintf(stderr,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1000                 return(-1);
1001             }
1002             else if ( nHeight == notarized_height && memcmp(&hash,&notarized_hash,sizeof(hash)) != 0 )
1003             {
1004                 fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
1005                 return(-1);
1006             }
1007         } //else fprintf(stderr,"[%s] unexpected error notary_hash %s ht.%d at ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,notary->GetHeight());
1008     }
1009     //else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
1010     //    fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->GetHeight());
1011     return(0);
1012 }
1013
1014 uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
1015 {
1016     LOCK(cs_main);
1017     CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
1018     *txheighttimep = *txheightp = *tiptimep = 0;
1019     *valuep = 0;
1020     if ( !GetTransaction(hash,tx,hashBlock,true) )
1021         return(0);
1022     uint32_t locktime = 0;
1023     if ( n < tx.vout.size() )
1024     {
1025         if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
1026         {
1027             *valuep = tx.vout[n].nValue;
1028             *txheightp = pindex->GetHeight();
1029             *txheighttimep = pindex->nTime;
1030             if ( *tiptimep == 0 && (tipindex= chainActive.LastTip()) != 0 )
1031                 *tiptimep = (uint32_t)tipindex->nTime;
1032             locktime = tx.nLockTime;
1033             //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
1034         }
1035     }
1036     return(locktime);
1037 }
1038
1039 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
1040
1041 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight)
1042 {
1043     uint64_t value; uint32_t tiptime=0,txheighttimep; CBlockIndex *pindex;
1044     if ( (pindex= chainActive[tipheight]) != 0 )
1045         tiptime = (uint32_t)pindex->nTime;
1046     else fprintf(stderr,"cant find height[%d]\n",tipheight);
1047     if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 )
1048     {
1049         if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
1050             return(komodo_interest(*txheightp,value,*locktimep,tiptime));
1051         //fprintf(stderr,"nValue %llu lock.%u:%u nTime.%u -> %llu\n",(long long)coins.vout[n].nValue,coins.nLockTime,timestamp,pindex->nTime,(long long)interest);
1052         else fprintf(stderr,"komodo_accrued_interest value mismatch %llu vs %llu or height mismatch %d vs %d\n",(long long)value,(long long)checkvalue,*txheightp,checkheight);
1053     }
1054     return(0);
1055 }
1056
1057 int32_t komodo_isrealtime(int32_t *kmdheightp)
1058 {
1059     struct komodo_state *sp; CBlockIndex *pindex;
1060     if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
1061         *kmdheightp = sp->CURRENT_HEIGHT;
1062     else *kmdheightp = 0;
1063     if ( (pindex= chainActive.LastTip()) != 0 && pindex->GetHeight() >= (int32_t)komodo_longestchain() )
1064         return(1);
1065     else return(0);
1066 }
1067
1068 int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
1069 {
1070     if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
1071     {
1072         if ( txheight > 246748 )
1073         {
1074             if ( txheight < 247205 )
1075                 cmptime -= 16000;
1076             if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
1077             {
1078                 if ( tx.nLockTime != 1477258935 && dispflag != 0 )
1079                 {
1080                     fprintf(stderr,"komodo_validate_interest.%d reject.%d [%d] locktime %u cmp2.%u\n",dispflag,txheight,(int32_t)(tx.nLockTime - (cmptime-KOMODO_MAXMEMPOOLTIME)),(uint32_t)tx.nLockTime,cmptime);
1081                 }
1082                 return(-1);
1083             }
1084             if ( 0 && dispflag != 0 )
1085                 fprintf(stderr,"validateinterest.%d accept.%d [%d] locktime %u cmp2.%u\n",dispflag,(int32_t)txheight,(int32_t)(tx.nLockTime - (cmptime-KOMODO_MAXMEMPOOLTIME)),(int32_t)tx.nLockTime,cmptime);
1086         }
1087     }
1088     return(0);
1089 }
1090
1091 /*
1092  komodo_checkPOW (fast) is called early in the process and should only refer to data immediately available. it is a filter to prevent bad blocks from going into the local DB. The more blocks we can filter out at this stage, the less junk in the local DB that will just get purged later on.
1093  
1094  komodo_checkPOW (slow) is called right before connecting blocks so all prior blocks can be assumed to be there and all checks must pass
1095  
1096  commission must be in coinbase.vout[1] and must be >= 10000 sats
1097  PoS stake must be without txfee and in the last tx in the block at vout[0]
1098  */
1099
1100 uint64_t komodo_commission(const CBlock *pblock)
1101 {
1102     int32_t i,j,n=0,txn_count; uint64_t commission,total = 0;
1103     txn_count = pblock->vtx.size();
1104     for (i=0; i<txn_count; i++)
1105     {
1106         n = pblock->vtx[i].vout.size();
1107         for (j=0; j<n; j++)
1108         {
1109             //fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
1110             if ( i != 0 || j != 1 )
1111                 total += pblock->vtx[i].vout[j].nValue;
1112         }
1113     }
1114     //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN));
1115     commission = ((total * ASSETCHAINS_COMMISSION) / COIN);
1116     if ( commission < 10000 )
1117         commission = 0;
1118     return(commission);
1119 }
1120
1121 uint32_t komodo_segid32(char *coinaddr)
1122 {
1123     bits256 addrhash;
1124     vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
1125     return(addrhash.uints[0]);
1126 }
1127
1128 int8_t komodo_segid(int32_t nocache,int32_t height)
1129 {
1130     CTxDestination voutaddress; CBlock block; CBlockIndex *pindex; uint64_t value; uint32_t txtime; char voutaddr[64],destaddr[64]; int32_t txn_count,vout; uint256 txid; int8_t segid = -1;
1131     if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
1132     {
1133         if ( nocache == 0 && pindex->segid >= -1 )
1134             return(pindex->segid);
1135         if ( komodo_blockload(block,pindex) == 0 )
1136         {
1137             txn_count = block.vtx.size();
1138             if ( txn_count > 1 && block.vtx[txn_count-1].vin.size() == 1 && block.vtx[txn_count-1].vout.size() == 1 )
1139             {
1140                 txid = block.vtx[txn_count-1].vin[0].prevout.hash;
1141                 vout = block.vtx[txn_count-1].vin[0].prevout.n;
1142                 txtime = komodo_txtime(&value,txid,vout,destaddr);
1143                 if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
1144                 {
1145                     strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
1146                     if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
1147                     {
1148                         segid = komodo_segid32(voutaddr) & 0x3f;
1149                         //fprintf(stderr,"komodo_segid.(%d) -> %02x\n",height,segid);
1150                     }
1151                 } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
1152             }
1153         }
1154     }
1155     return(segid);
1156 }
1157
1158 int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
1159 {
1160     static uint8_t prevhashbuf[100]; static int32_t prevheight;
1161     int32_t i;
1162     if ( height == prevheight && n == 100 )
1163         memcpy(hashbuf,prevhashbuf,100);
1164     else
1165     {
1166         memset(hashbuf,0xff,n);
1167         for (i=0; i<n; i++)
1168         {
1169             hashbuf[i] = (uint8_t)komodo_segid(1,height+i);
1170             //fprintf(stderr,"%02x ",hashbuf[i]);
1171         }
1172         if ( n == 100 )
1173         {
1174             memcpy(prevhashbuf,hashbuf,100);
1175             prevheight = height;
1176             //fprintf(stderr,"prevsegids.%d\n",height+n);
1177         }
1178     }
1179 }
1180
1181 uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout)
1182 {
1183     bits256 addrhash;
1184     vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
1185     memcpy(&hashbuf[100],&addrhash,sizeof(addrhash));
1186     memcpy(&hashbuf[100+sizeof(addrhash)],&txid,sizeof(txid));
1187     memcpy(&hashbuf[100+sizeof(addrhash)+sizeof(txid)],&vout,sizeof(vout));
1188     vcalc_sha256(0,(uint8_t *)hashp,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
1189     return(addrhash.uints[0]);
1190 }
1191
1192 uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr)
1193 {
1194     bool fNegative,fOverflow; uint8_t hashbuf[256]; char address[64]; bits256 addrhash; arith_uint256 hashval,mindiff,ratio,coinage256; uint256 hash,pasthash; int32_t diff=0,segid,minage,i,iter=0; uint32_t txtime,segid32,winner = 0 ; uint64_t value,coinage;
1195     txtime = komodo_txtime2(&value,txid,vout,address);
1196     if ( validateflag == 0 )
1197     {
1198         //fprintf(stderr,"blocktime.%u -> ",blocktime);
1199         if ( blocktime < prevtime+3 )
1200             blocktime = prevtime+3;
1201         if ( blocktime < GetAdjustedTime()-60 )
1202             blocktime = GetAdjustedTime()+30;
1203         //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime);
1204     }
1205     if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
1206     {
1207         //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
1208         return(0);
1209     }
1210     if ( value < SATOSHIDEN )
1211         return(0);
1212     value /= SATOSHIDEN;
1213     mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1214     ratio = (mindiff / bnTarget);
1215     if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
1216         minage = 6000;
1217     komodo_segids(hashbuf,nHeight-101,100);
1218     segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
1219     segid = ((nHeight + segid32) & 0x3f);
1220     for (iter=0; iter<600; iter++)
1221     {
1222         if ( blocktime+iter+segid*2 < txtime+minage )
1223             continue;
1224         diff = (iter + blocktime - txtime - minage);
1225         if ( diff < 0 )
1226             diff = 60;
1227         else if ( diff > 3600*24*30 )
1228         {
1229             //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
1230             diff = 3600*24*30;
1231         }
1232         if ( iter > 0 )
1233             diff += segid*2;
1234         coinage = (value * diff);
1235         if ( blocktime+iter+segid*2 > prevtime+480 )
1236             coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
1237         coinage256 = arith_uint256(coinage+1);
1238         hashval = ratio * (UintToArith256(hash) / coinage256);
1239         if ( hashval <= bnTarget )
1240         {
1241             winner = 1;
1242             if ( validateflag == 0 )
1243             {
1244                 //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid);
1245                 blocktime += iter;
1246                 blocktime += segid * 2;
1247             }
1248             break;
1249         }
1250         if ( validateflag != 0 )
1251         {
1252             /*for (i=31; i>=24; i--)
1253                 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1254             fprintf(stderr," vs ");
1255             for (i=31; i>=24; i--)
1256                 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1257             fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff);*/
1258             break;
1259         }
1260     }
1261     //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
1262     if ( 0 && validateflag != 0 )
1263     {
1264         for (i=31; i>=24; i--)
1265             fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1266         fprintf(stderr," vs ");
1267         for (i=31; i>=24; i--)
1268             fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1269         fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d ht.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff,nHeight);
1270     }
1271     if ( nHeight < 10 )
1272         return(blocktime);
1273     return(blocktime * winner);
1274 }
1275
1276 arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
1277 {
1278     int32_t oldflag = 0;
1279     CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
1280     *percPoSp = percPoS = 0;
1281     if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
1282         return(target);
1283     sum = arith_uint256(0);
1284     ave = sum;
1285     easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1286     for (i=n=m=0; i<100; i++)
1287     {
1288         ht = height - 100 + i;
1289         if ( ht <= 1 )
1290             continue;
1291         if ( (pindex= komodo_chainactive(ht)) != 0 )
1292         {
1293             if ( komodo_segid(0,ht) >= 0 )
1294             {
1295                 n++;
1296                 percPoS++;
1297                 if ( ASSETCHAINS_STAKED < 100 )
1298                     fprintf(stderr,"0");
1299             }
1300             else
1301             {
1302                 if ( ASSETCHAINS_STAKED < 100 )
1303                     fprintf(stderr,"1");
1304                 sum += UintToArith256(pindex->GetBlockHash());
1305                 m++;
1306             }
1307         }
1308         if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
1309             fprintf(stderr," %d, ",percPoS);
1310     }
1311     if ( m+n < 100 )
1312         percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
1313     if ( ASSETCHAINS_STAKED < 100 )
1314         fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
1315     *percPoSp = percPoS;
1316     if ( m > 0 )
1317     {
1318         ave = (sum / arith_uint256(m));
1319         if ( ave > target )
1320             ave = target;
1321     } else ave = target; //easydiff; //else return(target);
1322     if ( percPoS == 0 )
1323         percPoS = 1;
1324     if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
1325     {
1326         //if ( oldflag != 0 )
1327         //    bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
1328         if ( oldflag != 0 )
1329             bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
1330         else bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
1331         if ( ASSETCHAINS_STAKED < 100 )
1332         {
1333             for (i=31; i>=24; i--)
1334                 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1335             fprintf(stderr," increase diff -> ");
1336             for (i=31; i>=24; i--)
1337                 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1338             fprintf(stderr," floor diff ");
1339             for (i=31; i>=24; i--)
1340                 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1341             fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1342         }
1343     }
1344     else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget
1345     {
1346         if ( oldflag != 0 )
1347         {
1348             bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1349             //bnTarget = (bnTarget * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc);
1350             bnTarget = (bnTarget / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
1351         }
1352         else bnTarget = (ave / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
1353         if ( bnTarget > easydiff )
1354             bnTarget = easydiff;
1355         else if ( bnTarget < ave ) // overflow
1356         {
1357             bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1358             if ( bnTarget < ave )
1359                 bnTarget = ave;
1360         }
1361         if ( 1 )
1362         {
1363             for (i=31; i>=24; i--)
1364                 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1365             fprintf(stderr," decrease diff -> ");
1366             for (i=31; i>=24; i--)
1367                 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1368             fprintf(stderr," floor diff ");
1369             for (i=31; i>=24; i--)
1370                 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1371             fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1372         }
1373     }
1374     else bnTarget = ave; // recent ave is perfect
1375     return(bnTarget);
1376 }
1377
1378 int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget,arith_uint256 bhash)
1379 {
1380     CBlockIndex *previndex,*pindex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,PoSperc,txn_count,eligible=0,isPoS = 0,segid; uint64_t value; CTxDestination voutaddress;
1381     if ( ASSETCHAINS_STAKED == 100 && height <= 10 )
1382         return(1);
1383     pindex = mapBlockIndex[pblock->GetHash()];
1384     if ( pindex != 0 && pindex->segid >= -1 )
1385     {
1386         if ( pindex->segid == -1 )
1387             return(0);
1388         else return(1);
1389     }
1390     txn_count = pblock->vtx.size();
1391     if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 )
1392     {
1393         if ( prevtime == 0 )
1394         {
1395             if ( (previndex= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1396                 prevtime = (uint32_t)previndex->nTime;
1397         }
1398         txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1399         vout = pblock->vtx[txn_count-1].vin[0].prevout.n;
1400         if ( prevtime != 0 )
1401         {
1402             if ( komodo_isPoS(pblock) != 0 )
1403             {
1404                 eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"");
1405             }
1406             if ( eligible == 0 || eligible > pblock->nTime )
1407             {
1408                 if ( 0 && ASSETCHAINS_STAKED < 100 )
1409                     fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime));
1410                 if ( slowflag != 0 && pindex != 0 )
1411                 {
1412                     pindex->segid = -1;
1413                     fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
1414                 }
1415             }
1416             else
1417             {
1418                 isPoS = 2; // 2 means staking utxo validated
1419                 if ( slowflag != 0 && height > 100 )
1420                 {
1421                     segid = -3;
1422                     if ( pindex != 0 && pindex->segid == -2 && (segid= komodo_segid(1,height)) >= 0 )
1423                     {
1424                         pindex->segid = segid;
1425                         fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid);
1426                     } //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid);
1427                 }
1428             }
1429         }
1430         if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx
1431         {
1432             if ( komodo_isPoS(pblock) != 0 )
1433                 isPoS = 1;
1434         }
1435         if ( slowflag != 0 && isPoS != 0 )
1436         {
1437             if ( isPoS != 2 )
1438             {
1439                 fprintf(stderr,"ht.%d isPoS.%d utxo not validated -> must be PoW fake\n",height,isPoS);
1440                 isPoS = 0;
1441             }
1442             else
1443             {
1444                 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1445                 if ( bhash < bnTarget )
1446                 {
1447                     fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height);
1448                     isPoS = 0;
1449                 }
1450             }
1451         }
1452         //else return(-1);
1453     }
1454     //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
1455     return(isPoS != 0);
1456 }
1457
1458 bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
1459 bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating);
1460
1461 // for now, we will ignore slowFlag in the interest of keeping success/fail simpler for security purposes
1462 bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
1463 {
1464     CBlockIndex *pastBlockIndex;
1465     uint256 txid, blkHash;
1466     int32_t txn_count;
1467     uint32_t voutNum;
1468     CAmount value;
1469     bool isPOS = false;
1470     CTxDestination voutaddress, destaddress, cbaddress;
1471     arith_uint256 target, hash;
1472     CTransaction tx;
1473
1474     if (!pblock->IsVerusPOSBlock())
1475     {
1476         printf("%s, height %d not POS block\n", pblock->nNonce.GetHex().c_str(), height);
1477         //pblock->nNonce.SetPOSTarget(pblock->nNonce.GetPOSTarget());
1478         //printf("%s after setting POS target\n", pblock->nNonce.GetHex().c_str());
1479         return false;
1480     }
1481
1482     char voutaddr[64], destaddr[64], cbaddr[64];
1483
1484     txn_count = pblock->vtx.size();
1485
1486     if ( txn_count > 1 )
1487     {
1488         target.SetCompact(pblock->GetVerusPOSTarget());
1489         txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1490         voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
1491         value = pblock->vtx[txn_count-1].vout[0].nValue;
1492
1493         {
1494             bool validHash = true;
1495             bool enablePOSNonce = CPOSNonce::NewPOSActive(height);
1496             bool newPOSEnforcement = enablePOSNonce && (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= height);
1497             uint256 rawHash;
1498             arith_uint256 posHash;
1499             if (newPOSEnforcement)
1500             {
1501                 validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1502                 posHash = UintToArith256(rawHash) / value;
1503                 if (!validHash || posHash > target)
1504                 {
1505                     validHash = false;
1506                     printf("ERROR: invalid nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1507                             pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1508                 }
1509                 for (int i = 0; validHash && i < pblock->vtx[0].vout.size(); i++)
1510                 {
1511                     if (!ValidateMatchingStake(pblock->vtx[0], i, pblock->vtx[txn_count-1], validHash))
1512                     {
1513                         validHash = false;
1514                     }
1515                     else
1516                     {
1517                         // make sure prev block hash and block height are correct
1518                         CStakeParams p;
1519                         if (validHash = GetStakeParams(pblock->vtx[txn_count-1], p))
1520                         {
1521                             if (p.prevHash != pblock->hashPrevBlock || p.blkHeight != height)
1522                             {
1523                                 printf("ERROR: invalid block data for stake tx\nblkHash: %s\ntxBlkHash: %s\nblkHeight: %d\ntxBlkHeight: %d\n",
1524                                         pblock->hashPrevBlock.GetHex().c_str(), p.prevHash.GetHex().c_str(), height, p.blkHeight);
1525                                 validHash = false;
1526                             }
1527                         }
1528                     }
1529                 }
1530             }
1531             if (validHash)
1532             {
1533                 if (slowflag == 0)
1534                 {
1535                     isPOS = true;
1536                 }
1537                 else if (!(pastBlockIndex = komodo_chainactive(height - 100)))
1538                 {
1539                     fprintf(stderr,"ERROR: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str());
1540                 }
1541                 else 
1542 #ifndef KOMODO_ZCASH
1543                 if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
1544 #else
1545                 if (!GetTransaction(txid, tx, blkHash, true))
1546 #endif
1547                 {
1548                     fprintf(stderr,"ERROR: invalid PoS block %s - no source transaction\n",blkHash.ToString().c_str());
1549                 }
1550                 else
1551                 {
1552                     CBlockHeader bh = pastBlockIndex->GetBlockHeader();
1553                     uint256 pastHash = bh.GetVerusEntropyHash(height - 100);
1554
1555                     // if height is over when Nonce is required to be the new format, we check that the new format is correct
1556                     // if over when we have the new POS hash function, we validate that as well
1557                     // they are 100 blocks apart
1558                     CPOSNonce nonce = pblock->nNonce;
1559
1560                     //printf("before nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
1561                     //validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1562                     //hash = UintToArith256(rawHash) / tx.vout[voutNum].nValue;
1563                     //printf("Raw POShash:   %s\n", hash.GetHex().c_str());
1564
1565                     hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
1566
1567                     //printf("after nNonce:  %s, height: %d\n", nonce.GetHex().c_str(), height);
1568                     //printf("POShash:       %s\n\n", hash.GetHex().c_str());
1569
1570                     if ((!newPOSEnforcement || posHash == hash) && hash <= target)
1571                     {
1572                         if ((mapBlockIndex.count(blkHash) == 0) ||
1573                             !(pastBlockIndex = mapBlockIndex[blkHash]) || 
1574                             (height - pastBlockIndex->GetHeight()) < VERUS_MIN_STAKEAGE)
1575                         {
1576                             fprintf(stderr,"ERROR: invalid PoS block %s - stake transaction too new\n",blkHash.ToString().c_str());
1577                         }
1578                         else
1579                         {
1580                             // make sure we have the right target
1581                             CBlockIndex *previndex;
1582                             if (!(previndex = mapBlockIndex[pblock->hashPrevBlock]))
1583                             {
1584                                 fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
1585                             }
1586                             else
1587                             {
1588                                 arith_uint256 cTarget;
1589                                 uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
1590                                 cTarget.SetCompact(nBits);
1591                                 bool nonceOK = true;
1592
1593                                 // check to see how many fail
1594                                 //if (nonce != pblock->nNonce)
1595                                 //    printf("Mismatched nNonce: %s\nblkHash: %s, height: %d\n", nonce.GetHex().c_str(), pblock->GetHash().GetHex().c_str(), height);
1596
1597                                 if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum))
1598                                 {
1599                                     fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
1600                                     nonceOK = false;
1601                                 }
1602                                 else
1603                                 {
1604                                     if (cTarget != target)
1605                                     {
1606                                         fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
1607                                         nonceOK = false;
1608                                     }
1609                                 }
1610                                 if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) &&
1611                                         ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
1612                                         CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
1613                                 {
1614                                     strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
1615                                     strcpy(destaddr, CBitcoinAddress(destaddress).ToString().c_str());
1616                                     strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
1617                                     if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
1618                                     {
1619                                         isPOS = true;
1620                                     }
1621                                     else
1622                                     {
1623                                         fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n",blkHash.ToString().c_str());
1624                                     }
1625                                 }
1626                             }
1627                         }
1628                     }
1629                     else
1630                     {
1631                         printf("ERROR: malformed nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1632                             pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1633                     }
1634                 }
1635             }
1636         }
1637     }
1638     return(isPOS);
1639 }
1640
1641 int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1642 {
1643     int64_t checktoshis=0; uint8_t *script;
1644     if ( ASSETCHAINS_COMMISSION != 0 )
1645     {
1646         checktoshis = komodo_commission(pblock);
1647         if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1648             return(-1);
1649         else if ( checktoshis != 0 )
1650         {
1651             script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
1652             if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1653                 return(-1);
1654             if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1655             {
1656                 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1657                 return(-1);
1658             }
1659         }
1660     }
1661     return(checktoshis);
1662 }
1663
1664 bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1665
1666 int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1667 {
1668     uint256 hash; arith_uint256 bnTarget,bhash; bool fNegative,fOverflow; uint8_t *script,pubkey33[33],pubkeys[64][33]; int32_t i,possible,PoSperc,is_PoSblock=0,n,failed = 0,notaryid = -1; int64_t checktoshis,value; CBlockIndex *pprev;
1669     if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
1670         KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
1671     if ( !CheckEquihashSolution(pblock, Params()) )
1672     {
1673         fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1674         return(-1);
1675     }
1676     hash = pblock->GetHash();
1677     bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1678     bhash = UintToArith256(hash);
1679     possible = komodo_block2pubkey33(pubkey33,pblock);
1680     if ( height == 0 )
1681     {
1682         if ( slowflag != 0 )
1683         {
1684             fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
1685             return(0);
1686         }
1687         if ( (pprev= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1688             height = pprev->GetHeight() + 1;
1689         if ( height == 0 )
1690             return(0);
1691     }
1692     if ( ASSETCHAINS_LWMAPOS != 0 && bhash > bnTarget )
1693     {
1694         // if proof of stake is active, check if this is a valid PoS block before we fail
1695         if (verusCheckPOSBlock(slowflag, pblock, height))
1696         {
1697             return(0);
1698         }
1699     }
1700     if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget )
1701     {
1702         failed = 1;
1703         if ( height > 0 && ASSETCHAINS_SYMBOL[0] == 0 ) // for the fast case
1704         {
1705             if ( (n= komodo_notaries(pubkeys,height,pblock->nTime)) > 0 )
1706             {
1707                 for (i=0; i<n; i++)
1708                     if ( memcmp(pubkey33,pubkeys[i],33) == 0 )
1709                     {
1710                         notaryid = i;
1711                         break;
1712                     }
1713             }
1714         }
1715         else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 )
1716         {
1717             if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW )
1718                 return(0);
1719             if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget for staked chains
1720                 return(-1);
1721         }
1722     }
1723     if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
1724     {
1725         if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget,bhash)) == 0 )
1726         {
1727             if ( ASSETCHAINS_STAKED == 100 && height > 100 )  // only PoS allowed! POSTEST64
1728                 return(-1);
1729             else
1730             {
1731                 if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target
1732                     return(0);
1733                 if ( slowflag != 0 )
1734                     bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1735                 if ( bhash > bnTarget )
1736                 {
1737                     for (i=31; i>=16; i--)
1738                         fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]);
1739                     fprintf(stderr," > ");
1740                     for (i=31; i>=16; i--)
1741                         fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1742                     fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED);
1743                     return(-1);
1744                 } else failed = 0;
1745             }
1746         }
1747         else if ( is_PoSblock < 0 )
1748         {
1749             fprintf(stderr,"unexpected negative is_PoSblock.%d\n",is_PoSblock);
1750             return(-1);
1751         }
1752     }
1753     if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
1754     {
1755         if ( height == 1 )
1756         {
1757             script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
1758             if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1759                 return(-1);
1760         }
1761         else
1762         {
1763             if ( komodo_checkcommission(pblock,height) < 0 )
1764                 return(-1);
1765         }
1766     }
1767     //fprintf(stderr,"komodo_checkPOW possible.%d slowflag.%d ht.%d notaryid.%d failed.%d\n",possible,slowflag,height,notaryid,failed);
1768     if ( failed != 0 && possible == 0 && notaryid < 0 )
1769         return(-1);
1770     else return(0);
1771 }
1772
1773 int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
1774 {
1775     CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
1776     n = pblock->vtx.size();
1777     for (i=0; i<n; i++)
1778     {
1779         CTransaction vintx,&tx = pblock->vtx[i];
1780         zfunds += (tx.GetValueOut() - tx.GetShieldedValueIn());
1781         if ( (m= tx.vin.size()) > 0 )
1782         {
1783             for (j=0; j<m; j++)
1784             {
1785                 if ( i == 0 )
1786                     continue;
1787                 txid = tx.vin[j].prevout.hash;
1788                 vout = tx.vin[j].prevout.n;
1789                 if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
1790                 {
1791                     fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1792                     return(0);
1793                 }
1794                 vinsum += vintx.vout[vout].nValue;
1795             }
1796         }
1797         if ( (m= tx.vout.size()) > 0 )
1798         {
1799             for (j=0; j<m-1; j++)
1800             {
1801                 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1802                     voutsum += tx.vout[j].nValue;
1803                 else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
1804             }
1805             script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
1806             if ( script == 0 || script[0] != 0x6a )
1807             {
1808                 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1809                     voutsum += tx.vout[j].nValue;
1810             }
1811         }
1812     }
1813     *zfundsp = zfunds;
1814     if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times
1815         return(3 * SATOSHIDEN);
1816     //if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 )
1817     //.    fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
1818     return(voutsum - vinsum);
1819 }
1820
1821 int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
1822 {
1823     CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
1824     //fprintf(stderr,"coinsupply %d\n",height);
1825     *zfundsp = 0;
1826     if ( (pindex= komodo_chainactive(height)) != 0 )
1827     {
1828         while ( pindex != 0 && pindex->GetHeight() > 0 )
1829         {
1830             if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
1831             {
1832                 if ( komodo_blockload(block,pindex) == 0 )
1833                     pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->GetHeight(),&block);
1834                 else
1835                 {
1836                     fprintf(stderr,"error loading block.%d\n",pindex->GetHeight());
1837                     return(0);
1838                 }
1839             }
1840             supply += pindex->newcoins;
1841             zfunds += pindex->zfunds;
1842             //printf("start ht.%d new %.8f -> supply %.8f zfunds %.8f -> %.8f\n",pindex->GetHeight(),dstr(pindex->newcoins),dstr(supply),dstr(pindex->zfunds),dstr(zfunds));
1843             pindex = pindex->pprev;
1844         }
1845     }
1846     *zfundsp = zfunds;
1847     return(supply);
1848 }
This page took 0.137507 seconds and 4 git commands to generate.