]> Git Repo - VerusCoin.git/blame - src/komodo_bitcoind.h
Merge branch 'dev' of https://github.com/miketout/komodo into dev
[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"
23
c615ffff 24int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
25int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
1f722359 26unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
c615ffff 27
36c733e9 28//#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
77be6cd9 29
9b0e1808 30struct MemoryStruct { char *memory; size_t size; };
c2b50ce0 31struct return_string { char *ptr; size_t len; };
32
33// return data from the server
34#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
35#define CURL_GLOBAL_SSL (1<<0)
36#define CURL_GLOBAL_WIN32 (1<<1)
37
38
4ec67e74 39/************************************************************************
40 *
41 * Initialize the string handler so that it is thread safe
42 *
43 ************************************************************************/
44
45void init_string(struct return_string *s)
46{
47 s->len = 0;
48 s->ptr = (char *)calloc(1,s->len+1);
49 if ( s->ptr == NULL )
50 {
51 fprintf(stderr,"init_string malloc() failed\n");
52 exit(-1);
53 }
54 s->ptr[0] = '\0';
55}
c2b50ce0 56
4ec67e74 57/************************************************************************
58 *
59 * Use the "writer" to accumulate text until done
60 *
61 ************************************************************************/
62
63size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s)
64{
65 size_t new_len = s->len + size*nmemb;
66 s->ptr = (char *)realloc(s->ptr,new_len+1);
67 if ( s->ptr == NULL )
68 {
69 fprintf(stderr, "accumulate realloc() failed\n");
70 exit(-1);
71 }
72 memcpy(s->ptr+s->len,ptr,size*nmemb);
73 s->ptr[new_len] = '\0';
74 s->len = new_len;
75 return(size * nmemb);
76}
c2b50ce0 77
78/************************************************************************
79 *
80 * return the current system time in milliseconds
81 *
82 ************************************************************************/
83
84#define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field
85#ifdef EXTRACT_BITCOIND_RESULT
86
87/************************************************************************
88 *
89 * perform post processing of the results
90 *
91 ************************************************************************/
92
93char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params)
94{
95 long i,j,len; char *retstr = 0; cJSON *json,*result,*error;
96 //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
97 if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 )
98 {
99 if ( strcmp(command,"signrawtransaction") != 0 )
100 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
101 return(rpcstr);
102 }
103 json = cJSON_Parse(rpcstr);
104 if ( json == 0 )
105 {
106 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params);
107 free(rpcstr);
108 return(0);
109 }
110 result = cJSON_GetObjectItem(json,"result");
111 error = cJSON_GetObjectItem(json,"error");
112 if ( error != 0 && result != 0 )
113 {
114 if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL )
115 {
116 retstr = cJSON_Print(result);
117 len = strlen(retstr);
118 if ( retstr[0] == '"' && retstr[len-1] == '"' )
119 {
120 for (i=1,j=0; i<len-1; i++,j++)
121 retstr[j] = retstr[i];
122 retstr[j] = 0;
123 }
124 }
125 else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL )
126 {
127 if ( strcmp(command,"signrawtransaction") != 0 )
128 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr);
129 }
130 free(rpcstr);
131 } else retstr = rpcstr;
132 free_json(json);
133 //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr);
134 return(retstr);
135}
136#endif
137
138/************************************************************************
139 *
140 * perform the query
141 *
142 ************************************************************************/
143
c2b50ce0 144char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params)
145{
146 static int didinit,count,count2; static double elapsedsum,elapsedsum2;
147 struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle;
148 char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime;
149 if ( didinit == 0 )
150 {
151 didinit = 1;
152 curl_global_init(CURL_GLOBAL_ALL); //init the curl session
153 }
154 numretries = 0;
155 if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 )
156 specialcase = 1;
157 else specialcase = 0;
158 if ( url[0] == 0 )
159 strcpy(url,"http://127.0.0.1:7876/nxt");
160 if ( specialcase != 0 && 0 )
161 printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params);
162try_again:
163 if ( retstrp != 0 )
164 *retstrp = 0;
165 starttime = OS_milliseconds();
166 curl_handle = curl_easy_init();
167 init_string(&s);
168 headers = curl_slist_append(0,"Expect:");
f796b1fb 169
170 curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
c2b50ce0 171 curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers);
172 curl_easy_setopt(curl_handle,CURLOPT_URL, url);
4ec67e74 173 curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function
c2b50ce0 174 curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback
175 curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash
f796b1fb 176 curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback
c2b50ce0 177 if ( strncmp(url,"https",5) == 0 )
178 {
179 curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0);
180 curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0);
181 }
182 if ( userpass != 0 )
183 curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass);
184 databuf = 0;
185 if ( params != 0 )
186 {
187 if ( command != 0 && specialcase == 0 )
188 {
189 len = strlen(params);
190 if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) {
191 bracket0 = bracket1 = (char *)"";
192 }
193 else
194 {
195 bracket0 = (char *)"[";
196 bracket1 = (char *)"]";
197 }
f796b1fb 198
c2b50ce0 199 databuf = (char *)malloc(256 + strlen(command) + strlen(params));
200 sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1);
05e307ec 201 //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf);
c2b50ce0 202 //
203 } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params);
204 curl_easy_setopt(curl_handle,CURLOPT_POST,1L);
205 if ( databuf != 0 )
206 curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf);
207 else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params);
208 }
209 //laststart = milliseconds();
210 res = curl_easy_perform(curl_handle);
211 curl_slist_free_all(headers);
212 curl_easy_cleanup(curl_handle);
213 if ( databuf != 0 ) // clean up temporary buffer
214 {
215 free(databuf);
216 databuf = 0;
217 }
218 if ( res != CURLE_OK )
219 {
220 numretries++;
221 if ( specialcase != 0 )
222 {
223 printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res);
224 free(s.ptr);
225 return(0);
226 }
c59a3beb 227 else if ( numretries >= 1 )
c2b50ce0 228 {
bb7f7473 229 //printf("Maximum number of retries exceeded!\n");
c2b50ce0 230 free(s.ptr);
231 return(0);
232 }
32323ea1 233 if ( (rand() % 1000) == 0 )
234 printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries);
c2b50ce0 235 free(s.ptr);
236 sleep((1<<numretries));
237 goto try_again;
f796b1fb 238
c2b50ce0 239 }
240 else
241 {
242 if ( command != 0 && specialcase == 0 )
243 {
244 count++;
245 elapsedsum += (OS_milliseconds() - starttime);
32323ea1 246 if ( (count % 1000000) == 0)
c2b50ce0 247 printf("%d: ave %9.6f | elapsed %.3f millis | bitcoind_RPC.(%s) url.(%s)\n",count,elapsedsum/count,(OS_milliseconds() - starttime),command,url);
248 if ( retstrp != 0 )
249 {
250 *retstrp = s.ptr;
251 return(s.ptr);
252 }
253 return(post_process_bitcoind_RPC(debugstr,command,s.ptr,params));
254 }
255 else
256 {
257 if ( 0 && specialcase != 0 )
258 fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: BTCD.(%s) -> (%s)\n",params,s.ptr);
259 count2++;
260 elapsedsum2 += (OS_milliseconds() - starttime);
261 if ( (count2 % 10000) == 0)
262 printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command);
263 return(s.ptr);
264 }
265 }
266 printf("bitcoind_RPC: impossible case\n");
267 free(s.ptr);
268 return(0);
269}
9b0e1808 270
271static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data)
272{
273 size_t realsize = (size * nmemb);
274 struct MemoryStruct *mem = (struct MemoryStruct *)data;
b858fa74 275 mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1));
9b0e1808 276 if ( mem->memory != 0 )
277 {
278 if ( ptr != 0 )
279 memcpy(&(mem->memory[mem->size]),ptr,realsize);
280 mem->size += realsize;
281 mem->memory[mem->size] = 0;
282 }
283 //printf("got %d bytes\n",(int32_t)(size*nmemb));
284 return(realsize);
285}
286
05d3d5ff 287char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3)
9b0e1808 288{
289 struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
290 if ( (cHandle= *cHandlep) == NULL )
f796b1fb 291 *cHandlep = cHandle = curl_easy_init();
9b0e1808 292 else curl_easy_reset(cHandle);
293 //#ifdef DEBUG
f796b1fb 294 //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
9b0e1808 295 //#endif
f796b1fb 296 curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
297 curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0);
298 //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
299 curl_easy_setopt(cHandle,CURLOPT_URL,url);
300 curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
9b0e1808 301 if ( userpass != 0 && userpass[0] != 0 )
302 curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
f796b1fb 303 if ( postfields != 0 && postfields[0] != 0 )
9b0e1808 304 {
305 curl_easy_setopt(cHandle,CURLOPT_POST,1);
f796b1fb 306 curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
9b0e1808 307 }
308 if ( hdr0 != NULL && hdr0[0] != 0 )
309 {
310 //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:"");
311 headers = curl_slist_append(headers,hdr0);
312 if ( hdr1 != 0 && hdr1[0] != 0 )
313 headers = curl_slist_append(headers,hdr1);
314 if ( hdr2 != 0 && hdr2[0] != 0 )
315 headers = curl_slist_append(headers,hdr2);
316 if ( hdr3 != 0 && hdr3[0] != 0 )
317 headers = curl_slist_append(headers,hdr3);
318 } //headers = curl_slist_append(0,"Expect:");
319 if ( headers != 0 )
320 curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers);
321 //res = curl_easy_perform(cHandle);
322 memset(&chunk,0,sizeof(chunk));
323 curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback);
324 curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk);
325 curl_easy_perform(cHandle);
326 curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code);
327 if ( headers != 0 )
328 curl_slist_free_all(headers);
329 if ( code != 200 )
330 printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory);
331 return(chunk.memory);
332}
333
0ded57c8 334char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
9b0e1808 335{
4ac6cd92 336 //static void *cHandle;
a9132082 337 char url[512],*retstr=0,*retstr2=0,postdata[8192];
365378b5 338 if ( params == 0 || params[0] == 0 )
339 params = (char *)"[]";
9b0e1808 340 if ( strlen(params) < sizeof(postdata)-128 )
341 {
3c0f5d94 342 sprintf(url,(char *)"http://127.0.0.1:%u",port);
9b0e1808 343 sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params);
05e307ec 344 //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS);
0ded57c8 345 retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params);
c2b50ce0 346 //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0);
9b0e1808 347 }
1ccb1cf0 348 return(retstr2);
9b0e1808 349}
350
0cb025c1 351int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp)
b000fa04 352{
0cb025c1 353 char *jsonstr,params[256],*userpass; uint16_t port; cJSON *json,*item; int32_t height = 0,txid_height = 0,txid_confirmations = 0;
b000fa04 354 params[0] = 0;
355 *kmdnotarized_heightp = 0;
0cb025c1 356 if ( strcmp(dest,"KMD") == 0 )
b000fa04 357 {
05e307ec 358 port = KMD_PORT;
0cb025c1 359 userpass = KMDUSERPASS;
360 }
361 else if ( strcmp(dest,"BTC") == 0 )
362 {
363 port = 8332;
364 userpass = BTCUSERPASS;
365 }
366 else return(0);
367 if ( userpass[0] != 0 )
368 {
369 if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getinfo",params,port)) != 0 )
b000fa04 370 {
70d83934 371 //printf("(%s)\n",jsonstr);
b000fa04 372 if ( (json= cJSON_Parse(jsonstr)) != 0 )
373 {
978ca795 374 if ( (item= jobj(json,(char *)"result")) != 0 )
033f496d 375 {
033f496d 376 height = jint(item,(char *)"blocks");
57dd4ada 377 *kmdnotarized_heightp = strcmp(dest,"KMD") == 0 ? jint(item,(char *)"notarized") : height;
033f496d 378 }
b000fa04 379 free_json(json);
380 }
381 free(jsonstr);
382 }
383 sprintf(params,"[\"%s\", 1]",txidstr);
0cb025c1 384 if ( (jsonstr= komodo_issuemethod(userpass,(char *)"getrawtransaction",params,port)) != 0 )
b000fa04 385 {
70d83934 386 //printf("(%s)\n",jsonstr);
b000fa04 387 if ( (json= cJSON_Parse(jsonstr)) != 0 )
388 {
978ca795 389 if ( (item= jobj(json,(char *)"result")) != 0 )
033f496d 390 {
391 txid_confirmations = jint(item,(char *)"confirmations");
033f496d 392 if ( txid_confirmations > 0 && height > txid_confirmations )
393 txid_height = height - txid_confirmations;
19857195 394 else txid_height = height;
094b401e 395 //printf("height.%d tconfs.%d txid_height.%d\n",height,txid_confirmations,txid_height);
033f496d 396 }
b000fa04 397 free_json(json);
398 }
399 free(jsonstr);
400 }
43cc3df6 401 }
b000fa04 402 return(txid_height);
403}
404
20a5cb84 405int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH)
b55c2367 406{
407 int32_t i; uint256 hash; char params[256];
408 for (i=0; i<32; i++)
ebd18944 409 ((uint8_t *)&hash)[i] = script[2+i];
d56e5945 410 if ( hash == NOTARIZED_HASH )
3e9fcad0 411 return(1);
b556919a 412 for (i=0; i<32; i++)
413 printf("%02x",((uint8_t *)&NOTARIZED_HASH)[i]);
414 printf(" notarized, ");
415 for (i=0; i<32; i++)
416 printf("%02x",((uint8_t *)&hash)[i]);
895977bf 417 printf(" opreturn from [%s] ht.%d MISMATCHED\n",ASSETCHAINS_SYMBOL,height);
b556919a 418 return(-1);
b55c2367 419}
420
421int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
422{
3da303b5 423 char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
424 script = _script;
c3153900 425 /*params[0] = '[';
f796b1fb 426 params[1] = '"';
427 for (i=0; i<32; i++)
428 sprintf(&params[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
429 strcat(params,"\", 1]");*/
c3153900 430 sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
ed937645 431 if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
432 return(0);
05c1e522 433 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
a0b9382c 434 printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",ASSETCHAINS_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT);
b55c2367 435 if ( strcmp(dest,"KMD") == 0 )
b148643e 436 {
437 if ( KMDUSERPASS[0] != 0 )
5201bb51 438 {
439 if ( ASSETCHAINS_SYMBOL[0] != 0 )
a0b9382c 440 {
05e307ec 441 jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,KMD_PORT);
f796b1fb 442 //printf("userpass.(%s) got (%s)\n",KMDUSERPASS,jsonstr);
a0b9382c 443 }
444 }//else jsonstr = _dex_getrawtransaction();
48d0e5df 445 else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
b148643e 446 }
b55c2367 447 else if ( strcmp(dest,"BTC") == 0 )
b148643e 448 {
449 if ( BTCUSERPASS[0] != 0 )
48d0e5df 450 {
eee28662 451 //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS);
b148643e 452 jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332);
48d0e5df 453 }
b148643e 454 //else jsonstr = _dex_getrawtransaction();
48d0e5df 455 else return(0);
b148643e 456 }
9674c671 457 else
458 {
459 printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest);
460 return(-1);
461 }
b55c2367 462 if ( jsonstr != 0 )
463 {
13b64fd6 464 if ( (json= cJSON_Parse(jsonstr)) != 0 )
b55c2367 465 {
fa73aa67 466 if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 )
b55c2367 467 {
468 vout = jitem(vouts,n-1);
34c68daa 469 if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
a0b9382c 470 printf("vout.(%s)\n",jprint(vout,0));
523a5dc7 471 if ( (skey= jobj(vout,(char *)"scriptPubKey")) != 0 )
b55c2367 472 {
523a5dc7 473 if ( (hexstr= jstr(skey,(char *)"hex")) != 0 )
b55c2367 474 {
895977bf 475 //printf("HEX.(%s) vs hash.%s\n",hexstr,NOTARIZED_HASH.ToString().c_str());
b55c2367 476 len = strlen(hexstr) >> 1;
477 decode_hex(script,len,hexstr);
279fac91 478 if ( script[1] == 0x4c )
479 {
480 script++;
481 len--;
482 }
483 else if ( script[1] == 0x4d )
484 {
485 script += 2;
486 len -= 2;
487 }
20a5cb84 488 retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH);
b55c2367 489 }
490 }
491 }
492 free_json(txjson);
493 }
494 free(jsonstr);
495 }
496 return(retval);
497}
498
2934460c 499/*uint256 komodo_getblockhash(int32_t height)
f796b1fb 500 {
501 uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
502 memset(&hash,0,sizeof(hash));
503 sprintf(params,"[%d]",height);
05c2ba63 504 if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,BITCOIND_RPCPORT)) != 0 )
f796b1fb 505 {
506 if ( (result= cJSON_Parse(jsonstr)) != 0 )
507 {
508 if ( (hexstr= jstr(result,(char *)"result")) != 0 )
509 {
510 if ( is_hexstr(hexstr,0) == 64 )
511 {
512 decode_hex(revbuf,32,hexstr);
513 for (i=0; i<32; i++)
514 ((uint8_t *)&hash)[i] = revbuf[31-i];
515 }
516 }
517 free_json(result);
518 }
519 printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
520 free(jsonstr);
521 }
522 return(hash);
523 }
524
525 uint256 _komodo_getblockhash(int32_t height);*/
6b0e06b5 526
23256cca 527uint64_t komodo_seed(int32_t height)
528{
39b462c7 529 uint64_t seed = 0;
2934460c 530 /*if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
f796b1fb 531 {
532 uint256 hash,zero; CBlockIndex *pindex;
533 memset(&hash,0,sizeof(hash));
534 memset(&zero,0,sizeof(zero));
535 if ( height > 10 )
536 height -= 10;
537 if ( ASSETCHAINS_SYMBOL[0] == 0 )
538 hash = _komodo_getblockhash(height);
539 if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
540 hash = komodo_getblockhash(height);
541 int32_t i;
542 for (i=0; i<32; i++)
543 printf("%02x",((uint8_t *)&hash)[i]);
544 printf(" seed.%d\n",height);
545 seed = arith_uint256(hash.GetHex()).GetLow64();
546 }
547 else*/
8aef9e40 548 {
93fb251c 549 seed = (height << 13) ^ (height << 2);
550 seed <<= 21;
8aef9e40 551 seed |= (height & 0xffffffff);
93fb251c 552 seed ^= (seed << 17) ^ (seed << 1);
8aef9e40 553 }
23256cca 554 return(seed);
555}
556
1f722359 557uint32_t komodo_txtime(uint64_t *valuep,uint256 hash, int32_t n, char *destaddr)
3eea72f2 558{
8d584a9c 559 CTxDestination address; CTransaction tx; uint256 hashBlock;
ce5dd547 560 *valuep = 0;
7637aa7f 561 if (!GetTransaction(hash, tx,
562#ifndef KOMODO_ZCASH
563 Params().GetConsensus(),
564#endif
565 hashBlock, true))
3eea72f2 566 {
4ff37947 567 //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
2ef19f04 568 return(0);
3eea72f2 569 }
1619474e 570 //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
2ef19f04 571 if ( n < tx.vout.size() )
8d584a9c 572 {
2ef19f04 573 *valuep = tx.vout[n].nValue;
fa4d9e24 574 if (ExtractDestination(tx.vout[n].scriptPubKey, address))
575 strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
8d584a9c 576 }
2ef19f04 577 return(tx.nLockTime);
3eea72f2 578}
579
0a953df2 580uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
581{
582 CTxDestination address; CBlockIndex *pindex; CTransaction tx; uint256 hashBlock; uint32_t txtime = 0;
583 *valuep = 0;
584 if (!GetTransaction(hash, tx,
585#ifndef KOMODO_ZCASH
586 Params().GetConsensus(),
587#endif
588 hashBlock, true))
589 {
590 //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
591 return(0);
592 }
ec894008 593 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
0a953df2 594 txtime = pindex->nTime;
595 else txtime = tx.nLockTime;
596 //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
597 if ( n < tx.vout.size() )
598 {
599 *valuep = tx.vout[n].nValue;
600 if (ExtractDestination(tx.vout[n].scriptPubKey, address))
601 strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
602 }
603 return(txtime);
604}
605
d1db0920 606int32_t komodo_isPoS(CBlock *pblock)
607{
608 int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
609 if ( ASSETCHAINS_STAKED != 0 )
610 {
611 if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 )
612 {
613 txid = pblock->vtx[n-1].vin[0].prevout.hash;
614 vout = pblock->vtx[n-1].vin[0].prevout.n;
615 txtime = komodo_txtime(&value,txid,vout,destaddr);
616 if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
617 {
618 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
619 if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[n-1].vout[0].nValue == value )
620 {
88084272 621 //fprintf(stderr,"is PoS block!\n");
d1db0920 622 return(1);
623 }
624 }
625 }
626 }
627 return(0);
628}
629
3eea72f2 630void komodo_disconnect(CBlockIndex *pindex,CBlock& block)
631{
7c130297 632 char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
4b729ec5 633 //fprintf(stderr,"disconnect ht.%d\n",pindex->GetHeight());
634 komodo_init(pindex->GetHeight());
f3a1de3a 635 if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
7a183152 636 {
4b729ec5 637 //sp->rewinding = pindex->GetHeight();
638 //fprintf(stderr,"-%d ",pindex->GetHeight());
639 } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->GetHeight(),ASSETCHAINS_SYMBOL);
3eea72f2 640}
641
f24b36ca 642int32_t komodo_is_notarytx(const CTransaction& tx)
643{
faf51f1a 644 uint8_t *ptr; static uint8_t crypto777[33];
0554de3c 645 if ( tx.vout.size() > 0 )
646 {
0554de3c 647 ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0];
0554de3c 648 if ( ptr != 0 )
303fbd20 649 {
faf51f1a 650 if ( crypto777[0] == 0 )
651 decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
0554de3c 652 if ( memcmp(ptr+1,crypto777,33) == 0 )
653 {
654 //printf("found notarytx\n");
655 return(1);
656 }
303fbd20 657 }
f24b36ca 658 }
303fbd20 659 return(0);
f24b36ca 660}
661
3eea72f2 662int32_t komodo_block2height(CBlock *block)
663{
e1501755 664 static uint32_t match,mismatch;
c52074f2 665 int32_t i,n,height2=-1,height = 0; uint8_t *ptr; CBlockIndex *pindex;
666 if ( (pindex= mapBlockIndex[block->GetHash()]) != 0 )
8a0b06f6 667 {
4b729ec5 668 height2 = (int32_t)pindex->GetHeight();
8a0b06f6 669 if ( height2 >= 0 )
670 return(height2);
671 }
83064643 672 if ( block != 0 && block->vtx[0].vin.size() > 0 )
0554de3c 673 {
0554de3c 674 ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
0554de3c 675 if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
3eea72f2 676 {
0554de3c 677 //for (i=0; i<6; i++)
678 // printf("%02x",ptr[i]);
679 n = ptr[0];
643bc61b 680 for (i=0; i<n; i++) // looks strange but this works
0554de3c 681 {
682 //03bb81000101(bb 187) (81 48001) (00 12288256) <- coinbase.6 ht.12288256
683 height += ((uint32_t)ptr[i+1] << (i*8));
684 //printf("(%02x %x %d) ",ptr[i+1],((uint32_t)ptr[i+1] << (i*8)),height);
685 }
643bc61b 686 //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
3eea72f2 687 }
0554de3c 688 //komodo_init(height);
3eea72f2 689 }
d4cc6fc3 690 if ( height != height2 )
c52074f2 691 {
f73e64e0 692 //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch);
d4cc6fc3 693 mismatch++;
694 if ( height2 >= 0 )
f717835b 695 height = height2;
d4cc6fc3 696 } else match++;
3eea72f2 697 return(height);
698}
699
9464ac21 700int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block)
3eea72f2 701{
2dbf06e8 702 int32_t n;
0690e63e 703 if ( KOMODO_LOADINGBLOCKS == 0 )
704 memset(pubkey33,0xff,33);
705 else memset(pubkey33,0,33);
19848155 706 if ( block->vtx[0].vout.size() > 0 )
0554de3c 707 {
1f722359
MT
708 txnouttype whichType;
709 vector<vector<unsigned char>> vch = vector<vector<unsigned char>>();
710 if (Solver(block->vtx[0].vout[0].scriptPubKey, whichType, vch) && whichType == TX_PUBKEY)
9464ac21 711 {
1f722359
MT
712 CPubKey pubKey(vch[0]);
713 if (pubKey.IsValid())
714 {
715 memcpy(pubkey33,vch[0].data(),33);
716 return true;
717 }
718 else memset(pubkey33,0,33);
9464ac21 719 }
1f722359 720 else memset(pubkey33,0,33);
0554de3c 721 }
9464ac21 722 return(0);
3eea72f2 723}
724
d7093b33 725int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
875cf683 726{
727 block.SetNull();
728 // Open history file to read
729 CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION);
730 if (filein.IsNull())
731 return(-1);
732 // Read block
733 try { filein >> block; }
734 catch (const std::exception& e)
735 {
736 fprintf(stderr,"readblockfromdisk err B\n");
737 return(-1);
738 }
739 return(0);
740}
741
ae0bb3d3 742uint32_t komodo_chainactive_timestamp()
743{
86131275 744 if ( chainActive.LastTip() != 0 )
745 return((uint32_t)chainActive.LastTip()->GetBlockTime());
e34a9d43 746 else return(0);
ae0bb3d3 747}
748
7d44d3dd 749CBlockIndex *komodo_chainactive(int32_t height)
750{
049e890a 751 if ( chainActive.LastTip() != 0 )
7d44d3dd 752 {
4b729ec5 753 if ( height <= chainActive.LastTip()->GetHeight() )
5150cb47 754 return(chainActive[height]);
4b729ec5 755 // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.LastTip()->GetHeight());
d54aa57d 756 }
86131275 757 //fprintf(stderr,"komodo_chainactive null chainActive.LastTip() height %d\n",height);
d54aa57d 758 return(0);
7d44d3dd 759}
760
761uint32_t komodo_heightstamp(int32_t height)
762{
0cb1d2da 763 CBlockIndex *ptr;
58bec1f9 764 if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
f21afd94 765 return(ptr->nTime);
b91ef9cf 766 //else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
7d44d3dd 767 return(0);
768}
769
232506f7 770/*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted
3eea72f2 771{
5368f298 772 int32_t i,num; uint8_t pubkeys[64][33]; CBlock block;
5920762d 773 if ( pindex->didinit != 0 )
2b00bd23 774 return;
4b729ec5 775 //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->GetHeight(),pindex->notaryid,height);
065505b7 776 if ( pindex->didinit == 0 )
3eea72f2 777 {
326ddd86 778 pindex->notaryid = -1;
0690e63e 779 if ( KOMODO_LOADINGBLOCKS == 0 )
1f333439 780 memset(pindex->pubkey33,0xff,33);
0690e63e 781 else memset(pindex->pubkey33,0,33);
1746e25c 782 if ( komodo_blockload(block,pindex) == 0 )
a76b835b 783 {
19848155 784 komodo_block2pubkey33(pindex->pubkey33,&block);
3884efe7 785 //for (i=0; i<33; i++)
786 // fprintf(stderr,"%02x",pindex->pubkey33[i]);
4b729ec5 787 //fprintf(stderr," set pubkey at height %d/%d\n",pindex->GetHeight(),height);
702f7543 788 //if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 )
232506f7 789 // pindex->didinit = (KOMODO_LOADINGBLOCKS == 0);
4b729ec5 790 } // else fprintf(stderr,"error loading block at %d/%d",pindex->GetHeight(),height);
3eea72f2 791 }
4b729ec5 792 if ( pindex->didinit != 0 && pindex->GetHeight() >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->GetHeight(),(uint32_t)pindex->nTime)) > 0 )
3eea72f2 793 {
2b00bd23 794 for (i=0; i<num; i++)
141950a4 795 {
2b00bd23 796 if ( memcmp(pubkeys[i],pindex->pubkey33,33) == 0 )
141950a4 797 {
2b00bd23 798 pindex->notaryid = i;
799 break;
141950a4 800 }
801 }
524e0280 802 if ( 0 && i == num )
ace61bc1 803 {
804 for (i=0; i<33; i++)
805 fprintf(stderr,"%02x",pindex->pubkey33[i]);
4b729ec5 806 fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->GetHeight(),height);
ace61bc1 807 }
3eea72f2 808 }
faf51f1a 809}*/
875cf683 810
3eea72f2 811void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
812{
232506f7 813 int32_t num,i; CBlock block;
3eea72f2 814 memset(pubkey33,0,33);
071f1be1 815 if ( pindex != 0 )
3eea72f2 816 {
232506f7 817 if ( komodo_blockload(block,pindex) == 0 )
818 komodo_block2pubkey33(pubkey33,&block);
3eea72f2 819 }
820}
6034c671 821
da9fce3e 822/*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33)
4a4e912b 823{
149a4d64 824 int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t pubkey33[33],pubkeys[64][33];
3e7e3109 825 if ( (pindex= chainActive[height]) != 0 )
fc318ffe 826 {
d74896c5 827 if ( pindex->didinit != 0 )
5e0e5f85 828 {
149a4d64 829 if ( destpubkey33 != 0 )
830 memcpy(destpubkey33,pindex->pubkey33,33);
3e7e3109 831 return(pindex->notaryid);
5e0e5f85 832 }
149a4d64 833 komodo_index2pubkey33(pubkey33,pindex,height);
834 if ( destpubkey33 != 0 )
835 memcpy(destpubkey33,pindex->pubkey33,33);
836 if ( pindex->didinit != 0 )
837 return(pindex->notaryid);
5e0e5f85 838 timestamp = pindex->GetBlockTime();
eb7171f5 839 if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 )
840 {
841 for (i=0; i<num; i++)
842 if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
843 return(i);
1746e25c 844 }
dac1ef88 845 }
0f29cbd6 846 fprintf(stderr,"komodo_minerid height.%d null pindex\n",height);
8eaa7b03 847 return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp));
da9fce3e 848}*/
4a4e912b 849
a30dd993 850int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height)
353af8aa 851{
178618db 852 int32_t i,j,n,duplicate; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33];
353af8aa 853 memset(mids,-1,sizeof(*mids)*66);
1481a43d 854 n = komodo_notaries(notarypubs33,height,0);
353af8aa 855 for (i=duplicate=0; i<66; i++)
856 {
3c525df1 857 if ( (pindex= komodo_chainactive(height-i)) != 0 )
353af8aa 858 {
a30dd993 859 blocktimes[i] = pindex->nTime;
da9fce3e 860 if ( komodo_blockload(block,pindex) == 0 )
5e0e5f85 861 {
da9fce3e 862 komodo_block2pubkey33(pubkeys[i],&block);
863 for (j=0; j<n; j++)
5e0e5f85 864 {
178618db 865 if ( memcmp(notarypubs33[j],pubkeys[i],33) == 0 )
da9fce3e 866 {
867 mids[i] = j;
868 (*nonzpkeysp)++;
869 break;
870 }
5e0e5f85 871 }
1481a43d 872 } else fprintf(stderr,"couldnt load block.%d\n",height);
353af8aa 873 if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
874 duplicate++;
3c525df1 875 }
353af8aa 876 }
f2805ceb 877 if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
353af8aa 878 return(1);
879 else return(0);
880}
881
df03549d 882int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
dbaf1154 883{
df03549d 884 int32_t i,j,n,nonz,numnotaries; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33],pubkey33[33];
885 numnotaries = komodo_notaries(notarypubs33,height,0);
886 for (i=nonz=0; i<width; i++,n++)
056447a6 887 {
888 if ( height-i <= 0 )
df03549d 889 continue;
890 if ( (pindex= komodo_chainactive(height-width+i+1)) != 0 )
891 {
892 if ( komodo_blockload(block,pindex) == 0 )
893 {
894 komodo_block2pubkey33(pubkey33,&block);
895 for (j=0; j<numnotaries; j++)
896 {
897 if ( memcmp(notarypubs33[j],pubkey33,33) == 0 )
898 {
899 minerids[nonz++] = j;
900 break;
901 }
902 }
0d8dc237 903 if ( j == numnotaries )
904 minerids[nonz++] = j;
df03549d 905 } else fprintf(stderr,"couldnt load block.%d\n",height);
906 }
056447a6 907 }
df03549d 908 return(nonz);
dbaf1154 909}
910
dac3c30c 911int32_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 912{
442215b4 913 int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33];
dac3c30c 914 komodo_chosennotary(&notaryid,height,pubkey33,blocktimes[0]);
cb19d181 915 if ( height >= 82000 )
4a4e912b 916 {
442215b4 917 if ( notaryid >= 0 )
4a4e912b 918 {
82f82d3f 919 for (i=1; i<66; i++)
66e3c532 920 {
442215b4 921 if ( mids[i] == notaryid )
82f82d3f 922 {
3c89a023 923 if ( height > 792000 )
0f5e787b 924 {
925 for (j=0; j<66; j++)
926 fprintf(stderr,"%d ",mids[j]);
927 fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i);
861119a1 928 return(-1);
0f5e787b 929 } else break;
82f82d3f 930 }
931 }
a658d926 932 if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 )
3ad8d247 933 {
26d9f4c3 934 if ( height > 807000 )
a658d926 935 return(-2);
fb64a588 936 }
937 return(1);
82f82d3f 938 } else return(0);
939 }
442215b4 940 else
4a4e912b 941 {
428a3934 942 if ( height >= 34000 && notaryid >= 0 )
4a4e912b 943 {
428a3934 944 if ( height < 79693 )
945 limit = 64;
946 else if ( height < 82000 )
947 limit = 8;
948 else limit = 66;
949 for (i=1; i<limit; i++)
66e3c532 950 {
70ebf02a 951 komodo_chosennotary(&nid,height-i,pubkey33,blocktimes[i]);
428a3934 952 if ( nid == notaryid )
953 {
79fb8179 954 //for (j=0; j<66; j++)
955 // fprintf(stderr,"%d ",mids[j]);
956 //fprintf(stderr,"ht.%d repeat mids[%d] nid.%d notaryid.%d\n",height-i,i,nid,notaryid);
428a3934 957 if ( height > 225000 )
958 return(-1);
959 }
66e3c532 960 }
428a3934 961 //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
962 return(1);
4a4e912b 963 }
4a4e912b 964 }
965 return(0);
966}
967
51dab149 968int32_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 969{
aa5ca001 970 int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
51dab149 971 depth = komodo_MoMdata(&notarized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip);
0ab5b335 972 memset(MoMp,0,sizeof(*MoMp));
b3548b52 973 memset(kmdtxidp,0,sizeof(*kmdtxidp));
0ab5b335 974 *notarized_heightp = 0;
1b9f98cd 975 if ( depth != 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
0ab5b335 976 {
977 *MoMp = MoM;
978 *notarized_heightp = notarized_ht;
aa5ca001 979 *kmdtxidp = kmdtxid;
0ab5b335 980 }
981 return(depth);
982}
983
b62d7030 984int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
985{
c52074f2 986 int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
86131275 987 if ( (pindex= chainActive.LastTip()) == 0 )
d82623d2 988 return(-1);
4b729ec5 989 notarized_height = komodo_notarizeddata(pindex->GetHeight(),&notarized_hash,&notarized_desttxid);
b62d7030 990 *notarized_heightp = notarized_height;
4b729ec5 991 if ( notarized_height >= 0 && notarized_height <= pindex->GetHeight() && (notary= mapBlockIndex[notarized_hash]) != 0 )
b62d7030 992 {
4b729ec5 993 //printf("nHeight.%d -> (%d %s)\n",pindex->Tip()->GetHeight(),notarized_height,notarized_hash.ToString().c_str());
994 if ( notary->GetHeight() == notarized_height ) // if notarized_hash not in chain, reorg
b62d7030 995 {
996 if ( nHeight < notarized_height )
997 {
2c5af2cd 998 //fprintf(stderr,"[%s] nHeight.%d < NOTARIZED_HEIGHT.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
b62d7030 999 return(-1);
1000 }
1001 else if ( nHeight == notarized_height && memcmp(&hash,&notarized_hash,sizeof(hash)) != 0 )
1002 {
beb911ec 1003 fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height);
b62d7030 1004 return(-1);
1005 }
4b729ec5 1006 } //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 1007 }
dc836ee4 1008 //else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
4b729ec5 1009 // fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->GetHeight());
b62d7030 1010 return(0);
1011}
485e48ca 1012
83da1e16 1013uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
c1c95e36 1014{
1015 LOCK(cs_main);
1016 CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
63c93b0c 1017 *txheighttimep = *txheightp = *tiptimep = 0;
1018 *valuep = 0;
c1c95e36 1019 if ( !GetTransaction(hash,tx,hashBlock,true) )
1020 return(0);
1021 uint32_t locktime = 0;
1022 if ( n < tx.vout.size() )
1023 {
c60397dd 1024 if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
c1c95e36 1025 {
1026 *valuep = tx.vout[n].nValue;
4b729ec5 1027 *txheightp = pindex->GetHeight();
83da1e16 1028 *txheighttimep = pindex->nTime;
86131275 1029 if ( *tiptimep == 0 && (tipindex= chainActive.LastTip()) != 0 )
c60397dd 1030 *tiptimep = (uint32_t)tipindex->nTime;
c1c95e36 1031 locktime = tx.nLockTime;
1f52f946 1032 //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
c1c95e36 1033 }
1034 }
1035 return(locktime);
1036}
1037
1038uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
c60397dd 1039
1040uint64_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 1041{
c60397dd 1042 uint64_t value; uint32_t tiptime=0,txheighttimep; CBlockIndex *pindex;
1043 if ( (pindex= chainActive[tipheight]) != 0 )
1044 tiptime = (uint32_t)pindex->nTime;
72070c94 1045 else fprintf(stderr,"cant find height[%d]\n",tipheight);
83da1e16 1046 if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 )
c1c95e36 1047 {
798f28c7 1048 if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
1049 return(komodo_interest(*txheightp,value,*locktimep,tiptime));
c1c95e36 1050 //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 1051 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);
1052 }
c1c95e36 1053 return(0);
1054}
8a7f7063 1055
1056int32_t komodo_isrealtime(int32_t *kmdheightp)
1057{
d82623d2 1058 struct komodo_state *sp; CBlockIndex *pindex;
8a7c9241 1059 if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
ffbc2f00 1060 *kmdheightp = sp->CURRENT_HEIGHT;
1061 else *kmdheightp = 0;
4b729ec5 1062 if ( (pindex= chainActive.LastTip()) != 0 && pindex->GetHeight() >= (int32_t)komodo_longestchain() )
8a7f7063 1063 return(1);
1064 else return(0);
1065}
14aa6cc0 1066
99d7ed25 1067int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
14aa6cc0 1068{
14aa6cc0 1069 if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
1070 {
3d02f57b 1071 if ( txheight > 246748 )
14aa6cc0 1072 {
1073 if ( txheight < 247205 )
39d28b06 1074 cmptime -= 16000;
bd070d8b 1075 if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
14aa6cc0 1076 {
531b9293 1077 if ( tx.nLockTime != 1477258935 && dispflag != 0 )
14aa6cc0 1078 {
bd070d8b 1079 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 1080 }
1081 return(-1);
1082 }
948ad8f3 1083 if ( 0 && dispflag != 0 )
bd070d8b 1084 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 1085 }
14aa6cc0 1086 }
1087 return(0);
1088}
ec5ed2f7 1089
18443f69 1090/*
9464ac21 1091 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 1092
1093 komodo_checkPOW (slow) is called right before connecting blocks so all prior blocks can be assumed to be there and all checks must pass
1094
1095 commission must be in coinbase.vout[1] and must be >= 10000 sats
1096 PoS stake must be without txfee and in the last tx in the block at vout[0]
18443f69 1097 */
18443f69 1098
1099uint64_t komodo_commission(const CBlock *pblock)
1100{
1101 int32_t i,j,n=0,txn_count; uint64_t commission,total = 0;
1102 txn_count = pblock->vtx.size();
1103 for (i=0; i<txn_count; i++)
1104 {
3acce042 1105 n = pblock->vtx[i].vout.size();
18443f69 1106 for (j=0; j<n; j++)
1107 {
1108 //fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
1109 if ( i != 0 || j != 1 )
1110 total += pblock->vtx[i].vout[j].nValue;
1111 }
1112 }
1113 //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN));
1114 commission = ((total * ASSETCHAINS_COMMISSION) / COIN);
1115 if ( commission < 10000 )
1116 commission = 0;
1117 return(commission);
1118}
1119
acbc7a94 1120uint32_t komodo_segid32(char *coinaddr)
1121{
1122 bits256 addrhash;
3001f999 1123 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
acbc7a94 1124 return(addrhash.uints[0]);
1125}
1126
b70126d4 1127int8_t komodo_segid(int32_t nocache,int32_t height)
049e24ce 1128{
86f88c4f 1129 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 1130 if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
1131 {
b70126d4 1132 if ( nocache == 0 && pindex->segid >= -1 )
efb8981c 1133 return(pindex->segid);
049e24ce 1134 if ( komodo_blockload(block,pindex) == 0 )
1135 {
86f88c4f 1136 txn_count = block.vtx.size();
1137 if ( txn_count > 1 && block.vtx[txn_count-1].vin.size() == 1 && block.vtx[txn_count-1].vout.size() == 1 )
049e24ce 1138 {
86f88c4f 1139 txid = block.vtx[txn_count-1].vin[0].prevout.hash;
1140 vout = block.vtx[txn_count-1].vin[0].prevout.n;
049e24ce 1141 txtime = komodo_txtime(&value,txid,vout,destaddr);
86f88c4f 1142 if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
049e24ce 1143 {
1144 strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
86f88c4f 1145 if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value )
049e24ce 1146 {
1147 segid = komodo_segid32(voutaddr) & 0x3f;
e77d279f 1148 //fprintf(stderr,"komodo_segid.(%d) -> %02x\n",height,segid);
049e24ce 1149 }
1150 } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height);
1151 }
1152 }
1153 }
1154 return(segid);
1155}
1156
1157int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
1158{
1159 static uint8_t prevhashbuf[100]; static int32_t prevheight;
1160 int32_t i;
1161 if ( height == prevheight && n == 100 )
1162 memcpy(hashbuf,prevhashbuf,100);
1163 else
1164 {
1165 memset(hashbuf,0xff,n);
1166 for (i=0; i<n; i++)
1167 {
b70126d4 1168 hashbuf[i] = (uint8_t)komodo_segid(1,height+i);
488dab78 1169 //fprintf(stderr,"%02x ",hashbuf[i]);
049e24ce 1170 }
1171 if ( n == 100 )
1172 {
1173 memcpy(prevhashbuf,hashbuf,100);
1174 prevheight = height;
488dab78 1175 //fprintf(stderr,"prevsegids.%d\n",height+n);
049e24ce 1176 }
1177 }
1178}
1179
ac531095 1180uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout)
1181{
1273624d 1182 bits256 addrhash;
ac531095 1183 vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
1184 memcpy(&hashbuf[100],&addrhash,sizeof(addrhash));
1185 memcpy(&hashbuf[100+sizeof(addrhash)],&txid,sizeof(txid));
1186 memcpy(&hashbuf[100+sizeof(addrhash)+sizeof(txid)],&vout,sizeof(vout));
1187 vcalc_sha256(0,(uint8_t *)hashp,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
1188 return(addrhash.uints[0]);
1189}
1190
18443f69 1191uint32_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)
1192{
0ce374b7 1193 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 1194 txtime = komodo_txtime2(&value,txid,vout,address);
c3ed86ad 1195 if ( validateflag == 0 )
1196 {
0debf37f 1197 //fprintf(stderr,"blocktime.%u -> ",blocktime);
c3ed86ad 1198 if ( blocktime < prevtime+3 )
1199 blocktime = prevtime+3;
e0a3ab0a 1200 if ( blocktime < GetAdjustedTime()-60 )
8785f8ce 1201 blocktime = GetAdjustedTime()+30;
0debf37f 1202 //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime);
c3ed86ad 1203 }
7b6d6985 1204 if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
049e24ce 1205 {
01994dba 1206 //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime);
18443f69 1207 return(0);
049e24ce 1208 }
97a337f7 1209 if ( value < SATOSHIDEN )
1210 return(0);
a03465f6 1211 value /= SATOSHIDEN;
84f19b77 1212 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
1213 ratio = (mindiff / bnTarget);
049e24ce 1214 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
18443f69 1215 minage = 6000;
0ce374b7 1216 komodo_segids(hashbuf,nHeight-101,100);
1217 segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
1218 segid = ((nHeight + segid32) & 0x3f);
8e1ca1ad 1219 for (iter=0; iter<600; iter++)
049e24ce 1220 {
0401884f 1221 if ( blocktime+iter+segid*2 < txtime+minage )
1222 continue;
049e24ce 1223 diff = (iter + blocktime - txtime - minage);
f6567e80 1224 if ( diff < 0 )
1225 diff = 60;
1226 else if ( diff > 3600*24*30 )
18443f69 1227 {
01994dba 1228 //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage);
049e24ce 1229 diff = 3600*24*30;
5e90f445 1230 }
049e24ce 1231 if ( iter > 0 )
1232 diff += segid*2;
bfa19436 1233 coinage = (value * diff);
0ce374b7 1234 if ( blocktime+iter+segid*2 > prevtime+480 )
1235 coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
8a7c025a 1236 coinage256 = arith_uint256(coinage+1);
1237 hashval = ratio * (UintToArith256(hash) / coinage256);
049e24ce 1238 if ( hashval <= bnTarget )
1239 {
1240 winner = 1;
1241 if ( validateflag == 0 )
18443f69 1242 {
0debf37f 1243 //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid);
049e24ce 1244 blocktime += iter;
1245 blocktime += segid * 2;
18443f69 1246 }
049e24ce 1247 break;
18443f69 1248 }
049e24ce 1249 if ( validateflag != 0 )
18443f69 1250 {
26b9af80 1251 /*for (i=31; i>=24; i--)
18443f69 1252 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1253 fprintf(stderr," vs ");
1254 for (i=31; i>=24; i--)
1255 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
26b9af80 1256 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 1257 break;
18443f69 1258 }
1259 }
049e24ce 1260 //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner);
5162b553 1261 if ( 0 && validateflag != 0 )
049e24ce 1262 {
1263 for (i=31; i>=24; i--)
1264 fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
1265 fprintf(stderr," vs ");
1266 for (i=31; i>=24; i--)
1267 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
4dc0ad38 1268 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 1269 }
1270 if ( nHeight < 10 )
18443f69 1271 return(blocktime);
1272 return(blocktime * winner);
1273}
1274
1275arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
1276{
23c192b9 1277 int32_t oldflag = 0;
4cc33bf8 1278 CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
18443f69 1279 *percPoSp = percPoS = 0;
8daf7caf 1280 if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
96df006a 1281 return(target);
18443f69 1282 sum = arith_uint256(0);
1283 ave = sum;
97a337f7 1284 easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
4cc33bf8 1285 for (i=n=m=0; i<100; i++)
18443f69 1286 {
1287 ht = height - 100 + i;
e83bf6b3 1288 if ( ht <= 1 )
1289 continue;
18443f69 1290 if ( (pindex= komodo_chainactive(ht)) != 0 )
4cc33bf8 1291 {
c6d212db 1292 if ( komodo_segid(0,ht) >= 0 )
4cc33bf8 1293 {
1294 n++;
1295 percPoS++;
1296 if ( ASSETCHAINS_STAKED < 100 )
1297 fprintf(stderr,"0");
1298 }
1299 else
1300 {
1301 if ( ASSETCHAINS_STAKED < 100 )
1302 fprintf(stderr,"1");
9e1a6d76 1303 sum += UintToArith256(pindex->GetBlockHash());
4cc33bf8 1304 m++;
4cc33bf8 1305 }
1306 }
4cc33bf8 1307 if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
1308 fprintf(stderr," %d, ",percPoS);
18443f69 1309 }
0fa08b81 1310 if ( m+n < 100 )
3753f568 1311 percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
f2c1ac06 1312 if ( ASSETCHAINS_STAKED < 100 )
1313 fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
18443f69 1314 *percPoSp = percPoS;
4cc33bf8 1315 if ( m > 0 )
18443f69 1316 {
4cc33bf8 1317 ave = (sum / arith_uint256(m));
18443f69 1318 if ( ave > target )
1319 ave = target;
db871af5 1320 } else ave = target; //easydiff; //else return(target);
dfb0fdfa 1321 if ( percPoS == 0 )
1322 percPoS = 1;
18443f69 1323 if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
1324 {
db871af5 1325 //if ( oldflag != 0 )
1326 // bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
23c192b9 1327 if ( oldflag != 0 )
db871af5 1328 bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
1329 else bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
f2c1ac06 1330 if ( ASSETCHAINS_STAKED < 100 )
18443f69 1331 {
1332 for (i=31; i>=24; i--)
1333 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1334 fprintf(stderr," increase diff -> ");
1335 for (i=31; i>=24; i--)
1336 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1337 fprintf(stderr," floor diff ");
1338 for (i=31; i>=24; i--)
1339 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1340 fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1341 }
1342 }
1343 else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget
1344 {
23c192b9 1345 if ( oldflag != 0 )
1346 {
1347 bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
1348 //bnTarget = (bnTarget * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc);
1349 bnTarget = (bnTarget / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
db871af5 1350 }
1351 else bnTarget = (ave / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
b6c80e46 1352 if ( bnTarget > easydiff )
ce2b6b33 1353 bnTarget = easydiff;
b6c80e46 1354 else if ( bnTarget < ave ) // overflow
8ba2ae9e 1355 {
b6c80e46 1356 bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
8ba2ae9e 1357 if ( bnTarget < ave )
1358 bnTarget = ave;
1359 }
23b680a0 1360 if ( 1 )
18443f69 1361 {
1362 for (i=31; i>=24; i--)
1363 fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
1364 fprintf(stderr," decrease diff -> ");
1365 for (i=31; i>=24; i--)
1366 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1367 fprintf(stderr," floor diff ");
1368 for (i=31; i>=24; i--)
1369 fprintf(stderr,"%02x",((uint8_t *)&target)[i]);
1370 fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS);
1371 }
1372 }
1373 else bnTarget = ave; // recent ave is perfect
1374 return(bnTarget);
1375}
1376
84b0bd52 1377int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget,arith_uint256 bhash)
18443f69 1378{
e77d279f 1379 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 1380 if ( ASSETCHAINS_STAKED == 100 && height <= 10 )
6ac49724 1381 return(1);
435ef4fd 1382 pindex = mapBlockIndex[pblock->GetHash()];
15bec819 1383 if ( pindex != 0 && pindex->segid >= -1 )
efb8981c 1384 {
1385 if ( pindex->segid == -1 )
1386 return(0);
1387 else return(1);
15bec819 1388 }
18443f69 1389 txn_count = pblock->vtx.size();
feefa2d3 1390 if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 )
18443f69 1391 {
1392 if ( prevtime == 0 )
1393 {
1394 if ( (previndex= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
1395 prevtime = (uint32_t)previndex->nTime;
1396 }
1397 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1398 vout = pblock->vtx[txn_count-1].vin[0].prevout.n;
1399 if ( prevtime != 0 )
1400 {
d1db0920 1401 if ( komodo_isPoS(pblock) != 0 )
efb8981c 1402 {
e0a3ab0a 1403 eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"");
efb8981c 1404 }
18443f69 1405 if ( eligible == 0 || eligible > pblock->nTime )
1406 {
703faba6 1407 if ( 0 && ASSETCHAINS_STAKED < 100 )
308ee076 1408 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 1409 if ( slowflag != 0 && pindex != 0 )
549ca5a6 1410 {
efb8981c 1411 pindex->segid = -1;
703faba6 1412 fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
549ca5a6 1413 }
efb8981c 1414 }
1415 else
1416 {
1417 isPoS = 2; // 2 means staking utxo validated
eea0a57b 1418 if ( slowflag != 0 && height > 100 )
efb8981c 1419 {
066c16e5 1420 segid = -3;
eea0a57b 1421 if ( pindex != 0 && pindex->segid == -2 && (segid= komodo_segid(1,height)) >= 0 )
efb8981c 1422 {
eea0a57b 1423 pindex->segid = segid;
1424 fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid);
9e432c97 1425 } //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid);
efb8981c 1426 }
1427 }
18443f69 1428 }
11b390d8 1429 if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx
18443f69 1430 {
d1db0920 1431 if ( komodo_isPoS(pblock) != 0 )
1cdb961b 1432 isPoS = 1;
84b0bd52 1433 }
703faba6 1434 if ( slowflag != 0 && isPoS != 0 )
84b0bd52 1435 {
efb8981c 1436 if ( isPoS != 2 )
18443f69 1437 {
efb8981c 1438 fprintf(stderr,"ht.%d isPoS.%d utxo not validated -> must be PoW fake\n",height,isPoS);
84b0bd52 1439 isPoS = 0;
1440 }
efb8981c 1441 else
1442 {
1443 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
1444 if ( bhash < bnTarget )
1445 {
1446 fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height);
1447 isPoS = 0;
1448 }
1449 }
84b0bd52 1450 }
1451 //else return(-1);
18443f69 1452 }
ffd6dd51 1453 //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS);
11b390d8 1454 return(isPoS != 0);
18443f69 1455}
1456
c5325a32 1457// for now, we will ignore slowFlag in the interest of keeping success/fail simpler for security purposes
1f722359
MT
1458bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
1459{
1460 CBlockIndex *pastBlockIndex;
1461 uint256 txid, blkHash;
1462 int32_t txn_count;
1463 uint32_t voutNum;
9feb4b9e 1464 CAmount value;
1f722359 1465 bool isPOS = false;
cd230e37 1466 CTxDestination voutaddress, destaddress, cbaddress;
1f722359
MT
1467 arith_uint256 target, hash;
1468 CTransaction tx;
1469
f6608b5a 1470 if (!pblock->IsVerusPOSBlock())
17d0160a
MT
1471 {
1472 printf("%s, height %d not POS block\n", pblock->nNonce.GetHex().c_str(), height);
9feb4b9e 1473 //pblock->nNonce.SetPOSTarget(pblock->nNonce.GetPOSTarget());
1474 //printf("%s after setting POS target\n", pblock->nNonce.GetHex().c_str());
1fae37f6 1475 return false;
17d0160a 1476 }
1fae37f6 1477
cd230e37 1478 char voutaddr[64], destaddr[64], cbaddr[64];
1f722359 1479
1f722359
MT
1480 txn_count = pblock->vtx.size();
1481
1482 if ( txn_count > 1 )
1483 {
c5325a32 1484 target.SetCompact(pblock->GetVerusPOSTarget());
1f722359
MT
1485 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1486 voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
9feb4b9e 1487 value = pblock->vtx[txn_count-1].vout[0].nValue;
1f722359 1488
9feb4b9e 1489 {
1490 bool validHash;
1491 bool enablePOSNonce = CPOSNonce::NewPOSActive(height);
1492 bool newPOSActive = enablePOSNonce || (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= height);
1493 uint256 rawHash;
1494 arith_uint256 posHash;
1495 if (newPOSActive)
1496 {
1497 validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1498 posHash = UintToArith256(rawHash) / value;
1499 //if (slowflag)
1500 //{
1501 // printf("first nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
1502 // printf("Raw POShash: %s\n", posHash.GetHex().c_str());
1503 //}
1504 }
1505 if (newPOSActive && !(validHash && posHash <= target))
1506 {
644c7445 1507 printf("ERROR: invalid nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
9feb4b9e 1508 pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1509 }
1510 //else
1511 {
1512 if (slowflag == 0)
1513 {
1514 isPOS = true;
1515 }
1516 else if (!(pastBlockIndex = komodo_chainactive(height - 100)))
1517 {
1518 fprintf(stderr,"ERROR: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str());
1519 }
1520 else
1f722359 1521#ifndef KOMODO_ZCASH
9feb4b9e 1522 if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
1f722359 1523#else
9feb4b9e 1524 if (!GetTransaction(txid, tx, blkHash, true))
1f722359 1525#endif
1f722359 1526 {
9feb4b9e 1527 fprintf(stderr,"ERROR: invalid PoS block %s - no source transaction\n",blkHash.ToString().c_str());
1f722359 1528 }
9feb4b9e 1529 else
1f722359 1530 {
9feb4b9e 1531 CBlockHeader bh = pastBlockIndex->GetBlockHeader();
1532 uint256 pastHash = bh.GetVerusEntropyHash(height - 100);
1533
1534 // if height is over when Nonce is required to be the new format, we check that the new format is correct
1535 // if over when we have the new POS hash function, we validate that as well
1536 // they are 100 blocks apart
1537 CPOSNonce nonce = pblock->nNonce;
1538
1539 //printf("before nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
1540 //validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1541 //hash = UintToArith256(rawHash) / tx.vout[voutNum].nValue;
1542 //printf("Raw POShash: %s\n", hash.GetHex().c_str());
c5325a32 1543
9feb4b9e 1544 hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
1545
1546 //printf("after nNonce: %s, height: %d\n", nonce.GetHex().c_str(), height);
1547 //printf("POShash: %s\n\n", hash.GetHex().c_str());
1548
4b729ec5 1549 if (newPOSActive && posHash != hash)
1550 {
1551 printf("blk hash: %s\nnonce: %s\ncorrect: %s\n", pblock->GetHash().GetHex().c_str(), pblock->nNonce.GetHex().c_str(), nonce.GetHex().c_str());
1552 }
1553
1554
9feb4b9e 1555 //if ((!newPOSActive || posHash == hash) && hash <= target)
1556 if (hash <= target)
1557 {
1558 if ((mapBlockIndex.count(blkHash) == 0) ||
1559 !(pastBlockIndex = mapBlockIndex[blkHash]) ||
4b729ec5 1560 (height - pastBlockIndex->GetHeight()) < VERUS_MIN_STAKEAGE)
c5325a32 1561 {
9feb4b9e 1562 fprintf(stderr,"ERROR: invalid PoS block %s - stake transaction too new\n",blkHash.ToString().c_str());
c5325a32
MT
1563 }
1564 else
1f722359 1565 {
9feb4b9e 1566 // make sure we have the right target
1567 CBlockIndex *previndex;
1568 if (!(previndex = mapBlockIndex[pblock->hashPrevBlock]))
c5325a32 1569 {
9feb4b9e 1570 fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
1f722359
MT
1571 }
1572 else
1573 {
9feb4b9e 1574 arith_uint256 cTarget;
1575 uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
1576 cTarget.SetCompact(nBits);
1577 bool nonceOK = true;
1578
1579 // check to see how many fail
1580 //if (nonce != pblock->nNonce)
1581 // printf("Mismatched nNonce: %s\nblkHash: %s, height: %d\n", nonce.GetHex().c_str(), pblock->GetHash().GetHex().c_str(), height);
1582
1583 if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum))
1584 {
1585 fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
1586 nonceOK = false;
1587 }
1588 else
1589 {
1590 if (cTarget != target)
1591 {
1592 fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
1593 nonceOK = false;
1594 }
1595 }
1596 if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) &&
1597 ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
1598 CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
1599 {
1600 strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
1601 strcpy(destaddr, CBitcoinAddress(destaddress).ToString().c_str());
1602 strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
1603 if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
1604 {
1605 isPOS = true;
1606 }
1607 else
1608 {
1609 fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n",blkHash.ToString().c_str());
1610 }
1611 }
1f722359
MT
1612 }
1613 }
1614 }
1615 }
1f722359
MT
1616 }
1617 }
1618 }
1619 return(isPOS);
1620}
1621
fb6bb4e8 1622int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1623{
1624 int64_t checktoshis=0; uint8_t *script;
1625 if ( ASSETCHAINS_COMMISSION != 0 )
1626 {
1627 checktoshis = komodo_commission(pblock);
1628 if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1629 return(-1);
1630 else if ( checktoshis != 0 )
1631 {
9feb4b9e 1632 script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
fb6bb4e8 1633 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1634 return(-1);
1635 if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1636 {
1637 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1638 return(-1);
1639 }
1640 }
1641 }
1642 return(checktoshis);
1643}
1644
3fdb3782
SS
1645bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1646
18443f69 1647int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1648{
9464ac21 1649 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 1650 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
1651 KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
18443f69 1652 if ( !CheckEquihashSolution(pblock, Params()) )
1653 {
1654 fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
1655 return(-1);
1656 }
ec5b59fd 1657 hash = pblock->GetHash();
9464ac21 1658 bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1659 bhash = UintToArith256(hash);
1660 possible = komodo_block2pubkey33(pubkey33,pblock);
28b18b61 1661 if ( height == 0 )
f1b57a6e 1662 {
28b18b61 1663 if ( slowflag != 0 )
b088fa97 1664 {
1665 fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
28b18b61 1666 return(0);
b088fa97 1667 }
28b18b61 1668 if ( (pprev= mapBlockIndex[pblock->hashPrevBlock]) != 0 )
4b729ec5 1669 height = pprev->GetHeight() + 1;
28b18b61 1670 if ( height == 0 )
1671 return(0);
f1b57a6e 1672 }
1f722359
MT
1673 if ( ASSETCHAINS_LWMAPOS != 0 && bhash > bnTarget )
1674 {
1675 // if proof of stake is active, check if this is a valid PoS block before we fail
1676 if (verusCheckPOSBlock(slowflag, pblock, height))
1677 {
1678 return(0);
1679 }
1680 }
2c089649 1681 if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget )
18443f69 1682 {
1683 failed = 1;
9464ac21 1684 if ( height > 0 && ASSETCHAINS_SYMBOL[0] == 0 ) // for the fast case
18443f69 1685 {
1686 if ( (n= komodo_notaries(pubkeys,height,pblock->nTime)) > 0 )
1687 {
1688 for (i=0; i<n; i++)
1689 if ( memcmp(pubkey33,pubkeys[i],33) == 0 )
1690 {
1691 notaryid = i;
1692 break;
1693 }
1694 }
1695 }
9464ac21 1696 else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 )
1697 {
f02af889 1698 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW )
1699 return(0);
a3b5f801 1700 if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget for staked chains
2ba9de01 1701 return(-1);
9464ac21 1702 }
18443f69 1703 }
a3d08df0 1704 if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
18443f69 1705 {
84b0bd52 1706 if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget,bhash)) == 0 )
18443f69 1707 {
9aa24310 1708 if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! POSTEST64
18443f69 1709 return(-1);
1710 else
1711 {
1cdb961b 1712 if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target
1713 return(0);
18443f69 1714 if ( slowflag != 0 )
1715 bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
18443f69 1716 if ( bhash > bnTarget )
1717 {
1718 for (i=31; i>=16; i--)
2808b68f 1719 fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]);
18443f69 1720 fprintf(stderr," > ");
1721 for (i=31; i>=16; i--)
1722 fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
1723 fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED);
1724 return(-1);
b088fa97 1725 } else failed = 0;
18443f69 1726 }
b088fa97 1727 }
1728 else if ( is_PoSblock < 0 )
1729 {
1730 fprintf(stderr,"unexpected negative is_PoSblock.%d\n",is_PoSblock);
18443f69 1731 return(-1);
b088fa97 1732 }
18443f69 1733 }
d9f176ac 1734 if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
18443f69 1735 {
d9f176ac 1736 if ( height == 1 )
18443f69 1737 {
9feb4b9e 1738 script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
18443f69 1739 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1740 return(-1);
d9f176ac 1741 }
c9855c14 1742 else
1743 {
1744 if ( komodo_checkcommission(pblock,height) < 0 )
18443f69 1745 return(-1);
18443f69 1746 }
1747 }
c685d692 1748 //fprintf(stderr,"komodo_checkPOW possible.%d slowflag.%d ht.%d notaryid.%d failed.%d\n",possible,slowflag,height,notaryid,failed);
1749 if ( failed != 0 && possible == 0 && notaryid < 0 )
18443f69 1750 return(-1);
1751 else return(0);
1752}
1753
26189509 1754int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
7e282415 1755{
84eabd0d 1756 CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
7e282415 1757 n = pblock->vtx.size();
1758 for (i=0; i<n; i++)
1759 {
9f60c7ec 1760 CTransaction vintx,&tx = pblock->vtx[i];
9feb4b9e 1761 zfunds += (tx.GetValueOut() - tx.GetShieldedValueIn());
7e282415 1762 if ( (m= tx.vin.size()) > 0 )
1763 {
1764 for (j=0; j<m; j++)
1765 {
1766 if ( i == 0 )
1767 continue;
1768 txid = tx.vin[j].prevout.hash;
1769 vout = tx.vin[j].prevout.n;
1770 if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
1771 {
1772 fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1773 return(0);
1774 }
1775 vinsum += vintx.vout[vout].nValue;
1776 }
1777 }
1778 if ( (m= tx.vout.size()) > 0 )
1779 {
1780 for (j=0; j<m-1; j++)
84eabd0d 1781 {
1782 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1783 voutsum += tx.vout[j].nValue;
27d76b74 1784 else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
84eabd0d 1785 }
9feb4b9e 1786 script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
7e282415 1787 if ( script == 0 || script[0] != 0x6a )
84eabd0d 1788 {
1789 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1790 voutsum += tx.vout[j].nValue;
1791 }
7e282415 1792 }
1793 }
26189509 1794 *zfundsp = zfunds;
7130a7cd 1795 if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times
1ec2a42f 1796 return(3 * SATOSHIDEN);
aa51eef6 1797 //if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 )
1798 //. fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
7e282415 1799 return(voutsum - vinsum);
1800}
1801
26189509 1802int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
7e282415 1803{
26189509 1804 CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
67459d80 1805 //fprintf(stderr,"coinsupply %d\n",height);
26189509 1806 *zfundsp = 0;
7e282415 1807 if ( (pindex= komodo_chainactive(height)) != 0 )
1808 {
4b729ec5 1809 while ( pindex != 0 && pindex->GetHeight() > 0 )
9f60c7ec 1810 {
7130a7cd 1811 if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
97a4e923 1812 {
1813 if ( komodo_blockload(block,pindex) == 0 )
4b729ec5 1814 pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->GetHeight(),&block);
df74ee5f 1815 else
1816 {
4b729ec5 1817 fprintf(stderr,"error loading block.%d\n",pindex->GetHeight());
df74ee5f 1818 return(0);
1819 }
97a4e923 1820 }
1821 supply += pindex->newcoins;
26189509 1822 zfunds += pindex->zfunds;
4b729ec5 1823 //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 1824 pindex = pindex->pprev;
9f60c7ec 1825 }
7e282415 1826 }
26189509 1827 *zfundsp = zfunds;
7e282415 1828 return(supply);
1829}
This page took 0.71325 seconds and 4 git commands to generate.