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