Browse Source

Merge pull request #443 from jl777/spvdex

Spvdex
etomic
jl777 7 years ago
committed by GitHub
parent
commit
568d6f93e9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      iguana/exchanges/LP_commands.c
  2. 5
      iguana/exchanges/LP_include.h
  3. 20
      iguana/exchanges/LP_nativeDEX.c
  4. 54
      iguana/exchanges/LP_ordermatch.c
  5. 2
      iguana/exchanges/LP_rpc.c
  6. 36
      iguana/exchanges/LP_socket.c
  7. 18
      iguana/exchanges/LP_transaction.c
  8. 50
      iguana/exchanges/LP_utxo.c
  9. 1
      iguana/exchanges/LP_utxos.c
  10. 24
      iguana/exchanges/stats.c

5
iguana/exchanges/LP_commands.c

@ -375,7 +375,10 @@ bot_resume(botid)\n\
if ( (ptr= LP_coinsearch(coin)) != 0 )
{
ptr->inactive = 0;
return(jprint(LP_electrumserver(ptr,jstr(argjson,"ipaddr"),juint(argjson,"port")),1));
retstr = jprint(LP_electrumserver(ptr,jstr(argjson,"ipaddr"),juint(argjson,"port")),1);
if ( ptr->electrum != 0 && (retjson= electrum_address_listunspent(ptr->symbol,ptr->electrum,&retjson,ptr->smartaddr,2)) != 0 )
free_json(retjson);
return(retstr);
} else return(clonestr("{\"error\":\"cant find coind\"}"));
}
else if ( strcmp(method,"sendrawtransaction") == 0 )

5
iguana/exchanges/LP_include.h

@ -49,6 +49,7 @@ void emscripten_usleep(int32_t x); // returns immediate, no sense for sleeping
#define LP_MAXDESIRED_UTXOS 128
#define LP_MINDESIRED_UTXOS 32
#define LP_DUSTCOMBINE_THRESHOLD 1000000
// RTmetrics
#define LP_RTMETRICS_TOPGROUP 1.01
@ -254,7 +255,7 @@ struct iguana_info
portable_mutex_t txmutex,addrmutex; struct LP_transaction *transactions; struct LP_address *addresses;
uint64_t txfee;
int32_t numutxos,longestchain,firstrefht,firstscanht,lastscanht,bussock,height; uint16_t busport;
uint32_t importedprivkey,lastpushtime,lastutxosync,addr_listunspent_requested,lastutxos,updaterate,counter,inactive,lastmempool,lastgetinfo,ratetime,heighttime,lastmonitor,obooktime;
uint32_t lastunspent,importedprivkey,lastpushtime,lastutxosync,addr_listunspent_requested,lastutxos,updaterate,counter,inactive,lastmempool,lastgetinfo,ratetime,heighttime,lastmonitor,obooktime;
uint8_t pubtype,p2shtype,isPoS,wiftype,wiftaddr,taddr,noimportprivkey_flag,userconfirms,isassetchain,maxconfirms;
char symbol[16],smartaddr[64],userpass[1024],serverport[128];
// portfolio
@ -408,6 +409,8 @@ struct LP_address_utxo *LP_address_utxofind(struct iguana_info *coin,char *coina
int32_t LP_destaddr(char *destaddr,cJSON *item);
int32_t LP_waitmempool(char *symbol,char *coinaddr,bits256 txid,int32_t vout,int32_t duration);
char *LP_statslog_disp(int32_t n,uint32_t starttime,uint32_t endtime,char *refgui,bits256 refpubkey);
uint64_t LP_unspents_load(char *symbol,char *addr);
int32_t LP_validSPV(char *symbol,char *coinaddr,bits256 txid,int32_t vout);
struct LP_transaction *LP_transactionfind(struct iguana_info *coin,bits256 txid);
cJSON *LP_transactioninit(struct iguana_info *coin,bits256 txid,int32_t iter,cJSON *txobj);
int32_t LP_mempoolscan(char *symbol,bits256 searchtxid);

20
iguana/exchanges/LP_nativeDEX.c

@ -19,8 +19,6 @@
// marketmaker
//
// selftest and fix rpc port
// quotevalidate to do SPV
// autoadd dust utxo to vin for initial atomic tx
// verify portfolio, interest to KMD withdraw
// dPoW security -> 4: KMD notarized, 5: BTC notarized, after next notary elections
// bigendian architectures need to use little endian for sighash calcs
@ -595,7 +593,7 @@ void LP_coinsloop(void *_coins)
backupep = ep;
HASH_ITER(hh,coin->addresses,ap,atmp)
{
break;
break; // causes timeouts probably due to too much usage, SPV validation done on tx spending
DL_FOREACH_SAFE(ap->utxos,up,tmp)
{
if ( up->U.height > 0 && up->spendheight < 0 )
@ -622,12 +620,19 @@ void LP_coinsloop(void *_coins)
}
}
}
if ( time(NULL) > coin->lastunspent+30 )
{
//printf("call electrum listunspent.%s\n",coin->symbol);
if ( (retjson= electrum_address_listunspent(coin->symbol,ep,&retjson,coin->smartaddr,2)) != 0 )
free_json(retjson);
coin->lastunspent = (uint32_t)time(NULL);
}
while ( ep != 0 )
{
if ( time(NULL) > ep->keepalive+LP_ELECTRUM_KEEPALIVE )
{
//printf("%s electrum.%p needs a keepalive: lag.%d\n",ep->symbol,ep,(int32_t)(time(NULL) - ep->keepalive));
if ( (retjson= electrum_donation(ep->symbol,ep,&retjson)) != 0 )
if ( (retjson= electrum_address_listunspent(coin->symbol,ep,&retjson,coin->smartaddr,1)) != 0 )
free_json(retjson);
}
ep = ep->prev;
@ -1174,6 +1179,13 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybu
usleep(1000);
else if ( IAMLP == 0 )
usleep(1000);
/*if ( (rand() % 1000) == 0 )
{
int32_t sock = LP_bindsock;
printf("bindsock reset test\n");
LP_bindsock = -1;
closesocket(sock);
}*/
}
#endif
}

