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