]> Git Repo - VerusCoin.git/blame_incremental - src/komodo_bitcoind.h
Enable mining requires peers and default VRSCTEST nodes
[VerusCoin.git] / src / komodo_bitcoind.h
... / ...
CommitLineData
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
25int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
26int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
27unsigned 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
31struct MemoryStruct { char *memory; size_t size; };
32struct 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
46void 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
64size_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
94char *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
145char *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);
163try_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
272static 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
288char *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
335char *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
352int32_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
406int32_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
422int32_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
528uint64_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
558uint32_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
581uint32_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
607int32_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
631void 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
643int32_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
663int32_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
702int32_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
727int32_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
744uint32_t komodo_chainactive_timestamp()
745{
746 if ( chainActive.LastTip() != 0 )
747 return((uint32_t)chainActive.LastTip()->GetBlockTime());
748 else return(0);
749}
750
751CBlockIndex *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
763uint32_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
813void 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
852int32_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
884int32_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
913int32_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
970int32_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
986int32_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
1016uint32_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
1041uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
1042
1043uint64_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
1059int32_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
1070int32_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
1102uint64_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
1123uint32_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
1130int8_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
1160int32_t 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
1183uint32_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
1194uint32_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
1278arith_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
1380int32_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
1460bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
1461bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating);
1462bool 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
1465bool 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::SOLUTION_VERUSV3;
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 CBlockHeader bh = pastBlockIndex->GetBlockHeader();
1558 uint256 pastHash = bh.GetVerusEntropyHash(height - 100);
1559
1560 // if height is over when Nonce is required to be the new format, we check that the new format is correct
1561 // if over when we have the new POS hash function, we validate that as well
1562 // they are 100 blocks apart
1563 CPOSNonce nonce = pblock->nNonce;
1564
1565 //printf("before nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
1566 //validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1567 //hash = UintToArith256(rawHash) / tx.vout[voutNum].nValue;
1568 //printf("Raw POShash: %s\n", hash.GetHex().c_str());
1569
1570 hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
1571
1572 //printf("after nNonce: %s, height: %d\n", nonce.GetHex().c_str(), height);
1573 //printf("POShash: %s\n\n", hash.GetHex().c_str());
1574
1575 if ((!newPOSEnforcement || posHash == hash) && hash <= target)
1576 {
1577 BlockMap::const_iterator it = mapBlockIndex.find(blkHash);
1578 if ((it == mapBlockIndex.end()) ||
1579 !(pastBlockIndex = it->second) ||
1580 (height - pastBlockIndex->GetHeight()) < VERUS_MIN_STAKEAGE)
1581 {
1582 fprintf(stderr,"ERROR: invalid PoS block %s - stake source too new or not found\n",blkHash.ToString().c_str());
1583 }
1584 else
1585 {
1586 // make sure we have the right target
1587 CBlockIndex *previndex;
1588 it = mapBlockIndex.find(pblock->hashPrevBlock);
1589 if (it == mapBlockIndex.end() || !(previndex = it->second))
1590 {
1591 fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
1592 }
1593 else
1594 {
1595 arith_uint256 cTarget;
1596 uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
1597 cTarget.SetCompact(nBits);
1598 bool nonceOK = true;
1599
1600 // check to see how many fail
1601 //if (nonce != pblock->nNonce)
1602 // printf("Mismatched nNonce: %s\nblkHash: %s, height: %d\n", nonce.GetHex().c_str(), pblock->GetHash().GetHex().c_str(), height);
1603
1604 if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum, pblock->nVersion))
1605 {
1606 fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
1607 nonceOK = false;
1608 }
1609 else
1610 {
1611 if (cTarget != target)
1612 {
1613 fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
1614 nonceOK = false;
1615 }
1616 }
1617 if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) &&
1618 ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
1619 CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
1620 {
1621 strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
1622 strcpy(destaddr, CBitcoinAddress(destaddress).ToString().c_str());
1623 strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
1624 if (newPOSEnforcement)
1625 {
1626 if (!strcmp(destaddr, voutaddr))
1627 {
1628 // allow delegation of stake, but require all ouputs to be
1629 // crypto conditions
1630 CStakeParams p;
1631
1632 // validatestake transaction sets the pubkey of the stake output
1633 // if it has no override into the pubkey
1634 if (ValidateStakeTransaction(pblock->vtx[txn_count-1], p, false))
1635 {
1636 COptCCParams cpp;
1637 // loop through all outputs to make sure they are sent to the proper pubkey
1638 isPOS = true;
1639 for (auto vout : pblock->vtx[0].vout)
1640 {
1641 txnouttype tp;
1642 std::vector<std::vector<unsigned char>> vvch = std::vector<std::vector<unsigned char>>();
1643 // solve all outputs to check that non-instantspend destinations all go only to the pk
1644 // specified in the stake params
1645 if ((!supportInstantSpend || !vout.scriptPubKey.IsInstantSpend()) &&
1646 (!Solver(vout.scriptPubKey, tp, vvch) ||
1647 tp != TX_CRYPTOCONDITION ||
1648 vvch.size() < 2 ||
1649 p.pk != CPubKey(vvch[0])))
1650 {
1651 isPOS = false;
1652 break;
1653 }
1654 }
1655 }
1656 }
1657 }
1658 else if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
1659 {
1660 isPOS = true;
1661 }
1662 else
1663 {
1664 fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n",blkHash.ToString().c_str());
1665 }
1666 }
1667 }
1668 }
1669 }
1670 else
1671 {
1672 printf("ERROR: malformed nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1673 pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1674 }
1675 }
1676 }
1677 }
1678 }
1679 return(isPOS);
1680}
1681
1682int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1683{
1684 int64_t checktoshis=0; uint8_t *script;
1685 if ( ASSETCHAINS_COMMISSION != 0 )
1686 {
1687 checktoshis = komodo_commission(pblock);
1688 if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1689 return(-1);
1690 else if ( checktoshis != 0 )
1691 {
1692 script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
1693 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1694 return(-1);
1695 if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1696 {
1697 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1698 return(-1);
1699 }
1700 }
1701 }
1702 return(checktoshis);
1703}
1704
1705bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1706
1707int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1708{
1709 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;
1710 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
1711 KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
1712 if ( !CheckEquihashSolution(pblock, Params().GetConsensus()) )
1713 {
1714 fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1715 return(-1);
1716 }
1717 hash = pblock->GetHash();
1718 bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1719 bhash = UintToArith256(hash);
1720 possible = komodo_block2pubkey33(pubkey33,pblock);
1721 if ( height == 0 )
1722 {
1723 if ( slowflag != 0 )
1724 {
1725 fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
1726 return(0);
1727 }
1728 BlockMap::const_iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
1729 if ( it != mapBlockIndex.end() && (pprev= it->second) != 0 )
1730 height = pprev->GetHeight() + 1;
1731 if ( height == 0 )
1732 return(0);
1733 }
1734 if ( ASSETCHAINS_LWMAPOS != 0 && bhash > bnTarget )
1735 {
1736 // if proof of stake is active, check if this is a valid PoS block before we fail
1737 if (verusCheckPOSBlock(slowflag, pblock, height))
1738 {
1739 return(0);
1740 }
1741 }
1742 if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget )
1743 {
1744 failed = 1;
1745 if ( height > 0 && ASSETCHAINS_SYMBOL[0] == 0 ) // for the fast case
1746 {
1747 if ( (n= komodo_notaries(pubkeys,height,pblock->nTime)) > 0 )
1748 {
1749 for (i=0; i<n; i++)
1750 if ( memcmp(pubkey33,pubkeys[i],33) == 0 )
1751 {
1752 notaryid = i;
1753 break;
1754 }
1755 }
1756 }
1757 else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 )
1758 {
1759 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW )
1760 return(0);
1761 if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget for staked chains
1762 return(-1);
1763 }
1764 }
1765 if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
1766 {
1767 if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget,bhash)) == 0 )
1768 {
1769 if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! POSTEST64
1770 return(-1);
1771 else
1772 {
1773 if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target
1774 return(0);
1775 if ( slowflag != 0 )
1776 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1777 if ( bhash > bnTarget )
1778 {
1779 for (i=31; i>=16; i--)
1780 fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]);
1781 fprintf(stderr," > ");
1782 for (i=31; i>=16; i--)
1783 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1784 fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED);
1785 return(-1);
1786 } else failed = 0;
1787 }
1788 }
1789 else if ( is_PoSblock < 0 )
1790 {
1791 fprintf(stderr,"unexpected negative is_PoSblock.%d\n",is_PoSblock);
1792 return(-1);
1793 }
1794 }
1795 if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
1796 {
1797 if ( height == 1 )
1798 {
1799 script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
1800 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1801 return(-1);
1802 }
1803 else
1804 {
1805 if ( komodo_checkcommission(pblock,height) < 0 )
1806 return(-1);
1807 }
1808 }
1809 //fprintf(stderr,"komodo_checkPOW possible.%d slowflag.%d ht.%d notaryid.%d failed.%d\n",possible,slowflag,height,notaryid,failed);
1810 if ( failed != 0 && possible == 0 && notaryid < 0 )
1811 return(-1);
1812 else return(0);
1813}
1814
1815int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
1816{
1817 CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
1818 n = pblock->vtx.size();
1819 for (i=0; i<n; i++)
1820 {
1821 CTransaction vintx,&tx = pblock->vtx[i];
1822 zfunds += (tx.GetShieldedValueOut() - tx.GetShieldedValueIn());
1823 if ( (m= tx.vin.size()) > 0 )
1824 {
1825 for (j=0; j<m; j++)
1826 {
1827 if ( i == 0 )
1828 continue;
1829 txid = tx.vin[j].prevout.hash;
1830 vout = tx.vin[j].prevout.n;
1831 if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
1832 {
1833 fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1834 return(0);
1835 }
1836 vinsum += vintx.vout[vout].nValue;
1837 }
1838 }
1839 if ( (m= tx.vout.size()) > 0 )
1840 {
1841 for (j=0; j<m-1; j++)
1842 {
1843 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1844 voutsum += tx.vout[j].nValue;
1845 else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
1846 }
1847 script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
1848 if ( script == 0 || script[0] != 0x6a )
1849 {
1850 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1851 voutsum += tx.vout[j].nValue;
1852 }
1853 }
1854 }
1855 *zfundsp = zfunds;
1856 if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times
1857 return(3 * SATOSHIDEN);
1858 //if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 )
1859 //. fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
1860 return(voutsum - vinsum);
1861}
1862
1863int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
1864{
1865 CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
1866 //fprintf(stderr,"coinsupply %d\n",height);
1867 *zfundsp = 0;
1868 if ( (pindex= komodo_chainactive(height)) != 0 )
1869 {
1870 while ( pindex != 0 && pindex->GetHeight() > 0 )
1871 {
1872 if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
1873 {
1874 if ( komodo_blockload(block,pindex) == 0 )
1875 pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->GetHeight(),&block);
1876 else
1877 {
1878 fprintf(stderr,"error loading block.%d\n",pindex->GetHeight());
1879 return(0);
1880 }
1881 }
1882 supply += pindex->newcoins;
1883 zfunds += pindex->zfunds;
1884 //printf("start ht.%d new %.8f -> supply %.8f zfunds %.8f -> %.8f\n",pindex->GetHeight(),dstr(pindex->newcoins),dstr(supply),dstr(pindex->zfunds),dstr(zfunds));
1885 pindex = pindex->pprev;
1886 }
1887 }
1888 *zfundsp = zfunds;
1889 return(supply);
1890}
This page took 0.052746 seconds and 4 git commands to generate.