54
iguana/exchanges/LP_ordermatch.c

@ -246,7 +246,7 @@ int32_t LP_nearest_utxovalue(struct iguana_info *coin,char *coinaddr,struct LP_a
//printf("nearest i.%d target %.8f val %.8f dist %.8f mindist %.8f mini.%d spent.%d\n",i,dstr(targetval),dstr(up->U.value),dstr(dist),dstr(mindist),mini,up->spendheight);
if ( up->spendheight <= 0 )
{
if ( (coin->electrum == 0 || up->SPV > 0) && dist >= 0 && dist < mindist )
if ( dist >= 0 && dist < mindist ) //(coin->electrum == 0 || up->SPV > 0) &&
{
//printf("(%.8f %.8f %.8f).%d ",dstr(up->U.value),dstr(dist),dstr(mindist),mini);
mini = i;
@ -594,6 +594,26 @@ int32_t LP_aliceonly(char *symbol)
else return(0);
}
int32_t LP_validSPV(char *symbol,char *coinaddr,bits256 txid,int32_t vout)
{
struct electrum_info *ep,*backupep; struct LP_address_utxo *up; struct iguana_info *coin;
coin = LP_coinfind(symbol);
if ( coin != 0 && (ep= coin->electrum) != 0 )
{
if ( (up= LP_address_utxofind(coin,coinaddr,txid,vout)) != 0 )
{
if ( up->SPV < 0 )
return(-1);
if ( (backupep= ep->prev) == 0 )
backupep = ep;
up->SPV = LP_merkleproof(coin,backupep,up->U.txid,up->U.height);
if ( up->SPV <= 0 )
return(-1);
}
}
return(0);
}
int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen)
{
char *method,*msg,*retstr,str[65]; int32_t DEXselector = 0; uint64_t value,value2; cJSON *retjson; double qprice,price,bid,ask; struct LP_utxoinfo A,B,*autxo,*butxo; struct iguana_info *coin; struct LP_address_utxo *utxos[1000]; struct LP_quoteinfo Q; int32_t retval = -1,recalc,max=(int32_t)(sizeof(utxos)/sizeof(*utxos));
@ -605,8 +625,28 @@ int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,
LP_tradecommand_log(argjson);
//printf("LP_tradecommand: check received method %s aliceid.%llx\n",method,(long long)Q.aliceid);
retval = 1;
if ( LP_validSPV(Q.destcoin,Q.destaddr,Q.desttxid,Q.destvout) < 0 )
{
printf("%s dest %s failed SPV check\n",Q.destcoin,bits256_str(str,Q.desttxid));
return(retval);
}
else if (LP_validSPV(Q.destcoin,Q.destaddr,Q.feetxid,Q.feevout) < 0 )
{
printf("%s dexfee %s failed SPV check\n",Q.destcoin,bits256_str(str,Q.feetxid));
return(retval);
}
if ( strcmp(method,"reserved") == 0 )
{
if ( LP_validSPV(Q.srccoin,Q.coinaddr,Q.txid,Q.vout) < 0 )
{
printf("%s src %s failed SPV check\n",Q.srccoin,bits256_str(str,Q.txid));
return(retval);
}
else if (LP_validSPV(Q.srccoin,Q.coinaddr,Q.txid2,Q.vout2) < 0 )
{
printf("%s src2 %s failed SPV check\n",Q.srccoin,bits256_str(str,Q.txid2));
return(retval);
}
if ( bits256_cmp(G.LP_mypub25519,Q.desthash) == 0 && bits256_cmp(G.LP_mypub25519,Q.srchash) != 0 && LP_alice_eligible() > 0 )
{
printf("alice %s received RESERVED.(%s)\n",bits256_str(str,G.LP_mypub25519),jprint(argjson,0));
@ -620,7 +660,17 @@ int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,
{
if ( bits256_cmp(G.LP_mypub25519,Q.desthash) == 0 && bits256_cmp(G.LP_mypub25519,Q.srchash) != 0 )
{
//printf("alice %s received CONNECTED.(%s)\n",bits256_str(str,G.LP_mypub25519),jprint(argjson,0));
if ( LP_validSPV(Q.srccoin,Q.coinaddr,Q.txid,Q.vout) < 0 )
{
printf("%s src %s failed SPV check\n",Q.srccoin,bits256_str(str,Q.txid));
return(retval);
}
else if (LP_validSPV(Q.srccoin,Q.coinaddr,Q.txid2,Q.vout2) < 0 )
{
printf("%s src2 %s failed SPV check\n",Q.srccoin,bits256_str(str,Q.txid2));
return(retval);
}
//printf("alice %s received CONNECTED.(%s)\n",bits256_str(str,G.LP_mypub25519),jprint(argjson,0));
if ( (retstr= LP_connectedalice(argjson)) != 0 )
free(retstr);
}

2
iguana/exchanges/LP_rpc.c

@ -578,7 +578,7 @@ cJSON *LP_gettxout(char *symbol,char *coinaddr,bits256 txid,int32_t vout)
return(retjson);
}
}
printf("couldnt find %s/v%d\n",bits256_str(str,txid),vout);
printf("couldnt find %s (%s) %s/v%d\n",symbol,coinaddr,bits256_str(str,txid),vout);
return(cJSON_Parse("{\"error\":\"couldnt get tx\"}"));
}
}

36
iguana/exchanges/LP_socket.c

@ -591,27 +591,37 @@ cJSON *electrum_address_listunspent(char *symbol,struct electrum_info *ep,cJSON
usecache = 0;
}
//printf("electrum.%s/%s listunspent last.(%s lag %d)\n",ep->symbol,coin->symbol,coin->lastunspent,(int32_t)(time(NULL) - coin->unspenttime));
if ( usecache == 0 )
if ( usecache == 0 || electrumflag > 1 )
{
if ( (retjson= electrum_strarg(symbol,ep,retjsonp,"blockchain.address.listunspent",addr,ELECTRUM_TIMEOUT)) != 0 )
{
//printf("%s.%d u.%u/%d t.%ld %s LISTUNSPENT.(%d)\n",coin->symbol,height,ap->unspenttime,ap->unspentheight,time(NULL),addr,(int32_t)strlen(jprint(retjson,0)));
updatedflag = 0;
if ( electrum_process_array(coin,ep,addr,retjson,electrumflag) != 0 )
LP_postutxos(coin->symbol,addr), updatedflag = 1;
if ( strcmp(addr,coin->smartaddr) == 0 )
if ( jobj(retjson,"error") == 0 && is_cJSON_Array(retjson) != 0 )
{
retstr = jprint(retjson,0);
LP_unspents_cache(coin->symbol,coin->smartaddr,retstr,updatedflag);
free(retstr);
//printf("%s.%d u.%u/%d t.%ld %s LISTUNSPENT.(%d)\n",coin->symbol,height,ap->unspenttime,ap->unspentheight,time(NULL),addr,(int32_t)strlen(jprint(retjson,0)));
updatedflag = 0;
if ( electrum_process_array(coin,ep,addr,retjson,electrumflag) != 0 )
LP_postutxos(coin->symbol,addr), updatedflag = 1;
if ( strcmp(addr,coin->smartaddr) == 0 )
{
retstr = jprint(retjson,0);
LP_unspents_cache(coin->symbol,coin->smartaddr,retstr,1);
free(retstr);
}
if ( ap != 0 )
{
ap->unspenttime = (uint32_t)time(NULL);
ap->unspentheight = height;
}
}
if ( ap != 0 )
else
{
ap->unspenttime = (uint32_t)time(NULL);
ap->unspentheight = height;
free_json(retjson);
retjson = 0;
}
}
} else retjson = LP_address_utxos(coin,addr,1);
}
if ( retjson == 0 )
retjson = LP_address_utxos(coin,addr,1);
return(retjson);
}

