]> Git Repo - VerusCoin.git/blame - src/komodo_bitcoind.h
move things around and some debugging code for odd issues
[VerusCoin.git] / src / komodo_bitcoind.h
CommitLineData
d019c447 1/******************************************************************************
713c2a94 2 * Copyright © 2014-2018 The SuperNET Developers. *
d019c447 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
3eea72f2 16// komodo functions that interact with bitcoind C++
17
9d365796 18#include <curl/curl.h>
19#include <curl/easy.h>
9feb4b9e 20#include "primitives/nonce.h"
21#include "consensus/params.h"
5416af1d 22#include "komodo_defs.h"
185b2d4f 23#include "script/standard.h"
5416af1d 24
c615ffff 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);
1f722359 27unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
c615ffff 28
36c733e9 29//#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
77be6cd9 30
9b0e1808 31struct MemoryStruct { char *memory; size_t size; };
c2b50ce0 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
4ec67e74 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}
c2b50ce0 57
4ec67e74 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}
c2b50ce0 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
c2b50ce0 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:");
f796b1fb 170
171 curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
c2b50ce0 172 curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers);
173 curl_easy_setopt(curl_handle,CURLOPT_URL, url);
4ec67e74 174 curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function
c2b50ce0 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
f796b1fb 177 curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback
c2b50ce0 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 }
f796b1fb 199
c2b50ce0 200 databuf = (char *)malloc(256 + strlen(command) + strlen(params));
201 sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1);
05e307ec 202 //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf);
c2b50ce0 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 }
c59a3beb 228 else if ( numretries >= 1 )
c2b50ce0 229 {
bb7f7473 230 //printf("Maximum number of retries exceeded!\n");
c2b50ce0 231 free(s.ptr);
232 return(0);
233 }
32323ea1 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);
c2b50ce0 236 free(s.ptr);
237 sleep((1<<numretries));
238 goto try_again;
f796b1fb 239
c2b50ce0 240 }
241 else
242 {
243 if ( command != 0 && specialcase == 0 )
244 {
245 count++;
246 elapsedsum += (OS_milliseconds() - starttime);
32323ea1 247 if ( (count % 1000000) == 0)
c2b50ce0 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}
9b0e1808 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;
b858fa74 276 mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1));
9b0e1808 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
05d3d5ff 288char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3)
9b0e1808 289{
290 struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
291 if ( (cHandle= *cHandlep) == NULL )
f796b1fb 292 *cHandlep = cHandle = curl_easy_init();
9b0e1808 293 else curl_easy_reset(cHandle);
294 //#ifdef DEBUG
f796b1fb 295 //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
9b0e1808 296 //#endif
f796b1fb 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);
9b0e1808 302 if ( userpass != 0 && userpass[0] != 0 )
303 curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
f796b1fb 304 if ( postfields != 0 && postfields[0] != 0 )
9b0e1808 305 {
306 curl_easy_setopt(cHandle,CURLOPT_POST,1);
f796b1fb 307 curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
9b0e1808 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
0ded57c8 335char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
9b0e1808 336{
4ac6cd92 337 //static void *cHandle;
a9132082 338 char url[512],*retstr=0,*retstr2=0,postdata[8192];
365378b5 339 if ( params == 0 || params[0] == 0 )
340 params = (char *)"[]";
9b0e1808 341 if ( strlen(params) < sizeof(postdata)-128 )
342 {
3c0f5d94 343 sprintf(url,(char *)"http://127.0.0.1:%u",port);
9b0e1808 344 sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params);
05e307ec 345 //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS);
0ded57c8 346 retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params);
c2b50ce0 347 //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0);
9b0e1808 348 }
1ccb1cf0 349 return(retstr2);
9b0e1808 350}
351
0cb025c1 352int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp)
b000fa04 353{
0cb025c1 354 char *jsonstr,params[256],*userpass; uint16_t port; cJSON *json,*item; int32_t height = 0,txid_height = 0,txid_confirmations = 0;
b000fa04 355 params[0] = 0;
356 *kmdnotarized_heightp = 0;
0cb025c1 357 if ( strcmp(dest,"KMD") == 0 )
b000fa04 358 {
05e307ec 359 port = KMD_PORT;
0cb025c1 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 )
b000fa04 371 {
70d83934 372 //printf("(%s)\n",jsonstr);
b000fa04 373 if ( (json= cJSON_Parse(jsonstr)) != 0 )
374 {
978ca795 375 if ( (item= jobj(json,(char *)"result")) != 0 )
033f496d 376 {
033f496d 377 height = jint(item,(char *)"blocks");
57dd4ada 378 *kmdnotarized_heightp = strcmp(dest,"KMD") == 0 ? jint(item,(char *)"notarized") : height;
033f496d 379 }
b000fa04 380 free_json(json);
381 }
382 free(jsonstr);
383 }
384 sprintf(params,"[\"%s\", 1]",txidstr);
0cb025c1 385 if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getrawtransaction",params,port)) != 0 )
b000fa04 386 {
70d83934 387 //printf("(%s)\n",jsonstr);
b000fa04 388 if ( (json= cJSON_Parse(jsonstr)) != 0 )
389 {
978ca795 390 if ( (item= jobj(json,(char *)"result")) != 0 )
033f496d 391 {
392 txid_confirmations = jint(item,(char *)"confirmations");
033f496d 393 if ( txid_confirmations > 0 && height > txid_confirmations )
394 txid_height = height - txid_confirmations;
19857195 395 else txid_height = height;
094b401e 396 //printf("height.%d tconfs.%d txid_height.%d\n",height,txid_confirmations,txid_height);
033f496d 397 }
b000fa04 398 free_json(json);
399 }
400 free(jsonstr);
401 }
43cc3df6 402 }
b000fa04 403 return(txid_height);
404}
405
20a5cb84 406int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH)
b55c2367 407{
408 int32_t i; uint256 hash; char params[256];
409 for (i=0; i<32; i++)
ebd18944 410 ((uint8_t *)&hash)[i] = script[2+i];
d56e5945 411 if ( hash == NOTARIZED_HASH )
3e9fcad0 412 return(1);
b556919a 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]);
895977bf 418 printf(" opreturn from [%s] ht.%d MISMATCHED\n",ASSETCHAINS_SYMBOL,height);
b556919a 419 return(-1);
b55c2367 420}
421
422int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
423{
3da303b5 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;
c3153900 426 /*params[0] = '[';
f796b1fb 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]");*/
c3153900 431 sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
ed937645 432 if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
433 return(0);
05c1e522 434 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
a0b9382c 435 printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",ASSETCHAINS_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT);
b55c2367 436 if ( strcmp(dest,"KMD") == 0 )
b148643e 437 {
438 if ( KMDUSERPASS[0] != 0 )
5201bb51 439 {
440 if ( ASSETCHAINS_SYMBOL[0] != 0 )
a0b9382c 441 {
05e307ec 442 jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT);
f796b1fb 443 //printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr);
a0b9382c 444 }
445 }//else jsonstr = _dex_getrawtransaction();
48d0e5df 446 else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
b148643e 447 }
b55c2367 448 else if ( strcmp(dest,"BTC") == 0 )
b148643e 449 {
450 if ( BTCUSERPASS[0] != 0 )
48d0e5df 451 {
eee28662 452 //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS);
b148643e 453 jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332);
48d0e5df 454 }
b148643e 455 //else jsonstr = _dex_getrawtransaction();
48d0e5df 456 else return(0);
b148643e 457 }
9674c671 458 else
459 {
460 printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest);
461 return(-1);
462 }
b55c2367 463 if ( jsonstr != 0 )
464 {
13b64fd6 465 if ( (json= cJSON_Parse(jsonstr)) != 0 )
b55c2367 466 {
fa73aa67 467 if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 )
b55c2367 468 {
469 vout = jitem(vouts,n-1);
34c68daa 470 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
a0b9382c 471 printf("vout.(%s)\n",jprint(vout,0));
523a5dc7 472 if ( (skey= jobj(vout,(char *)"scriptPubKey")) != 0 )
b55c2367 473 {
523a5dc7 474 if ( (hexstr= jstr(skey,(char *)"hex")) != 0 )
b55c2367 475 {
895977bf 476 //printf("HEX.(%s) vs hash.%s\n",hexstr,NOTARIZED_HASH.ToString().c_str());
b55c2367 477 len = strlen(hexstr) >> 1;
478 decode_hex(script,len,hexstr);
279fac91 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 }
20a5cb84 489 retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH);
b55c2367 490 }
491 }
492 }
493 free_json(txjson);
494 }
495 free(jsonstr);
496 }
497 return(retval);
498}
499
2934460c 500/*uint256 komodo_getblockhash(int32_t height)
f796b1fb 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);
05c2ba63 505 if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_RPCPORT)) != 0 )
f796b1fb 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);*/
6b0e06b5 527
23256cca 528uint64_t komodo_seed(int32_t height)
529{
39b462c7 530 uint64_t seed = 0;
2934460c 531 /*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
f796b1fb 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*/
8aef9e40 549 {
93fb251c 550 seed = (height << 13) ^ (height << 2);
551 seed <<= 21;
8aef9e40 552 seed |= (height & 0xffffffff);
93fb251c 553 seed ^= (seed << 17) ^ (seed << 1);
8aef9e40 554 }
23256cca 555 return(seed);
556}
557
1f722359 558uint32_t komodo_txtime(uint64_t *valuep,uint256 hash, int32_t n, char *destaddr)
3eea72f2 559{
8d584a9c 560 CTxDestination address; CTransaction tx; uint256 hashBlock;
ce5dd547 561 *valuep = 0;
7637aa7f 562 if (!GetTransaction(hash, tx,
563#ifndef KOMODO_ZCASH
564 Params().GetConsensus(),
565#endif
566 hashBlock, true))
3eea72f2 567 {
4ff37947 568 //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
2ef19f04 569 return(0);
3eea72f2 570 }
1619474e 571 //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
2ef19f04 572 if ( n < tx.vout.size() )
8d584a9c 573 {
2ef19f04 574 *valuep = tx.vout[n].nValue;
fa4d9e24 575 if (ExtractDestination(tx.vout[n].scriptPubKey, address))
576 strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
8d584a9c 577 }
2ef19f04 578 return(tx.nLockTime);
3eea72f2 579}
580
0a953df2 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 }
ec894008 594 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
0a953df2 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
d1db0920 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 {
88084272 622 //fprintf(stderr,"is PoS block!\n");
d1db0920 623 return(1);
624 }
625 }
626 }
627 }
628 return(0);
629}
630
3eea72f2 631void komodo_disconnect(CBlockIndex *pindex,CBlock& block)
632{
7c130297 633 char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
4b729ec5 634 //fprintf(stderr,"disconnect ht.%d\n",pindex->GetHeight());
635 komodo_init(pindex->GetHeight());
f3a1de3a 636 if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
7a183152 637 {
4b729ec5 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);
3eea72f2 641}
642
f24b36ca 643int32_t komodo_is_notarytx(const CTransaction& tx)
644{
faf51f1a 645 uint8_t *ptr; static uint8_t crypto777[33];
0554de3c 646 if ( tx.vout.size() > 0 )
647 {
0554de3c 648 ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0];
0554de3c 649 if ( ptr != 0 )
303fbd20 650 {
faf51f1a 651 if ( crypto777[0] == 0 )
652 decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
0554de3c 653 if ( memcmp(ptr+1,crypto777,33) == 0 )
654 {
655 //printf("found notarytx\n");
656 return(1);
657 }
303fbd20 658 }
f24b36ca 659 }
303fbd20 660 return(0);
f24b36ca 661}
662
3eea72f2 663int32_t komodo_block2height(CBlock *block)
664{
e1501755 665 static uint32_t match,mismatch;
c52074f2 666 int32_t i,n,height2=-1,height = 0; uint8_t *ptr; CBlockIndex *pindex;
667 if ( (pindex= mapBlockIndex[block->GetHash()]) != 0 )
8a0b06f6 668 {
4b729ec5 669 height2 = (int32_t)pindex->GetHeight();
8a0b06f6 670 if ( height2 >= 0 )
671 return(height2);
672 }
83064643 673 if ( block != 0 && block->vtx[0].vin.size() > 0 )
0554de3c 674 {
0554de3c 675 ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
0554de3c 676 if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
3eea72f2 677 {
0554de3c 678 //for (i=0; i<6; i++)
679 // printf("%02x",ptr[i]);
680 n = ptr[0];
643bc61b 681 for (i=0; i<n; i++) // looks strange but this works
0554de3c 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 }
643bc61b 687 //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
3eea72f2 688 }
0554de3c 689 //komodo_init(height);
3eea72f2 690 }
d4cc6fc3 691 if ( height != height2 )
c52074f2 692 {
f73e64e0 693 //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch);
d4cc6fc3 694 mismatch++;
695 if ( height2 >= 0 )
f717835b 696 height = height2;
d4cc6fc3 697 } else match++;
3eea72f2 698 return(height);
699}
700
9464ac21 701int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
3eea72f2 702{
2dbf06e8 703 int32_t n;
0690e63e 704 if ( KOMODO_LOADINGBLOCKS == 0 )
705 memset(pubkey33,0xff,33);
706 else memset(pubkey33,0,33);
19848155 707 if ( block->vtx[0].vout.size() > 0 )
0554de3c 708 {
1f722359
MT
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)
9464ac21 712 {
1f722359
MT
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);
9464ac21 720 }
1f722359 721 else memset(pubkey33,0,33);
0554de3c 722 }
9464ac21 723 return(0);
3eea72f2 724}
725
d7093b33 726int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
875cf683 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
ae0bb3d3 743uint32_t komodo_chainactive_timestamp()
744{
86131275 745 if ( chainActive.LastTip() != 0 )
746 return((uint32_t)chainActive.LastTip()->GetBlockTime());
e34a9d43 747 else return(0);
ae0bb3d3 748}
749
7d44d3dd 750CBlockIndex *komodo_chainactive(int32_t height)
751{
049e890a 752 if ( chainActive.LastTip() != 0 )
7d44d3dd 753 {
4b729ec5 754 if ( height <= chainActive.LastTip()->GetHeight() )
5150cb47 755 return(chainActive[height]);
4b729ec5 756 // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.LastTip()->GetHeight());
d54aa57d 757 }
86131275 758 //fprintf(stderr,"komodo_chainactive null chainActive.LastTip() height %d\n",height);
d54aa57d 759 return(0);
7d44d3dd 760}
761
762uint32_t komodo_heightstamp(int32_t height)
763{
0cb1d2da 764 CBlockIndex *ptr;
58bec1f9 765 if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
f21afd94 766 return(ptr->nTime);
b91ef9cf 767 //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
7d44d3dd 768 return(0);
769}
770
232506f7 771/*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted
3eea72f2 772{
5368f298 773 int32_t i,num; uint8_t pubkeys[64][33]; CBlock block;
5920762d 774 if ( pindex->didinit != 0 )
2b00bd23 775 return;
4b729ec5 776 //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->GetHeight(),pindex->notaryid,height);
065505b7 777 if ( pindex->didinit == 0 )
3eea72f2 778 {
326ddd86 779 pindex->notaryid = -1;
0690e63e 780 if ( KOMODO_LOADINGBLOCKS == 0 )
1f333439 781 memset(pindex->pubkey33,0xff,33);
0690e63e 782 else memset(pindex->pubkey33,0,33);
1746e25c 783 if ( komodo_blockload(block,pindex) == 0 )
a76b835b 784 {
19848155 785 komodo_block2pubkey33(pindex->pubkey33,&block);
3884efe7 786 //for (i=0; i<33; i++)
787 // fprintf(stderr,"%02x",pindex->pubkey33[i]);
4b729ec5 788 //fprintf(stderr," set pubkey at height %d/%d\n",pindex->GetHeight(),height);
702f7543 789 //if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 )
232506f7 790 // pindex->didinit = (KOMODO_LOADINGBLOCKS == 0);
4b729ec5 791 } // else fprintf(stderr,"error loading block at %d/%d",pindex->GetHeight(),height);
3eea72f2 792 }
4b729ec5 793 if ( pindex->didinit != 0 && pindex->GetHeight() >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->GetHeight(),(uint32_t)pindex->nTime)) > 0 )
3eea72f2 794 {
2b00bd23 795 for (i=0; i<num; i++)
141950a4 796 {
2b00bd23 797 if ( memcmp(pubkeys[i],pindex->pubkey33,33) == 0 )
141950a4 798 {
2b00bd23 799 pindex->notaryid = i;
800 break;
141950a4 801 }
802 }
524e0280 803 if ( 0 && i == num )
ace61bc1 804 {
805 for (i=0; i<33; i++)
806 fprintf(stderr,"%02x",pindex->pubkey33[i]);
4b729ec5 807 fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->GetHeight(),height);
ace61bc1 808 }
3eea72f2 809 }
faf51f1a 810}*/
875cf683 811
3eea72f2 812void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
813{
232506f7 814 int32_t num,i; CBlock block;
3eea72f2 815 memset(pubkey33,0,33);
071f1be1 816 if ( pindex != 0 )
3eea72f2 817 {
232506f7 818 if ( komodo_blockload(block,pindex) == 0 )
819 komodo_block2pubkey33(pubkey33,&block);
3eea72f2 820 }
821}
6034c671 822
da9fce3e 823/*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33)
4a4e912b 824{
149a4d64 825 int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t pubkey33[33],pubkeys[64][33];
3e7e3109 826 if ( (pindex= chainActive[height]) != 0 )
fc318ffe 827 {
d74896c5 828 if ( pindex->didinit != 0 )
5e0e5f85 829 {
149a4d64 830 if ( destpubkey33 != 0 )
831 memcpy(destpubkey33,pindex->pubkey33,33);
3e7e3109 832 return(pindex->notaryid);
5e0e5f85 833 }
149a4d64 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);
5e0e5f85 839 timestamp = pindex->GetBlockTime();
eb7171f5 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);
1746e25c 845 }
dac1ef88 846 }
0f29cbd6 847 fprintf(stderr,"komodo_minerid height.%d null pindex\n",height);
8eaa7b03 848 return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp));
da9fce3e 849}*/
4a4e912b 850
a30dd993 851int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height)
353af8aa 852{
178618db 853 int32_t i,j,n,duplicate; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33];
353af8aa 854 memset(mids,-1,sizeof(*mids)*66);
1481a43d 855 n = komodo_notaries(notarypubs33,height,0);
353af8aa 856 for (i=duplicate=0; i<66; i++)
857 {
3c525df1 858 if ( (pindex= komodo_chainactive(height-i)) != 0 )
353af8aa 859 {
a30dd993 860 blocktimes[i] = pindex->nTime;
da9fce3e 861 if ( komodo_blockload(block,pindex) == 0 )
5e0e5f85 862 {
da9fce3e 863 komodo_block2pubkey33(pubkeys[i],&block);
864 for (j=0; j<n; j++)
5e0e5f85 865 {
178618db 866 if ( memcmp(notarypubs33[j],pubkeys[i],33) == 0 )
da9fce3e 867 {
868 mids[i] = j;
869 (*nonzpkeysp)++;
870 break;
871 }
5e0e5f85 872 }
1481a43d 873 } else fprintf(stderr,"couldnt load block.%d\n",height);
353af8aa 874 if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
875 duplicate++;
3c525df1 876 }
353af8aa 877 }
f2805ceb 878 if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
353af8aa 879 return(1);
880 else return(0);
881}
882
df03549d 883int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
dbaf1154 884{
df03549d 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++)
056447a6 888 {
889 if ( height-i <= 0 )
df03549d 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 }
0d8dc237 904 if ( j == numnotaries )
905 minerids[nonz++] = j;
df03549d 906 } else fprintf(stderr,"couldnt load block.%d\n",height);
907 }
056447a6 908 }
df03549d 909 return(nonz);
dbaf1154 910}
911
dac3c30c 912int32_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)
4a4e912b 913{
442215b4 914 int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33];
dac3c30c 915 komodo_chosennotary(&notaryid,height,pubkey33,blocktimes[0]);
cb19d181 916 if ( height >= 82000 )
4a4e912b 917 {
442215b4 918 if ( notaryid >= 0 )
4a4e912b 919 {
82f82d3f 920 for (i=1; i<66; i++)
66e3c532 921 {
442215b4 922 if ( mids[i] == notaryid )
82f82d3f 923 {
3c89a023 924 if ( height > 792000 )
0f5e787b 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);
861119a1 929 return(-1);
0f5e787b 930 } else break;
82f82d3f 931 }
932 }
a658d926 933 if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 )
3ad8d247 934 {
26d9f4c3 935 if ( height > 807000 )
a658d926 936 return(-2);
fb64a588 937 }
938 return(1);
82f82d3f 939 } else return(0);
940 }
442215b4 941 else
4a4e912b 942 {
428a3934 943 if ( height >= 34000 && notaryid >= 0 )
4a4e912b 944 {
428a3934 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++)
66e3c532 951 {
70ebf02a 952 komodo_chosennotary(&nid,height-i,pubkey33,blocktimes[i]);
428a3934 953 if ( nid == notaryid )
954 {
79fb8179 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);
428a3934 958 if ( height > 225000 )
959 return(-1);
960 }
66e3c532 961 }
428a3934 962 //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
963 return(1);
4a4e912b 964 }
4a4e912b 965 }
966 return(0);
967}
968
51dab149 969int32_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)
0ab5b335 970{
aa5ca001 971 int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
51dab149 972 depth = komodo_MoMdata(&notarized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip);
0ab5b335 973 memset(MoMp,0,sizeof(*MoMp));
b3548b52 974 memset(kmdtxidp,0,sizeof(*kmdtxidp));
0ab5b335 975 *notarized_heightp = 0;
1b9f98cd 976 if ( depth != 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
0ab5b335 977 {
978 *MoMp = MoM;
979 *notarized_heightp = notarized_ht;
aa5ca001 980 *kmdtxidp = kmdtxid;
0ab5b335 981 }
982 return(depth);
983}
984
b62d7030 985int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
986{
c52074f2 987 int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
86131275 988 if ( (pindex= chainActive.LastTip()) == 0 )
d82623d2 989 return(-1);
4b729ec5 990 notarized_height = komodo_notarizeddata(pindex->GetHeight(),&notarized_hash,&notarized_desttxid);
b62d7030 991 *notarized_heightp = notarized_height;
4b729ec5 992 if ( notarized_height >= 0 && notarized_height <= pindex->GetHeight() && (notary= mapBlockIndex[notarized_hash]) != 0 )
b62d7030 993 {
4b729ec5 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
b62d7030 996 {
997 if ( nHeight < notarized_height )
998 {
2c5af2cd 999 //fprintf(stderr,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
b62d7030 1000 return(-1);
1001 }
1002 else if ( nHeight == notarized_height && memcmp(&hash,&notarized_hash,sizeof(hash)) != 0 )
1003 {
beb911ec 1004 fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
b62d7030 1005 return(-1);
1006 }
4b729ec5 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());
beb911ec 1008 }
dc836ee4 1009 //else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
4b729ec5 1010 // fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->GetHeight());
b62d7030 1011 return(0);
1012}
485e48ca 1013
83da1e16 1014uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
c1c95e36 1015{
1016 LOCK(cs_main);
1017 CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
63c93b0c 1018 *txheighttimep = *txheightp = *tiptimep = 0;
1019 *valuep = 0;
c1c95e36 1020 if ( !GetTransaction(hash,tx,hashBlock,true) )
1021 return(0);
1022 uint32_t locktime = 0;
1023 if ( n < tx.vout.size() )
1024 {
c60397dd 1025 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
c1c95e36 1026 {
1027 *valuep = tx.vout[n].nValue;
4b729ec5 1028 *txheightp = pindex->GetHeight();
83da1e16 1029 *txheighttimep = pindex->nTime;
86131275 1030 if ( *tiptimep == 0 && (tipindex= chainActive.LastTip()) != 0 )
c60397dd 1031 *tiptimep = (uint32_t)tipindex->nTime;
c1c95e36 1032 locktime = tx.nLockTime;
1f52f946 1033 //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
c1c95e36 1034 }
1035 }
1036 return(locktime);
1037}
1038
1039uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
c60397dd 1040
1041uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight)
c1c95e36 1042{
c60397dd 1043 uint64_t value; uint32_t tiptime=0,txheighttimep; CBlockIndex *pindex;
1044 if ( (pindex= chainActive[tipheight]) != 0 )
1045 tiptime = (uint32_t)pindex->nTime;
72070c94 1046 else fprintf(stderr,"cant find height[%d]\n",tipheight);
83da1e16 1047 if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 )
c1c95e36 1048 {
798f28c7 1049 if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
1050 return(komodo_interest(*txheightp,value,*locktimep,tiptime));
c1c95e36 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);
1c2f0c49 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 }
c1c95e36 1054 return(0);
1055}
8a7f7063 1056
1057int32_t komodo_isrealtime(int32_t *kmdheightp)
1058{
d82623d2 1059 struct komodo_state *sp; CBlockIndex *pindex;
8a7c9241 1060 if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
ffbc2f00 1061 *kmdheightp = sp->CURRENT_HEIGHT;
1062 else *kmdheightp = 0;
4b729ec5 1063 if ( (pindex= chainActive.LastTip()) != 0 && pindex->GetHeight() >= (int32_t)komodo_longestchain() )
8a7f7063 1064 return(1);
1065 else return(0);
1066}
14aa6cc0 1067
99d7ed25 1068int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
14aa6cc0 1069{
14aa6cc0 1070 if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
1071 {
3d02f57b 1072 if ( txheight > 246748 )
14aa6cc0 1073 {
1074 if ( txheight < 247205 )
39d28b06 1075 cmptime -= 16000;
bd070d8b 1076 if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
14aa6cc0 1077 {
531b9293 1078 if ( tx.nLockTime != 1477258935 && dispflag != 0 )
14aa6cc0 1079 {
bd070d8b 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);
14aa6cc0 1081 }
1082 return(-1);
1083 }
948ad8f3 1084 if ( 0 && dispflag != 0 )
bd070d8b 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);
14aa6cc0 1086 }
14aa6cc0 1087 }
1088 return(0);
1089}
ec5ed2f7 1090
18443f69 1091/*
9464ac21 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.
18443f69 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]
18443f69 1098 */
18443f69 1099
1100uint64_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 {
3acce042 1106 n = pblock->vtx[i].vout.size();
18443f69 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
acbc7a94 1121uint32_t komodo_segid32(char *coinaddr)
1122{
1123 bits256 addrhash;
3001f999 1124 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
acbc7a94 1125 return(addrhash.uints[0]);
1126}
1127
b70126d4 1128int8_t komodo_segid(int32_t nocache,int32_t height)
049e24ce 1129{
86f88c4f 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;
049e24ce 1131 if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
1132 {
b70126d4 1133 if ( nocache == 0 && pindex->segid >= -1 )
efb8981c 1134 return(pindex->segid);
049e24ce 1135 if ( komodo_blockload(block,pindex) == 0 )
1136 {
86f88c4f 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 )
049e24ce 1139 {
86f88c4f 1140 txid = block.vtx[txn_count-1].vin[0].prevout.hash;
1141 vout = block.vtx[txn_count-1].vin[0].prevout.n;
049e24ce 1142 txtime = komodo_txtime(&value,txid,vout,destaddr);
86f88c4f 1143 if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
049e24ce 1144 {
1145 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
86f88c4f 1146 if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
049e24ce 1147 {
1148 segid = komodo_segid32(voutaddr) & 0x3f;
e77d279f 1149 //fprintf(stderr,"komodo_segid.(%d) -> %02x\n",height,segid);
049e24ce 1150 }
1151 } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
1152 }
1153 }
1154 }
1155 return(segid);
1156}
1157
1158int32_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 {
b70126d4 1169 hashbuf[i] = (uint8_t)komodo_segid(1,height+i);
488dab78 1170 //fprintf(stderr,"%02x ",hashbuf[i]);
049e24ce 1171 }
1172 if ( n == 100 )
1173 {
1174 memcpy(prevhashbuf,hashbuf,100);
1175 prevheight = height;
488dab78 1176 //fprintf(stderr,"prevsegids.%d\n",height+n);
049e24ce 1177 }
1178 }
1179}
1180
ac531095 1181uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout)
1182{
1273624d 1183 bits256 addrhash;
ac531095 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
18443f69 1192uint32_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{
0ce374b7 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;
0a953df2 1195 txtime = komodo_txtime2(&value,txid,vout,address);
c3ed86ad 1196 if ( validateflag == 0 )
1197 {
0debf37f 1198 //fprintf(stderr,"blocktime.%u -> ",blocktime);
c3ed86ad 1199 if ( blocktime < prevtime+3 )
1200 blocktime = prevtime+3;
e0a3ab0a 1201 if ( blocktime < GetAdjustedTime()-60 )
8785f8ce 1202 blocktime = GetAdjustedTime()+30;
0debf37f 1203 //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime);
c3ed86ad 1204 }
7b6d6985 1205 if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
049e24ce 1206 {
01994dba 1207 //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
18443f69 1208 return(0);
049e24ce 1209 }
97a337f7 1210 if ( value < SATOSHIDEN )
1211 return(0);
a03465f6 1212 value /= SATOSHIDEN;
84f19b77 1213 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1214 ratio = (mindiff / bnTarget);
049e24ce 1215 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
18443f69 1216 minage = 6000;
0ce374b7 1217 komodo_segids(hashbuf,nHeight-101,100);
1218 segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
1219 segid = ((nHeight + segid32) & 0x3f);
8e1ca1ad 1220 for (iter=0; iter<600; iter++)
049e24ce 1221 {
0401884f 1222 if ( blocktime+iter+segid*2 < txtime+minage )
1223 continue;
049e24ce 1224 diff = (iter + blocktime - txtime - minage);
f6567e80 1225 if ( diff < 0 )
1226 diff = 60;
1227 else if ( diff > 3600*24*30 )
18443f69 1228 {
01994dba 1229 //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
049e24ce 1230 diff = 3600*24*30;
5e90f445 1231 }
049e24ce 1232 if ( iter > 0 )
1233 diff += segid*2;
bfa19436 1234 coinage = (value * diff);
0ce374b7 1235 if ( blocktime+iter+segid*2 > prevtime+480 )
1236 coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
8a7c025a 1237 coinage256 = arith_uint256(coinage+1);
1238 hashval = ratio * (UintToArith256(hash) / coinage256);
049e24ce 1239 if ( hashval <= bnTarget )
1240 {
1241 winner = 1;
1242 if ( validateflag == 0 )
18443f69 1243 {
0debf37f 1244 //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid);
049e24ce 1245 blocktime += iter;
1246 blocktime += segid * 2;
18443f69 1247 }
049e24ce 1248 break;
18443f69 1249 }
049e24ce 1250 if ( validateflag != 0 )
18443f69 1251 {
26b9af80 1252 /*for (i=31; i>=24; i--)
18443f69 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]);
26b9af80 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);*/
049e24ce 1258 break;
18443f69 1259 }
1260 }
049e24ce 1261 //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
5162b553 1262 if ( 0 && validateflag != 0 )
049e24ce 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]);
4dc0ad38 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);
049e24ce 1270 }
1271 if ( nHeight < 10 )
18443f69 1272 return(blocktime);
1273 return(blocktime * winner);
1274}
1275
1276arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
1277{
23c192b9 1278 int32_t oldflag = 0;
4cc33bf8 1279 CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
18443f69 1280 *percPoSp = percPoS = 0;
8daf7caf 1281 if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
96df006a 1282 return(target);
18443f69 1283 sum = arith_uint256(0);
1284 ave = sum;
97a337f7 1285 easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
4cc33bf8 1286 for (i=n=m=0; i<100; i++)
18443f69 1287 {
1288 ht = height - 100 + i;
e83bf6b3 1289 if ( ht <= 1 )
1290 continue;
18443f69 1291 if ( (pindex= komodo_chainactive(ht)) != 0 )
4cc33bf8 1292 {
c6d212db 1293 if ( komodo_segid(0,ht) >= 0 )
4cc33bf8 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");
9e1a6d76 1304 sum += UintToArith256(pindex->GetBlockHash());
4cc33bf8 1305 m++;
4cc33bf8 1306 }
1307 }
4cc33bf8 1308 if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
1309 fprintf(stderr," %d, ",percPoS);
18443f69 1310 }
0fa08b81 1311 if ( m+n < 100 )
3753f568 1312 percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
f2c1ac06 1313 if ( ASSETCHAINS_STAKED < 100 )
1314 fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
18443f69 1315 *percPoSp = percPoS;
4cc33bf8 1316 if ( m > 0 )
18443f69 1317 {
4cc33bf8 1318 ave = (sum / arith_uint256(m));
18443f69 1319 if ( ave > target )
1320 ave = target;
db871af5 1321 } else ave = target; //easydiff; //else return(target);
dfb0fdfa 1322 if ( percPoS == 0 )
1323 percPoS = 1;
18443f69 1324 if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
1325 {
db871af5 1326 //if ( oldflag != 0 )
1327 // bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
23c192b9 1328 if ( oldflag != 0 )
db871af5 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);
f2c1ac06 1331 if ( ASSETCHAINS_STAKED < 100 )
18443f69 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 {
23c192b9 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);
db871af5 1351 }
1352 else bnTarget = (ave / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
b6c80e46 1353 if ( bnTarget > easydiff )
ce2b6b33 1354 bnTarget = easydiff;
b6c80e46 1355 else if ( bnTarget < ave ) // overflow
8ba2ae9e 1356 {
b6c80e46 1357 bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
8ba2ae9e 1358 if ( bnTarget < ave )
1359 bnTarget = ave;
1360 }
23b680a0 1361 if ( 1 )
18443f69 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
84b0bd52 1378int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget,arith_uint256 bhash)
18443f69 1379{
e77d279f 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;
9aa24310 1381 if ( ASSETCHAINS_STAKED == 100 && height <= 10 )
6ac49724 1382 return(1);
435ef4fd 1383 pindex = mapBlockIndex[pblock->GetHash()];
15bec819 1384 if ( pindex != 0 && pindex->segid >= -1 )
efb8981c 1385 {
1386 if ( pindex->segid == -1 )
1387 return(0);
1388 else return(1);
15bec819 1389 }
18443f69 1390 txn_count = pblock->vtx.size();
feefa2d3 1391 if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 )
18443f69 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 {
d1db0920 1402 if ( komodo_isPoS(pblock) != 0 )
efb8981c 1403 {
e0a3ab0a 1404 eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"");
efb8981c 1405 }
18443f69 1406 if ( eligible == 0 || eligible > pblock->nTime )
1407 {
703faba6 1408 if ( 0 && ASSETCHAINS_STAKED < 100 )
308ee076 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));
efb8981c 1410 if ( slowflag != 0 && pindex != 0 )
549ca5a6 1411 {
efb8981c 1412 pindex->segid = -1;
703faba6 1413 fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
549ca5a6 1414 }
efb8981c 1415 }
1416 else
1417 {
1418 isPoS = 2; // 2 means staking utxo validated
eea0a57b 1419 if ( slowflag != 0 && height > 100 )
efb8981c 1420 {
066c16e5 1421 segid = -3;
eea0a57b 1422 if ( pindex != 0 && pindex->segid == -2 && (segid= komodo_segid(1,height)) >= 0 )
efb8981c 1423 {
eea0a57b 1424 pindex->segid = segid;
1425 fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid);
9e432c97 1426 } //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid);
efb8981c 1427 }
1428 }
18443f69 1429 }
11b390d8 1430 if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx
18443f69 1431 {
d1db0920 1432 if ( komodo_isPoS(pblock) != 0 )
1cdb961b 1433 isPoS = 1;
84b0bd52 1434 }
703faba6 1435 if ( slowflag != 0 && isPoS != 0 )
84b0bd52 1436 {
efb8981c 1437 if ( isPoS != 2 )
18443f69 1438 {
efb8981c 1439 fprintf(stderr,"ht.%d isPoS.%d utxo not validated -> must be PoW fake\n",height,isPoS);
84b0bd52 1440 isPoS = 0;
1441 }
efb8981c 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 }
84b0bd52 1451 }
1452 //else return(-1);
18443f69 1453 }
ffd6dd51 1454 //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
11b390d8 1455 return(isPoS != 0);
18443f69 1456}
1457
185b2d4f 1458bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
f3b0d2ab 1459bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating);
1460
c5325a32 1461// for now, we will ignore slowFlag in the interest of keeping success/fail simpler for security purposes
1f722359
MT
1462bool 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;
9feb4b9e 1468 CAmount value;
1f722359 1469 bool isPOS = false;
cd230e37 1470 CTxDestination voutaddress, destaddress, cbaddress;
1f722359
MT
1471 arith_uint256 target, hash;
1472 CTransaction tx;
1473
f6608b5a 1474 if (!pblock->IsVerusPOSBlock())
17d0160a
MT
1475 {
1476 printf("%s, height %d not POS block\n", pblock->nNonce.GetHex().c_str(), height);
9feb4b9e 1477 //pblock->nNonce.SetPOSTarget(pblock->nNonce.GetPOSTarget());
1478 //printf("%s after setting POS target\n", pblock->nNonce.GetHex().c_str());
1fae37f6 1479 return false;
17d0160a 1480 }
1fae37f6 1481
cd230e37 1482 char voutaddr[64], destaddr[64], cbaddr[64];
1f722359 1483
1f722359
MT
1484 txn_count = pblock->vtx.size();
1485
1486 if ( txn_count > 1 )
1487 {
c5325a32 1488 target.SetCompact(pblock->GetVerusPOSTarget());
1f722359
MT
1489 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1490 voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
9feb4b9e 1491 value = pblock->vtx[txn_count-1].vout[0].nValue;
1f722359 1492
9feb4b9e 1493 {
f3b0d2ab 1494 bool validHash = true;
9feb4b9e 1495 bool enablePOSNonce = CPOSNonce::NewPOSActive(height);
c68ca1a2 1496 bool newPOSEnforcement = enablePOSNonce && (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= height);
9feb4b9e 1497 uint256 rawHash;
1498 arith_uint256 posHash;
c68ca1a2 1499 if (newPOSEnforcement)
9feb4b9e 1500 {
1501 validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1502 posHash = UintToArith256(rawHash) / value;
f3b0d2ab 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 }
185b2d4f 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 }
f3b0d2ab 1529 }
9feb4b9e 1530 }
f3b0d2ab 1531 if (validHash)
9feb4b9e 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
1f722359 1542#ifndef KOMODO_ZCASH
9feb4b9e 1543 if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
1f722359 1544#else
9feb4b9e 1545 if (!GetTransaction(txid, tx, blkHash, true))
1f722359 1546#endif
1f722359 1547 {
9feb4b9e 1548 fprintf(stderr,"ERROR: invalid PoS block %s - no source transaction\n",blkHash.ToString().c_str());
1f722359 1549 }
9feb4b9e 1550 else
1f722359 1551 {
9feb4b9e 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());
c5325a32 1564
9feb4b9e 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
c68ca1a2 1570 if ((!newPOSEnforcement || posHash == hash) && hash <= target)
9feb4b9e 1571 {
1572 if ((mapBlockIndex.count(blkHash) == 0) ||
1573 !(pastBlockIndex = mapBlockIndex[blkHash]) ||
4b729ec5 1574 (height - pastBlockIndex->GetHeight()) < VERUS_MIN_STAKEAGE)
c5325a32 1575 {
9feb4b9e 1576 fprintf(stderr,"ERROR: invalid PoS block %s - stake transaction too new\n",blkHash.ToString().c_str());
c5325a32
MT
1577 }
1578 else
1f722359 1579 {
9feb4b9e 1580 // make sure we have the right target
1581 CBlockIndex *previndex;
1582 if (!(previndex = mapBlockIndex[pblock->hashPrevBlock]))
c5325a32 1583 {
9feb4b9e 1584 fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
1f722359
MT
1585 }
1586 else
1587 {
9feb4b9e 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 }
1f722359
MT
1626 }
1627 }
1628 }
c68ca1a2 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 }
1f722359 1634 }
1f722359
MT
1635 }
1636 }
1637 }
1638 return(isPOS);
1639}
1640
fb6bb4e8 1641int64_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 {
9feb4b9e 1651 script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
fb6bb4e8 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
3fdb3782
SS
1664bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1665
18443f69 1666int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1667{
9464ac21 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;
efb8981c 1669 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
1670 KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
18443f69 1671 if ( !CheckEquihashSolution(pblock, Params()) )
1672 {
1673 fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1674 return(-1);
1675 }
ec5b59fd 1676 hash = pblock->GetHash();
9464ac21 1677 bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1678 bhash = UintToArith256(hash);
1679 possible = komodo_block2pubkey33(pubkey33,pblock);
28b18b61 1680 if ( height == 0 )
f1b57a6e 1681 {
28b18b61 1682 if ( slowflag != 0 )
b088fa97 1683 {
1684 fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
28b18b61 1685 return(0);
b088fa97 1686 }
28b18b61 1687 if ( (pprev= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
4b729ec5 1688 height = pprev->GetHeight() + 1;
28b18b61 1689 if ( height == 0 )
1690 return(0);
f1b57a6e 1691 }
1f722359
MT
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 }
2c089649 1700 if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget )
18443f69 1701 {
1702 failed = 1;
9464ac21 1703 if ( height > 0 && ASSETCHAINS_SYMBOL[0] == 0 ) // for the fast case
18443f69 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 }
9464ac21 1715 else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 )
1716 {
f02af889 1717 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW )
1718 return(0);
a3b5f801 1719 if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget for staked chains
2ba9de01 1720 return(-1);
9464ac21 1721 }
18443f69 1722 }
a3d08df0 1723 if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
18443f69 1724 {
84b0bd52 1725 if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget,bhash)) == 0 )
18443f69 1726 {
9aa24310 1727 if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! POSTEST64
18443f69 1728 return(-1);
1729 else
1730 {
1cdb961b 1731 if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target
1732 return(0);
18443f69 1733 if ( slowflag != 0 )
1734 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
18443f69 1735 if ( bhash > bnTarget )
1736 {
1737 for (i=31; i>=16; i--)
2808b68f 1738 fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]);
18443f69 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);
b088fa97 1744 } else failed = 0;
18443f69 1745 }
b088fa97 1746 }
1747 else if ( is_PoSblock < 0 )
1748 {
1749 fprintf(stderr,"unexpected negative is_PoSblock.%d\n",is_PoSblock);
18443f69 1750 return(-1);
b088fa97 1751 }
18443f69 1752 }
d9f176ac 1753 if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
18443f69 1754 {
d9f176ac 1755 if ( height == 1 )
18443f69 1756 {
9feb4b9e 1757 script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
18443f69 1758 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1759 return(-1);
d9f176ac 1760 }
c9855c14 1761 else
1762 {
1763 if ( komodo_checkcommission(pblock,height) < 0 )
18443f69 1764 return(-1);
18443f69 1765 }
1766 }
c685d692 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 )
18443f69 1769 return(-1);
1770 else return(0);
1771}
1772
26189509 1773int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
7e282415 1774{
84eabd0d 1775 CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
7e282415 1776 n = pblock->vtx.size();
1777 for (i=0; i<n; i++)
1778 {
9f60c7ec 1779 CTransaction vintx,&tx = pblock->vtx[i];
9feb4b9e 1780 zfunds += (tx.GetValueOut() - tx.GetShieldedValueIn());
7e282415 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++)
84eabd0d 1800 {
1801 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1802 voutsum += tx.vout[j].nValue;
27d76b74 1803 else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
84eabd0d 1804 }
9feb4b9e 1805 script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
7e282415 1806 if ( script == 0 || script[0] != 0x6a )
84eabd0d 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 }
7e282415 1811 }
1812 }
26189509 1813 *zfundsp = zfunds;
7130a7cd 1814 if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times
1ec2a42f 1815 return(3 * SATOSHIDEN);
aa51eef6 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));
7e282415 1818 return(voutsum - vinsum);
1819}
1820
26189509 1821int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
7e282415 1822{
26189509 1823 CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
67459d80 1824 //fprintf(stderr,"coinsupply %d\n",height);
26189509 1825 *zfundsp = 0;
7e282415 1826 if ( (pindex= komodo_chainactive(height)) != 0 )
1827 {
4b729ec5 1828 while ( pindex != 0 && pindex->GetHeight() > 0 )
9f60c7ec 1829 {
7130a7cd 1830 if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
97a4e923 1831 {
1832 if ( komodo_blockload(block,pindex) == 0 )
4b729ec5 1833 pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->GetHeight(),&block);
df74ee5f 1834 else
1835 {
4b729ec5 1836 fprintf(stderr,"error loading block.%d\n",pindex->GetHeight());
df74ee5f 1837 return(0);
1838 }
97a4e923 1839 }
1840 supply += pindex->newcoins;
26189509 1841 zfunds += pindex->zfunds;
4b729ec5 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));
97a4e923 1843 pindex = pindex->pprev;
9f60c7ec 1844 }
7e282415 1845 }
26189509 1846 *zfundsp = zfunds;
7e282415 1847 return(supply);
1848}
This page took 0.683742 seconds and 4 git commands to generate.