d019c447 |
1 | /****************************************************************************** |
37fed603 |
2 | * Copyright © 2014-2017 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 |
19 | #include <curl.h> |
20 | #include <easy.h> |
21 | #else |
22 | #include <curl/curl.h> |
23 | #include <curl/easy.h> |
24 | #endif |
25 | |
fba6038c |
26 | #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr)) |
77be6cd9 |
27 | |
9b0e1808 |
28 | struct MemoryStruct { char *memory; size_t size; }; |
c2b50ce0 |
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 | |
4ec67e74 |
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 | } |
c2b50ce0 |
54 | |
4ec67e74 |
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 | } |
c2b50ce0 |
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 | |
c2b50ce0 |
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); |
4ec67e74 |
171 | curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function |
c2b50ce0 |
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 | } |
c59a3beb |
225 | else if ( numretries >= 1 ) |
c2b50ce0 |
226 | { |
bb7f7473 |
227 | //printf("Maximum number of retries exceeded!\n"); |
c2b50ce0 |
228 | free(s.ptr); |
229 | return(0); |
230 | } |
32323ea1 |
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); |
c2b50ce0 |
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); |
32323ea1 |
244 | if ( (count % 1000000) == 0) |
c2b50ce0 |
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 | } |
9b0e1808 |
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; |
b858fa74 |
273 | mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1)); |
9b0e1808 |
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 | |
05d3d5ff |
285 | char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) |
9b0e1808 |
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 | |
0ded57c8 |
332 | char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) |
9b0e1808 |
333 | { |
4ac6cd92 |
334 | //static void *cHandle; |
a9132082 |
335 | char url[512],*retstr=0,*retstr2=0,postdata[8192]; |
365378b5 |
336 | if ( params == 0 || params[0] == 0 ) |
337 | params = (char *)"[]"; |
9b0e1808 |
338 | if ( strlen(params) < sizeof(postdata)-128 ) |
339 | { |
3c0f5d94 |
340 | sprintf(url,(char *)"http://127.0.0.1:%u",port); |
9b0e1808 |
341 | sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); |
f38345e9 |
342 | //printf("postdata.(%s) USERPASS.(%s)\n",postdata,KMDUSERPASS); |
0ded57c8 |
343 | retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); |
c2b50ce0 |
344 | //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); |
9b0e1808 |
345 | } |
1ccb1cf0 |
346 | return(retstr2); |
9b0e1808 |
347 | } |
348 | |
20a5cb84 |
349 | int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,uint256 NOTARIZED_HASH) |
b55c2367 |
350 | { |
351 | int32_t i; uint256 hash; char params[256]; |
352 | for (i=0; i<32; i++) |
ebd18944 |
353 | ((uint8_t *)&hash)[i] = script[2+i]; |
d56e5945 |
354 | if ( hash == NOTARIZED_HASH ) |
355 | return(0); |
b556919a |
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]); |
20a5cb84 |
361 | printf(" opreturn from [%s] ht.%d\n",ASSETCHAINS_SYMBOL,height); |
b556919a |
362 | return(-1); |
b55c2367 |
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 | { |
c3153900 |
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] = '['; |
eee28662 |
369 | params[1] = '"'; |
370 | for (i=0; i<32; i++) |
c3153900 |
371 | sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]); |
372 | strcat(params,"\", 1]");*/ |
373 | sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str()); |
ed937645 |
374 | if ( strcmp(symbol,ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL) != 0 ) |
375 | return(0); |
a82f9da1 |
376 | //printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",ASSETCHAINS_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT); |
b55c2367 |
377 | if ( strcmp(dest,"KMD") == 0 ) |
b148643e |
378 | { |
379 | if ( KMDUSERPASS[0] != 0 ) |
380 | jsonstr = komodo_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,7771); |
381 | //else jsonstr = _dex_getrawtransaction(); |
48d0e5df |
382 | else return(0); // need universal way to issue DEX* API, since notaries mine most blocks, this ok |
b148643e |
383 | } |
b55c2367 |
384 | else if ( strcmp(dest,"BTC") == 0 ) |
b148643e |
385 | { |
386 | if ( BTCUSERPASS[0] != 0 ) |
48d0e5df |
387 | { |
eee28662 |
388 | //printf("BTCUSERPASS.(%s)\n",BTCUSERPASS); |
b148643e |
389 | jsonstr = komodo_issuemethod(BTCUSERPASS,(char *)"getrawtransaction",params,8332); |
48d0e5df |
390 | } |
b148643e |
391 | //else jsonstr = _dex_getrawtransaction(); |
48d0e5df |
392 | else return(0); |
b148643e |
393 | } |
9674c671 |
394 | else |
395 | { |
396 | printf("[%s] verifynotarization error unexpected dest.(%s)\n",ASSETCHAINS_SYMBOL,dest); |
397 | return(-1); |
398 | } |
b55c2367 |
399 | if ( jsonstr != 0 ) |
400 | { |
13b64fd6 |
401 | if ( (json= cJSON_Parse(jsonstr)) != 0 ) |
b55c2367 |
402 | { |
fa73aa67 |
403 | if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) > 0 ) |
b55c2367 |
404 | { |
405 | vout = jitem(vouts,n-1); |
51ecd3f9 |
406 | //printf("vout.(%s)\n",jprint(vout,0)); |
523a5dc7 |
407 | if ( (skey= jobj(vout,(char *)"scriptPubKey")) != 0 ) |
b55c2367 |
408 | { |
523a5dc7 |
409 | if ( (hexstr= jstr(skey,(char *)"hex")) != 0 ) |
b55c2367 |
410 | { |
ebd18944 |
411 | //printf("HEX.(%s)\n",hexstr); |
b55c2367 |
412 | len = strlen(hexstr) >> 1; |
413 | decode_hex(script,len,hexstr); |
20a5cb84 |
414 | retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH); |
b55c2367 |
415 | } |
416 | } |
417 | } |
418 | free_json(txjson); |
419 | } |
420 | free(jsonstr); |
421 | } |
422 | return(retval); |
423 | } |
424 | |
23256cca |
425 | uint256 komodo_getblockhash(int32_t height) |
426 | { |
dffceecf |
427 | uint256 hash; char params[128],*hexstr,*jsonstr; cJSON *result; int32_t i; uint8_t revbuf[32]; |
23256cca |
428 | memset(&hash,0,sizeof(hash)); |
429 | sprintf(params,"[%d]",height); |
ccf895cf |
430 | if ( (jsonstr= komodo_issuemethod(KMDUSERPASS,(char *)"getblockhash",params,7771)) != 0 ) |
23256cca |
431 | { |
ccf895cf |
432 | if ( (result= cJSON_Parse(jsonstr)) != 0 ) |
433 | { |
25391719 |
434 | if ( (hexstr= jstr(result,(char *)"result")) != 0 ) |
ccf895cf |
435 | { |
436 | if ( is_hexstr(hexstr,0) == 64 ) |
e9f49d50 |
437 | { |
438 | decode_hex(revbuf,32,hexstr); |
439 | for (i=0; i<32; i++) |
440 | ((uint8_t *)&hash)[i] = revbuf[31-i]; |
441 | } |
ccf895cf |
442 | } |
443 | free_json(result); |
444 | } |
5f1f19fd |
445 | printf("KMD hash.%d (%s) %x\n",height,jsonstr,*(uint32_t *)&hash); |
1fd57718 |
446 | free(jsonstr); |
23256cca |
447 | } |
448 | return(hash); |
449 | } |
450 | |
6b0e06b5 |
451 | uint256 _komodo_getblockhash(int32_t height); |
452 | |
23256cca |
453 | uint64_t komodo_seed(int32_t height) |
454 | { |
39b462c7 |
455 | uint64_t seed = 0; |
8aef9e40 |
456 | if ( 0 ) // problem during init time, seeds are needed for loading blockindex, so null seeds... |
457 | { |
39b462c7 |
458 | uint256 hash,zero; CBlockIndex *pindex; |
8aef9e40 |
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); |
8c072b0b |
471 | seed = arith_uint256(hash.GetHex()).GetLow64(); |
8aef9e40 |
472 | } |
473 | else |
474 | { |
93fb251c |
475 | seed = (height << 13) ^ (height << 2); |
476 | seed <<= 21; |
8aef9e40 |
477 | seed |= (height & 0xffffffff); |
93fb251c |
478 | seed ^= (seed << 17) ^ (seed << 1); |
8aef9e40 |
479 | } |
23256cca |
480 | return(seed); |
481 | } |
482 | |
3eea72f2 |
483 | uint32_t komodo_txtime(uint256 hash) |
484 | { |
485 | CTransaction tx; |
486 | uint256 hashBlock; |
7637aa7f |
487 | if (!GetTransaction(hash, tx, |
488 | #ifndef KOMODO_ZCASH |
489 | Params().GetConsensus(), |
490 | #endif |
491 | hashBlock, true)) |
3eea72f2 |
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 | { |
b46eae72 |
501 | char symbol[16],dest[16]; struct komodo_state *sp; |
c93dc546 |
502 | komodo_init(pindex->nHeight); |
f3a1de3a |
503 | if ( (sp= komodo_stateptr(symbol,dest)) != 0 ) |
7a183152 |
504 | { |
9c432d66 |
505 | //sp->rewinding = pindex->nHeight; |
506 | //fprintf(stderr,"-%d ",pindex->nHeight); |
7a183152 |
507 | } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->nHeight,ASSETCHAINS_SYMBOL); |
3eea72f2 |
508 | } |
509 | |
303fbd20 |
510 | |
f24b36ca |
511 | int32_t komodo_is_notarytx(const CTransaction& tx) |
512 | { |
513 | uint8_t *ptr,crypto777[33]; |
0554de3c |
514 | if ( tx.vout.size() > 0 ) |
515 | { |
f24b36ca |
516 | #ifdef KOMODO_ZCASH |
0554de3c |
517 | ptr = (uint8_t *)tx.vout[0].scriptPubKey.data(); |
f24b36ca |
518 | #else |
0554de3c |
519 | ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0]; |
f24b36ca |
520 | #endif |
0554de3c |
521 | if ( ptr != 0 ) |
303fbd20 |
522 | { |
0554de3c |
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 | } |
303fbd20 |
529 | } |
f24b36ca |
530 | } |
303fbd20 |
531 | return(0); |
f24b36ca |
532 | } |
533 | |
3eea72f2 |
534 | int32_t komodo_block2height(CBlock *block) |
535 | { |
189d9dee |
536 | int32_t i,n,height = 0; uint8_t *ptr; |
0554de3c |
537 | if ( block->vtx[0].vin.size() > 0 ) |
538 | { |
189d9dee |
539 | #ifdef KOMODO_ZCASH |
0554de3c |
540 | ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data(); |
189d9dee |
541 | #else |
0554de3c |
542 | ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0]; |
189d9dee |
543 | #endif |
0554de3c |
544 | if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 ) |
3eea72f2 |
545 | { |
0554de3c |
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); |
3eea72f2 |
556 | } |
0554de3c |
557 | //komodo_init(height); |
3eea72f2 |
558 | } |
559 | return(height); |
560 | } |
561 | |
562 | void komodo_block2pubkey33(uint8_t *pubkey33,CBlock& block) |
563 | { |
2dbf06e8 |
564 | int32_t n; |
0554de3c |
565 | memset(pubkey33,0,33); |
97561034 |
566 | if ( block.vtx[0].vout.size() > 0 ) |
0554de3c |
567 | { |
da00f2dd |
568 | #ifdef KOMODO_ZCASH |
0554de3c |
569 | uint8_t *ptr = (uint8_t *)block.vtx[0].vout[0].scriptPubKey.data(); |
da00f2dd |
570 | #else |
0554de3c |
571 | uint8_t *ptr = (uint8_t *)&block.vtx[0].vout[0].scriptPubKey[0]; |
da00f2dd |
572 | #endif |
0554de3c |
573 | //komodo_init(0); |
574 | n = block.vtx[0].vout[0].scriptPubKey.size(); |
575 | if ( n == 35 ) |
576 | memcpy(pubkey33,ptr+1,33); |
577 | } |
3eea72f2 |
578 | } |
579 | |
d7093b33 |
580 | int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex) |
875cf683 |
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 | |
3eea72f2 |
597 | void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height) |
598 | { |
599 | CBlock block; |
bc9f2e03 |
600 | //komodo_init(height); |
3eea72f2 |
601 | memset(pubkey33,0,33); |
602 | if ( pindex != 0 ) |
603 | { |
a92123ef |
604 | if ( komodo_blockload(block,pindex) == 0 ) |
605 | komodo_block2pubkey33(pubkey33,block); |
3eea72f2 |
606 | } |
607 | else |
608 | { |
609 | // height -> pubkey33 |
610 | //printf("extending chaintip komodo_index2pubkey33 height.%d need to get pubkey33\n",height); |
611 | } |
612 | } |
613 | |
875cf683 |
614 | void komodo_connectpindex(CBlockIndex *pindex) |
615 | { |
616 | CBlock block; |
a92123ef |
617 | if ( komodo_blockload(block,pindex) == 0 ) |
618 | komodo_connectblock(pindex,block); |
875cf683 |
619 | } |
620 | |
3617ec15 |
621 | CBlockIndex *komodo_chainactive(int32_t height) |
dd278be2 |
622 | { |
623 | return(chainActive[height]); |
624 | } |
625 | |
6034c671 |
626 | int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height); |
1b475b79 |
627 | int32_t komodo_electednotary(uint8_t *pubkey33,int32_t height); |
6034c671 |
628 | |
c142de7e |
629 | int8_t komodo_minerid(int32_t height,uint8_t *pubkey33) |
4a4e912b |
630 | { |
c142de7e |
631 | int32_t num,i; CBlockIndex *pindex; uint8_t _pubkey33[33],pubkeys[64][33]; |
a8e94add |
632 | if ( pubkey33 == 0 && (pindex= chainActive[height]) != 0 ) |
fc318ffe |
633 | { |
c142de7e |
634 | if ( pubkey33 == 0 ) |
635 | { |
636 | pubkey33 = _pubkey33; |
637 | komodo_index2pubkey33(pubkey33,pindex,height); |
638 | } |
18594cf7 |
639 | if ( (num= komodo_notaries(pubkeys,height)) > 0 ) |
e9ed4986 |
640 | { |
18594cf7 |
641 | for (i=0; i<num; i++) |
642 | if ( memcmp(pubkeys[i],pubkey33,33) == 0 ) |
643 | return(i); |
fc318ffe |
644 | } |
dac1ef88 |
645 | } |
14095588 |
646 | return(komodo_electednotary(pubkey33,height)); |
4a4e912b |
647 | } |
648 | |
8c654ec5 |
649 | int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *nonzpkeysp,int32_t height) |
353af8aa |
650 | { |
dac1ef88 |
651 | int32_t i,j,duplicate; CBlockIndex *pindex; uint8_t pubkey33[33]; |
353af8aa |
652 | memset(mids,-1,sizeof(*mids)*66); |
653 | for (i=duplicate=0; i<66; i++) |
654 | { |
3c525df1 |
655 | if ( (pindex= komodo_chainactive(height-i)) != 0 ) |
353af8aa |
656 | { |
657 | komodo_index2pubkey33(pubkey33,pindex,height-i); |
8c654ec5 |
658 | for (j=0; j<33; j++) |
659 | pubkeys[i][j] = pubkey33[j]; |
17c303dd |
660 | if ( (mids[i]= komodo_minerid(height-i,pubkey33)) >= 0 ) |
661 | { |
611acf22 |
662 | //mids[i] = *(int32_t *)pubkey33; |
353af8aa |
663 | (*nonzpkeysp)++; |
17c303dd |
664 | } |
353af8aa |
665 | if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] ) |
666 | duplicate++; |
3c525df1 |
667 | } |
353af8aa |
668 | } |
f2805ceb |
669 | if ( i == 66 && duplicate == 0 && (height > 186233 || *nonzpkeysp > 0) ) |
353af8aa |
670 | return(1); |
671 | else return(0); |
672 | } |
673 | |
780c9ff1 |
674 | int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) |
dbaf1154 |
675 | { |
676 | int32_t i,n=0; |
780c9ff1 |
677 | for (i=0; i<width; i++,n++) |
056447a6 |
678 | { |
679 | if ( height-i <= 0 ) |
680 | break; |
c142de7e |
681 | minerids[i] = komodo_minerid(height - i,0); |
056447a6 |
682 | } |
dbaf1154 |
683 | return(n); |
684 | } |
685 | |
4a4e912b |
686 | int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33]) |
687 | { |
edcf9a39 |
688 | int32_t i,notaryid,minerid,limit,nid; uint8_t _pubkey33[33]; |
689 | komodo_chosennotary(¬aryid,height,_pubkey33); |
4a4e912b |
690 | if ( height >= 34000 && notaryid >= 0 ) |
691 | { |
031b1129 |
692 | if ( height < 79693 ) |
693 | limit = 64; |
694 | else if ( height < 82000 ) |
3fe63a7d |
695 | limit = 8; |
28bc6208 |
696 | else limit = 66; |
1b3ce02c |
697 | for (i=1; i<limit; i++) |
4a4e912b |
698 | { |
edcf9a39 |
699 | komodo_chosennotary(&nid,height-i,_pubkey33); |
42b84cdf |
700 | if ( komodo_minerid(height-i,_pubkey33) == notaryid ) |
66e3c532 |
701 | { |
edcf9a39 |
702 | fprintf(stderr,"ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid); |
4a4e912b |
703 | return(-1); |
66e3c532 |
704 | } |
4a4e912b |
705 | } |
6a645f7b |
706 | //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit); |
4a4e912b |
707 | return(1); |
708 | } |
709 | return(0); |
710 | } |
711 | |
b62d7030 |
712 | int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash) |
713 | { |
d82623d2 |
714 | int32_t notarized_height; uint256 notarized_hash,notarized_desttxid; CBlockIndex *notary; CBlockIndex *pindex; |
715 | if ( (pindex= chainActive.Tip()) == 0 ) |
716 | return(-1); |
717 | notarized_height = komodo_notarizeddata(pindex->nHeight,¬arized_hash,¬arized_desttxid); |
b62d7030 |
718 | *notarized_heightp = notarized_height; |
aba9ea3c |
719 | if ( notarized_height >= 0 && notarized_height <= pindex->nHeight && (notary= mapBlockIndex[notarized_hash]) != 0 ) |
b62d7030 |
720 | { |
d82623d2 |
721 | //printf("nHeight.%d -> (%d %s)\n",pindex->Tip()->nHeight,notarized_height,notarized_hash.ToString().c_str()); |
b62d7030 |
722 | if ( notary->nHeight == notarized_height ) // if notarized_hash not in chain, reorg |
723 | { |
724 | if ( nHeight < notarized_height ) |
725 | { |
726 | fprintf(stderr,"nHeight.%d < NOTARIZED_HEIGHT.%d\n",nHeight,notarized_height); |
727 | return(-1); |
728 | } |
729 | else if ( nHeight == notarized_height && memcmp(&hash,¬arized_hash,sizeof(hash)) != 0 ) |
730 | { |
731 | fprintf(stderr,"nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",nHeight,notarized_height); |
732 | return(-1); |
733 | } |
734 | } else fprintf(stderr,"unexpected error notary_hash %s ht.%d at ht.%d\n",notarized_hash.ToString().c_str(),notarized_height,notary->nHeight); |
e0086592 |
735 | } else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 ) |
d82623d2 |
736 | fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight); |
b62d7030 |
737 | return(0); |
738 | } |
485e48ca |
739 | |
c1c95e36 |
740 | uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n) |
741 | { |
742 | LOCK(cs_main); |
743 | CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex; |
744 | if ( !GetTransaction(hash,tx,hashBlock,true) ) |
745 | return(0); |
746 | uint32_t locktime = 0; |
747 | if ( n < tx.vout.size() ) |
748 | { |
749 | if ( (pindex= mapBlockIndex[hashBlock]) != 0 && (tipindex= chainActive.Tip()) != 0 ) |
750 | { |
751 | *valuep = tx.vout[n].nValue; |
752 | *txheightp = pindex->nHeight; |
753 | *tiptimep = tipindex->nTime; |
754 | locktime = tx.nLockTime; |
1f52f946 |
755 | //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep); |
c1c95e36 |
756 | } |
757 | } |
758 | return(locktime); |
759 | } |
760 | |
761 | uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); |
798f28c7 |
762 | uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue) |
c1c95e36 |
763 | { |
798f28c7 |
764 | uint64_t value; uint32_t tiptime; |
765 | if ( (*locktimep= komodo_interest_args(txheightp,&tiptime,&value,hash,n)) != 0 ) |
c1c95e36 |
766 | { |
798f28c7 |
767 | if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) ) |
768 | return(komodo_interest(*txheightp,value,*locktimep,tiptime)); |
c1c95e36 |
769 | //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 |
770 | 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); |
771 | } |
c1c95e36 |
772 | return(0); |
773 | } |
8a7f7063 |
774 | |
775 | int32_t komodo_isrealtime(int32_t *kmdheightp) |
776 | { |
d82623d2 |
777 | struct komodo_state *sp; CBlockIndex *pindex; |
8a7c9241 |
778 | if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 ) |
ffbc2f00 |
779 | *kmdheightp = sp->CURRENT_HEIGHT; |
780 | else *kmdheightp = 0; |
d82623d2 |
781 | if ( (pindex= chainActive.Tip()) != 0 && pindex->nHeight == (int32_t)komodo_longestchain() ) |
8a7f7063 |
782 | return(1); |
783 | else return(0); |
784 | } |