]> Git Repo - VerusCoin.git/blob - src/komodo_bitcoind.h
test
[VerusCoin.git] / src / komodo_bitcoind.h
1 /******************************************************************************
2  * Copyright © 2014-2017 The SuperNET Developers.                             *
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
16 // komodo functions that interact with bitcoind C++
17
18 #ifdef _WIN32
19 #include <curl.h>
20 #include <easy.h>
21 #else
22 #include <curl/curl.h>
23 #include <curl/easy.h>
24 #endif
25
26 #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
27
28 struct MemoryStruct { char *memory; size_t size; };
29 struct return_string { char *ptr; size_t len; };
30
31 // return data from the server
32 #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
33 #define CURL_GLOBAL_SSL (1<<0)
34 #define CURL_GLOBAL_WIN32 (1<<1)
35
36
37 /************************************************************************
38  *
39  * Initialize the string handler so that it is thread safe
40  *
41  ************************************************************************/
42
43 void init_string(struct return_string *s)
44 {
45     s->len = 0;
46     s->ptr = (char *)calloc(1,s->len+1);
47     if ( s->ptr == NULL )
48     {
49         fprintf(stderr,"init_string malloc() failed\n");
50         exit(-1);
51     }
52     s->ptr[0] = '\0';
53 }
54
55 /************************************************************************
56  *
57  * Use the "writer" to accumulate text until done
58  *
59  ************************************************************************/
60
61 size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s)
62 {
63     size_t new_len = s->len + size*nmemb;
64     s->ptr = (char *)realloc(s->ptr,new_len+1);
65     if ( s->ptr == NULL )
66     {
67         fprintf(stderr, "accumulate realloc() failed\n");
68         exit(-1);
69     }
70     memcpy(s->ptr+s->len,ptr,size*nmemb);
71     s->ptr[new_len] = '\0';
72     s->len = new_len;
73     return(size * nmemb);
74 }
75
76 /************************************************************************
77  *
78  * return the current system time in milliseconds
79  *
80  ************************************************************************/
81
82 #define EXTRACT_BITCOIND_RESULT  // if defined, ensures error is null and returns the "result" field
83 #ifdef EXTRACT_BITCOIND_RESULT
84
85 /************************************************************************
86  *
87  * perform post processing of the results
88  *
89  ************************************************************************/
90
91 char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params)
92 {
93     long i,j,len; char *retstr = 0; cJSON *json,*result,*error;
94     //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
95     if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 )
96     {
97         if ( strcmp(command,"signrawtransaction") != 0 )
98             printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
99         return(rpcstr);
100     }
101     json = cJSON_Parse(rpcstr);
102     if ( json == 0 )
103     {
104         printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params);
105         free(rpcstr);
106         return(0);
107     }
108     result = cJSON_GetObjectItem(json,"result");
109     error = cJSON_GetObjectItem(json,"error");
110     if ( error != 0 && result != 0 )
111     {
112         if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL )
113         {
114             retstr = cJSON_Print(result);
115             len = strlen(retstr);
116             if ( retstr[0] == '"' && retstr[len-1] == '"' )
117             {
118                 for (i=1,j=0; i<len-1; i++,j++)
119                     retstr[j] = retstr[i];
120                 retstr[j] = 0;
121             }
122         }
123         else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL )
124         {
125             if ( strcmp(command,"signrawtransaction") != 0 )
126                 printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr);
127         }
128         free(rpcstr);
129     } else retstr = rpcstr;
130     free_json(json);
131     //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr);
132     return(retstr);
133 }
134 #endif
135
136 /************************************************************************
137  *
138  * perform the query
139  *
140  ************************************************************************/
141
142 char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params)
143 {
144     static int didinit,count,count2; static double elapsedsum,elapsedsum2;
145     struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle;
146     char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime;
147     if ( didinit == 0 )
148     {
149         didinit = 1;
150         curl_global_init(CURL_GLOBAL_ALL); //init the curl session
151     }
152     numretries = 0;
153     if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") ==  0 )
154         specialcase = 1;
155     else specialcase = 0;
156     if ( url[0] == 0 )
157         strcpy(url,"http://127.0.0.1:7876/nxt");
158     if ( specialcase != 0 && 0 )
159         printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params);
160 try_again:
161     if ( retstrp != 0 )
162         *retstrp = 0;
163     starttime = OS_milliseconds();
164     curl_handle = curl_easy_init();
165     init_string(&s);
166     headers = curl_slist_append(0,"Expect:");
167     
168         curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
169     curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER,    headers);
170     curl_easy_setopt(curl_handle,CURLOPT_URL,           url);
171     curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes);               // send all data to this function
172     curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA,             &s);                    // we pass our 's' struct to the callback
173     curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL,              1L);                    // supposed to fix "Alarm clock" and long jump crash
174         curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS,        1L);                    // no progress callback
175     if ( strncmp(url,"https",5) == 0 )
176     {
177         curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0);
178         curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0);
179     }
180     if ( userpass != 0 )
181         curl_easy_setopt(curl_handle,CURLOPT_USERPWD,   userpass);
182     databuf = 0;
183     if ( params != 0 )
184     {
185         if ( command != 0 && specialcase == 0 )
186         {
187             len = strlen(params);
188             if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) {
189                 bracket0 = bracket1 = (char *)"";
190             }
191             else
192             {
193                 bracket0 = (char *)"[";
194                 bracket1 = (char *)"]";
195             }
196             
197             databuf = (char *)malloc(256 + strlen(command) + strlen(params));
198             sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1);
199             //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf);
200             //
201         } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params);
202         curl_easy_setopt(curl_handle,CURLOPT_POST,1L);
203         if ( databuf != 0 )
204             curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf);
205         else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params);
206     }
207     //laststart = milliseconds();
208     res = curl_easy_perform(curl_handle);
209     curl_slist_free_all(headers);
210     curl_easy_cleanup(curl_handle);
211     if ( databuf != 0 ) // clean up temporary buffer
212     {
213         free(databuf);
214         databuf = 0;
215     }
216     if ( res != CURLE_OK )
217     {
218         numretries++;
219         if ( specialcase != 0 )
220         {
221             printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res);
222             free(s.ptr);
223             return(0);
224         }
225         else if ( numretries >= 1 )
226         {
227             //printf("Maximum number of retries exceeded!\n");
228             free(s.ptr);
229             return(0);
230         }
231         if ( (rand() % 1000) == 0 )
232             printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries);
233         free(s.ptr);
234         sleep((1<<numretries));
235         goto try_again;
236         
237     }
238     else
239     {
240         if ( command != 0 && specialcase == 0 )
241         {
242             count++;
243             elapsedsum += (OS_milliseconds() - starttime);
244             if ( (count % 1000000) == 0)
245                 printf("%d: ave %9.6f | elapsed %.3f millis | bitcoind_RPC.(%s) url.(%s)\n",count,elapsedsum/count,(OS_milliseconds() - starttime),command,url);
246             if ( retstrp != 0 )
247             {
248                 *retstrp = s.ptr;
249                 return(s.ptr);
250             }
251             return(post_process_bitcoind_RPC(debugstr,command,s.ptr,params));
252         }
253         else
254         {
255             if ( 0 && specialcase != 0 )
256                 fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: BTCD.(%s) -> (%s)\n",params,s.ptr);
257             count2++;
258             elapsedsum2 += (OS_milliseconds() - starttime);
259             if ( (count2 % 10000) == 0)
260                 printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command);
261             return(s.ptr);
262         }
263     }
264     printf("bitcoind_RPC: impossible case\n");
265     free(s.ptr);
266     return(0);
267 }
268
269 static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data)
270 {
271     size_t realsize = (size * nmemb);
272     struct MemoryStruct *mem = (struct MemoryStruct *)data;
273     mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1));
274     if ( mem->memory != 0 )
275     {
276         if ( ptr != 0 )
277             memcpy(&(mem->memory[mem->size]),ptr,realsize);
278         mem->size += realsize;
279         mem->memory[mem->size] = 0;
280     }
281     //printf("got %d bytes\n",(int32_t)(size*nmemb));
282     return(realsize);
283 }
284
285 char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3)
286 {
287     struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
288     if ( (cHandle= *cHandlep) == NULL )
289                 *cHandlep = cHandle = curl_easy_init();
290     else curl_easy_reset(cHandle);
291     //#ifdef DEBUG
292         //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
293     //#endif
294         curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
295         curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0);
296         //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
297         curl_easy_setopt(cHandle,CURLOPT_URL,url);
298         curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
299     if ( userpass != 0 && userpass[0] != 0 )
300         curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
301         if ( postfields != 0 && postfields[0] != 0 )
302     {
303         curl_easy_setopt(cHandle,CURLOPT_POST,1);
304                 curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
305     }
306     if ( hdr0 != NULL && hdr0[0] != 0 )
307     {
308         //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:"");
309         headers = curl_slist_append(headers,hdr0);
310         if ( hdr1 != 0 && hdr1[0] != 0 )
311             headers = curl_slist_append(headers,hdr1);
312         if ( hdr2 != 0 && hdr2[0] != 0 )
313             headers = curl_slist_append(headers,hdr2);
314         if ( hdr3 != 0 && hdr3[0] != 0 )
315             headers = curl_slist_append(headers,hdr3);
316     } //headers = curl_slist_append(0,"Expect:");
317     if ( headers != 0 )
318         curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers);
319     //res = curl_easy_perform(cHandle);
320     memset(&chunk,0,sizeof(chunk));
321     curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback);
322     curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk);
323     curl_easy_perform(cHandle);
324     curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code);
325     if ( headers != 0 )
326         curl_slist_free_all(headers);
327     if ( code != 200 )
328         printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory);
329     return(chunk.memory);
330 }
331
332 char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
333 {
334     //static void *cHandle;
335     char url[512],*retstr=0,*retstr2=0,postdata[8192];
336     if ( params == 0 || params[0] == 0 )
337         params = (char *)"[]";
338     if ( strlen(params) < sizeof(postdata)-128 )
339     {
340         sprintf(url,(char *)"http://127.0.0.1:%u",port);
341         sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params);
342         //printf("postdata.(%s) USERPASS.(%s)\n",postdata,KMDUSERPASS);
343         retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params);
344         //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0);
345     }
346     return(retstr2);
347 }
348
349 int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH)
350 {
351     int32_t i; uint256 hash; char params[256];
352     for (i=0; i<32; i++)
353         ((uint8_t *)&hash)[i] = script[2+i];
354     if ( hash == NOTARIZED_HASH )
355         return(0);
356     for (i=0; i<32; i++)
357         printf("%02x",((uint8_t *)&NOTARIZED_HASH)[i]);
358     printf(" notarized, ");
359     for (i=0; i<32; i++)
360         printf("%02x",((uint8_t *)&hash)[i]);
361     printf(" opreturn from [%s] ht.%d\n",ASSETCHAINS_SYMBOL,height);
362     return(-1);
363 }
364
365 int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
366 {
367     char params[256],*jsonstr,*hexstr; uint8_t script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
368     /*params[0] = '[';
369     params[1] = '"';
370     for (i=0; i<32; i++)
371         sprintf(&params[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
372     strcat(params,"\", 1]");*/
373     sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
374     if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 )
375         return(0);
376     //printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",ASSETCHAINS_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT);
377     if ( strcmp(dest,"KMD") == 0 )
378     {
379         if ( KMDUSERPASS[0] != 0 )
380             jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,7771);
381         //else jsonstr = _dex_getrawtransaction();
382         else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok
383     }
384     else if ( strcmp(dest,"BTC") == 0 )
385     {
386         if ( BTCUSERPASS[0] != 0 )
387         {
388             //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS);
389             jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332);
390         }
391         //else jsonstr = _dex_getrawtransaction();
392         else return(0);
393     }
394     else
395     {
396         printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest);
397         return(-1);
398     }
399     if ( jsonstr != 0 )
400     {
401         if ( (json= cJSON_Parse(jsonstr)) != 0 )
402         {
403             if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 )
404             {
405                 vout = jitem(vouts,n-1);
406                 //printf("vout.(%s)\n",jprint(vout,0));
407                 if ( (skey= jobj(vout,(char *)"scriptPubKey")) != 0 )
408                 {
409                     if ( (hexstr= jstr(skey,(char *)"hex")) != 0 )
410                     {
411                         //printf("HEX.(%s)\n",hexstr);
412                         len = strlen(hexstr) >> 1;
413                         decode_hex(script,len,hexstr);
414                         retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH);
415                     }
416                 }
417             }
418             free_json(txjson);
419         }
420         free(jsonstr);
421     }
422     return(retval);
423 }
424
425 uint256 komodo_getblockhash(int32_t height)
426 {
427     uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32];
428     memset(&hash,0,sizeof(hash));
429     sprintf(params,"[%d]",height);
430     if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,7771)) != 0 )
431     {
432         if ( (result= cJSON_Parse(jsonstr)) != 0 )
433         {
434             if ( (hexstr= jstr(result,(char *)"result")) != 0 )
435             {
436                 if ( is_hexstr(hexstr,0) == 64 )
437                 {
438                     decode_hex(revbuf,32,hexstr);
439                     for (i=0; i<32; i++)
440                         ((uint8_t *)&hash)[i] = revbuf[31-i];
441                 }
442             }
443             free_json(result);
444         }
445         printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash);
446         free(jsonstr);
447     }
448     return(hash);
449 }
450
451 uint256 _komodo_getblockhash(int32_t height);
452
453 uint64_t komodo_seed(int32_t height)
454 {
455     uint64_t seed = 0;
456     if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds...
457     {
458         uint256 hash,zero; CBlockIndex *pindex;
459         memset(&hash,0,sizeof(hash));
460         memset(&zero,0,sizeof(zero));
461         if ( height > 10 )
462             height -= 10;
463         if ( ASSETCHAINS_SYMBOL[0] == 0 )
464             hash = _komodo_getblockhash(height);
465         if ( memcmp(&hash,&zero,sizeof(hash)) == 0 )
466             hash = komodo_getblockhash(height);
467         int32_t i;
468         for (i=0; i<32; i++)
469             printf("%02x",((uint8_t *)&hash)[i]);
470         printf(" seed.%d\n",height);
471         seed = arith_uint256(hash.GetHex()).GetLow64();
472     }
473     else
474     {
475         seed = (height << 13) ^ (height << 2);
476         seed <<= 21;
477         seed |= (height & 0xffffffff);
478         seed ^= (seed << 17) ^ (seed << 1);
479     }
480     return(seed);
481 }
482
483 uint32_t komodo_txtime(uint256 hash)
484 {
485     CTransaction tx;
486     uint256 hashBlock;
487     if (!GetTransaction(hash, tx,
488 #ifndef KOMODO_ZCASH
489                         Params().GetConsensus(),
490 #endif
491                         hashBlock, true))
492     {
493         //printf("null GetTransaction\n");
494         return(tx.nLockTime);
495     }
496     return(0);
497 }
498
499 void komodo_disconnect(CBlockIndex *pindex,CBlock& block)
500 {
501     char symbol[16],dest[16]; struct komodo_state *sp;
502     komodo_init(pindex->nHeight);
503     if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
504     {
505         //sp->rewinding = pindex->nHeight;
506         //fprintf(stderr,"-%d ",pindex->nHeight);
507     } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->nHeight,ASSETCHAINS_SYMBOL);
508 }
509
510
511 int32_t komodo_is_notarytx(const CTransaction& tx)
512 {
513     uint8_t *ptr,crypto777[33];
514     if ( tx.vout.size() > 0 )
515     {
516 #ifdef KOMODO_ZCASH
517         ptr = (uint8_t *)tx.vout[0].scriptPubKey.data();
518 #else
519         ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0];
520 #endif
521         if ( ptr != 0 )
522         {
523             decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
524             if ( memcmp(ptr+1,crypto777,33) == 0 )
525             {
526                 //printf("found notarytx\n");
527                 return(1);
528             }
529         }
530     }
531     return(0);
532 }
533
534 int32_t komodo_block2height(CBlock *block)
535 {
536     int32_t i,n,height = 0; uint8_t *ptr;
537     if ( block->vtx[0].vin.size() > 0 )
538     {
539 #ifdef KOMODO_ZCASH
540         ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data();
541 #else
542         ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
543 #endif
544         if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
545         {
546             //for (i=0; i<6; i++)
547             //    printf("%02x",ptr[i]);
548             n = ptr[0];
549             for (i=0; i<n; i++)
550             {
551                 //03bb81000101(bb 187) (81 48001) (00 12288256)  <- coinbase.6 ht.12288256
552                 height += ((uint32_t)ptr[i+1] << (i*8));
553                 //printf("(%02x %x %d) ",ptr[i+1],((uint32_t)ptr[i+1] << (i*8)),height);
554             }
555             //printf(" <- coinbase.%d ht.%d\n",(int32_t)block->vtx[0].vin[0].scriptSig.size(),height);
556         }
557         //komodo_init(height);
558     }
559     return(height);
560 }
561
562 void komodo_block2pubkey33(uint8_t *pubkey33,CBlock& block)
563 {
564     int32_t n;
565     memset(pubkey33,0,33);
566     if ( block->vtx[0].vout.size() > 0 )
567     {
568 #ifdef KOMODO_ZCASH
569         uint8_t *ptr = (uint8_t *)block.vtx[0].vout[0].scriptPubKey.data();
570 #else
571         uint8_t *ptr = (uint8_t *)&block.vtx[0].vout[0].scriptPubKey[0];
572 #endif
573         //komodo_init(0);
574         n = block.vtx[0].vout[0].scriptPubKey.size();
575         if ( n == 35 )
576             memcpy(pubkey33,ptr+1,33);
577     }
578 }
579
580 int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex)
581 {
582     block.SetNull();
583     // Open history file to read
584     CAutoFile filein(OpenBlockFile(pindex->GetBlockPos(),true),SER_DISK,CLIENT_VERSION);
585     if (filein.IsNull())
586         return(-1);
587     // Read block
588     try { filein >> block; }
589     catch (const std::exception& e)
590     {
591         fprintf(stderr,"readblockfromdisk err B\n");
592         return(-1);
593     }
594     return(0);
595 }
596
597 void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
598 {
599     CBlock block;
600     //komodo_init(height);
601     memset(pubkey33,0,33);
602     if ( pindex != 0 )
603     {
604         if ( komodo_blockload(block,pindex) == 0 )
605             komodo_block2pubkey33(pubkey33,block);
606     }
607     else
608     {
609         // height -> pubkey33
610         //printf("extending chaintip komodo_index2pubkey33 height.%d need to get pubkey33\n",height);
611     }
612 }
613
614 void komodo_connectpindex(CBlockIndex *pindex)
615 {
616     CBlock block;
617     if ( komodo_blockload(block,pindex) == 0 )
618         komodo_connectblock(pindex,block);
619 }
620
621 CBlockIndex *komodo_chainactive(int32_t height)
622 {
623     return(chainActive[height]);
624 }
625
626 int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height);
627 int32_t komodo_electednotary(uint8_t *pubkey33,int32_t height);
628
629 int8_t komodo_minerid(int32_t height,uint8_t *pubkey33)
630 {
631     int32_t num,i; CBlockIndex *pindex; uint8_t _pubkey33[33],pubkeys[64][33];
632     if ( pubkey33 == 0 && (pindex= chainActive[height]) != 0 )
633     {
634         if ( pubkey33 == 0 )
635         {
636             pubkey33 = _pubkey33;
637             komodo_index2pubkey33(pubkey33,pindex,height);
638         }
639         if ( (num= komodo_notaries(pubkeys,height)) > 0 )
640         {
641             for (i=0; i<num; i++)
642                 if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
643                     return(i);
644         }
645     }
646     return(komodo_electednotary(pubkey33,height));
647 }
648
649 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *nonzpkeysp,int32_t height)
650 {
651     int32_t i,j,duplicate; CBlockIndex *pindex; uint8_t pubkey33[33];
652     memset(mids,-1,sizeof(*mids)*66);
653     for (i=duplicate=0; i<66; i++)
654     {
655         if ( (pindex= komodo_chainactive(height-i)) != 0 )
656         {
657             komodo_index2pubkey33(pubkey33,pindex,height-i);
658             for (j=0; j<33; j++)
659                 pubkeys[i][j] = pubkey33[j];
660             if ( (mids[i]= komodo_minerid(height-i,pubkey33)) >= 0 )
661             {
662                 //mids[i] = *(int32_t *)pubkey33;
663                 (*nonzpkeysp)++;
664             }
665             if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
666                 duplicate++;
667         }
668     }
669     if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) )
670         return(1);
671     else return(0);
672 }
673
674 int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
675 {
676     int32_t i,n=0;
677     for (i=0; i<width; i++,n++)
678     {
679         if ( height-i <= 0 )
680             break;
681         minerids[i] = komodo_minerid(height - i,0);
682     }
683     return(n);
684 }
685
686 int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33])
687 {
688     int32_t i,notaryid,minerid,limit; uint8_t _pubkey33[33];
689     if ( height >= 34000 && notaryid >= 0 )
690     {
691         if ( height < 79693 )
692             limit = 64;
693         else if ( height < 82000 )
694             limit = 8;
695         else limit = 66;
696         for (i=1; i<limit; i++)
697         {
698             komodo_chosennotary(&notaryid,height-i,_pubkey33);
699             if ( komodo_minerid(height-i,_pubkey33) == notaryid )
700             {
701                 //fprintf(stderr,"ht.%d notaryid.%d already mined -i.%d\n",height,notaryid,i);
702                 return(-1);
703             }
704         }
705         //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit);
706         return(1);
707     }
708     return(0);
709 }
710
711 int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
712 {
713     int32_t notarized_height; uint256 notarized_hash,notarized_desttxid; CBlockIndex *notary; CBlockIndex *pindex;
714     if ( (pindex= chainActive.Tip()) == 0 )
715         return(-1);
716     notarized_height = komodo_notarizeddata(pindex->nHeight,&notarized_hash,&notarized_desttxid);
717     *notarized_heightp = notarized_height;
718     if ( notarized_height >= 0 && notarized_height <= pindex->nHeight && (notary= mapBlockIndex[notarized_hash]) != 0 )
719     {
720         //printf("nHeight.%d -> (%d %s)\n",pindex->Tip()->nHeight,notarized_height,notarized_hash.ToString().c_str());
721         if ( notary->nHeight == notarized_height ) // if notarized_hash not in chain, reorg
722         {
723             if ( nHeight < notarized_height )
724             {
725                 fprintf(stderr,"nHeight.%d < NOTARIZED_HEIGHT.%d\n",nHeight,notarized_height);
726                 return(-1);
727             }
728             else if ( nHeight == notarized_height && memcmp(&hash,&notarized_hash,sizeof(hash)) != 0 )
729             {
730                 fprintf(stderr,"nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",nHeight,notarized_height);
731                 return(-1);
732             }
733         } else fprintf(stderr,"unexpected error notary_hash %s ht.%d at ht.%d\n",notarized_hash.ToString().c_str(),notarized_height,notary->nHeight);
734     } else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
735         fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight);
736     return(0);
737 }
738
739 uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
740 {
741     LOCK(cs_main);
742     CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
743     if ( !GetTransaction(hash,tx,hashBlock,true) )
744         return(0);
745     uint32_t locktime = 0;
746     if ( n < tx.vout.size() )
747     {
748         if ( (pindex= mapBlockIndex[hashBlock]) != 0 && (tipindex= chainActive.Tip()) != 0 )
749         {
750             *valuep = tx.vout[n].nValue;
751             *txheightp = pindex->nHeight;
752             *tiptimep = tipindex->nTime;
753             locktime = tx.nLockTime;
754             //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
755         }
756     }
757     return(locktime);
758 }
759
760 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
761 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue)
762 {
763     uint64_t value; uint32_t tiptime;
764     if ( (*locktimep= komodo_interest_args(txheightp,&tiptime,&value,hash,n)) != 0 )
765     {
766         if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
767             return(komodo_interest(*txheightp,value,*locktimep,tiptime));
768         //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);
769         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);
770     }
771     return(0);
772 }
773
774 int32_t komodo_isrealtime(int32_t *kmdheightp)
775 {
776     struct komodo_state *sp; CBlockIndex *pindex;
777     if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 )
778         *kmdheightp = sp->CURRENT_HEIGHT;
779     else *kmdheightp = 0;
780     if ( (pindex= chainActive.Tip()) != 0 && pindex->nHeight == (int32_t)komodo_longestchain() )
781         return(1);
782     else return(0);
783 }
This page took 0.066274 seconds and 4 git commands to generate.