You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

861 lines
36 KiB

/******************************************************************************
* 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. *
* *
******************************************************************************/
#include "iguana777.h"
static uint16_t iguana_primes[] = { 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521 };
struct iguana_bloominds iguana_calcbloom(bits256 hash2)
{
int32_t i,j,k; struct iguana_bloominds bit;
k = (int32_t)(sizeof(bit)/sizeof(uint16_t)) - 1;
j = 15;
for (i=0; i<sizeof(bit)/sizeof(uint16_t); i++,j--,k--)
bit.inds[i] = (hash2.ushorts[j] % iguana_primes[k]);//, printf("%d ",bit.inds[i]);
//printf("bit.inds\n");
return(bit);
}
struct iguana_bloominds iguana_bloomset(struct iguana_info *coin,struct iguana_bloom16 *bloom,int32_t incr,struct iguana_bloominds bit)
{
int32_t i,alreadyset;
for (alreadyset=i=0; i<sizeof(bit)/sizeof(uint16_t); i++,bloom+=incr)
{
if ( GETBIT(bloom->hash2bits,bit.inds[i]) == 0 )
SETBIT(bloom->hash2bits,bit.inds[i]);
else alreadyset++;
}
if ( alreadyset == i )
printf("iguana_bloomset: collision\n");
return(bit);
}
int32_t iguana_bloomfind(struct iguana_info *coin,struct iguana_bloom16 *bloom,int32_t incr,struct iguana_bloominds bit)
{
int32_t i;
coin->bloomsearches++;
for (i=0; i<sizeof(bit)/sizeof(uint16_t); i++,bloom+=incr)
if ( GETBIT(bloom->hash2bits,bit.inds[i]) == 0 )
return(-1);
coin->bloomhits++;
return(0);
}
int32_t iguana_bundlescan(struct iguana_info *coin,struct iguana_bundle *bp,bits256 hash2)
{
int32_t bundlei;
for (bundlei=0; bundlei<bp->n; bundlei++)
{
if ( memcmp(hash2.bytes,bp->hashes[bundlei].bytes,sizeof(hash2)) == 0 )
{
//char str[65]; printf("hdrsi.%d scan.%s found %d of %d\n",bp->hdrsi,bits256_str(str,hash2),bundlei,bp->n);
return(bundlei);
}
}
return(-2);
}
struct iguana_bundle *iguana_bundlefind(struct iguana_info *coin,struct iguana_bundle **bpp,int32_t *bundleip,bits256 hash2)
{
int32_t i; struct iguana_bloominds bit; struct iguana_bundle *bp = *bpp;
bit = iguana_calcbloom(hash2);
if ( bp == 0 )
{
for (i=coin->bundlescount-1; i>=0; i--)
//for (i=0; i<coin->bundlescount; i++)
{
if ( (bp= coin->bundles[i]) != 0 )
{
if ( iguana_bloomfind(coin,&bp->bloom,0,bit) == 0 )
{
*bpp = bp;
if ( (*bundleip= iguana_bundlescan(coin,bp,hash2)) < 0 )
{
//printf("bloom miss\n");
coin->bloomfalse++;
} else return(bp);
} //else printf("no bloom\n");
}
}
*bundleip = -2;
*bpp = 0;
return(0);
}
else if ( iguana_bloomfind(coin,&bp->bloom,0,bit) == 0 )
{
if ( (*bundleip= iguana_bundlescan(coin,bp,hash2)) >= 0 )
{
*bpp = bp;
return(bp);
} else printf("scan miss\n");
}
*bpp = 0;
*bundleip = -2;
return(0);
}
bits256 *iguana_bundleihash2p(struct iguana_info *coin,int32_t *isinsidep,struct iguana_bundle *bp,int32_t bundlei)
{
*isinsidep = 0;
if ( bundlei >= 0 && bundlei < coin->chain->bundlesize )
{
*isinsidep = 1;
return(&bp->hashes[bundlei]);
}
else if ( bundlei == -1 )
return(&bp->prevbundlehash2);
else if ( bundlei == coin->chain->bundlesize)
return(&bp->nextbundlehash2);
else return(0);
}
int32_t iguana_hash2set(struct iguana_info *coin,char *debugstr,struct iguana_bundle *bp,int32_t bundlei,bits256 newhash2)
{
int32_t isinside,checki,retval = -1; bits256 *orighash2p = 0; struct iguana_bundle *checkbp; char str[65]; struct iguana_bloominds bit;
if ( bp == 0 )
return(-1);
if ( bp->n <= bundlei )
{
printf("hash2set.%s [%d] of %d <- %s\n",debugstr,bundlei,bp->n,bits256_str(str,newhash2));
bp->n = coin->chain->bundlesize;
}
if ( bits256_nonz(newhash2) == 0 || (orighash2p= iguana_bundleihash2p(coin,&isinside,bp,bundlei)) == 0 )
{
printf("iguana_hash2set warning: bundlei.%d newhash2.%s orighash2p.%p\n",bundlei,bits256_str(str,newhash2),orighash2p);
//*orighash2p = newhash2;
//getchar();
return(-1);
}
if ( bits256_nonz(*orighash2p) > 0 && memcmp(newhash2.bytes,orighash2p,sizeof(bits256)) != 0 )
{
char str2[65],str3[65];
bits256_str(str2,*orighash2p), bits256_str(str3,newhash2);
printf("WARNING iguana_hash2set REFUSE overwrite [%s] %s with %s [%d:%d]\n",debugstr,str2,str3,bp->hdrsi,bundlei);
//*orighash2p = newhash2;
// getchar();
return(-1);
}
if ( isinside != 0 )
{
bit = iguana_calcbloom(newhash2);
if ( iguana_bloomfind(coin,&bp->bloom,0,bit) < 0 )
{
//printf("bloomset (%s)\n",bits256_str(str,newhash2));
iguana_bloomset(coin,&bp->bloom,0,bit);
if ( 0 )
{
int32_t i;
if ( iguana_bloomfind(coin,&bp->bloom,0,bit) < 0 )
{
for (i=0; i<8; i++)
printf("%d ",bit.inds[i]);
printf("cant bloomfind just bloomset\n");
}
else
{
*orighash2p = newhash2;
checkbp = bp, checki = -2;
if ( iguana_bundlefind(coin,&checkbp,&checki,newhash2) == 0 || checki != bundlei )
{
printf("cant iguana_bundlefind just added.(%s) bundlei.%d %p vs checki.%d %p\n",bits256_str(str,newhash2),bundlei,bp,checki,checkbp);
}
else if ( (coin->bloomsearches % 100000) == 0 )
printf("BLOOM SUCCESS %.2f%% FP.%d/%d collisions.%d\n",100.*(double)coin->bloomhits/coin->bloomsearches,(int32_t)coin->bloomfalse,(int32_t)coin->bloomsearches,(int32_t)coin->collisions);
}
}
} //else printf("bloom found\n");
retval = 0;
} else retval = (bundlei >= 0 && bundlei < coin->chain->bundlesize) ? 0 : 1;
//printf("set [%d] <- %s\n",bundlei,bits256_str(str,newhash2));
*orighash2p = newhash2;
return(retval);
}
int32_t iguana_bundlehash2add(struct iguana_info *coin,struct iguana_block **blockp,struct iguana_bundle *bp,int32_t bundlei,bits256 hash2)
{
struct iguana_block *block =0; struct iguana_bundle *otherbp; //
int32_t otherbundlei,setval,bundlesize,err = 0;
if ( blockp != 0 )
*blockp = 0;
if ( bp == 0 || bits256_nonz(hash2) == 0 )
return(-1111);
if ( bits256_nonz(hash2) > 0 && (block= iguana_blockhashset(coin,-1,hash2,1)) != 0 )
{
/*if ( (block->hdrsi != bp->hdrsi || block->bundlei != bundlei) && (block->hdrsi != 0 || block->bundlei != 0) )
{
return(-2);
}*/
bundlesize = coin->chain->bundlesize;
if ( bp->n > bundlesize )
{
printf("bp->n.%d is too big\n",bp->n);
return(0);
}
if ( bundlei >= bp->n && bundlei < coin->chain->bundlesize )
bp->n = bundlesize;//(bundlei < bundlesize-1) ? bundlesize : (bundlei + 1);
if ( (setval= iguana_hash2set(coin,"blockadd",bp,bundlei,hash2)) == 0 )
{
if ( (block->hdrsi != bp->hdrsi || block->bundlei != bundlei) && (block->hdrsi != 0 || block->bundlei != 0) )
{
printf("blockadd warning: %d[%d] <- %d[%d]\n",block->hdrsi,block->bundlei,bp->hdrsi,bundlei);
err |= 2;
exit(-1);
}
else
{
//char str[65]; printf(">>>>>>>>>>>>>> bundlehash2.(%s) ht.(%d %d)\n",bits256_str(str,hash2),bp->bundleheight,bundlei);
block->hdrsi = bp->hdrsi;
block->bundlei = bundlei;
bp->hashes[bundlei] = block->RO.hash2;
bp->blocks[bundlei] = block;
otherbp = 0;
if ( (otherbp= iguana_bundlefind(coin,&otherbp,&otherbundlei,hash2)) != 0 || (bundlei % (bundlesize-1)) == 0)
{
if ( bundlei == 0 && (otherbundlei == -2 || otherbundlei == bundlesize-1) )
{
if ( otherbp != 0 && iguana_hash2set(coin,"blockadd0_prev",bp,-1,otherbp->hashes[0]) != 0 )
err |= 4;
if ( otherbp != 0 && iguana_hash2set(coin,"blockadd0_next",otherbp,bundlesize,bp->hashes[0]) != 0 )
err |= 8;
}
else if ( bundlei == bundlesize-1 && (otherbundlei == -2 || otherbundlei == 0) )
{
if ( otherbp != 0 && iguana_hash2set(coin,"blockaddL_prev",otherbp,-1,bp->hashes[0]) != 0 )
err |= 16;
if ( otherbp != 0 && iguana_hash2set(coin,"blockaddL_next",bp,bundlesize,otherbp->hashes[0]) != 0 )
err |= 32;
}
//else printf("blockadd warning: %d[%d] bloomfound %d[%d]\n",bp->hdrsi,bundlei,otherbp!=0?otherbp->hdrsi:-1,otherbundlei);
}
}
}
else if ( setval == 1 )
{
if ( bundlei == -1 && iguana_hash2set(coin,"blockadd_m1",bp,-1,hash2) != 0 )
err |= 4;
if ( bundlei == bundlesize && iguana_hash2set(coin,"blockaddL_m1",bp,bundlesize,hash2) != 0 )
err |= 4;
}
else if ( setval < 0 )
{
printf("neg setval error\n");
err |= 64;
}
if ( err == 0 && blockp != 0 )
*blockp = block;
} else err |= 128;
if ( err != 0 )
{
printf("bundlehash2add err.%d\n",err);
return(0);
//while ( 1 )
// sleep(1);
//exit(-1);
}
return(-err);
}
struct iguana_bundle *iguana_bundlecreate(struct iguana_info *coin,int32_t *bundleip,int32_t bundleheight,bits256 bundlehash2,bits256 allhash,int32_t issueflag)
{
char str[65],dirname[1024]; struct iguana_bundle *bp = 0;
if ( bits256_nonz(bundlehash2) > 0 )
{
bits256_str(str,bundlehash2);
if ( iguana_bundlefind(coin,&bp,bundleip,bundlehash2) != 0 )
{
if ( bp->bundleheight >= 0 && bp->bundleheight != (bundleheight - *bundleip) )
printf("bundlecreate warning: bp->bundleheight %d != %d (bundleheight %d - %d bundlei)\n",bp->bundleheight,(bundleheight - *bundleip),bundleheight,*bundleip);
else if ( bits256_nonz(bp->allhash) == 0 )
bp->allhash = allhash;
return(bp);
}
bp = mycalloc('b',1,sizeof(*bp));
bp->n = coin->chain->bundlesize;
bp->hdrsi = coin->bundlescount;
bp->bundleheight = bundleheight;
bp->allhash = allhash;
iguana_hash2set(coin,"create",bp,0,bundlehash2);
if ( iguana_bundlehash2add(coin,0,bp,0,bundlehash2) == 0 )
{
bp->coin = coin;
bp->avetime = coin->avetime * 2.;
coin->bundles[coin->bundlescount] = bp;
if ( coin->bundlescount > 0 )
coin->bundles[coin->bundlescount-1]->nextbp = bp;
*bundleip = 0;
bits256_str(str,bundlehash2);
sprintf(dirname,"%s/%s/%d",GLOBALTMPDIR,coin->symbol,bp->bundleheight), OS_ensure_directory(dirname);
//printf("ht.%d alloc.[%d] new hdrs.%s %s\n",bp->bundleheight,coin->bundlescount,str,bits256_str(str2,allhash));
iguana_bundlehash2add(coin,0,bp,0,bundlehash2);
if ( issueflag != 0 )
{
iguana_blockQ("bundlecreate",coin,bp,0,bundlehash2,1);
queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(str),1);
}
coin->bundlescount++;
}
else
{
printf("error adding bundlehash2 bundleheight.%d\n",bundleheight);
myfree(bp,sizeof(*bp));
bp = 0;
}
return(bp);
} else printf("cant create bundle with zerohash\n");
//else printf("iguana_hdrscreate cant find hdr with %s or %s\n",bits256_str(bundlehash2),bits256_str2(firstblockhash2));
return(0);
}
struct iguana_txid *iguana_bundletx(struct iguana_info *coin,struct iguana_bundle *bp,int32_t bundlei,struct iguana_txid *tx,int32_t txidind)
{
static bits256 zero;
int32_t hdrsi; int64_t Toffset; char fname[1024]; FILE *fp; struct iguana_ramchaindata rdata;
iguana_peerfname(coin,&hdrsi,"DB",fname,0,bp->hashes[0],zero,bp->n);
if ( (fp= fopen(fname,"rb")) != 0 )
{
fseek(fp,(long)&rdata.Toffset - (long)&rdata,SEEK_SET);
if ( fread(&Toffset,1,sizeof(Toffset),fp) == sizeof(Toffset) )
{
fseek(fp,Toffset + sizeof(struct iguana_txid) * txidind,SEEK_SET);
if ( fread(tx,1,sizeof(*tx),fp) == sizeof(*tx) )
{
fclose(fp);
return(tx);
} else printf("bundletx read error\n");
} else printf("bundletx Toffset read error\n");
fclose(fp);
} else printf("bundletx couldnt open.(%s)\n",fname);
return(0);
}
void iguana_bundlepurge(struct iguana_info *coin,struct iguana_bundle *bp)
{
static bits256 zero;
char fname[1024]; int32_t hdrsi,m,j; uint32_t ipbits;
if ( bp->emitfinish > coin->startutc && bp->purgetime == 0 && time(NULL) > bp->emitfinish+30 )
{
for (j=m=0; j<sizeof(coin->peers.active)/sizeof(*coin->peers.active); j++)
{
if ( (ipbits= (uint32_t)coin->peers.active[j].ipbits) != 0 )
{
if ( iguana_peerfname(coin,&hdrsi,GLOBALTMPDIR,fname,ipbits,bp->hashes[0],zero,1) >= 0 )
{
if ( OS_removefile(fname,0) > 0 )
coin->peers.numfiles--, m++;
}
else printf("error removing.(%s)\n",fname);
}
}
//printf("purged hdrsi.%d m.%d\n",bp->hdrsi,m);
bp->purgetime = (uint32_t)time(NULL);
}
}
int32_t iguana_bundleissue(struct iguana_info *coin,struct iguana_bundle *bp,int32_t max,int32_t timelimit)
{
int32_t i,j,k,len,starti,lag,doneval,nonz,total=0,maxval,numpeers,laggard,flag=0,finished,peercounts[IGUANA_MAXPEERS],donecounts[IGUANA_MAXPEERS],counter = 0;
struct iguana_peer *addr; uint32_t now; struct iguana_block *block;
bits256 hashes[50]; uint8_t serialized[sizeof(hashes) + 256];
if ( bp == 0 )
return(0);
now = (uint32_t)time(NULL);
memset(peercounts,0,sizeof(peercounts));
memset(donecounts,0,sizeof(donecounts));
if ( coin->current != 0 )
starti = coin->current->hdrsi;
else starti = 0;
lag = (bp->hdrsi - starti);
lag *= lag;
if ( (i= sqrt(bp->hdrsi)) < 2 )
i = 2;
if ( lag < i )
lag = i;
else if ( lag > 10*i )
lag = 10*i;
if ( (numpeers= coin->peers.numranked) > 8 )//&& bp->currentflag < bp->n )
{
if ( bp->currentflag == 0 )
bp->currenttime = now;
if ( bp->numhashes >= bp->n )
{
for (j=0; j<numpeers; j++)
{
if ( (addr= coin->peers.ranked[j]) != 0 && addr->dead == 0 && addr->usock >= 0 )
{
now = (uint32_t)time(NULL);
for (i=j,k=doneval=maxval=0; i<bp->n&&k<sizeof(hashes)/sizeof(*hashes); i+=numpeers)
{
if ( bits256_nonz(bp->hashes[i]) != 0 )
{
if ( (block= bp->blocks[i]) != 0 )
{
if ( block->peerid == 0 )
{
//printf("<%d>.%d ",i,j);
if ( block->fpipbits == 0 )
{
hashes[k++] = bp->hashes[i];
bp->issued[i] = now;
block->issued = now;
block->peerid = j + 1;
block->numrequests++;
}
else
{
block->peerid = 1;
block->numrequests++;
}
}
else if ( block->peerid > 0 )
{
total++;
if ( block->fpipbits != 0 )//&& block->fpos >= 0 )
{
donecounts[block->peerid - 1]++;
if ( donecounts[block->peerid - 1] > doneval )
doneval = donecounts[block->peerid - 1];
}
else
{
peercounts[block->peerid - 1]++;
if ( peercounts[block->peerid - 1] > maxval )
maxval = peercounts[block->peerid - 1];
}
}
}
}
}
if ( k > 0 )
{
if ( (len= iguana_getdata(coin,serialized,MSG_BLOCK,hashes,k)) > 0 )
{
iguana_send(coin,addr,serialized,len);
counter += k;
coin->numreqsent += k;
addr->pendblocks += k;
addr->pendtime = (uint32_t)time(NULL);
bp->currentflag += k;
}
//printf("a%d/%d ",j,k);
}
}
}
//printf("doneval.%d maxval.%d\n",doneval,maxval);
if ( bp == coin->current )
{
double threshold;
for (i=nonz=0; i<numpeers; i++)
if ( donecounts[i]+peercounts[i] != 0 )
nonz++;
if ( nonz != 0 && total != 0 )
{
threshold = ((double)total / nonz) - 1.;
for (i=laggard=finished=0; i<numpeers; i++)
{
if ( peercounts[i] > threshold )
laggard++;
if ( peercounts[i] == 0 && donecounts[i] > threshold )
finished++;
}
if ( finished > laggard*10 && numpeers > 2*laggard && laggard > 0 )
{
for (i=laggard=finished=0; i<numpeers; i++)
{
if ( peercounts[i] > threshold && (addr= coin->peers.ranked[i]) != 0 && now > bp->currenttime+lag )
{
if ( numpeers > 64 || addr->laggard++ > 3 )
addr->dead = (uint32_t)time(NULL);
for (j=0; j<bp->n; j++)
{
if ( (block= bp->blocks[j]) != 0 && block->peerid == i && block->fpipbits == 0 )
{
printf("%d ",j);
flag++;
counter++;
block->peerid = 0;
iguana_blockQ("kick",coin,bp,j,block->RO.hash2,1);
bp->issued[i] = block->issued = now;
}
}
printf("kill peer.%d %s reissued\n",i,addr->ipaddr);
}
}
}
for (i=0; i<numpeers; i++)
printf("%d ",peercounts[i]);
printf("peercounts: finished %d, laggards.%d threshold %f\n",finished,laggard,threshold);
}
}
for (i=0; i<bp->n; i++)
{
if ( (block= bp->blocks[i]) != 0 && block->fpipbits == 0 )
{
if ( now > block->issued+lag )
{
counter++;
if ( bp == coin->current )
{
if ( bp == coin->current && (addr= coin->peers.ranked[rand() % numpeers]) != 0 )
iguana_sendblockreqPT(coin,addr,bp,i,block->RO.hash2,0);
printf("[%d:%d] ",bp->hdrsi,i);
}
iguana_blockQ("kick",coin,bp,i,block->RO.hash2,0);
flag++;
} //else printf("%d ",now - block->issued);
}
}
if ( flag != 0 && bp == coin->current )
printf("currentflag.%d ht.%d s.%d finished.%d most.%d laggards.%d maxunfinished.%d\n",bp->currentflag,bp->bundleheight,bp->numsaved,finished,doneval,laggard,maxval);
}
}
if ( bp == coin->current )
return(counter);
for (i=0; i<bp->n; i++)
{
if ( (block= bp->blocks[i]) != 0 )
{
if ( block->fpipbits == 0 || block->RO.recvlen == 0 )
{
if ( block->issued == 0 || now > block->issued+lag )
{
block->numrequests++;
if ( bp == coin->current )
printf("[%d:%d] ",bp->hdrsi,i);
iguana_blockQ("kick",coin,bp,i,block->RO.hash2,0);
bp->issued[i] = block->issued = now;
counter++;
if ( --max <= 0 )
break;
}
//else if ( block->fpipbits != 0 && ((bp->hdrsi == 0 && i == 0) || bits256_nonz(block->RO.prev_block) != 0) )
// n++;
}
} //else printf("iguana_bundleiters[%d] unexpected null block[%d]\n",bp->bundleheight,i);
}
return(counter);
}
int32_t iguana_bundleready(struct iguana_info *coin,struct iguana_bundle *bp)
{
int32_t i,ready,valid; struct iguana_block *block;
for (i=ready=0; i<bp->n; i++)
{
if ( (block= bp->blocks[i]) != 0 )
{
//printf("(%x:%x) ",(uint32_t)block->RO.hash2.ulongs[3],(uint32_t)bp->hashes[i].ulongs[3]);
if ( block->fpipbits == 0 || (bp->bundleheight+i > 0 && bits256_nonz(block->RO.prev_block) == 0) || iguana_blockvalidate(coin,&valid,block,1) < 0 )
{
char str[65]; printf(">>>>>>> ipbits.%x null prevblock error at ht.%d patch.(%s) and reissue\n",block->fpipbits,bp->bundleheight+i,bits256_str(str,block->RO.prev_block));
iguana_blockQ("null retry",coin,bp,i,block->RO.hash2,1);
} else ready++;
} else printf("error getting block (%d:%d) %p vs %p\n",bp->hdrsi,i,block,iguana_blockfind(coin,bp->hashes[i]));
}
return(ready);
}
int32_t iguana_bundlehdr(struct iguana_info *coin,struct iguana_bundle *bp,int32_t starti)
{
int32_t counter=0;
//if ( bp->speculative != 0 )
// printf("hdr ITERATE bundle.%d vs %d: h.%d n.%d r.%d s.%d finished.%d speculative.%p\n",bp->bundleheight,coin->longestchain-coin->chain->bundlesize,bp->numhashes,bp->n,bp->numrecv,bp->numsaved,bp->emitfinish,bp->speculative);
if ( strcmp(coin->symbol,"BTC") != 0 && bp->speculative == 0 && bp->numhashes < bp->n )
{
char str[64];
queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(bits256_str(str,bp->hashes[0])),1);
}
return(counter);
}
int32_t iguana_bundlefinish(struct iguana_info *coin,struct iguana_bundle *bp)
{
struct iguana_bundle *prevbp;
if ( bp->hdrsi == 0 || ((prevbp= coin->bundles[bp->hdrsi-1]) != 0 && coin->current != 0 && coin->current->hdrsi >= prevbp->hdrsi && prevbp->emitfinish > coin->startutc && time(NULL) > prevbp->emitfinish+3) )
{
//printf("postfinish.%d startutxo.%u prevbp.%p current.%p\n",bp->hdrsi,bp->startutxo,coin->bundles[bp->hdrsi-1],coin->current);
if ( bp->startutxo == 0 )
{
bp->startutxo = (uint32_t)time(NULL);
if ( iguana_utxogen(coin,bp) >= 0 )
{
printf("GENERATED UTXO for ht.%d duration %d seconds\n",bp->bundleheight,(uint32_t)time(NULL)-bp->startutxo);
bp->utxofinish = (uint32_t)time(NULL);
}
else printf("UTXO gen.[%d] error\n",bp->hdrsi);
}
if ( bp->utxofinish != 0 && bp->balancefinish == 0 && (bp->hdrsi == 0 || (prevbp != 0 && prevbp->utxofinish != 0)) )
{
iguana_balancesQ(coin,bp);
return(-1);
}
}
return(0);
}
int32_t iguana_bundletweak(struct iguana_info *coin,struct iguana_bundle *bp)
{
struct iguana_bundle *lastbp;
if ( (lastbp= coin->lastpending) != 0 && lastbp->hdrsi < coin->bundlescount-1 )
coin->lastpending = coin->bundles[lastbp->hdrsi + 1];
if ( (rand() % 2) == 0 )
{
if ( coin->MAXBUNDLES > IGUANA_MINPENDBUNDLES )
coin->MAXBUNDLES--;
else if ( coin->MAXBUNDLES < IGUANA_MINPENDBUNDLES )
coin->MAXBUNDLES++;
}
return(coin->MAXBUNDLES);
}
int64_t iguana_bundlecalcs(struct iguana_info *coin,struct iguana_bundle *bp)
{
FILE *fp; int32_t bundlei,checki,hdrsi,numhashes,numsaved,numcached,numrecv,minrequests;
int64_t datasize; struct iguana_block *block; char fname[1024]; static bits256 zero;
if ( bp->emitfinish > coin->startutc )
{
bp->numhashes = bp->numsaved = bp->numcached = bp->numrecv = bp->n;
return(bp->datasize);
}
datasize = numhashes = numsaved = numcached = numrecv = minrequests = 0;
for (bundlei=0; bundlei<bp->n; bundlei++)
{
if ( bits256_nonz(bp->hashes[bundlei]) > 0 && (block= bp->blocks[bundlei]) != 0 )
{
if ( block == iguana_blockfind(coin,bp->hashes[bundlei]) )
{
if ( (checki= iguana_peerfname(coin,&hdrsi,GLOBALTMPDIR,fname,0,bp->hashes[bundlei],bundlei>0?bp->hashes[bundlei-1]:zero,1)) != bundlei || bundlei < 0 || bundlei >= coin->chain->bundlesize )
{
printf("iguana_bundlecalcs.(%s) illegal hdrsi.%d bundlei.%d checki.%d\n",fname,hdrsi,bundlei,checki);
continue;
}
if ( 0 && bp->checkedtmp < bp->n && (fp= fopen(fname,"rb")) != 0 )
{
fseek(fp,0,SEEK_END);
if ( block->RO.recvlen == 0 )
{
block->RO.recvlen = (uint32_t)ftell(fp);
block->fpipbits = 1;
block->fpos = 0;
//printf("[%d:%d] len.%d\n",hdrsi,bundlei,block->RO.recvlen);
}
fclose(fp);
}
bp->blocks[bundlei] = block;
block->hdrsi = bp->hdrsi, block->bundlei = bundlei;
if ( bp->minrequests == 0 || (block->numrequests > 0 && block->numrequests < bp->minrequests) )
bp->minrequests = block->numrequests;
if ( (bp->hdrsi == 0 && bundlei == 0) || bits256_nonz(block->RO.prev_block) > 0 )
{
if ( block->fpipbits != 0 ) //block->fpos >= 0 &&
numsaved++;
if ( block->RO.recvlen != 0 || block->fpipbits != 0 || block->fpos >= 0 || block->queued != 0 )
{
numrecv++;
datasize += block->RO.recvlen;
if ( block->queued != 0 )
numcached++;
}
}
/*else //if ( 0 )
{
printf("cleared block?\n");
//block->RO.recvlen = 0;
//block->fpipbits = 0;
//block->fpos = -1;
//block->issued = bp->issued[bundlei] = 0;
}*/
}
else if ( 0 )
{
bp->blocks[bundlei] = iguana_blockfind(coin,bp->hashes[bundlei]);
bp->hashes[bundlei] = bp->blocks[bundlei]->RO.hash2;
if ( (block= bp->blocks[bundlei]) != 0 )
block->fpipbits = block->queued = 0;
}
numhashes++;
bp->checkedtmp++;
}
}
bp->datasize = datasize;
bp->numhashes = numhashes;
bp-> numsaved = numsaved;
bp->numcached = numcached;
bp->numrecv = numrecv;
bp->minrequests = minrequests;
bp->estsize = ((int64_t)bp->datasize * bp->n) / (bp->numrecv+1);
return(bp->estsize);
}
int32_t iguana_bundleiters(struct iguana_info *coin,struct iguana_bundle *bp,int32_t timelimit)
{
int32_t range,starti,lasti,retval=0,max,counter = 0; struct iguana_bundle *currentbp,*lastbp;
if ( (range= coin->peers.numranked) > coin->MAXBUNDLES )
range = coin->MAXBUNDLES;
currentbp = coin->current;
lastbp = coin->lastpending;
starti = currentbp == 0 ? 0 : currentbp->hdrsi;
lasti = lastbp == 0 ? coin->bundlescount-1 : lastbp->hdrsi;
coin->numbundlesQ--;
iguana_bundlecalcs(coin,bp);
if ( bp->numhashes < bp->n && bp->bundleheight < coin->longestchain-coin->chain->bundlesize )
iguana_bundlehdr(coin,bp,starti);
else if ( bp->emitfinish > coin->startutc && (retval= iguana_bundlefinish(coin,bp)) < 0 )
return(0);
else if ( bp->emitfinish == 0 && bp->numsaved >= bp->n )
{
if ( iguana_bundleready(coin,bp) == bp->n )
{
printf(">>>>>>>>>>>>>>>>>>>>>>> EMIT bundle.%d | 1st.%d h.%d s.[%d] maxbundles.%d NET.(h%d b%d)\n",bp->bundleheight,coin->current!=0?coin->current->hdrsi:-1,coin->current!=0?coin->current->numhashes:-1,coin->current!=0?coin->current->numsaved:-1,coin->MAXBUNDLES,HDRnet,netBLOCKS);
bp->emitfinish = 1;
iguana_bundletweak(coin,bp);
sleep(1); // just in case data isnt totally sync'ed to HDD
iguana_emitQ(coin,bp);
}
retval = 1;
}
else if ( bp->hdrsi > starti && bp->hdrsi <= starti+range )
{
max = bp->n;//sqrt(bp->n) - (bp->n/coin->MAXBUNDLES)*(bp->hdrsi - starti);
/*if ( max > 500 )
max = 500;
else if ( max < 10 )
max = 10;*/
counter = iguana_bundleissue(coin,bp,max,timelimit);
if ( counter > 0 )
printf("ITERATE.%d max.%d bundle.%d h.%d n.%d r.%d s.%d F.%d T.%d counter.%d\n",bp->rank,max,bp->bundleheight/coin->chain->bundlesize,bp->numhashes,bp->n,bp->numrecv,bp->numsaved,bp->emitfinish,timelimit,counter);
}
bp->nexttime = (uint32_t)time(NULL) + 1;
iguana_bundleQ(coin,bp,1000);
return(retval);
}
static int _decreasing_double(const void *a,const void *b)
{
#define double_a (*(double *)a)
#define double_b (*(double *)b)
if ( double_b > double_a )
return(1);
else if ( double_b < double_a )
return(-1);
return(0);
#undef double_a
#undef double_b
}
static int32_t revsortds(double *buf,uint32_t num,int32_t size)
{
qsort(buf,num,size,_decreasing_double);
return(0);
}
void iguana_bundlestats(struct iguana_info *coin,char *str)
{
static uint32_t lastdisp;
int32_t i,n,m,numv,count,pending,dispflag,numrecv,done,numhashes,numcached,numsaved,numemit;
int64_t spaceused=0,estsize = 0; struct iguana_bundle *bp,*lastpending = 0,*firstgap = 0; double *sortbuf; struct iguana_peer *addr;
dispflag = (rand() % 1000) == 0;
numrecv = numhashes = numcached = numsaved = numemit = done = 0;
count = coin->bundlescount;
sortbuf = calloc(count,sizeof(*sortbuf)*2);
for (i=n=m=numv=pending=0; i<count; i++)
{
if ( (bp= coin->bundles[i]) != 0 )
{
bp->rank = 0;
estsize += bp->estsize;//iguana_bundlecalcs(coin,bp,done);
//bp->metric = bp->numhashes;
bp->metric = coin->bundlescount - bp->hdrsi;
if ( done > coin->bundlescount*IGUANA_HEADPERCENTAGE && bp->hdrsi > coin->bundlescount*IGUANA_TAILPERCENTAGE )
bp->metric *= 1000;
numhashes += bp->numhashes;
numcached += bp->numcached;
numrecv += bp->numrecv;
numsaved += bp->numsaved;
if ( bp->validated != 0 )
numv++;
if ( bp->emitfinish > coin->startutc )
{
done++;
numemit++;
iguana_bundlepurge(coin,bp);
}
else
{
if ( ++pending == coin->MAXBUNDLES )
{
lastpending = bp;
//printf("SET MAXBUNDLES.%d pend.%d\n",bp->hdrsi,pending);
}
if ( firstgap == 0 )
firstgap = bp;
if ( bp->emitfinish == 0 )
{
spaceused += bp->estsize;
sortbuf[m*2] = bp->metric;
sortbuf[m*2 + 1] = i;
m++;
}
}
}
}
if ( m > 0 )
{
revsortds(sortbuf,m,sizeof(*sortbuf)*2);
for (i=0; i<m; i++)
{
if ( (bp= coin->bundles[(int32_t)sortbuf[i*2 + 1]]) != 0 )
{
bp->rank = i + 1;
if ( coin->peers.numranked > 0 && i < coin->peers.numranked && (addr= coin->peers.ranked[i]) != 0 )
addr->bp = bp;
}
}
}
free(sortbuf);
coin->numremain = n;
coin->blocksrecv = numrecv;
char str2[65]; uint64_t tmp; int32_t diff,p = 0; struct tai difft,t = tai_now();
for (i=0; i<IGUANA_MAXPEERS; i++)
if ( coin->peers.active[i].usock >= 0 )
p++;
diff = (int32_t)time(NULL) - coin->startutc;
difft.x = (t.x - coin->starttime.x), difft.millis = (t.millis - coin->starttime.millis);
tmp = (difft.millis * 1000000);
tmp %= 1000000000;
difft.millis = ((double)tmp / 1000000.);
if ( (coin->current= firstgap) == 0 )
coin->current = coin->bundles[0];
if ( lastpending != 0 )
coin->lastpending = lastpending;
else coin->lastpending = coin->bundles[coin->bundlescount - 1];
coin->numsaved = numsaved;
coin->spaceused = spaceused;
coin->numverified = numv;
char str4[65];
sprintf(str,"v.%d/%d (%d 1st.%d) to %d N[%d] Q.%d h.%d r.%d c.%s s.%d d.%d E.%d:%d M.%d L.%d est.%d %s %d:%02d:%02d %03.3f peers.%d/%d Q.(%d %d)",numv,coin->pendbalances,firstgap!=0?firstgap->numsaved:0,firstgap!=0?firstgap->hdrsi:0,coin->lastpending!=0?coin->lastpending->hdrsi:0,count,coin->numbundlesQ,numhashes,coin->blocksrecv,mbstr(str4,spaceused),numsaved,done,numemit,coin->numreqsent,coin->blocks.hwmchain.height,coin->longestchain,coin->MAXBUNDLES,mbstr(str2,estsize),(int32_t)difft.x/3600,(int32_t)(difft.x/60)%60,(int32_t)difft.x%60,difft.millis,p,coin->MAXPEERS,queue_size(&coin->priorityQ),queue_size(&coin->blocksQ));
//sprintf(str+strlen(str),"%s.%-2d %s time %.2f files.%d Q.%d %d\n",coin->symbol,flag,str,(double)(time(NULL)-coin->starttime)/60.,coin->peers.numfiles,queue_size(&coin->priorityQ),queue_size(&coin->blocksQ));
if ( time(NULL) > lastdisp+10 )
{
printf("%s\n",str);
if ( (rand() % 100) == 0 )
myallocated(0,0);
lastdisp = (uint32_t)time(NULL);
if ( firstgap != 0 && firstgap->queued == 0 )
iguana_bundleQ(coin,firstgap,1000);
}
strcpy(coin->statusstr,str);
coin->estsize = estsize;
}