18
iguana/exchanges/LP_transaction.c

@ -854,7 +854,7 @@ int64_t LP_komodo_interest(bits256 txid,int64_t value)
int32_t LP_vins_select(void *ctx,struct iguana_info *coin,int64_t *totalp,int64_t amount,struct vin_info *V,struct LP_address_utxo **utxos,int32_t numunspents,int32_t suppress_pubkeys,int32_t ignore_cltverr,bits256 privkey,cJSON *privkeys,cJSON *vins,uint8_t *script,int32_t scriptlen,bits256 utxotxid,int32_t utxovout,int32_t dustcombine)
{
char wifstr[128],spendscriptstr[128],str[65]; int32_t i,j,n,numpre,ind,abovei,belowi,maxmode=0; struct vin_info *vp; cJSON *txobj; struct LP_address_utxo *up,*min0,*min1,*preselected[3]; struct electrum_info *ep,*backupep; int64_t value,interest,interestsum,above,below,remains = amount,total = 0;
char wifstr[128],spendscriptstr[128],str[65]; int32_t i,j,n,numpre,ind,abovei,belowi,maxmode=0; struct vin_info *vp; cJSON *txobj; struct LP_address_utxo *up,*min0,*min1,*preselected[3]; int64_t value,interest,interestsum,above,below,remains = amount,total = 0;
*totalp = 0;
interestsum = 0;
init_hexbytes_noT(spendscriptstr,script,scriptlen);
@ -916,10 +916,10 @@ int32_t LP_vins_select(void *ctx,struct iguana_info *coin,int64_t *totalp,int64_
return(0);
}
}
if ( dustcombine >= 1 && min0 != 0 && min0->U.value < SATOSHIDEN && (coin->electrum == 0 || min0->SPV > 0) )
if ( dustcombine >= 1 && min0 != 0 && min0->U.value < LP_DUSTCOMBINE_THRESHOLD && (coin->electrum == 0 || min0->SPV > 0) )
preselected[numpre++] = min0;
else min0 = 0;
if ( dustcombine >= 2 && min1 != 0 && min1->U.value < SATOSHIDEN && (coin->electrum == 0 || min1->SPV > 0) )
if ( dustcombine >= 2 && min1 != 0 && min1->U.value < LP_DUSTCOMBINE_THRESHOLD && (coin->electrum == 0 || min1->SPV > 0) )
preselected[numpre++] = min1;
else min1 = 0;
printf("dustcombine.%d numpre.%d min0.%p min1.%p numutxos.%d\n",dustcombine,numpre,min0,min1,numunspents);
@ -955,16 +955,8 @@ int32_t LP_vins_select(void *ctx,struct iguana_info *coin,int64_t *totalp,int64_
break;
if ( j < numpre )
continue;
if ( (ep= coin->electrum) != 0 && up->SPV <= 0 )
{
if ( up->SPV < 0 )
continue;
if ( (backupep= ep->prev) == 0 )
backupep = ep;
up->SPV = LP_merkleproof(coin,backupep,up->U.txid,up->U.height);
if ( up->SPV <= 0 )
continue;
}
if ( LP_validSPV(coin->symbol,coin->smartaddr,up->U.txid,up->U.vout) < 0 )
continue;
}
up->spendheight = 1;

