/****************************************************************************** * 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_utxos.c // marketmaker // int32_t LP_ismine(struct LP_utxoinfo *utxo) { if ( utxo != 0 && bits256_cmp(utxo->pubkey,LP_mypub25519) == 0 ) return(1); else return(0); } int32_t LP_isavailable(struct LP_utxoinfo *utxo) { if ( time(NULL) > utxo->T.swappending ) utxo->T.swappending = 0; if ( utxo != 0 && utxo->T.swappending == 0 && utxo->S.swap == 0 ) return(1); else return(0); } int32_t LP_isunspent(struct LP_utxoinfo *utxo) { if ( utxo != 0 && utxo->T.spentflag == 0 && LP_isavailable(utxo) > 0 ) return(1); else return(0); } struct LP_utxoinfo *LP_utxopairfind(int32_t iambob,bits256 txid,int32_t vout,bits256 txid2,int32_t vout2) { struct LP_utxoinfo *utxo=0; struct _LP_utxoinfo u; if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 ) { u = (iambob != 0) ? utxo->deposit : utxo->fee; if (vout2 == u.vout && bits256_cmp(u.txid,txid2) == 0 ) return(utxo); } return(0); } struct LP_utxoinfo *LP_utxofinds(int32_t iambob,bits256 txid,int32_t vout,bits256 txid2,int32_t vout2) { struct LP_utxoinfo *utxo; if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 || (utxo= LP_utxofind(iambob,txid2,vout2)) != 0 || (utxo= LP_utxo2find(iambob,txid,vout)) != 0 || (utxo= LP_utxo2find(iambob,txid2,vout2)) != 0 ) return(utxo); else return(0); } int32_t LP_utxoaddptrs(struct LP_utxoinfo *ptrs[],int32_t n,struct LP_utxoinfo *utxo) { int32_t i; for (i=0; ipayment.txid,refutxo->payment.vout)) != 0 && utxo != refutxo ) n = LP_utxoaddptrs(ptrs,n,utxo); if ( (utxo= _LP_utxo2find(iambob,refutxo->payment.txid,refutxo->payment.vout)) != 0 && utxo != refutxo ) n = LP_utxoaddptrs(ptrs,n,utxo); u = (refutxo->iambob != 0) ? refutxo->deposit : refutxo->fee; if ( (utxo= _LP_utxofind(iambob,u.txid,u.vout)) != 0 && utxo != refutxo ) n = LP_utxoaddptrs(ptrs,n,utxo); if ( (utxo= _LP_utxo2find(iambob,u.txid,u.vout)) != 0 && utxo != refutxo ) n = LP_utxoaddptrs(ptrs,n,utxo); } portable_mutex_unlock(&LP_utxomutex); if ( 0 && n > 0 ) printf("LP_utxocollisions n.%d\n",n); return(n); } int32_t _LP_availableset(struct LP_utxoinfo *utxo) { int32_t flag = 0; if ( utxo != 0 ) { if ( bits256_nonz(utxo->S.otherpubkey) != 0 ) flag = 1, memset(&utxo->S.otherpubkey,0,sizeof(utxo->S.otherpubkey)); if ( utxo->S.swap != 0 ) flag = 1, utxo->S.swap = 0; if ( utxo->T.swappending != 0 ) flag = 1, utxo->T.swappending = 0; return(flag); } return(0); } void _LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) { if ( utxo != 0 ) { utxo->T.swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); utxo->S.otherpubkey = otherpubkey; } } void LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) { struct LP_utxoinfo *ptrs[8]; int32_t i,n; struct _LP_utxoinfo u; memset(ptrs,0,sizeof(ptrs)); if ( (n= LP_utxocollisions(ptrs,utxo)) > 0 ) { for (i=0; iiambob != 0) ? utxo->deposit : utxo->fee; char str[65],str2[65]; printf("UTXO.[%d] RESERVED %s/v%d %s/v%d collisions.%d\n",utxo->iambob,bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,u.txid),u.vout,n); _LP_unavailableset(utxo,otherpubkey); } void LP_availableset(struct LP_utxoinfo *utxo) { struct LP_utxoinfo *ptrs[8]; int32_t i,n,count = 0; struct _LP_utxoinfo u; if ( utxo != 0 ) { memset(ptrs,0,sizeof(ptrs)); if ( (n= LP_utxocollisions(ptrs,utxo)) > 0 ) { for (i=0; i 0 ) { u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; char str[65],str2[65]; printf("UTXO.[%d] AVAIL %s/v%d %s/v%d collisions.%d\n",utxo->iambob,bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,u.txid),u.vout,n); } } } 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); } cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { struct _LP_utxoinfo u; jaddstr(item,"method","utxo"); if ( utxo == 0 ) return(item); if ( utxo->gui[0] != 0 ) jaddstr(item,"gui",utxo->gui); jaddstr(item,"coin",utxo->coin); //jaddnum(item,"now",time(NULL)); jaddnum(item,"iambob",utxo->iambob); jaddstr(item,"address",utxo->coinaddr); jaddbits256(item,"txid",utxo->payment.txid); jaddnum(item,"vout",utxo->payment.vout); jadd64bits(item,"value",utxo->payment.value); jadd64bits(item,"satoshis",utxo->S.satoshis); u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( bits256_nonz(u.txid) != 0 ) { jaddbits256(item,"txid2",u.txid); jaddnum(item,"vout2",u.vout); jadd64bits(item,"value2",u.value); } if ( utxo->T.swappending != 0 ) jaddnum(item,"pending",utxo->T.swappending); if ( utxo->iambob != 0 ) { jaddbits256(item,"srchash",utxo->pubkey);//LP_mypub25519); if ( bits256_nonz(utxo->S.otherpubkey) != 0 ) jaddbits256(item,"desthash",utxo->S.otherpubkey); } else { jaddbits256(item,"desthash",utxo->pubkey);//LP_mypub25519); if ( bits256_nonz(utxo->S.otherpubkey) != 0 ) jaddbits256(item,"srchash",utxo->S.otherpubkey); } if ( utxo->S.swap != 0 ) jaddstr(item,"swap","in progress"); if ( utxo->T.spentflag != 0 ) jaddnum(item,"spent",utxo->T.spentflag); jaddnum(item,"session",utxo->T.sessionid); return(item); } cJSON *LP_utxojson(struct LP_utxoinfo *utxo) { cJSON *item = cJSON_CreateObject(); item = LP_inventoryjson(item,utxo); jaddbits256(item,"pubkey",utxo->pubkey); //jaddnum(item,"profit",utxo->S.profitmargin); jaddstr(item,"base",utxo->coin); jaddstr(item,"script",utxo->spendscript); return(item); } 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= %d\n",utxo->T.spentflag,LP_iseligible(&srcvalue,&srcvalue2,utxo->iambob,symbol,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,utxo->fee.txid,utxo->fee.vout),dstr(destsatoshis),dstr(utxo->S.satoshis),utxo->coin,bits256_str(str,utxo->payment.txid),LP_isavailable(utxo) > 0,LP_ismine(utxo) > 0,utxo->S.satoshis >= destsatoshis); if ( strcmp(symbol,utxo->coin) != 0 ) continue; if ( LP_isavailable(utxo) > 0 && LP_ismine(utxo) > 0 ) { if ( utxo->S.satoshis >= destsatoshis/2 && (bestutxo == 0 || (bestutxo->S.satoshis < destsatoshis && utxo->S.satoshis >= destsatoshis) || (bestutxo->S.satoshis >= destsatoshis && utxo->S.satoshis < bestutxo->S.satoshis)) ) { if ( LP_iseligible(&srcvalue,&srcvalue2,utxo->iambob,symbol,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,utxo->fee.txid,utxo->fee.vout) == 0 ) { //if ( utxo->T.spentflag == 0 ) // utxo->T.spentflag = (uint32_t)time(NULL); continue; } bestutxo = utxo; } //else printf("skip alice utxo %.8f vs dest %.8f\n",dstr(utxo->S.satoshis),dstr(destsatoshis)); } } return(bestutxo); } 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_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\"}")); } void LP_utxo_clientpublish(struct LP_utxoinfo *utxo) { bits256 zero; char *msg; if ( 0 && LP_isunspent(utxo) > 0 ) { memset(zero.bytes,0,sizeof(zero)); msg = jprint(LP_utxojson(utxo),1); LP_broadcast_message(LP_mypubsock,utxo->coin,"",zero,msg); } } struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,char *gui,uint32_t sessionid) { uint64_t val,val2=0,tmpsatoshis,txfee; int32_t spendvini,numconfirms,selector; bits256 spendtxid; struct iguana_info *coin; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 || sessionid == 0 ) { printf("session.%u malformed addutxo %d %d %d %d %d %d %d %d %d\n",sessionid,symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } if ( (coin= LP_coinfind(symbol)) == 0 || (IAMLP == 0 && coin->inactive != 0) ) { printf("LP_utxoadd reject inactive %s\n",symbol); return(0); } txfee = LP_txfeecalc(coin,0); if ( iambob != 0 && value2 < 9 * (value >> 3) + 2*txfee ) // big txfee padding { if ( value2 > 2*txfee ) tmpsatoshis = (((value2 - 2*txfee) / 9) << 3); else return(0); } else tmpsatoshis = (value - txfee); char str[65],str2[65],dispflag = 0;//(iambob == 0); if ( iambob == 0 && bits256_cmp(pubkey,LP_mypub25519) != 0 ) { printf("trying to add Alice utxo when not mine? %s/v%d\n",bits256_str(str,txid),vout); return(0); } if ( coin->inactive == 0 ) { if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("iambob.%d utxoadd %s inactive.%u got ineligible txid value %.8f:%.8f, value2 %.8f:%.8f, tmpsatoshis %.8f\n",iambob,symbol,coin->inactive,dstr(value),dstr(val),dstr(value2),dstr(val2),dstr(tmpsatoshis)); return(0); } if ( (numconfirms= LP_numconfirms(symbol,coinaddr,txid,vout,0)) <= 0 ) { printf("LP_utxoadd reject numconfirms.%d %s.%s\n",numconfirms,symbol,bits256_str(str,txid)); return(0); } if ( (numconfirms= LP_numconfirms(symbol,coinaddr,txid2,vout2,0)) <= 0 ) { printf("LP_utxoadd reject2 numconfirms.%d\n",numconfirms); return(0); } } else { val = value; val2 = value2; } if ( dispflag != 0 ) printf("%.8f %.8f %s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",dstr(val),dstr(val2),coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); dispflag = 1; if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { if ( 0 && LP_ismine(utxo) == 0 ) { char str2[65],str3[65]; printf("iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis)); } u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { utxo->T.errors++; char str[65],str2[65],str3[65],str4[65],str5[65],str6[65]; if ( utxo->T.spentflag != 0 || LP_txvalue(0,utxo->coin,utxo->payment.txid,utxo->payment.vout) < utxo->payment.value || LP_txvalue(0,utxo->coin,u.txid,u.vout) < u.value ) { //if ( utxo->T.spentflag == 0 ) // utxo->T.spentflag = (uint32_t)time(NULL); printf("original utxo pair not valid\n"); if ( dispflag != 0 ) printf("error on subsequent utxo iambob.%d %.8f %.8f add.(%s %s) when.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",iambob,dstr(val),dstr(val2),bits256_str(str,txid),bits256_str(str2,txid2),bits256_str(str3,utxo->payment.txid),bits256_str(str4,utxo->deposit.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str5,pubkey),bits256_str(str6,utxo->pubkey)); utxo = 0; } } if ( utxo != 0 ) { if ( utxo->T.sessionid == 0 ) utxo->T.sessionid = sessionid; //else if ( profitmargin > SMALLVAL ) // utxo->S.profitmargin = profitmargin; utxo->T.lasttime = (uint32_t)time(NULL); return(utxo); } } utxo = calloc(1,sizeof(*utxo)); //utxo->S.profitmargin = profitmargin; utxo->pubkey = pubkey; safecopy(utxo->gui,gui,sizeof(utxo->gui)); safecopy(utxo->coin,symbol,sizeof(utxo->coin)); safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); utxo->payment.txid = txid; utxo->payment.vout = vout; utxo->payment.value = value; utxo->S.satoshis = tmpsatoshis; if ( (utxo->iambob= iambob) != 0 ) { utxo->deposit.txid = txid2; utxo->deposit.vout = vout2; utxo->deposit.value = value2; } else { utxo->fee.txid = txid2; utxo->fee.vout = vout2; utxo->fee.value = value2; } LP_utxosetkey(utxo->key,txid,vout); LP_utxosetkey(utxo->key2,txid2,vout2); if ( LP_ismine(utxo) > 0 ) utxo->T.sessionid = LP_sessionid; else utxo->T.sessionid = sessionid; if ( coin->inactive == 0 && (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,coinaddr,txid,vout,txid2,vout2)) >= 0 ) { printf("utxoadd selector.%d spent in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); utxo->T.spentflag = (uint32_t)time(NULL); } printf("U.%d %s %.8f %.8f addutxo.%d pubkey.%s session.%u\n",LP_mypeer!=0?LP_mypeer->numutxos:-1,symbol,dstr(value),dstr(value2),LP_ismine(utxo) > 0,bits256_str(str,utxo->pubkey),utxo->T.sessionid); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) HASH_ADD_KEYPTR(hh2,LP_utxoinfos2[iambob],utxo->key2,sizeof(utxo->key2),utxo); portable_mutex_unlock(&LP_utxomutex); if ( iambob != 0 ) { if ( LP_mypeer != 0 ) LP_mypeer->numutxos++; if ( LP_ismine(utxo) > 0 ) { LP_utxo_clientpublish(utxo); if ( LP_mypeer != 0 ) utxo->T.lasttime = (uint32_t)time(NULL); } } return(utxo); } 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 *destpeer,*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); } 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); } cJSON *LP_inventory(char *symbol,int32_t iambob) { struct LP_utxoinfo *utxo,*tmp; struct _LP_utxoinfo u; char *myipaddr; cJSON *array; uint64_t val,val2; array = cJSON_CreateArray(); if ( LP_mypeer != 0 ) myipaddr = LP_mypeer->ipaddr; else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { char str[65]; //printf("iambob.%d iterate %s\n",iambob,bits256_str(str,LP_mypub25519)); if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) > 0 ) { u = (iambob != 0) ? utxo->deposit : utxo->fee; if ( LP_iseligible(&val,&val2,iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) == 0 ) { //if ( utxo->T.spentflag == 0 ) // utxo->T.spentflag = (uint32_t)time(NULL); printf("%s %s ineligible %.8f %.8f\n",utxo->coin,bits256_str(str,u.txid),dstr(val),dstr(val2)); continue; } if ( iambob != 0 ) LP_utxo_clientpublish(utxo); jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } else if ( LP_ismine(utxo) > 0 && strcmp(symbol,utxo->coin) == 0 ) printf("skip %s %s %d %d %d %d\n",utxo->coin,bits256_str(str,utxo->payment.txid),LP_isunspent(utxo) != 0,strcmp(symbol,utxo->coin) == 0,utxo->iambob == iambob,LP_ismine(utxo) > 0); } return(array); } int32_t LP_maxvalue(uint64_t *values,int32_t n) { int32_t i,maxi = -1; uint64_t maxval = 0; for (i=0; i maxval ) { maxi = i; maxval = values[i]; } return(maxi); } int32_t LP_nearestvalue(int32_t iambob,uint64_t *values,int32_t n,uint64_t targetval) { int32_t i,mini = -1; int64_t dist; uint64_t mindist = (1 << 31); for (i=0; i= 0 && dist < mindist ) { mini = i; mindist = dist; } } return(mini); } int32_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 myprivkey,bits256 mypub) { int32_t enable_utxos = 0; char *script,destaddr[64]; struct LP_utxoinfo *utxo; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,flag=0,height,n,cmpflag,iambob,vout,depositvout; uint64_t *values=0,satoshis,txfee,depositval,value,total = 0; int64_t targetval; if ( coin == 0 ) { printf("coin not active\n"); return(0); } //printf("privkey init.(%s) %s\n",coin->symbol,coin->smartaddr); if ( coin->inactive == 0 && (array= LP_listunspent(coin->symbol,coin->smartaddr)) != 0 ) { txfee = LP_txfeecalc(coin,0); if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { for (iambob=0; iambob<=1; iambob++) { if ( iambob == 0 ) values = calloc(n,sizeof(*values)); else memset(values,0,n * sizeof(*values)); used = 0; for (i=0; ielectrum == 0 ) { txid = jbits256(item,"txid"); vout = juint(item,"vout"); value = LP_value_extract(item,0); height = LP_getheight(coin) - jint(item,"confirmations"); } else { txid = jbits256(item,"tx_hash"); vout = juint(item,"tx_pos"); value = j64bits(item,"value"); height = jint(item,"height"); } satoshis = LP_txvalue(destaddr,coin->symbol,txid,vout); if ( satoshis != 0 && satoshis != value ) printf("unexpected privkey_init value mismatch %.8f vs %.8f (%s) %.8f %.8f\n",dstr(satoshis),dstr(value),jprint(item,0),jdouble(item,"amount"),jdouble(item,"interest")); if ( LP_inventory_prevent(iambob,coin->symbol,txid,vout) == 0 && height > 0 ) { //printf("%s\n",jprint(item,0)); values[i] = satoshis; flag += LP_address_utxoadd(coin,destaddr,txid,vout,satoshis,height,-1); } else used++; } //printf("array.%d\n",n); while ( used < n-1 ) { //for (i=0; i= 0 ) { item = jitem(array,i); if ( coin->electrum == 0 ) { deposittxid = jbits256(item,"txid"); depositvout = juint(item,"vout"); script = jstr(item,"scriptPubKey"); } else { deposittxid = jbits256(item,"tx_hash"); depositvout = juint(item,"tx_pos"); script = coin->smartaddr; } depositval = values[i]; values[i] = 0, used++; if ( iambob == 0 ) targetval = (depositval / 776) + txfee; else targetval = (depositval / 9) * 8 + 2*txfee; if ( targetval < txfee*2 ) targetval = txfee*2; //printf("iambob.%d i.%d deposit %.8f min %.8f target %.8f\n",iambob,i,dstr(depositval),dstr((1+LP_MINSIZE_TXFEEMULT)*txfee),dstr(targetval)); if ( depositval < (1+LP_MINSIZE_TXFEEMULT)*txfee ) continue; i = -1; if ( iambob != 0 ) { if ( (i= LP_nearestvalue(iambob,values,n,targetval)) < 0 ) targetval /= 4; if ( targetval < txfee*(1+LP_MINSIZE_TXFEEMULT) ) continue; } if ( i >= 0 || (i= LP_nearestvalue(iambob,values,n,targetval)) >= 0 ) { //printf("iambob.%d i.%d %.8f target %.8f\n",iambob,i,dstr(depositval),dstr(targetval)); item = jitem(array,i); cmpflag = 0; if ( coin->electrum == 0 ) { txid = jbits256(item,"txid"); vout = juint(item,"vout"); if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 ) cmpflag = 1; } else { txid = jbits256(item,"tx_hash"); vout = juint(item,"tx_pos"); cmpflag = 1; } if ( cmpflag != 0 ) { value = values[i]; values[i] = 0, used++; portable_mutex_lock(&LP_UTXOmutex); if ( iambob != 0 ) { if ( (utxo= LP_utxoadd(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_gui,LP_sessionid)) != 0 ) { } } else { //printf("call utxoadd\n"); if ( (utxo= LP_utxoadd(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,LP_gui,LP_sessionid)) != 0 ) { } } portable_mutex_unlock(&LP_UTXOmutex); total += value; } else printf("scriptmismatch.(%s) vs %s\n",script,jprint(item,0)); } //else printf("nothing near i.%d\n",i); } else break; } if ( iambob == 1 ) free(values); if ( enable_utxos == 0 ) break; } } free_json(array); if ( flag != 0 ) LP_postutxos(coin->symbol,coin->smartaddr); } //printf("privkey.%s %.8f\n",symbol,dstr(total)); return(flag); } char *LP_secretaddresses(void *ctx,char *passphrase,int32_t n,uint8_t taddr,uint8_t pubtype) { int32_t i; uint8_t tmptype,pubkey33[33],rmd160[20]; char output[777*45],str[65],str2[65],buf[8192],wifstr[128],coinaddr[64]; bits256 checkprivkey,privkey,pubkey; cJSON *retjson; retjson = cJSON_CreateObject(); if ( passphrase == 0 || passphrase[0] == 0 ) passphrase = "password"; if ( n <= 0 ) n = 16; else if ( n > 777 ) n = 777; conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); bitcoin_priv2pub(ctx,pubkey33,coinaddr,privkey,taddr,pubtype); printf("generator (%s) secrets.[%d] <%s> t.%u p.%u\n",coinaddr,n,passphrase,taddr,pubtype); sprintf(output,"\"addresses\":["); for (i=0; i %s vs %s?\n",wifstr,bits256_str(str,privkey),bits256_str(str2,checkprivkey)); free_json(retjson); return(clonestr("{\"error\":\"couldnt validate wifstr\"}")); } else if ( tmptype != pubtype ) { printf("checktype.%d != pubtype.%d\n",tmptype,pubtype); free_json(retjson); return(clonestr("{\"error\":\"couldnt validate pubtype\"}")); } jaddstr(retjson,coinaddr,wifstr); sprintf(output+strlen(output),"\\\"%s\\\"%c ",coinaddr,ibytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); //vcalc_sha256(0,checkkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); //printf("SHA256.(%s) ",bits256_str(pstr,checkkey)); //printf("privkey.(%s)\n",bits256_str(pstr,privkey)); } else { bitcoin_wif2priv(coin->wiftaddr,&tmptype,&privkey,wifstr); if ( 0 ) { char str[65],str2[65]; checkkey = iguana_wif2privkey(wifstr); if ( bits256_cmp(checkkey,privkey) != 0 ) printf("WIF.(%s) -> %s or %s?\n",wifstr,bits256_str(str,privkey),bits256_str(str2,checkkey)); } } bitcoin_priv2pub(ctx,coin->pubkey33,coin->smartaddr,privkey,coin->taddr,coin->pubtype); if ( coin->counter == 0 ) { coin->counter++; bitcoin_priv2wif(coin->wiftaddr,tmpstr,privkey,coin->wiftype); bitcoin_addr2rmd160(coin->taddr,&tmptype,LP_myrmd160,coin->smartaddr); LP_privkeyadd(privkey,LP_myrmd160); if ( 0 && (coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0) ) printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( counter++ == 0 ) { bitcoin_priv2wif(coin->wiftaddr,USERPASS_WIFSTR,privkey,188); bitcoin_wif2priv(coin->wiftaddr,&tmptype,&checkkey,USERPASS_WIFSTR); if ( bits256_cmp(checkkey,privkey) != 0 ) { char str[65],str2[65]; printf("FATAL ERROR converting USERPASS_WIFSTR %s -> %s != %s\n",USERPASS_WIFSTR,bits256_str(str,checkkey),bits256_str(str2,privkey)); exit(-1); } conv_NXTpassword(userpass.bytes,pubkeyp->bytes,(uint8_t *)USERPASS_WIFSTR,(int32_t)strlen(USERPASS_WIFSTR)); userpub = curve25519(userpass,curve25519_basepoint9()); printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); } if ( coin->electrum == 0 && (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) { if ( jobj(retjson,"error") != 0 ) { printf("cant importprivkey.%s -> (%s), abort session\n",coin->symbol,jprint(retjson,1)); exit(-1); } } } LP_mypub25519 = *pubkeyp = curve25519(privkey,curve25519_basepoint9()); LP_mypriv25519 = privkey; //printf("privkey.(%s) -> LP_mypub25519.(%s)\n",bits256_str(str,privkey),bits256_str(str2,LP_mypub25519)); return(privkey); } void LP_privkey_updates(void *ctx,int32_t pubsock,char *passphrase,int32_t initonly) { struct iguana_info *coin,*tmp; bits256 pubkey,privkey; uint8_t pubkey33[33]; memset(privkey.bytes,0,sizeof(privkey)); pubkey = privkey; HASH_ITER(hh,LP_coins,coin,tmp) { //printf("i.%d of %d\n",i,LP_numcoins); if ( bits256_nonz(privkey) == 0 || coin->smartaddr[0] == 0 ) privkey = LP_privkeycalc(ctx,pubkey33,&pubkey,coin,passphrase,""); if ( coin->inactive == 0 && initonly == 0 ) { if ( LP_privkey_init(pubsock,coin,privkey,pubkey) == 0 && (rand() % 10) == 0 ) LP_postutxos(coin->symbol,coin->smartaddr); } } }