/******************************************************************************
* 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 , G . 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 )
{
struct LP_address_utxo * up ; struct _LP_utxoinfo u ; struct iguana_info * coin ;
if ( ( coin = LP_coinfind ( utxo - > coin ) ) = = 0 )
return ( 0 ) ;
if ( ( up = LP_address_utxofind ( coin , utxo - > coinaddr , utxo - > payment . txid , utxo - > payment . vout ) ) ! = 0 & & up - > spendheight > 0 )
{
utxo - > T . spentflag = up - > spendheight ;
return ( 0 ) ;
}
u = ( utxo - > iambob ! = 0 ) ? utxo - > deposit : utxo - > fee ;
if ( ( up = LP_address_utxofind ( coin , utxo - > coinaddr , u . txid , u . vout ) ) ! = 0 & & up - > spendheight > 0 )
{
utxo - > T . spentflag = up - > spendheight ;
return ( 0 ) ;
}
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 ; i < n ; i + + )
if ( ptrs [ i ] = = utxo )
return ( n ) ;
ptrs [ n + + ] = utxo ;
return ( n ) ;
}
int32_t LP_utxocollisions ( struct LP_utxoinfo * ptrs [ ] , struct LP_utxoinfo * refutxo )
{
int32_t iambob , n = 0 ; struct LP_utxoinfo * utxo ; struct _LP_utxoinfo u ;
if ( refutxo = = 0 )
return ( 0 ) ;
portable_mutex_lock ( & LP_utxomutex ) ;
for ( iambob = 0 ; iambob < = 1 ; iambob + + )
{
if ( ( utxo = _LP_utxofind ( iambob , refutxo - > payment . 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 ; i < n ; i + + )
_LP_unavailableset ( ptrs [ i ] , otherpubkey ) ;
}
u = ( utxo - > iambob ! = 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 < n ; i + + )
count + = _LP_availableset ( ptrs [ i ] ) ;
}
count + = _LP_availableset ( utxo ) ;
if ( count > 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 ) ;
}
}
}
cJSON * LP_inventoryjson ( cJSON * item , struct LP_utxoinfo * utxo )
{
struct _LP_utxoinfo u ;
//jaddstr(item,"method","oldutxo");
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 ) ;
}
struct LP_utxoinfo * LP_utxo_bestfit ( char * symbol , uint64_t destsatoshis )
{
uint64_t srcvalue , srcvalue2 ; struct LP_utxoinfo * utxo , * tmp , * bestutxo = 0 ; int32_t iambob = 0 ;
if ( symbol = = 0 | | destsatoshis = = 0 )
{
printf ( " LP_utxo_bestfit error symbol.%p %.8f \n " , symbol , dstr ( destsatoshis ) ) ;
return ( 0 ) ;
}
// jl777 remove mempool
HASH_ITER ( hh , G . LP_utxoinfos [ iambob ] , utxo , tmp )
{
//char str[65]; printf("s%u %d [%.8f vs %.8f] check %s.%s avail.%d ismine.%d >= %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 & & ( 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 )
{
if ( utxo = = 0 )
return ;
utxo - > T . spentflag = ( uint32_t ) time ( NULL ) ;
}
/*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 \" } " ) ) ;
} */
struct LP_utxoinfo * LP_utxoadd ( int32_t iambob , char * symbol , bits256 txid , int32_t vout , int64_t value , bits256 txid2 , int32_t vout2 , int64_t value2 , 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 | | coinaddr = = 0 | | coinaddr [ 0 ] = = 0 | | bits256_nonz ( txid ) = = 0 | | bits256_nonz ( txid2 ) = = 0 | | vout < 0 | | vout2 < 0 | | value < = 0 | | value2 < = 0 ) //|| sessionid == 0 )
{
char str [ 65 ] , str2 [ 65 ] ; printf ( " REJECT %s iambob.%d %s utxoadd.(%.8f %.8f) %s %s \n " , coinaddr , iambob , symbol , dstr ( value ) , dstr ( value2 ) , bits256_str ( str , txid ) , bits256_str ( str2 , txid2 ) ) ;
printf ( " session.%u addutxo %d %d %d %d %d %d %d %d \n " , sessionid , symbol = = 0 , coinaddr = = 0 , bits256_nonz ( txid ) = = 0 , bits256_nonz ( txid2 ) = = 0 , vout < 0 , vout2 < 0 , value < = 0 , value2 < = 0 ) ;
return ( 0 ) ;
}
/*if ( iambob != 0 )
{
printf ( " deprecated bob utxos \n " ) ;
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 , 0 ) ;
if ( iambob ! = 0 & & value2 < 9 * ( value > > 3 ) + 2 * txfee ) // big txfee padding
{
if ( value2 > 2 * txfee )
tmpsatoshis = ( ( ( value2 - 2 * txfee ) / 9 ) < < 3 ) ;
else
{
printf ( " value2 %.8f <= 2 * %.8f \n " , dstr ( value2 ) , dstr ( txfee ) ) ;
return ( 0 ) ;
}
} else tmpsatoshis = ( value - txfee ) ;
char str [ 65 ] , str2 [ 65 ] , dispflag = 0 ; //(iambob == 0);
if ( iambob = = 0 & & bits256_cmp ( pubkey , G . 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 )
{
static uint32_t counter ;
if ( counter + + < 3 )
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 %s %s/v%d \n " , numconfirms , symbol , bits256_str ( str , txid2 ) , vout2 ) ;
return ( 0 ) ;
}
}
else
{
val = value ;
val2 = value2 ;
}
dispflag = 0 ;
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 ( 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 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 ( 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 ) ;
//printf("return existing utxo[%d] %s %s\n",iambob,bits256_str(str,utxo->payment.txid),bits256_str(str2,iambob != 0 ? utxo->deposit.txid : utxo->fee.txid));
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 = G . 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(" %s %.8f %.8f %p addutxo.%d (%s %s) session.%u iambob.%d <<<<<<<<<<<<<<<\n",symbol,dstr(value),dstr(value2),utxo,LP_ismine(utxo) > 0,bits256_str(str,utxo->payment.txid),bits256_str(str2,iambob != 0 ? utxo->deposit.txid : utxo->fee.txid),utxo->T.sessionid,iambob);
portable_mutex_lock ( & LP_utxomutex ) ;
HASH_ADD_KEYPTR ( hh , G . LP_utxoinfos [ iambob ] , utxo - > key , sizeof ( utxo - > key ) , utxo ) ;
if ( _LP_utxo2find ( iambob , txid2 , vout2 ) = = 0 )
HASH_ADD_KEYPTR ( hh2 , G . LP_utxoinfos2 [ iambob ] , utxo - > key2 , sizeof ( utxo - > key2 ) , utxo ) ;
portable_mutex_unlock ( & LP_utxomutex ) ;
if ( iambob ! = 0 )
{
if ( LP_ismine ( utxo ) > 0 )
{
//LP_utxo_clientpublish(utxo);
if ( LP_mypeer ! = 0 )
utxo - > T . lasttime = ( uint32_t ) time ( NULL ) ;
}
}
return ( utxo ) ;
}
cJSON * LP_inventory ( char * symbol )
{
struct LP_utxoinfo * utxo , * tmp ; struct _LP_utxoinfo u ; char * myipaddr ; cJSON * array ; uint64_t val , val2 ; int32_t iambob = 0 ; struct iguana_info * coin ;
array = cJSON_CreateArray ( ) ;
if ( LP_mypeer ! = 0 )
myipaddr = LP_mypeer - > ipaddr ;
else myipaddr = " 127.0.0.1 " ;
if ( ( coin = LP_coinfind ( symbol ) ) ! = 0 )
{
coin - > unspenttime = ( uint32_t ) time ( NULL ) - 777 ;
LP_listunspent_both ( symbol , coin - > smartaddr , 0 ) ;
}
HASH_ITER ( hh , G . 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 ( 0 & & 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 < n ; i + + )
if ( values [ 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 < n ; i + + )
{
dist = ( values [ i ] - targetval ) ;
if ( iambob ! = 0 & & dist < 0 & & - dist < values [ i ] / 10 )
dist = - dist ;
//printf("(%.8f %.8f %.8f).%d ",dstr(values[i]),dstr(dist),dstr(mindist),mini);
if ( dist > = 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 | | ( IAMLP = = 0 & & coin - > inactive ! = 0 ) )
{
//printf("coin not active\n");
return ( 0 ) ;
}
//printf("privkey init.(%s) %s\n",coin->symbol,coin->smartaddr);
if ( coin - > inactive = = 0 )
LP_listunspent_issue ( coin - > symbol , coin - > smartaddr , 0 ) ;
LP_address ( coin , coin - > smartaddr ) ;
if ( coin - > inactive = = 0 & & ( array = LP_listunspent ( coin - > symbol , coin - > smartaddr ) ) ! = 0 )
{
txfee = LP_txfeecalc ( coin , 0 , 0 ) ;
if ( is_cJSON_Array ( array ) ! = 0 & & ( n = cJSON_GetArraySize ( array ) ) > 0 )
{
//printf("LP_privkey_init %s %s\n",coin->symbol,jprint(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 ; i < n ; i + + )
{
item = jitem ( array , i ) ;
if ( coin - > electrum = = 0 )
{
txid = jbits256 ( item , " txid " ) ;
vout = juint ( item , " vout " ) ;
value = LP_value_extract ( item , 0 ) ;
height = LP_txheight ( coin , txid ) ; //LP_getheight(coin) - jint(item,"confirmations") + 1;
}
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<n; i++)
// printf("%.8f ",dstr(values[i]));
//printf("used.%d of n.%d\n",used,n);
if ( ( i = LP_maxvalue ( values , n ) ) > = 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 , coin - > symbol , txid , vout , value , deposittxid , depositvout , depositval , coin - > smartaddr , mypub , LP_gui , G . LP_sessionid ) ) ! = 0 )
{
}
}
else
{
//printf("call utxoadd\n");
if ( ( utxo = LP_utxoadd ( 0 , coin - > symbol , deposittxid , depositvout , depositval , txid , vout , value , coin - > smartaddr , mypub , LP_gui , G . 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 ( enable_utxos = = 0 )
break ;
}
}
free_json ( array ) ;
if ( flag ! = 0 )
LP_postutxos ( coin - > symbol , coin - > smartaddr ) ;
}
if ( values ! = 0 )
free ( values ) ;
//printf("privkey.%s %.8f\n",symbol,dstr(total));
return ( flag ) ;
}
char * LP_secretaddresses ( void * ctx , char * prefix , 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 ( prefix = = 0 | | prefix [ 0 ] = = 0 )
prefix = " secretaddress " ;
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 < n ; i + + )
{
sprintf ( buf , " %s %s %03d " , prefix , passphrase , i ) ;
conv_NXTpassword ( privkey . bytes , pubkey . bytes , ( uint8_t * ) buf , ( int32_t ) strlen ( buf ) ) ;
bitcoin_priv2pub ( ctx , pubkey33 , coinaddr , privkey , taddr , pubtype ) ;
bitcoin_priv2wif ( 0 , wifstr , privkey , 188 ) ;
bitcoin_wif2priv ( 0 , & tmptype , & checkprivkey , wifstr ) ;
bitcoin_addr2rmd160 ( taddr , & tmptype , rmd160 , coinaddr ) ;
if ( bits256_cmp ( checkprivkey , privkey ) ! = 0 )
{
printf ( " WIF.(%s) error -> %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 , i < n - 1 ? ' , ' : ' ' ) ;
printf ( " ./komodo-cli jumblr_secret %s \n " , coinaddr ) ;
}
printf ( " %s] \n " , output ) ;
return ( jprint ( retjson , 1 ) ) ;
}
bits256 LP_privkeycalc ( void * ctx , uint8_t * pubkey33 , bits256 * pubkeyp , struct iguana_info * coin , char * passphrase , char * wifstr )
{
//static uint32_t counter;
bits256 privkey , userpub , userpass , checkkey ; char tmpstr [ 128 ] ; cJSON * retjson ; uint8_t tmptype ;
if ( passphrase ! = 0 & & passphrase [ 0 ] ! = 0 )
{
conv_NXTpassword ( privkey . bytes , pubkeyp - > bytes , ( 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 + + ;
memcpy ( G . LP_pubsecp , coin - > pubkey33 , 33 ) ;
bitcoin_priv2wif ( coin - > wiftaddr , tmpstr , privkey , coin - > wiftype ) ;
bitcoin_addr2rmd160 ( coin - > taddr , & tmptype , G . LP_myrmd160 , coin - > smartaddr ) ;
LP_privkeyadd ( privkey , G . 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 ( G . counter + + = = 0 )
{
bitcoin_priv2wif ( coin - > wiftaddr , G . USERPASS_WIFSTR , privkey , 188 ) ;
bitcoin_wif2priv ( coin - > wiftaddr , & tmptype , & checkkey , G . USERPASS_WIFSTR ) ;
if ( bits256_cmp ( checkkey , privkey ) ! = 0 )
{
char str [ 65 ] , str2 [ 65 ] ;
printf ( " FATAL ERROR converting USERPASS_WIFSTR %s -> %s != %s \n " , G . USERPASS_WIFSTR , bits256_str ( str , checkkey ) , bits256_str ( str2 , privkey ) ) ;
exit ( - 1 ) ;
}
conv_NXTpassword ( userpass . bytes , pubkeyp - > bytes , ( uint8_t * ) G . USERPASS_WIFSTR , ( int32_t ) strlen ( G . USERPASS_WIFSTR ) ) ;
userpub = curve25519 ( userpass , curve25519_basepoint9 ( ) ) ;
printf ( " userpass.(%s) \n " , bits256_str ( G . USERPASS , userpub ) ) ;
}
if ( coin - > electrum = = 0 & & coin - > userpass [ 0 ] ! = 0 )
{
LP_listunspent_issue ( coin - > symbol , coin - > smartaddr , 0 ) ;
if ( ( 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 ) ;
}
} else free_json ( retjson ) ;
}
}
vcalc_sha256 ( 0 , checkkey . bytes , privkey . bytes , sizeof ( privkey ) ) ;
checkkey . bytes [ 0 ] & = 248 , checkkey . bytes [ 31 ] & = 127 , checkkey . bytes [ 31 ] | = 64 ;
G . LP_mypub25519 = * pubkeyp = curve25519 ( checkkey , curve25519_basepoint9 ( ) ) ;
G . LP_mypriv25519 = checkkey ;
return ( privkey ) ;
}
void LP_privkey_updates ( void * ctx , int32_t pubsock , char * passphrase )
{
struct iguana_info * coin , * tmp ; bits256 pubkey , privkey ; uint8_t pubkey33 [ 33 ] ; int32_t initonly ;
initonly = ( passphrase ! = 0 ) ;
memset ( privkey . bytes , 0 , sizeof ( privkey ) ) ;
memset ( pubkey . bytes , 0 , sizeof ( pubkey ) ) ;
//printf("Total coins: %d\n", HASH_COUNT(LP_coins));
//int num_iter = 0;
HASH_ITER ( hh , LP_coins , coin , tmp )
{
//printf("LP_privkey_updates [%02d / %02d]\n", num_iter++, HASH_COUNT(LP_coins));
if ( initonly ! = 0 )
{
coin - > counter = 0 ;
memset ( coin - > smartaddr , 0 , sizeof ( coin - > smartaddr ) ) ;
if ( bits256_nonz ( privkey ) = = 0 | | coin - > smartaddr [ 0 ] = = 0 )
privkey = LP_privkeycalc ( ctx , pubkey33 , & pubkey , coin , passphrase , " " ) ;
}
//printf("i.%d of %d\n",i,LP_numcoins);
else if ( IAMLP = = 0 | | coin - > inactive = = 0 )
{
if ( LP_privkey_init ( pubsock , coin , G . LP_mypriv25519 , G . LP_mypub25519 ) = = 0 & & ( rand ( ) % 10 ) = = 0 )
LP_postutxos ( coin - > symbol , coin - > smartaddr ) ;
}
}
}
int32_t LP_passphrase_init ( char * passphrase , char * gui )
{
static void * ctx ; int32_t iambob ; struct LP_utxoinfo * utxo , * tmp ;
if ( ctx = = 0 )
ctx = bitcoin_ctx ( ) ;
if ( G . LP_pendingswaps ! = 0 )
return ( - 1 ) ;
G . initializing = 1 ;
if ( gui = = 0 )
gui = " cli " ;
while ( G . waiting = = 0 )
{
printf ( " waiting for G.waiting \n " ) ;
sleep ( 5 ) ;
}
for ( iambob = 0 ; iambob < 2 ; iambob + + )
{
if ( G . LP_utxoinfos [ iambob ] ! = 0 )
{
HASH_ITER ( hh , G . LP_utxoinfos [ iambob ] , utxo , tmp )
{
HASH_DELETE ( hh , G . LP_utxoinfos [ iambob ] , utxo ) ;
free ( utxo ) ;
}
}
if ( G . LP_utxoinfos2 [ iambob ] ! = 0 )
{
HASH_ITER ( hh , G . LP_utxoinfos2 [ iambob ] , utxo , tmp )
{
HASH_DELETE ( hh , G . LP_utxoinfos2 [ iambob ] , utxo ) ;
free ( utxo ) ;
}
}
}
memset ( & G , 0 , sizeof ( G ) ) ;
LP_privkey_updates ( ctx , LP_mypubsock , passphrase ) ;
init_hexbytes_noT ( G . LP_myrmd160str , G . LP_myrmd160 , 20 ) ;
G . LP_sessionid = ( uint32_t ) time ( NULL ) ;
safecopy ( G . gui , gui , sizeof ( G . gui ) ) ;
return ( 0 ) ;
}