50
iguana/exchanges/LP_utxo.c

@ -472,13 +472,38 @@ cJSON *LP_address_utxos(struct iguana_info *coin,char *coinaddr,int32_t electrum
cJSON *LP_address_balance(struct iguana_info *coin,char *coinaddr,int32_t electrumret)
{
cJSON *array,*retjson; int32_t i,n; uint64_t balance = 0;
if ( (array= LP_address_utxos(coin,coinaddr,1)) != 0 )
cJSON *array,*retjson,*item; int32_t i,n; uint64_t balance = 0;
if ( coin->electrum == 0 )
{
if ( (n= cJSON_GetArraySize(array)) > 0 )
if ( (array= LP_listunspent(coin->symbol,coinaddr)) != 0 )
{
for (i=0; i<n; i++)
balance += j64bits(jitem(array,i),"value");
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
balance += LP_value_extract(item,1);
}
}
}
}
else
{
if ( strcmp(coin->smartaddr,coinaddr) == 0 )
balance = LP_unspents_load(coin->symbol,coinaddr);
else
{
if ( (array= LP_address_utxos(coin,coinaddr,1)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
balance += j64bits(item,"value");
}
}
}
}
}
retjson = cJSON_CreateObject();
@ -1062,9 +1087,9 @@ void LP_unspents_cache(char *symbol,char *addr,char *arraystr,int32_t updatedfla
}
}
void LP_unspents_load(char *symbol,char *addr)
uint64_t LP_unspents_load(char *symbol,char *addr)
{
char fname[1024],*arraystr; long fsize; struct iguana_info *coin; cJSON *retjson;
char fname[1024],*arraystr; uint64_t balance = 0; int32_t i,n; long fsize; struct iguana_info *coin; cJSON *retjson,*item;
if ( (coin= LP_coinfind(symbol)) != 0 )
{
sprintf(fname,"%s/UNSPENTS/%s_%s",GLOBAL_DBDIR,symbol,addr), OS_portable_path(fname);
@ -1072,13 +1097,22 @@ void LP_unspents_load(char *symbol,char *addr)
{
if ( (retjson= cJSON_Parse(arraystr)) != 0 )
{
printf("PROCESS UNSPENTS %s\n",arraystr);
//printf("PROCESS UNSPENTS %s\n",arraystr);
if ( (n= cJSON_GetArraySize(retjson)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(retjson,i);
balance += j64bits(item,"value");
}
}
electrum_process_array(coin,coin->electrum,coin->smartaddr,retjson,1);
free_json(retjson);
}
free(arraystr);
}
}
return(balance);
}

