/****************************************************************************** * Copyright © 2014-2015 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" // peer context, ie massively multithreaded -> bundlesQ struct iguana_bundlereq *iguana_bundlereq(struct iguana_info *coin,struct iguana_peer *addr,int32_t type,int32_t datalen) { struct iguana_bundlereq *req; int32_t allocsize; allocsize = (uint32_t)sizeof(*req) + datalen; req = mycalloc(type,1,allocsize); req->allocsize = allocsize; req->datalen = datalen; req->addr = addr; req->coin = coin; req->type = type; return(req); } void iguana_gotblockM(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_txblock *origtxdata,struct iguana_msgtx *txarray,uint8_t *data,int32_t recvlen) { struct iguana_bundlereq *req; struct iguana_txblock *txdata = 0; int32_t i; char fname[1024]; if ( 0 ) { for (i=0; ispace[0]; i++) if ( txdata->space[i] != 0 ) break; if ( i != txdata->space[0] ) { for (i=0; ispace[0]; i++) printf("%02x ",txdata->space[i]); printf("extra\n"); } } req = iguana_bundlereq(coin,addr,'B',0); txdata = origtxdata; if ( addr != 0 ) { if ( addr->pendblocks > 0 ) addr->pendblocks--; addr->lastblockrecv = (uint32_t)time(NULL); addr->recvblocks += 1.; addr->recvtotal += recvlen; origtxdata->block.ipbits = addr->ipbits; iguana_ramchain_data(coin,addr,origtxdata,txarray,origtxdata->block.txn_count,data,recvlen); { txdata->block.ipbits = addr->ipbits; if ( 0 ) { struct iguana_txblock *checktxdata; struct iguana_memspace checkmem; int32_t checkbundlei; memset(&checkmem,0,sizeof(checkmem)); iguana_meminit(&checkmem,"checkmem",0,txdata->datalen + 4096,0); if ( (checktxdata= iguana_peertxdata(coin,&checkbundlei,fname,&checkmem,addr->ipbits,txdata->block.hash2)) != 0 ) { printf("check datalen.%d bundlei.%d T.%d U.%d S.%d P.%d X.%d\n",checktxdata->datalen,checkbundlei,checktxdata->numtxids,checktxdata->numunspents,checktxdata->numspends,checktxdata->numpkinds,checktxdata->numexternaltxids); } iguana_mempurge(&checkmem); } } req->datalen = txdata->datalen; } //printf("datalen.%d\n",req->datalen); if ( req->datalen == 0 ) req->datalen = recvlen; req->block = txdata->block; req->ipbits = txdata->block.ipbits; req->block.txn_count = req->numtx = txdata->block.txn_count; coin->recvcount++; coin->recvtime = (uint32_t)time(NULL); req->addr = addr; queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0); } void iguana_gottxidsM(struct iguana_info *coin,struct iguana_peer *addr,bits256 *txids,int32_t n) { struct iguana_bundlereq *req; printf("got %d txids from %s\n",n,addr->ipaddr); req = iguana_bundlereq(coin,addr,'T',0); req->hashes = txids, req->n = n; queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0); } void iguana_gotunconfirmedM(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_msgtx *tx,uint8_t *data,int32_t datalen) { struct iguana_bundlereq *req; char str[65]; bits256_str(str,tx->txid); printf("%s unconfirmed.%s\n",addr->ipaddr,str); req = iguana_bundlereq(coin,addr,'U',datalen); req->datalen = datalen; memcpy(req->serialized,data,datalen); //iguana_freetx(tx,1); queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0); } void iguana_gotheadersM(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_block *blocks,int32_t n) { struct iguana_bundlereq *req; if ( addr != 0 ) { addr->recvhdrs++; if ( addr->pendhdrs > 0 ) addr->pendhdrs--; //printf("%s blocks[%d] ht.%d gotheaders pend.%d %.0f\n",addr->ipaddr,n,blocks[0].height,addr->pendhdrs,milliseconds()); } req = iguana_bundlereq(coin,addr,'H',0); req->blocks = blocks, req->n = n; queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0); } void iguana_gotblockhashesM(struct iguana_info *coin,struct iguana_peer *addr,bits256 *blockhashes,int32_t n) { struct iguana_bundlereq *req; if ( addr != 0 ) { addr->recvhdrs++; if ( addr->pendhdrs > 0 ) addr->pendhdrs--; } req = iguana_bundlereq(coin,addr,'S',0); req->hashes = blockhashes, req->n = n; //printf("bundlesQ blockhashes.%p[%d]\n",blockhashes,n); queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0); } void iguana_blocklink(struct iguana_info *coin,struct iguana_bundle *bp,int32_t bundlei,struct iguana_block *prev,struct iguana_block *block) { if ( block == 0 || prev == 0 ) return; //printf("%p prev-> %p [%d:%d] %p block %p\n",prev,prev->hh.next,bp!=0?bp->bundleheight:-1,bundlei,block->hh.prev,block); if ( (prev->hh.next == 0 || prev->hh.next == block) && block->hh.prev == 0 ) block->hh.prev = prev; else if ( prev->hh.next == 0 && block->hh.prev == prev ) prev->hh.next = block; else if ( prev->hh.next == block && block->hh.prev == prev ) { /*if ( bundlei < coin->chain->bundlesize ) { if ( bp != 0 && iguana_bundlehash2add(coin,0,bp,bundlei,block->hash2) < 0 ) { if ( prev->mainchain == 0 ) block->hh.prev = prev->hh.next = 0; printf("clear hashes?\n"); //memset(bp->hashes[i].bytes,0,sizeof(bp->hashes[i])); } } else if ( bp != 0 && bp->bundleheight + coin->chain->bundlesize >= coin->bundlescount*coin->chain->bundlesize ) { char str[65]; printf("AUTOCREATE.%d new bundle.%s\n",bp->bundleheight + coin->chain->bundlesize,bits256_str(str,block->hash2)); iguana_bundlecreate(coin,&bundlei,bp->bundleheight + coin->chain->bundlesize,block->hash2); //for (j=2; jn; j++) // iguana_blockQ(coin,bp,j,bp->hashes[j],0); }*/ } else if ( prev->mainchain == 0 ) block->hh.prev = prev->hh.next = 0; } void iguana_recvissue(struct iguana_info *coin,struct iguana_block *origblock) { int32_t height,bundlei,i; struct iguana_block *prev,*block; bits256 prevhash2; struct iguana_bundle *bp; block = iguana_blockhashset(coin,-1,origblock->prev_block,1); if ( block != origblock ) iguana_blockcopy(coin,block,origblock); for (i=0; ichain->bundlesize; i++) { if ( block != 0 && bits256_nonz(block->prev_block) > 0 ) { prev = iguana_blockhashset(coin,-1,block->prev_block,1); bp = 0, bundlei = -2, iguana_bundlefind(coin,&bp,&bundlei,block->hash2); if ( prev != 0 && prev->ipbits == 0 && bp != 0 && bp->bundleheight >= 0 ) { prevhash2 = iguana_blockhash(coin,bp->bundleheight + bundlei - 1); if ( bits256_nonz(prevhash2) == 0 ) { height = bp->bundleheight + bundlei - 1; //char str[65]; printf("[%d] RECVISSUE.%s %d\n",i,bits256_str(str,block->prev_block),height); iguana_hash2set(coin,"recvadd",coin->bundles[height/coin->chain->bundlesize],height%coin->chain->bundlesize,block->prev_block); iguana_blockQ(coin,coin->bundles[height/coin->chain->bundlesize],height%coin->chain->bundlesize,block->prev_block,1); break; } } block = prev; } else break; } } // main context, ie single threaded struct iguana_bundlereq *iguana_recvblockhashes(struct iguana_info *coin,struct iguana_bundlereq *req,bits256 *blockhashes,int32_t num) { int32_t i,bundlei; struct iguana_bundle *bp; struct iguana_block *block,*prev = 0; bp = 0, bundlei = -2, iguana_bundlefind(coin,&bp,&bundlei,blockhashes[1]); if ( (rand() % 100) == 0 ) { char str[65]; printf("got %d hashes %d:%d %s\n",num,bp==0?-1:bp->bundleheight,bundlei,bits256_str(str,blockhashes[1])); } if ( bp == 0 || bundlei != 1 || num <= 2 ) { if ( num > 2 ) iguana_blockQ(coin,0,-1,blockhashes[1],1); return(req); } bp->hdrtime = (uint32_t)time(NULL); //if ( num > coin->chain->bundlesize+1 ) // num = coin->chain->bundlesize+1; for (i=0; i 0 ) { if ( (block= iguana_blockhashset(coin,-1,blockhashes[i],1)) != 0 && prev != 0 && block->ipbits == 0 ) { prev->hh.next = block; if ( prev->mainchain != 0 ) { //char str[65]; printf("idle issue %s %d\n",bits256_str(str,block->hash2),prev->height+1); iguana_blockQ(coin,0,-1,block->hash2,0); } } if ( block != 0 && block->ipbits == 0 && i < coin->chain->bundlesize ) iguana_hash2set(coin,"recvhash",bp,i,blockhashes[i]); if ( (i % coin->chain->bundlesize) == 0 || i == 1 ) iguana_blockQ(coin,0,-1,blockhashes[i],1); else //if ( bp->hdrsi < 100 ) iguana_blockQ(coin,0,-1,blockhashes[i],0); } prev = block; } return(req); } struct iguana_bundle *iguana_bundleset(struct iguana_info *coin,struct iguana_block **blockp,int32_t *bundleip,struct iguana_block *origblock) { struct iguana_block *block,*prev = 0; struct iguana_bundle *bp = 0; int32_t bundlei = -2; if ( origblock == 0 ) return(0); block = iguana_blockhashset(coin,-1,origblock->hash2,1); *blockp = block; if ( block != 0 ) { if ( bits256_nonz(origblock->prev_block) > 0 ) { prev = iguana_blockhashset(coin,-1,origblock->prev_block,1); //iguana_blocklink(coin,0,-1,prev,block); if ( prev != 0 ) { prev->hh.next = block, block->hh.prev = prev; //printf("link block\n"); } } if ( (bp= iguana_bundlefind(coin,&bp,&bundlei,origblock->hash2)) != 0 ) { if ( bundlei < coin->chain->bundlesize ) { iguana_blocklink(coin,bp,bundlei,prev,block); block->bundlei = bundlei; block->hdrsi = bp->hdrsi; block->havebundle = 1; iguana_hash2set(coin,"blockadd",bp,block->bundlei,block->hash2); } } else if ( (bp= iguana_bundlefind(coin,&bp,&bundlei,origblock->prev_block)) != 0 ) { if ( bundlei < coin->chain->bundlesize-1 ) { block->bundlei = ++bundlei; block->hdrsi = bp->hdrsi; block->havebundle = 1; iguana_hash2set(coin,"blockadd",bp,block->bundlei,block->hash2); } else if ( bundlei == coin->chain->bundlesize-1 ) { char str[65]; printf("CREATE.%d new bundle.%s\n",bp->bundleheight + coin->chain->bundlesize,bits256_str(str,origblock->hash2)); iguana_blockQ(coin,0,-1,origblock->hash2,1); iguana_bundlecreate(coin,&bundlei,bp->bundleheight + coin->chain->bundlesize,origblock->hash2); } } else { //char str[65]; printf("can find.(%s)\n",bits256_str(str,origblock->hash2)); return(0); } if ( block->havebundle != 0 && block->hdrsi < coin->bundlescount ) { bundlei = block->bundlei; bp = coin->bundles[block->hdrsi]; } //char str[65]; printf("iguana_recvblock (%s) %d %d[%d] %p\n",bits256_str(str,block->hash2),block->havebundle,block->hdrsi,bundlei,bp); } *bundleip = bundlei; return(bp); } struct iguana_bundlereq *iguana_recvblockhdrs(struct iguana_info *coin,struct iguana_bundlereq *req,struct iguana_block *blocks,int32_t n,int32_t *newhwmp) { int32_t i,bundlei; struct iguana_block *block; struct iguana_bundle *bp; if ( blocks == 0 ) { printf("iguana_recvblockhdrs null blocks?\n"); return(req); } if ( blocks != 0 && n > 0 ) { for (i=0; iprev_block.bytes,coin->blocks.hwmchain.hash2.bytes,sizeof(bits256)) == 0 ) _iguana_chainlink(coin,block); if ( bundlei == 1 ) iguana_blockQ(coin,0,-1,blocks[i].hash2,1); else if ( bp != 0 && bp->hdrsi < IGUANA_MAXACTIVEBUNDLES ) iguana_blockQ(coin,0,-1,blocks[i].hash2,0); //fprintf(stderr,"i.%d of %d iguana_chainextend\n",i,n); //iguana_chainextend(coin,&blocks[i]); } } return(req); } struct iguana_bundlereq *iguana_recvblock(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_bundlereq *req,struct iguana_block *origblock,int32_t numtx,int32_t datalen,int32_t *newhwmp) { struct iguana_bundle *bp=0; char str[65]; int32_t tmp,bundlei = -2; bits256 hash2; struct iguana_block *block,*prev,*ptr; double duration; bp = iguana_bundleset(coin,&block,&bundlei,origblock); if ( block != origblock ) iguana_blockcopy(coin,block,origblock); if ( memcmp(block->prev_block.bytes,coin->blocks.hwmchain.hash2.bytes,sizeof(bits256)) == 0 ) { _iguana_chainlink(coin,block); iguana_bundleset(coin,&ptr,&tmp,block); //printf("HWMCHAIN %s height.%d\n",bits256_str(str,block->hash2),coin->blocks.hwmchain.height+1); } else if ( (prev= iguana_blockfind(coin,block->prev_block)) != 0 ) { if ( prev->mainchain != 0 && prev->height >= 0 ) { block->mainchain = 1; block->height = prev->height+1; iguana_bundleset(coin,&ptr,&tmp,block); hash2 = iguana_blockhash(coin,block->height+1); if ( bits256_nonz(hash2) == 0 && (ptr= block->hh.next) != 0 ) hash2 = ptr->hash2; if ( bits256_nonz(hash2) > 0 && (ptr= iguana_blockfind(coin,hash2)) != 0 && ptr->ipbits == 0 ) { //printf("AUTONEXT.%d\n",block->height+1); if ( prev->height == coin->blocks.hwmchain.height ) { coin->backstop = coin->blocks.hwmchain.height+1; coin->backstophash2 = hash2; coin->backstopmillis = milliseconds(); } iguana_blockQ(coin,0,-1,hash2,0); } } } if ( strcmp(coin->symbol,"BTC") != 0 ) iguana_recvissue(coin,block); if ( bp != 0 && bundlei >= 0 ) { if ( bp->bundleheight+bundlei > coin->longestchain ) coin->longestchain = bp->bundleheight+bundlei; if ( bp->bundleheight+bundlei == coin->blocks.hwmchain.height+1 && bp->requests[bundlei] > 99 ) printf("recv bundlei.%d hdrs.%d reqs.[%d]\n",bundlei,bp->hdrsi,bp->requests[bundlei]); if ( 0 && bundlei == 1 && bp->numhashes < bp->n ) { bits256_str(str,block->prev_block); queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(str),1); } if ( datalen > 0 ) { SETBIT(bp->recv,bundlei); if ( bp->issued[bundlei] > 0 ) { duration = 1000. * ((int32_t)time(NULL) - bp->issued[bundlei]); if ( duration < bp->avetime/10. ) duration = bp->avetime/10.; else if ( duration > bp->avetime*10. ) duration = bp->avetime * 10.; dxblend(&bp->avetime,duration,.9); if ( bp->avetime < 100 ) bp->avetime = 100; dxblend(&coin->avetime,bp->avetime,.9); if ( coin->avetime < 100 ) coin->avetime = 100; } if ( bundlei >= 0 && bundlei < bp->n ) { //bp->blocks[bundlei] = block; //bp->numrecv++; } } if ( strcmp(coin->symbol,"BTC") != 0 && bp->bundleheight+bundlei == coin->blocks.hwmchain.height+1 ) { _iguana_chainlink(coin,block); //if ( (rand() % 10) == 0 ) { hash2 = iguana_blockhash(coin,coin->blocks.hwmchain.height+2); if ( bits256_nonz(hash2) > 0 ) { printf("AUTOBLOCK.%d\n",coin->blocks.hwmchain.height+2); iguana_blockQ(coin,0,-1,hash2,0); } } } } if ( block != 0 ) { block->recvlen = datalen; if ( bp != 0 ) block->ipbits = req->ipbits; //printf("datalen.%d ipbits.%x\n",datalen,req->ipbits); } else printf("cant create block.%llx block.%p bp.%p bundlei.%d\n",(long long)origblock->hash2.txid,block,bp,bundlei); return(req); } struct iguana_bundlereq *iguana_recvtxids(struct iguana_info *coin,struct iguana_bundlereq *req,bits256 *txids,int32_t n) { return(req); } struct iguana_bundlereq *iguana_recvunconfirmed(struct iguana_info *coin,struct iguana_bundlereq *req,uint8_t *data,int32_t datalen) { return(req); } int32_t iguana_processbundlesQ(struct iguana_info *coin,int32_t *newhwmp) // single threaded { int32_t flag = 0; struct iguana_bundlereq *req; *newhwmp = 0; while ( flag < IGUANA_BUNDLELOOP && (req= queue_dequeue(&coin->bundlesQ,0)) != 0 ) { //printf("%s bundlesQ.%p type.%c n.%d\n",req->addr != 0 ? req->addr->ipaddr : "0",req,req->type,req->n); if ( req->type == 'B' ) // one block with all txdata req = iguana_recvblock(coin,req->addr,req,&req->block,req->numtx,req->datalen,newhwmp); else if ( req->type == 'H' ) // blockhdrs (doesnt have txn_count!) { if ( (req= iguana_recvblockhdrs(coin,req,req->blocks,req->n,newhwmp)) != 0 ) { if ( req->blocks != 0 ) myfree(req->blocks,sizeof(*req->blocks) * req->n), req->blocks = 0; } } else if ( req->type == 'S' ) // blockhashes { if ( (req= iguana_recvblockhashes(coin,req,req->hashes,req->n)) != 0 && req->hashes != 0 ) myfree(req->hashes,sizeof(*req->hashes) * req->n), req->hashes = 0; } else if ( req->type == 'U' ) // unconfirmed tx req = iguana_recvunconfirmed(coin,req,req->serialized,req->datalen); else if ( req->type == 'T' ) // txids from inv { if ( (req= iguana_recvtxids(coin,req,req->hashes,req->n)) != 0 ) myfree(req->hashes,(req->n+1) * sizeof(*req->hashes)), req->hashes = 0; } else printf("iguana_updatebundles unknown type.%c\n",req->type); flag++; //printf("done %s bundlesQ.%p type.%c n.%d\n",req->addr != 0 ? req->addr->ipaddr : "0",req,req->type,req->n); if ( req != 0 ) myfree(req,req->allocsize), req = 0; } return(flag); } /*int32_t iguana_needhdrs(struct iguana_info *coin) { if ( coin->longestchain == 0 || coin->blocks.hashblocks < coin->longestchain-coin->chain->bundlesize ) return(1); else return(0); }*/ int32_t iguana_reqhdrs(struct iguana_info *coin) { int32_t i,gap,n = 0; struct iguana_bundle *bp; char hashstr[65]; if ( queue_size(&coin->hdrsQ) == 0 ) //iguana_needhdrs(coin) > 0 && { if ( coin->zcount++ > 100 ) { for (i=0; ibundlescount; i++) { if ( (bp= coin->bundles[i]) != 0 ) { if ( i == coin->bundlescount-1 && coin->longestchain/coin->chain->bundlesize != i ) gap = 6; else gap = 60; if ( bp->emitfinish != 0 || bp->numhashes >= bp->n || time(NULL) < bp->hdrtime+gap ) continue; if ( bp->emitfinish == 0 && time(NULL) > bp->issuetime+gap ) { printf("LAG.%ld hdrsi.%d numhashes.%d:%d qsize.%d zcount.%d\n",time(NULL)-bp->hdrtime,i,bp->numhashes,bp->n,queue_size(&coin->hdrsQ),coin->zcount); if ( bp->issuetime == 0 ) coin->numpendings++; char str[65]; bits256_str(str,bp->hashes[0]); printf("(%s %d).%d ",str,bp->bundleheight,i); init_hexbytes_noT(hashstr,bp->hashes[0].bytes,sizeof(bits256)); queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(hashstr),1); n++; bp->issuetime = (uint32_t)time(NULL); } } } if ( n > 0 ) printf("REQ HDRS pending.%d\n",coin->numpendings); coin->zcount = 0; } } else coin->zcount = 0; return(n); } struct iguana_blockreq { struct queueitem DL; bits256 hash2,*blockhashes; struct iguana_bundle *bp; int32_t n,height,bundlei; }; int32_t iguana_blockQ(struct iguana_info *coin,struct iguana_bundle *bp,int32_t bundlei,bits256 hash2,int32_t priority) { queue_t *Q; char *str; struct iguana_blockreq *req; struct iguana_block *block; if ( bits256_nonz(hash2) == 0 ) { printf("cant queue zerohash bundlei.%d\n",bundlei); return(-1); } if ( priority != 0 || bp == 0 || (block= iguana_blockfind(coin,bp->hashes[bundlei])) == 0 || block->ipbits == 0 ) { if ( priority != 0 ) str = "priorityQ", Q = &coin->priorityQ; else str = "blocksQ", Q = &coin->blocksQ; if ( Q != 0 ) { req = mycalloc('r',1,sizeof(*req)); req->hash2 = hash2; req->bp = bp; req->bundlei = bundlei; if ( bp != 0 && bundlei >= 0 && bundlei < bp->n ) { bp->issued[bundlei] = milliseconds(); if ( bp->bundleheight >= 0 ) req->height = (bp->bundleheight + bundlei); } char str[65]; bits256_str(str,hash2); if ( 0 && (bundlei % 250) == 0 ) printf("%s %d %s recv.%d numranked.%d qsize.%d\n",str,req->height,str,coin->blocks.recvblocks,coin->peers.numranked,queue_size(Q)); queue_enqueue(str,Q,&req->DL,0); return(1); } else printf("null Q\n"); } //else printf("queueblock skip priority.%d bundlei.%d\n",bundlei,priority); return(0); } int32_t iguana_pollQsPT(struct iguana_info *coin,struct iguana_peer *addr) { uint8_t serialized[sizeof(struct iguana_msghdr) + sizeof(uint32_t)*32 + sizeof(bits256)]; char *hashstr=0,hexstr[65]; bits256 hash2; uint32_t now; struct iguana_blockreq *req=0; struct iguana_bundle *bp,*bestbp = 0; int32_t limit,refbundlei,bundlei,height=-1,datalen,flag = 0; now = (uint32_t)time(NULL); if ( addr->pendhdrs < IGUANA_MAXPENDHDRS ) //iguana_needhdrs(coin) != 0 && { //printf("%s check hdrsQ\n",addr->ipaddr); if ( (hashstr= queue_dequeue(&coin->hdrsQ,1)) != 0 ) { if ( (datalen= iguana_gethdrs(coin,serialized,coin->chain->gethdrsmsg,hashstr)) > 0 ) { decode_hex(hash2.bytes,sizeof(hash2),hashstr); bp = 0, bundlei = -2, iguana_bundlefind(coin,&bp,&bundlei,hash2); if ( bits256_nonz(hash2) > 0 ) { if ( bp == 0 || bp->emitfinish == 0 ) { if ( (rand() % 100) == 0 ) printf("%s request hdr.(%s) ht.%d\n",addr!=0?addr->ipaddr:"local",hashstr,bp!=0?bp->bundleheight:-1); iguana_send(coin,addr,serialized,datalen); addr->pendhdrs++; flag++; } } } else printf("datalen.%d from gethdrs\n",datalen); free_queueitem(hashstr); hashstr = 0; if ( flag != 0 ) return(flag); } } if ( (limit= addr->recvblocks) > coin->MAXPENDING ) limit = coin->MAXPENDING; if ( limit < 1 ) limit = 1; if ( coin->bundlescount > 0 && (req= queue_dequeue(&coin->priorityQ,0)) == 0 && addr->pendblocks < limit ) { int32_t i,flag,r,diff,j,k,n; double metric,bestmetric = -1.; for (i=n=0; ibundlescount; i++) if ( coin->bundles[i] != 0 && coin->bundles[i]->emitfinish == 0 ) n++; if ( n >= coin->bundlescount-(coin->bundlescount>>3) || (addr->ipbits % 10) < 2 ) refbundlei = (addr->ipbits % coin->bundlescount); else { if ( n*2 < coin->bundlescount ) { for (i=refbundlei=0; iusock == coin->peers.active[i].usock ) break; if ( coin->peers.active[i].usock >= 0 ) refbundlei++; } //printf("half done\n"); } else refbundlei = ((addr->addrind*100) % coin->bundlescount); } for (i=0; ibundlescount; i++) { if ( (diff= (i - refbundlei)) < 0 ) diff = -diff; if ( (bp= coin->bundles[i]) != 0 && bp->emitfinish == 0 ) { metric = (1 + diff * ((addr->addrind&1) == 0 ? 1 : diff) * (1. + bp->metric)) / (i + 1); //printf("%f ",bp->metric); if ( bestmetric < 0. || metric < bestmetric ) bestmetric = metric, bestbp = bp; } } if ( bestbp != 0 && bp->emitfinish == 0 ) { for (k=0; kbundlescount; k++) { i = (bestbp->hdrsi + k) % coin->bundlescount; if ( (bp= coin->bundles[i]) == 0 || bp->emitfinish > coin->starttime ) continue; //printf("%.15f ref.%d addrind.%d bestbp.%d\n",bestmetric,refbundlei,addr->addrind,bp->hdrsi); for (r=0; rchain->bundlesize && rn; r++) { j = (addr->addrind*3 + r) % bp->n; hash2 = bp->hashes[j]; if ( bits256_nonz(hash2) == 0 ) continue; flag = 0; if ( (bp->numrecv >= bp->n-5 || bp->requests[j] <= bp->minrequests) && bp->ipbits[j] == 0 && (bp->issued[j] == 0 || now > bp->issued[j]+bp->avetime/1000.) ) flag = 1; if ( flag != 0 ) { init_hexbytes_noT(hexstr,hash2.bytes,sizeof(hash2)); if ( (datalen= iguana_getdata(coin,serialized,MSG_BLOCK,hexstr)) > 0 ) { iguana_send(coin,addr,serialized,datalen); coin->numreqsent++; addr->pendblocks++; addr->pendtime = (uint32_t)time(NULL); if ( 1 && (rand() % 1000) == 0 ) { char str[65]; printf(" %s %s issue.%d %d lag.%d\n",addr->ipaddr,bits256_str(str,hash2),bp->hdrsi,j,now-bp->issued[j]); } bp->issued[j] = (uint32_t)time(NULL); if ( bp->requests[j] < 100 ) bp->requests[j]++; return(1); } else printf("MSG_BLOCK null datalen.%d\n",datalen); } //else printf("null hash\n"); } } } } if ( addr->rank != 1 && req == 0 ) req = queue_dequeue(&coin->blocksQ,0); if ( req != 0 ) { hash2 = req->hash2; height = req->height; if ( 0 && req->bp != 0 && req->bundlei >= 0 && req->bundlei < req->bp->n && req->bundlei < coin->chain->bundlesize && req->bp->recvlens[req->bundlei] != 0 ) { //printf("%p[%d] %d\n",req->bp,req->bp!=0?req->bp->bundleheight:-1,req->bundlei); myfree(req,sizeof(*req)); } else if ( req->bp == 0 || (req->bp != 0 && req->bundlei >= 0) )//&& GETBIT(req->bp->recv,req->bundlei) == 0) ) { init_hexbytes_noT(hexstr,hash2.bytes,sizeof(hash2)); if ( (datalen= iguana_getdata(coin,serialized,MSG_BLOCK,hexstr)) > 0 ) { if ( 0 && queue_size(&coin->priorityQ) > 0 ) printf("%s %s BLOCK.%d:%d bit.%d Q.(%d %d)\n",addr->ipaddr,hexstr,req->bp!=0?req->bp->hdrsi:-1,req->bundlei,req->bp!=0?GETBIT(req->bp->recv,req->bundlei):-1,queue_size(&coin->priorityQ),queue_size(&coin->blocksQ)); iguana_send(coin,addr,serialized,datalen); coin->numreqsent++; addr->pendblocks++; addr->pendtime = (uint32_t)time(NULL); if ( (bp= req->bp) != 0 && req->bundlei >= 0 && req->bundlei < bp->n ) { if ( bp->requests[req->bundlei] < 100 ) bp->requests[req->bundlei]++; bp->issued[req->bundlei] = (uint32_t)time(NULL); } flag++; myfree(req,sizeof(*req)); return(flag); } else printf("error constructing request %s.%d\n",hexstr,height); } } return(flag); } int32_t iguana_processrecv(struct iguana_info *coin) // single threaded { int32_t newhwm = 0,h,lflag,i,flag = 0; bits256 hash2; struct iguana_block *next,*block,*prev; //printf("process bundlesQ\n"); flag += iguana_processbundlesQ(coin,&newhwm); flag += iguana_reqhdrs(coin); lflag = 1; while ( 1 ) { h = coin->blocks.hwmchain.height; if ( (next= iguana_blockfind(coin,iguana_blockhash(coin,coin->blocks.hwmchain.height+1))) != 0 ) { double lag; _iguana_chainlink(coin,next); lag = milliseconds() - coin->backstopmillis; if ( (coin->blocks.hwmchain.height+1 < coin->longestchain && (lag > coin->avetime && coin->backstop != coin->blocks.hwmchain.height+1)) || lag > 10*coin->avetime ) { coin->backstop = coin->blocks.hwmchain.height+1; coin->backstophash2 = next->hash2; coin->backstopmillis = milliseconds(); iguana_blockQ(coin,0,coin->blocks.hwmchain.height+1,next->hash2,0); //char str[65]; printf("MAINCHAIN.%d %s avetime.%.3f lag %.3f\n",coin->blocks.hwmchain.height+1,bits256_str(str,next->hash2),coin->avetime,lag); } } iguana_chainextend(coin,iguana_blockfind(coin,coin->blocks.hwmchain.hash2)); if ( h == coin->blocks.hwmchain.height ) break; } if ( strcmp(coin->symbol,"BTC") != 0 ) for (i=coin->blocks.hwmchain.height+1; ilongestchain; i++) { if ( (block= iguana_blockfind(coin,iguana_blockhash(coin,i))) != 0 && block->ipbits == 0 ) { if ( (prev= iguana_blockfind(coin,block->prev_block)) != 0 && prev->mainchain != 0 ) { printf("adjacent %d\n",i); iguana_blockQ(coin,0,-1,block->hash2,1); } } } while ( 0)//lflag != 0 ) { lflag = 0; h = coin->blocks.hwmchain.height / coin->chain->bundlesize; if ( (next= iguana_blockfind(coin,iguana_blockhash(coin,coin->blocks.hwmchain.height+1))) != 0 ) /*{ if ( (block= iguana_blockfind(coin,coin->blocks.hwmchain.hash2)) != 0 ) next = block->hh.next;//, block->mainchain = 1; } if ( next != 0 )*/ { if ( _iguana_chainlink(coin,next) == 0 ) //printf("have next\n"); /*if ( 0 && memcmp(next->prev_block.bytes,coin->blocks.hwmchain.hash2.bytes,sizeof(bits256)) == 0 ) { if ( _iguana_chainlink(coin,next) != 0 ) lflag++; else printf("chainlink error for %d\n",coin->blocks.hwmchain.height+1);//, getchar(); } else if ( 0 )*/ { double threshold,lag = milliseconds() - coin->backstopmillis; threshold = (10 + coin->longestchain - coin->blocksrecv); if ( threshold < 1 ) threshold = 1.; threshold = 1000;//coin->avetime * sqrt(threshold) * .000777; if ( coin->blocks.hwmchain.height+1 < coin->longestchain && (coin->backstop != coin->blocks.hwmchain.height+1 || lag > threshold) ) { coin->backstop = coin->blocks.hwmchain.height+1; coin->backstophash2 = next->hash2; coin->backstopmillis = milliseconds(); iguana_blockQ(coin,0,coin->blocks.hwmchain.height+1,next->hash2,0); // clear recvlens //if ( (rand() % 100) == 0 ) { char str[65]; printf("MAINCHAIN.%d %s avetime %.3f lag %.3f\n",coin->blocks.hwmchain.height+1,bits256_str(str,next->hash2),coin->avetime,lag); } } else if ( 0 && bits256_nonz(next->prev_block) > 0 ) printf("next prev cmp error nonz.%d\n",bits256_nonz(next->prev_block)); } } else if ( 0 ) { for (i=2; ichain->bundlesize; i++) { hash2 = iguana_blockhash(coin,coin->blocks.hwmchain.height+i); if ( bits256_nonz(hash2) > 0 ) { if ( (block= iguana_blockfind(coin,hash2)) != 0 && bits256_nonz(block->prev_block) > 0 ) { printf("REVBACKSTOP.%d\n",coin->blocks.hwmchain.height+i-1); iguana_blockQ(coin,0,-1,block->prev_block,1); break; } } } } if ( h != coin->blocks.hwmchain.height / coin->chain->bundlesize ) iguana_savehdrs(coin); } return(flag); }