/******************************************************************************
* Copyright © 2014 - 2016 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 . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//#define uthash_malloc(size) iguana_memalloc(&coin->RThashmem,size,1)
//#define uthash_free(ptr,size)
# include "iguana777.h"
# include "exchanges/bitcoin.h"
int32_t iguana_unspentind2txid ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t * spentheightp , bits256 * txidp , int32_t * voutp , int16_t hdrsi , uint32_t unspentind )
{
struct iguana_ramchaindata * rdata = 0 ; struct iguana_bundle * bp = 0 ; struct iguana_unspent * U , * u ; struct iguana_txid * T , * t ;
* voutp = * spentheightp = - 1 ;
memset ( txidp , 0 , sizeof ( * txidp ) ) ;
//if ( hdrsi == coin->bundlescount-1 )
// rdata = coin->RTramchain.H.data;
//else if ( (bp= coin->bundles[hdrsi]) != 0 )
bp = coin - > bundles [ hdrsi ] ;
rdata = bp - > ramchain . H . data ;
while ( rdata ! = 0 & & unspentind > 0 & & unspentind < rdata - > numunspents )
{
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
u = & U [ unspentind ] ;
if ( u - > txidind > 0 & & u - > txidind < rdata - > numtxids )
{
T = RAMCHAIN_PTR ( rdata , Toffset ) ;
t = & T [ u - > txidind ] ;
if ( unspentind > = t - > firstvout )
{
* txidp = t - > txid ;
* spentheightp = ( hdrsi * coin - > chain - > bundlesize ) + t - > bundlei ;
* voutp = unspentind - t - > firstvout ;
return ( 0 ) ;
}
}
else if ( bp = = 0 & & ( bp = coin - > bundles [ hdrsi ] ) ! = 0 )
rdata = bp - > ramchain . H . data ;
else break ;
}
return ( - 1 ) ;
//{"txid":"e34686afc17ec37a8438f0c9a7e48f98d0c625c7917a59c2d7fa22b53d570115","vout":1,"address":"16jsjc1YvzDXqKf7PorMhTyK8ym3ra3uxm","scriptPubKey":"76a9143ef4734c1141725c095342095f6e0e7748b6c16588ac","amount":0.01000000,"timestamp":0,"height":419261,"confirmations":1729,"checkind":4497018,"account":"default","spendable":true,"spent":{"hdrsi":209,"pkind":2459804,"unspentind":4497018,"prevunspentind":0,"satoshis":"1000000","txidind":1726947,"vout":1,"type":2,"fileid":0,"scriptpos":0,"scriptlen":25},"spentheight":419713,"dest":{"spentfrom":"22651e62f248fe2e72053d650f177e4b246ee016605102a40419e603b2bbeac8","vin":0,"timestamp":0,"vouts":[{"1KRhTPvoxyJmVALwHFXZdeeWFbcJSbkFPu":0.00010000}, {"1GQHQ7vwVpGeir2kKrYATsLtrkUQSc7FGY":0.00980000}],"total":0.00990000,"ratio":1}}
cJSON * retarray , * item , * uitem , * sitem ; char * retstr ; int32_t i , n , retval = - 1 ;
* voutp = * spentheightp = - 1 ;
memset ( txidp , 0 , sizeof ( * txidp ) ) ;
if ( ( retstr = bitcoinrpc_listunspent ( myinfo , coin , 0 , 0 , 0 , 0 , 0 ) ) ! = 0 )
{
if ( ( retarray = cJSON_Parse ( retstr ) ) ! = 0 )
{
if ( ( n = cJSON_GetArraySize ( retarray ) ) > 0 )
{
for ( i = 0 ; i < n ; i + + )
{
item = jitem ( retarray , i ) ;
if ( ( uitem = jobj ( item , " unspent " ) ) ! = 0 )
{
if ( juint ( uitem , " hdrsi " ) = = hdrsi & & juint ( uitem , " unspentind " ) = = unspentind )
{
* txidp = jbits256 ( item , " txid " ) ;
* voutp = jint ( item , " vout " ) ;
* spentheightp = 0 ;
retval = 0 ;
break ;
}
}
else if ( ( sitem = jobj ( item , " spent " ) ) ! = 0 )
{
if ( juint ( sitem , " hdrsi " ) = = hdrsi & & juint ( sitem , " unspentind " ) = = unspentind )
{
* txidp = jbits256 ( item , " txid " ) ;
* voutp = jint ( item , " vout " ) ;
* spentheightp = jint ( item , " spentheight " ) ;
retval = 1 ;
break ;
}
}
}
}
free_json ( retarray ) ;
}
free ( retstr ) ;
}
return ( retval ) ;
}
int32_t iguana_unspentindfind ( struct supernet_info * myinfo , struct iguana_info * coin , char * coinaddr , uint8_t * spendscript , int32_t * spendlenp , uint64_t * valuep , int32_t * heightp , bits256 txid , int32_t vout , int32_t lasthdrsi , int32_t mempool )
{
struct iguana_txid * tp , TX ; struct gecko_memtx * memtx ; struct iguana_pkhash * P ; struct iguana_unspent * U ; struct iguana_bundle * bp ; struct iguana_ramchaindata * rdata ; int64_t RTspend ; int64_t value ; int32_t pkind , hdrsi , firstvout , spentheight , flag = 0 , unspentind = - 1 ;
//portable_mutex_lock(&coin->RTmutex);
if ( valuep ! = 0 )
* valuep = 0 ;
if ( coinaddr ! = 0 )
coinaddr [ 0 ] = 0 ;
if ( coin - > fastfind ! = 0 & & ( firstvout = iguana_txidfastfind ( coin , heightp , txid , lasthdrsi ) ) > = 0 )
unspentind = ( firstvout + vout ) ;
else if ( ( tp = iguana_txidfind ( coin , heightp , & TX , txid , lasthdrsi ) ) ! = 0 )
unspentind = ( tp - > firstvout + vout ) ;
if ( coinaddr ! = 0 & & unspentind > 0 & & ( hdrsi = * heightp / coin - > chain - > bundlesize ) > = 0 & & hdrsi < coin - > bundlescount & & ( bp = coin - > bundles [ hdrsi ] ) ! = 0 & & ( rdata = bp - > ramchain . H . data ) ! = 0 & & unspentind < rdata - > numunspents )
{
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
P = RAMCHAIN_PTR ( rdata , Poffset ) ;
pkind = U [ unspentind ] . pkind ;
if ( pkind > 0 & & pkind < rdata - > numpkinds )
{
RTspend = 0 ;
flag + + ;
if ( iguana_spentflag ( myinfo , coin , & RTspend , & spentheight , & bp - > ramchain , bp - > hdrsi , unspentind , 0 , 1 , coin - > longestchain , U [ unspentind ] . value ) = = 0 ) //bp == coin->current ? &coin->RTramchain :
{
if ( valuep ! = 0 )
* valuep = U [ unspentind ] . value ;
bitcoin_address ( coinaddr , iguana_addrtype ( coin , U [ unspentind ] . type ) , P [ pkind ] . rmd160 , sizeof ( P [ pkind ] . rmd160 ) ) ;
if ( spendscript ! = 0 & & spendlenp ! = 0 )
* spendlenp = iguana_voutscript ( coin , bp , spendscript , 0 , & U [ unspentind ] , & P [ pkind ] , 1 ) ;
}
}
}
if ( flag = = 0 & & mempool ! = 0 )
{
if ( ( memtx = gecko_unspentfind ( 0 , coin , txid ) ) ! = 0 & & vout < memtx - > numoutputs )
{
memcpy ( & value , gecko_valueptr ( memtx , vout ) , sizeof ( value ) ) ;
if ( value > 0 )
{
* valuep = value ;
if ( spendlenp ! = 0 )
{
* spendlenp = 1 ;
spendscript = 0 ;
printf ( " mempool unspentind doesnt support scriptlenp yet \n " ) ;
}
}
}
}
//portable_mutex_unlock(&coin->RTmutex);
return ( unspentind ) ;
}
char * iguana_inputaddress ( struct supernet_info * myinfo , struct iguana_info * coin , char * coinaddr , int16_t * spent_hdrsip , uint32_t * unspentindp , cJSON * vinobj )
{
bits256 txid ; int32_t vout , checkind , height ;
* unspentindp = 0 ;
* spent_hdrsip = - 1 ;
if ( jobj ( vinobj , " txid " ) ! = 0 & & jobj ( vinobj , " vout " ) ! = 0 )
{
txid = jbits256 ( vinobj , " txid " ) ;
vout = jint ( vinobj , " vout " ) ;
height = jint ( vinobj , " height " ) ;
checkind = jint ( vinobj , " checkind " ) ;
if ( ( height ! = 0 & & checkind ! = 0 ) | | ( checkind = iguana_unspentindfind ( myinfo , coin , coinaddr , 0 , 0 , 0 , & height , txid , vout , coin - > bundlescount - 1 , 0 ) ) > 0 )
{
* spent_hdrsip = ( height / coin - > chain - > bundlesize ) ;
* unspentindp = checkind ;
return ( coinaddr ) ;
}
else
{
char str [ 65 ] ;
printf ( " error finding (%s/%d) height.%d checkind.%d \n " , bits256_str ( str , txid ) , vout , height , checkind ) ;
}
}
return ( 0 ) ;
}
cJSON * ramchain_unspentjson ( struct iguana_unspent * up , uint32_t unspentind )
{
cJSON * item = cJSON_CreateObject ( ) ;
jaddnum ( item , " hdrsi " , up - > hdrsi ) ;
jaddnum ( item , " pkind " , up - > pkind ) ;
jaddnum ( item , " unspentind " , unspentind ) ;
jaddnum ( item , " prevunspentind " , up - > prevunspentind ) ;
jadd64bits ( item , " satoshis " , up - > value ) ;
jaddnum ( item , " txidind " , up - > txidind ) ;
jaddnum ( item , " vout " , up - > vout ) ;
jaddnum ( item , " type " , up - > type ) ;
jaddnum ( item , " fileid " , up - > fileid ) ;
jaddnum ( item , " scriptpos " , up - > scriptpos ) ;
jaddnum ( item , " scriptlen " , up - > scriptlen ) ;
return ( item ) ;
}
cJSON * ramchain_spentjson ( struct iguana_info * coin , int32_t spentheight , int32_t hdrsi , int32_t unspentind , bits256 txid , int32_t vout , int64_t uvalue )
{
char coinaddr [ 64 ] ; bits256 hash2 , * X ; struct iguana_txid T , * tx , * spentT , * spent_tx ; struct iguana_bundle * bp ; int32_t j , i , ind ; struct iguana_block * block ; int64_t total = 0 ; struct iguana_unspent * U , * u ; struct iguana_pkhash * P ; struct iguana_spend * S , * s ; struct iguana_ramchaindata * rdata ; cJSON * addrs , * item , * voutobj ;
item = cJSON_CreateObject ( ) ;
hash2 = iguana_blockhash ( coin , spentheight ) ;
if ( ( block = iguana_blockfind ( " spent " , coin , hash2 ) ) ! = 0 & & ( bp = coin - > bundles [ spentheight / coin - > chain - > bundlesize ] ) ! = 0 & & ( rdata = bp - > ramchain . H . data ) ! = 0 )
{
X = RAMCHAIN_PTR ( rdata , Xoffset ) ;
S = RAMCHAIN_PTR ( rdata , Soffset ) ;
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
P = RAMCHAIN_PTR ( rdata , Poffset ) ;
spentT = RAMCHAIN_PTR ( rdata , Toffset ) ;
for ( i = 0 ; i < block - > RO . txn_count ; i + + )
{
if ( ( tx = iguana_blocktx ( coin , & T , block , i ) ) ! = 0 )
{
// struct iguana_txid { bits256 txid; uint32_t txidind:29,firstvout:28,firstvin:28,bundlei:11,locktime,version,timestamp,extraoffset; uint16_t numvouts,numvins; } __attribute__((packed));
// struct iguana_spend { uint64_t scriptpos:48,scriptlen:16; uint32_t spendtxidind,sequenceid; int16_t prevout; uint16_t fileid:15,external:1; } __attribute__((packed)); // numsigs:4,numpubkeys:4,p2sh:1,sighash:4
s = & S [ tx - > firstvin ] ;
for ( j = 0 ; j < tx - > numvins ; j + + , s + + )
{
if ( s - > prevout = = vout )
{
if ( s - > external ! = 0 )
{
ind = s - > spendtxidind & 0xfffffff ;
if ( bits256_cmp ( X [ ind ] , txid ) ! = 0 )
continue ;
}
else
{
spent_tx = & spentT [ s - > spendtxidind ] ;
if ( bits256_cmp ( spent_tx - > txid , txid ) ! = 0 )
continue ;
}
jaddbits256 ( item , " spentfrom " , tx - > txid ) ;
jaddnum ( item , " vin " , j ) ;
jaddnum ( item , " timestamp " , tx - > timestamp ) ;
u = & U [ tx - > firstvout ] ;
addrs = cJSON_CreateArray ( ) ;
for ( j = 0 ; j < tx - > numvouts ; j + + , u + + )
{
voutobj = cJSON_CreateObject ( ) ;
bitcoin_address ( coinaddr , iguana_addrtype ( coin , u - > type ) , P [ u - > pkind ] . rmd160 , sizeof ( P [ u - > pkind ] . rmd160 ) ) ;
jaddnum ( voutobj , coinaddr , dstr ( u - > value ) ) ;
jaddi ( addrs , voutobj ) ;
total + = u - > value ;
}
jadd ( item , " vouts " , addrs ) ;
jaddnum ( item , " total " , dstr ( total ) ) ;
jaddnum ( item , " ratio " , dstr ( uvalue ) / dstr ( total + coin - > txfee ) ) ;
return ( item ) ;
}
}
}
}
}
jaddstr ( item , " error " , " couldnt find spent info " ) ;
return ( item ) ;
}
cJSON * iguana_unspentjson ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t hdrsi , uint32_t unspentind , struct iguana_txid * T , struct iguana_unspent * up , uint8_t rmd160 [ 20 ] , char * coinaddr , uint8_t * pubkey33 , int32_t spentheight , char * remoteaddr )
{
/*{
" txid " : " d54994ece1d11b19785c7248868696250ab195605b469632b7bd68130e880c9a " ,
" vout " : 1 ,
" address " : " mgnucj8nYqdrPFh2JfZSB1NmUThUGnmsqe " ,
" account " : " test label " ,
" scriptPubKey " : " 76a9140dfc8bafc8419853b34d5e072ad37d1a5159f58488ac " ,
" amount " : 0.00010000 ,
" confirmations " : 6210 ,
" spendable " : true
} , */
//struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; uint16_t hdrsi:12,type:4,vout; } __attribute__((packed));
struct iguana_waccount * wacct ; struct iguana_waddress * waddr ; int32_t height ; char scriptstr [ 8192 ] , asmstr [ sizeof ( scriptstr ) + 1024 ] ; cJSON * item ; uint32_t checkind ;
item = cJSON_CreateObject ( ) ;
jaddbits256 ( item , " txid " , T [ up - > txidind ] . txid ) ;
jaddnum ( item , " vout " , up - > vout ) ;
jaddstr ( item , " address " , coinaddr ) ;
if ( iguana_scriptget ( coin , scriptstr , asmstr , sizeof ( scriptstr ) , hdrsi , unspentind , T [ up - > txidind ] . txid , up - > vout , rmd160 , up - > type , pubkey33 ) ! = 0 )
jaddstr ( item , " scriptPubKey " , scriptstr ) ;
jaddnum ( item , " amount " , dstr ( up - > value ) ) ;
jaddnum ( item , " timestamp " , T [ up - > txidind ] . timestamp ) ;
if ( ( checkind = iguana_unspentindfind ( myinfo , coin , 0 , 0 , 0 , 0 , & height , T [ up - > txidind ] . txid , up - > vout , coin - > bundlescount - 1 , 0 ) ) ! = 0 )
{
jaddnum ( item , " height " , height ) ;
jaddnum ( item , " confirmations " , coin - > blocks . hwmchain . height - height + 1 ) ;
jaddnum ( item , " checkind " , checkind ) ;
}
if ( remoteaddr = = 0 | | remoteaddr [ 0 ] = = 0 )
{
if ( ( waddr = iguana_waddresssearch ( myinfo , & wacct , coinaddr ) ) ! = 0 )
{
jaddstr ( item , " account " , wacct - > account ) ;
jadd ( item , " spendable " , jtrue ( ) ) ;
} else jadd ( item , " spendable " , jfalse ( ) ) ;
}
if ( spentheight > 0 )
{
jadd ( item , " spent " , ramchain_unspentjson ( up , unspentind ) ) ;
jaddnum ( item , " spentheight " , spentheight ) ;
jadd ( item , " dest " , ramchain_spentjson ( coin , spentheight , hdrsi , unspentind , T [ up - > txidind ] . txid , up - > vout , up - > value ) ) ;
} else jadd ( item , " unspent " , ramchain_unspentjson ( up , unspentind ) ) ;
return ( item ) ;
}
struct iguana_pkhash * iguana_pkhashfind ( struct iguana_info * coin , struct iguana_ramchain * * ramchainp , int64_t * depositsp , uint32_t * lastunspentindp , struct iguana_pkhash * p , uint8_t rmd160 [ 20 ] , int32_t firsti , int32_t endi )
{
uint8_t * PKbits ; struct iguana_pkhash * P ; uint32_t pkind , numpkinds , i ; struct iguana_bundle * bp ; struct iguana_ramchain * ramchain ; struct iguana_ramchaindata * rdata ; struct iguana_account * ACCTS ;
* depositsp = 0 ;
* ramchainp = 0 ;
* lastunspentindp = 0 ;
for ( i = firsti ; i < coin - > bundlescount & & i < = endi ; i + + )
{
if ( ( bp = coin - > bundles [ i ] ) ! = 0 )
{
if ( 0 & & coin - > RTramchain_busy ! = 0 )
{
printf ( " iguana_pkhashfind: unexpected access when RTramchain_busy \n " ) ;
return ( 0 ) ;
}
ramchain = & bp - > ramchain ; //(bp != coin->current) ? &bp->ramchain : &coin->RTramchain;
if ( ( rdata = ramchain - > H . data ) ! = 0 )
{
numpkinds = rdata - > numpkinds ;
PKbits = RAMCHAIN_PTR ( rdata , PKoffset ) ;
P = RAMCHAIN_PTR ( rdata , Poffset ) ;
if ( bp = = coin - > current )
ACCTS = ramchain - > A ;
else ACCTS = RAMCHAIN_PTR ( rdata , Aoffset ) ;
if ( ( pkind = iguana_sparseaddpk ( PKbits , rdata - > pksparsebits , rdata - > numpksparse , rmd160 , P , 0 , ramchain ) ) > 0 & & pkind < numpkinds )
{
* ramchainp = ramchain ;
* depositsp = ACCTS [ pkind ] . total ;
* lastunspentindp = ACCTS [ pkind ] . lastunspentind ;
//printf("[%d] return pkind.%u of %u P.%p %.8f last.%u ACCTS.%p %p\n",i,pkind,numpkinds,P,dstr(*depositsp),*lastunspentindp,ACCTS,ramchain->A);
if ( P ! = 0 )
* p = P [ pkind ] ;
return ( p ) ;
} else if ( pkind ! = 0 )
printf ( " [%d] not found pkind.%d vs num.%d RT.%d rdata.%p \n " , i , pkind , rdata - > numpkinds , bp - > isRT , rdata ) ;
} else if ( coin - > spendvectorsaved > 1 & & bp ! = coin - > current )
printf ( " %s.[%d] skip null rdata isRT.%d \n " , coin - > symbol , i , bp - > isRT ) ;
}
}
return ( 0 ) ;
}
int32_t iguana_uheight ( struct iguana_info * coin , int32_t bundleheight , struct iguana_txid * T , int32_t numtxids , struct iguana_unspent * up )
{
if ( up - > txidind > 0 & & up - > txidind < numtxids )
return ( bundleheight + T [ up - > txidind ] . bundlei ) ;
else return ( bundleheight ) ;
}
int32_t iguana_datachain_scan ( struct supernet_info * myinfo , struct iguana_info * coin , uint8_t rmd160 [ 20 ] )
{
int64_t deposits , crypto777_payment ; uint32_t lastunspentind , unspentind ; int32_t i , j , num , uheight ; struct iguana_bundle * bp ; struct iguana_ramchain * ramchain ; struct iguana_ramchaindata * rdata ; struct iguana_pkhash * P , p ; struct iguana_unspent * U , * u ; struct iguana_txid * T , * tx ;
for ( i = num = 0 ; i < coin - > bundlescount ; i + + )
{
if ( ( bp = coin - > bundles [ i ] ) ! = 0 )
{
//iguana_volatilesalloc(coin,&bp->ramchain,1);
//iguana_volatilesmap(coin,&bp->ramchain);
ramchain = 0 ;
if ( iguana_pkhashfind ( coin , & ramchain , & deposits , & lastunspentind , & p , rmd160 , i , i ) ! = 0 )
{
if ( ramchain ! = 0 & & ( rdata = ramchain - > H . data ) ! = 0 )
{
unspentind = lastunspentind ;
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
T = RAMCHAIN_PTR ( rdata , Toffset ) ;
P = RAMCHAIN_PTR ( rdata , Poffset ) ;
while ( unspentind > 0 )
{
tx = & T [ U [ unspentind ] . txidind ] ;
u = & U [ tx - > firstvout ] ;
uheight = iguana_uheight ( coin , ramchain - > height , T , rdata - > numtxids , u ) ;
for ( crypto777_payment = j = 0 ; j < tx - > numvouts ; j + + , u + + )
{
//u = &U[tx->firstvout + j];
crypto777_payment = datachain_update ( myinfo , 0 , coin , tx - > timestamp , bp , P [ u - > pkind ] . rmd160 , crypto777_payment , u - > type , uheight , ( ( ( uint64_t ) bp - > hdrsi < < 32 ) | unspentind ) , u - > value , u - > fileid , u - > scriptpos , u - > scriptlen , tx - > txid , j ) ;
}
num + + ;
unspentind = U [ unspentind ] . prevunspentind ;
}
}
}
}
}
//iguana_utxoaddr_gen(myinfo,coin,(coin->bundlescount - 1) * coin->chain->bundlesize);
return ( num ) ;
}
int64_t iguana_pkhashbalance ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * array , int64_t * spentp , int64_t * unspents , int32_t * nump , struct iguana_ramchain * ramchain , struct iguana_pkhash * p , uint32_t lastunspentind , uint8_t rmd160 [ 20 ] , char * coinaddr , uint8_t * pubkey33 , int32_t hdrsi , int32_t lastheight , int32_t minconf , int32_t maxconf , char * remoteaddr )
{
struct iguana_unspent * U ; struct iguana_utxo * U2 ; int32_t max , uheight , spentheight ; uint32_t pkind = 0 , unspentind ; int64_t spent = 0 , checkval , deposits = 0 ; struct iguana_txid * T ; struct iguana_account * A2 ; struct iguana_ramchaindata * rdata = 0 ; int64_t RTspend = 0 ; //struct iguana_spend *S;
max = * nump ;
* spentp = * nump = 0 ;
if ( 0 & & coin - > RTramchain_busy ! = 0 )
{
printf ( " iguana_pkhashbalance: unexpected access when RTramchain_busy \n " ) ;
return ( 0 ) ;
}
if ( ramchain - > Uextras = = 0 | | ( rdata = ramchain - > H . data ) = = 0 )
{
if ( ramchain - > height < ( coin - > bundlescount - 1 ) * coin - > chain - > bundlesize )
{
//printf("iguana_pkhashbalance.[%d] %d: unexpected null spents.%p or rdata.%p\n",ramchain->height,(coin->bundlescount-1)*coin->chain->bundlesize,ramchain->Uextras,rdata);
} else iguana_volatilesalloc ( coin , ramchain , 0 ) ;
return ( 0 ) ;
}
unspentind = lastunspentind ;
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
T = RAMCHAIN_PTR ( rdata , Toffset ) ;
RTspend = 0 ;
if ( lastheight = = 0 )
lastheight = IGUANA_MAXHEIGHT ;
while ( unspentind > 0 )
{
uheight = iguana_uheight ( coin , ramchain - > height , T , rdata - > numtxids , & U [ unspentind ] ) ;
if ( lastheight < = 0 | | uheight < lastheight )
{
deposits + = U [ unspentind ] . value ;
if ( iguana_spentflag ( myinfo , coin , & RTspend , & spentheight , ramchain , hdrsi , unspentind , lastheight , minconf , maxconf , U [ unspentind ] . value ) = = 0 )
{
if ( * nump < max & & unspents ! = 0 )
{
unspents [ * nump < < 1 ] = ( ( uint64_t ) hdrsi < < 32 ) | unspentind ;
unspents [ ( * nump < < 1 ) + 1 ] = U [ unspentind ] . value ;
}
//printf("+%.8f ",dstr(U[unspentind].value));
( * nump ) + + ;
if ( array ! = 0 )
jaddi ( array , iguana_unspentjson ( myinfo , coin , hdrsi , unspentind , T , & U [ unspentind ] , rmd160 , coinaddr , pubkey33 , spentheight , remoteaddr ) ) ;
}
else
{
//printf("-%.8f ",dstr(U[unspentind].value));
spent + = U [ unspentind ] . value ;
}
if ( p - > pkind ! = U [ unspentind ] . pkind )
printf ( " warning: [%d] p->pkind.%u vs U->pkind.%u for u%d \n " , hdrsi , p - > pkind , U [ unspentind ] . pkind , unspentind ) ;
} // else printf("skip uheight.%d lastheight.%d\n",uheight,lastheight);
pkind = p - > pkind ;
unspentind = U [ unspentind ] . prevunspentind ;
}
if ( lastheight > 0 & & ( A2 = ramchain - > A2 ) ! = 0 & & ( U2 = ramchain - > Uextras ) ! = 0 )
{
//S = RAMCHAIN_PTR(rdata,Soffset);
unspentind = A2 [ pkind ] . lastunspentind ;
checkval = 0 ;
while ( unspentind > 0 )
{
uheight = iguana_uheight ( coin , ramchain - > height , T , rdata - > numtxids , & U [ unspentind ] ) ;
if ( uheight < lastheight )
{
checkval + = U [ unspentind ] . value ;
//printf("u%u %.8f spentflag.%d prev.%u fromheight.%d\n",unspentind,dstr(U[unspentind].value),U2[unspentind].spentflag,U2[unspentind].prevunspentind,U2[unspentind].fromheight);
}
unspentind = U2 [ unspentind ] . prevunspentind ;
}
if ( 0 & & llabs ( spent - checkval - RTspend ) > SMALLVAL )
printf ( " spend %s: [%d] deposits %.8f spent %.8f check %.8f (%.8f) vs A2[%u] %.8f \n " , lastheight = = IGUANA_MAXHEIGHT ? " checkerr " : " " , hdrsi , dstr ( deposits ) , dstr ( spent ) , dstr ( checkval ) + dstr ( RTspend ) , dstr ( * spentp ) , pkind , dstr ( A2 [ pkind ] . total ) ) ;
}
( * spentp ) = spent ;
//printf("(%s) spent %.8f, RTspent %.8f deposits %.8f\n",coinaddr,dstr(spent),dstr(RTspend),dstr(deposits));
return ( deposits - spent ) ;
}
int32_t iguana_pkhasharray ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * array , int32_t minconf , int32_t maxconf , int64_t * totalp , struct iguana_pkhash * P , int32_t max , uint8_t rmd160 [ 20 ] , char * coinaddr , uint8_t * pubkey33 , int32_t lastheight , int64_t * unspents , int32_t * numunspentsp , int32_t maxunspents , char * remoteaddr )
{
int32_t i , n , m , numunspents ; int64_t spent , deposits , netbalance , total ; uint32_t lastunspentind ; struct iguana_pkhash * p , _p ; struct iguana_ramchain * ramchain ; struct iguana_bundle * bp ;
if ( 0 & & coin - > RTramchain_busy ! = 0 )
{
printf ( " iguana_pkhasharray: unexpected access when RTramchain_busy \n " ) ;
return ( - 1 ) ;
}
numunspents = numunspentsp ! = 0 ? * numunspentsp : 0 ;
if ( lastheight = = 0 )
lastheight = IGUANA_MAXHEIGHT ;
if ( max > coin - > bundlescount )
max = coin - > bundlescount ;
//printf("minconf.%d maxconf.%d max.%d addr.%s last.%d maxunspents.%d\n",minconf,maxconf,max,coinaddr,lastheight,maxunspents);
for ( total = n = i = 0 ; i < max ; i + + )
{
if ( ( bp = coin - > bundles [ i ] ) = = 0 )
continue ;
if ( 0 )
{
if ( lastheight > 0 & & bp - > bundleheight > lastheight )
{
//printf("lastheight.%d less than %d\n",lastheight,bp->bundleheight+bp->n);
break ;
}
if ( ( coin - > blocks . hwmchain . height - ( bp - > bundleheight + bp - > n - 1 ) ) > maxconf )
{
//printf("%d more than minconf.%d\n",(coin->blocks.hwmchain.height - (bp->bundleheight + bp->n - 1)),maxconf);
continue ;
}
if ( ( coin - > blocks . hwmchain . height - bp - > bundleheight ) < minconf )
{
//printf("%d less than minconf.%d\n",(coin->blocks.hwmchain.height - bp->bundleheight),minconf);
break ;
}
}
if ( iguana_pkhashfind ( coin , & ramchain , & deposits , & lastunspentind , P ! = 0 ? & P [ n ] : & _p , rmd160 , i , i ) ! = 0 )
{
m = maxunspents > > 1 ;
p = ( P = = 0 ) ? & _p : & P [ n ] ;
if ( ( netbalance = iguana_pkhashbalance ( myinfo , coin , array , & spent , unspents ! = 0 ? & unspents [ numunspents < < 1 ] : 0 , & m , ramchain , p , lastunspentind , rmd160 , coinaddr , pubkey33 , i , lastheight , minconf , maxconf , remoteaddr ) ) ! = deposits - spent & & lastheight = = IGUANA_MAXHEIGHT & & minconf = = 1 & & maxconf > coin - > blocks . hwmchain . height )
{
printf ( " pkhash balance mismatch from m.%d check %.8f vs %.8f spent %.8f [%.8f] \n " , m , dstr ( netbalance ) , dstr ( deposits ) , dstr ( spent ) , dstr ( deposits ) - dstr ( spent ) ) ;
}
else
{
//printf("%s pkhash balance.[%d] from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",coinaddr,i,m,dstr(netbalance),dstr(deposits),dstr(spent),dstr(deposits)-dstr(spent));
total + = netbalance ;
n + + ;
}
if ( maxunspents > 0 )
{
maxunspents - = m ;
if ( maxunspents < = 0 )
break ;
}
numunspents + = m ;
//printf("%d: balance %.8f, lastunspent.%u m.%d num.%d max.%d\n",i,dstr(total),lastunspentind,m,numunspents,maxunspents);
}
}
if ( numunspentsp ! = 0 )
* numunspentsp = numunspents ;
//printf("numunspents.%d max.%d\n",numunspents,maxunspents);
* totalp + = total ;
return ( n ) ;
}
int64_t iguana_unspents ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * array , int32_t minconf , int32_t maxconf , uint8_t * rmdarray , int32_t numrmds , int32_t lastheight , int64_t * unspents , int32_t * numunspentsp , char * remoteaddr )
{
int64_t total = 0 , sum = 0 ; struct iguana_pkhash * P ; uint8_t * addrtypes , * pubkeys ; int32_t i , numunspents , maxunspents , flag = 0 ; char coinaddr [ 64 ] ;
//portable_mutex_lock(&coin->RTmutex);
while ( 0 & & coin - > RTramchain_busy ! = 0 )
{
fprintf ( stderr , " iguana_pkhasharray: %s unexpected access when RTramchain_busy \n " , coin - > symbol ) ;
sleep ( 1 ) ;
}
numunspents = 0 ;
maxunspents = * numunspentsp ;
if ( rmdarray = = 0 )
rmdarray = iguana_walletrmds ( myinfo , coin , & numrmds ) , flag + + ;
if ( numrmds > 0 & & rmdarray ! = 0 )
{
addrtypes = & rmdarray [ numrmds * 20 ] , pubkeys = & rmdarray [ numrmds * 21 ] ;
P = calloc ( coin - > bundlescount , sizeof ( * P ) ) ;
for ( i = 0 ; i < numrmds ; i + + )
{
bitcoin_address ( coinaddr , addrtypes [ i ] , & rmdarray [ i * 20 ] , 20 ) ;
* numunspentsp = 0 ;
iguana_pkhasharray ( myinfo , coin , array , minconf , maxconf , & total , P , coin - > bundlescount , & rmdarray [ i * 20 ] , coinaddr , & pubkeys [ 33 * i ] , lastheight , & unspents [ numunspents < < 1 ] , numunspentsp , maxunspents , remoteaddr ) ;
//printf("iguana_unspents: i.%d of %d: %s %.8f numunspents.%d\n",i,numrmds,coinaddr,dstr(total),*numunspentsp);
maxunspents - = * numunspentsp ;
numunspents + = * numunspentsp ;
sum + = total ;
}
//printf("sum %.8f\n",dstr(sum));
free ( P ) ;
}
* numunspentsp = numunspents ;
if ( flag ! = 0 & & rmdarray ! = 0 )
free ( rmdarray ) ;
//portable_mutex_unlock(&coin->RTmutex);
return ( sum ) ;
}
uint8_t * iguana_rmdarray ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t * numrmdsp , cJSON * array , int32_t firsti )
{
int32_t i , n , flag = 0 , j = 0 ; char * coinaddr , rmdstr [ 41 ] ; uint8_t * addrtypes , * rmdarray = 0 ;
* numrmdsp = 0 ;
if ( array = = 0 | | cJSON_GetArraySize ( array ) = = 0 )
array = iguana_getaddressesbyaccount ( myinfo , coin , " * " ) ;
if ( array ! = 0 & & ( n = cJSON_GetArraySize ( array ) ) > 0 )
{
* numrmdsp = n - firsti ;
rmdarray = calloc ( 1 , ( n - firsti ) * ( 21 + 33 ) ) ;
addrtypes = & rmdarray [ ( n - firsti ) * 20 ] ;
for ( i = firsti ; i < n ; i + + )
{
if ( ( coinaddr = jstr ( jitem ( array , i ) , 0 ) ) ! = 0 )
{
bitcoin_addr2rmd160 ( & addrtypes [ j ] , & rmdarray [ 20 * j ] , coinaddr ) ;
init_hexbytes_noT ( rmdstr , & rmdarray [ 20 * j ] , 20 ) ;
//printf("(%s %s) ",coinaddr,rmdstr);
j + + ;
}
}
//printf("rmdarray[%d]\n",n);
}
if ( flag ! = 0 )
free_json ( array ) ;
return ( rmdarray ) ;
}
int64_t * iguana_PoS_weights ( struct supernet_info * myinfo , struct iguana_info * coin , struct iguana_pkhash * * Ptrp , int64_t * supplyp , int32_t * numacctsp , int32_t * nonzp , int32_t * errsp , int32_t lastheight )
{
int64_t balance , total , supply , * weights = 0 ; uint32_t pkind ; int32_t numrmds , minconf , neg , numunspents , nonz , num = 0 ; struct iguana_bundle * bp ; struct iguana_ramchaindata * rdata ; struct iguana_pkhash * refP ; uint8_t rmd160 [ 20 ] , * rmdarray ; cJSON * array ; char coinaddr [ 64 ] ; //struct iguana_account *A2; struct iguana_utxo *U2;
* supplyp = 0 ;
* numacctsp = * nonzp = 0 ;
* errsp = 1 ;
( * Ptrp ) = 0 ;
if ( ( bp = coin - > bundles [ lastheight / coin - > chain - > bundlesize ] ) = = 0 | | bp = = coin - > current )
return ( 0 ) ;
if ( ( rdata = bp - > ramchain . H . data ) = = 0 )
return ( 0 ) ;
( * Ptrp ) = refP = RAMCHAIN_PTR ( rdata , Poffset ) ;
if ( ( num = rdata - > numpkinds ) > 0 )
{
weights = calloc ( num , sizeof ( * weights ) ) ;
minconf = coin - > blocks . hwmchain . height - lastheight ;
for ( pkind = 1 ; pkind < num ; pkind + + )
{
total = 0 ;
memcpy ( rmd160 , refP [ pkind ] . rmd160 , sizeof ( rmd160 ) ) ;
array = cJSON_CreateArray ( ) ;
bitcoin_address ( coinaddr , coin - > chain - > pubtype , rmd160 , sizeof ( rmd160 ) ) ;
jaddistr ( array , coinaddr ) ;
//bitcoin_address(coinaddr,coin->chain->p2shtype,rmd160,sizeof(rmd160));
//jaddistr(array,coinaddr);
if ( ( rmdarray = iguana_rmdarray ( myinfo , coin , & numrmds , array , 0 ) ) ! = 0 )
{
numunspents = 0 ;
balance = iguana_unspents ( myinfo , coin , 0 , minconf , ( 1 < < 30 ) , rmdarray , numrmds , lastheight , 0 , & numunspents , 0 ) ;
free ( rmdarray ) ;
weights [ pkind ] + = balance ;
if ( weights [ pkind ] ! = balance )
printf ( " PKIND.%d %s %.8f += %.8f \n " , pkind , coinaddr , dstr ( weights [ pkind ] ) , dstr ( balance ) ) ;
}
free_json ( array ) ;
}
}
nonz = neg = 0 ;
supply = 0 ;
for ( pkind = 1 ; pkind < num ; pkind + + )
if ( weights [ pkind ] ! = 0 )
{
nonz + + ;
if ( weights [ pkind ] < 0 )
neg + + , weights [ pkind ] = 0 ;
else supply + = weights [ pkind ] ;
}
* numacctsp = num ;
* errsp = neg ;
* nonzp = nonz ;
* supplyp = supply ;
printf ( " ht.%d [%d] numaddrs.%d nonz.%d neg.%d supply %.8f \n " , lastheight , lastheight / coin - > chain - > bundlesize , num , nonz , neg , dstr ( supply ) ) ;
return ( weights ) ;
}
bits256 iguana_staker_hash2 ( bits256 refhash2 , uint8_t * refrmd160 , uint8_t * rmd160 , int64_t weight )
{
bits256 hash2 ;
vcalc_sha256cat ( hash2 . bytes , refhash2 . bytes , sizeof ( refhash2 ) , rmd160 , 20 ) ;
return ( mpz_div64 ( hash2 , weight ) ) ;
}
int _cmp_hashes ( const void * a , const void * b )
{
# define hasha (*(bits256 *)a)
# define hashb (*(bits256 *)b)
return ( bits256_cmp ( hasha , hashb ) ) ;
# undef hasha
# undef hashb
}
int32_t iguana_staker_sort ( struct iguana_info * coin , bits256 * hash2p , uint8_t * refrmd160 , struct iguana_pkhash * refP , int64_t * weights , int32_t numweights , bits256 * sortbuf )
{
int32_t i , j , n = 0 ; bits256 ind , refhash2 = * hash2p ;
memset ( sortbuf , 0 , sizeof ( * sortbuf ) * 2 * numweights ) ;
for ( i = 0 ; i < numweights ; i + + )
{
if ( weights [ i ] > 0 )
{
memset ( & ind , 0 , sizeof ( ind ) ) ;
for ( j = 0 ; j < 20 ; j + + )
ind . bytes [ j ] = refP [ i ] . rmd160 [ j ] ;
ind . ulongs [ 3 ] = weights [ i ] ;
ind . uints [ 5 ] = i ;
sortbuf [ n < < 1 ] = iguana_staker_hash2 ( refhash2 , refrmd160 , ind . bytes , weights [ i ] ) ;
sortbuf [ ( n < < 1 ) + 1 ] = ind ;
n + + ;
}
}
if ( n > 0 )
qsort ( sortbuf , n , sizeof ( * sortbuf ) * 2 , _cmp_hashes ) ;
vcalc_sha256cat ( hash2p - > bytes , refhash2 . bytes , sizeof ( refhash2 ) , sortbuf [ 1 ] . bytes , 20 ) ;
memcpy ( refrmd160 , sortbuf [ 1 ] . bytes , 20 ) ;
{
char str [ 65 ] , coinaddr [ 64 ] ;
bitcoin_address ( coinaddr , coin - > chain - > pubtype , refrmd160 , 20 ) ;
printf ( " winner.%s %.8f: %s \n " , coinaddr , dstr ( sortbuf [ 1 ] . ulongs [ 3 ] ) , bits256_str ( str , sortbuf [ 0 ] ) ) ;
}
return ( ( int32_t ) sortbuf [ 1 ] . uints [ 5 ] ) ;
}
int32_t iguana_unspent_check ( struct supernet_info * myinfo , struct iguana_info * coin , uint16_t hdrsi , uint32_t unspentind )
{
bits256 txid ; int32_t vout , spentheight ;
memset ( & txid , 0 , sizeof ( txid ) ) ;
if ( iguana_unspentind2txid ( myinfo , coin , & spentheight , & txid , & vout , hdrsi , unspentind ) = = 0 )
{
//char str[65]; printf("verify %s/v%d is not already used\n",bits256_str(str,txid),vout);
if ( basilisk_addspend ( myinfo , coin - > symbol , txid , vout , 0 ) ! = 0 )
{
char str [ 65 ] ; printf ( " iguana_unspent_check found unspentind (%u %d) %s \n " , hdrsi , unspentind , bits256_str ( str , txid ) ) ;
return ( 1 ) ;
} else return ( 0 ) ;
}
printf ( " iguana_unspent_check: couldnt find (%d %d) \n " , hdrsi , unspentind ) ;
return ( - 1 ) ;
}
int32_t iguana_addr_unspents ( struct supernet_info * myinfo , struct iguana_info * coin , int64_t * sump , int64_t * unspents , int32_t max , char * coinaddr , char * remoteaddr , int32_t lastheight )
{
int32_t n , k , numunspents , minconf = 0 ; int64_t total ; uint8_t rmd160 [ 20 ] , pubkey [ 65 ] , addrtype ;
total = 0 ;
n = numunspents = 0 ;
bitcoin_addr2rmd160 ( & addrtype , rmd160 , coinaddr ) ;
iguana_pkhasharray ( myinfo , coin , 0 , minconf , coin - > longestchain , & total , 0 , coin - > bundlescount , rmd160 , coinaddr , pubkey , lastheight , unspents , & n , max - 1000 , remoteaddr ) ;
/*if ( n > 0 )
{
candidates = unspents ;
for ( j = 0 ; j < n ; j + + )
{
hdrsi = ( int32_t ) ( candidates [ j < < 1 ] > > 32 ) ;
unspentind = ( int32_t ) candidates [ j < < 1 ] ;
if ( iguana_unspent_check ( myinfo , coin , hdrsi , unspentind ) = = 0 )
{
//printf("(%d u%d) %.8f not in mempool\n",hdrsi,unspentind,dstr(candidates[(j << 1) + 1]));
//for (k=0; k<numunspents; k++)
// if ( &unspents[k<<1] != &candidates[j<<1] && unspents[k << 1] == candidates[j << 1] )
// break;
//if ( k == numunspents )
{
//unspents[numunspents << 1] = candidates[j << 1];
//unspents[(numunspents << 1) + 1] = candidates[(j << 1) + 1];
printf ( " [%d u%d %.8f] " , hdrsi , unspentind , dstr ( unspents [ ( numunspents < < 1 ) + 1 ] ) ) ;
( * sump ) + = unspents [ ( numunspents < < 1 ) + 1 ] ;
unspents + = 2 ;
numunspents + + ;
} else printf ( " found duplicate unspent j.%d numunspents.%d \n " , j , numunspents ) ;
} else printf ( " found spent unspent j.%d numunspents.%d \n " , j , numunspents ) ;
}
} */
numunspents = n ;
for ( k = 0 ; k < n ; k + + )
( * sump ) + = unspents [ ( k < < 1 ) + 1 ] ;
return ( numunspents ) ;
}
int32_t iguana_unspentslists ( struct supernet_info * myinfo , struct iguana_info * coin , int64_t * totalp , int64_t * unspents , int32_t max , int64_t required , int32_t minconf , cJSON * addresses , char * remoteaddr )
{
int64_t sum = 0 ; int32_t k , i , j , r , numunspents , numaddrs ; uint8_t pubkey [ 65 ] ; char * coinaddr , str [ 65 ] ; struct iguana_waddress * waddr ; struct iguana_waccount * wacct ; struct basilisk_unspent * bu ;
* totalp = 0 ;
if ( ( numaddrs = cJSON_GetArraySize ( addresses ) ) = = 0 )
{
printf ( " null addresses.(%s) \n " , jprint ( addresses , 0 ) ) ;
return ( 0 ) ;
}
memset ( pubkey , 0 , sizeof ( pubkey ) ) ;
//remains = required * 1.1 + coin->txfee;
for ( i = numunspents = 0 ; i < numaddrs ; i + + )
{
if ( ( coinaddr = jstri ( addresses , i ) ) ! = 0 )
{
//printf("i.%d coinaddr.(%s) minconf.%d longest.%d diff.%d\n",i,coinaddr,minconf,coin->longestchain,coin->blocks.hwmchain.height - minconf);
if ( coin - > RELAYNODE ! = 0 | | coin - > VALIDATENODE ! = 0 )
{
numunspents = iguana_addr_unspents ( myinfo , coin , & sum , unspents , max , coinaddr , remoteaddr , coin - > blocks . hwmchain . height - minconf ) ;
}
else
{
if ( ( waddr = iguana_waddresssearch ( myinfo , & wacct , coinaddr ) ) ! = 0 & & waddr - > numunspents > 0 )
{
r = ( rand ( ) % waddr - > numunspents ) ;
for ( j = 0 ; j < waddr - > numunspents ; j + + )
{
i = ( ( j + r ) % waddr - > numunspents ) ;
bu = & waddr - > unspents [ i ] ;
if ( basilisk_addspend ( myinfo , coin - > symbol , bu - > txid , bu - > vout , 0 ) = = 0 )
{
for ( k = 0 ; k < numunspents ; k + + )
{
// filterout duplicates here
}
unspents [ 0 ] = ( ( uint64_t ) bu - > hdrsi < < 32 ) | bu - > unspentind ;
unspents [ 1 ] = bu - > value ;
sum + = bu - > value ;
printf ( " ADD unspent, mark spent \n " ) ;
basilisk_addspend ( myinfo , coin - > symbol , bu - > txid , bu - > vout , 1 ) ;
unspents + + ;
numunspents + + ;
} else printf ( " skip pending txid.%s/v%d \n " , bits256_str ( str , bu - > txid ) , bu - > vout ) ;
}
}
}
if ( numunspents > max | | sum > required )
break ;
//printf("n.%d max.%d total %.8f\n",n,max,dstr(total));
}
}
* totalp = sum ;
return ( numunspents ) ;
}
int32_t iguana_uvaltxid ( struct supernet_info * myinfo , bits256 * txidp , struct iguana_info * coin , int16_t hdrsi , uint32_t unspentind )
{
struct iguana_bundle * bp ; struct iguana_unspent * U , * u ; struct iguana_txid * T ; struct iguana_ramchain * ramchain ; struct iguana_ramchaindata * rdata ;
if ( ( bp = coin - > bundles [ hdrsi ] ) = = 0 )
return ( - 1 ) ;
ramchain = & bp - > ramchain ; //(bp == coin->current) ? &coin->RTramchain : &bp->ramchain;
if ( ( rdata = ramchain - > H . data ) ! = 0 )
{
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
T = RAMCHAIN_PTR ( rdata , Toffset ) ;
if ( unspentind > 0 & & unspentind < rdata - > numunspents )
{
u = & U [ unspentind ] ;
if ( u - > txidind > 0 & & u - > txidind < rdata - > numtxids )
{
* txidp = T [ u - > txidind ] . txid ;
return ( unspentind - T [ u - > txidind ] . firstvout ) ;
}
}
}
return ( - 1 ) ;
}
int64_t iguana_unspentavail ( struct supernet_info * myinfo , struct iguana_info * coin , uint64_t hdrsi_unspentind , int32_t minconf , int32_t maxconf )
{
struct iguana_ramchain * ramchain ; struct iguana_bundle * bp ; int64_t RTspend ; int32_t hdrsi , spentheight , spentflag ; struct iguana_unspent * U , * u ; uint32_t unspentind ; struct iguana_ramchaindata * rdata ;
if ( ( bp = coin - > bundles [ hdrsi_unspentind > > 32 ] ) = = 0 )
return ( - 1 ) ;
hdrsi = ( int16_t ) ( hdrsi_unspentind > > 32 ) ;
unspentind = ( uint32_t ) hdrsi_unspentind ;
ramchain = & bp - > ramchain ; //(bp == coin->current) ? &coin->RTramchain : &bp->ramchain;
if ( ( rdata = ramchain - > H . data ) = = 0 )
return ( 0 ) ;
if ( ( spentflag = iguana_spentflag ( myinfo , coin , & RTspend , & spentheight , ramchain , hdrsi , unspentind , 0 , minconf , maxconf , 0 ) ) > 0 )
{
printf ( " [%d].u%d was already spent ht.%d \n " , bp - > hdrsi , ( uint32_t ) unspentind , spentheight ) ;
return ( - 1 ) ;
}
else if ( spentflag = = 0 )
{
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
if ( unspentind > 0 & & unspentind < rdata - > numunspents )
{
u = & U [ unspentind ] ;
return ( u - > value ) ;
}
else
{
printf ( " illegal unspentind.%u vs %u [%d] \n " , unspentind , rdata - > numunspents , bp - > hdrsi ) ;
return ( - 2 ) ;
}
}
else return ( 0 ) ;
}
# define UTXOADDR_ITEMSIZE 32
# define iguana_utxotable_numinds(ind) (((ind) == 0xffff) ? coin->utxoaddrlastcount : (coin->utxoaddroffsets[(ind) + 1] - coin->utxoaddroffsets[ind]))
int32_t iguana_rwutxoaddr ( int32_t rwflag , uint16_t ind , uint8_t * serialized , struct iguana_utxoaddr * utxoaddr )
{
uint32_t pkind = 0 ; int32_t len = 0 ;
len + = iguana_rwnum ( rwflag , & serialized [ 0 ] , sizeof ( utxoaddr - > hdrsi ) , & utxoaddr - > hdrsi ) ;
if ( rwflag = = 0 )
{
utxoaddr - > rmd160 [ 0 ] = ( ind & 0xff ) ;
utxoaddr - > rmd160 [ 1 ] = ( ( ind > > 8 ) & 0xff ) ;
memcpy ( & utxoaddr - > rmd160 [ 2 ] , & serialized [ 2 ] , 18 ) ;
} else memcpy ( & serialized [ 2 ] , & utxoaddr - > rmd160 [ 2 ] , 18 ) ;
len + = 18 ;
if ( rwflag ! = 0 )
pkind = utxoaddr - > pkind ;
len + = iguana_rwnum ( rwflag , & serialized [ 20 ] , sizeof ( pkind ) , & pkind ) ;
if ( rwflag = = 0 )
utxoaddr - > pkind = pkind ;
len + = iguana_rwnum ( rwflag , & serialized [ 24 ] , sizeof ( utxoaddr - > histbalance ) , & utxoaddr - > histbalance ) ;
return ( len ) ;
}
int64_t iguana_utxoaddrtablefind ( struct iguana_info * coin , int16_t search_hdrsi , uint32_t search_pkind , uint8_t rmd160 [ 20 ] )
{
struct iguana_utxoaddr UA ; int32_t ind , num , i ; uint8_t * ptr ;
memset ( & UA , 0 , sizeof ( UA ) ) ;
ind = rmd160 [ 0 ] + ( ( int32_t ) rmd160 [ 1 ] < < 8 ) ;
if ( ( num = iguana_utxotable_numinds ( ind ) ) > 0 )
{
for ( i = 0 ; i < num ; i + + )
{
ptr = & coin - > utxoaddrtable [ ( coin - > utxoaddroffsets [ ind ] + i ) * UTXOADDR_ITEMSIZE ] ;
iguana_rwutxoaddr ( 0 , ind , ptr , & UA ) ;
if ( ( UA . pkind = = search_pkind & & UA . hdrsi = = search_hdrsi ) | | memcmp ( UA . rmd160 , rmd160 , 20 ) = = 0 )
return ( UA . histbalance ) ;
}
//printf("ind.%04x no [%d] p%u after num.%d\n",ind,search_hdrsi,search_pkind,num);
}
return ( 0 ) ;
}
struct iguana_utxoaddr * iguana_utxoaddrfind ( int32_t createflag , struct iguana_info * coin , int16_t hdrsi , uint32_t pkind , uint8_t rmd160 [ 20 ] , struct iguana_utxoaddr * * prevp )
{
struct iguana_utxoaddr * utxoaddr ; char coinaddr [ 64 ] ;
HASH_FIND ( hh , coin - > utxoaddrs , rmd160 , sizeof ( utxoaddr - > rmd160 ) , utxoaddr ) ;
if ( utxoaddr = = 0 & & createflag ! = 0 )
{
utxoaddr = calloc ( 1 , sizeof ( * utxoaddr ) ) ;
+ + coin - > utxoaddrind ;
utxoaddr - > hdrsi = hdrsi ;
utxoaddr - > pkind = pkind ;
if ( coin - > utxoaddrtable ! = 0 & & coin - > utxoaddroffsets ! = 0 )
{
utxoaddr - > searchedhist = 1 ;
utxoaddr - > histbalance = iguana_utxoaddrtablefind ( coin , hdrsi , pkind , rmd160 ) ;
}
memcpy ( utxoaddr - > rmd160 , rmd160 , sizeof ( utxoaddr - > rmd160 ) ) ;
HASH_ADD_KEYPTR ( hh , coin - > utxoaddrs , utxoaddr - > rmd160 , sizeof ( utxoaddr - > rmd160 ) , utxoaddr ) ;
if ( prevp ! = 0 )
{
utxoaddr - > hh . prev = * prevp ;
if ( * prevp ! = 0 )
( * prevp ) - > hh . next = utxoaddr ;
* prevp = utxoaddr ;
}
HASH_FIND ( hh , coin - > utxoaddrs , rmd160 , sizeof ( utxoaddr - > rmd160 ) , utxoaddr ) ;
if ( utxoaddr = = 0 )
{
int32_t i ; for ( i = 0 ; i < 20 ; i + + )
printf ( " %02x " , utxoaddr - > rmd160 [ i ] ) ;
bitcoin_address ( coinaddr , coin - > chain - > pubtype , utxoaddr - > rmd160 , sizeof ( utxoaddr - > rmd160 ) ) ;
printf ( " %d of %d: %s %.8f \n " , coin - > utxoaddrind , coin - > utxodatasize , coinaddr , dstr ( utxoaddr - > histbalance ) ) ;
printf ( " failed to find just added %d of %d \n " , coin - > utxoaddrind , coin - > utxodatasize ) ;
}
}
return ( utxoaddr ) ;
}
int64_t iguana_bundle_unspents ( struct iguana_info * coin , struct iguana_bundle * bp , struct iguana_utxoaddr * * prevp )
{
struct iguana_utxoaddr * utxoaddr ; uint32_t unspentind , pkind ; struct iguana_ramchaindata * rdata = 0 ; struct iguana_pkhash * P ; struct iguana_unspent * U ; struct iguana_utxo * U2 = 0 ; int64_t value , balance = 0 ;
if ( bp = = 0 | | ( rdata = bp - > ramchain . H . data ) = = 0 | | ( U2 = bp - > ramchain . Uextras ) = = 0 )
{
printf ( " missing ptr bp.%p rdata.%p U2.%p \n " , bp , rdata , U2 ) ;
return ( 0 ) ;
}
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
P = RAMCHAIN_PTR ( rdata , Poffset ) ;
for ( unspentind = 1 ; unspentind < rdata - > numunspents ; unspentind + + )
{
value = U [ unspentind ] . value ;
//printf("[%d] u%d: (p%u %.8f) from.%d lock.%d prev.%u spent.%d\n",bp->hdrsi,unspentind,U[unspentind].pkind,dstr(value),U2[unspentind].fromheight,U2[unspentind].lockedflag,U2[unspentind].prevunspentind,U2[unspentind].spentflag);
if ( U2 [ unspentind ] . fromheight = = 0 & & U2 [ unspentind ] . lockedflag = = 0 & & U2 [ unspentind ] . prevunspentind = = 0 & & U2 [ unspentind ] . spentflag = = 0 & & value ! = 0 )
{
if ( value < = 0 )
printf ( " [%d] u%u negative value %.8f?? \n " , bp - > hdrsi , unspentind , dstr ( value ) ) ;
else
{
balance + = value ;
if ( ( pkind = U [ unspentind ] . pkind ) < rdata - > numpkinds & & pkind > 0 )
{
if ( ( utxoaddr = iguana_utxoaddrfind ( 1 , coin , bp - > hdrsi , pkind , P [ pkind ] . rmd160 , prevp ) ) ! = 0 )
{
//printf("%.8f ",dstr(value));
utxoaddr - > histbalance + = value ;
} else printf ( " cant find pkind.%u for unspentind.%u hdrsi.%d \n " , pkind , unspentind , bp - > hdrsi ) ;
} else printf ( " illegal pkind.%u for unspentind.%u hdrsi.%d \n " , pkind , unspentind , bp - > hdrsi ) ;
}
} // else printf("[%d] u%u spent %.8f\n",bp->hdrsi,unspentind,dstr(value));
}
printf ( " [%d %.8f] " , bp - > hdrsi , dstr ( balance ) ) ;
return ( balance ) ;
}
static int _utxoaddr_cmp ( const void * a , const void * b )
{
# define item_a ((uint8_t *)a)
# define item_b ((uint8_t *)b)
uint16_t hdrsi_a , hdrsi_b ; uint32_t pkind_a , pkind_b ;
iguana_rwnum ( 0 , & item_a [ 0 ] , sizeof ( hdrsi_a ) , & hdrsi_a ) ;
iguana_rwnum ( 0 , & item_a [ 20 ] , sizeof ( pkind_a ) , & pkind_a ) ;
iguana_rwnum ( 0 , & item_b [ 0 ] , sizeof ( hdrsi_b ) , & hdrsi_b ) ;
iguana_rwnum ( 0 , & item_b [ 20 ] , sizeof ( pkind_b ) , & pkind_b ) ;
if ( hdrsi_b > hdrsi_a )
return ( 1 ) ;
else if ( hdrsi_b < hdrsi_a )
return ( - 1 ) ;
else
{
if ( pkind_b > pkind_a )
return ( 1 ) ;
else if ( pkind_b < pkind_a )
return ( - 1 ) ;
else return ( 0 ) ;
}
# undef item_a
# undef item_b
}
int32_t iguana_utxoaddr_save ( struct iguana_info * coin , char * fname , int64_t balance , uint32_t * counts , uint32_t * offsets , uint8_t * table )
{
FILE * fp ; bits256 hash ; int32_t retval = - 1 ;
if ( ( fp = fopen ( fname , " wb " ) ) ! = 0 )
{
fwrite ( & balance , 1 , sizeof ( balance ) , fp ) ;
fwrite ( & counts [ 0xffff ] , 1 , sizeof ( counts [ 0xffff ] ) , fp ) ;
fwrite ( & coin - > utxoaddrind , 1 , sizeof ( coin - > utxoaddrind ) , fp ) ;
vcalc_sha256cat ( hash . bytes , ( void * ) offsets , ( int32_t ) ( 0x10000 * sizeof ( * offsets ) ) , table , ( int32_t ) ( ( coin - > utxoaddrind + 1 ) * UTXOADDR_ITEMSIZE ) ) ;
if ( fwrite ( hash . bytes , 1 , sizeof ( hash ) , fp ) = = sizeof ( hash ) )
{
if ( fwrite ( offsets , 1 , 0x10000 * sizeof ( * offsets ) , fp ) = = 0x10000 * sizeof ( * offsets ) )
{
if ( fwrite ( table , 1 , ( coin - > utxoaddrind + 1 ) * UTXOADDR_ITEMSIZE , fp ) ! = ( coin - > utxoaddrind + 1 ) * UTXOADDR_ITEMSIZE )
printf ( " error writing %s table \n " , fname ) ;
else retval = 0 ;
} else printf ( " error writing %s offsets \n " , fname ) ;
} else printf ( " error writing %s hash \n " , fname ) ;
fclose ( fp ) ;
} else printf ( " error creating %s \n " , fname ) ;
return ( retval ) ;
}
int32_t iguana_utxoaddr_map ( struct iguana_info * coin , char * fname )
{
uint32_t ind , total = 0 , offset , size = 0 , last = 0 , lastcount = 0 , count , prevoffset = 0 ;
if ( ( coin - > utxoaddrfileptr = OS_mapfile ( fname , & coin - > utxoaddrfilesize , 0 ) ) ! = 0 & & coin - > utxoaddrfilesize > sizeof ( bits256 ) + 0x10000 * sizeof ( * coin - > utxoaddroffsets ) )
{
memcpy ( & coin - > histbalance , coin - > utxoaddrfileptr , sizeof ( coin - > histbalance ) ) ;
memcpy ( & last , ( void * ) ( ( long ) coin - > utxoaddrfileptr + sizeof ( int64_t ) ) , sizeof ( last ) ) ;
memcpy ( & coin - > utxoaddrind , ( void * ) ( ( long ) coin - > utxoaddrfileptr + sizeof ( int64_t ) + sizeof ( uint32_t ) ) , sizeof ( coin - > utxoaddrind ) ) ;
memcpy ( & coin - > utxoaddrhash . bytes , ( void * ) ( ( long ) coin - > utxoaddrfileptr + sizeof ( int64_t ) + 2 * sizeof ( uint32_t ) ) , sizeof ( coin - > utxoaddrhash ) ) ;
coin - > utxoaddroffsets = ( void * ) ( ( long ) coin - > utxoaddrfileptr + sizeof ( int64_t ) + 2 * sizeof ( uint32_t ) + sizeof ( bits256 ) ) ;
for ( ind = total = count = 0 ; ind < 0x10000 ; ind + + )
{
if ( ( offset = coin - > utxoaddroffsets [ ind ] ) ! = 0 )
{
count = offset - prevoffset ;
prevoffset = offset ;
total + = count ;
}
}
size = ( uint32_t ) ( ( total + 1 ) * UTXOADDR_ITEMSIZE ) ;
size + = sizeof ( int64_t ) + 2 * sizeof ( uint32_t ) + sizeof ( bits256 ) ;
size + = 0x10000 * sizeof ( * coin - > utxoaddroffsets ) ;
if ( size < = coin - > utxoaddrfilesize )
{
lastcount = ( uint32_t ) ( coin - > utxoaddrfilesize - size ) ;
if ( ( lastcount % UTXOADDR_ITEMSIZE ) = = 0 )
{
lastcount / = UTXOADDR_ITEMSIZE ;
coin - > utxoaddrlastcount = lastcount ;
coin - > utxoaddrtable = ( void * ) & coin - > utxoaddroffsets [ 0x10000 ] ;
//iguana_utxoaddr_purge(coin);
}
}
printf ( " %.8f LASTCOUNT %d vs total %d, last %d vs lastcount %d, size.%d %ld \n " , dstr ( coin - > histbalance ) , coin - > utxoaddrlastcount , total , last , lastcount , size , coin - > utxoaddrfilesize ) ;
return ( total + 1 + lastcount ) ;
}
return ( 0 ) ;
}
void iguana_utxoaddr_purge ( struct iguana_info * coin )
{
struct iguana_utxoaddr * utxoaddr , * tmp ;
if ( coin - > utxoaddrs ! = 0 )
{
printf ( " free %s utxoaddrs \n " , coin - > symbol ) ;
HASH_ITER ( hh , coin - > utxoaddrs , utxoaddr , tmp )
{
if ( utxoaddr ! = 0 )
{
HASH_DELETE ( hh , coin - > utxoaddrs , utxoaddr ) ;
free ( utxoaddr ) ;
}
}
coin - > utxoaddrs = 0 ;
}
if ( coin - > utxoaddrfileptr ! = 0 )
{
OS_releasemap ( coin - > utxoaddrfileptr , coin - > utxoaddrfilesize ) ;
coin - > utxoaddrfileptr = 0 ;
coin - > utxoaddrtable = 0 ;
coin - > utxoaddroffsets = 0 ;
}
memset ( coin - > utxoaddrhash . bytes , 0 , sizeof ( coin - > utxoaddrhash ) ) ;
coin - > histbalance = 0 ;
coin - > utxoaddrlastcount = 0 ;
coin - > utxoaddrind = 0 ;
coin - > utxoaddrfilesize = 0 ;
}
int32_t iguana_utxoaddr_check ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t lastheight , int64_t * unspents , int32_t max , struct iguana_utxoaddr * utxoaddr )
{
static int32_t good , bad ;
char coinaddr [ 64 ] ; int64_t sum , checkbalance ; int32_t iter , i , numunspents = 0 ;
sum = 0 ;
for ( iter = 0 ; iter < 2 ; iter + + )
{
bitcoin_address ( coinaddr , iter = = 0 ? coin - > chain - > pubtype : coin - > chain - > p2shtype , utxoaddr - > rmd160 , sizeof ( utxoaddr - > rmd160 ) ) ;
numunspents + = iguana_addr_unspents ( myinfo , coin , & sum , & unspents [ numunspents ] , max - numunspents , coinaddr , 0 , lastheight ) ;
if ( sum = = utxoaddr - > histbalance )
{
checkbalance = iguana_utxoaddrtablefind ( coin , 0 , 0 , utxoaddr - > rmd160 ) ;
if ( checkbalance ! = sum )
printf ( " %s checkbalance %.8f vs sum %.8f \n " , coinaddr , dstr ( checkbalance ) , dstr ( sum ) ) ;
break ;
}
}
if ( sum ! = utxoaddr - > histbalance | | checkbalance ! = sum )
{
bad + + ;
for ( i = 0 ; i < numunspents ; i + + )
printf ( " (%lld %lld %.8f) " , ( long long ) ( unspents [ i < < 1 ] > > 32 ) & 0xffffffff , ( long long ) unspents [ i < < 1 ] & 0xffffffff , dstr ( unspents [ ( i < < 1 ) + 1 ] ) ) ;
for ( i = 0 ; i < 20 ; i + + )
printf ( " %02x " , utxoaddr - > rmd160 [ i ] ) ;
bitcoin_address ( coinaddr , coin - > chain - > pubtype , utxoaddr - > rmd160 , sizeof ( utxoaddr - > rmd160 ) ) ;
printf ( " %s: sum %.8f != %.8f numunspents.%d diff %.8f \n " , coinaddr , dstr ( sum ) , dstr ( utxoaddr - > histbalance ) , numunspents , dstr ( utxoaddr - > histbalance ) - dstr ( sum ) ) ;
return ( - 1 ) ;
}
good + + ;
if ( ( ( good + bad ) % 1000 ) = = 0 )
printf ( " %s total %d utxoaddr validate good.%d bad.%d%s \n " , coin - > symbol , coin - > utxoaddrind , good , bad , strcmp ( coin - > symbol , " BTC " ) = = 0 ? " | (if this is taking too long, just exit and restart iguana) " : " " ) ;
return ( 0 ) ;
}
int32_t iguana_utxoaddr_validate ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t lastheight )
{
int64_t * unspents ; uint8_t * item ; struct iguana_bundle * bp ; struct iguana_utxoaddr UA ; int32_t i , num , max , ind , total , errs = 0 ;
if ( coin - > utxoaddrtable = = 0 )
{
printf ( " no utxoaddrtable to validate? \n " ) ;
return ( - 1 ) ;
}
for ( i = 0 ; i < coin - > bundlescount ; i + + )
if ( ( bp = coin - > bundles [ i ] ) ! = 0 & & bp ! = coin - > current )
{
iguana_volatilespurge ( coin , & bp - > ramchain ) ;
/*sprintf(fname,"%s/%s/accounts/debits.%d",GLOBAL_DBDIR,coin->symbol,bp->bundleheight);
OS_removefile ( fname , 0 ) ;
sprintf ( fname , " %s/%s/accounts/lastspends.%d " , GLOBAL_DBDIR , coin - > symbol , bp - > bundleheight ) ;
OS_removefile ( fname , 0 ) ; */
iguana_volatilesmap ( coin , & bp - > ramchain ) ;
}
total = 0 ;
max = 1024 * 1024 ;
if ( strcmp ( " BTC " , coin - > symbol ) = = 0 )
max * = 1024 ;
unspents = calloc ( 1 , max ) ;
max / = sizeof ( * unspents ) ;
memset ( & UA , 0 , sizeof ( UA ) ) ;
for ( ind = 0 ; ind < 0x10000 ; ind + + )
{
if ( ( num = iguana_utxotable_numinds ( ind ) ) > 0 )
{
for ( i = 0 ; i < num ; i + + )
{
item = & coin - > utxoaddrtable [ ( coin - > utxoaddroffsets [ ind ] + i ) * UTXOADDR_ITEMSIZE ] ;
iguana_rwutxoaddr ( 0 , ind , item , & UA ) ;
errs + = iguana_utxoaddr_check ( myinfo , coin , lastheight , unspents , max , & UA ) ;
total + + ;
//if ( (total % 1000) == 0 )
// fprintf(stderr,".");
}
}
}
free ( unspents ) ;
printf ( " validate errs.%d \n " , errs ) ;
return ( errs ) ;
}
int64_t iguana_utxoaddr_gen ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t maxheight )
{
char fname [ 1024 ] , fname2 [ 1024 ] , coinaddr [ 64 ] , str [ 65 ] , checkaddr [ 64 ] ; struct iguana_utxoaddr * utxoaddr , UA , * tmp , * last = 0 ; uint16_t hdrsi ; uint8_t * table , item [ UTXOADDR_ITEMSIZE ] ; uint32_t * counts , * offsets , offset , n ; int32_t errs = 0 , height = 0 , j , k , ind , tablesize = 0 ; struct iguana_bundle * bp ; struct iguana_block * block ; struct iguana_ramchaindata * rdata = 0 ; int64_t checkbalance = 0 , balance = 0 ;
for ( hdrsi = 0 ; hdrsi < coin - > bundlescount - 1 ; hdrsi + + )
{
if ( ( bp = coin - > bundles [ hdrsi ] ) ! = 0 & & bp - > bundleheight < maxheight )
height = bp - > bundleheight + bp - > n ;
}
sprintf ( fname2 , " %s/%s/utxoaddrs.%d " , GLOBAL_DBDIR , coin - > symbol , height ) , OS_portable_path ( fname2 ) ;
if ( iguana_utxoaddr_map ( coin , fname2 ) ! = 0 )
{
if ( strcmp ( " BTC " , coin - > symbol ) ! = 0 )
errs = iguana_utxoaddr_validate ( myinfo , coin , height ) ;
printf ( " nogen %s HIST BALANCE %s %.8f errs %d \n " , fname2 , bits256_str ( str , coin - > utxoaddrhash ) , dstr ( coin - > histbalance ) , errs ) ;
if ( errs = = 0 & & coin - > histbalance > 0 & & height > 0 )
{
coin - > firstRTheight = coin - > RTheight = height ;
iguana_RTreset ( coin ) ;
iguana_RTpurge ( coin , coin - > firstRTheight ) ;
if ( ( block = iguana_blockfind ( " utxogen " , coin , coin - > blocks . hwmchain . RO . hash2 ) ) ! = 0 )
iguana_RTnewblock ( coin , block ) ;
return ( coin - > histbalance ) ;
}
}
printf ( " utxoaddr_gen.%d \n " , maxheight ) ;
iguana_utxoaddr_purge ( coin ) ;
HASH_ITER ( hh , coin - > utxoaddrs , utxoaddr , tmp )
{
checkbalance + = utxoaddr - > histbalance ;
}
printf ( " balance after purge %.8f \n " , dstr ( checkbalance ) ) ;
for ( hdrsi = 0 ; hdrsi < coin - > bundlescount - 1 ; hdrsi + + )
if ( ( bp = coin - > bundles [ hdrsi ] ) ! = 0 & & bp - > bundleheight < maxheight & & ( rdata = bp - > ramchain . H . data ) ! = 0 )
{
tablesize + = rdata - > numpkinds ;
}
printf ( " allocate UTXOADDRS[%d] \n " , tablesize ) ;
coin - > utxodatasize = tablesize ;
coin - > utxoaddrind = 0 ;
for ( hdrsi = 0 ; hdrsi < coin - > bundlescount - 1 ; hdrsi + + )
{
if ( ( bp = coin - > bundles [ hdrsi ] ) ! = 0 & & bp - > bundleheight < maxheight )
{
balance + = iguana_bundle_unspents ( coin , bp , & last ) ;
fprintf ( stderr , " (%d %.8f) " , hdrsi , dstr ( balance ) ) ;
height = bp - > bundleheight + bp - > n ;
}
}
sprintf ( fname , " %s/%s/utxoaddrs " , GLOBAL_DBDIR , coin - > symbol ) , OS_portable_path ( fname ) ;
fprintf ( stderr , " %d bundles for iguana_utxoaddr_gen.[%d] max.%d ht.%d \n " , hdrsi , coin - > utxoaddrind , coin - > utxodatasize , maxheight ) ;
counts = calloc ( 0x10000 , sizeof ( * counts ) ) ;
checkbalance = 0 ;
HASH_ITER ( hh , coin - > utxoaddrs , utxoaddr , tmp )
{
if ( utxoaddr - > histbalance > 0 )
{
checkbalance + = utxoaddr - > histbalance ;
ind = utxoaddr - > rmd160 [ 0 ] + ( ( int32_t ) utxoaddr - > rmd160 [ 1 ] < < 8 ) ;
counts [ ind ] + + ;
} else printf ( " error neg or zero balance %.8f \n " , dstr ( utxoaddr - > histbalance ) ) ;
}
printf ( " checkbalance %.8f vs %.8f \n " , dstr ( checkbalance ) , dstr ( balance ) ) ;
if ( checkbalance = = balance )
{
table = calloc ( coin - > utxoaddrind + 1 , UTXOADDR_ITEMSIZE ) ;
offsets = calloc ( 0x10000 , sizeof ( * offsets ) ) ;
offset = 0 ;
for ( ind = 0 ; ind < 0x10000 ; ind + + )
{
n = counts [ ind ] ;
offsets [ ind ] = offset ;
counts [ ind ] = 0 ;
offset + = n ;
}
HASH_ITER ( hh , coin - > utxoaddrs , utxoaddr , tmp )
{
if ( utxoaddr - > histbalance > 0 )
{
bitcoin_address ( coinaddr , coin - > chain - > pubtype , utxoaddr - > rmd160 , sizeof ( utxoaddr - > rmd160 ) ) ;
memset ( item , 0 , UTXOADDR_ITEMSIZE ) ;
ind = utxoaddr - > rmd160 [ 0 ] + ( ( int32_t ) utxoaddr - > rmd160 [ 1 ] < < 8 ) ;
iguana_rwutxoaddr ( 1 , ind , item , utxoaddr ) ;
memcpy ( & table [ ( offsets [ ind ] + counts [ ind ] ) * UTXOADDR_ITEMSIZE ] , item , UTXOADDR_ITEMSIZE ) ;
iguana_rwutxoaddr ( 0 , ind , & table [ ( offsets [ ind ] + counts [ ind ] ) * UTXOADDR_ITEMSIZE ] , & UA ) ;
iguana_rwutxoaddr ( 1 , ind , item , & UA ) ;
bitcoin_address ( checkaddr , coin - > chain - > pubtype , UA . rmd160 , sizeof ( UA . rmd160 ) ) ;
if ( strcmp ( checkaddr , coinaddr ) ! = 0 )
printf ( " rw coinaddr error %s != %s \n " , coinaddr , checkaddr ) ;
//else printf("ind.%04x %s %.8f %.8f %d\n",ind,coinaddr,dstr(UA.histbalance),dstr(utxoaddr->histbalance),counts[ind]);
if ( memcmp ( & table [ ( offsets [ ind ] + counts [ ind ] ) * UTXOADDR_ITEMSIZE ] , item , UTXOADDR_ITEMSIZE ) ! = 0 )
printf ( " rwutxoaddr cmp error \n " ) ;
counts [ ind ] + + ;
} else printf ( " error neg or zero balance %.8f \n " , dstr ( utxoaddr - > histbalance ) ) ;
}
offset = 1 ;
for ( ind = 0 ; ind < 0x10000 ; ind + + )
offset + = counts [ ind ] ;
if ( offset = = coin - > utxoaddrind + 1 )
{
for ( ind = 0 ; ind < 0x10000 ; ind + + )
{
if ( counts [ ind ] > 0 )
{
qsort ( & table [ offsets [ ind ] * UTXOADDR_ITEMSIZE ] , counts [ ind ] , UTXOADDR_ITEMSIZE , _utxoaddr_cmp ) ;
continue ;
for ( j = 0 ; j < counts [ ind ] ; j + + )
{
iguana_rwutxoaddr ( 0 , ind , & table [ ( offsets [ ind ] + j ) * UTXOADDR_ITEMSIZE ] , & UA ) ;
for ( k = 0 ; k < 20 ; k + + )
printf ( " %02x " , UA . rmd160 [ k ] ) ;
bitcoin_address ( coinaddr , coin - > chain - > pubtype , UA . rmd160 , sizeof ( UA . rmd160 ) ) ;
printf ( " [%4d] p%-5d %12.8f ind.%04x %d %s \n " , UA . hdrsi , UA . pkind , dstr ( UA . histbalance ) , ind , j , coinaddr ) ;
}
}
}
if ( iguana_utxoaddr_save ( coin , fname , balance , counts , offsets , table ) = = 0 )
{
if ( OS_copyfile ( fname , fname2 , 1 ) < 0 )
printf ( " error copying file %s to %s \n " , fname , fname2 ) ;
else
{
for ( hdrsi = 0 ; hdrsi < coin - > bundlescount - 1 ; hdrsi + + )
{
if ( ( bp = coin - > bundles [ hdrsi ] ) ! = 0 & & bp - > bundleheight < maxheight )
bp - > balancefinish = ( uint32_t ) time ( NULL ) ;
}
}
} else printf ( " error saving %s \n " , fname ) ;
} else printf ( " table has %d vs %d \n " , offset , coin - > utxoaddrind + 1 ) ;
free ( offsets ) ;
free ( table ) ;
iguana_utxoaddr_purge ( coin ) ;
if ( iguana_utxoaddr_map ( coin , fname ) ! = 0 )
{
printf ( " validating %s HIST BALANCE %s %.8f errs %d \n " , fname2 , bits256_str ( str , coin - > utxoaddrhash ) , dstr ( coin - > histbalance ) , errs ) ;
errs = iguana_utxoaddr_validate ( myinfo , coin , height ) ;
printf ( " gen %s HIST BALANCE %s %.8f errs %d \n " , fname2 , bits256_str ( str , coin - > utxoaddrhash ) , dstr ( coin - > histbalance ) , errs ) ;
if ( errs ! = 0 | | height = = 0 )
{
printf ( " delete bad utxoaddr files \n " ) ;
OS_removefile ( fname , 0 ) ;
OS_removefile ( fname2 , 0 ) ;
}
else
{
coin - > firstRTheight = coin - > RTheight = height ;
iguana_RTreset ( coin ) ;
iguana_RTpurge ( coin , coin - > firstRTheight ) ;
if ( ( block = iguana_blockfind ( " utxogen " , coin , coin - > blocks . hwmchain . RO . hash2 ) ) ! = 0 )
iguana_RTnewblock ( coin , block ) ;
return ( coin - > histbalance ) ;
}
}
}
free ( counts ) ;
sprintf ( fname , " %s/%s/balancecrc.%d " , GLOBAL_DBDIR , coin - > symbol , height / coin - > chain - > bundlesize - 1 ) ;
OS_removefile ( fname , 0 ) ;
sprintf ( fname , " %s/%s/balancecrc.%d " , GLOBAL_DBDIR , coin - > symbol , height / coin - > chain - > bundlesize - 2 ) ;
OS_removefile ( fname , 0 ) ;
printf ( " return neg one remove %s \n " , fname ) ;
return ( - 1 ) ;
}
void iguana_utxoaddrs_purge ( struct iguana_info * coin )
{
struct iguana_utxoaddr * utxoaddr , * tmp ;
coin - > RTdebits = coin - > RTdebits = 0 ;
HASH_ITER ( hh , coin - > utxoaddrs , utxoaddr , tmp )
{
if ( utxoaddr ! = 0 )
utxoaddr - > RTcredits = utxoaddr - > RTdebits = 0 ;
}
}