1
iguana/exchanges/LP_utxos.c

@ -826,6 +826,7 @@ int32_t LP_passphrase_init(char *passphrase,char *gui)
G.LP_sessionid = (uint32_t)time(NULL);
safecopy(G.gui,gui,sizeof(G.gui));
G.USERPASS_COUNTER = counter;
G.initializing = 0;
return(0);
}

24
iguana/exchanges/stats.c

@ -740,30 +740,32 @@ void LP_rpc_processreq(void *_ptr)
}
extern int32_t IAMLP;
int32_t LP_bindsock = -1;
void stats_rpcloop(void *args)
{
static uint32_t counter;
uint16_t port; int32_t retval,sock,bindsock=-1; socklen_t clilen; struct sockaddr_in cli_addr; uint32_t ipbits,localhostbits; struct rpcrequest_info *req,*req2,*rtmp;
//static uint32_t counter;
uint16_t port; int32_t retval,sock; socklen_t clilen; struct sockaddr_in cli_addr; uint32_t ipbits,localhostbits; struct rpcrequest_info *req,*req2,*rtmp;
if ( (port= *(uint16_t *)args) == 0 )
port = 7779;
RPC_port = port;
localhostbits = (uint32_t)calc_ipbits("127.0.0.1");
while ( 1 )
{
if ( bindsock < 0 )
//printf("LP_bindsock.%d\n",LP_bindsock);
if ( LP_bindsock < 0 )
{
while ( (bindsock= iguana_socket(1,"0.0.0.0",port)) < 0 )
while ( (LP_bindsock= iguana_socket(1,"0.0.0.0",port)) < 0 )
usleep(10000);
if ( counter++ < 1 )
printf(">>>>>>>>>> DEX stats 127.0.0.1:%d bind sock.%d DEX stats API enabled <<<<<<<<<\n",port,bindsock);
//if ( counter++ < 1 )
printf(">>>>>>>>>> DEX stats 127.0.0.1:%d bind sock.%d DEX stats API enabled <<<<<<<<<\n",port,LP_bindsock);
}
clilen = sizeof(cli_addr);
sock = accept(bindsock,(struct sockaddr *)&cli_addr,&clilen);
sock = accept(LP_bindsock,(struct sockaddr *)&cli_addr,&clilen);
if ( sock < 0 )
{
printf("iguana_rpcloop ERROR on accept usock.%d errno %d %s\n",sock,errno,strerror(errno));
close(bindsock);
bindsock = -1;
closesocket(LP_bindsock);
LP_bindsock = -1;
continue;
}
memcpy(&ipbits,&cli_addr.sin_addr.s_addr,sizeof(ipbits));
@ -775,8 +777,8 @@ continue;
if ( (retval= OS_thread_create(&req->T,NULL,(void *)LP_rpc_processreq,req)) != 0 )
{
printf("error launching rpc handler on port %d, retval.%d\n",port,retval);
close(bindsock);
bindsock = -1;
closesocket(LP_bindsock);
LP_bindsock = -1;
portable_mutex_lock(&LP_gcmutex);
DL_FOREACH_SAFE(LP_garbage_collector,req2,rtmp)
{

Loading…
Cancel
Save