/****************************************************************************** * Copyright © 2014-2017 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ // // LP_statemachine.c // marketmaker // else { CTransaction tx; uint256 hashBlock; int32_t numvouts,len; uint8_t *ptr; if ( GetTransaction(NOTARIZED_DESTTXID,tx,hashBlock,true) == 0 ) { fprintf(stderr,"error finding") return(-1); } if ( (numvouts= tx.vout.size()) > 0 ) { ptr = (uint8_t *)tx.vout[numvouts - 1].scriptPubKey.data(); len = tx.vout[numvouts - 1].scriptPubKey.size(); retval = komodo_verifynotarizedscript(height,ptr,len,NOTARIZED_HASH); printf("direct verify ht.%d -> %d\n",height,retval); return(retval); } } /*struct LP_cacheinfo *ptr,*tmp; HASH_ITER(hh,LP_cacheinfos,ptr,tmp) { if ( ptr->timestamp < now-3600*2 || ptr->price == 0. ) continue; if ( strcmp(ptr->Q.srccoin,base) == 0 && strcmp(ptr->Q.destcoin,rel) == 0 ) { asks = realloc(asks,sizeof(*asks) * (numasks+1)); if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,ptr->price,ptr->Q.satoshis,ptr->Q.srchash)) != 0 ) asks[numasks++] = op; } else if ( strcmp(ptr->Q.srccoin,rel) == 0 && strcmp(ptr->Q.destcoin,base) == 0 ) { bids = realloc(bids,sizeof(*bids) * (numbids+1)); if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,1./ptr->price,ptr->Q.satoshis,ptr->Q.srchash)) != 0 ) bids[numbids++] = op; } }*/ /*void basilisk_swaps_init(struct supernet_info *myinfo) { char fname[512]; uint32_t iter,swapcompleted,requestid,quoteid,optionduration,statebits; FILE *fp; bits256 privkey;struct basilisk_request R; struct basilisk_swapmessage M; struct basilisk_swap *swap = 0; sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); if ( (myinfo->swapsfp= fopen(fname,"rb+")) != 0 ) { while ( fread(&requestid,1,sizeof(requestid),myinfo->swapsfp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),myinfo->swapsfp) == sizeof(quoteid) ) { sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); printf("%s\n",fname); if ( (fp= fopen(fname,"rb+")) != 0 ) // check to see if completed { memset(&M,0,sizeof(M)); swapcompleted = 1; for (iter=0; iter<2; iter++) { if ( fread(privkey.bytes,1,sizeof(privkey),fp) == sizeof(privkey) && fread(&R,1,sizeof(R),fp) == sizeof(R) && fread(&statebits,1,sizeof(statebits),fp) == sizeof(statebits) && fread(&optionduration,1,sizeof(optionduration),fp) == sizeof(optionduration) ) { while ( 0 && fread(&M,1,sizeof(M),fp) == sizeof(M) ) { M.data = 0; //printf("entry iter.%d crc32.%x datalen.%d\n",iter,M.crc32,M.datalen); if ( M.datalen < 100000 ) { M.data = malloc(M.datalen); if ( fread(M.data,1,M.datalen,fp) == M.datalen ) { if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) { if ( iter == 1 ) { if ( swap == 0 ) { swap = basilisk_thread_start(privkey,&R,statebits,optionduration,1); swap->I.choosei = swap->I.otherchoosei = -1; } if ( swap != 0 ) basilisk_swapgotdata(swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); } } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); } else printf("error reading M.datalen %d\n",M.datalen); free(M.data), M.data = 0; } } } if ( swapcompleted != 0 ) break; rewind(fp); } } } } else myinfo->swapsfp = fopen(fname,"wb+"); }*/ FILE *basilisk_swap_save(struct basilisk_swap *swap,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { FILE *fp=0; /*char fname[512]; sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,rp->requestid,rp->quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"rb+")) == 0 ) { if ( (fp= fopen(fname,"wb+")) != 0 ) { fwrite(privkey.bytes,1,sizeof(privkey),fp); fwrite(rp,1,sizeof(*rp),fp); fwrite(&statebits,1,sizeof(statebits),fp); fwrite(&optionduration,1,sizeof(optionduration),fp); fflush(fp); } } else if ( reinit != 0 ) { }*/ return(fp); } //printf("VOUT.(%s)\n",jprint(vout,0)); /*if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) { item = jitem(addresses,0); //printf("item.(%s)\n",jprint(item,0)); if ( (addr= jstr(item,0)) != 0 ) { safecopy(coinaddr,addr,64); //printf("extracted.(%s)\n",coinaddr); } }*/ /*if ( IAMLP != 0 && time(NULL) > lasthello+600 ) { char *hellostr,*retstr; cJSON *retjson; int32_t allgood,sock = LP_bindsock; allgood = 0; if ( (retstr= issue_hello(myport)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (hellostr= jstr(retjson,"status")) != 0 && strcmp(hellostr,"got hello") == 0 ) allgood = 1; else printf("strange return.(%s)\n",jprint(retjson,0)); free_json(retjson); } else printf("couldnt parse hello return.(%s)\n",retstr); free(retstr); } else printf("issue_hello NULL return\n"); lasthello = (uint32_t)time(NULL); if ( allgood == 0 ) { printf("RPC port got stuck, would have close bindsocket\n"); if ( 0 ) { LP_bindsock = -1; closesocket(sock); LP_bindsock_reset++; sleep(10); printf("launch new rpcloop\n"); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } } } }*/ /* now = (uint32_t)time(NULL); numpeers = LP_numpeers(); needpings = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( peer->errors >= LP_MAXPEER_ERRORS ) { if ( (LP_rand() % 10000) == 0 ) { peer->errors--; if ( peer->errors < LP_MAXPEER_ERRORS ) peer->diduquery = 0; } if ( IAMLP == 0 ) continue; } if ( now > peer->lastpeers+LP_ORDERBOOK_DURATION*.777 || (LP_rand() % 100000) == 0 ) { if ( strcmp(peer->ipaddr,myipaddr) != 0 ) { nonz++; //issue_LP_getpeers(peer->ipaddr,peer->port); //LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport); //if ( peer->diduquery == 0 ) // LP_peer_pricesquery(peer); //LP_utxos_sync(peer); needpings++; } peer->lastpeers = now; } if ( peer->needping != 0 ) { peer->diduquery = now; nonz++; if ( (retstr= issue_LP_notify(peer->ipaddr,peer->port,"127.0.0.1",0,numpeers,G.LP_sessionid,G.LP_myrmd160str,G.LP_mypub25519)) != 0 ) free(retstr); peer->needping = 0; needpings++; } }*/ #ifdef oldway int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t numpeers,i,n=0; if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; i numpeers) ) peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jint(item,"numpeers"),jint(item,"numutxos"),juint(item,"session")); } if ( peer != 0 ) { peer->lasttime = now; if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers != n ) peer->numpeers = n; } } } } free_json(array); } return(n); } void issue_LP_getpeers(char *destip,uint16_t destport) { cJSON *reqjson = cJSON_CreateObject(); jaddstr(reqjson,"method","getpeers"); LP_peer_request(destip,destport,reqjson); /*char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&numpeers=%d",destip,destport,ipaddr,port,numpeers); retstr = LP_issue_curl("getpeers",destip,port,url); //printf("%s -> getpeers.(%s)\n",destip,retstr); return(retstr);*/ } void LP_peer_request(char *destip,uint16_t destport,cJSON *argjson) { struct LP_peerinfo *peer; uint8_t *msg; int32_t msglen; uint32_t crc32; peer = LP_peerfind((uint32_t)calc_ipbits(destip),destport); msg = (void *)jprint(argjson,0); msglen = (int32_t)strlen((char *)msg) + 1; crc32 = calc_crc32(0,&msg[2],msglen - 2); LP_queuesend(crc32,peer->pushsock,"","",msg,msglen); free_json(argjson); }void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport) { char *retstr; struct LP_peerinfo *peer,*tmp; bits256 zero; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,mypeer!=0?mypeer->numpeers:0)) != 0 ) { //printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); if ( IAMLP != 0 ) { HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( peer->lasttime != now ) { printf("{%s:%u}.%d ",peer->ipaddr,peer->port,peer->lasttime - now); flag++; memset(&zero,0,sizeof(zero)); if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->numpeers,peer->sessionid,0,zero)) != 0 ) free(retstr); } } if ( flag != 0 ) printf(" <- missing peers\n"); } } } void issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,int32_t numpeers,uint32_t sessionid,char *rmd160str,bits256 pub) { cJSON *reqjson = cJSON_CreateObject(); jaddstr(reqjson,"method","notify"); jaddstr(reqjson,"coin",symbol); jaddstr(reqjson,"coinaddr",coinaddr); jaddbits256(reqjson,"txid",txid); jaddnum(reqjson,"vout",vout); jaddnum(reqjson,"ht",height); jadd64bits(reqjson,"value",value); LP_peer_request(destip,destport,reqjson); /*char url[512],*retstr,str[65]; if ( (retstr= LP_isitme(destip,destport)) != 0 ) return(retstr); sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&numpeers=%d&session=%u",destip,destport,ipaddr,port,numpeers,sessionid); if ( rmd160str != 0 && bits256_nonz(pub) != 0 ) { sprintf(url+strlen(url),"&rmd160=%s&pub=%s",rmd160str,bits256_str(str,pub)); //printf("SEND (%s)\n",url); } return(LP_issue_curl("notify",destip,destport,url)); //return(issue_curlt(url,LP_HTTP_TIMEOUT));*/ } char *issue_hello(uint16_t port) { char url[512]; sprintf(url,"http://127.0.0.1:%u/api/stats/hello",port); //printf("getutxo.(%s)\n",url); return(issue_curlt(url,600)); // might be starting a trade } void issue_LP_uitem(char *destip,uint16_t destport,char *symbol,char *coinaddr,bits256 txid,int32_t vout,int32_t height,uint64_t value) { cJSON *reqjson = cJSON_CreateObject(); jaddstr(reqjson,"method","uitem"); jaddstr(reqjson,"coin",symbol); jaddstr(reqjson,"coinaddr",coinaddr); jaddbits256(reqjson,"txid",txid); jaddnum(reqjson,"vout",vout); jaddnum(reqjson,"ht",height); jadd64bits(reqjson,"value",value); LP_peer_request(destip,destport,reqjson); /*char url[512],*retstr,str[65]; if ( (retstr= LP_isitme(destip,destport)) != 0 ) return(retstr); sprintf(url,"http://%s:%u/api/stats/uitem?coin=%s&coinaddr=%s&txid=%s&vout=%d&ht=%d&value=%llu",destip,destport,symbol,coinaddr,bits256_str(str,txid),vout,height,(long long)value); retstr = LP_issue_curl("uitem",destip,destport,url); //printf("uitem.(%s)\n",retstr); return(retstr);*/ } /*if ( (liststr= basilisk_swaplist(requestid,quoteid)) != 0 ) { //printf("swapentry.(%s)\n",liststr); if ( (retjson= cJSON_Parse(liststr)) != 0 ) { if ( (array= jarray(&n,retjson,"swaps")) != 0 ) { for (i=0; itimestamp = (uint32_t)time(NULL); ptr->item = item; item->cjsonid = LP_rand(); ptr->cjsonid = item->cjsonid; portable_mutex_lock(&LP_cJSONmutex); DL_APPEND(LP_cJSONlist,ptr); portable_mutex_unlock(&LP_cJSONmutex); } void cJSON_unregister(cJSON *item) { static uint32_t lasttime; int32_t n; char *tmpstr; uint64_t total = 0; struct cJSON_list *ptr,*tmp; uint32_t now; if ( (now= (uint32_t)time(NULL)) > lasttime+6 ) { n = 0; DL_FOREACH_SAFE(LP_cJSONlist,ptr,tmp) { if ( ptr->item != 0 && ptr->item->child != 0 && ptr->cjsonid != 0 ) { if ( (tmpstr= jprint(ptr->item,0)) != 0 ) { total += strlen(tmpstr); free(tmpstr); } } n++; } printf("total %d cJSON pending\n",n); lasttime = (uint32_t)time(NULL); } DL_FOREACH_SAFE(LP_cJSONlist,ptr,tmp) { if ( ptr->cjsonid == item->cjsonid ) break; else if ( now > ptr->timestamp+60 && item->cjsonid != 0 ) { portable_mutex_lock(&LP_cJSONmutex); DL_DELETE(LP_cJSONlist,ptr); portable_mutex_unlock(&LP_cJSONmutex); printf("free expired\n"); cJSON_Delete(ptr->item); free(ptr); } ptr = 0; } if ( ptr != 0 ) { portable_mutex_lock(&LP_cJSONmutex); DL_DELETE(LP_cJSONlist,ptr); free(ptr); portable_mutex_unlock(&LP_cJSONmutex); } //else printf("cJSON_unregister of unknown %p %u\n",item,item->cjsonid); }*/ char *issue_LP_getprices(char *destip,uint16_t destport) { char url[512]; sprintf(url,"http://%s:%u/api/stats/getprices",destip,destport); //printf("getutxo.(%s)\n",url); return(LP_issue_curl("getprices",destip,destport,url)); //return(issue_curlt(url,LP_HTTP_TIMEOUT)); } /*if ( fullflag != 0 ) { if ( (destport= LP_randpeer(destip)) > 0 ) { retstr = issue_LP_listunspent(destip,destport,symbol,coinaddr); //printf("issue %s %s %s -> (%s)\n",coin->symbol,coinaddr,destip,retstr); retjson = cJSON_Parse(retstr); } else printf("LP_listunspent_issue couldnt get a random peer?\n"); }*/ void issue_LP_listunspent(char *destip,uint16_t destport,char *symbol,char *coinaddr) { cJSON *reqjson = cJSON_CreateObject(); jaddstr(reqjson,"method","listunspent"); jaddstr(reqjson,"coin",symbol); jaddstr(reqjson,"address",coinaddr); LP_peer_request(destip,destport,reqjson); /*char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/listunspent?coin=%s&address=%s",destip,destport,symbol,coinaddr); retstr = LP_issue_curl("listunspent",destip,destport,url); //printf("listunspent.(%s) -> (%s)\n",url,retstr); return(retstr);*/ } int32_t LP_utxos_sync(struct LP_peerinfo *peer) { int32_t i,j,n=0,m,v,posted=0; bits256 txid; cJSON *array,*item,*item2,*array2; uint64_t total,total2; struct iguana_info *coin,*ctmp; char *retstr,*retstr2; if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 ) return(0); HASH_ITER(hh,LP_coins,coin,ctmp) { if ( IAMLP == 0 && coin->inactive != 0 ) continue; if ( coin->smartaddr[0] == 0 ) continue; total = 0; if ( (j= LP_listunspent_both(coin->symbol,coin->smartaddr,0)) == 0 ) continue; if ( (array= LP_address_utxos(coin,coin->smartaddr,1)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; i 0 && total > 0 && (retstr= issue_LP_listunspent(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr)) != 0 ) { //printf("UTXO sync.%d %s n.%d total %.8f -> %s (%s)\n",j,coin->symbol,n,dstr(total),peer->ipaddr,retstr); total2 = 0; if ( (array2= cJSON_Parse(retstr)) != 0 ) { if ( (m= cJSON_GetArraySize(array2)) > 0 ) { for (i=0; iipaddr,coin->symbol,jprint(item,0)); issue_LP_uitem(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr,txid,v,jint(item,"height"),j64bits(item,"value")); posted++; } } if ( 0 && posted != 0 ) printf(">>>>>>>> %s compare %s %s (%.8f n%d) (%.8f m%d)\n",peer->ipaddr,coin->symbol,coin->smartaddr,dstr(total),n,dstr(total2),m); } //else printf("%s matches %s\n",peer->ipaddr,coin->symbol); free_json(array2); } else printf("parse error (%s)\n",retstr); free(retstr); } else if ( n != 0 && total != 0 ) { //printf("no response from %s for %s %s\n",peer->ipaddr,coin->symbol,coin->smartaddr); for (i=0; iipaddr,peer->port,coin->symbol,coin->smartaddr,txid,v,jint(item,"height"),j64bits(item,"value")); } } free_json(array); } } return(posted); } /*char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65],str3[65],*retstr; struct _LP_utxoinfo u; uint64_t val,val2; if ( (retstr= LP_isitme(destip,destport)) != 0 ) return(retstr); if ( utxo->iambob == 0 ) { printf("issue_LP_notifyutxo trying to send Alice %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); return(0); } u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) > 0 ) { sprintf(url,"http://%s:%u/api/stats/notified?iambob=%d&pubkey=%s&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u&gui=%s",destip,destport,utxo->iambob,bits256_str(str3,utxo->pubkey),utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL),utxo->gui); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(LP_issue_curl("notifyutxo",destip,destport,url)); //return(issue_curlt(url,LP_HTTP_TIMEOUT)); } else { printf("issue_LP_notifyutxo: ineligible utxo iambob.%d %.8f %.8f\n",utxo->iambob,dstr(val),dstr(val2)); if ( utxo->T.spentflag == 0 ) utxo->T.spentflag = (uint32_t)time(NULL); return(0); } }*/ /*char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) { char url[512],str[65]; sprintf(url,"http://%s:%u/api/stats/lookup?client=%s",destip,destport,bits256_str(str,pubkey)); //printf("getutxo.(%s)\n",url); return(LP_issue_curl("lookup",destip,destport,url)); //return(issue_curlt(url,LP_HTTP_TIMEOUT)); }*/ /*if ( LP_canbind == 0 ) { //printf("check deadman %u vs %u\n",LP_deadman_switch,(uint32_t)time(NULL)); if ( LP_deadman_switch < time(NULL)-PSOCK_KEEPALIVE ) { printf("DEAD man's switch %u activated at %u lag.%d, register forwarding again\n",LP_deadman_switch,(uint32_t)time(NULL),(uint32_t)(time(NULL) - LP_deadman_switch)); if ( pullsock >= 0 ) nn_close(pullsock); pullsock = LP_initpublicaddr(ctx,&mypullport,pushaddr,myipaddr,mypullport,0); LP_deadman_switch = (uint32_t)time(NULL); strcpy(LP_publicaddr,pushaddr); LP_publicport = mypullport; LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,MAX_PSOCK_PORT); } }*/ /*if ( lastforward < now-3600 ) { if ( (retstr= LP_registerall(0)) != 0 ) free(retstr); //LP_forwarding_register(LP_mypubkey,pushaddr,pushport,10); lastforward = now; }*/ //if ( IAMLP != 0 && (counter % 600) == 42 ) // LP_hellos(); /*if ( 0 && LP_canbind == 0 && (counter % (PSOCK_KEEPALIVE*MAINLOOP_PERSEC/2)) == 13 ) { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); //printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); if ( /LP_send(pullsock,keepalive,(int32_t)strlen(keepalive)+1,0) < 0 ) { //LP_deadman_switch = 0; } }*/ /*int32_t nn_tests(void *ctx,int32_t pullsock,char *pushaddr,int32_t nnother) { int32_t sock,n,m,timeout,retval = -1; char msg[512],*retstr; printf("nn_tests.(%s)\n",pushaddr); if ( (sock= nn_socket(AF_SP,nnother)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); else { sleep(3); timeout = 1; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); n = /LP_send(sock,msg,(int32_t)strlen(msg)+1,0); sleep(3); LP_pullsock_check(ctx,&retstr,"127.0.0.1",-1,pullsock,0.); sprintf(msg,"{\"method\":\"nn_tests2\",\"ipaddr\":\"%s\"}",pushaddr); m = /LP_send(pullsock,msg,(int32_t)strlen(msg)+1,0); printf(">>>>>>>>>>>>>>>>>>>>>> sent %d+%d bytes -> pullsock.%d retstr.(%s)\n",n,m,pullsock,retstr!=0?retstr:""); if ( retstr != 0 ) { free(retstr); retval = 0; } } nn_close(sock); } return(retval); }*/ int32_t basilisk_swap_load(uint32_t requestid,uint32_t quoteid,bits256 *privkeyp,struct basilisk_request *rp,uint32_t *statebitsp,int32_t *optiondurationp) { FILE *fp=0; char fname[512]; int32_t retval = -1; sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"rb+")) != 0 ) { if ( fread(privkeyp,1,sizeof(*privkeyp),fp) == sizeof(*privkeyp) && fread(rp,1,sizeof(*rp),fp) == sizeof(*rp) && fread(statebitsp,1,sizeof(*statebitsp),fp) == sizeof(*statebitsp) && fread(optiondurationp,1,sizeof(*optiondurationp),fp) == sizeof(*optiondurationp) ) retval = 0; fclose(fp); } return(retval); } void basilisk_swap_saveupdate(struct basilisk_swap *swap) { FILE *fp; char fname[512]; sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"wb")) != 0 ) { fwrite(&swap->I,1,sizeof(swap->I),fp); /*fwrite(&swap->bobdeposit,1,sizeof(swap->bobdeposit),fp); fwrite(&swap->bobpayment,1,sizeof(swap->bobpayment),fp); fwrite(&swap->alicepayment,1,sizeof(swap->alicepayment),fp); fwrite(&swap->myfee,1,sizeof(swap->myfee),fp); fwrite(&swap->otherfee,1,sizeof(swap->otherfee),fp); fwrite(&swap->aliceclaim,1,sizeof(swap->aliceclaim),fp); fwrite(&swap->alicespend,1,sizeof(swap->alicespend),fp); fwrite(&swap->bobreclaim,1,sizeof(swap->bobreclaim),fp); fwrite(&swap->bobspend,1,sizeof(swap->bobspend),fp); fwrite(&swap->bobrefund,1,sizeof(swap->bobrefund),fp); fwrite(&swap->alicereclaim,1,sizeof(swap->alicereclaim),fp);*/ fwrite(swap->privkeys,1,sizeof(swap->privkeys),fp); fwrite(swap->otherdeck,1,sizeof(swap->otherdeck),fp); fwrite(swap->deck,1,sizeof(swap->deck),fp); fclose(fp); } } void basilisk_swap_sendabort(struct basilisk_swap *swap) { uint32_t msgbits = 0; uint8_t buf[sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2]; int32_t sentbytes,offset=0; memset(buf,0,sizeof(buf)); offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) { if ( sentbytes < 0 ) { if ( swap->pushsock >= 0 ) // nn_close(swap->pushsock), swap->pushsock = -1; if ( swap->subsock >= 0 ) // nn_close(swap->subsock), swap->subsock = -1; swap->connected = 0; } } else printf("basilisk_swap_sendabort\n"); } void basilisk_psockinit(struct basilisk_swap *swap,int32_t amlp); void basilisk_swapgotdata(struct basilisk_swap *swap,uint32_t crc32,bits256 srchash,bits256 desthash,uint32_t quoteid,uint32_t msgbits,uint8_t *data,int32_t datalen,int32_t reinit) { int32_t i; struct basilisk_swapmessage *mp; for (i=0; inummessages; i++) if ( crc32 == swap->messages[i].crc32 && msgbits == swap->messages[i].msgbits && bits256_cmp(srchash,swap->messages[i].srchash) == 0 && bits256_cmp(desthash,swap->messages[i].desthash) == 0 ) return; //printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); swap->messages = realloc(swap->messages,sizeof(*swap->messages) * (swap->nummessages + 1)); mp = &swap->messages[swap->nummessages++]; mp->crc32 = crc32; mp->srchash = srchash; mp->desthash = desthash; mp->msgbits = msgbits; mp->quoteid = quoteid; mp->data = malloc(datalen); mp->datalen = datalen; memcpy(mp->data,data,datalen); if ( reinit == 0 && swap->fp != 0 ) { fwrite(mp,1,sizeof(*mp),swap->fp); fwrite(data,1,datalen,swap->fp); fflush(swap->fp); } } int32_t basilisk_swapget(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(void *ptr,uint8_t *data,int32_t datalen)) { uint8_t *ptr; bits256 srchash,desthash; uint32_t crc32,_msgbits,quoteid; int32_t i,size,offset,retval = -1; struct basilisk_swapmessage *mp = 0; while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) { swap->lasttime = (uint32_t)time(NULL); memset(srchash.bytes,0,sizeof(srchash)); memset(desthash.bytes,0,sizeof(desthash)); //printf("gotmsg.[%d] crc.%x\n",size,crc32); offset = 0; for (i=0; i<32; i++) srchash.bytes[i] = ptr[offset++]; for (i=0; i<32; i++) desthash.bytes[i] = ptr[offset++]; offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),"eid); offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),&_msgbits); if ( size > offset ) { crc32 = calc_crc32(0,&ptr[offset],size-offset); if ( size > offset ) { //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); basilisk_swapgotdata(swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); } } else if ( bits256_nonz(srchash) == 0 && bits256_nonz(desthash) == 0 ) { if ( swap->aborted == 0 ) { swap->aborted = (uint32_t)time(NULL); printf("got abort signal from other side\n"); } } else printf("basilisk_swapget: got strange packet\n"); if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } //char str[65],str2[65]; for (i=0; inummessages; i++) { //printf("%d: %s vs %s\n",i,bits256_str(str,swap->messages[i].srchash),bits256_str(str2,swap->messages[i].desthash)); if ( bits256_cmp(swap->messages[i].desthash,swap->I.myhash) == 0 ) { if ( swap->messages[i].msgbits == msgbits ) { if ( swap->I.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) { printf("nothing received for a while from Bob, try new sockets\n"); if ( swap->pushsock >= 0 ) // nn_close(swap->pushsock), swap->pushsock = -1; if ( swap->subsock >= 0 ) // nn_close(swap->subsock), swap->subsock = -1; swap->connected = 0; basilisk_psockinit(swap,swap->I.iambob != 0); } mp = &swap->messages[i]; if ( msgbits != 0x80000000 ) break; } } } if ( mp != 0 ) retval = (*basilisk_verify_func)(swap,mp->data,mp->datalen); //printf("mine/other %s vs %s\n",bits256_str(str,swap->I.myhash),bits256_str(str2,swap->I.otherhash)); return(retval); } int32_t basilisk_messagekeyread(uint8_t *key,uint32_t *channelp,uint32_t *msgidp,bits256 *srchashp,bits256 *desthashp) { int32_t keylen = 0; keylen += iguana_rwnum(0,&key[keylen],sizeof(uint32_t),channelp); keylen += iguana_rwnum(0,&key[keylen],sizeof(uint32_t),msgidp); keylen += iguana_rwbignum(0,&key[keylen],sizeof(*srchashp),srchashp->bytes); keylen += iguana_rwbignum(0,&key[keylen],sizeof(*desthashp),desthashp->bytes); return(keylen); } int32_t basilisk_messagekey(uint8_t *key,uint32_t channel,uint32_t msgid,bits256 srchash,bits256 desthash) { int32_t keylen = 0; keylen += iguana_rwnum(1,&key[keylen],sizeof(uint32_t),&channel); keylen += iguana_rwnum(1,&key[keylen],sizeof(uint32_t),&msgid); keylen += iguana_rwbignum(1,&key[keylen],sizeof(srchash),srchash.bytes); keylen += iguana_rwbignum(1,&key[keylen],sizeof(desthash),desthash.bytes); return(keylen); } void LP_channelsend(bits256 srchash,bits256 desthash,uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen) { int32_t keylen; uint8_t key[BASILISK_KEYSIZE]; //char *retstr; keylen = basilisk_messagekey(key,channel,msgid,srchash,desthash); //if ( (retstr= _dex_reqsend(myinfo,"DEX",key,keylen,data,datalen)) != 0 ) // free(retstr); } #ifdef adfafds void iguana_ensure_privkey(struct iguana_info *coin,bits256 privkey) { uint8_t pubkey33[33]; struct iguana_waccount *wacct; struct iguana_waddress *waddr,addr; char coinaddr[128]; bitcoin_pubkey33(swap->ctx,pubkey33,privkey); bitcoin_address(coinaddr,coin->pubtype,pubkey33,33); //printf("privkey for (%s)\n",coinaddr); if ( myinfo->expiration != 0 && ((waddr= iguana_waddresssearch(&wacct,coinaddr)) == 0 || bits256_nonz(waddr->privkey) == 0) ) { if ( waddr == 0 ) { memset(&addr,0,sizeof(addr)); iguana_waddresscalc(coin->pubtype,coin->wiftype,&addr,privkey); if ( (wacct= iguana_waccountfind("default")) != 0 ) waddr = iguana_waddressadd(coin,wacct,&addr,0); } if ( waddr != 0 ) { waddr->privkey = privkey; if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->wiftype) > 0 ) { if ( (0) && waddr->wiftype != coin->wiftype ) printf("ensurepriv warning: mismatched wiftype %02x != %02x\n",waddr->wiftype,coin->wiftype); if ( (0) && waddr->addrtype != coin->pubtype ) printf("ensurepriv warning: mismatched addrtype %02x != %02x\n",waddr->addrtype,coin->pubtype); } } } } int32_t basilisk_rawtx_return(struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) { char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) { privkeyarray = cJSON_CreateArray(); jaddistr(privkeyarray,wifstr); if ( (signedtx= LP_signrawtx(rawtx->coin->symbol,&rawtx->I.signedtxid,&rawtx->I.completed,vins,txbytes,privkeyarray,V)) != 0 ) { if ( lockinputs != 0 ) { //printf("lockinputs\n"); LP_unspentslock(rawtx->coin->symbol,vins); if ( (n= cJSON_GetArraySize(vins)) != 0 ) { bits256 txid; int32_t vout; for (i=0; iI.datalen = (int32_t)strlen(signedtx) >> 1; //rawtx->txbytes = calloc(1,rawtx->I.datalen); decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); //printf("%s SIGNEDTX.(%s)\n",rawtx->name,signedtx); free(signedtx); retval = 0; } else printf("error signrawtx\n"); //do a very short timeout so it finishes via local poll free_json(privkeyarray); } return(retval); } #endif cJSON *LP_createvins(struct basilisk_rawtx *dest,struct vin_info *V,struct basilisk_rawtx *rawtx,uint8_t *userdata,int32_t userdatalen,uint32_t sequenceid) { cJSON *vins,*item,*sobj; char hexstr[8192]; vins = cJSON_CreateArray(); item = cJSON_CreateObject(); if ( userdata != 0 && userdatalen > 0 ) { memcpy(V[0].userdata,userdata,userdatalen); V[0].userdatalen = userdatalen; init_hexbytes_noT(hexstr,userdata,userdatalen); jaddstr(item,"userdata",hexstr); #ifdef DISABLE_CHECKSIG needsig = 0; #endif } //printf("rawtx B\n"); if ( bits256_nonz(rawtx->I.actualtxid) != 0 ) jaddbits256(item,"txid",rawtx->I.actualtxid); else jaddbits256(item,"txid",rawtx->I.signedtxid); jaddnum(item,"vout",0); //sobj = cJSON_CreateObject(); init_hexbytes_noT(hexstr,rawtx->spendscript,rawtx->I.spendlen); //jaddstr(sobj,"hex",hexstr); //jadd(item,"scriptPubKey",sobj); jaddstr(item,"scriptPubKey",hexstr); jaddnum(item,"suppress",dest->I.suppress_pubkeys); jaddnum(item,"sequence",sequenceid); if ( (dest->I.redeemlen= rawtx->I.redeemlen) != 0 ) { init_hexbytes_noT(hexstr,rawtx->redeemscript,rawtx->I.redeemlen); memcpy(dest->redeemscript,rawtx->redeemscript,rawtx->I.redeemlen); jaddstr(item,"redeemScript",hexstr); } jaddi(vins,item); return(vins); } int32_t _basilisk_rawtx_gen(char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey) { char scriptstr[1024],wifstr[256],coinaddr[64],*signedtx,*rawtxbytes; uint32_t basilisktag; int32_t retval = -1; cJSON *vins,*privkeys,*addresses,*valsobj; struct vin_info *V; init_hexbytes_noT(scriptstr,script,scriptlen); basilisktag = (uint32_t)LP_rand(); valsobj = cJSON_CreateObject(); jaddstr(valsobj,"coin",rawtx->coin->symbol); jaddstr(valsobj,"spendscript",scriptstr); jaddstr(valsobj,"changeaddr",rawtx->coin->smartaddr); jadd64bits(valsobj,"satoshis",rawtx->I.amount); if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) txfee = 50000; jadd64bits(valsobj,"txfee",txfee); jaddnum(valsobj,"minconf",minconf); if ( locktime == 0 ) locktime = (uint32_t)time(NULL) - 777; jaddnum(valsobj,"locktime",locktime); jaddnum(valsobj,"timeout",30000); jaddnum(valsobj,"timestamp",swapstarted+delay); addresses = cJSON_CreateArray(); bitcoin_address(coinaddr,rawtx->coin->pubtype,pubkey33,33); jaddistr(addresses,coinaddr); jadd(valsobj,"addresses",addresses); rawtx->I.locktime = locktime; printf("%s locktime.%u\n",rawtx->name,locktime); V = calloc(256,sizeof(*V)); privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,privkey,rawtx->coin->wiftype); jaddistr(privkeys,wifstr); vins = LP_createvins(rawtx,V,rawtx,0,0,0xffffffff); rawtx->vins = jduplicate(vins); jdelete(valsobj,"vin"); jadd(valsobj,"vin",vins); if ( (rawtxbytes= bitcoin_json2hex(rawtx->coin->isPoS,&rawtx->I.txid,valsobj,V)) != 0 ) { //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); if ( (signedtx= LP_signrawtx(rawtx->coin->symbol,&rawtx->I.signedtxid,&rawtx->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); else printf("DEX tx is too big %d vs %d\n",rawtx->I.datalen,(int32_t)sizeof(rawtx->txbytes)); if ( signedtx != rawtxbytes ) free(signedtx); if ( rawtx->I.completed != 0 ) retval = 0; else printf("couldnt complete sign transaction %s\n",rawtx->name); } else printf("error signing\n"); free(rawtxbytes); } else printf("error making rawtx\n"); free_json(privkeys); free_json(valsobj); free(V); return(retval); } int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,uint32_t timestamp,uint32_t locktime,uint32_t sequenceid,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) { char *rawtxbytes=0,*signedtx=0,wifstr[128]; cJSON *txobj,*vins,*privkeys; int32_t needsig=1,retval = -1; struct vin_info *V; V = calloc(256,sizeof(*V)); V[0].signers[0].privkey = privkey; bitcoin_pubkey33(swap->ctx,V[0].signers[0].pubkey,privkey); privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,privkey,wiftype); jaddistr(privkeys,wifstr); if ( privkey2 != 0 ) { V[0].signers[1].privkey = *privkey2; bitcoin_pubkey33(swap->ctx,V[0].signers[1].pubkey,*privkey2); bitcoin_priv2wif(wifstr,*privkey2,wiftype); jaddistr(privkeys,wifstr); V[0].N = V[0].M = 2; //char str[65]; printf("add second privkey.(%s) %s\n",jprint(privkeys,0),bits256_str(str,*privkey2)); } else V[0].N = V[0].M = 1; V[0].suppress_pubkeys = dest->I.suppress_pubkeys; V[0].ignore_cltverr = ignore_cltverr; if ( dest->I.redeemlen != 0 ) memcpy(V[0].p2shscript,dest->redeemscript,dest->I.redeemlen), V[0].p2shlen = dest->I.redeemlen; txobj = bitcoin_txcreate(symbol,isPoS,locktime,userdata == 0 ? 1 : 1,timestamp);//rawtx->coin->locktime_txversion); vins = LP_createvins(dest,V,rawtx,userdata,userdatalen,sequenceid); jdelete(txobj,"vin"); jadd(txobj,"vin",vins); //printf("basilisk_rawtx_sign locktime.%u/%u for %s spendscript.%s -> %s, suppress.%d\n",rawtx->I.locktime,dest->I.locktime,rawtx->name,hexstr,dest->name,dest->I.suppress_pubkeys); txobj = bitcoin_txoutput(txobj,dest->spendscript,dest->I.spendlen,dest->I.amount); if ( (rawtxbytes= bitcoin_json2hex(isPoS,&dest->I.txid,txobj,V)) != 0 ) { //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); if ( needsig == 0 ) signedtx = rawtxbytes; if ( signedtx != 0 || (signedtx= LP_signrawtx(symbol,&dest->I.signedtxid,&dest->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) { dest->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( dest->I.datalen <= sizeof(dest->txbytes) ) decode_hex(dest->txbytes,dest->I.datalen,signedtx); else printf("DEX tx is too big %d vs %d\n",dest->I.datalen,(int32_t)sizeof(dest->txbytes)); if ( signedtx != rawtxbytes ) free(signedtx); if ( dest->I.completed != 0 ) retval = 0; else printf("couldnt complete sign transaction %s\n",rawtx->name); } else printf("error signing\n"); free(rawtxbytes); } else printf("error making rawtx\n"); free_json(privkeys); free_json(txobj); free(V); return(retval); } int32_t basilisk_process_swapverify(void *ptr,int32_t (*internal_func)(void *ptr,uint8_t *data,int32_t datalen),uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen,uint32_t expiration,uint32_t duration) { struct basilisk_swap *swap = ptr; if ( internal_func != 0 ) return((*internal_func)(swap,data,datalen)); else return(0); } int32_t basilisk_priviextract(struct iguana_info *coin,char *name,bits256 *destp,uint8_t secret160[20],bits256 srctxid,int32_t srcvout) { /*bits256 txid; char str[65]; int32_t i,vini,scriptlen; uint8_t rmd160[20],scriptsig[IGUANA_MAXSCRIPTSIZE]; memset(privkey.bytes,0,sizeof(privkey)); // use dex_listtransactions! if ( (vini= iguana_vinifind(coin,&txid,srctxid,srcvout)) >= 0 ) { if ( (scriptlen= iguana_scriptsigextract(coin,scriptsig,sizeof(scriptsig),txid,vini)) > 32 ) { for (i=0; i<32; i++) privkey.bytes[i] = scriptsig[scriptlen - 33 + i]; revcalc_rmd160_sha256(rmd160,privkey);//.bytes,sizeof(privkey)); if ( memcmp(secret160,rmd160,sizeof(rmd160)) == sizeof(rmd160) ) { *destp = privkey; printf("basilisk_priviextract found privi %s (%s)\n",name,bits256_str(str,privkey)); return(0); } } }*/ return(-1); } int32_t basilisk_verify_privi(void *ptr,uint8_t *data,int32_t datalen); int32_t basilisk_privBn_extract(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { if ( basilisk_priviextract(&swap->bobcoin,"privBn",&swap->I.privBn,swap->I.secretBn,swap->bobrefund.I.actualtxid,0) == 0 ) { printf("extracted privBn from blockchain\n"); } else if ( basilisk_swapget(swap,0x40000000,data,maxlen,basilisk_verify_privi) == 0 ) { } if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) { char str[65]; printf("got privBn.%s\n",bits256_str(str,swap->I.privBn)); return(basilisk_alicepayment_spend(swap,&swap->alicereclaim)); } return(-1); } int32_t basilisk_privAm_extract(struct basilisk_swap *swap) { if ( basilisk_priviextract(&swap->bobcoin,"privAm",&swap->I.privAm,swap->I.secretAm,swap->bobpayment.I.actualtxid,0) == 0 ) { printf("extracted privAm from blockchain\n"); } if ( bits256_nonz(swap->I.privAm) != 0 && swap->bobspend.I.datalen == 0 ) { char str[65]; printf("got privAm.%s\n",bits256_str(str,swap->I.privAm)); return(basilisk_alicepayment_spend(swap,&swap->bobspend)); } return(-1); } int32_t basilisk_verify_otherstatebits(void *ptr,uint8_t *data,int32_t datalen) { int32_t retval; struct basilisk_swap *swap = ptr; if ( datalen == sizeof(swap->I.otherstatebits) ) { retval = iguana_rwnum(0,data,sizeof(swap->I.otherstatebits),&swap->I.otherstatebits); return(retval); } else return(-1); } int32_t basilisk_verify_statebits(void *ptr,uint8_t *data,int32_t datalen) { int32_t retval = -1; uint32_t statebits; struct basilisk_swap *swap = ptr; if ( datalen == sizeof(swap->I.statebits) ) { retval = iguana_rwnum(0,data,sizeof(swap->I.statebits),&statebits); if ( statebits != swap->I.statebits ) { printf("statebits.%x != %x\n",statebits,swap->I.statebits); return(-1); } } return(retval); } void basilisk_sendstate(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t datalen=0; datalen = iguana_rwnum(1,data,sizeof(swap->I.statebits),&swap->I.statebits); LP_swapsend(swap,0x80000000,data,datalen,0,0); } int32_t basilisk_swapiteration(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t j,datalen,retval = 0; uint32_t savestatebits=0,saveotherbits=0; if ( swap->I.iambob != 0 ) swap->I.statebits |= 0x80; while ( swap->aborted == 0 && ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) { if ( swap->connected == 0 ) basilisk_psockinit(swap,swap->I.iambob != 0); printf("D r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); if ( swap->I.iambob != 0 && (swap->I.statebits & 0x80) == 0 ) // wait for fee { if ( basilisk_swapget(swap,0x80,data,maxlen,basilisk_verify_otherfee) == 0 ) { // verify and submit otherfee swap->I.statebits |= 0x80; basilisk_sendstate(swap,data,maxlen); } } else if ( swap->I.iambob == 0 ) swap->I.statebits |= 0x80; basilisk_sendstate(swap,data,maxlen); basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); if ( (swap->I.otherstatebits & 0x80) != 0 && (swap->I.statebits & 0x80) != 0 ) break; if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); basilisk_sendstate(swap,data,maxlen); if ( (swap->I.otherstatebits & 0x80) == 0 ) LP_swapdata_rawtxsend(swap,0x80,data,maxlen,&swap->myfee,0x40,0); } basilisk_swap_saveupdate(swap); while ( swap->aborted == 0 && retval == 0 && time(NULL) < swap->I.expiration ) // both sides have setup required data and paid txfee { basilisk_swap_saveupdate(swap); if ( swap->connected == 0 ) basilisk_psockinit(swap,swap->I.iambob != 0); //if ( (LP_rand() % 30) == 0 ) printf("E r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); if ( swap->I.iambob != 0 ) { //printf("BOB\n"); if ( (swap->I.statebits & 0x100) == 0 ) { printf("send bobdeposit\n"); swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0); } // [BLOCKING: altfound] make sure altpayment is confirmed and send payment else if ( (swap->I.statebits & 0x1000) == 0 ) { printf("check alicepayment\n"); if ( basilisk_swapget(swap,0x1000,data,maxlen,basilisk_verify_alicepaid) == 0 ) { swap->I.statebits |= 0x1000; printf("got alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); } } else if ( (swap->I.statebits & 0x2000) == 0 ) { if ( (swap->I.aliceconfirms == 0 && swap->aliceunconf != 0) || LP_numconfirms(swap,&swap->alicepayment,1) >= swap->I.aliceconfirms ) { swap->I.statebits |= 0x2000; printf("alicepayment confirmed\n"); } } else if ( (swap->I.statebits & 0x4000) == 0 ) { basilisk_bobscripts_set(swap,0,1); printf("send bobpayment\n"); swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0); } // [BLOCKING: privM] Bob waits for privAm either from Alice or alice blockchain else if ( (swap->I.statebits & 0xc0000) != 0xc0000 ) { if ( basilisk_swapget(swap,0x40000,data,maxlen,basilisk_verify_privi) == 0 || basilisk_privAm_extract(swap) == 0 ) // divulges privAm { //printf("got privi spend alicepayment, dont divulge privBn until bobspend propagated\n"); basilisk_alicepayment_spend(swap,&swap->bobspend); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobspend,0x40000,1) == 0 ) printf("Bob error spending alice payment\n"); else { tradebot_swap_balancingtrade(swap,1); printf("Bob spends alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); swap->I.statebits |= 0x40000; if ( LP_numconfirms(swap,&swap->bobspend,1) >= swap->I.aliceconfirms ) { printf("bobspend confirmed\n"); swap->I.statebits |= 0x80000; printf("Bob confirming spend of Alice's payment\n"); sleep(DEX_SLEEP); } retval = 1; } } } if ( swap->bobpayment.I.locktime != 0 && time(NULL) > swap->bobpayment.I.locktime ) { // submit reclaim of payment printf("bob reclaims bobpayment\n"); swap->I.statebits |= (0x40000 | 0x80000); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobreclaim,0,0) == 0 ) printf("Bob error reclaiming own payment after alice timed out\n"); else { printf("Bob reclaimed own payment\n"); while ( 0 && (swap->I.statebits & 0x100000) == 0 ) // why wait for own tx? { if ( LP_numconfirms(swap,&swap->bobreclaim,1) >= 1 ) { printf("bobreclaim confirmed\n"); swap->I.statebits |= 0x100000; printf("Bob confirms reclain of payment\n"); break; } } retval = 1; } } } else { //printf("ALICE\n"); // [BLOCKING: depfound] Alice waits for deposit to confirm and sends altpayment if ( (swap->I.statebits & 0x200) == 0 ) { printf("checkfor deposit\n"); if ( basilisk_swapget(swap,0x200,data,maxlen,basilisk_verify_bobdeposit) == 0 ) { // verify deposit and submit, set confirmed height printf("got bobdeposit\n"); swap->I.statebits |= 0x200; } else printf("no valid deposit\n"); } else if ( (swap->I.statebits & 0x400) == 0 ) { if ( basilisk_istrustedbob(swap) != 0 || (swap->I.bobconfirms == 0 && swap->depositunconf != 0) || LP_numconfirms(swap,&swap->bobdeposit,1) >= swap->I.bobconfirms ) { printf("bobdeposit confirmed\n"); swap->I.statebits |= 0x400; } } else if ( (swap->I.statebits & 0x800) == 0 ) { printf("send alicepayment\n"); swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0); } // [BLOCKING: payfound] make sure payment is confrmed and send in spend or see bob's reclaim and claim else if ( (swap->I.statebits & 0x8000) == 0 ) { if ( basilisk_swapget(swap,0x8000,data,maxlen,basilisk_verify_bobpaid) == 0 ) { printf("got bobpayment\n"); tradebot_swap_balancingtrade(swap,0); // verify payment and submit, set confirmed height swap->I.statebits |= 0x8000; } } else if ( (swap->I.statebits & 0x10000) == 0 ) { if ( basilisk_istrustedbob(swap) != 0 || (swap->I.bobconfirms == 0 && swap->paymentunconf != 0) || LP_numconfirms(swap,&swap->bobpayment,1) >= swap->I.bobconfirms ) { printf("bobpayment confirmed\n"); swap->I.statebits |= 0x10000; } } else if ( (swap->I.statebits & 0x20000) == 0 ) { printf("alicespend bobpayment\n"); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->alicespend,0x20000,0) != 0 )//&& (swap->aliceunconf != 0 || basilisk_numconfirms(swap,&swap->alicespend) > 0) ) { swap->I.statebits |= 0x20000; } } else if ( (swap->I.statebits & 0x40000) == 0 ) { int32_t numconfs; if ( (numconfs= LP_numconfirms(swap,&swap->alicespend,1)) >= swap->I.bobconfirms ) { for (j=datalen=0; j<32; j++) data[datalen++] = swap->I.privAm.bytes[j]; printf("send privAm %x\n",swap->I.statebits); swap->I.statebits |= LP_swapsend(swap,0x40000,data,datalen,0x20000,swap->I.crcs_mypriv); printf("Alice confirms spend of Bob's payment\n"); retval = 1; } else printf("alicespend numconfs.%d < %d\n",numconfs,swap->I.bobconfirms); } if ( swap->bobdeposit.I.locktime != 0 && time(NULL) > swap->bobdeposit.I.locktime ) { printf("Alice claims deposit\n"); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->aliceclaim,0,0) == 0 ) printf("Alice couldnt claim deposit\n"); else { printf("Alice claimed deposit\n"); retval = 1; } } else if ( swap->aborted != 0 || basilisk_privBn_extract(swap,data,maxlen) == 0 ) { printf("Alice reclaims her payment\n"); swap->I.statebits |= 0x40000000; if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->alicereclaim,0x40000000,0) == 0 ) printf("Alice error sending alicereclaim\n"); else { printf("Alice reclaimed her payment\n"); retval = 1; } } } if ( (LP_rand() % 30) == 0 ) printf("finished swapstate.%x other.%x\n",swap->I.statebits,swap->I.otherstatebits); if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; basilisk_sendstate(swap,data,maxlen); basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); } return(retval); } int32_t swapcompleted(struct basilisk_swap *swap) { if ( swap->I.iambob != 0 ) return(swap->I.bobspent); else return(swap->I.alicespent); } cJSON *swapjson(struct basilisk_swap *swap) { cJSON *retjson = cJSON_CreateObject(); return(retjson); } int32_t basilisk_rwDEXquote(int32_t rwflag,uint8_t *serialized,struct basilisk_request *rp) { int32_t len = 0; len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->requestid),&rp->requestid); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->timestamp),&rp->timestamp); // must be 2nd len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->quoteid),&rp->quoteid); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->quotetime),&rp->quotetime); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->optionhours),&rp->optionhours); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->srcamount),&rp->srcamount); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->unused),&rp->unused); len += iguana_rwbignum(rwflag,&serialized[len],sizeof(rp->srchash),rp->srchash.bytes); len += iguana_rwbignum(rwflag,&serialized[len],sizeof(rp->desthash),rp->desthash.bytes); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->destamount),&rp->destamount); if ( rwflag != 0 ) { memcpy(&serialized[len],rp->src,sizeof(rp->src)), len += sizeof(rp->src); memcpy(&serialized[len],rp->dest,sizeof(rp->dest)), len += sizeof(rp->dest); } else { memcpy(rp->src,&serialized[len],sizeof(rp->src)), len += sizeof(rp->src); memcpy(rp->dest,&serialized[len],sizeof(rp->dest)), len += sizeof(rp->dest); } //len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->DEXselector),&rp->DEXselector); //len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->extraspace),&rp->extraspace); if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) printf(" basilisk_rwDEXquote.%d: quoteid.%u mismatch calc %u rp.%p\n",rwflag,rp->quoteid,basilisk_quoteid(rp),rp); if ( basilisk_requestid(rp) != rp->requestid ) printf(" basilisk_rwDEXquote.%d: requestid.%u mismatch calc %u rp.%p\n",rwflag,rp->requestid,basilisk_requestid(rp),rp); return(len); } struct basilisk_request *basilisk_parsejson(struct basilisk_request *rp,cJSON *reqjson) { uint32_t requestid,quoteid; memset(rp,0,sizeof(*rp)); rp->srchash = jbits256(reqjson,"srchash"); rp->desthash = jbits256(reqjson,"desthash"); rp->srcamount = j64bits(reqjson,"srcamount"); //rp->minamount = j64bits(reqjson,"minamount"); //rp->destamount = j64bits(reqjson,"destamount"); rp->destamount = j64bits(reqjson,"destsatoshis"); //printf("parse DESTSATOSHIS.%llu (%s)\n",(long long)rp->destamount,jprint(reqjson,0)); requestid = juint(reqjson,"requestid"); quoteid = juint(reqjson,"quoteid"); //if ( jstr(reqjson,"relay") != 0 ) // rp->relaybits = (uint32_t)calc_ipbits(jstr(reqjson,"relay")); rp->timestamp = juint(reqjson,"timestamp"); rp->quotetime = juint(reqjson,"quotetime"); safecopy(rp->src,jstr(reqjson,"src"),sizeof(rp->src)); safecopy(rp->dest,jstr(reqjson,"dest"),sizeof(rp->dest)); if ( quoteid != 0 ) { rp->quoteid = basilisk_quoteid(rp); if ( quoteid != rp->quoteid ) printf("basilisk_parsejson quoteid.%u != %u error\n",quoteid,rp->quoteid); } rp->requestid = basilisk_requestid(rp); if ( requestid != rp->requestid ) { int32_t i; for (i=0; irequestid); } return(rp); } cJSON *basilisk_requestjson(struct basilisk_request *rp) { cJSON *item = cJSON_CreateObject(); /*if ( rp->relaybits != 0 ) { expand_ipbits(ipaddr,rp->relaybits); jaddstr(item,"relay",ipaddr); }*/ jaddbits256(item,"srchash",rp->srchash); if ( bits256_nonz(rp->desthash) != 0 ) jaddbits256(item,"desthash",rp->desthash); jaddstr(item,"src",rp->src); if ( rp->srcamount != 0 ) jadd64bits(item,"srcamount",rp->srcamount); //if ( rp->minamount != 0 ) // jadd64bits(item,"minamount",rp->minamount); jaddstr(item,"dest",rp->dest); if ( rp->destamount != 0 ) { //jadd64bits(item,"destamount",rp->destamount); jadd64bits(item,"destsatoshis",rp->destamount); //printf("DESTSATOSHIS.%llu\n",(long long)rp->destamount); } jaddnum(item,"quotetime",rp->quotetime); jaddnum(item,"timestamp",rp->timestamp); jaddnum(item,"requestid",rp->requestid); jaddnum(item,"quoteid",rp->quoteid); //jaddnum(item,"DEXselector",rp->DEXselector); jaddnum(item,"optionhours",rp->optionhours); //jaddnum(item,"profit",(double)rp->profitmargin / 1000000.); if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) printf("quoteid mismatch %u vs %u\n",basilisk_quoteid(rp),rp->quoteid); if ( basilisk_requestid(rp) != rp->requestid ) printf("requestid mismatch %u vs calc %u\n",rp->requestid,basilisk_requestid(rp)); { int32_t i; struct basilisk_request R; if ( basilisk_parsejson(&R,item) != 0 ) { if ( memcmp(&R,rp,sizeof(*rp)-sizeof(uint32_t)) != 0 ) { for (i=0; iI.req.requestid); jaddnum(item,"quoteid",swap->I.req.quoteid); jaddnum(item,"state",swap->I.statebits); jaddnum(item,"otherstate",swap->I.otherstatebits); jadd(item,"request",basilisk_requestjson(&swap->I.req)); return(item); } #ifdef later cJSON *basilisk_privkeyarray(struct iguana_info *coin,cJSON *vins) { cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],typestr[64],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; double bidasks[2]; privkeyarray = cJSON_CreateArray(); if ( (n= cJSON_GetArraySize(vins)) > 0 ) { for (i=0; i= 0 ) { iguana_txidcategory(coin,account,coinaddr,txid,vout); if ( coinaddr[0] == 0 && (sobj= jobj(item,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 && is_hexstr(hexstr,0) > 0 ) { len = (int32_t)strlen(hexstr) >> 1; if ( len < (sizeof(script) << 1) ) { decode_hex(script,len,hexstr); if ( len == 25 && script[0] == 0x76 && script[1] == 0xa9 && script[2] == 0x14 ) bitcoin_address(coinaddr,coin->chain->pubtype,script+3,20); } } if ( coinaddr[0] != 0 ) { if ( (waddr= iguana_waddresssearch(&wacct,coinaddr)) != 0 ) { bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype); jaddistr(privkeyarray,waddr->wifstr); } else if ( smartaddress(typestr,bidasks,&privkey,coin->symbol,coinaddr) >= 0 ) { bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeyarray,wifstr); } else printf("cant find (%s) in wallet\n",coinaddr); } else printf("cant coinaddr from (%s).v%d\n",bits256_str(str,txid),vout); } else printf("invalid txid/vout %d of %d\n",i,n); } } return(privkeyarray); } #endif #ifdef old void basilisk_swaploop(void *_utxo) { uint8_t *data; uint32_t expiration,savestatebits=0,saveotherbits=0; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; swap = utxo->swap; fprintf(stderr,"start swap iambob.%d\n",swap->I.iambob); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + 300; //myinfo->DEXactive = expiration; channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) { LP_channelsend(swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); if ( swap->connected == 0 ) basilisk_psockinit(swap,swap->I.iambob != 0); if ( swap->connected > 0 ) { printf("A r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); basilisk_sendstate(swap,data,maxlen); basilisk_sendpubkeys(swap,data,maxlen); // send pubkeys if ( basilisk_checkdeck(swap,data,maxlen) == 0) // check for other deck 0x02 basilisk_sendchoosei(swap,data,maxlen); basilisk_waitchoosei(swap,data,maxlen); // wait for choosei 0x08 if ( (swap->I.statebits & (0x08|0x02)) == (0x08|0x02) ) break; } if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; } if ( swap->connected == 0 ) { printf("couldnt establish connection\n"); retval = -1; } while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 ) { if ( swap->connected == 0 ) basilisk_psockinit(swap,swap->I.iambob != 0); printf("B r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); basilisk_sendstate(swap,data,maxlen); basilisk_sendchoosei(swap,data,maxlen); basilisk_sendmostprivs(swap,data,maxlen); if ( basilisk_swapget(swap,0x20,data,maxlen,basilisk_verify_privkeys) == 0 ) { swap->I.statebits |= 0x20; break; } if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; if ( time(NULL) > expiration ) break; } //myinfo->DEXactive = swap->I.expiration; if ( time(NULL) >= expiration ) { retval = -1; //myinfo->DEXactive = 0; } if ( swap->aborted != 0 ) { printf("swap aborted before tx sent\n"); retval = -1; } printf("C r%u/q%u swapstate.%x retval.%d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,retval); iters = 0; while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x40) == 0 && iters++ < 10 ) // send fee { if ( swap->connected == 0 ) basilisk_psockinit(swap,swap->I.iambob != 0); //printf("sendstate.%x\n",swap->I.statebits); basilisk_sendstate(swap,data,maxlen); //printf("swapget\n"); basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); //printf("after swapget\n"); if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) { printf("bobscripts set\n"); if ( basilisk_bobscripts_set(swap,1,1) < 0 ) { sleep(DEX_SLEEP); printf("bobscripts set error\n"); continue; } } if ( swap->I.iambob == 0 ) { /*for (i=0; i<20; i++) printf("%02x",swap->secretAm[i]); printf(" <- secretAm\n"); for (i=0; i<32; i++) printf("%02x",swap->secretAm256[i]); printf(" <- secretAm256\n"); for (i=0; i<32; i++) printf("%02x",swap->pubAm.bytes[i]); printf(" <- pubAm\n"); for (i=0; i<20; i++) printf("%02x",swap->secretBn[i]); printf(" <- secretBn\n"); for (i=0; i<32; i++) printf("%02x",swap->secretBn256[i]); printf(" <- secretBn256\n"); for (i=0; i<32; i++) printf("%02x",swap->pubBn.bytes[i]); printf(" <- pubBn\n"); for (i=0; i<32; i++) printf("%02x",swap->pubA0.bytes[i]); printf(" <- pubA0\n"); for (i=0; i<32; i++) printf("%02x",swap->pubA1.bytes[i]); printf(" <- pubA1\n"); for (i=0; i<32; i++) printf("%02x",swap->pubB0.bytes[i]); printf(" <- pubB0\n"); for (i=0; i<32; i++) printf("%02x",swap->pubB1.bytes[i]); printf(" <- pubB1\n");*/ if ( (retval= basilisk_alicetxs(swap,data,maxlen)) != 0 ) { printf("basilisk_alicetxs error\n"); break; } } } if ( swap->I.iambob == 0 && (swap->I.statebits & 0x40) == 0 ) { printf("couldnt send fee\n"); retval = -8; } if ( retval == 0 ) { if ( swap->I.iambob == 0 && (swap->myfee.I.datalen == 0 || swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.datalen == 0) ) { printf("ALICE's error %d %d %d\n",swap->myfee.I.datalen,swap->alicepayment.I.datalen,swap->alicepayment.I.datalen); retval = -7; } else if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) //swap->bobpayment.I.datalen == 0 { printf("BOB's error %d %d %d\n",swap->myfee.I.datalen,swap->bobpayment.I.datalen,swap->bobdeposit.I.datalen); retval = -7; } } while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(swap,data,maxlen) == 0 ) { if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; basilisk_sendstate(swap,data,maxlen); basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); basilisk_swap_saveupdate(swap); if ( time(NULL) > swap->I.expiration ) break; } if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen != 0 && bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) { printf("BOB waiting for confirm state.%x\n",swap->I.statebits); sleep(60); // wait for confirm/propagation of msig printf("BOB reclaims refund\n"); basilisk_bobdeposit_refund(swap,0); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobrefund,0x40000000,0) == 0 ) // use secretBn { printf("Bob submit error getting refund of deposit\n"); } else { // maybe wait for bobrefund to be confirmed for (j=datalen=0; j<32; j++) data[datalen++] = swap->I.privBn.bytes[j]; LP_swapsend(swap,0x40000000,data,datalen,0x40000000,swap->I.crcs_mypriv); } basilisk_swap_saveupdate(swap); } if ( retval != 0 ) basilisk_swap_sendabort(swap); printf("end of atomic swap\n"); if ( swapcompleted(swap) > 0 ) // only if swap completed { if ( swap->I.iambob != 0 ) tradebot_pendingadd(swapjson(swap),swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); else tradebot_pendingadd(swapjson(swap),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.src,dstr(swap->I.req.srcamount)); } printf("%s swap finished statebits %x\n",swap->I.iambob!=0?"BOB":"ALICE",swap->I.statebits); basilisk_swap_purge(swap); free(data); } #endif int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct iguana_info **alicecoinp,char *src,char *dest,bits256 srchash,bits256 desthash) { struct iguana_info *coin = LP_coinfind(src); if ( coin == 0 || LP_coinfind(dest) == 0 ) return(0); *bobcoinp = *alicecoinp = 0; *bobcoinp = LP_coinfind(dest); *alicecoinp = LP_coinfind(src); if ( bits256_cmp(pubkey,srchash) == 0 ) { if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) return(1); else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) return(-1); else return(0); } else if ( bits256_cmp(pubkey,desthash) == 0 ) { if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) return(-1); else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) return(1); else return(0); } return(0); } /*void basilisk_swap_purge(struct basilisk_swap *swap) { int32_t i,n; // while still in orderbook, wait //return; portable_mutex_lock(&myinfo->DEX_swapmutex); n = myinfo->numswaps; for (i=0; iswaps[i] == swap ) { myinfo->swaps[i] = myinfo->swaps[--myinfo->numswaps]; myinfo->swaps[myinfo->numswaps] = 0; basilisk_swap_finished(swap); break; } portable_mutex_unlock(&myinfo->DEX_swapmutex); }*/ /*if ( bits256_nonz(Q.srchash) == 0 || bits256_cmp(Q.srchash,G.LP_mypub25519) == 0 || strcmp(butxo->coinaddr,coin->smartaddr) != 0 || bits256_nonz(butxo->payment.txid) == 0 || bits256_nonz(butxo->deposit.txid) == 0 ) { qprice = (double)Q.destsatoshis / Q.satoshis; strcpy(Q.gui,G.gui); strcpy(Q.coinaddr,coin->smartaddr); strcpy(butxo->coinaddr,coin->smartaddr); Q.srchash = G.LP_mypub25519; memset(&Q.txid,0,sizeof(Q.txid)); memset(&Q.txid2,0,sizeof(Q.txid2)); Q.vout = Q.vout2 = -1; recalc = 1; } else if ( (qprice= LP_quote_validate(autxo,butxo,&Q,1)) < SMALLVAL ) recalc = 1; else if ( price < qprice ) { char tmp[64]; if ( bits256_nonz(Q.txid) != 0 ) LP_utxos_remove(Q.txid,Q.vout); else recalc = 1; if ( bits256_nonz(Q.txid2) != 0 ) LP_utxos_remove(Q.txid2,Q.vout2); else recalc = 1; //printf("price %.8f qprice %.8f\n",price,qprice); if ( recalc == 0 ) { value = LP_txvalue(tmp,Q.srccoin,Q.txid,Q.vout); value2 = LP_txvalue(tmp,Q.srccoin,Q.txid2,Q.vout2); //printf("call LP_utxoadd.(%s) %.8f %.8f\n",Q.coinaddr,dstr(value),dstr(value2)); if ( (butxo= LP_utxoadd(1,coin->symbol,Q.txid,Q.vout,value,Q.txid2,Q.vout2,value2,Q.coinaddr,Q.srchash,G.gui,0,Q.satoshis)) == 0 ) recalc = 1; else if ( bits256_cmp(Q.txid,butxo->payment.txid) != 0 || Q.vout != butxo->payment.vout || bits256_cmp(Q.txid2,butxo->deposit.txid) != 0 || Q.vout2 != butxo->deposit.vout ) recalc = 1; } } else return(retval);*/ /*int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double origprice) { double price,bid,ask; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; if ( (now= (uint32_t)time(NULL)) > utxo->T.swappending && utxo->S.swap == 0 ) utxo->T.swappending = 0; if ( now > utxo->T.published+60 && LP_isavailable(utxo) && (price= LP_myprice(&bid,&ask,utxo->coin,rel)) != 0. ) { if ( origprice < price ) price = origprice; if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); Q.timestamp = (uint32_t)time(NULL); retjson = LP_quotejson(&Q); jaddstr(retjson,"method","quote"); retstr = jprint(retjson,1); //printf("PING.(%s)\n",retstr); if ( pubsock >= 0 ) LP_send(pubsock,retstr,1); else { // verify it is in list // push if it isnt } utxo->T.published = now; return(0); } return(-1); }*/ /*if ( (butxo= LP_utxopairfind(1,Q.txid,Q.vout,Q.txid2,Q.vout2)) == 0 ) { value = LP_txvalue(Q.coinaddr,Q.srccoin,Q.txid,Q.vout); value2 = LP_txvalue(Q.coinaddr,Q.srccoin,Q.txid2,Q.vout2); if ( value == 0 || value2 == 0 ) { printf("zero value %.8f or value2 %.8f\n",dstr(value),dstr(value2)); return(clonestr("{\"error\":\"spent txid or txid2 for bob?\"}")); } if ( (butxo= LP_utxoadd(1,Q.srccoin,Q.txid,Q.vout,value,Q.txid2,Q.vout2,value2,Q.coinaddr,Q.srchash,LP_gui,0)) == 0 ) { printf("cant find or create butxo\n"); return(clonestr("{\"error\":\"cant find or create butxo\"}")); } if ( value < Q.satoshis ) { printf("butxo value %.8f less satoshis %.8f\n",dstr(value),dstr(Q.satoshis)); return(clonestr("{\"error\":\"butxo value less than satoshis\"}")); } }*/ /*if ( addflag != 0 && LP_utxofind(1,Q.txid,Q.vout) == 0 ) { LP_utxoadd(1,-1,Q.srccoin,Q.txid,Q.vout,Q.value,Q.txid2,Q.vout2,Q.value2,"",Q.srcaddr,Q.srchash,0.); LP_utxoadd(0,-1,Q.destcoin,Q.desttxid,Q.destvout,Q.destvalue,Q.feetxid,Q.feevout,Q.feevalu,"",Q.destaddr,Q.desthash,0.); }*/ /*struct LP_utxoinfo *utxo,*tmp; HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { if ( LP_ismine(utxo) > 0 && strcmp(utxo->coin,base) == 0 ) LP_priceping(LP_mypubsock,utxo,rel,price * LP_profitratio); }*/ /* bestprice = 0.; if ( (array= LP_tradecandidates(base)) != 0 ) { printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); memset(Q,0,sizeof(Q)); for (i=0; icoin,zero); Q[i].destsatoshis = price * Q[i].satoshis; } if ( (prices[i]= price) > SMALLVAL && (bestprice == 0. || price < bestprice) ) bestprice = price; char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); } if ( bestprice > SMALLVAL ) { bestmetric = 0.; besti = -1; for (i=0; i SMALLVAL && myutxo->S.satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) { metric = price / bestprice; printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); if ( metric < 1.1 ) { metric = dstr(Q[i].destsatoshis) * metric * metric * metric; printf("%f\n",metric); if ( bestmetric == 0. || metric < bestmetric ) { besti = i; bestmetric = metric; } } } else printf("(%f %f) ",dstr(myutxo->S.satoshis),dstr(Q[i].destsatoshis)); } printf("metrics, best %f\n",bestmetric); */ int32_t LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,int32_t maxentries) { char *retstr; struct LP_peerinfo *peer; uint32_t now; int32_t retval = -1; printf("deprecated LP_utxosquery\n"); return(-1); peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( coin == 0 ) coin = ""; //printf("utxo query.(%s)\n",destipaddr); if ( IAMLP != 0 ) retstr = issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,mypeer != 0 ? mypeer->numpeers : 0,maxentries); else retstr = issue_LP_clientgetutxos(destipaddr,destport,coin,maxentries); if ( retstr != 0 ) { now = (uint32_t)time(NULL); retval = LP_utxosparse(destipaddr,destport,retstr,now); //printf("got.(%s)\n",retstr); free(retstr); } return(retval); } char *issue_LP_numutxos(char *destip,uint16_t destport,char *ipaddr,uint16_t port,int32_t numpeers,int32_t numutxos) { char url[512],*retstr; printf("deprecated issue_LP_numutxos\n"); return(0); sprintf(url,"http://%s:%u/api/stats/numutxos?ipaddr=%s&port=%u&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,numpeers,numutxos); retstr = LP_issue_curl("numutxos",destip,port,url); //printf("%s -> getpeers.(%s)\n",destip,retstr); return(retstr); } char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,int32_t numpeers,int32_t numutxos) { char url[512]; printf("deprecated issue_LP_getutxos\n"); return(0); sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,numpeers,numutxos); return(LP_issue_curl("getutxos",destip,destport,url)); //return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t lastn) { char url[512];//,*retstr; printf("deprecated issue_LP_clientgetutxos\n"); return(0); sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); return(LP_issue_curl("clientgetutxos",destip,destport,url)); //retstr = issue_curlt(url,LP_HTTP_TIMEOUT); //printf("%s clientgetutxos.(%s)\n",url,retstr); //return(retstr); } void LP_address_monitor(struct LP_pubkeyinfo *pubp) { struct iguana_info *coin,*tmp; char coinaddr[64]; cJSON *retjson; struct LP_address *ap; return; HASH_ITER(hh,LP_coins,coin,tmp) { bitcoin_address(coinaddr,coin->taddr,coin->pubtype,pubp->rmd160,sizeof(pubp->rmd160)); portable_mutex_lock(&coin->addrmutex); if ( (ap= _LP_address(coin,coinaddr)) != 0 ) { ap->monitor = (uint32_t)time(NULL); } portable_mutex_unlock(&coin->addrmutex); if ( coin->electrum != 0 ) { if ( (retjson= electrum_address_subscribe(coin->symbol,coin->electrum,&retjson,coinaddr)) != 0 ) { printf("%s MONITOR.(%s) -> %s\n",coin->symbol,coinaddr,jprint(retjson,0)); free_json(retjson); } } } } /*else if ( strcmp(method,"ordermatch") == 0 ) { if ( price > SMALLVAL ) return(LP_ordermatch(base,j64bits(argjson,"txfee"),price,jdouble(argjson,"relvolume"),rel,jbits256(argjson,"txid"),jint(argjson,"vout"),jbits256(argjson,"feetxid"),jint(argjson,"feevout"),j64bits(argjson,"desttxfee"),jint(argjson,"duration"))); else return(clonestr("{\"error\":\"no price set\"}")); } else if ( strcmp(method,"trade") == 0 ) { struct LP_quoteinfo Q; if ( price > SMALLVAL || jobj(argjson,"quote") != 0 ) { LP_quoteparse(&Q,jobj(argjson,"quote")); return(LP_trade(ctx,myipaddr,pubsock,&Q,price,jint(argjson,"timeout"),jint(argjson,"duration"))); } else return(clonestr("{\"error\":\"no price set or no quote object\"}")); } else if ( strcmp(method,"autotrade") == 0 ) { if ( price > SMALLVAL ) { return(LP_autotrade(ctx,myipaddr,pubsock,base,rel,price,jdouble(argjson,"relvolume"),jint(argjson,"timeout"),jint(argjson,"duration"))); } else return(clonestr("{\"error\":\"no price set\"}")); }*/ if ( flag != 0 ) { // need to find the requestid/quoteid for aliceid if ( (retstr= basilisk_swapentries(bot->base,bot->rel,0)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(retjson)) != 0 ) { for (flag=j=0; jnumtrades; i++) { if ( (tp= bot->trades[i]) != 0 && tp->finished == 0 && tp->requestid == 0 && tp->quoteid == 0 ) { if ( tp->aliceid == aliceid ) { tp->requestid = juint(item,"requestid"); tp->quoteid = juint(item,"quoteid"); printf("found aliceid.%llx to set requestid.%u quoteid.%u\n",(long long)aliceid,tp->requestid,tp->quoteid); flag = 1; break; } } } } } free_json(retjson); } free(retstr); } } // check for finished pending swap for (i=0; inumtrades; i++) { if ( (tp= bot->trades[i]) != 0 && tp->finished == 0 && tp->requestid != 0 && tp->quoteid != 0 ) { if ( (retstr= basilisk_swapentry(tp->requestid,tp->quoteid)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (status= jstr(retjson,"status")) != 0 && strcmp(status,"finished") == 0 ) { bot->pendbasesum -= tp->basevol, bot->basesum += tp->basevol; bot->pendrelsum -= tp->relvol, bot->relsum += tp->relvol; bot->numpending--, bot->completed++; printf("detected completion aliceid.%llx r.%u q.%u\n",(long long)tp->aliceid,tp->requestid,tp->quoteid); tp->finished = (uint32_t)time(NULL); } free_json(retjson); } free(retstr); } } } } int32_t LP_utxopurge(int32_t allutxos) { char str[65]; struct LP_utxoinfo *utxo,*tmp; int32_t iambob,n = 0; printf("LP_utxopurge mypub.(%s)\n",bits256_str(str,LP_mypub25519)); portable_mutex_lock(&LP_utxomutex); for (iambob=0; iambob<=1; iambob++) { HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { if ( LP_isavailable(utxo) > 0 ) { if ( allutxos != 0 || LP_ismine(utxo) > 0 ) { printf("iambob.%d delete.(%s)\n",iambob,bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); //free(utxo); let the LP_utxoinfos2 free the utxo, should be 1:1 } else n++; } else n++; } HASH_ITER(hh,LP_utxoinfos2[iambob],utxo,tmp) { if ( LP_isavailable(utxo) > 0 ) { if ( allutxos != 0 || LP_ismine(utxo) > 0 ) { printf("iambob.%d delete2.(%s)\n",iambob,bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh2,LP_utxoinfos2[iambob],utxo); free(utxo); } else n++; } else n++; } } portable_mutex_unlock(&LP_utxomutex); return(n); } /*struct LP_utxoinfo *_LP_butxo_find(struct LP_utxoinfo *butxo) { int32_t i; struct LP_utxoinfo *utxo=0; uint32_t now = (uint32_t)time(NULL); //portable_mutex_lock(&LP_butxomutex); for (i=0; ipayment.vout == utxo->payment.vout && butxo->deposit.vout == utxo->deposit.vout && bits256_nonz(butxo->payment.txid) != 0 && bits256_nonz(butxo->deposit.txid) != 0 && bits256_cmp(butxo->payment.txid,utxo->payment.txid) == 0 && bits256_cmp(butxo->deposit.txid,utxo->deposit.txid) == 0 ) break; if ( utxo->S.swap == 0 && now > utxo->T.swappending ) memset(utxo,0,sizeof(*utxo)); utxo = 0; } //portable_mutex_unlock(&LP_butxomutex); return(utxo); } struct LP_utxoinfo *LP_butxo_add(struct LP_utxoinfo *butxo) { static struct LP_utxoinfo zeroes; int32_t i; struct LP_utxoinfo *utxo=0; portable_mutex_lock(&LP_butxomutex); if ( (utxo= _LP_butxo_find(butxo)) == 0 ) { for (i=0; iS = srcutxo->S; destutxo->T = srcutxo->T; } void LP_butxo_swapfields(struct LP_utxoinfo *butxo) { struct LP_utxoinfo *getutxo=0; portable_mutex_lock(&LP_butxomutex); if ( (getutxo= _LP_butxo_find(butxo)) != 0 ) LP_butxo_swapfields_copy(butxo,getutxo); portable_mutex_unlock(&LP_butxomutex); } void LP_butxo_swapfields_set(struct LP_utxoinfo *butxo) { struct LP_utxoinfo *setutxo; if ( (setutxo= LP_butxo_add(butxo)) != 0 ) { LP_butxo_swapfields_copy(setutxo,butxo); } }*/ /*struct LP_utxoinfo BUTXOS[100]; int32_t LP_butxo_findeither(bits256 txid,int32_t vout) { struct LP_utxoinfo *utxo; int32_t i,retval = 0; portable_mutex_lock(&LP_butxomutex); for (i=0; ipayment.vout && bits256_cmp(txid,utxo->payment.txid)) == 0 || (vout == utxo->deposit.vout && bits256_cmp(txid,utxo->deposit.txid) == 0) ) { retval = 1; break; } } portable_mutex_unlock(&LP_butxomutex); return(retval); }*/ struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson) { struct LP_utxoinfo *utxo; if ( jobj(argjson,"iambob") == 0 || iambob != jint(argjson,"iambob") ) { printf("LP_utxoaddjson: iambob.%d != arg.%d obj.%p (%s)\n",iambob,jint(argjson,"iambob"),jobj(argjson,"iambob"),jprint(argjson,0)); return(0); } portable_mutex_lock(&LP_UTXOmutex); utxo = LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jstr(argjson,"gui"),juint(argjson,"session")); if ( LP_ismine(utxo) > 0 && utxo->T.lasttime == 0 ) { utxo->T.lasttime = (uint32_t)time(NULL); printf("set lasttime!\n"); } portable_mutex_unlock(&LP_UTXOmutex); return(utxo); } int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; //printf("parse.(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; iT.lasttime = now; } } if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) { destpeer->numutxos = n; } } free_json(array); } return(n); } void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) { //cJSON *argjson; struct _LP_utxoinfo u; char *msg; if ( utxo == 0 ) return; utxo->T.spentflag = (uint32_t)time(NULL); /*if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) LP_mypeer->numutxos--; if ( LP_mypubsock >= 0 ) { argjson = cJSON_CreateObject(); jaddstr(argjson,"method","checktxid"); jaddbits256(argjson,"txid",utxo->payment.txid); jaddnum(argjson,"vout",utxo->payment.vout); if ( selector != 0 ) { if ( bits256_nonz(utxo->deposit.txid) != 0 ) u = utxo->deposit; else u = utxo->fee; jaddbits256(argjson,"checktxid",u.txid); jaddnum(argjson,"checkvout",u.vout); } msg = jprint(argjson,1); /LP_send(LP_mypubsock,msg,(int32_t)strlen(msg)+1,1); }*/ } char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t lastn) { int32_t i,n,m; uint64_t val,val2; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); printf("deprecated! LP_utxos\n"); //n = mypeer != 0 ? mypeer->numutxos : 0; if ( lastn <= 0 ) lastn = LP_PROPAGATION_SLACK * 2; HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { //char str[65]; printf("check %s.%s\n",utxo->coin,bits256_str(str,utxo->payment.txid)); if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 ) { u = (iambob != 0) ? utxo->deposit : utxo->fee; if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) == 0 ) { char str[65]; printf("iambob.%d not eligible (%.8f %.8f) %s %s/v%d\n",iambob,dstr(val),dstr(val2),utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout); continue; } else jaddi(utxosjson,LP_utxojson(utxo)); } } if ( (n= cJSON_GetArraySize(utxosjson)) > lastn ) { m = n - lastn; for (i=0; i 0 ) { memset(zero.bytes,0,sizeof(zero)); msg = jprint(LP_utxojson(utxo),1); LP_broadcast_message(LP_mypubsock,utxo->coin,"",zero,msg); } } /*char *LP_spentcheck(cJSON *argjson) { bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; int32_t iambob,retval = 0; txid = jbits256(argjson,"txid"); vout = jint(argjson,"vout"); for (iambob=0; iambob<=1; iambob++) { if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 && utxo->T.spentflag == 0 ) { if ( jobj(argjson,"check") == 0 ) checktxid = txid, checkvout = vout; else { checktxid = jbits256(argjson,"checktxid"); checkvout = jint(argjson,"checkvout"); } if ( LP_txvalue(0,utxo->coin,checktxid,checkvout) == 0 ) { //if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) // LP_mypeer->numutxos--; utxo->T.spentflag = (uint32_t)time(NULL); retval++; printf("indeed txid was spent\n"); } } } if ( retval > 0 ) return(clonestr("{\"result\":\"marked as spent\"}")); return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); }*/ /*char *LP_pricestr(char *base,char *rel,double origprice) { cJSON *retjson; double price = 0.; if ( base != 0 && base[0] != 0 && rel != 0 && rel[0] != 0 ) { price = LP_price(base,rel); if ( origprice > SMALLVAL && origprice < price ) price = origprice; } if ( LP_pricevalid(price) > 0 ) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); jaddstr(retjson,"method","postprice"); jaddbits256(retjson,"pubkey",G.LP_mypub25519); jaddstr(retjson,"base",base); jaddstr(retjson,"rel",rel); jaddnum(retjson,"price",price); jadd(retjson,"theoretical",LP_priceinfomatrix(0)); jadd(retjson,"quotes",LP_priceinfomatrix(1)); return(jprint(retjson,1)); } else return(clonestr("{\"error\":\"cant find baserel pair\"}")); }*/ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo) { struct _LP_utxoinfo u; struct iguana_info *coin; char str[65]; uint32_t now = (uint32_t)time(NULL); if ( IAMLP != 0 && (coin= LP_coinfind(utxo->coin)) != 0 && coin->inactive != 0 ) return; //printf("%s lag.%d\n",bits256_str(str,utxo->txid),now-utxo->lastspentcheck); if ( utxo->T.spentflag == 0 && now > utxo->T.lastspentcheck+60 ) { u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; utxo->T.lastspentcheck = now; if ( LP_txvalue(0,utxo->coin,utxo->payment.txid,utxo->payment.vout) == 0 ) { printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,dstr(utxo->payment.value)); LP_spentnotify(utxo,0); } else if ( LP_txvalue(0,utxo->coin,u.txid,u.vout) == 0 ) { printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,u.txid),u.vout,dstr(u.value)); LP_spentnotify(utxo,1); } } } int32_t LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubsock,struct LP_peerinfo *peer,uint32_t now,int32_t interval,int32_t maxentries) { int32_t lastn,n = -1; if ( peer->lastutxos < now-interval ) { //lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; //if ( lastn < LP_PROPAGATION_SLACK * 2 ) lastn = LP_PROPAGATION_SLACK * 2; if ( mypeer == 0 || strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) { peer->lastutxos = now; //printf("query utxos from %s\n",peer->ipaddr); n = LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,maxentries); } } //else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); return(n); } bestitem = LP_quotejson(qp); if ( LP_pricevalid(price) > 0 ) { if ( price <= maxprice ) { LP_query(ctx,myipaddr,mypubsock,"connect",qp); //price = LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout); LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis-2*qp->txfee,qp->destcoin,qp->destsatoshis-2*qp->desttxfee,qp->timestamp,qp->quotetime,DEXselector); while ( time(NULL) < expiration ) { if ( aliceutxo->S.swap != 0 ) break; sleep(3); } jaddnum(bestitem,"quotedprice",price); jaddnum(bestitem,"maxprice",maxprice); if ( (swap= aliceutxo->S.swap) == 0 ) { if ( (pubp= LP_pubkeyadd(qp->srchash)) != 0 ) pubp->numerrors++; jaddstr(bestitem,"status","couldnt establish connection"); } else { jaddstr(bestitem,"status","connected"); jaddnum(bestitem,"requestid",swap->I.req.requestid); jaddnum(bestitem,"quoteid",swap->I.req.quoteid); printf("Alice r.%u qp->%u\n",swap->I.req.requestid,swap->I.req.quoteid); } } else { jaddnum(bestitem,"quotedprice",price); jaddnum(bestitem,"maxprice",maxprice); jaddstr(bestitem,"status","too expensive"); } } else { printf("invalid price %.8f\n",price); jaddnum(bestitem,"maxprice",maxprice); jaddstr(bestitem,"status","no response to request"); } /*while ( time(NULL) < expiration ) { if ( (price= LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout)) > SMALLVAL ) { printf("break out of price %.8f %s/%s\n",price,qp->srccoin,qp->destcoin); break; } sleep(1); }*/ if ( aliceutxo->S.swap == 0 ) LP_availableset(aliceutxo); return(jprint(bestitem,0)); } if ( 0 && (retstr= issue_LP_listunspent(peer->ipaddr,peer->port,coin->symbol,"")) != 0 ) { if ( (array2= cJSON_Parse(retstr)) != 0 ) { if ( (m= cJSON_GetArraySize(array2)) > 0 ) { for (j=0; j %.8f n.%d\n",coinaddr,dstr(metric>>16),(uint16_t)metric); if ( (ap= LP_addressfind(coin,coinaddr)) == 0 || _LP_unspents_metric(ap->total,ap->n) != metric ) { if ( ap == 0 || ap->n < (metric & 0xffff) ) { if ( (retstr2= issue_LP_listunspent(peer->ipaddr,peer->port,coin->symbol,coinaddr)) != 0 ) { if ( (array3= cJSON_Parse(retstr2)) != 0 ) { LP_unspents_array(coin,coinaddr,array3); //printf("pulled.(%s)\n",retstr2); free_json(array3); } free(retstr2); } } //else printf("wait for %s to pull %d vs %d\n",peer->ipaddr,ap!=0?ap->n:-1,(uint16_t)metric); } } } } free_json(array2); } //printf("processed.(%s)\n",retstr); free(retstr); } /*if ( time(NULL) > coin->lastmonitor+60 ) { //portable_mutex_lock(&coin->addrmutex); HASH_ITER(hh,coin->addresses,ap,atmp) { if ( coin->electrum == 0 ) { LP_listunspent_issue(coin->symbol,ap->coinaddr); DL_FOREACH_SAFE(ap->utxos,up,utmp) { if ( up->spendheight <= 0 ) { if ( LP_txvalue(0,coin->symbol,up->U.txid,up->U.vout) == 0 ) up->spendheight = 1; } } } } //portable_mutex_unlock(&coin->addrmutex); coin->lastmonitor = (uint32_t)time(NULL); }*/ /*cJSON *LP_tradecandidates(char *base) { struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; totaladded = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { printf("%s:%u %s\n",peer->ipaddr,peer->port,base); n = added = 0; if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); if ( (array= cJSON_Parse(utxostr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { retarray = cJSON_CreateArray(); for (i=0; i 0 ) { memset(&Q,0,sizeof(Q)); for (i=0; i 0 ) { printf("iterate through all locally generated quotes and update, or change to price feed\n"); // jl777: iterated Q's if ( strcmp(utxo->coin,"KMD") == 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); else LP_priceping(pubsock,utxo,"KMD",profitmargin); }*/ /*if ( LP_txvalue(destaddr,symbol,searchtxid,searchvout) > 0 ) return(0); if ( (txobj= LP_gettx(symbol,searchtxid)) == 0 ) return(0); hash = jbits256(txobj,"blockhash"); free_json(txobj); if ( bits256_nonz(hash) == 0 ) return(0); if ( (blockjson= LP_getblock(symbol,hash)) == 0 ) return(0); loadheight = jint(blockjson,"height"); free_json(blockjson); if ( loadheight <= 0 ) return(0); while ( errs == 0 && *indp < 0 ) { //printf("search %s ht.%d\n",symbol,loadheight); if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 && h == loadheight ) { if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) { for (i=0; i= 0 ) break; } } free_json(blockjson); } else errs++; loadheight++; } char str[65]; printf("reached %s ht.%d %s/v%d\n",symbol,loadheight,bits256_str(str,*spendtxidp),*indp); if ( bits256_nonz(*spendtxidp) != 0 && *indp >= 0 ) return(loadheight); else return(0);*/ /*if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; i= 0 ) return(selector); } }*/ /*int32_t LP_orderbookfind(struct LP_orderbookentry **array,int32_t num,bits256 txid,int32_t vout) { int32_t i; for (i=0; ivout == vout && bits256_cmp(array[i]->txid,txid) == 0) || (array[i]->vout2 == vout && bits256_cmp(array[i]->txid2,txid) == 0) ) return(i); return(-1); }*/ //char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); //if ( strcmp(base,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && pubp != 0 && (price= pubp->matrix[baseid][relid]) > SMALLVAL ) //if ( polarity > 0 ) // minsatoshis = utxo->S.satoshis; //else minsatoshis = utxo->S.satoshis * price; /*if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,utxo->deposit.txid,utxo->deposit.vout) == 0 ) continue; if ( polarity > 0 ) basesatoshis = utxo->S.satoshis; else basesatoshis = utxo->S.satoshis * price; //char str[65]; printf("found utxo not in orderbook %s/v%d %.8f %.8f\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,dstr(basesatoshis),polarity > 0 ? price : 1./price); if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey,now - pubp->timestamp)) != 0 ) { *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); (*arrayp)[num++] = op; if ( LP_ismine(utxo) > 0 && utxo->T.lasttime == 0 ) LP_utxo_clientpublish(utxo); } }*/ void LP_price_broadcastloop(void *ctx) { struct LP_priceinfo *basepp,*relpp; double price; int32_t baseind,relind; sleep(30); while ( 1 ) { for (baseind=0; baseindsymbol[0] == 0 ) continue; for (relind=0; relindsymbol[0] == 0 ) continue; if ( basepp != 0 && relpp != 0 && (price= relpp->myprices[basepp->ind]) > SMALLVAL) { //printf("automated price broadcast %s/%s %.8f\n",relpp->symbol,basepp->symbol,price); LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,relpp->symbol,basepp->symbol,price); } } } sleep(LP_ORDERBOOK_DURATION * .9); } } //else if ( strcmp(method,"checktxid") == 0 ) // retstr = LP_spentcheck(argjson); //else if ( IAMLP == 0 && LP_isdisabled(base,rel) != 0 ) // return(clonestr("{\"result\":\"at least one of coins disabled\"}")); //else if ( IAMLP == 0 && LP_isdisabled(jstr(argjson,"coin"),0) != 0 ) // retstr = clonestr("{\"result\":\"coin is disabled\"}"); /*if ( strcmp(method,"broadcast") == 0 ) { bits256 zero; char *cipherstr; int32_t cipherlen; uint8_t cipher[LP_ENCRYPTED_MAXSIZE]; if ( (reqjson= LP_dereference(argjson,"broadcast")) != 0 ) { Broadcaststr = jprint(reqjson,0); if ( (cipherstr= jstr(reqjson,"cipher")) != 0 ) { cipherlen = (int32_t)strlen(cipherstr) >> 1; if ( cipherlen <= sizeof(cipher) ) { decode_hex(cipher,cipherlen,cipherstr); LP_queuesend(calc_crc32(0,&cipher[2],cipherlen-2),LP_mypubsock,base,rel,cipher,cipherlen); } else retstr = clonestr("{\"error\":\"cipher too big\"}"); } else { memset(zero.bytes,0,sizeof(zero)); //printf("broadcast.(%s)\n",Broadcaststr); LP_reserved_msg(base!=0?base:jstr(argjson,"coin"),rel,zero,jprint(reqjson,0)); } retstr = clonestr("{\"result\":\"success\"}"); } else retstr = clonestr("{\"error\":\"couldnt dereference sendmessage\"}"); } else*/ /*relvol = bot->totalrelvolume * .1; p = LP_pricevol_invert(&v,bot->maxprice,relvol); if ( bot->dispdir > 0 ) { printf("simulated trade buy %s/%s maxprice %.8f volume %.8f, %.8f %s -> %s, price %.8f relvol %.8f\n",bot->base,bot->rel,bot->maxprice,bot->totalrelvolume - bot->relsum,relvol,bot->rel,bot->base,bot->maxprice,relvol); } else { minprice = LP_pricevol_invert(&basevol,bot->maxprice,bot->totalrelvolume - bot->relsum); printf("simulated trade sell %s/%s minprice %.8f volume %.8f, %.8f %s -> %s price %.8f relvol %.8f\n",bot->rel,bot->base,minprice,basevol,v,bot->base,bot->rel,p,relvol); } if ( (LP_rand() % 2) == 0 ) { bot->relsum += relvol; bot->basesum += v; bot->completed++; } else { bot->pendrelsum += relvol; bot->pendbasesum += v; bot->numpending++; } bot->numtrades++; */ #ifdef FROM_JS int32_t sentbytes,sock,peerind,maxind; if ( (maxind= LP_numpeers()) > 0 ) peerind = (LP_rand() % maxind) + 1; else peerind = 1; sock = LP_peerindsock(&peerind); if ( sock >= 0 ) { if ( (sentbytes= nn_send(sock,msg,msglen,0)) != msglen ) printf("LP_send sent %d instead of %d\n",sentbytes,msglen); else printf("sent %d bytes of %d to sock.%d\n",sentbytes,msglen,sock); } else printf("couldnt get valid sock\n"); #else void _LP_queuesend(uint32_t crc32,int32_t sock0,int32_t sock1,uint8_t *msg,int32_t msglen,int32_t needack) { int32_t maxind,peerind = 0; //sentbytes, if ( sock0 >= 0 || sock1 >= 0 ) { /* if ( sock0 >= 0 && LP_sockcheck(sock0) > 0 ) { if ( (sentbytes= nn_send(sock0,msg,msglen,0)) != msglen ) printf("_LP_queuesend0 sent %d instead of %d\n",sentbytes,msglen); else { printf("Q sent %u msglen.%d (%s)\n",crc32,msglen,msg); sock0 = -1; } } if ( sock1 >= 0 && LP_sockcheck(sock1) > 0 ) { if ( (sentbytes= nn_send(sock1,msg,msglen,0)) != msglen ) printf("_LP_queuesend1 sent %d instead of %d\n",sentbytes,msglen); else { printf("Q sent1 %u msglen.%d (%s)\n",crc32,msglen,msg); sock1 = -1; } } if ( sock0 < 0 && sock1 < 0 ) return;*/ } else { if ( (maxind= LP_numpeers()) > 0 ) peerind = (LP_rand() % maxind) + 1; else peerind = 1; sock0 = LP_peerindsock(&peerind); if ( (maxind= LP_numpeers()) > 0 ) peerind = (LP_rand() % maxind) + 1; else peerind = 1; sock1 = LP_peerindsock(&peerind); } if ( sock0 >= 0 ) _LP_sendqueueadd(crc32,sock0,msg,msglen,needack * peerind); if ( sock1 >= 0 ) _LP_sendqueueadd(crc32,sock1,msg,msglen,needack); } if ( 0 && OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_price_broadcastloop,(void *)ctx) != 0 ) { printf("error launching LP_swapsloop for port.%u\n",myport); exit(-1); } void LP_queuesend(uint32_t crc32,int32_t pubsock,char *base,char *rel,uint8_t *msg,int32_t msglen) { //struct iguana_info *coin; int32_t flag=0,socks[2]; portable_mutex_lock(&LP_networkmutex); if ( pubsock >= 0 ) { //socks[0] = socks[1] = -1; //if ( rel != 0 && rel[0] != 0 && (coin= LP_coinfind(rel)) != 0 && coin->bussock >= 0 ) // socks[flag++] = coin->bussock; //if ( base != 0 && base[0] != 0 && (coin= LP_coinfind(base)) != 0 && coin->bussock >= 0 ) // socks[flag++] = coin->bussock; //if ( flag == 0 && pubsock >= 0 ) _LP_queuesend(crc32,pubsock,-1,msg,msglen,0); //else _LP_queuesend(socks[0],socks[1],msg,msglen,0); } else _LP_queuesend(crc32,-1,-1,msg,msglen,1); portable_mutex_unlock(&LP_networkmutex); } #ifdef oldway struct LP_utxoinfo *LP_bestutxo(double *ordermatchpricep,int64_t *bestsatoshisp,int64_t *bestdestsatoshisp,struct LP_utxoinfo *autxo,char *base,double maxprice,int32_t duration,uint64_t txfee,uint64_t desttxfee,uint64_t maxdestsatoshis) { int64_t satoshis,destsatoshis; uint64_t val,val2; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item; struct LP_utxoinfo *butxo,*bestutxo = 0; int32_t i,n,j,vout,numasks; double bestmetric=0.,metric,vol,price,qprice,bestprice = 0.; struct LP_pubkeyinfo *pubp; *ordermatchpricep = 0.; *bestsatoshisp = *bestdestsatoshisp = 0; if ( duration <= 0 ) duration = LP_ORDERBOOK_DURATION; if ( maxprice <= 0. || LP_priceinfofind(base) == 0 ) return(0); LP_txfees(&txfee,&desttxfee,base,autxo->coin); if ( (obookstr= LP_orderbook(base,autxo->coin,duration)) != 0 ) { if ( (orderbook= cJSON_Parse(obookstr)) != 0 ) { if ( (asks= jarray(&numasks,orderbook,"asks")) != 0 ) { for (i=0; i 0 && price <= maxprice ) { //price *= 1.0001; //if ( price > maxprice ) // price = maxprice; pubkey = jbits256(item,"pubkey"); if ( bits256_cmp(pubkey,LP_mypub25519) != 0 && (pubp= LP_pubkeyadd(pubkey)) != 0 && pubp->numerrors < LP_MAXPUBKEY_ERRORS ) { if ( bestprice == 0. ) // assumes price ordered asks bestprice = price; printf("item.[%d] %s\n",i,jprint(item,0)); txid = jbits256(item,"txid"); vout = jint(item,"vout"); vol = jdouble(item,"volume"); metric = price / bestprice; printf("maxdest %.8f metric %f vol %f add pings numutxos.%d min %.8f max %.8f\n",dstr(maxdestsatoshis),metric,vol,jint(item,"numutxos"),jdouble(item,"minvolume"),jdouble(item,"maxvolume")); // check utxos > 1 for pubkey, SPV validate recv'ed /*if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && (long long)(vol*SATOSHIDEN) == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 && butxo->T.bestflag == 0 ) { printf("got butxo? %p\n",butxo); if ( LP_iseligible(&val,&val2,butxo->iambob,butxo->coin,butxo->payment.txid,butxo->payment.vout,butxo->S.satoshis,butxo->deposit.txid,butxo->deposit.vout) > 0 ) { destsatoshis = ((butxo->S.satoshis - txfee) * price); satoshis = (destsatoshis / price + 0.49) - txfee; if ( satoshis <= 0 ) continue; qprice = (double)destsatoshis / satoshis; n = (int32_t)((double)destsatoshis / desttxfee); if ( n < 10 ) n = 10; else n = 3; for (j=0; jS.satoshis,txfee,autxo->payment.value,maxdestsatoshis,desttxfee)) > price+SMALLVAL ) break; } //printf("j.%d/%d qprice %.8f vs price %.8f best.(%.8f %.8f)\n",j,n,qprice,price,dstr(satoshis),dstr(destsatoshis)); if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value / LP_MINCLIENTVOL) && satoshis-txfee > (butxo->S.satoshis / LP_MINVOL) && satoshis <= butxo->payment.value-txfee ) { printf("value %.8f price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",dstr(autxo->payment.value),price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; if ( bestmetric == 0. || metric < bestmetric ) { bestutxo = butxo; *ordermatchpricep = price; *bestdestsatoshisp = destsatoshis; *bestsatoshisp = satoshis; bestmetric = metric; printf("set best!\n"); } } // else printf("skip.(%d %d %d %d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f sats %.8f\n",metric < 1.2,destsatoshis > desttxfee,destsatoshis-desttxfee > (autxo->payment.value / LP_MINCLIENTVOL),satoshis-txfee > (butxo->S.satoshis / LP_MINVOL),satoshis < butxo->payment.value-txfee,metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee),dstr(satoshis)); } else { printf("ineligible.(%.8f %.8f)\n",price,dstr(butxo->S.satoshis)); //if ( butxo->T.spentflag == 0 ) // butxo->T.spentflag = (uint32_t)time(NULL); } } else { if ( butxo != 0 ) printf("%llu %llu %d %d %d: ",(long long)(vol*SATOSHIDEN),(long long)butxo->S.satoshis,vol*SATOSHIDEN == butxo->S.satoshis,LP_isavailable(butxo) > 0,LP_ismine(butxo) == 0); printf("cant find butxo.%p or value mismatch %.8f != %.8f or bestflag.%d\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0,butxo->T.bestflag); }*/ } else printf("self trading or blacklisted peer\n"); } else { if ( i == 0 ) printf("maxprice %.8f vs %.8f\n",maxprice,price); break; } } if ( bestutxo == 0 ) { int32_t numrestraints; for (i=numrestraints=0; iT.bestflag = 0; //pubp->numerrors = 0; } } } printf("no bob utxo found -> cleared %d restraints\n",numrestraints); } } free_json(orderbook); } free(obookstr); } printf("bestutxo.%p %.8f %.8f\n",bestutxo,*ordermatchpricep,dstr(*bestdestsatoshisp)); if ( bestutxo == 0 || *ordermatchpricep == 0. || *bestdestsatoshisp == 0 ) return(0); bestutxo->T.bestflag = 1; int32_t changed; LP_mypriceset(&changed,autxo->coin,base,1. / *ordermatchpricep); return(bestutxo); } if ( (0) ) { ep = LP_electrum_info(&already,"BTC","88.198.241.196",50001,IGUANA_MAXPACKETSIZE * 10); if ( ep != 0 && OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_dedicatedloop,(void *)ep) != 0 ) { printf("error launching LP_dedicatedloop (%s:%u)\n",ep->ipaddr,ep->port); exit(-1); } else printf("launched.(%s:%u)\n",ep->ipaddr,ep->port); electrum_test(); } /*static int _LP_metric_eval(const void *a,const void *b) { #define aptr (*(struct LP_metricinfo **)a) #define bptr (*(struct LP_metricinfo **)b) if ( bptr->metric > aptr->metric ) return(1); else if ( bptr->metric < aptr->metric ) return(-1); return(0); #undef aptr #undef bptr }*/ /*if ( (utxo= LP_utxoadd(1,coin->symbol,up->U.txid,up->U.vout,up->U.value,up2->U.txid,up2->U.vout,up2->U.value,coinaddr,ap->pubkey,G.gui,0,targetval)) != 0 ) { utxo->S.satoshis = targetval; char str[65],str2[65]; printf("butxo.%p targetval %.8f, found val %.8f %s | targetval2 %.8f val2 %.8f %s\n",utxo,dstr(targetval),dstr(up->U.value),bits256_str(str,utxo->payment.txid),dstr(targetval2),dstr(up2->U.value),bits256_str(str2,utxo->deposit.txid)); return(butxo); }*/ /*if ( (sobj= jobj(v,"scriptPubKey")) != 0 ) { if ( (scriptstr= jstr(sobj,"hex")) != 0 ) { printf("amount64 %.8f vout.%d (%s) weeki.%d %.8f (%s)\n",dstr(amount64),vout,jprint(v,0),weeki,dstr(satoshis),scriptstr); len = (int32_t)strlen(scriptstr) >> 1; if ( len <= sizeof(spendscript)/sizeof(*spendscript) ) { decode_hex(spendscript,len,scriptstr); if ( spendscript[11] == 33 ) { pub33 = &spendscript[12]; redeemlen = LP_deposit_addr(p2shaddr,redeemscript,coin->taddr,coin->p2shtype,timestamp,pub33); if ( len == redeemlen && (timestamp % LP_WEEKMULT) == 0 ) { bitcoin_address(coinaddr,coin->taddr,coin->pubtype,pub33,33); printf("%s -> matched %s script t.%u weeki.%d deposit %.8f\n",coinaddr,p2shaddr,timestamp,(timestamp-LP_FIRSTWEEKTIME)/LP_WEEKMULT,dstr(satoshis)); // add to pubp->credits; } } } } }*/ /*portable_mutex_lock(&ep->pendingQ.mutex); if ( ep->pendingQ.list != 0 ) { printf("list %p\n",ep->pendingQ.list); DL_FOREACH_SAFE(ep->pendingQ.list,item,tmp) { printf("item.%p\n",item); if ( item->type == 0xffffffff ) { 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);*/ //printf("%p SENT.(%s) to %s:%u\n",sitem,sitem->str,ep->ipaddr,ep->port); #ifdef oldway struct LP_utxoinfo *LP_ordermatch_iter(struct LP_address_utxo **utxos,int32_t max,double *ordermatchpricep,int64_t *bestsatoshisp,int64_t *bestdestsatoshisp,struct iguana_info *basecoin,char *coinaddr,uint64_t asatoshis,double price,uint64_t txfee,uint64_t desttxfee,bits256 pubkey,char *gui) { uint64_t basesatoshis; struct LP_utxoinfo *bestutxo; basesatoshis = LP_basesatoshis(dstr(asatoshis),price,txfee,desttxfee); //printf("basesatoshis %.8f price %.8f txfee %.8f desttxfee %.8f\n",dstr(basesatoshis),price,dstr(txfee),dstr(desttxfee)); if ( basesatoshis != 0 && (bestutxo= LP_address_utxopair(0,utxos,max,basecoin,coinaddr,txfee,dstr(basesatoshis)*price,price,desttxfee)) != 0 ) { bestutxo->pubkey = pubkey; safecopy(bestutxo->gui,gui,sizeof(bestutxo->gui)); *bestsatoshisp = basesatoshis; *ordermatchpricep = price; *bestdestsatoshisp = asatoshis; return(bestutxo); } return(0); } struct LP_utxoinfo *LP_buyutxo(double *ordermatchpricep,int64_t *bestsatoshisp,int64_t *bestdestsatoshisp,struct LP_utxoinfo *autxo,char *base,double maxprice,int32_t duration,uint64_t txfee,uint64_t desttxfee,char *gui,bits256 *avoids,int32_t numavoids,bits256 destpubkey) { bits256 pubkey; char *obookstr,coinaddr[64]; cJSON *orderbook,*asks,*rawasks,*item; int32_t maxiters,i,j,numasks,max; struct LP_address_utxo **utxos; double price; struct LP_pubkey_info *pubp; uint64_t asatoshis; struct iguana_info *basecoin; struct LP_utxoinfo *bestutxo = 0; maxiters = 100; *ordermatchpricep = 0.; *bestsatoshisp = *bestdestsatoshisp = 0; basecoin = LP_coinfind(base); if ( duration <= 0 ) duration = LP_ORDERBOOK_DURATION; if ( maxprice <= 0. || LP_priceinfofind(base) == 0 || basecoin == 0 ) return(0); if ( basecoin->electrum == 0 ) max = 1000; else max = LP_MAXDESIRED_UTXOS; utxos = calloc(max,sizeof(*utxos)); LP_txfees(&txfee,&desttxfee,base,autxo->coin); printf("LP_buyutxo maxprice %.8f relvol %.8f %s/%s %.8f %.8f\n",maxprice,dstr(autxo->S.satoshis),base,autxo->coin,dstr(txfee),dstr(desttxfee)); if ( (obookstr= LP_orderbook(base,autxo->coin,duration)) != 0 ) { if ( (orderbook= cJSON_Parse(obookstr)) != 0 ) { if ( (rawasks= jarray(&numasks,orderbook,"asks")) != 0 ) { if ( (asks= LP_RTmetrics_sort(base,autxo->coin,rawasks,numasks,maxprice,dstr(autxo->S.satoshis))) == 0 ) asks = rawasks; for (i=0; i maxprice*0.8) // price = price * 0.9 + 0.1 * maxprice; //else price *= 1.005; pubkey = jbits256(item,"pubkey"); if ( bits256_nonz(destpubkey) != 0 && bits256_cmp(destpubkey,pubkey) != 0 ) continue; if ( LP_RTmetrics_blacklisted(pubkey) >= 0 ) continue; //printf("[%d/%d] %s pubcmp %d price %.8f vs maxprice %.8f asatoshis %.8f\n",i,numasks,jprint(item,0),bits256_cmp(pubkey,G.LP_mypub25519),price,maxprice,dstr(autxo->S.satoshis)); if ( LP_pricevalid(price) > 0 && price <= maxprice ) { if ( bits256_nonz(destpubkey) == 0 ) { for (j=0; jtaddr,basecoin->pubtype,pubp->rmd160,sizeof(pubp->rmd160)); asatoshis = autxo->S.satoshis; //LP_listunspent_query(base,coinaddr); for (j=0; jpubkey,gui)) != 0 ) { //printf("j.%d/%d ordermatch %.8f best satoshis %.8f destsatoshis %.8f txfees (%.8f %.8f)\n",j,maxiters,price,dstr(*bestsatoshisp),dstr(*bestdestsatoshisp),dstr(txfee),dstr(desttxfee)); break; } asatoshis = (asatoshis / 64) * 63; } if ( j < maxiters ) break; } else printf("self trading or blacklisted peer\n"); } else { if ( i == 0 ) printf("too expensive maxprice %.8f vs %.8f\n",maxprice,price); break; } } if ( asks != 0 && asks != rawasks ) free_json(asks); } free_json(orderbook); } free(obookstr); } free(utxos); if ( *ordermatchpricep == 0. || *bestdestsatoshisp == 0 ) return(0); int32_t changed; LP_mypriceset(&changed,autxo->coin,base,1. / *ordermatchpricep); return(bestutxo); } #endif #ifdef oldway //LP_RTmetrics_update(base,rel); while ( 1 ) { if ( (bestutxo= LP_buyutxo(&ordermatchprice,&bestsatoshis,&bestdestsatoshis,autxo,base,maxprice,duration,txfee,desttxfee,gui,pubkeys,numpubs,destpubkey)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 ) { printf("bestutxo.%p ordermatchprice %.8f bestdestsatoshis %.8f\n",bestutxo,ordermatchprice,dstr(bestdestsatoshis)); return(clonestr("{\"error\":\"cant find ordermatch utxo, need to change relvolume to be closer to available\"}")); } pubkeys[numpubs++] = bestutxo->pubkey; if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,G.LP_mypub25519,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); maxiters = 200; qprice = 1. / SMALLVAL; for (i=0; i maxprice ) { printf("i.%d maxiters.%d qprice %.8f vs maxprice %.8f, no acceptable quote for this pubkey\n",i,maxiters,dstr(qprice),dstr(maxprice)); if ( bits256_nonz(destpubkey) == 0 ) continue; else return(clonestr("{\"error\":\"cant ordermatch to destpubkey\"}")); } printf("i.%d maxiters.%d qprice %.8f vs maxprice %.8f\n",i,maxiters,dstr(qprice),dstr(maxprice)); return(LP_trade(ctx,myipaddr,mypubsock,&Q,maxprice,timeout,duration,tradeid,destpubkey)); } return(clonestr("{\"error\":\"cant get here\"}")); #endif char *LP_ordermatch(char *base,int64_t txfee,double maxprice,double maxvolume,char *rel,bits256 txid,int32_t vout,bits256 feetxid,int32_t feevout,int64_t desttxfee,int32_t duration) { struct LP_quoteinfo Q; int64_t bestsatoshis=0,bestdestsatoshis = 0; double ordermatchprice = 0.; struct LP_utxoinfo *autxo,*bestutxo; txfee = LP_txfeecalc(LP_coinfind(base),txfee); desttxfee = LP_txfeecalc(LP_coinfind(rel),desttxfee); if ( (autxo= LP_utxopairfind(0,txid,vout,feetxid,feevout)) == 0 ) return(clonestr("{\"error\":\"cant find alice utxopair\"}")); if ( (bestutxo= LP_bestutxo(&ordermatchprice,&bestsatoshis,&bestdestsatoshis,autxo,base,maxprice,duration,txfee,desttxfee,SATOSHIDEN*maxvolume)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 ) return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypub25519,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); return(jprint(LP_quotejson(&Q),1)); } char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel,double maxprice,double relvolume,int32_t timeout,int32_t duration) { uint64_t desttxfee,txfee; int64_t bestsatoshis=0,bestdestsatoshis=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; double qprice,ordermatchprice=0.; struct LP_quoteinfo Q; if ( duration <= 0 ) duration = LP_ORDERBOOK_DURATION; if ( timeout <= 0 ) timeout = LP_AUTOTRADE_TIMEOUT; if ( maxprice <= 0. || relvolume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) return(clonestr("{\"error\":\"invalid parameter\"}")); if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * relvolume)) == 0 ) return(clonestr("{\"error\":\"cant find utxo that is big enough\"}")); LP_txfees(&txfee,&desttxfee,base,rel); if ( (bestutxo= LP_bestutxo(&ordermatchprice,&bestsatoshis,&bestdestsatoshis,autxo,base,maxprice,duration,txfee,desttxfee,SATOSHIDEN*relvolume)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 ) { printf("bestutxo.%p ordermatchprice %.8f bestdestsatoshis %.8f\n",bestutxo,ordermatchprice,dstr(bestdestsatoshis)); return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); } if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypub25519,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,0)) <= SMALLVAL ) { printf("quote validate error %.0f\n",qprice); return(clonestr("{\"error\":\"quote validation error\"}")); } printf("do quote.(%s)\n",jprint(LP_quotejson(&Q),1)); return(LP_trade(ctx,myipaddr,mypubsock,&Q,maxprice,timeout,duration)); } #endif