/****************************************************************************** * 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. * * * ******************************************************************************/ #define uthash_malloc(size) ((ramchain->hashmem == 0) ? mycalloc('u',1,size) : iguana_memalloc(ramchain->hashmem,size,1)) #define uthash_free(ptr,size) ((ramchain->hashmem == 0) ? myfree(ptr,size) : 0) //#define HASH_BLOOM 16 //#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 #include "iguana777.h" //void iguana_stub(void *ptr,int size) { }//printf("uthash_free ptr.%p %d\n",ptr,size); } #define iguana_hashfind(ramchain,selector,key) iguana_hashsetPT(ramchain,selector,key,0) struct iguana_kvitem *iguana_hashsetPT(struct iguana_ramchain *ramchain,int32_t selector,void *key,uint32_t itemind) { struct iguana_kvitem *tmp,*ptr = 0; int32_t allocsize,keylen; char str[65]; allocsize = (int32_t)(sizeof(*ptr)); if ( selector == 'T' ) { keylen = sizeof(bits256); HASH_FIND(hh,ramchain->txids,key,keylen,ptr); } else if ( selector == 'P' ) { keylen = 20; HASH_FIND(hh,ramchain->pkhashes,key,keylen,ptr); } else return(0); init_hexbytes_noT(str,key,keylen); if ( ptr == 0 && itemind != 0 ) { if ( ramchain->hashmem != 0 ) ptr = iguana_memalloc(ramchain->hashmem,allocsize,1); else ptr = mycalloc('e',1,allocsize); if ( ptr == 0 ) printf("fatal alloc error in hashset\n"), exit(-1); if ( 0 && ramchain->expanded && selector == 'T' ) printf("hashmem.%p selector.%c added.(%s) itemind.%x ptr.%p\n",ramchain->hashmem,selector,str,itemind,ptr); ptr->hh.itemind = itemind; if ( selector == 'T' ) HASH_ADD_KEYPTR(hh,ramchain->txids,key,keylen,ptr); else HASH_ADD_KEYPTR(hh,ramchain->pkhashes,key,keylen,ptr); if ( selector == 'T' ) HASH_FIND(hh,ramchain->txids,key,keylen,tmp); else HASH_FIND(hh,ramchain->pkhashes,key,keylen,tmp); //if ( strcmp(str,"0000000000000000000000000000000000000000000000000000000000000000") == 0 ) // printf("added null txid?\n"), getchar(); if ( 0 && ramchain->expanded && selector == 'T' ) printf("selector.%c added.(%s) itemind.%x ptr.%p tmp.%p\n",selector,str,itemind,ptr,tmp); if ( itemind == 0 ) printf("negative itemind\n"), exit(-1); if ( tmp != ptr ) { printf("(%s) hashmem.%p selector.%c %s search error %p != %p itemind.%x\n",str,ramchain->hashmem,selector,str,ptr,tmp,itemind), exit(-1); } } return(ptr); } uint32_t iguana_sparseadd(uint8_t *bits,uint32_t ind,int32_t width,uint32_t tablesize,uint8_t *key,int32_t keylen,uint32_t setind,void *refdata,int32_t refsize) { static long sparsesearches,sparseiters,sparsehits,sparsemax; static uint8_t masks[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; int32_t i,j,x,n,modval; int64_t bitoffset; uint8_t *ptr; if ( tablesize == 0 ) { printf("iguana_sparseadd tablesize zero illegal\n"); return(0); } if ( 0 && setind == 0 ) { char str[65]; for (i=n=0; i> 3]; modval = (bitoffset & 7); for (x=j=0; j= 8 ) ptr++, modval = 0; x <<= 1; x |= (*ptr & masks[modval]) >> modval; } if ( x != 0 ) printf("%s ",bits256_str(str,*(bits256 *)(refdata + x*refsize))), n++; } printf("tableentries.%d\n",n); } bitoffset = (ind * width); sparsesearches++; if ( 0 && setind == 0 ) printf("tablesize.%d width.%d bitoffset.%d\n",tablesize,width,(int32_t)bitoffset); for (i=0; i= tablesize ) { ind = 0; bitoffset = 0; } ptr = &bits[bitoffset >> 3]; modval = (bitoffset & 7); if ( 0 && setind == 0 ) printf("tablesize.%d width.%d bitoffset.%d modval.%d i.%d\n",tablesize,width,(int32_t)bitoffset,modval,i); for (x=j=0; j= 8 ) ptr++, modval = 0; x <<= 1; x |= (*ptr & masks[modval]) >> modval; } if ( 0 && setind == 0 ) printf("x.%d\n",x); if ( x == 0 ) { if ( (x= setind) == 0 ) return(0); ptr = &bits[(bitoffset+width-1) >> 3]; modval = ((bitoffset+width-1) & 7); for (j=0; j>=1,modval--) { if ( modval < 0 ) ptr--, modval = 7; if ( (x & 1) != 0 ) *ptr |= masks[modval]; } if ( 0 ) { for (x=j=0; j sparsemax ) sparsemax = i; return(setind); } else if ( memcmp((void *)(long)((long)refdata + x*refsize),key,keylen) == 0 ) { if ( setind == 0 ) sparsehits++; else if ( setind != x ) printf("sparseadd index collision setind.%d != x.%d\n",setind,x); return(x); } } return(0); } uint32_t iguana_sparseaddtx(uint8_t *bits,int32_t width,uint32_t tablesize,bits256 txid,struct iguana_txid *T,uint32_t txidind) { uint32_t ind; ind = (txid.ulongs[0] ^ txid.ulongs[1] ^ txid.ulongs[2] ^ txid.ulongs[3]) % tablesize; return(iguana_sparseadd(bits,ind,width,tablesize,txid.bytes,sizeof(txid),txidind,T,sizeof(*T))); } uint32_t iguana_sparseaddpk(uint8_t *bits,int32_t width,uint32_t tablesize,uint8_t rmd160[20],struct iguana_pkhash *P,uint32_t pkind) { uint32_t ind,key2; uint64_t key0,key1; memcpy(&key0,rmd160,sizeof(key0)); memcpy(&key1,&rmd160[sizeof(key0)],sizeof(key1)); memcpy(&key2,&rmd160[sizeof(key0) + sizeof(key1)],sizeof(key2)); ind = (key0 ^ key1 ^ key2) % tablesize; return(iguana_sparseadd(bits,ind,width,tablesize,rmd160,20,pkind,P,sizeof(*P))); } void iguana_blocksetcounters(struct iguana_info *coin,struct iguana_block *block,struct iguana_ramchain * ramchain) { block->RO.firsttxidind = ramchain->H.txidind; block->RO.firstvout = ramchain->H.unspentind; block->RO.firstvin = ramchain->H.spendind; block->RO.firstpkind = ramchain->pkind; block->RO.firstexternalind = ramchain->externalind; } struct iguana_txid *iguana_txidfind(struct iguana_info *coin,int32_t *heightp,struct iguana_txid *tx,bits256 txid) { uint8_t *TXbits; struct iguana_txid *T; uint32_t txidind,i,j; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; struct iguana_block *block; *heightp = -1; for (i=0; ibundlescount; i++) { if ( (bp= coin->bundles[i]) != 0 && bp->emitfinish > coin->startutc ) { ramchain = &bp->ramchain; if ( ramchain->H.data != 0 ) { TXbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->TXoffset); T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); //printf("search bp.%p TXbits.%p T.%p %d %d\n",bp,TXbits,T,(int32_t)ramchain->H.data->TXoffset,(int32_t)ramchain->H.data->Toffset); if ( (txidind= iguana_sparseaddtx(TXbits,ramchain->H.data->txsparsebits,ramchain->H.data->numtxsparse,txid,T,0)) > 0 ) { //printf("found txidind.%d\n",txidind); for (j=0; jn; j++) if ( (block= bp->blocks[j]) != 0 && txidind >= block->RO.firsttxidind && txidind < block->RO.firsttxidind+block->RO.txn_count ) break; *heightp = bp->bundleheight + j; //printf("found height.%d\n",*heightp); *tx = T[txidind]; return(tx); } } } } return(0); } struct iguana_pkhash *iguana_pkhashfind(struct iguana_info *coin,struct iguana_pkhash *p,uint8_t rmd160[20]) { uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind,i; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; for (i=0; ibundlescount; i++) { if ( (bp= coin->bundles[i]) != 0 ) { ramchain = &bp->ramchain; PKbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->PKoffset); P = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Poffset); if ( (pkind= iguana_sparseaddpk(PKbits,ramchain->H.data->pksparsebits,ramchain->H.data->numpksparse,rmd160,P,0)) > 0 ) { *p = P[pkind]; return(p); } } } return(0); } int32_t iguana_peerfname(struct iguana_info *coin,int32_t *hdrsip,char *dirname,char *fname,uint32_t ipbits,bits256 hash2,bits256 prevhash2,int32_t numblocks) { struct iguana_bundle *bp = 0; int32_t bundlei = -2; char str[65]; *hdrsip = -1; //if ( ipbits == 0 ) // printf("illegal ipbits.%d\n",ipbits), getchar(); if ( (bp= iguana_bundlefind(coin,&bp,&bundlei,hash2)) == 0 ) { if ( bits256_nonz(prevhash2) == 0 || (bp= iguana_bundlefind(coin,&bp,&bundlei,prevhash2)) == 0 || bundlei >= coin->chain->bundlesize-1 ) return(-2); else bundlei++; } hash2 = bp->hashes[0], *hdrsip = bp->hdrsi; if ( numblocks == 1 ) sprintf(fname,"%s/%s/%s.%u",dirname,coin->symbol,bits256_str(str,hash2),ipbits!=0?ipbits:*hdrsip); else sprintf(fname,"%s/%s/%s_%d.%u",dirname,coin->symbol,bits256_str(str,hash2),numblocks,ipbits!=0?ipbits:*hdrsip); OS_compatible_path(fname); return(bundlei); } int32_t iguana_peerfile_exists(struct iguana_info *coin,struct iguana_peer *addr,char *dirname,char *fname,bits256 hash2,bits256 prevhash2,int32_t numblocks) { FILE *fp; int32_t bundlei,hdrsi; if ( (bundlei= iguana_peerfname(coin,&hdrsi,dirname,fname,addr!=0?addr->ipbits:0,hash2,prevhash2,numblocks)) >= 0 ) { OS_compatible_path(fname); if ( (fp= fopen(fname,"rb")) == 0 ) bundlei = -1; else fclose(fp); } return(bundlei); } #define RAMCHAIN_FUNC struct iguana_ramchain *ramchain,struct iguana_blockRO *B,struct iguana_txid *T,struct iguana_unspent20 *U,struct iguana_spend256 *S,struct iguana_pkhash *P,struct iguana_account *A,bits256 *X,struct iguana_unspent *Ux,struct iguana_spend *Sx,uint8_t *TXbits,uint8_t *PKbits #define RAMCHAIN_PTRPS struct iguana_ramchain *ramchain,struct iguana_blockRO **B,struct iguana_txid **T,struct iguana_unspent20 **U,struct iguana_spend256 **S,struct iguana_pkhash **P,struct iguana_account **A,bits256 **X,struct iguana_unspent **Ux,struct iguana_spend **Sx,uint8_t **TXbits,uint8_t **PKbits #define _RAMCHAIN_ARG B,T,U,S,P,A,X,Ux,Sx,TXbits,PKbits #define RAMCHAIN_ARG ramchain,_RAMCHAIN_ARG #define MAPCHAIN_ARG mapchain,_RAMCHAIN_ARG #define RAMCHAIN_PTRS ramchain,&B,&T,&U,&S,&P,&A,&X,&Ux,&Sx,&TXbits,&PKbits #define RAMCHAIN_DECLARE struct iguana_blockRO *B; struct iguana_txid *T; struct iguana_unspent20 *U; struct iguana_spend256 *S; struct iguana_pkhash *P; struct iguana_account *A; bits256 *X; struct iguana_unspent *Ux; struct iguana_spend *Sx; uint8_t *TXbits,*PKbits; #define RAMCHAIN_DESTARG dest,destB,destT,destU,destS,destP,destA,destX,destUx,destSx,destTXbits,destPKbits #define RAMCHAIN_DESTPTRS dest,&destB,&destT,&destU,&destS,&destP,&destA,&destX,&destUx,&destSx,&destTXbits,&destPKbits #define RAMCHAIN_DESTDECLARE struct iguana_blockRO *destB; struct iguana_txid *destT; struct iguana_unspent20 *destU; struct iguana_spend256 *destS; struct iguana_pkhash *destP; struct iguana_account *destA; bits256 *destX; struct iguana_unspent *destUx; struct iguana_spend *destSx; uint8_t *destTXbits,*destPKbits; uint32_t iguana_ramchain_addtxid(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 txid,int32_t numvouts,int32_t numvins,uint32_t locktime,uint32_t version,uint32_t timestamp) { uint32_t txidind; struct iguana_txid *t; struct iguana_kvitem *ptr; txidind = ramchain->H.txidind; t = &T[txidind]; if ( ramchain->H.ROflag != 0 ) { if ( t->txidind != txidind || memcmp(t->txid.bytes,txid.bytes,sizeof(bits256)) != 0 || t->numvouts != numvouts || t->numvins != numvins || t->firstvout != ramchain->H.unspentind || t->firstvin != ramchain->H.spendind || t->locktime != locktime || t->version != version || t->timestamp != timestamp ) { printf("iguana_ramchain_addtxid: addtxid mismatch (%d %d %d %d %d) vs. (%d %d %d %d %d)\n",t->txidind,t->numvouts,t->numvins,t->firstvout,t->firstvin,txidind,numvouts,numvins,ramchain->H.unspentind,ramchain->H.spendind); exit(-1); return(0); } } else { //if ( ramchain->expanded != 0 ) // printf("T.%p txidind.%d numvouts.%d numvins.%d\n",T,txidind,numvouts,numvins); t->txidind = txidind, t->txid = txid, t->numvouts = numvouts, t->numvins = numvins; t->firstvout = ramchain->H.unspentind, t->firstvin = ramchain->H.spendind; t->locktime = locktime, t->version = version, t->timestamp = timestamp; if ( ramchain->expanded != 0 ) iguana_sparseaddtx(TXbits,ramchain->H.data->txsparsebits,ramchain->H.data->numtxsparse,txid,T,txidind); //if ( txidind <= 2 ) // printf("%p TXID.[%d] firstvout.%d/%d firstvin.%d/%d\n",t,txidind,ramchain->unspentind,numvouts,ramchain->spendind,numvins); } if ( ramchain->expanded != 0 ) { if ( (ptr= iguana_hashsetPT(ramchain,'T',t->txid.bytes,txidind)) == 0 ) { printf("iguana_ramchain_addtxid error adding txidind\n"); return(0); } } return(txidind); } uint32_t iguana_ramchain_addpkhash(struct iguana_info *coin,RAMCHAIN_FUNC,uint8_t rmd160[20],int32_t flags,uint32_t unspentind) { struct iguana_kvitem *ptr; uint32_t pkind = 0; if ( ramchain->expanded != 0 && (ptr= iguana_hashfind(ramchain,'P',rmd160)) == 0 ) { pkind = ramchain->pkind++; if ( ramchain->H.ROflag != 0 ) { if ( P[pkind].flags != flags || P[pkind].firstunspentind != unspentind || P[pkind].pkind != pkind ) { printf("iguana_ramchain_addpkhash pkind.%d vs %d error mismatched flags.(%x %x) firstunspentind.%x vs %x\n",pkind,P[pkind].pkind,P[pkind].flags,flags,P[pkind].firstunspentind,unspentind); exit(-1); return(0); } if ( memcmp(P[pkind].rmd160,rmd160,sizeof(P[pkind].rmd160)) != 0 ) { printf("iguana_ramchain_addpkhash error mismatched rmd160\n"); return(0); } } else { P[pkind].flags = flags; P[pkind].pkind = pkind; P[pkind].firstunspentind = unspentind; //printf("%p P[%d] <- firstunspent.%d\n",&P[pkind],pkind,unspentind); memcpy(P[pkind].rmd160,rmd160,sizeof(P[pkind].rmd160)); if ( ramchain->expanded != 0 ) iguana_sparseaddpk(PKbits,ramchain->H.data->pksparsebits,ramchain->H.data->numpksparse,rmd160,P,pkind); } if ( (ptr= iguana_hashsetPT(ramchain,'P',&P[pkind],pkind)) == 0 ) { printf("iguana_ramchain_addpkhash error adding pkhash\n"); return(0); } } return(pkind); } uint32_t iguana_ramchain_addunspent20(struct iguana_info *coin,RAMCHAIN_FUNC,uint64_t value,uint8_t *script,int32_t scriptlen,bits256 txid,int32_t vout,uint8_t type) { //struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; } __attribute__((packed)); uint8_t rmd160[20],msigs160[16][20]; int32_t M,N; uint32_t unspentind; struct iguana_unspent20 *u; unspentind = ramchain->H.unspentind++; u = &U[unspentind]; if ( scriptlen == -20 ) memcpy(rmd160,script,20); else type = iguana_calcrmd160(coin,rmd160,msigs160,&M,&N,script,scriptlen,txid); if ( ramchain->H.ROflag != 0 ) { //printf("%p U[%d] txidind.%d pkind.%d\n",u,unspentind,ramchain->txidind,pkind); if ( u->txidind != ramchain->H.txidind || u->value != value || memcmp(u->rmd160,rmd160,sizeof(rmd160)) != 0 ) { printf("iguana_ramchain_addunspent20: mismatched values.(%.8f %d) vs (%.8f %d)\n",dstr(u->value),u->txidind,dstr(value),ramchain->H.txidind); return(0); } } else { u->value = value; u->type = type; u->txidind = ramchain->H.txidind; memcpy(u->rmd160,rmd160,sizeof(rmd160)); } return(unspentind); } uint32_t iguana_ramchain_addunspent(struct iguana_info *coin,RAMCHAIN_FUNC,uint64_t value,uint16_t hdrsi,uint8_t *rmd160,uint16_t vout,uint8_t type) { uint32_t unspentind; struct iguana_unspent *u; struct iguana_kvitem *ptr; int32_t pkind; unspentind = ramchain->H.unspentind++; u = &Ux[unspentind]; if ( (ptr= iguana_hashfind(ramchain,'P',rmd160)) == 0 ) pkind = iguana_ramchain_addpkhash(coin,RAMCHAIN_ARG,rmd160,0,unspentind); else pkind = ptr->hh.itemind; if ( pkind == 0 ) return(0); if ( ramchain->H.ROflag != 0 ) { //printf("%p U[%d] txidind.%d pkind.%d\n",u,unspentind,ramchain->txidind,pkind); if ( u->value != value || u->pkind != pkind || u->value != value || u->txidind != ramchain->H.txidind || (pkind != 0 && u->prevunspentind != A[pkind].lastunspentind) || u->vout != vout || u->hdrsi != hdrsi ) { printf("iguana_ramchain_addunspent: mismatched values.(%d %.8f %d %d %d %d) vs (%d %.8f %d %d %d %d)\n",u->pkind,dstr(u->value),u->txidind,u->prevunspentind,u->vout,u->hdrsi,pkind,dstr(value),ramchain->H.txidind,A[pkind].lastunspentind,vout,hdrsi); exit(-1); return(0); } } else { u->value = value; u->type = type; u->vout = vout, u->hdrsi = hdrsi; u->txidind = ramchain->H.txidind, u->pkind = pkind; u->prevunspentind = A[pkind].lastunspentind; } //printf("%p A[%d] last <- U%d\n",&A[pkind],pkind,unspentind); A[pkind].balance += value; A[pkind].lastunspentind = unspentind; return(unspentind); } uint32_t iguana_ramchain_addspend256(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 prev_hash,int32_t prev_vout,uint8_t *script,int32_t scriptlen,uint32_t sequence)//,int32_t hdrsi,int32_t bundlei) { struct iguana_spend256 *s; uint32_t spendind; spendind = ramchain->H.spendind++; s = &S[spendind]; if ( ramchain->H.ROflag != 0 ) { if ( (s->diffsequence == 0 && sequence != 0xffffffff) || (s->diffsequence != 0 && sequence == 0xffffffff) || memcmp(s->prevhash2.bytes,prev_hash.bytes,sizeof(bits256)) != 0 || s->prevout != prev_vout ) //|| s->hdrsi != hdrsi { char str[65],str2[65]; printf("check addspend.%d v %d RO value mismatch diffseq.%d seq.%x prev_vout(%d vs %d) %s vs %s\n",spendind,s->spendind,s->diffsequence,sequence,s->prevout,prev_vout,bits256_str(str,s->prevhash2),bits256_str(str2,prev_hash)); //printf("check addspend.%d vs %d RO value mismatch (%d %d:%d) vs (%d %d:%d)\n",spendind,s->spendind,s->prevout,s->hdrsi,s->bundlei,prev_vout,hdrsi,bundlei); exit(-1); return(0); } //printf(" READ.%p spendind.%d vs %d prevout.%d hdrsi.%d:%d\n",s,spendind,s->spendind,s->prevout,s->hdrsi,s->bundlei); } else { if ( sequence != 0xffffffff ) s->diffsequence = 1; s->prevhash2 = prev_hash, s->prevout = prev_vout; //s->hdrsi = hdrsi, s->bundlei = bundlei; s->spendind = spendind; //char str[65]; printf("W.%p s.%d vout.%d/%d %d:%d %s\n",s,spendind,s->prevout,prev_vout,s->hdrsi,s->bundlei,bits256_str(str,prev_hash)); } return(spendind); } int32_t iguana_ramchain_spendtxid(struct iguana_info *coin,bits256 *txidp,struct iguana_txid *T,int32_t numtxids,bits256 *X,int32_t numexternaltxids,struct iguana_spend *s) { uint32_t ind,external; memset(txidp,0,sizeof(*txidp)); //printf("s.%p ramchaintxid vout.%x spendtxidind.%d numexternals.%d isext.%d numspendinds.%d\n",s,s->vout,s->spendtxidind,ramchain->numexternaltxids,s->external,ramchain->numspends); if ( s->prevout < 0 ) return(-1); ind = s->spendtxidind; external = (ind >> 31) & 1; ind &= ~(1 << 31); if ( s->external != 0 && s->external == external && ind < numexternaltxids ) { //printf("ind.%d externalind.%d X[%d]\n",ind,ramchain->externalind,ramchain->H.data->numexternaltxids); *txidp = X[ind]; return(s->prevout); } else if ( s->external == 0 && s->external == external && ind < numtxids ) { *txidp = T[ind].txid; return(s->prevout); } return(-2); } int32_t iguana_ramchain_txid(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 *txidp,struct iguana_spend *s) { uint32_t ind,external; memset(txidp,0,sizeof(*txidp)); //printf("s.%p ramchaintxid vout.%x spendtxidind.%d numexternals.%d isext.%d numspendinds.%d\n",s,s->vout,s->spendtxidind,ramchain->numexternaltxids,s->external,ramchain->numspends); if ( s->prevout < 0 ) return(-1); ind = s->spendtxidind; external = (ind >> 31) & 1; ind &= ~(1 << 31); if ( s->external != 0 && s->external == external && ind < ramchain->H.data->numexternaltxids ) { //printf("ind.%d externalind.%d X[%d]\n",ind,ramchain->externalind,ramchain->H.data->numexternaltxids); *txidp = X[ind]; return(s->prevout); } else if ( s->external == 0 && s->external == external && ind < ramchain->H.txidind ) { *txidp = T[ind].txid; return(s->prevout); } return(-2); } uint32_t iguana_ramchain_addspend(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 prev_hash,int32_t prev_vout,uint32_t sequence)//,int32_t hdrsi,int32_t bundlei) { struct iguana_spend *s; struct iguana_kvitem *ptr; bits256 txid; uint32_t spendind,unspentind,txidind,pkind,external; uint64_t value = 0; spendind = ramchain->H.spendind++; s = &Sx[spendind]; pkind = unspentind = 0; if ( (ptr= iguana_hashfind(ramchain,'T',prev_hash.bytes)) == 0 ) { external = 1; txidind = ramchain->externalind++; if ( 0 && ramchain->expanded != 0 ) { char str[65]; printf("%p X[%d] <- %s\n",X,txidind,bits256_str(str,prev_hash)); } if ( ramchain->H.ROflag != 0 ) { if ( memcmp(X[txidind].bytes,prev_hash.bytes,sizeof(prev_hash)) != 0 ) { char str[65],str2[65]; printf("iguana_ramchain_addspend X[%d] of %d cmperror %s vs %s\n",txidind,ramchain->H.data->numexternaltxids,bits256_str(str,X[txidind]),bits256_str(str2,prev_hash)); return(0); } } else X[txidind] = prev_hash; if ( (ptr= iguana_hashsetPT(ramchain,'T',&X[txidind].bytes,txidind | (1 << 31))) == 0 ) { printf("iguana_ramchain_addspend error adding external\n"); return(0); } txidind |= (1 << 31); } else txidind = ptr->hh.itemind; if ( (external= ((txidind >> 31) & 1)) == 0 ) { if ( txidind > 0 && txidind < ramchain->H.data->numtxids ) { if ( (unspentind= T[txidind].firstvout + prev_vout) > 0 && unspentind < ramchain->H.data->numunspents ) { value = Ux[unspentind].value; if ( (pkind= Ux[unspentind].pkind) == 0 || pkind >= ramchain->H.data->numpkinds ) { printf("spendind.%d -> unspendind.%d %.8f -> pkind.0x%x\n",spendind,unspentind,dstr(value),pkind); return(0); } } else printf("addspend illegal unspentind.%d vs %d\n",unspentind,ramchain->H.data->numunspents); } else printf("addspend illegal txidind.%d vs %d\n",txidind,ramchain->H.data->numtxids), exit(-1); } if ( ramchain->H.ROflag != 0 ) { iguana_ramchain_txid(coin,RAMCHAIN_ARG,&txid,s); if ( (s->diffsequence == 0 && sequence != 0xffffffff) || (s->diffsequence != 0 && sequence == 0xffffffff) || memcmp(txid.bytes,prev_hash.bytes,sizeof(bits256)) != 0 || s->prevout != prev_vout )// || s->hdrsi != hdrsi { char str[65],str2[65]; printf("ramchain_addspend RO value mismatch diffseq.%d v %x (%d) vs (%d) %s vs %s\n",s->diffsequence,sequence,s->prevout,prev_vout,bits256_str(str,txid),bits256_str(str2,prev_hash)); return(0); } } else { if ( sequence != 0xffffffff ) s->diffsequence = 1; s->external = external, s->spendtxidind = txidind, s->prevout = prev_vout; //s->hdrsi = hdrsi; //s->bundlei = bundlei; //char str[65]; printf("%s set prevout.%d -> %d\n",bits256_str(str,prev_hash),prev_vout,s->prevout); //if ( pkind != 0 ) // s->prevspendind = A[pkind].lastspendind; } if ( pkind != 0 ) { A[pkind].balance -= value; //A[pkind].lastspendind = spendind; //if ( P2[pkind].firstspendind == 0 ) // P2[pkind].firstspendind = spendind; } /*if ( unspentind != 0 ) { if ( U2[unspentind].spendind == 0 ) U2[unspentind].spendind = spendind; }*/ return(spendind); } int64_t iguana_hashmemsize(uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids) { int64_t allocsize = 0; allocsize += (65536*4 + ((numtxids + numpkinds) * (sizeof(UT_hash_handle)*2)) + (((sizeof(struct iguana_account)) * 2 * numpkinds)) + (2 * numunspents * sizeof(struct iguana_Uextra))); //printf("iguana_hashmemsize T.%d U.%d S.%d P.%d X.%d -> %ld\n",numtxids,numunspents,numspends,numpkinds,numexternaltxids,(long)allocsize); return(allocsize); } void _iguana_ramchain_setptrs(RAMCHAIN_PTRPS,struct iguana_ramchaindata *rdata) { *B = (void *)(long)((long)rdata + (long)rdata->Boffset); *T = (void *)(long)((long)rdata + (long)rdata->Toffset); if ( ramchain->expanded != 0 ) { *Ux = (void *)(long)((long)rdata + (long)rdata->Uoffset); *Sx = (void *)(long)((long)rdata + (long)rdata->Soffset); *P = (void *)(long)((long)rdata + (long)rdata->Poffset); *X = (void *)(long)((long)rdata + (long)rdata->Xoffset); //ramchain->roU2 = (void *)(long)((long)rdata + (long)rdata->U2offset); //ramchain->roP2 = (void *)(long)((long)rdata + (long)rdata->P2offset); ramchain->roA = (void *)(long)(long)((long)rdata + (long)rdata->Aoffset); //if ( (*U2= ramchain->U2) == 0 ) // *U2 = ramchain->U2 = ramchain->roU2; //if ( (*P2= ramchain->P2) == 0 ) // *P2 = ramchain->P2 = ramchain->roP2; if ( (*A= ramchain->A) == 0 ) *A = ramchain->A = ramchain->roA; //printf("T.%p Ux.%p Sx.%p P.%p\n",*T,*Ux,*Sx,*P); *TXbits = (void *)(long)((long)rdata + (long)rdata->TXoffset); *PKbits = (void *)(long)((long)rdata + (long)rdata->PKoffset); *U = 0, *S = 0; } else { *U = (void *)(long)((long)rdata + (long)rdata->Uoffset); *S = (void *)(long)((long)rdata + (long)rdata->Soffset); *Ux = 0, *Sx = 0, *P = 0, *X = 0, *A = 0, *TXbits = 0, *PKbits = 0; //*U2 = 0, *P2 = 0, } } void *iguana_ramchain_offset(void *dest,uint8_t *lhash,FILE *fp,uint64_t fpos,void *srcptr,uint64_t *offsetp,uint64_t len,uint64_t srcsize) { void *destptr = (void *)(long)((long)dest + *offsetp); if ( (lhash != 0 || fp != 0) && (*offsetp + len) > srcsize ) { printf("ramchain_offset overflow (%p %p) offset.%ld + len.%ld %ld > %ld srcsize\n",fp,lhash,(long)*offsetp,(long)len,(long)(*offsetp + len),(long)srcsize); exit(-1); } if ( lhash != 0 ) { //fprintf(stderr,"lhash.%p memptr.%p offset.%ld len.%ld avail.%ld srcsize.%ld\n",lhash,srcptr,(long)*offsetp,(long)len,(long)(srcsize - (*offsetp + len)),(long)srcsize); vcalc_sha256(0,lhash,srcptr,(uint32_t)len); } else if ( fp != 0 ) { if ( fwrite(srcptr,1,len,fp) != len ) printf("iguana_ramchain_sizefunc: error writing len.%ld to fp.%p\n",(long)len,fp); //else printf("fp.(%ld <- %d) ",ftell(fp),(int32_t)len); } (*offsetp) += len; return((void *)(long)((long)destptr + fpos)); } int64_t _iguana_rdata_action(FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],void *destptr,uint64_t fpos,uint32_t expanded,uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids,uint32_t txsparsebits,uint64_t numtxsparse,uint32_t pksparsebits,uint64_t numpksparse,uint64_t srcsize,RAMCHAIN_FUNC,int32_t numblocks) { #define RAMCHAIN_LARG(ind) ((lhashes == 0) ? 0 : lhashes[ind].bytes) #define SPARSECOUNT(x) ((x) << 2) FILE *fparg = 0; int32_t iter; uint64_t txbits,pkbits,offset = 0; struct iguana_ramchaindata *rdata = destptr; if ( expanded != 0 ) { if( txsparsebits == 0 || numtxsparse == 0 ) { txsparsebits = hcalc_bitsize(numtxids); numtxsparse = SPARSECOUNT(numtxids); } if ( pksparsebits == 0 || numpksparse == 0 ) { pksparsebits = hcalc_bitsize(numpkinds); numpksparse = SPARSECOUNT(numpkinds); } txbits = numtxsparse * txsparsebits; pkbits = numpksparse * pksparsebits; } else txbits = pkbits = numtxsparse = txsparsebits = numpksparse = pksparsebits = 0; for (iter=0; iter<2; iter++) { if ( iter == 0 && lhashes == 0 ) { fparg = fp; continue; } offset = sizeof(struct iguana_ramchaindata); B = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_BLOCKS),fparg,fpos,B,&offset,(sizeof(struct iguana_blockRO) * numblocks),srcsize); T = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_TXIDS),fparg,fpos,T,&offset,(sizeof(struct iguana_txid) * numtxids),srcsize); if ( expanded != 0 ) { U = destptr, S = destptr; Ux = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_UNSPENTS),fparg,fpos,Ux,&offset,(sizeof(struct iguana_unspent) * numunspents),srcsize); Sx = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_SPENDS),fparg,fpos,Sx,&offset,(sizeof(struct iguana_spend) * numspends),srcsize); P = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_PKHASHES),fparg,fpos,P,&offset,(sizeof(struct iguana_pkhash) * numpkinds),srcsize); //U2 = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_SPENTINDS),fparg,fpos,U2,&offset,(sizeof(struct iguana_Uextra) * numunspents),srcsize); //P2 = 0;//iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_FIRSTSPENDS),fparg,fpos,P2,&offset,(sizeof(struct iguana_pkextra) * numpkinds),srcsize); A = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_ACCOUNTS),fparg,fpos,A,&offset,(sizeof(struct iguana_account) * numpkinds),srcsize); char str[65]; if ( 0 && X != 0 ) printf("%p X[1] -> %s\n",&X[1],bits256_str(str,X[1])); X = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_EXTERNALS),fparg,fpos,X,&offset,(sizeof(bits256) * numexternaltxids),srcsize); TXbits = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_TXBITS),fparg,fpos,TXbits,&offset,hconv_bitlen(txbits),srcsize); PKbits = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_PKBITS),fparg,fpos,PKbits,&offset,hconv_bitlen(pkbits),srcsize); } else { Ux = destptr, Sx = destptr, P = destptr, A = destptr, X = destptr, TXbits = destptr, PKbits = destptr; //U2 = destptr, P2 = destptr, U = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_UNSPENTS),fparg,fpos,U,&offset,(sizeof(struct iguana_unspent20) * numunspents),srcsize); if ( 0 && lhashes != 0 ) printf("iter.%d lhashes.%p offset.%ld destptr.%p len.%ld fparg.%p fpos.%ld srcsize.%ld\n",iter,RAMCHAIN_LARG(IGUANA_LHASH_SPENDS),(long)offset,destptr,(long)sizeof(struct iguana_spend256) * numspends,fparg,(long)fpos,(long)srcsize); S = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_SPENDS),fparg,fpos,S,&offset,(sizeof(struct iguana_spend256) * numspends),srcsize); } if ( (fparg= fp) == 0 ) break; lhashes = 0; } if ( rdata != 0 ) { rdata->allocsize = offset; rdata->Boffset = (uint64_t)((long)B - (long)destptr); rdata->Toffset = (uint64_t)((long)T - (long)destptr); if ( expanded != 0 ) { rdata->Uoffset = (uint64_t)((long)Ux - (long)destptr); rdata->Soffset = (uint64_t)((long)Sx - (long)destptr); } else { rdata->Uoffset = (uint64_t)((long)U - (long)destptr); rdata->Soffset = (uint64_t)((long)S - (long)destptr); } rdata->Poffset = (uint64_t)((long)P - (long)destptr); //rdata->U2offset = (uint64_t)((long)U2 - (long)destptr); //rdata->P2offset = (uint64_t)((long)P2 - (long)destptr); rdata->Aoffset = (uint64_t)((long)A - (long)destptr); rdata->Xoffset = (uint64_t)((long)X - (long)destptr); rdata->TXoffset = (uint64_t)((long)TXbits - (long)destptr); rdata->PKoffset = (uint64_t)((long)PKbits - (long)destptr); rdata->numtxids = numtxids; rdata->numunspents = numunspents; rdata->numspends = numspends; rdata->numpkinds = numpkinds; rdata->numexternaltxids = numexternaltxids; rdata->txsparsebits = txsparsebits, rdata->numtxsparse = (uint32_t)numtxsparse; rdata->pksparsebits = pksparsebits, rdata->numpksparse = (uint32_t)numpksparse; } return(offset); #undef RAMCHAIN_LARG #undef SPARSECOUNT } int64_t iguana_ramchain_action(RAMCHAIN_FUNC,FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],struct iguana_ramchaindata *destdata,uint64_t fpos,struct iguana_ramchaindata *srcdata,int32_t numblocks) { if ( 0 && ramchain->expanded != 0 ) printf("action.%p (%p %p %p) %ld allocated.%ld [%d:%d %d:%d]\n",srcdata,fp,lhashes,destdata,(long)fpos,(long)srcdata->allocsize,srcdata->txsparsebits,srcdata->numtxsparse,srcdata->pksparsebits,srcdata->numpksparse); return(_iguana_rdata_action(fp,lhashes,destdata,fpos,ramchain->expanded,srcdata->numtxids,srcdata->numunspents,srcdata->numspends,srcdata->numpkinds,srcdata->numexternaltxids,srcdata->txsparsebits,srcdata->numtxsparse,srcdata->pksparsebits,srcdata->numpksparse,srcdata->allocsize,RAMCHAIN_ARG,numblocks)); } int64_t iguana_ramchain_size(RAMCHAIN_FUNC,int32_t numblocks) { return(iguana_ramchain_action(RAMCHAIN_ARG,0,0,0,0,ramchain->H.data,numblocks)); } long iguana_ramchain_setsize(struct iguana_ramchain *ramchain,struct iguana_ramchaindata *srcdata,int32_t numblocks) { RAMCHAIN_DECLARE; struct iguana_ramchaindata *rdata = ramchain->H.data; B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, TXbits = 0, PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, rdata->numtxids = ramchain->H.txidind; rdata->numunspents = ramchain->H.unspentind; rdata->numspends = ramchain->H.spendind; rdata->numpkinds = ramchain->pkind; rdata->numexternaltxids = ramchain->externalind; rdata->allocsize = iguana_ramchain_size(RAMCHAIN_ARG,numblocks); ramchain->datasize = rdata->allocsize; return((long)rdata->allocsize); } int64_t iguana_ramchain_compact(RAMCHAIN_FUNC,struct iguana_ramchaindata *destdata,struct iguana_ramchaindata *srcdata,int32_t numblocks) { //iguana_ramchain_setsize(ramchain,srcdata); return(iguana_ramchain_action(RAMCHAIN_ARG,0,0,destdata,0,srcdata,numblocks)); } bits256 iguana_ramchain_lhashes(RAMCHAIN_FUNC,struct iguana_ramchaindata *destdata,struct iguana_ramchaindata *srcdata,int32_t numblocks) { iguana_ramchain_action(RAMCHAIN_ARG,0,destdata->lhashes,0,0,srcdata,numblocks); memset(&destdata->sha256,0,sizeof(destdata->sha256)); vcalc_sha256(0,destdata->sha256.bytes,(void *)destdata,sizeof(*destdata)); return(destdata->sha256); } int64_t iguana_ramchain_saveaction(RAMCHAIN_FUNC,FILE *fp,struct iguana_ramchaindata *rdata,int32_t numblocks) { long before,after; before = ftell(fp); iguana_ramchain_action(RAMCHAIN_ARG,fp,0,rdata,0,rdata,numblocks); after = ftell(fp); if ( 0 && ramchain->expanded != 0 ) { char str[65]; printf("SAVEACTION: rdata.%ld DEST T.%d U.%d S.%d P.%d X.%d -> size.%ld %ld vs %ld %p %s\n",sizeof(*rdata),rdata->numtxids,rdata->numunspents,rdata->numspends,rdata->numpkinds,rdata->numexternaltxids,(long)rdata->allocsize,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks),after-before+sizeof(*rdata),&X[1],bits256_str(str,X[1])); } //printf("before.%ld after.%ld allocsize.%ld [%ld] %ld expanded.%d\n",before,after,(long)srcdata->allocsize,(long)ramchain->H.data->allocsize,(long)iguana_ramchain_size(ramchain),ramchain->expanded); return(after - before); } int64_t iguana_ramchain_init(struct iguana_ramchain *ramchain,struct OS_memspace *mem,struct OS_memspace *hashmem,int32_t firsti,int32_t numtxids,int32_t numunspents,int32_t numspends,int32_t numpkinds,int32_t numexternaltxids,int32_t expanded,int32_t numblocks) { RAMCHAIN_DECLARE; int64_t offset = 0; struct iguana_ramchaindata *rdata; B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, TXbits = 0, PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, if ( mem == 0 ) return(0); memset(ramchain,0,sizeof(*ramchain)); ramchain->expanded = (expanded != 0); if ( (ramchain->hashmem= hashmem) != 0 ) iguana_memreset(hashmem); rdata = ramchain->H.data = mem->ptr, offset += sizeof(struct iguana_ramchaindata); if ( (rdata->firsti= firsti) != 0 ) { numtxids++, numunspents++, numspends++; if ( numpkinds != 0 ) numpkinds++; } if ( numexternaltxids == 0 ) numexternaltxids = numspends; if ( numpkinds == 0 ) numpkinds = numunspents; if ( 0 && expanded != 0 ) printf("init T.%d U.%d S.%d P.%d X.%d -> %ld\n",numtxids,numunspents,numspends,numpkinds,numexternaltxids,(long)offset); _iguana_rdata_action(0,0,rdata,0,expanded,numtxids,numunspents,numspends,numpkinds,numexternaltxids,0,0,0,0,0,RAMCHAIN_ARG,numblocks); if ( rdata->allocsize != iguana_ramchain_size(RAMCHAIN_ARG,numblocks) ) { printf("offset.%ld vs memsize.%ld\n",(long)offset,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks)); exit(-1); } if ( offset < mem->totalsize ) iguana_memreset(mem); else { printf("offset.%ld vs memsize.%ld\n",(long)offset,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks)); printf("NEED %ld realloc for %ld\n",(long)offset,(long)mem->totalsize); exit(-1); iguana_mempurge(mem); iguana_meminit(mem,"ramchain",0,offset,0); } //printf("init.(%d %d %d %d %d)\n",numtxids,numunspents,numspends,numpkinds,numexternaltxids); return(offset); } int32_t iguana_ramchain_alloc(struct iguana_info *coin,struct iguana_ramchain *ramchain,struct OS_memspace *mem,struct OS_memspace *hashmem,uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids,int32_t height,int32_t numblocks) { RAMCHAIN_DECLARE; int64_t hashsize,allocsize,x; B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, TXbits = 0, PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, memset(ramchain,0,sizeof(*ramchain)); ramchain->height = height; allocsize = _iguana_rdata_action(0,0,0,0,1,numtxids,numunspents,numspends,numpkinds,numexternaltxids,0,0,0,0,0,RAMCHAIN_ARG,numblocks); //printf("T.%d U.%d S.%d P.%d X.%d -> %ld\n",numtxids,numunspents,numspends,numpkinds,numexternaltxids,(long)allocsize); memset(mem,0,sizeof(*mem)); memset(hashmem,0,sizeof(*hashmem)); hashsize = iguana_hashmemsize(numtxids,numunspents,numspends,numpkinds,numexternaltxids); while ( (x= (myallocated(0,-1)+hashsize+allocsize)) > coin->MAXMEM ) { char str[65],str2[65]; fprintf(stderr,"ht.%d wait for allocated %s < MAXMEM %s | elapsed %.2f minutes\n",height,mbstr(str,hashsize+allocsize),mbstr(str2,coin->MAXMEM),(double)(time(NULL)-coin->startutc)/60.); sleep(3); } iguana_meminit(hashmem,"ramhashmem",0,hashsize + 4096,0); iguana_meminit(mem,"ramchain",0,allocsize + 4096,0); mem->alignflag = sizeof(uint32_t); hashmem->alignflag = sizeof(uint32_t); if ( iguana_ramchain_init(ramchain,mem,hashmem,1,numtxids,numunspents,numspends,numpkinds,numexternaltxids,1,numblocks) == 0 ) return(-1); return(0); } long iguana_ramchain_save(struct iguana_info *coin,RAMCHAIN_FUNC,uint32_t ipbits,bits256 hash2,bits256 prevhash2,int32_t bundlei,struct iguana_bundle *bp) { struct iguana_ramchaindata *rdata,tmp; char fname[1024]; long fpos = -1; int32_t hdrsi,checki; FILE *fp; if ( (rdata= ramchain->H.data) == 0 ) { printf("ramchainsave no data ptr\n"); return(-1); } if ( (checki= iguana_peerfname(coin,&hdrsi,ipbits==0?"DB":"tmp",fname,ipbits,hash2,prevhash2,ramchain->numblocks)) != bundlei || bundlei < 0 || bundlei >= coin->chain->bundlesize ) { printf(" wont save.(%s) bundlei.%d != checki.%d\n",fname,bundlei,checki); return(-1); } OS_compatible_path(fname); if ( (fp= fopen(fname,"rb+")) == 0 ) { if ( (fp= fopen(fname,"wb")) != 0 ) coin->peers.numfiles++; } else if ( ipbits != 0 ) fseek(fp,0,SEEK_END); else { fclose(fp); fp = fopen(fname,"wb"); } if ( fp != 0 ) { fpos = ftell(fp); iguana_ramchain_lhashes(RAMCHAIN_ARG,rdata,rdata,bp!=0?bp->n:1); tmp = *rdata; iguana_ramchain_compact(RAMCHAIN_ARG,&tmp,rdata,bp!=0?bp->n:1); fwrite(&tmp,1,sizeof(tmp),fp); iguana_ramchain_saveaction(RAMCHAIN_ARG,fp,rdata,bp!=0?bp->n:1); *rdata = tmp; fclose(fp); } return(fpos); } int32_t iguana_ramchain_verify(struct iguana_info *coin,struct iguana_ramchain *ramchain) { RAMCHAIN_DECLARE; struct iguana_txid *t; struct iguana_unspent *u; struct iguana_pkhash *p; struct iguana_ramchaindata *rdata; int32_t k,pkind,vout; struct iguana_kvitem *ptr; bits256 txid; // iguana_txid { bits256 txid; uint32_t txidind,firstvout,firstvin; uint16_t numvouts,numvins;} if ( (rdata= ramchain->H.data) == 0 ) return(-100); _iguana_ramchain_setptrs(RAMCHAIN_PTRS,rdata); ramchain->pkind = ramchain->H.unspentind = ramchain->H.spendind = rdata->firsti; ramchain->externalind = 0; for (ramchain->H.txidind=rdata->firsti; ramchain->H.txidindnumtxids; ramchain->H.txidind++) { t = &T[ramchain->H.txidind]; if ( t->txidind != ramchain->H.txidind ) { printf("firsti.%d t->txidind.%d != txidind.%d\n",rdata->firsti,t->txidind,ramchain->H.txidind); return(-1); } if ( t->firstvout != ramchain->H.unspentind ) { printf("%p txidind.%d firstvout.%d != unspentind.%d\n",t,ramchain->H.txidind,t->firstvout,ramchain->H.unspentind); exit(-1); return(-4); } if ( t->firstvin != ramchain->H.spendind ) { printf("t[%d] firstvin.%d vs spendind.%d\n",t->txidind,t->firstvin,ramchain->H.spendind); return(-5); } if ( ramchain->expanded != 0 ) { if ( (ptr= iguana_hashfind(ramchain,'T',t->txid.bytes)) == 0 ) return(-2); if ( ptr->hh.itemind != ramchain->H.txidind ) { if ( strcmp(coin->symbol,"BTC") == 0 ) { bits256 duptxid,duptxid2; decode_hex(duptxid.bytes,sizeof(duptxid),"e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468"); // BTC.tx0: 91722, 91880 decode_hex(duptxid2.bytes,sizeof(duptxid2),"d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599"); // BTC.tx0 91812, 91842 if ( memcmp(duptxid.bytes,t->txid.bytes,sizeof(duptxid)) == 0 || memcmp(duptxid2.bytes,t->txid.bytes,sizeof(duptxid2)) == 0 ) printf("BIP 0 detected\n"); else { char str[65]; printf("error -3: %s itemind.%d vs txidind.%d | num.%d\n",bits256_str(str,t->txid),ptr->hh.itemind,ramchain->H.txidind,ramchain->H.data->numtxids); return(-3); } } else { char str[65]; printf("error -3: %s itemind.%d vs txidind.%d | num.%d\n",bits256_str(str,t->txid),ptr->hh.itemind,ramchain->H.txidind,ramchain->H.data->numtxids); exit(-1); return(-3); } } for (k=0; knumvouts; k++,ramchain->H.unspentind++) { u = &Ux[ramchain->H.unspentind]; if ( u->txidind != ramchain->H.txidind ) { printf("ramchain_verify k.%d %p U.%d u->txidind.%x != txidind.%d\n",k,u,ramchain->H.unspentind,u->txidind,ramchain->H.txidind); exit(-1); return(-6); } if ( (pkind= u->pkind) < 0 || pkind >= rdata->numpkinds ) { printf("k.%d unspentind.%d pkind.%d numpkinds.%d\n",k,ramchain->H.unspentind,pkind,rdata->numpkinds); return(-7); } p = &P[pkind]; if ( (ptr= iguana_hashfind(ramchain,'P',p->rmd160)) == 0 ) return(-8); if ( ptr->hh.itemind == pkind && p->firstunspentind > ramchain->H.unspentind ) { printf("%p itemind.%d pkind.%d firstunspent.%d != %d unspentind?\n",p,ptr->hh.itemind,pkind,p->firstunspentind,ramchain->H.unspentind); return(-9); } } } else { for (k=0; knumvouts; k++,ramchain->H.unspentind++) { if ( U[ramchain->H.unspentind].txidind != ramchain->H.txidind ) { printf(" k.%d U.%d u->txidind.%x != txidind.%d\n",k,ramchain->H.unspentind,U[ramchain->H.unspentind].txidind,ramchain->H.txidind); return(-6); } } } ramchain->H.spendind += t->numvins; } ramchain->H.spendind = rdata->firsti; for (ramchain->H.txidind=rdata->firsti; ramchain->H.txidindnumtxids; ramchain->H.txidind++) { t = &T[ramchain->H.txidind]; for (k=0; knumvins; k++,ramchain->H.spendind++) { if ( ramchain->expanded != 0 ) { //printf("item.%p [%d] X.%p k.%d txidind.%d/%d spendind.%d/%d s->txidind.%x/v%d\n",rdata,rdata->numexternaltxids,X,k,ramchain->txidind,rdata->numtxids,spendind,rdata->numspends,s->spendtxidind,s->vout); if ( (vout= iguana_ramchain_txid(coin,RAMCHAIN_ARG,&txid,&Sx[ramchain->H.spendind])) < -1 ) { printf("txidind.%d k.%d error getting txid firsti.%d X.%d vout.%d spend.%x/%d numX.%d numT.%d\n",ramchain->H.txidind,k,rdata->firsti,ramchain->externalind,vout,Sx[ramchain->H.spendind].spendtxidind,rdata->numspends,rdata->numexternaltxids,rdata->numtxids); return(-10); } if ( vout == -1 ) { // mining output } else { if ( (ptr= iguana_hashfind(ramchain,'T',txid.bytes)) == 0 ) { char str[65]; printf("cant find vout.%d %s\n",vout,bits256_str(str,txid)); return(-11); } } } } } if ( ramchain->expanded != 0 && ramchain->A != ramchain->roA ) { for (k=rdata->firsti; knumpkinds; k++) { if ( memcmp(&ramchain->A[k],&ramchain->roA[k],sizeof(ramchain->A[k])) != 0 ) { printf("k.%d balance.(%.8f vs %.8f) lastU.(%d %d)\n",k,dstr(ramchain->A[k].balance),dstr(ramchain->roA[k].balance),ramchain->A[k].lastunspentind,ramchain->roA[k].lastunspentind); return(-14); } //if ( memcmp(&ramchain->P2[k],&ramchain->roP2[k],sizeof(ramchain->P2[k])) != 0 ) // return(-15); } //for (k=rdata->firsti; knumunspents; k++) // if ( memcmp(&ramchain->U2[k],&ramchain->roU2[k],sizeof(ramchain->U2[k])) != 0 ) // return(-16); } return(0); } int32_t iguana_ramchain_free(struct iguana_ramchain *ramchain,int32_t deleteflag) { struct iguana_kvitem *item,*tmp; if ( ramchain->H.ROflag != 0 && ramchain->hashmem == 0 ) { //printf("Free A %p %p, U2, P2\n",ramchain->A,ramchain->roA); if ( ramchain->A != ramchain->roA ) myfree(ramchain->A,sizeof(*ramchain->A) * ramchain->H.data->numpkinds), ramchain->A = 0; //if ( ramchain->U2 != ramchain->roU2 ) // myfree(ramchain->U2,sizeof(*ramchain->U2) * ramchain->H.data->numunspents), ramchain->U2 = 0; //if ( ramchain->P2 != ramchain->roP2 ) // myfree(ramchain->P2,sizeof(*ramchain->P2) * ramchain->H.data->numpkinds), ramchain->P2 = 0; } if ( deleteflag != 0 ) { if ( ramchain->txids != 0 ) { HASH_ITER(hh,ramchain->txids,item,tmp) { HASH_DEL(ramchain->txids,item); if ( ramchain->hashmem == 0 ) myfree(item,sizeof(*item)); } } if ( ramchain->pkhashes != 0 ) { HASH_ITER(hh,ramchain->pkhashes,item,tmp) { HASH_DEL(ramchain->pkhashes,item); if ( ramchain->hashmem == 0 ) myfree(item,sizeof(*item)); } } } if ( ramchain->hashmem != 0 ) iguana_memreset(ramchain->hashmem); if ( ramchain->filesize != 0 ) munmap(ramchain->fileptr,ramchain->filesize); memset(ramchain,0,sizeof(*ramchain)); return(0); } void iguana_ramchain_extras(struct iguana_ramchain *ramchain,struct OS_memspace *hashmem) { RAMCHAIN_DECLARE; if ( ramchain->expanded != 0 ) { _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); if ( (ramchain->hashmem= hashmem) != 0 ) iguana_memreset(hashmem); ramchain->A = (hashmem != 0) ? iguana_memalloc(hashmem,sizeof(struct iguana_account) * ramchain->H.data->numpkinds,1) : mycalloc('p',ramchain->H.data->numpkinds,sizeof(struct iguana_account)); //ramchain->P2 = (hashmem != 0) ? iguana_memalloc(hashmem,sizeof(struct iguana_pkextra) * ramchain->H.data->numpkinds,1) : mycalloc('2',ramchain->H.data->numpkinds,sizeof(struct iguana_pkextra)); ///ramchain->U2 = (hashmem != 0) ? iguana_memalloc(hashmem,sizeof(struct iguana_Uextra) * ramchain->H.data->numunspents,1) : mycalloc('3',ramchain->H.data->numunspents,sizeof(struct iguana_Uextra)); //printf("iguana_ramchain_extras A.%p:%p U2.%p:%p P2.%p:%p\n",ramchain->A,ramchain->roA,ramchain->U2,ramchain->roU2,ramchain->P2,ramchain->roP2); //memcpy(ramchain->U2,ramchain->roU2,sizeof(*ramchain->U2) * ramchain->H.data->numunspents); //memcpy(ramchain->P2,ramchain->roP2,sizeof(*ramchain->P2) * ramchain->H.data->numpkinds); } } struct iguana_ramchain *iguana_ramchain_map(struct iguana_info *coin,char *fname,struct iguana_bundle *bp,int32_t numblocks,struct iguana_ramchain *ramchain,struct OS_memspace *hashmem,uint32_t ipbits,bits256 hash2,bits256 prevhash2,int32_t bundlei,long fpos,int32_t allocextras,int32_t expanded) { RAMCHAIN_DECLARE; int32_t valid,i,checki,hdrsi; char str[65],str2[65]; long filesize; void *ptr; struct iguana_block *block; if ( ramchain->fileptr == 0 || ramchain->filesize <= 0 ) { if ( (checki= iguana_peerfname(coin,&hdrsi,ipbits==0?"DB":"tmp",fname,ipbits,hash2,prevhash2,numblocks)) != bundlei || bundlei < 0 || bundlei >= coin->chain->bundlesize ) { printf("iguana_ramchain_map.(%s) illegal hdrsi.%d bundlei.%d %s\n",fname,hdrsi,bundlei,bits256_str(str,hash2)); return(0); } memset(ramchain,0,sizeof(*ramchain)); if ( (ptr= OS_mapfile(fname,&filesize,0)) == 0 ) return(0); ramchain->fileptr = ptr; ramchain->filesize = (long)filesize; if ( (ramchain->hashmem= hashmem) != 0 ) iguana_memreset(hashmem); } if ( ramchain->fileptr != 0 && ramchain->filesize > 0 ) { // verify hashes ramchain->H.data = (void *)(long)((long)ramchain->fileptr + fpos); ramchain->H.ROflag = 1; ramchain->expanded = expanded; ramchain->numblocks = (bp == 0) ? 1 : bp->n; //printf("ptr.%p %p mapped P[%d] fpos.%d + %ld -> %ld vs %ld\n",ptr,ramchain->H.data,(int32_t)ramchain->H.data->Poffset,(int32_t)fpos,(long)ramchain->H.data->allocsize,(long)(fpos + ramchain->H.data->allocsize),ramchain->filesize); if ( 0 && bp != 0 ) { /*blocksRO = (struct iguana_blockRO *)ramchain->H.data; for (i=0; in; i++) { printf("%p ",&blocksRO[i]); bp->hashes[i] = blocksRO[i].hash2; if ( (bp->blocks[i]= iguana_blockhashset(coin,-1,blocksRO[i].hash2,1)) == 0 ) { printf("Error getting blockptr\n"); return(0); } bp->blocks[i]->RO = blocksRO[i]; } ramchain->H.data = (void *)&blocksRO[bp->n];*/ for (valid=0,i=bp->n=1; i>=0; i--) { if ( (block= bp->blocks[i]) != 0 ) { if ( memcmp(block->RO.hash2.bytes,bp->hashes[i].bytes,sizeof(block->RO.hash2)) == 0 ) { if ( i == 0 || memcmp(block->RO.prev_block.bytes,bp->hashes[i-1].bytes,sizeof(block->RO.prev_block)) == 0 ) valid++; } } } if ( valid != bp->n ) { printf("valid.%d != bp->n.%d, reject mapped ramchain\n",valid,bp->n); return(0); } } _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); if ( iguana_ramchain_size(RAMCHAIN_ARG,ramchain->numblocks) != ramchain->H.data->allocsize || fpos+ramchain->H.data->allocsize > filesize ) { printf("iguana_ramchain_map.(%s) size mismatch %ld vs %ld vs filesize.%ld numblocks.%d expanded.%d fpos.%d sum %ld\n",fname,(long)iguana_ramchain_size(RAMCHAIN_ARG,ramchain->numblocks),(long)ramchain->H.data->allocsize,(long)filesize,ramchain->numblocks,expanded,(int32_t)fpos,(long)(fpos+ramchain->H.data->allocsize)); exit(-1); //munmap(ramchain->fileptr,ramchain->filesize); return(0); } else if ( memcmp(hash2.bytes,ramchain->H.data->firsthash2.bytes,sizeof(bits256)) != 0 ) { printf("iguana_ramchain_map.(%s) hash2 mismatch %s vs %s\n",fname,bits256_str(str,hash2),bits256_str(str2,ramchain->H.data->firsthash2)); //munmap(ramchain->fileptr,ramchain->filesize); return(0); } else if ( ramchain->expanded != 0 ) { if ( allocextras > 0 ) iguana_ramchain_extras(ramchain,ramchain->hashmem); } if ( B != 0 ) { for (i=0; in; i++) { if ( (bp->blocks[i]= iguana_blockhashset(coin,-1,B[i].hash2,1)) == 0 ) { printf("Error getting blockptr\n"); return(0); } bp->blocks[i]->RO = B[i];//coin->blocks.RO[bp->bundleheight + i]; coin->blocks.RO[bp->bundleheight+i] = B[i]; } } return(ramchain); } else printf("iguana_ramchain_map.(%s) cant map file\n",fname); return(0); } void iguana_ramchain_link(struct iguana_ramchain *ramchain,bits256 firsthash2,bits256 lasthash2,int32_t hdrsi,int32_t height,int32_t bundlei,int32_t numblocks,int32_t firsti,int32_t ROflag) { if ( ROflag == 0 ) { ramchain->H.data->firsthash2 = firsthash2; ramchain->H.data->lasthash2 = lasthash2; ramchain->H.data->hdrsi = hdrsi; ramchain->H.data->height = height; ramchain->H.data->numblocks = numblocks; } ramchain->H.hdrsi = hdrsi; ramchain->H.bundlei = bundlei; ramchain->height = height; ramchain->numblocks = numblocks; ramchain->lasthash2 = lasthash2; ramchain->H.txidind = ramchain->H.unspentind = ramchain->H.spendind = ramchain->pkind = firsti; ramchain->externalind = 0; } int32_t iguana_ramchain_cmp(struct iguana_ramchain *A,struct iguana_ramchain *B,int32_t deepflag) { int32_t i; char str[65],str2[65]; struct iguana_txid *Ta,*Tb; struct iguana_unspent20 *Ua,*Ub; struct iguana_spend256 *Sa,*Sb; struct iguana_pkhash *Pa,*Pb; bits256 *Xa,*Xb; struct iguana_blockRO *Ba,*Bb; struct iguana_account *ACCTa,*ACCTb; struct iguana_unspent *Uxa,*Uxb; struct iguana_spend *Sxa,*Sxb; uint8_t *TXbitsa,*TXbitsb,*PKbitsa,*PKbitsb; if ( A->H.data != 0 && B->H.data != 0 && A->H.data->numblocks == B->H.data->numblocks && memcmp(A->H.data->firsthash2.bytes,B->H.data->firsthash2.bytes,sizeof(A->H.data->firsthash2)) == 0 ) { if ( A->H.data->firsti == B->H.data->firsti && A->H.data->numtxids == B->H.data->numtxids && A->H.data->numunspents == B->H.data->numunspents && A->H.data->numspends == B->H.data->numspends && A->H.data->numpkinds == B->H.data->numpkinds && A->H.data->numexternaltxids == B->H.data->numexternaltxids ) { _iguana_ramchain_setptrs(A,&Ba,&Ta,&Ua,&Sa,&Pa,&ACCTa,&Xa,&Uxa,&Sxa,&TXbitsa,&PKbitsa,A->H.data); _iguana_ramchain_setptrs(B,&Bb,&Tb,&Ub,&Sb,&Pb,&ACCTb,&Xb,&Uxb,&Sxb,&TXbitsb,&PKbitsb,B->H.data); for (i=A->H.data->firsti; iH.data->numtxids; i++) if ( memcmp(&Ta[i],&Tb[i],sizeof(Ta[i])) != 0 ) return(-2); if ( A->numblocks > 1 ) { for (i=A->H.data->firsti; iH.data->numspends; i++) if ( memcmp(&Sxa[i],&Sxb[i],sizeof(Sxa[i])) != 0 ) return(-3); for (i=A->H.data->firsti; iH.data->numunspents; i++) { if ( memcmp(&Uxa[i],&Uxb[i],sizeof(Uxa[i])) != 0 ) return(-4); //if ( memcmp(&U2a[i],&U2b[i],sizeof(U2a[i])) != 0 ) // return(-5); } for (i=A->H.data->firsti; iH.data->numpkinds; i++) { //if ( memcmp(&P2a[i],&P2b[i],sizeof(P2a[i])) != 0 ) // return(-6); if ( memcmp(&ACCTa[i],&ACCTb[i],sizeof(ACCTa[i])) != 0 ) return(-7); } for (i=0; iH.data->numexternaltxids; i++) if ( memcmp(&Xa[i],&Xb[i],sizeof(Xa[i])) != 0 ) { bits256_str(str2,Xb[i]); bits256_str(str,Xa[i]); printf("X[%d] A.%s B.%s\n",i,str,str2); return(-8); } } else { for (i=A->H.data->firsti; iH.data->numspends; i++) if ( memcmp(&Sa[i],&Sb[i],sizeof(Sa[i])) != 0 ) return(-9); for (i=A->H.data->firsti; iH.data->numunspents; i++) if ( memcmp(&Ua[i],&Ub[i],sizeof(Ua[i])) != 0 ) return(-10); } } return(0); } printf("cmp %p %p, numblocks %d:%d %d:%d %s %s\n",A->H.data,B->H.data,A->numblocks,A->H.data->numblocks,B->numblocks,B->H.data->numblocks,bits256_str(str,A->H.data->firsthash2),bits256_str(str2,B->H.data->firsthash2)); return(-1); } int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain *dest,struct iguana_ramchain *ramchain) { RAMCHAIN_DECLARE; RAMCHAIN_DESTDECLARE; int32_t j,hdrsi,prevout; uint32_t sequence,destspendind=0,desttxidind=0; bits256 prevhash; uint64_t value; uint8_t type; struct iguana_txid *tx; struct iguana_ramchaindata *rdata; uint8_t *rmd160; struct iguana_unspent *u; if ( dest != 0 ) _iguana_ramchain_setptrs(RAMCHAIN_DESTPTRS,dest->H.data); _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); if ( (rdata= ramchain->H.data) == 0 ) { printf("iguana_ramchain_iterate cant iterate without data\n"); return(-1); } ramchain->H.ROflag = 1; ramchain->H.unspentind = ramchain->H.spendind = ramchain->pkind = rdata->firsti; ramchain->externalind = 0; if ( dest != 0 ) { desttxidind = dest->H.txidind; destspendind = dest->H.spendind; } for (ramchain->H.txidind=rdata->firsti; ramchain->H.txidindnumtxids; ramchain->H.txidind++) { if ( 0 && ramchain->expanded != 0 ) printf("ITER TXID.%d -> dest.%p desttxid.%d dest->hashmem.%p\n",ramchain->H.txidind,dest,dest!=0?dest->H.txidind:0,dest!=0?dest->hashmem:0); tx = &T[ramchain->H.txidind]; if ( iguana_ramchain_addtxid(coin,RAMCHAIN_ARG,tx->txid,tx->numvouts,tx->numvins,tx->locktime,tx->version,tx->timestamp) == 0 ) return(-1); if ( dest != 0 ) { char str[65]; if ( 0 && ramchain->expanded != 0 ) printf("add hdrsi.%d dest.%p txidind.%d %s\n",dest->H.hdrsi,ramchain,dest->H.txidind,bits256_str(str,tx->txid)); if ( iguana_ramchain_addtxid(coin,RAMCHAIN_DESTARG,tx->txid,tx->numvouts,tx->numvins,tx->locktime,tx->version,tx->timestamp) == 0 ) return(-2); } for (j=0; jnumvouts; j++) { if ( 0 && ramchain->expanded != 0 ) printf("unspentind.%d pkind.%d Ux.%p\n",ramchain->H.unspentind,Ux[ramchain->H.unspentind].pkind,Ux); if ( ramchain->H.unspentind < rdata->numunspents ) { if ( ramchain->expanded != 0 ) { u = &Ux[ramchain->H.unspentind]; value = u->value; hdrsi = u->hdrsi; type = u->type; if ( u->pkind < rdata->numpkinds ) { rmd160 = P[u->pkind].rmd160; if ( iguana_ramchain_addunspent(coin,RAMCHAIN_ARG,value,hdrsi,rmd160,j,type) == 0 ) return(-3); } } else { hdrsi = rdata->hdrsi; value = U[ramchain->H.unspentind].value; rmd160 = U[ramchain->H.unspentind].rmd160; type = U[ramchain->H.unspentind].type; if ( iguana_ramchain_addunspent20(coin,RAMCHAIN_ARG,value,rmd160,-20,tx->txid,j,type) == 0 ) return(-4); } if ( dest != 0 ) { if ( iguana_ramchain_addunspent(coin,RAMCHAIN_DESTARG,value,hdrsi,rmd160,j,type) == 0 ) return(-5); } } else return(-6); } ramchain->H.spendind += tx->numvins; if ( dest != 0 ) { dest->H.txidind++; dest->H.spendind += tx->numvins; } } if ( dest != 0 ) { dest->H.txidind = desttxidind; dest->H.spendind = destspendind; } ramchain->H.txidind = ramchain->H.spendind = rdata->firsti; for (ramchain->H.txidind=rdata->firsti; ramchain->H.txidindnumtxids; ramchain->H.txidind++) { tx = &T[ramchain->H.txidind]; for (j=0; jnumvins; j++) { if ( ramchain->expanded != 0 ) { sequence = (Sx[ramchain->H.spendind].diffsequence == 0) ? 0xffffffff : 0; prevout = iguana_ramchain_txid(coin,RAMCHAIN_ARG,&prevhash,&Sx[ramchain->H.spendind]); //bundlei = Sx[ramchain->H.spendind].bundlei; //hdrsi = Sx[ramchain->H.spendind].hdrsi; if ( iguana_ramchain_addspend(coin,RAMCHAIN_ARG,prevhash,prevout,sequence) == 0 ) { char str[65]; int32_t i; printf("txidind.%d spendind.%d spendtxid.%x %d vin.%d %s vout.%d\n",ramchain->H.txidind,ramchain->H.spendind,Sx[ramchain->H.spendind].spendtxidind,Sx[ramchain->H.spendind].spendtxidind&0xfffffff,j,bits256_str(str,prevhash),prevout); for (i=0; iH.data->numexternaltxids; i++) printf("%p X[%d] %s\n",X,i,bits256_str(str,X[i])); exit(-1); iguana_ramchain_txid(coin,RAMCHAIN_ARG,&prevhash,&Sx[ramchain->H.spendind]); return(-7); } } else { //spendind = (tx->firstvin + j); sequence = (S[ramchain->H.spendind].diffsequence == 0) ? 0xffffffff : 0; prevhash = S[ramchain->H.spendind].prevhash2; prevout = S[ramchain->H.spendind].prevout; //bundlei = S[ramchain->H.spendind].bundlei; //hdrsi = S[ramchain->H.spendind].hdrsi; if ( iguana_ramchain_addspend256(coin,RAMCHAIN_ARG,prevhash,prevout,0,0,sequence) == 0 ) return(-8); } if ( dest != 0 ) { if ( iguana_ramchain_addspend(coin,RAMCHAIN_DESTARG,prevhash,prevout,sequence) == 0 ) return(-9); } } if ( dest != 0 ) dest->H.txidind++; } return(0); } long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_txblock *origtxdata,struct iguana_msgtx *txarray,int32_t txn_count,uint8_t *data,int32_t recvlen) { int32_t verifyflag = 0; RAMCHAIN_DECLARE; long fsize; void *ptr; struct iguana_ramchain R,*mapchain,*ramchain = &addr->ramchain; struct iguana_msgtx *tx; int32_t i,j,fpos,firsti=1,err,flag,bundlei = -2; char fname[1024]; struct iguana_bundle *bp = 0; struct iguana_block *block; if ( iguana_bundlefind(coin,&bp,&bundlei,origtxdata->block.RO.hash2) == 0 ) { if ( iguana_bundlefind(coin,&bp,&bundlei,origtxdata->block.RO.prev_block) == 0 ) return(-1); else if ( bundlei < coin->chain->bundlesize-1 ) bundlei++; else { printf("error finding block\n"); return(-1); } } if ( bits256_nonz(bp->hashes[bundlei]) == 0 ) bp->hashes[bundlei] = origtxdata->block.RO.hash2; if ( (block= bp->blocks[bundlei]) == 0 ) { //char str[65]; printf("%d:%d has no block ptr %s\n",bp->hdrsi,bundlei,bits256_str(str,bp->hashes[bundlei])); return(-1); } if ( block->fpipbits != 0 ) { //printf("ramchaindata have %d:%d at %d\n",bp->hdrsi,bundlei,bp->fpos[bundlei]); return(block->fpos); } //SETBIT(bp->recv,bundlei); fpos = -1; //bp->recvlens[bundlei] = recvlen; //bp->firsttxidinds[bundlei] = firsti; if ( iguana_ramchain_init(ramchain,&addr->TXDATA,&addr->HASHMEM,1,txn_count,origtxdata->numunspents,origtxdata->numspends,0,0,0,1) == 0 ) return(-1); iguana_ramchain_link(ramchain,origtxdata->block.RO.hash2,origtxdata->block.RO.hash2,bp->hdrsi,bp->bundleheight+bundlei,bundlei,1,firsti,0); _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); if ( T == 0 || U == 0 || S == 0 )// P == 0//|| X == 0 || A == 0 || U2 == 0 || P2 == 0 ) { printf("fatal error getting txdataptrs\n"); return(-1); } for (i=0; iH.txidind++) { tx = &txarray[i]; iguana_ramchain_addtxid(coin,RAMCHAIN_ARG,tx->txid,tx->tx_out,tx->tx_in,tx->lock_time,tx->version,tx->timestamp); for (j=0; jtx_out; j++) { iguana_ramchain_addunspent20(coin,RAMCHAIN_ARG,tx->vouts[j].value,tx->vouts[j].pk_script,tx->vouts[j].pk_scriptlen,tx->txid,j,0); } ramchain->H.spendind += tx->tx_in; } ramchain->H.txidind = ramchain->H.spendind = ramchain->H.data->firsti; for (i=0; iH.txidind++) { tx = &txarray[i]; for (j=0; jtx_in; j++) { //char str[65]; printf("PT vin.%d %s vout.%d\n",j,bits256_str(str,tx->vins[j].prev_hash),tx->vins[j].prev_vout); iguana_ramchain_addspend256(coin,RAMCHAIN_ARG,tx->vins[j].prev_hash,tx->vins[j].prev_vout,tx->vins[j].script,tx->vins[j].scriptlen,tx->vins[j].sequence);//,bp->hdrsi,bundlei); } } //char str[65]; printf("before height.%d num.%d:%d T.%d U.%d S.%d P.%d X.%d %s\n",ramchain->height,ramchain->numblocks,ramchain->H.data->numblocks,ramchain->H.txidind,ramchain->H.unspentind,ramchain->H.spendind,ramchain->pkind,ramchain->externalind,bits256_str(str,ramchain->H.data->firsthash2)); iguana_ramchain_setsize(ramchain,ramchain->H.data,1); flag = 0; if ( ramchain->H.txidind != ramchain->H.data->numtxids || ramchain->H.unspentind != ramchain->H.data->numunspents || ramchain->H.spendind != ramchain->H.data->numspends ) { printf("error creating PT ramchain: ramchain->txidind %d != %d ramchain->data->numtxids || ramchain->unspentind %d != %d ramchain->data->numunspents || ramchain->spendind %d != %d ramchain->data->numspends\n",ramchain->H.txidind,ramchain->H.data->numtxids,ramchain->H.unspentind,ramchain->H.data->numunspents,ramchain->H.spendind,ramchain->H.data->numspends); } else { if ( (err= iguana_ramchain_verify(coin,ramchain)) == 0 ) { if ( (fpos= (int32_t)iguana_ramchain_save(coin,RAMCHAIN_ARG,addr->ipbits,origtxdata->block.RO.hash2,origtxdata->block.RO.prev_block,bundlei,0)) >= 0 ) { //printf("set fpos.%d\n",fpos); //bp->ipbits[bundlei] = addr->ipbits; origtxdata->datalen = (int32_t)ramchain->H.data->allocsize; ramchain->H.ROflag = 0; flag = 1; memset(&R,0,sizeof(R)); if ( verifyflag != 0 && (mapchain= iguana_ramchain_map(coin,fname,0,1,&R,0,addr->ipbits,origtxdata->block.RO.hash2,origtxdata->block.RO.prev_block,bundlei,fpos,1,0)) != 0 ) { //printf("mapped Soffset.%ld\n",(long)mapchain->data->Soffset); iguana_ramchain_link(&R,origtxdata->block.RO.hash2,origtxdata->block.RO.hash2,bp->hdrsi,bp->bundleheight+bundlei,bundlei,1,firsti,1); if ( 0 ) // crashes unix { if ( (err= iguana_ramchain_cmp(ramchain,mapchain,0)) != 0 ) printf("error.%d comparing ramchains\n",err); ptr = mapchain->fileptr; fsize = mapchain->filesize; mapchain->fileptr = 0, mapchain->filesize = 0; iguana_ramchain_free(mapchain,1); memset(&R,0,sizeof(R)); R.H.data = (void *)(long)((long)ptr + fpos), R.filesize = fsize; iguana_ramchain_link(&R,origtxdata->block.RO.hash2,origtxdata->block.RO.hash2,bp->hdrsi,bp->bundleheight+bundlei,bundlei,1,firsti,1); } if ( (err= iguana_ramchain_cmp(ramchain,&R,0)) != 0 ) { fpos = -1; printf("error.%d comparing REMAP ramchains\n",err); } else { iguana_ramchain_extras(&R,0); if ( (err= iguana_ramchain_iterate(coin,0,&R)) != 0 ) printf("err.%d iterate ",err); //printf("SUCCESS REMAP\n"); bp->numtxids += ramchain->H.data->numtxids; bp->numunspents += ramchain->H.data->numunspents; bp->numspends += ramchain->H.data->numspends; } iguana_ramchain_free(&R,1); } else { bp->numtxids += ramchain->H.data->numtxids; bp->numunspents += ramchain->H.data->numunspents; bp->numspends += ramchain->H.data->numspends; } if ( fpos >= 0 ) block->fpos = fpos, block->fpipbits = addr->ipbits; } } else printf("ramchain verification error.%d hdrsi.%d bundlei.%d\n",err,bp->hdrsi,bundlei); } ramchain->H.ROflag = 0; iguana_ramchain_free(ramchain,0); return(fpos); } // two passes to check data size void iguana_ramchain_disp(struct iguana_ramchain *ramchain) { RAMCHAIN_DECLARE; int32_t j; uint32_t txidind,unspentind,spendind; struct iguana_txid *tx; char str[65]; _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); if ( ramchain->H.data != 0 ) { unspentind = spendind = ramchain->H.data->firsti; for (txidind=ramchain->H.data->firsti; txidindH.data->numtxids; txidind++) { tx = &T[txidind]; for (j=0; jnumvins; j++, spendind++) printf("%s/v%d ",bits256_str(str,S[spendind].prevhash2),S[spendind].prevout); for (j=0; jnumvouts; j++,unspentind++) { init_hexbytes_noT(str,U[unspentind].rmd160,20); printf("(%.8f %s) ",dstr(U[unspentind].value),str); } printf("txid.[%d] %s (%d:%d %d:%d)\n",txidind,bits256_str(str,tx->txid),tx->firstvout,tx->numvouts,tx->firstvin,tx->numvins); } } } int32_t iguana_bundlefiles(struct iguana_info *coin,uint32_t *ipbits,void **ptrs,long *filesizes,struct iguana_bundle *bp) { static bits256 zero; int32_t j,bundlei,num,hdrsi,checki; struct iguana_block *block; uint32_t fpipbits; char fname[1024]; for (bundlei=num=0; bundlein; bundlei++) { if ( (block= bp->blocks[bundlei]) != 0 ) fpipbits = block->fpipbits; else return(0); if ( num > 0 ) { for (j=0; jhashes[bundlei],bundlei>0?bp->hashes[bundlei-1]:zero,1)) != bundlei || bundlei < 0 || bundlei >= coin->chain->bundlesize ) { printf("B iguana_ramchain_map.(%s) illegal hdrsi.%d bundlei.%d checki.%d\n",fname,hdrsi,bundlei,checki); return(0); } if ( (ptrs[num]= OS_mapfile(fname,&filesizes[num],0)) == 0 ) { printf("error mapping bundlei.%d\n",bundlei); return(0); } //printf("%s mapped ptrs[%d] filesize.%ld bundlei.%d ipbits.%x fpos.%d\n",fname,num,(long)filesizes[num],bundlei,fpipbits,bp->fpos[bundlei]); num++; } } return(num); } void iguana_bundlemapfree(struct OS_memspace *mem,struct OS_memspace *hashmem,uint32_t *ipbits,void **ptrs,long *filesizes,int32_t num,struct iguana_ramchain *R,int32_t n) { int32_t j; for (j=0; jH.data->firsthash2, lasthash2 = ramchain->H.data->lasthash2; height = ramchain->height, firsti = ramchain->H.data->firsti, hdrsi = ramchain->H.hdrsi, numblocks = ramchain->numblocks; //printf("Apresave T.%d U.%d S.%d P.%d X.%d -> size.%ld firsti.%d\n",ramchain->H.data->numtxids,ramchain->H.data->numunspents,ramchain->H.data->numspends,ramchain->H.data->numpkinds,ramchain->H.data->numexternaltxids,(long)ramchain->H.data->allocsize,firsti); iguana_ramchain_setsize(ramchain,ramchain->H.data,bp->n); *newchain = *ramchain; //memcpy(ramchain->roU2,ramchain->U2,sizeof(*ramchain->U2) * ramchain->H.data->numunspents); //memcpy(ramchain->roP2,ramchain->P2,sizeof(*ramchain->P2) * ramchain->H.data->numpkinds); memcpy(ramchain->roA,ramchain->A,sizeof(*ramchain->A) * ramchain->H.data->numpkinds); memset(ramchain->A,0,sizeof(*ramchain->A) * ramchain->H.data->numpkinds); //printf("presave T.%d U.%d S.%d P.%d X.%d -> size.%ld firsti.%d\n",ramchain->H.data->numtxids,ramchain->H.data->numunspents,ramchain->H.data->numspends,ramchain->H.data->numpkinds,ramchain->H.data->numexternaltxids,(long)ramchain->H.data->allocsize,firsti); if ( (err= iguana_ramchain_iterate(coin,0,ramchain)) != 0 ) printf("ERROR.%d iterating presave ramchain hdrsi.%d\n",err,hdrsi); else if ( (err= iguana_ramchain_verify(coin,ramchain)) != 0 ) printf("ERROR.%d verifying presave ramchain hdrsi.%d\n",err,hdrsi); else retval = 0; printf("postiterateA T.%d U.%d S.%d P.%d X.%d -> size.%ld firsti.%d\n",ramchain->H.data->numtxids,ramchain->H.data->numunspents,ramchain->H.data->numspends,ramchain->H.data->numpkinds,ramchain->H.data->numexternaltxids,(long)ramchain->H.data->allocsize,firsti); if ( iguana_ramchain_save(coin,RAMCHAIN_ARG,0,firsthash2,zero,0,bp) < 0 ) printf("ERROR saving ramchain hdrsi.%d\n",hdrsi); else { //printf("DEST T.%d U.%d S.%d P.%d X.%d -> size.%ld Xoffset.%d\n",ramchain->H.data->numtxids,ramchain->H.data->numunspents,ramchain->H.data->numspends,ramchain->H.data->numpkinds,ramchain->H.data->numexternaltxids,(long)ramchain->H.data->allocsize,(int32_t)ramchain->H.data->Xoffset); //printf("free dest hdrs.%d retval.%d\n",bp->hdrsi,retval); memset(&checkR,0,sizeof(checkR)); bundlei = 0; if ( cmpflag == 0 ) iguana_memreset(hashmem); if ( (mapchain= iguana_ramchain_map(coin,fname,bp,numblocks,&checkR,cmpflag==0?hashmem:0,0,firsthash2,zero,bundlei,0,1,1)) != 0 ) { iguana_ramchain_link(mapchain,firsthash2,lasthash2,hdrsi,height,0,numblocks,firsti,1); iguana_ramchain_extras(mapchain,hashmem); //printf("MAP T.%d U.%d S.%d P.%d X.%d -> size.%ld Xoffset.%d\n",mapchain->H.data->numtxids,mapchain->H.data->numunspents,mapchain->H.data->numspends,mapchain->H.data->numpkinds,mapchain->H.data->numexternaltxids,(long)mapchain->H.data->allocsize,(int32_t)mapchain->H.data->Xoffset); if ( (err= iguana_ramchain_iterate(coin,0,mapchain)) != 0 ) printf("err.%d iterate mapped dest\n",err); else if ( cmpflag != 0 ) { if ( (err= iguana_ramchain_cmp(mapchain,ramchain,0)) != 0 ) printf("err.%d cmp mapchain.%d vs ramchain\n",err,height); else { printf("BUNDLE.%d iterated and compared\n",height); retval = 0; } } int32_t i; for (i=0; iH.data->lhashes[i].uints[0]); printf("%llx ht.%d\n",(long long)mapchain->H.data->sha256.txid,mapchain->height); iguana_ramchain_free(mapchain,cmpflag); } iguana_mempurge(hashmem); } return(retval); } struct iguana_ramchain *iguana_bundleload(struct iguana_info *coin,struct iguana_bundle *bp) { static bits256 zero; struct iguana_blockRO *B; struct iguana_txid *T; int32_t i,firsti = 1; char fname[512]; struct iguana_block *block; struct iguana_ramchain *mapchain; memset(&bp->ramchain,0,sizeof(bp->ramchain)); if ( (mapchain= iguana_ramchain_map(coin,fname,bp,bp->n,&bp->ramchain,0,0,bp->hashes[0],zero,0,0,0,1)) != 0 ) { iguana_ramchain_link(mapchain,bp->hashes[0],bp->ramchain.lasthash2,bp->hdrsi,bp->bundleheight,0,bp->ramchain.numblocks,firsti,1); //char str[65]; printf("bp.%d: T.%d U.%d S.%d P%d X.%d MAPPED %s %p\n",bp->hdrsi,bp->ramchain.H.data->numtxids,bp->ramchain.H.data->numunspents,bp->ramchain.H.data->numspends,bp->ramchain.H.data->numpkinds,bp->ramchain.H.data->numexternaltxids,mbstr(str,bp->ramchain.H.data->allocsize),bp->ramchain.H.data); B = (void *)(long)((long)mapchain->H.data + mapchain->H.data->Boffset); T = (void *)(long)((long)mapchain->H.data + mapchain->H.data->Toffset); for (i=0; in; i++) { if ( (block= bp->blocks[i]) != 0 || (block= iguana_blockhashset(coin,bp->bundleheight+i,bp->hashes[i],1)) != 0 ) { block->queued = 1; block->height = bp->bundleheight + i; block->hdrsi = bp->hdrsi; block->bundlei = i; block->fpipbits = (uint32_t)calc_ipbits("127.0.0.1"); if ( bp->blocks[i] == 0 ) bp->blocks[i] = block; if ( bits256_nonz(bp->hashes[i]) == 0 ) bp->hashes[i] = B[i].hash2; //_iguana_chainlink(coin,block); } } bp->emitfinish = (uint32_t)time(NULL) + 1; /*for (i=1; iH.data->numtxids; i++) {break; if ( iguana_txidfind(coin,&height,&tx,T[i].txid) == 0 ) printf("error couldnt find T[%d] %s\n",i,bits256_str(str,T[i].txid)); else if ( memcmp(&tx,&T[i],sizeof(T[i])) != 0 ) printf("compare error T[%d] %s\n",i,bits256_str(str,T[i].txid)); }*/ } if ( mapchain != 0 ) coin->newramchain++; return(mapchain); } // helper threads: NUM_HELPERS int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,struct OS_memspace *memB,struct iguana_bundle *bp,uint32_t starttime) // helper thread { static int depth; static bits256 zero; RAMCHAIN_DESTDECLARE; RAMCHAIN_DECLARE; void **ptrs,*ptr; long *filesizes,filesize; uint32_t *ipbits; char fname[1024]; struct iguana_ramchain *R,*mapchain,*dest,newchain; uint32_t fpipbits,now = (uint32_t)time(NULL); int32_t numtxids,numunspents,numspends,numpkinds,numexternaltxids,fpos; struct iguana_block *block; struct OS_memspace HASHMEM; int32_t err,j,num,hdrsi,bundlei,firsti= 1,retval = -1; B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, TXbits = 0, PKbits = 0, U = 0, S = 0, T = 0;//U2 = 0, P2 = 0, R = mycalloc('s',bp->n,sizeof(*R)); ptrs = mycalloc('w',bp->n,sizeof(*ptrs)); ipbits = mycalloc('w',bp->n,sizeof(*ipbits)); filesizes = mycalloc('f',bp->n,sizeof(*filesizes)); if ( (num= iguana_bundlefiles(coin,ipbits,ptrs,filesizes,bp)) == 0 ) { iguana_bundlemapfree(0,0,ipbits,ptrs,filesizes,bp->n,R,bp->n); return(-1); } for (bundlei=numtxids=numunspents=numspends=0; bundlein; bundlei++) { if ( (block= bp->blocks[bundlei]) != 0 ) fpipbits = block->fpipbits, fpos = block->fpos; else fpipbits = fpos = 0; mapchain = &R[bundlei]; for (j=0; jfileptr = ptr; mapchain->filesize = filesize; mapchain->H.data = (void *)(long)((long)ptr + fpos); mapchain->H.ROflag = 1; if ( fpos+mapchain->H.data->allocsize > filesize || iguana_ramchain_size(MAPCHAIN_ARG,1) != mapchain->H.data->allocsize ) { printf("iguana_bundlesaveHT ipbits.%x size mismatch %ld vs %ld vs filesize.%ld fpos.%ld bundlei.%d expanded.%d\n",fpipbits,(long)iguana_ramchain_size(MAPCHAIN_ARG,1),(long)mapchain->H.data->allocsize,(long)filesize,(long)fpos,bundlei,mapchain->expanded); //getchar(); break; } else if ( memcmp(bp->hashes[bundlei].bytes,mapchain->H.data->firsthash2.bytes,sizeof(bits256)) != 0 ) { char str[65],str2[65]; printf("iguana_bundlesaveHT hash2 mismatch %s vs %s\n",bits256_str(str,bp->hashes[bundlei]),bits256_str(str2,mapchain->H.data->firsthash2)); break; } iguana_ramchain_link(mapchain,bp->hashes[bundlei],bp->hashes[bundlei],bp->hdrsi,bp->bundleheight+bundlei,bundlei,1,firsti,1); numtxids += (mapchain->H.data->numtxids - 1); numunspents += (mapchain->H.data->numunspents - 1); numspends += (mapchain->H.data->numspends - 1); //printf("(%d %d %d) ",numtxids,numunspents,numspends); //printf("%d ",numtxids); } if ( bundlei != bp->n ) { iguana_bundlemapfree(0,0,ipbits,ptrs,filesizes,num,R,bp->n); printf("error mapping hdrsi.%d bundlei.%d\n",bp->hdrsi,bundlei); return(-1); } //printf("-> total (%d %d %d)\n",numtxids,numunspents,numspends); numpkinds = numunspents; numexternaltxids = numspends; dest = &bp->ramchain; //printf("E.%d depth.%d start bundle ramchain %d at %u started.%u lag.%d\n",coin->numemitted,depth,bp->bundleheight,now,starttime,now-starttime); depth++; if ( iguana_ramchain_alloc(coin,dest,mem,&HASHMEM,numtxids,numunspents,numspends,numpkinds,numexternaltxids,bp->bundleheight,bp->n) < 0 ) { iguana_bundlemapfree(mem,&HASHMEM,ipbits,ptrs,filesizes,num,R,bp->n); return(-1); } iguana_ramchain_link(dest,bp->hashes[0],bp->hashes[bp->n-1],bp->hdrsi,bp->bundleheight,0,bp->n,firsti,0); _iguana_ramchain_setptrs(RAMCHAIN_DESTPTRS,dest->H.data); iguana_ramchain_extras(dest,&HASHMEM); dest->H.txidind = dest->H.unspentind = dest->H.spendind = dest->pkind = dest->H.data->firsti; dest->externalind = 0; //printf("\n"); for (bundlei=0; bundlein; bundlei++) { if ( (block= bp->blocks[bundlei]) != 0 ) { iguana_blocksetcounters(coin,block,dest); coin->blocks.RO[bp->bundleheight+bundlei] = block->RO; } //printf("(%d %d) ",R[bundlei].H.data->numtxids,dest->H.txidind); if ( (err= iguana_ramchain_iterate(coin,dest,&R[bundlei])) != 0 ) { printf("error ramchain_iterate hdrs.%d bundlei.%d\n",bp->hdrsi,bundlei); break; } } depth--; if ( bundlei == bp->n && iguana_ramchain_expandedsave(coin,RAMCHAIN_DESTARG,&newchain,&HASHMEM,0,bp) == 0 ) { char str[65],str2[65]; printf("%s d.%d ht.%d %s saved lag.%d elapsed.%ld\n",bits256_str(str2,newchain.H.data->sha256),depth,dest->height,mbstr(str,dest->H.data->allocsize),now-starttime,time(NULL)-now); retval = 0; } iguana_bundlemapfree(mem,&HASHMEM,ipbits,ptrs,filesizes,num,R,bp->n); if ( retval == 0 ) { //printf("delete %d files hdrs.%d retval.%d\n",num,bp->hdrsi,retval); for (j=0; jhashes[0],zero,1) >= 0 ) coin->peers.numfiles -= OS_removefile(fname,0); else printf("error removing.(%s)\n",fname); } } iguana_ramchain_free(dest,0); bp->ramchain = newchain; if ( 0 ) { bp->ramchain.hashmem = 0; bp->ramchain.txids = 0; bp->ramchain.pkhashes = 0; bp->ramchain.fileptr = 0; bp->ramchain.filesize = 0; } else iguana_bundleload(coin,bp); return(retval); } void iguana_mergefree(struct OS_memspace *mem,struct iguana_ramchain *A,struct iguana_ramchain *B,struct OS_memspace *hashmem,struct OS_memspace *hashmemA,struct OS_memspace *hashmemB) { if ( A != 0 ) iguana_ramchain_free(A,0); if ( B != 0 ) iguana_ramchain_free(B,0); if ( mem != 0 ) iguana_mempurge(mem); if ( hashmemA != 0 ) iguana_mempurge(hashmemA); if ( hashmemB != 0 ) iguana_mempurge(hashmemB); } int32_t iguana_bundlemergeHT(struct iguana_info *coin,struct OS_memspace *mem,struct OS_memspace *memB,struct iguana_bundle *bp,struct iguana_bundle *nextbp,uint32_t starttime) { static int32_t depth; static bits256 zero; RAMCHAIN_DESTDECLARE; struct OS_memspace HASHMEM,HASHMEMA,HASHMEMB; uint32_t now = (uint32_t)time(NULL); char str[65],fnameA[1024],fnameB[1024]; struct iguana_ramchain _Achain,_Bchain,*A,*B,R,newchain,*dest = &R; int32_t err,retval = -1,firsti = 1; memset(mem,0,sizeof(*mem)); memset(&HASHMEMA,0,sizeof(HASHMEMA)); iguana_meminit(&HASHMEMA,"hashmemA",0,iguana_hashmemsize(bp->ramchain.H.txidind,bp->ramchain.H.unspentind,bp->ramchain.H.spendind,bp->ramchain.pkind,bp->ramchain.externalind) + 4096,0); memset(&HASHMEMB,0,sizeof(HASHMEMB)); iguana_meminit(&HASHMEMB,"hashmemB",0,iguana_hashmemsize(nextbp->ramchain.H.txidind,nextbp->ramchain.H.unspentind,nextbp->ramchain.H.spendind,nextbp->ramchain.pkind,nextbp->ramchain.externalind) + 4096,0); memset(&_Achain,0,sizeof(_Achain)); A = &_Achain; memset(&_Bchain,0,sizeof(_Bchain)); B = &_Bchain; if ( (A= iguana_ramchain_map(coin,fnameA,bp,bp->ramchain.numblocks,A,&HASHMEMA,0,bp->hashes[0],zero,0,0,1,1)) != 0 ) { iguana_ramchain_link(A,bp->hashes[0],bp->ramchain.lasthash2,bp->hdrsi,bp->bundleheight,0,bp->ramchain.numblocks,firsti,1); } if ( (B= iguana_ramchain_map(coin,fnameB,bp,nextbp->ramchain.numblocks,B,&HASHMEMB,0,nextbp->hashes[0],zero,0,0,1,1)) != 0 ) { iguana_ramchain_link(B,bp->hashes[0],nextbp->ramchain.lasthash2,nextbp->hdrsi,nextbp->bundleheight,0,nextbp->ramchain.numblocks,firsti,1); } if ( A == 0 || B == 0 || A->H.data == 0 || B->H.data == 0 || (A->H.data->allocsize + B->H.data->allocsize) > IGUANA_MAXRAMCHAINSIZE ) { printf("MERGE error %d[%d] %d[%d]\n",A->height,A->numblocks,B->height,B->numblocks); iguana_mergefree(mem,A,B,&HASHMEM,&HASHMEMA,&HASHMEMB); return(-1); } if ( A->H.data != 0 && B->H.data != 0 && B->height == A->height+A->numblocks ) { if ( iguana_ramchain_alloc(coin,dest,mem,&HASHMEM,(A->H.data->numtxids+B->H.data->numtxids),(A->H.data->numunspents+B->H.data->numunspents),(A->H.data->numspends+B->H.data->numspends),(A->H.data->numpkinds+B->H.data->numpkinds),(A->H.data->numexternaltxids+B->H.data->numexternaltxids),A->height,A->numblocks + B->numblocks) < 0 ) { printf("depth.%d ht.%d fsize.%s ERROR alloc lag.%d elapsed.%ld\n",depth,dest->height,mbstr(str,dest->H.data->allocsize),now-starttime,time(NULL)-now); iguana_mergefree(mem,A,B,&HASHMEM,&HASHMEMA,&HASHMEMB); return(-1); } depth++; iguana_ramchain_link(dest,A->H.data->firsthash2,B->H.data->lasthash2,A->H.hdrsi,A->height,0,A->numblocks+B->numblocks,firsti,0); _iguana_ramchain_setptrs(RAMCHAIN_DESTPTRS,dest->H.data); iguana_ramchain_extras(dest,&HASHMEM); dest->H.txidind = dest->H.unspentind = dest->H.spendind = dest->pkind = dest->H.data->firsti; dest->externalind = 0; if ( (err= iguana_ramchain_iterate(coin,dest,A)) != 0 ) printf("error.%d ramchain_iterate A.%d\n",err,A->height); else if ( (err= iguana_ramchain_iterate(coin,dest,B)) != 0 ) printf("error.%d ramchain_iterate B.%d\n",err,B->height); else if ( iguana_ramchain_expandedsave(coin,RAMCHAIN_DESTARG,&newchain,&HASHMEM,0,0) == 0 ) { printf("merging isnt setup to save the blockROs\n"); printf("depth.%d ht.%d fsize.%s MERGED %d[%d] and %d[%d] lag.%d elapsed.%ld bp.%d -> %d\n",depth,dest->height,mbstr(str,dest->H.data->allocsize),A->height,A->numblocks,B->height,B->numblocks,now-starttime,time(NULL)-now,bp->bundleheight,nextbp->bundleheight); iguana_mergefree(mem,A,B,&HASHMEM,&HASHMEMA,&HASHMEMB); bp->mergefinish = 0; nextbp->mergefinish = (uint32_t)time(NULL); bp->nextbp = nextbp->nextbp; newchain.hashmem = 0; retval = 0; nextbp->ramchain = bp->ramchain = newchain; OS_removefile(fnameA,0); OS_removefile(fnameB,0); } else { bp->mergefinish = nextbp->mergefinish = 0; iguana_mergefree(mem,A,B,&HASHMEM,&HASHMEMA,&HASHMEMB); } iguana_ramchain_free(dest,0); depth--; } else printf("error merging A.%d [%d] and B.%d [%d]\n",A->height,A->numblocks,B->height,B->numblocks); coin->merging--; return(retval); } void iguana_ramchainmerge(struct iguana_info *coin) // jl777: verify prev/next hash2 { struct iguana_bundle *bp,*nextbp,*A,*B; int64_t total = 0; int32_t n,flag = 0; if ( coin->bundlescount <= 0 || coin->merging > 0 ) return; A = B = 0; n = 0; bp = coin->bundles[0]; while ( bp != 0 && (nextbp= bp->nextbp) != 0 ) { n++; if ( nextbp != 0 && bp != 0 && bp->emitfinish > coin->startutc && nextbp->emitfinish > coin->startutc && bp->mergefinish == 0 && nextbp->mergefinish == 0 && bp->ramchain.datasize + nextbp->ramchain.datasize < IGUANA_MAXRAMCHAINSIZE ) { if ( total == 0 || (bp->ramchain.datasize + nextbp->ramchain.datasize) < total ) { total = (bp->ramchain.datasize + nextbp->ramchain.datasize); A = bp, B = nextbp; } } bp = nextbp; } if ( A != 0 && B != 0 ) { bp = A, nextbp = B; bp->mergefinish = nextbp->mergefinish = 1; flag++; char str[65]; printf("start merge %d[%d] + %d[%d] %s\n",bp->bundleheight,bp->ramchain.numblocks,nextbp->bundleheight,nextbp->ramchain.numblocks,mbstr(str,bp->ramchain.datasize + nextbp->ramchain.datasize)); coin->merging++; iguana_mergeQ(coin,bp,nextbp); } if ( flag != 0 ) { bp = coin->bundles[0]; while ( bp != 0 && (nextbp= bp->nextbp) != 0 ) { printf("%d[%d].%d ",bp->bundleheight,bp->ramchain.numblocks,bp->mergefinish); bp = nextbp; } printf("bundles.%d\n",n); } }