|
|
@ -26,7 +26,7 @@ |
|
|
|
#include <WinSock2.h> |
|
|
|
#endif |
|
|
|
|
|
|
|
#define ELECTRUM_TIMEOUT 5 |
|
|
|
#define ELECTRUM_TIMEOUT 3 |
|
|
|
|
|
|
|
int32_t LP_socket(int32_t bindflag,char *hostname,uint16_t port) |
|
|
|
{ |
|
|
@ -253,7 +253,7 @@ int32_t Num_electrums; |
|
|
|
|
|
|
|
// purge timedout
|
|
|
|
/*
|
|
|
|
if ( (retjson= electrum_address_listunspent(symbol,ep,0,addr)) != 0 ) |
|
|
|
if ( (retjson= electrum_address_listunspent(symbol,ep,&retjson,addr)) != 0 ) |
|
|
|
you can call it like the above, where symbol is the coin, ep is the electrum server info pointer, the 0 is a callback ptr where 0 means to block till it is done |
|
|
|
all the API calls have the same three args |
|
|
|
if the callback ptr is &retjson, then on completion it will put the cJSON *ptr into it, so to spawn a bunch of calls you need to call with symbol,ep,&retjsons[i],... |
|
|
@ -306,52 +306,52 @@ struct electrum_info *electrum_server(char *symbol,struct electrum_info *ep) |
|
|
|
cJSON *electrum_submit(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *method,char *params,int32_t timeout) |
|
|
|
{ |
|
|
|
// queue id and string and callback
|
|
|
|
char stratumreq[16384]; uint32_t expiration; struct stritem *sitem; cJSON *retjson = 0; |
|
|
|
if ( strcmp(method,"getrawmempool") == 0 ) |
|
|
|
{ |
|
|
|
retjson = cJSON_Parse("{\"error\":\"unsupported method\"}"); |
|
|
|
if ( retjsonp != 0 ) |
|
|
|
*retjsonp = retjson; |
|
|
|
return(retjson); |
|
|
|
} |
|
|
|
char stratumreq[16384]; uint32_t expiration; struct stritem *sitem; |
|
|
|
if ( ep == 0 ) |
|
|
|
ep = electrum_server(symbol,0); |
|
|
|
if ( ep != 0 ) |
|
|
|
if ( ep != 0 && retjsonp != 0 ) |
|
|
|
{ |
|
|
|
*retjsonp = 0; |
|
|
|
if ( strcmp(method,"getrawmempool") == 0 ) |
|
|
|
{ |
|
|
|
*retjsonp = cJSON_Parse("{\"error\":\"unsupported method\"}"); |
|
|
|
return(*retjsonp); |
|
|
|
} |
|
|
|
sprintf(stratumreq,"{ \"jsonrpc\":\"2.0\", \"id\": %u, \"method\":\"%s\", \"params\": %s }\n",ep->stratumid,method,params); |
|
|
|
ep->buf[0] = 0; |
|
|
|
sitem = (struct stritem *)queueitem(stratumreq); |
|
|
|
sitem->expiration = timeout; |
|
|
|
sitem->DL.type = ep->stratumid++; |
|
|
|
if ( retjsonp != 0 ) |
|
|
|
sitem->retptrp = (void **)retjsonp; |
|
|
|
else sitem->retptrp = (void **)&retjson; |
|
|
|
sitem->retptrp = (void **)retjsonp; |
|
|
|
queue_enqueue("sendQ",&ep->sendQ,&sitem->DL); |
|
|
|
if ( sitem->retptrp == (void **)&retjson ) |
|
|
|
expiration = (uint32_t)time(NULL) + timeout + 1; |
|
|
|
while ( *retjsonp == 0 && time(NULL) <= expiration ) |
|
|
|
usleep(10000); |
|
|
|
if ( *retjsonp == 0 ) |
|
|
|
{ |
|
|
|
expiration = (uint32_t)time(NULL) + timeout + 1; |
|
|
|
while ( retjson == 0 && time(NULL) <= expiration ) |
|
|
|
usleep(10000); |
|
|
|
if ( retjson == 0 ) |
|
|
|
{ |
|
|
|
printf("unexpected timeout with null retjson: %s %s\n",method,params); |
|
|
|
retjson = cJSON_Parse("{\"error\":\"timeout\"}"); |
|
|
|
} |
|
|
|
printf("unexpected timeout with null retjson: %s %s\n",method,params); |
|
|
|
*retjsonp = cJSON_Parse("{\"error\":\"timeout\"}"); |
|
|
|
} |
|
|
|
} else printf("couldnt find electrum server for (%s %s)\n",method,params); |
|
|
|
return(retjson); |
|
|
|
return(*retjsonp); |
|
|
|
} else printf("couldnt find electrum server for (%s %s) or no retjsonp.%p\n",method,params,retjsonp); |
|
|
|
return(0); |
|
|
|
} |
|
|
|
|
|
|
|
cJSON *electrum_noargs(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *method,int32_t timeout) |
|
|
|
{ |
|
|
|
cJSON *retjson; |
|
|
|
if ( retjsonp == 0 ) |
|
|
|
retjsonp = &retjson; |
|
|
|
return(electrum_submit(symbol,ep,retjsonp,method,"[]",timeout)); |
|
|
|
} |
|
|
|
|
|
|
|
cJSON *electrum_strarg(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *method,char *arg,int32_t timeout) |
|
|
|
{ |
|
|
|
char params[16384]; |
|
|
|
char params[16384]; cJSON *retjson; |
|
|
|
if ( strlen(arg) < sizeof(params) ) |
|
|
|
{ |
|
|
|
if ( retjsonp == 0 ) |
|
|
|
retjsonp = &retjson; |
|
|
|
sprintf(params,"[\"%s\"]",arg); |
|
|
|
return(electrum_submit(symbol,ep,retjsonp,method,params,timeout)); |
|
|
|
} else return(0); |
|
|
@ -359,14 +359,18 @@ cJSON *electrum_strarg(char *symbol,struct electrum_info *ep,cJSON **retjsonp,ch |
|
|
|
|
|
|
|
cJSON *electrum_intarg(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *method,int32_t arg,int32_t timeout) |
|
|
|
{ |
|
|
|
char params[64]; |
|
|
|
char params[64]; cJSON *retjson; |
|
|
|
if ( retjsonp == 0 ) |
|
|
|
retjsonp = &retjson; |
|
|
|
sprintf(params,"[\"%d\"]",arg); |
|
|
|
return(electrum_submit(symbol,ep,retjsonp,method,params,timeout)); |
|
|
|
} |
|
|
|
|
|
|
|
cJSON *electrum_hasharg(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *method,bits256 arg,int32_t timeout) |
|
|
|
{ |
|
|
|
char params[128],str[65]; |
|
|
|
char params[128],str[65]; cJSON *retjson; |
|
|
|
if ( retjsonp == 0 ) |
|
|
|
retjsonp = &retjson; |
|
|
|
sprintf(params,"[\"%s\"]",bits256_str(str,arg)); |
|
|
|
return(electrum_submit(symbol,ep,retjsonp,method,params,timeout)); |
|
|
|
} |
|
|
@ -519,7 +523,7 @@ int32_t LP_recvfunc(struct electrum_info *ep,char *str,int32_t len) |
|
|
|
if ( (strjson= cJSON_Parse(str)) != 0 ) |
|
|
|
{ |
|
|
|
resultjson = jobj(strjson,"result"); |
|
|
|
//printf("result.(%s)\n",jprint(resultjson,0));
|
|
|
|
//printf("strjson.(%s)\n",jprint(strjson,0));
|
|
|
|
if ( (method= jstr(strjson,"method")) != 0 ) |
|
|
|
{ |
|
|
|
if ( strcmp(method,"blockchain.headers.subscribe") == 0 ) |
|
|
@ -542,45 +546,34 @@ int32_t LP_recvfunc(struct electrum_info *ep,char *str,int32_t len) |
|
|
|
} |
|
|
|
} |
|
|
|
idnum = juint(strjson,"id"); |
|
|
|
//if ( 0 ) // crashes cipi's node likely due to mutex across threads
|
|
|
|
portable_mutex_lock(&ep->pendingQ.mutex); |
|
|
|
if ( ep->pendingQ.list != 0 ) |
|
|
|
{ |
|
|
|
portable_mutex_lock(&ep->pendingQ.mutex); |
|
|
|
if ( ep->pendingQ.list != 0 ) |
|
|
|
DL_FOREACH(ep->pendingQ.list,item) |
|
|
|
{ |
|
|
|
DL_FOREACH(ep->pendingQ.list,item) |
|
|
|
stritem = (struct stritem *)item; |
|
|
|
if ( item->type == idnum ) |
|
|
|
{ |
|
|
|
if ( item->type == 0xffffffff ) |
|
|
|
continue; |
|
|
|
stritem = (struct stritem *)item; |
|
|
|
if ( item->type == idnum ) |
|
|
|
{ |
|
|
|
//printf("matched idnum.%d\n",idnum);
|
|
|
|
item->type = 0xffffffff; |
|
|
|
if ( stritem->retptrp != 0 ) |
|
|
|
{ |
|
|
|
*((cJSON **)stritem->retptrp) = strjson; |
|
|
|
strjson = 0; |
|
|
|
} |
|
|
|
//DL_DELETE(ep->pendingQ.list,item);
|
|
|
|
break; |
|
|
|
} |
|
|
|
if ( stritem->expiration < ep->lasttime ) |
|
|
|
{ |
|
|
|
printf("expired (%s)\n",stritem->str); |
|
|
|
item->type = 0xffffffff; |
|
|
|
//DL_DELETE(ep->pendingQ.list,item);
|
|
|
|
if ( stritem->retptrp != 0 ) |
|
|
|
{ |
|
|
|
errjson = cJSON_CreateObject(); |
|
|
|
jaddnum(errjson,"id",item->type); |
|
|
|
jaddstr(errjson,"error","timeout"); |
|
|
|
*((cJSON **)stritem->retptrp) = errjson; |
|
|
|
}; |
|
|
|
} |
|
|
|
//printf("matched idnum.%d result.%p\n",idnum,resultjson);
|
|
|
|
DL_DELETE(ep->pendingQ.list,item); |
|
|
|
*((cJSON **)stritem->retptrp) = (resultjson != 0 ? jduplicate(resultjson) : strjson); |
|
|
|
resultjson = strjson = 0; |
|
|
|
free(item); |
|
|
|
break; |
|
|
|
} |
|
|
|
if ( stritem->expiration < ep->lasttime ) |
|
|
|
{ |
|
|
|
DL_DELETE(ep->pendingQ.list,item); |
|
|
|
printf("expired (%s)\n",stritem->str); |
|
|
|
errjson = cJSON_CreateObject(); |
|
|
|
jaddnum(errjson,"id",item->type); |
|
|
|
jaddstr(errjson,"error","timeout"); |
|
|
|
*((cJSON **)stritem->retptrp) = errjson; |
|
|
|
free(item); |
|
|
|
} |
|
|
|
} |
|
|
|
portable_mutex_unlock(&ep->pendingQ.mutex); |
|
|
|
} |
|
|
|
portable_mutex_unlock(&ep->pendingQ.mutex); |
|
|
|
if ( strjson != 0 ) |
|
|
|
free_json(strjson); |
|
|
|
} |
|
|
@ -589,7 +582,7 @@ int32_t LP_recvfunc(struct electrum_info *ep,char *str,int32_t len) |
|
|
|
|
|
|
|
void LP_dedicatedloop(void *arg) |
|
|
|
{ |
|
|
|
struct pollfd fds; int32_t i,len,flag,timeout = 10; struct iguana_info *coin; cJSON *retjson; struct stritem *sitem; struct queueitem *item = 0; struct electrum_info *ep = arg; |
|
|
|
struct pollfd fds; int32_t i,len,flag,timeout = 10; struct iguana_info *coin; cJSON *retjson; struct stritem *sitem; struct electrum_info *ep = arg; |
|
|
|
if ( (coin= LP_coinfind(ep->symbol)) != 0 ) |
|
|
|
ep->heightp = &coin->height, ep->heighttimep = &coin->heighttime; |
|
|
|
if ( (retjson= electrum_headers_subscribe(ep->symbol,ep,0)) != 0 ) |
|
|
@ -614,23 +607,25 @@ void LP_dedicatedloop(void *arg) |
|
|
|
if ( sitem->expiration != 0 ) |
|
|
|
sitem->expiration += (uint32_t)time(NULL); |
|
|
|
else sitem->expiration = (uint32_t)time(NULL) + ELECTRUM_TIMEOUT; |
|
|
|
//printf("SEND.(%s) to %s:%u\n",sitem->str,ep->ipaddr,ep->port);
|
|
|
|
//queue_enqueue("pendingQ",&ep->pendingQ,(struct queueitem *)sitem);
|
|
|
|
portable_mutex_lock(&ep->pendingQ.mutex); |
|
|
|
/*portable_mutex_lock(&ep->pendingQ.mutex);
|
|
|
|
if ( ep->pendingQ.list != 0 ) |
|
|
|
{ |
|
|
|
printf("list %p\n",ep->pendingQ.list); |
|
|
|
DL_FOREACH(ep->pendingQ.list,item) |
|
|
|
{ |
|
|
|
printf("item.%p\n",item); |
|
|
|
if ( item->type == 0xffffffff ) |
|
|
|
{ |
|
|
|
printf("purge %s",((struct stritem *)item)->str); |
|
|
|
printf("%p purge %s",item,((struct stritem *)item)->str); |
|
|
|
DL_DELETE(ep->pendingQ.list,item); |
|
|
|
free(item); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
DL_APPEND(ep->pendingQ.list,&sitem->DL); |
|
|
|
portable_mutex_unlock(&ep->pendingQ.mutex); |
|
|
|
portable_mutex_unlock(&ep->pendingQ.mutex);*/ |
|
|
|
//printf("%p SEND.(%s) to %s:%u\n",sitem,sitem->str,ep->ipaddr,ep->port);
|
|
|
|
queue_enqueue("pendingQ",&ep->pendingQ,&sitem->DL); |
|
|
|
flag++; |
|
|
|
} |
|
|
|
if ( flag == 0 ) |
|
|
|