]> Git Repo - VerusCoin.git/blame - src/komodo_bitcoind.h
Build fix
[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
53debd37 1160void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
049e24ce 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;
7695dab4 1473 CTxDestination 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
1f722359
MT
1483 txn_count = pblock->vtx.size();
1484
1485 if ( txn_count > 1 )
1486 {
c5325a32 1487 target.SetCompact(pblock->GetVerusPOSTarget());
1f722359
MT
1488 txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
1489 voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
9feb4b9e 1490 value = pblock->vtx[txn_count-1].vout[0].nValue;
1f722359 1491
9feb4b9e 1492 {
8c3a9bc7 1493 bool validHash = (value != 0);
9feb4b9e 1494 bool enablePOSNonce = CPOSNonce::NewPOSActive(height);
c68ca1a2 1495 bool newPOSEnforcement = enablePOSNonce && (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= height);
f37d48ca 1496 bool supportInstantSpend = !IsVerusActive() && CConstVerusSolutionVector::activationHeight.ActiveVersion(height) >= CActivationHeight::ACTIVATE_PBAAS;
7695dab4 1497 bool extendedStake = CConstVerusSolutionVector::activationHeight.ActiveVersion(height) >= CActivationHeight::ACTIVATE_EXTENDEDSTAKE;
9feb4b9e 1498 uint256 rawHash;
1499 arith_uint256 posHash;
95c5c69b 1500
8c3a9bc7 1501 if (validHash && newPOSEnforcement)
9feb4b9e 1502 {
1503 validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1504 posHash = UintToArith256(rawHash) / value;
f3b0d2ab 1505 if (!validHash || posHash > target)
1506 {
1507 validHash = false;
1508 printf("ERROR: invalid nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1509 pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1510 }
8c3a9bc7 1511 // make sure prev block hash and block height are correct
1512 CStakeParams p;
1513 if (validHash && (validHash = GetStakeParams(pblock->vtx[txn_count-1], p)))
f3b0d2ab 1514 {
8c3a9bc7 1515 for (int i = 0; validHash && i < pblock->vtx[0].vout.size(); i++)
f3b0d2ab 1516 {
1517 validHash = false;
17274e5e 1518 if (pblock->vtx[0].vout[i].scriptPubKey.IsInstantSpend() || ValidateMatchingStake(pblock->vtx[0], i, pblock->vtx[txn_count-1], validHash) && !validHash)
185b2d4f 1519 {
79b0432d 1520 if ((p.prevHash == pblock->hashPrevBlock) && (int32_t)p.blkHeight == height)
8c3a9bc7 1521 {
1522 validHash = true;
1523 }
79b0432d 1524 else
185b2d4f 1525 {
79b0432d 1526 printf("ERROR: invalid block data for stake tx\nblkHash: %s\ntxBlkHash: %s\nblkHeight: %d, txBlkHeight: %d\n",
185b2d4f 1527 pblock->hashPrevBlock.GetHex().c_str(), p.prevHash.GetHex().c_str(), height, p.blkHeight);
1528 validHash = false;
1529 }
1530 }
8c3a9bc7 1531 else validHash = false;
185b2d4f 1532 }
f3b0d2ab 1533 }
9feb4b9e 1534 }
f3b0d2ab 1535 if (validHash)
9feb4b9e 1536 {
1537 if (slowflag == 0)
1538 {
1539 isPOS = true;
1540 }
1541 else if (!(pastBlockIndex = komodo_chainactive(height - 100)))
1542 {
1543 fprintf(stderr,"ERROR: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str());
1544 }
1545 else
1f722359 1546#ifndef KOMODO_ZCASH
9feb4b9e 1547 if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
1f722359 1548#else
9feb4b9e 1549 if (!GetTransaction(txid, tx, blkHash, true))
1f722359 1550#endif
1f722359 1551 {
9feb4b9e 1552 fprintf(stderr,"ERROR: invalid PoS block %s - no source transaction\n",blkHash.ToString().c_str());
1f722359 1553 }
9feb4b9e 1554 else
1f722359 1555 {
56fe75cb 1556 uint256 pastHash = chainActive.GetVerusEntropyHash(height);
9feb4b9e 1557 // if height is over when Nonce is required to be the new format, we check that the new format is correct
1558 // if over when we have the new POS hash function, we validate that as well
1559 // they are 100 blocks apart
1560 CPOSNonce nonce = pblock->nNonce;
1561
1562 //printf("before nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
1563 //validHash = pblock->GetRawVerusPOSHash(rawHash, height);
1564 //hash = UintToArith256(rawHash) / tx.vout[voutNum].nValue;
1565 //printf("Raw POShash: %s\n", hash.GetHex().c_str());
c5325a32 1566
9feb4b9e 1567 hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
1568
1569 //printf("after nNonce: %s, height: %d\n", nonce.GetHex().c_str(), height);
1570 //printf("POShash: %s\n\n", hash.GetHex().c_str());
1571
c68ca1a2 1572 if ((!newPOSEnforcement || posHash == hash) && hash <= target)
9feb4b9e 1573 {
d565e7b7 1574 BlockMap::const_iterator it = mapBlockIndex.find(blkHash);
1575 if ((it == mapBlockIndex.end()) ||
1576 !(pastBlockIndex = it->second) ||
4b729ec5 1577 (height - pastBlockIndex->GetHeight()) < VERUS_MIN_STAKEAGE)
c5325a32 1578 {
d565e7b7 1579 fprintf(stderr,"ERROR: invalid PoS block %s - stake source too new or not found\n",blkHash.ToString().c_str());
c5325a32
MT
1580 }
1581 else
1f722359 1582 {
9feb4b9e 1583 // make sure we have the right target
1584 CBlockIndex *previndex;
d565e7b7 1585 it = mapBlockIndex.find(pblock->hashPrevBlock);
1586 if (it == mapBlockIndex.end() || !(previndex = it->second))
c5325a32 1587 {
9feb4b9e 1588 fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
1f722359
MT
1589 }
1590 else
1591 {
9feb4b9e 1592 arith_uint256 cTarget;
1593 uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
1594 cTarget.SetCompact(nBits);
1595 bool nonceOK = true;
1596
1597 // check to see how many fail
1598 //if (nonce != pblock->nNonce)
1599 // printf("Mismatched nNonce: %s\nblkHash: %s, height: %d\n", nonce.GetHex().c_str(), pblock->GetHash().GetHex().c_str(), height);
1600
12217420 1601 if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum, pblock->nVersion))
9feb4b9e 1602 {
1603 fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
7695dab4 1604 return false;
9feb4b9e 1605 }
1606 else
1607 {
1608 if (cTarget != target)
1609 {
1610 fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
7695dab4 1611 return false;
9feb4b9e 1612 }
1613 }
7695dab4 1614 CTransaction &stakeTx = pblock->vtx[txn_count-1];
1615 CStakeParams sp;
1616 std::vector<CTxDestination> destinations;
1617 txnouttype outType;
1618 int nRequired;
1619 if (nonceOK &&
1620 ExtractDestinations(stakeTx.vout[0].scriptPubKey, outType, destinations, nRequired) &&
1621 destinations.size() &&
1622 ValidateStakeTransaction(stakeTx, sp, false) &&
1623 ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress))
9feb4b9e 1624 {
7695dab4 1625 isPOS = true;
1626
1627 // overwrite and set delegate if it is empty as the only destination we care about below
1628 // otherwise, use it as is
1629 if (sp.delegate.which() == COptCCParams::ADDRTYPE_INVALID)
1630 {
1631 sp.delegate = destinations[0];
1632 }
1633
1634 // normalize delegate to PKH if PK
1635 if (sp.delegate.which() == COptCCParams::ADDRTYPE_PK)
1636 {
1637 sp.delegate = CKeyID(GetDestinationID(sp.delegate));
1638 }
1639
1640 // if the source transaction is not spent to the same output as the stake transaction, error
1641 if ((destaddress.which() == COptCCParams::ADDRTYPE_PK ? CTxDestination(CKeyID(GetDestinationID(destaddress))) : destaddress) !=
1642 (destinations[0].which() == COptCCParams::ADDRTYPE_PK ? CTxDestination(CKeyID(GetDestinationID(destinations[0]))) : destinations[0]))
1643 {
1644 printf("ERROR: in staking block %s - source tx and stake have different scripts\n", blkHash.ToString().c_str());
1645 LogPrintf("ERROR: in staking block %s - source tx and stake have different scripts\n", blkHash.ToString().c_str());
1646 return false;
1647 }
1648
1649 if (extendedStake)
68b9a352 1650 {
7695dab4 1651 std::vector<CTxDestination> prevDests;
1652 std::map<CTxDestination, CCurrencyValueMap> cbOutputs;
1653 txnouttype cbType;
1654 int numRequired;
1655 uint160 reserveDepositCurrencyID;
1656 CCurrencyDefinition reserveDepositCurrency;
1657 std::map<uint160, int> reserveDepositReserves;
1658
1659 COptCCParams ccp;
1660 if (tx.vout[voutNum].scriptPubKey.IsPayToCryptoCondition(ccp) &&
1661 ccp.IsValid() &&
1662 ccp.evalCode == EVAL_RESERVE_DEPOSIT)
68b9a352 1663 {
2d8b9129 1664 printf("ERROR: in staking block %s - invalid reserve deposit stake\n", blkHash.ToString().c_str());
1665 LogPrintf("ERROR: in staking block %s - invalid reserve deposit stake\n", blkHash.ToString().c_str());
1666 return false;
7695dab4 1667 }
1668
1669 for (auto &oneOut : pblock->vtx[0].vout)
1670 {
1671 if (!supportInstantSpend ||
1672 !oneOut.scriptPubKey.IsInstantSpend())
1673 {
1674 std::vector<CTxDestination> oneOutDests;
1675 if (!ExtractDestinations(oneOut.scriptPubKey, cbType, oneOutDests, numRequired) ||
1676 numRequired > 1)
1677 {
1678 printf("ERROR: in staking block %s - invalid coinbase output\n", blkHash.ToString().c_str());
1679 LogPrintf("ERROR: in staking block %s - invalid coinbase output\n", blkHash.ToString().c_str());
1680 return false;
1681 }
477fd227 1682
7695dab4 1683 // make sure that we have no extraneous spenders and that all reward outputs
1684 // are either reserve transfers (TODO) or stakeguard outputs
1685 if (cbType == TX_CRYPTOCONDITION)
1686 {
1687 // first validate our destinations, if the output is reserve transfer,
1688 // the stake tx must be a reserve deposit to the same reserve currency,
1689 // or it is not valid
1690 // we validate a bit differently, otherwise, it must be a spendable output
1691 COptCCParams p;
1692 CCurrencyValueMap outVal = oneOut.scriptPubKey.ReserveOutValue(p);
1693 if (p.version >= p.VERSION_V3 &&
1694 (oneOut.scriptPubKey.IsSpendableOutputType() ||
1695 p.evalCode == EVAL_RESERVE_TRANSFER))
1696 {
1697 // we need to make sure we output only to delegate or back to the currency
1698 // TODO: enable currency contribution, now all goes to miner/staker
1699 // normalize destination to ID
1700 if (p.vKeys[0].which() == COptCCParams::ADDRTYPE_PK)
1701 {
1702 p.vKeys[0] = CKeyID(GetDestinationID(p.vKeys[0]));
1703 }
1704 if (p.m > 1 ||
1705 p.n > 1 ||
1706 p.vKeys[0] != sp.delegate)
1707 {
1708 printf("ERROR: in staking block %s - invalid coinbase destinations\n", blkHash.ToString().c_str());
1709 LogPrintf("ERROR: in staking block %s - invalid coinbase destinations\n", blkHash.ToString().c_str());
1710 return false;
1711 }
1712 }
1713 else
1714 {
1715 printf("ERROR: in staking block %s - invalid coinbase output type\n", blkHash.ToString().c_str());
1716 LogPrintf("ERROR: in staking block %s - invalid coinbase output type\n", blkHash.ToString().c_str());
1717 return false;
1718 }
1719 outVal.valueMap[ASSETCHAINS_CHAINID] += oneOut.nValue;
1720 cbOutputs[p.vKeys[0]] += outVal;
1721 }
1722 else
1723 {
1724 printf("ERROR: in staking block %s - invalid coinbase output type\n", blkHash.ToString().c_str());
1725 LogPrintf("ERROR: in staking block %s - invalid coinbase output type\n", blkHash.ToString().c_str());
1726 return false;
1727 }
1728 }
1729 }
1730 // now, we have all the currencies and amounts that are being sent to each destination
1731
1732 // rules for all non instant-spend coinbase outputs:
1733 // 1) Where the stake transaction spends a normal, "spendable" output, cb output must be to:
1734 // a) the same destination(s) as the output of the stake transaction, or
1735 // b) the specified delegate in the stake transaction
1736 // 2) Where the stake transaction spends a reserve deposit it is the same, except (TODO):
1737 // a) coinbase output must send all applicable reserve currency fees to currency reserve
1738 // deposits, if the currency is a reserve currency. For example, if the currency for which
1739 // the staker is staking a block uses BTC, ETH, USD, and VRSC as reserves, the staker/miner
1740 // keeps all block rewards and all fees, except the fees (block reward excluded) earned in
1741 // those 4 currencies. Those fees are put into reserve deposits for the currency for which
1742 // the staker earned the block.
1743 // 3) no other recipient than specified may be on the non-instant spend coinbase outputs
1744 }
1745 else if (CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) &&
1746 (destaddress.which() == COptCCParams::ADDRTYPE_PK ||
1747 destaddress.which() == COptCCParams::ADDRTYPE_PKH) &&
1748 (destinations[0].which() == COptCCParams::ADDRTYPE_PK ||
1749 destinations[0].which() == COptCCParams::ADDRTYPE_PKH) &&
1750 (cbaddress.which() == COptCCParams::ADDRTYPE_PK ||
1751 cbaddress.which() == COptCCParams::ADDRTYPE_PKH))
1752 {
1753 uint160 voutDestID = GetDestinationID(destinations[0]);
1754 uint160 destID = GetDestinationID(destaddress);
1755 uint160 cbDestID = GetDestinationID(cbaddress);
1756 if (newPOSEnforcement)
1757 {
1758 if (GetDestinationID(cbaddress) != GetDestinationID(destinations[0]))
68b9a352 1759 {
7695dab4 1760 // allow delegation of stake, but require all ouputs to be
1761 // crypto conditions
68b9a352 1762 // loop through all outputs to make sure they are sent to the proper pubkey
1763 isPOS = true;
1764 for (auto vout : pblock->vtx[0].vout)
1765 {
1766 txnouttype tp;
1767 std::vector<std::vector<unsigned char>> vvch = std::vector<std::vector<unsigned char>>();
e87527cf 1768 // solve all outputs to check that non-instantspend destinations all go only to the pk
68b9a352 1769 // specified in the stake params
ff466a91
MT
1770 if ((!supportInstantSpend || !vout.scriptPubKey.IsInstantSpend()) &&
1771 (!Solver(vout.scriptPubKey, tp, vvch) ||
68b9a352 1772 tp != TX_CRYPTOCONDITION ||
1773 vvch.size() < 2 ||
7695dab4 1774 sp.pk != CPubKey(vvch[0])))
68b9a352 1775 {
1776 isPOS = false;
1777 break;
1778 }
1779 }
1780 }
1781 }
7695dab4 1782 else if ( voutDestID == destID && ( destID == cbDestID || (height < 17840)) )
1783 {
1784 isPOS = true;
1785 }
1786 else
1787 {
1788 fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n", blkHash.ToString().c_str());
1789 }
9feb4b9e 1790 }
1791 }
1f722359
MT
1792 }
1793 }
1794 }
c68ca1a2 1795 else
1796 {
1797 printf("ERROR: malformed nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
1798 pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
1799 }
1f722359 1800 }
1f722359
MT
1801 }
1802 }
1803 }
7695dab4 1804 return isPOS;
1f722359
MT
1805}
1806
fb6bb4e8 1807int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
1808{
1809 int64_t checktoshis=0; uint8_t *script;
1810 if ( ASSETCHAINS_COMMISSION != 0 )
1811 {
1812 checktoshis = komodo_commission(pblock);
1813 if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
1814 return(-1);
1815 else if ( checktoshis != 0 )
1816 {
9feb4b9e 1817 script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
fb6bb4e8 1818 if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
1819 return(-1);
1820 if ( pblock->vtx[0].vout[1].nValue != checktoshis )
1821 {
1822 fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));
1823 return(-1);
1824 }
1825 }
1826 }
1827 return(checktoshis);
1828}
1829
3fdb3782
SS
1830bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
1831
18443f69 1832int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
1833{
9464ac21 1834 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 1835 if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
1836 KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
88d014d0 1837 if ( !CheckEquihashSolution(pblock, Params().GetConsensus()) )
18443f69 1838 {
1839 fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height);
c17dbdee 1840 return -1;
18443f69 1841 }
ec5b59fd 1842 hash = pblock->GetHash();
9464ac21 1843 bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow);
1844 bhash = UintToArith256(hash);
1845 possible = komodo_block2pubkey33(pubkey33,pblock);
28b18b61 1846 if ( height == 0 )
f1b57a6e 1847 {
28b18b61 1848 if ( slowflag != 0 )
b088fa97 1849 {
1850 fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget);
c17dbdee 1851 return 0;
b088fa97 1852 }
d565e7b7 1853 BlockMap::const_iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
1854 if ( it != mapBlockIndex.end() && (pprev= it->second) != 0 )
4b729ec5 1855 height = pprev->GetHeight() + 1;
28b18b61 1856 if ( height == 0 )
c17dbdee 1857 return 0;
1f722359 1858 }
c17dbdee 1859
1860 if (ASSETCHAINS_LWMAPOS != 0 && pblock->IsVerusPOSBlock())
18443f69 1861 {
c17dbdee 1862 return 0;
18443f69 1863 }
c17dbdee 1864 else if (bhash <= bnTarget)
18443f69 1865 {
599d8437 1866 // tolerate variable size solutions, but ensure that we have at least 16 bytes extra space to fit the clhash at the end
1867 int modSpace = GetSerializeSize(*(CBlockHeader *)pblock, SER_NETWORK, PROTOCOL_VERSION) % 32;
f37d48ca 1868 int solutionVer = CConstVerusSolutionVector::GetVersionByHeight(height);
1869 if (solutionVer < CActivationHeight::ACTIVATE_VERUSHASH2_1 || (modSpace >= 1 && modSpace <= 16))
18443f69 1870 {
c17dbdee 1871 return 0;
b088fa97 1872 }
c17dbdee 1873 else
b088fa97 1874 {
599d8437 1875 printf("Block header size modulo 32 must be > 1 and <= 16 for PoW blocks\n");
b088fa97 1876 }
18443f69 1877 }
c17dbdee 1878 else
18443f69 1879 {
c17dbdee 1880 printf("Insufficient hash result and not PoS block\n");
18443f69 1881 }
c17dbdee 1882
1883 return -1;
18443f69 1884}
1885
adbc38d0 1886bool IsCoinbaseTimeLocked(const CTransaction &tx, uint32_t &outUnlockHeight);
1887
1888void GetImmatureCoins(std::map<uint32_t, int64_t> *pimmatureBlockAmounts, CBlock &block, uint32_t &maturity, int64_t &amount, uint32_t height)
1889{
1890 std::map<uint32_t, int64_t> _unlockBlockAmounts;
1891 std::map<uint32_t, int64_t> &unlockBlockAmounts = pimmatureBlockAmounts ? *pimmatureBlockAmounts : _unlockBlockAmounts;
1892 amount = 0;
1893
5bc6b8a3 1894 // PBaaS chains release block one outputs without maturity, since the entire chain is either
1895 // valid or not
1896 if (block.vtx.size() && IsVerusActive() || height != 1)
adbc38d0 1897 {
1898 const CTransaction &tx = block.vtx[0];
1899 uint32_t unlockHeight = 0;
1900 if (IsCoinbaseTimeLocked(tx, unlockHeight) && unlockHeight > (height + COINBASE_MATURITY))
1901 {
1902 maturity = unlockHeight;
1903 }
1904 else
1905 {
1906 maturity = height + COINBASE_MATURITY;
1907 }
1908 for (auto &out : tx.vout)
1909 {
1910 if (!out.scriptPubKey.IsInstantSpend())
1911 {
1912 amount += out.nValue;
1913 }
1914 }
1915 unlockBlockAmounts[maturity] += amount;
1916 }
1917}
1918
1919bool GetNewCoins(int64_t &newCoins, int64_t *pzsupplydelta, std::map<uint32_t, int64_t> *pimmatureBlockAmounts, CBlock &block, uint32_t &maturity, int64_t &amount, uint32_t height)
1920{
1921 int64_t _zfunds;
1922 int64_t &zfunds = pzsupplydelta ? *pzsupplydelta : _zfunds;
1923 std::map<uint32_t, int64_t> _unlockBlockAmounts;
1924 std::map<uint32_t, int64_t> &unlockBlockAmounts = pimmatureBlockAmounts ? *pimmatureBlockAmounts : _unlockBlockAmounts;
1925
1926 for (auto &tx : block.vtx)
1927 {
1928 if (tx.IsCoinBase())
1929 {
1930 for (auto &out : tx.vout)
1931 {
1932 newCoins += out.nValue;
1933 }
1934 GetImmatureCoins(&unlockBlockAmounts, block, maturity, amount, height);
1935 }
1936 else
1937 {
1938 int64_t vinSum = 0, voutSum = 0;
1939 CTransaction vinTx;
1940 uint256 blockHash;
1941
1942 for (auto &in : tx.vin)
1943 {
1944 if ( !GetTransaction(in.prevout.hash, vinTx, blockHash, false) || in.prevout.n >= vinTx.vout.size() )
1945 {
1946 fprintf(stderr,"ERROR: %s/v%d cant find\n", in.prevout.hash.ToString().c_str(), in.prevout.n);
1947 return false;
1948 }
1949 vinSum += vinTx.vout[in.prevout.n].nValue;
1950 }
1951 for (auto &out : tx.vout)
1952 {
1953 if ( !out.scriptPubKey.IsOpReturn() )
1954 {
1955 voutSum += out.nValue;
1956 }
1957 }
1958 // this should be a negative number due to fees, which will mature when the coinbase does
1959 // all normal blocks should have negative coin emission due to maturity only
1960 // resolving the pmatureBlockAmounts map is required for an accurate mature and immature supply
1961 newCoins += voutSum - vinSum;
1962 }
1963 }
1964
1965 zfunds += (chainActive[height]->nSproutValue ? chainActive[height]->nSproutValue.get() : 0) + chainActive[height]->nSaplingValue;
1966
1967 return true;
1968}
1969
26189509 1970int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
7e282415 1971{
84eabd0d 1972 CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
7e282415 1973 n = pblock->vtx.size();
1974 for (i=0; i<n; i++)
1975 {
adbc38d0 1976 CTransaction vintx, &tx = pblock->vtx[i];
9657f334 1977 zfunds += (tx.GetShieldedValueOut() - tx.GetShieldedValueIn());
7e282415 1978 if ( (m= tx.vin.size()) > 0 )
1979 {
1980 for (j=0; j<m; j++)
1981 {
1982 if ( i == 0 )
1983 continue;
1984 txid = tx.vin[j].prevout.hash;
1985 vout = tx.vin[j].prevout.n;
1986 if ( !GetTransaction(txid,vintx,hashBlock, false) || vout >= vintx.vout.size() )
1987 {
1988 fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout);
1989 return(0);
1990 }
1991 vinsum += vintx.vout[vout].nValue;
1992 }
1993 }
1994 if ( (m= tx.vout.size()) > 0 )
1995 {
1996 for (j=0; j<m-1; j++)
84eabd0d 1997 {
1998 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
1999 voutsum += tx.vout[j].nValue;
27d76b74 2000 else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
84eabd0d 2001 }
9feb4b9e 2002 script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
7e282415 2003 if ( script == 0 || script[0] != 0x6a )
84eabd0d 2004 {
2005 if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
2006 voutsum += tx.vout[j].nValue;
2007 }
7e282415 2008 }
2009 }
26189509 2010 *zfundsp = zfunds;
7130a7cd 2011 if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times
1ec2a42f 2012 return(3 * SATOSHIDEN);
aa51eef6 2013 //if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 )
2014 //. fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds));
7e282415 2015 return(voutsum - vinsum);
2016}
2017
26189509 2018int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height)
7e282415 2019{
26189509 2020 CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0;
67459d80 2021 //fprintf(stderr,"coinsupply %d\n",height);
26189509 2022 *zfundsp = 0;
7e282415 2023 if ( (pindex= komodo_chainactive(height)) != 0 )
2024 {
4b729ec5 2025 while ( pindex != 0 && pindex->GetHeight() > 0 )
9f60c7ec 2026 {
7130a7cd 2027 if ( pindex->newcoins == 0 && pindex->zfunds == 0 )
97a4e923 2028 {
2029 if ( komodo_blockload(block,pindex) == 0 )
4b729ec5 2030 pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->GetHeight(),&block);
df74ee5f 2031 else
2032 {
4b729ec5 2033 fprintf(stderr,"error loading block.%d\n",pindex->GetHeight());
df74ee5f 2034 return(0);
2035 }
97a4e923 2036 }
2037 supply += pindex->newcoins;
26189509 2038 zfunds += pindex->zfunds;
4b729ec5 2039 //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 2040 pindex = pindex->pprev;
9f60c7ec 2041 }
7e282415 2042 }
26189509 2043 *zfundsp = zfunds;
7e282415 2044 return(supply);
2045}
adbc38d0 2046
2047bool GetCoinSupply(int64_t &transparentSupply, int64_t *pzsupply, int64_t *pimmaturesupply, uint32_t height)
2048{
2049 int64_t _immature = 0, _zsupply = 0;
2050 int64_t &immature = pimmaturesupply ? *pimmaturesupply : _immature;
2051 int64_t &zfunds = pzsupply ? *pzsupply : _zsupply;
2052
2053 // keep a running map of immature coin amounts and block maturity as we move forward on the block chain
2054 std::map<uint32_t, int64_t> immatureBlockAmounts;
2055
2056 if (height > chainActive.Height())
2057 {
2058 height = chainActive.Height();
2059 }
2060
2061 for (int curHeight = 1; curHeight <= height; curHeight++)
2062 {
2063 CBlockIndex *pIndex;
2064 CBlock block;
423e30fd 2065 LOCK(cs_main);
adbc38d0 2066 if ( (pIndex = komodo_chainactive(curHeight)) != 0 )
2067 {
2068 if ( pIndex->newcoins == 0 && pIndex->zfunds == 0 )
2069 {
2070 if ( !komodo_blockload(block, pIndex) == 0 || !GetNewCoins(pIndex->newcoins, &pIndex->zfunds, &immatureBlockAmounts, block, pIndex->maturity, pIndex->immature, curHeight) )
2071 {
2072 fprintf(stderr,"error loading block.%d\n", pIndex->GetHeight());
2073 return false;
2074 }
2075 }
2076 else
2077 {
2078 if (pIndex->maturity)
2079 {
2080 if (immatureBlockAmounts.count(pIndex->maturity))
2081 {
2082 immatureBlockAmounts[pIndex->maturity] += pIndex->immature;
2083 }
2084 else
2085 {
2086 immatureBlockAmounts[pIndex->maturity] = pIndex->immature;
2087 }
2088 }
2089 }
2090
2091 transparentSupply += pIndex->newcoins;
2092 zfunds += pIndex->zfunds;
2093 }
2094 }
2095
2096 // remove coins that matured this block from the map to prevent double counting
2097 auto lastIt = immatureBlockAmounts.upper_bound(height);
2098 immatureBlockAmounts.erase(immatureBlockAmounts.begin(), lastIt);
2099 for (auto &lockedAmount : immatureBlockAmounts)
2100 {
2101 immature += lockedAmount.second;
2102 }
2103
2104 return true;
2105}
This page took 0.808802 seconds and 4 git commands to generate.