/****************************************************************************** * Copyright © 2014-2016 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #include "iguana777.h" #ifdef DEPRECATED_HHUTXO struct iguana_hhaccount *iguana_hhaccountfind(struct iguana_info *coin,uint64_t pval) { struct iguana_hhaccount *hhacct; HASH_FIND(hh,coin->accountstable,&pval,sizeof(pval),hhacct); return(hhacct); } int32_t iguana_utxoupdate(struct iguana_info *coin,int16_t spent_hdrsi,uint32_t spent_unspentind,uint32_t spent_pkind,uint64_t spent_value,uint32_t spendind,uint32_t fromheight,uint8_t *rmd160) { struct iguana_hhutxo *hhutxo,*tmputxo; struct iguana_hhaccount *hhacct,*tmpacct; uint64_t uval,pval; if ( spent_hdrsi < 0 ) { printf(">>>>>>>>>> RESET UTXO HASH <<<<<<<<<\n"); if ( coin->utxotable != 0 ) { HASH_ITER(hh,coin->utxotable,hhutxo,tmputxo) { hhutxo->u.lockedflag = 0; hhutxo->u.spentflag = 0; hhutxo->u.fromheight = 0; hhutxo->u.prevunspentind = 0; //free(hhutxo); } } if ( coin->accountstable != 0 ) { HASH_ITER(hh,coin->accountstable,hhacct,tmpacct) { hhacct->a.lastunspentind = 0; hhacct->a.total = 0; //free(hhacct); } } return(0); } if ( coin->disableUTXO != 0 ) { printf("skip utxoupdate when disabled\n"); return(0); } uval = ((uint64_t)spent_hdrsi << 32) | spent_unspentind; pval = ((uint64_t)spent_hdrsi << 32) | spent_pkind; if ( (hhutxo= iguana_hhutxofind(coin,uval)) != 0 ) { if ( hhutxo->u.spentflag != 0 ) { printf("hhutxo.%p spentflag.%d\n",hhutxo,hhutxo->u.spentflag); return(-1); } else if ( spendind == hhutxo->u.spendind && fromheight == hhutxo->u.fromheight ) { printf("redundant hhutxo ht.%d s%u\n",fromheight,spendind); return(0); } } hhutxo = calloc(1,sizeof(*hhutxo)); hhutxo->uval = uval; HASH_ADD_KEYPTR(hh,coin->utxotable,&hhutxo->uval,sizeof(hhutxo->uval),hhutxo); if ( (hhacct= iguana_hhaccountfind(coin,pval)) == 0 ) { hhacct = calloc(1,sizeof(*hhacct)); hhacct->pval = pval; HASH_ADD_KEYPTR(hh,coin->accountstable,&hhacct->pval,sizeof(hhacct->pval),hhacct); } //printf("create hhutxo.%p hhacct.%p from.%d\n",hhutxo,hhacct,fromheight); hhutxo->u.spentflag = 1; hhutxo->u.lockedflag = 0; hhutxo->u.fromheight = fromheight; hhutxo->u.spendind = spendind; hhutxo->u.prevunspentind = hhacct->a.lastunspentind; hhacct->a.lastunspentind = spent_unspentind; hhacct->a.total += spent_value; /*struct iguana_utxoaddr *utxoaddr; if ( (utxoaddr= iguana_utxoaddrfind(1,coin,spent_hdrsi,spent_pkind,rmd160,&coin->RTprev)) != 0 ) { utxoaddr->RTdebits += spent_value; coin->RTdebits += spent_value; //printf("from.%d [%d] u%u -= %.8f\n",fromheight,spent_hdrsi,spent_pkind,dstr(spent_value)); }*/ return(0); } #endif void iguana_hhutxo_purge(struct iguana_info *coin) { struct iguana_hhutxo *hhutxo,*tmp; HASH_ITER(hh,coin->utxotable,hhutxo,tmp) { HASH_DELETE(hh,coin->utxotable,hhutxo); free(hhutxo); } } struct iguana_hhutxo *iguana_hhutxofind(struct iguana_info *coin,uint64_t uval) { struct iguana_hhutxo *hhutxo; HASH_FIND(hh,coin->utxotable,&uval,sizeof(uval),hhutxo); return(hhutxo); } int32_t iguana_RTutxofunc(struct iguana_info *coin,int32_t *fromheightp,int32_t *lockedflagp,struct iguana_outpoint spentpt,int32_t *RTspendflagp,int32_t lockflag,int32_t fromheight) { uint64_t val; struct iguana_hhutxo *hhutxo; struct iguana_utxo utxo; struct iguana_ramchain *ramchain; struct iguana_bundle *bp; struct iguana_ramchaindata *rdata; struct iguana_RTunspent *unspent; int32_t spentflag = 0; *RTspendflagp = *lockedflagp = *fromheightp = 0; memset(&utxo,0,sizeof(utxo)); if ( coin->disableUTXO != 0 ) { printf("skip utxofind when disabled\n"); return(1); } if ( spentpt.isptr != 0 ) { if ( (unspent= spentpt.ptr) != 0 ) { if ( lockflag == 0 && fromheight == 0 ) { if ( unspent->spend != 0 ) spentflag = 1; if ( unspent->locked != 0 ) *lockedflagp = 1; *fromheightp = unspent->fromheight; } else if ( fromheight != 0 ) { unspent->fromheight = fromheight; if ( unspent->spend == 0 ) printf("unexpected null spend when fromheight.%d\n",fromheight); } else if ( lockflag != 0 ) unspent->locked = 1; } else { printf("missing spentpt ptr when isptr?\n"); return(1); } } else { if ( (bp= coin->bundles[spentpt.hdrsi]) == 0 ) return(1); ramchain = &bp->ramchain;//(bp == coin->current) ? &coin->RTramchain : &bp->ramchain; if ( (rdata= ramchain->H.data) == 0 ) return(1); val = ((uint64_t)spentpt.hdrsi << 32) | spentpt.unspentind; if ( fromheight != 0 ) utxo.fromheight = fromheight, utxo.spentflag = 1; if ( spentpt.unspentind > 0 && spentpt.unspentind < rdata->numunspents ) { if ( ramchain->Uextras != 0 ) { utxo = ramchain->Uextras[spentpt.unspentind]; if ( fromheight != 0 ) utxo.fromheight = fromheight, utxo.spentflag = 1; if ( lockflag != 0 || fromheight != 0 ) { if ( (hhutxo= iguana_hhutxofind(coin,val)) == 0 ) { hhutxo = calloc(1,sizeof(*hhutxo)); hhutxo->uval = val; hhutxo->u = utxo; HASH_ADD_KEYPTR(hh,coin->utxotable,&hhutxo->uval,sizeof(hhutxo->uval),hhutxo); } //printf("iguana_utxofind: need to change to new RT lock method\n"); } } if ( ramchain->Uextras == 0 || utxo.spentflag == 0 ) { if ( (hhutxo= iguana_hhutxofind(coin,val)) != 0 ) { utxo = hhutxo->u; if ( fromheight != 0 ) { utxo.fromheight = fromheight, utxo.spentflag = 1; hhutxo->u = utxo; } } //printf("iguana_utxofind: need to change to new RT method\n"); } } else { printf("%s illegal unspentind.%u vs %u hdrs.%d\n",coin->symbol,spentpt.unspentind,rdata->numunspents,spentpt.hdrsi); } } if ( lockflag != 0 ) { if ( utxo.lockedflag == 0 ) utxo.lockedflag = 1; else printf("iguana_hhutxofind warning: locking already locked [%d].%u\n",spentpt.hdrsi,spentpt.unspentind); } else utxo.lockedflag = 0; if ( utxo.spentflag != 0 || utxo.lockedflag != 0 ) *RTspendflagp = 1; *fromheightp = utxo.fromheight; return(utxo.spentflag); } int32_t iguana_RTspentflag(struct supernet_info *myinfo,struct iguana_info *coin,int64_t *RTspendp,int32_t *spentheightp,struct iguana_ramchain *ramchain,struct iguana_outpoint spentpt,int32_t height,int32_t minconf,int32_t maxconf,uint64_t amount) { uint32_t numunspents; int32_t RTspentflag,spentflag,lockedflag,fromheight=0; uint64_t confs;//,RTspend = 0; struct iguana_ramchaindata *rdata; struct iguana_RTunspent *unspent; *spentheightp = -1; if ( coin->disableUTXO != 0 ) { //printf("skip spentflag when disabled\n"); return(0); } if ( spentpt.isptr != 0 ) { if ( (unspent= spentpt.ptr) != 0 ) { *spentheightp = unspent->fromheight; if ( unspent->spend != 0 ) { *RTspendp += (amount == 0) ? coin->txfee : amount; return(1); } else if ( unspent->locked != 0 ) return(-1); } else printf("missing spentpt ptr when isptr?\n"); return(0); } if ( (rdata= ramchain->H.data) == 0 ) return(0); numunspents = rdata->numunspents; spentflag = iguana_RTutxofunc(coin,&fromheight,&lockedflag,spentpt,&RTspentflag,0,0); if ( spentflag != 0 && fromheight == 0 ) { if ( height == 0 ) { //printf("%s illegal unspentind.%u vs %u hdrs.%d zero fromheight.%d?\n",coin->symbol,spentpt.unspentind,numunspents,spentpt.hdrsi,fromheight); height = spentpt.hdrsi*coin->chain->bundlesize + 1; } fromheight = height; } if ( RTspentflag != 0 ) *RTspendp += (amount == 0) ? coin->txfee : amount; //printf("[%d] u%u %.8f, spentheight.%d vs height.%d spentflag.%d\n",spent_hdrsi,spent_unspentind,dstr(amount),fromheight,height,spentflag); *spentheightp = fromheight; if ( (confs= coin->blocks.hwmchain.height - fromheight) >= minconf && confs < maxconf && (height <= 0 || fromheight < height) ) { //(*RTspendp) += RTspend; if ( spentflag != 0 ) return(1); else if ( lockedflag != 0 ) return(-1); else return(0); } return(0); } int32_t iguana_volatileupdate(struct iguana_info *coin,int32_t incremental,struct iguana_ramchain *spentchain,int16_t spent_hdrsi,uint32_t spent_unspentind,uint32_t spent_pkind,uint64_t spent_value,uint32_t spendind,uint32_t fromheight) { struct iguana_ramchaindata *rdata; struct iguana_utxo *utxo; struct iguana_account *A2; // struct iguana_unspent *spentU; struct iguana_pkhash *spentP; if ( coin->disableUTXO != 0 ) { printf("skip volatileupdate when disabled\n"); return(0); } if ( (rdata= spentchain->H.data) != 0 ) { //portable_mutex_lock(&coin->RTmutex); if ( incremental == 0 ) { if ( spentchain->Uextras == 0 || spentchain->A2 == 0 ) iguana_volatilesalloc(coin,spentchain,1); if ( spentchain->Uextras != 0 && (A2= spentchain->A2) != 0 ) { utxo = &spentchain->Uextras[spent_unspentind]; if ( utxo->spentflag == 0 ) { if ( 0 && fromheight/coin->chain->bundlesize >= coin->current->hdrsi ) printf("iguana_volatileupdate.%d: [%d] spent.(u%u %.8f pkind.%d) fromht.%d [%d] spendind.%d\n",incremental,spent_hdrsi,spent_unspentind,dstr(spent_value),spent_pkind,fromheight,fromheight/coin->chain->bundlesize,spendind); utxo->prevunspentind = A2[spent_pkind].lastunspentind; utxo->spendind = spendind; utxo->spentflag = 1; utxo->fromheight = fromheight; A2[spent_pkind].total += spent_value; A2[spent_pkind].lastunspentind = spent_unspentind; //portable_mutex_unlock(&coin->RTmutex); return(0); } else { if ( spendind != utxo->spendind || fromheight != utxo->fromheight ) printf("from.%d spent_unspentind[%d] in hdrs.[%d] is spent fromht.%d %.8f\n",fromheight,spent_unspentind,spent_hdrsi,utxo->fromheight,dstr(spent_value)); else { //portable_mutex_unlock(&coin->RTmutex); return(0); } } } else printf("null ptrs.[%d] u.%u p.%u %.8f from ht.%d s.%u\n",spent_hdrsi,spent_unspentind,spent_pkind,dstr(spent_value),fromheight,spendind); } else // do the equivalent of historical, ie mark as spent, linked list, balance { //double startmillis = OS_milliseconds(); static double totalmillis; static int32_t utxon; printf("hhutxo deprecated\n"); iguana_exit(0,0); } //portable_mutex_unlock(&coin->RTmutex); printf("end iguana_volatileupdate.%d: [%d] spent.(u%u %.8f pkind.%d) double spend? at ht.%d [%d] spendind.%d (%p %p)\n",incremental,spent_hdrsi,spent_unspentind,dstr(spent_value),spent_pkind,fromheight,fromheight/coin->chain->bundlesize,spendind,spentchain->Uextras,spentchain->A2); coin->RTdatabad = 1; if ( coin->current != 0 && spent_hdrsi != coin->current->hdrsi && spent_hdrsi != fromheight/coin->chain->bundlesize ) { printf("restart iguana\n"); struct iguana_bundle *bp; portable_mutex_lock(&coin->special_mutex); if ( (bp= coin->bundles[spent_hdrsi]) != 0 ) { iguana_bundleremove(coin,spent_hdrsi,0); bp->ramchain.H.data = 0; } if ( (bp= coin->bundles[fromheight/coin->chain->bundlesize]) != 0 ) { iguana_bundleremove(coin,fromheight/coin->chain->bundlesize,0); bp->ramchain.H.data = 0; } portable_mutex_unlock(&coin->special_mutex); iguana_exit(0,0); } } else if ( coin->spendvectorsaved > 1 ) printf("volatileupdate skip null rdata [%d]\n",spentchain->height/coin->current->bundleheight); return(-1); } void iguana_volatilesalloc(struct iguana_info *coin,struct iguana_ramchain *ramchain,int32_t copyflag) { int32_t i; struct iguana_utxo *U2; struct iguana_account *A2; struct iguana_ramchaindata *rdata = 0; if ( ramchain != 0 && (rdata= ramchain->H.data) != 0 && (coin->current == 0 || coin->current->bundleheight > ramchain->height) ) { //printf("volatilesalloc.[%d] %p %p\n",ramchain->height/coin->chain->bundlesize,ramchain->debitsfileptr,ramchain->lastspendsfileptr); if ( ramchain->allocatedA2 == 0 ) { ramchain->A2 = calloc(sizeof(*ramchain->A2),rdata->numpkinds + 16); ramchain->allocatedA2 = sizeof(*ramchain->A2) * rdata->numpkinds; } if ( ramchain->allocatedU2 == 0 ) { ramchain->Uextras = calloc(sizeof(*ramchain->Uextras),rdata->numunspents + 16); ramchain->allocatedU2 = sizeof(*ramchain->Uextras) * rdata->numunspents; } if ( ramchain->debitsfileptr != 0 ) { if ( copyflag != 0 ) { A2 = (void *)((long)ramchain->debitsfileptr + sizeof(int32_t) + 2*sizeof(bits256)); if ( ramchain->debitsfilesize != sizeof(int32_t) + 2*sizeof(bits256) + sizeof(*A2)*rdata->numpkinds ) printf("A2 size mismatch %ld != %d\n",ramchain->debitsfilesize,(int32_t)(sizeof(int32_t) + 2*sizeof(bits256) + sizeof(*A2)*rdata->numpkinds)); for (i=0; inumpkinds; i++) ramchain->A2[i] = A2[i]; } munmap(ramchain->debitsfileptr,ramchain->debitsfilesize); ramchain->debitsfileptr = 0; ramchain->debitsfilesize = 0; } if ( ramchain->lastspendsfileptr != 0 ) { if ( copyflag != 0 ) { U2 = (void *)((long)ramchain->lastspendsfileptr + sizeof(int32_t) + 2*sizeof(bits256)); if ( ramchain->lastspendsfilesize != sizeof(int32_t) + 2*sizeof(bits256) + sizeof(*U2)*rdata->numunspents ) printf("U2 size mismatch %ld != %d\n",ramchain->lastspendsfilesize,(int32_t)(sizeof(int32_t) + 2*sizeof(bits256) + sizeof(*U2)*rdata->numunspents)); for (i=0; inumunspents; i++) ramchain->Uextras[i] = U2[i]; } munmap(ramchain->lastspendsfileptr,ramchain->lastspendsfilesize); ramchain->lastspendsfileptr = 0; ramchain->lastspendsfilesize = 0; } } else printf("illegal ramchain.%p rdata.%p\n",ramchain,rdata); } void iguana_volatilespurge(struct iguana_info *coin,struct iguana_ramchain *ramchain) { if ( ramchain != 0 ) { //printf("volatilespurge.[%d] (%p %p) %p %p\n",ramchain->height/coin->chain->bundlesize,ramchain->A2,ramchain->Uextras,ramchain->debitsfileptr,ramchain->lastspendsfileptr); if ( ramchain->allocatedA2 != 0 && ramchain->A2 != 0 && (long)ramchain->A2 != (long)ramchain->debitsfileptr+sizeof(bits256)*2+sizeof(int32_t) ) free(ramchain->A2); if ( ramchain->allocatedU2 != 0 && ramchain->Uextras != 0 && (long)ramchain->Uextras != (long)ramchain->lastspendsfileptr+sizeof(bits256)*2+sizeof(int32_t) ) free(ramchain->Uextras); ramchain->A2 = 0; ramchain->Uextras = 0; ramchain->allocatedA2 = ramchain->allocatedU2 = 0; if ( ramchain->debitsfileptr != 0 ) { munmap(ramchain->debitsfileptr,ramchain->debitsfilesize); ramchain->debitsfileptr = 0; ramchain->debitsfilesize = 0; } if ( ramchain->lastspendsfileptr != 0 ) { munmap(ramchain->lastspendsfileptr,ramchain->lastspendsfilesize); ramchain->lastspendsfileptr = 0; ramchain->lastspendsfilesize = 0; } } } int32_t iguana_volatilesmap(struct iguana_info *coin,struct iguana_ramchain *ramchain) { int32_t iter,numhdrsi,err = -1; char fname[1024]; bits256 balancehash,allbundles; struct iguana_ramchaindata *rdata; if ( (rdata= ramchain->H.data) == 0 ) { if ( ramchain->height > 0 ) printf("volatilesmap.[%d] no rdata\n",ramchain->height/coin->chain->bundlesize); return(-1); } if ( ramchain->debitsfileptr != 0 && ramchain->lastspendsfileptr != 0 ) { //printf("volatilesmap.[%d] already mapped %p %p\n",ramchain->height,ramchain->debitsfileptr,ramchain->lastspendsfileptr); return(0); } for (iter=0; iter<2; iter++) { sprintf(fname,"%s/%s%s/accounts/debits.%d",GLOBAL_DBDIR,iter==0?"ro/":"",coin->symbol,ramchain->height); if ( (ramchain->debitsfileptr= OS_mapfile(fname,&ramchain->debitsfilesize,0)) != 0 && ramchain->debitsfilesize == sizeof(int32_t) + 2*sizeof(bits256) + sizeof(*ramchain->A2) * rdata->numpkinds ) { ramchain->from_roA = (iter == 0); numhdrsi = *(int32_t *)ramchain->debitsfileptr; memcpy(balancehash.bytes,(void *)((long)ramchain->debitsfileptr + sizeof(numhdrsi)),sizeof(balancehash)); memcpy(allbundles.bytes,(void *)((long)ramchain->debitsfileptr + sizeof(numhdrsi) + sizeof(balancehash)),sizeof(allbundles)); if ( coin->balanceswritten == 0 ) { coin->balanceswritten = numhdrsi; coin->balancehash = balancehash; coin->allbundles = allbundles; } if ( numhdrsi >= coin->balanceswritten-1 && memcmp(balancehash.bytes,coin->balancehash.bytes,sizeof(balancehash)) == 0 && memcmp(allbundles.bytes,coin->allbundles.bytes,sizeof(allbundles)) == 0 ) { ramchain->A2 = (void *)((long)ramchain->debitsfileptr + sizeof(numhdrsi) + 2*sizeof(bits256)); sprintf(fname,"%s/%s%s/accounts/lastspends.%d",GLOBAL_DBDIR,iter==0?"ro/":"",coin->symbol,ramchain->height); if ( (ramchain->lastspendsfileptr= OS_mapfile(fname,&ramchain->lastspendsfilesize,0)) != 0 && ramchain->lastspendsfilesize == sizeof(int32_t) + 2*sizeof(bits256) + sizeof(*ramchain->Uextras) * rdata->numunspents ) { numhdrsi = *(int32_t *)ramchain->lastspendsfileptr; memcpy(balancehash.bytes,(void *)((long)ramchain->lastspendsfileptr + sizeof(numhdrsi)),sizeof(balancehash)); memcpy(allbundles.bytes,(void *)((long)ramchain->lastspendsfileptr + sizeof(numhdrsi) + sizeof(balancehash)),sizeof(allbundles)); if ( numhdrsi >= coin->balanceswritten-1 && memcmp(balancehash.bytes,coin->balancehash.bytes,sizeof(balancehash)) == 0 && memcmp(allbundles.bytes,coin->allbundles.bytes,sizeof(allbundles)) == 0 ) { ramchain->Uextras = (void *)((long)ramchain->lastspendsfileptr + sizeof(numhdrsi) + 2*sizeof(bits256)); ramchain->from_roU = (iter == 0); uint32_t unspentind,nonz=0; struct iguana_unspent *U; struct iguana_utxo *U2; if ( iter == 1 && (ramchain->height % 100000) == 0 ) { U2 = ramchain->Uextras; U = RAMCHAIN_PTR(ramchain->H.data,Uoffset); for (unspentind=1; unspentindH.data->numunspents; unspentind++) { if ( U2[unspentind].spentflag != 0 ) nonz++; //printf("[%d] u%d: (p%u %.8f) from.%d lock.%d prev.%u spent.%d\n",ramchain->height/coin->chain->bundlesize,unspentind,U[unspentind].pkind,dstr(U[unspentind].value),U2[unspentind].fromheight,U2[unspentind].lockedflag,U2[unspentind].prevunspentind,U2[unspentind].spentflag); } //printf("iter.%d nonz.%d %s volatilesmap.[%d] %p %p\n",iter,nonz,fname,ramchain->height/coin->chain->bundlesize,ramchain->debitsfileptr,ramchain->lastspendsfileptr); } err = 0; struct iguana_bundle *bp; if ( (bp= coin->bundles[ramchain->height / coin->chain->bundlesize]) != 0 ) bp->balancefinish = (uint32_t)time(NULL); } else printf("ramchain map error2 balanceswritten %d vs %d hashes %x %x\n",coin->balanceswritten,numhdrsi,coin->balancehash.uints[0],balancehash.uints[0]); } else printf("ramchain map error3 %s\n",fname); } else { static uint32_t counter; if ( counter++ < 3 ) printf("ramchain.[%d] map error balanceswritten %d vs %d hashes %x %x\n",rdata->height,coin->balanceswritten,numhdrsi,coin->balancehash.uints[0],balancehash.uints[0]); err++; OS_removefile(fname,0); } } if ( err == 0 ) return(0); } //printf("couldnt map [%d]\n",ramchain->height/coin->chain->bundlesize); iguana_volatilespurge(coin,ramchain); return(err); }