/****************************************************************************** * 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" #include "exchanges/bitcoin.h" struct iguana_pkhash *iguana_pkhashfind(struct iguana_info *coin,struct iguana_ramchain **ramchainp,int64_t *balancep,uint32_t *lastunspentindp,struct iguana_pkhash *p,uint8_t rmd160[20],int32_t firsti,int32_t endi) { uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind,i; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; struct iguana_account *ACCTS; *balancep = 0; *ramchainp = 0; *lastunspentindp = 0; for (i=firsti; ibundlescount&&i<=endi; i++) { if ( (bp= coin->bundles[i]) != 0 ) { ramchain = &bp->ramchain; if ( ramchain->H.data != 0 ) { PKbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->PKoffset); P = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Poffset); ACCTS = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Aoffset); if ( (pkind= iguana_sparseaddpk(PKbits,ramchain->H.data->pksparsebits,ramchain->H.data->numpksparse,rmd160,P,0)) > 0 && pkind < ramchain->H.data->numpkinds ) { *ramchainp = ramchain; *balancep = ACCTS[pkind].total; *lastunspentindp = ACCTS[pkind].lastind; *p = P[pkind]; return(p); } //else printf("not found pkind.%d vs num.%d\n",pkind,ramchain->H.data->numpkinds); } else printf("%s.[%d] error null ramchain->H.data\n",coin->symbol,i); } } return(0); } char *iguana_bundleaddrs(struct iguana_info *coin,int32_t hdrsi) { uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; cJSON *retjson; char rmdstr[41]; if ( (bp= coin->bundles[hdrsi]) != 0 ) { ramchain = &bp->ramchain; if ( ramchain->H.data != 0 ) { retjson = cJSON_CreateArray(); PKbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->PKoffset); P = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Poffset); for (pkind=0; pkindH.data->numpkinds; pkind++,P++) { init_hexbytes_noT(rmdstr,P->rmd160,20); jaddistr(retjson,rmdstr); } return(jprint(retjson,1)); } //iguana_bundleQ(coin,bp,bp->n); return(clonestr("{\"error\":\"no bundle data\"}")); } return(clonestr("{\"error\":\"no bundle\"}")); } struct iguana_bundle *iguana_spent(struct iguana_info *coin,bits256 *prevhashp,uint32_t *unspentindp,struct iguana_ramchain *ramchain,int32_t spend_hdrsi,struct iguana_spend *s) { int32_t prev_vout,height,hdrsi; uint32_t sequenceid,unspentind; char str[65]; struct iguana_bundle *spentbp=0; struct iguana_txid *T,TX,*tp; bits256 *X; bits256 prev_hash; X = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Xoffset); T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); sequenceid = s->sequenceid; hdrsi = spend_hdrsi; *unspentindp = 0; memset(prevhashp,0,sizeof(*prevhashp)); if ( s->prevout < 0 ) { //printf("n.%d coinbase at spendind.%d firstvin.%d -> firstvout.%d -> unspentind\n",m,spendind,nextT->firstvin,nextT->firstvout); //nextT++; //m++; return(0); } else { prev_vout = s->prevout; iguana_ramchain_spendtxid(coin,&unspentind,&prev_hash,T,ramchain->H.data->numtxids,X,ramchain->H.data->numexternaltxids,s); *prevhashp = prev_hash; *unspentindp = unspentind; if ( unspentind == 0 ) { if ( (tp= iguana_txidfind(coin,&height,&TX,prev_hash,spend_hdrsi-1)) != 0 ) { *unspentindp = unspentind = TX.firstvout + ((prev_vout > 0) ? prev_vout : 0); hdrsi = height / coin->chain->bundlesize; //printf("%s height.%d firstvout.%d prev.%d ->U%d\n",bits256_str(str,prev_hash),height,TX.firstvout,prev_vout,unspentind); } else { printf("cant find prev_hash.(%s) for bp.[%d]\n",bits256_str(str,prev_hash),spend_hdrsi); } } } if ( hdrsi > spend_hdrsi || (spentbp= coin->bundles[hdrsi]) == 0 ) printf("illegal hdrsi.%d when [%d] spentbp.%p\n",hdrsi,spend_hdrsi,spentbp);//, getchar(); //else if ( spentbp->ramchain.spents[unspentind].ind != 0 || hdrsi < 0 ) // printf("DOUBLE SPEND? U%d %p bp.[%d] unspentind.%u already has %u, no room\n",unspentind,&spentbp->ramchain.spents[unspentind],hdrsi,unspentind,spentbp->ramchain.spents[unspentind].ind);//, getchar(); else if ( unspentind == 0 || unspentind >= spentbp->ramchain.H.data->numunspents ) printf("illegal unspentind.%d vs max.%d spentbp.%p[%d]\n",unspentind,spentbp->ramchain.H.data->numunspents,spentbp,hdrsi);//, getchar(); else return(spentbp); return(0); } cJSON *iguana_unspentjson(struct iguana_info *coin,int32_t hdrsi,uint32_t unspentind,struct iguana_txid *T,struct iguana_unspent *up,uint8_t rmd160[20],char *coinaddr,uint8_t *pubkey33) { /*{ "txid" : "d54994ece1d11b19785c7248868696250ab195605b469632b7bd68130e880c9a", "vout" : 1, "address" : "mgnucj8nYqdrPFh2JfZSB1NmUThUGnmsqe", "account" : "test label", "scriptPubKey" : "76a9140dfc8bafc8419853b34d5e072ad37d1a5159f58488ac", "amount" : 0.00010000, "confirmations" : 6210, "spendable" : true },*/ //struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; uint16_t hdrsi:12,type:4,vout; } __attribute__((packed)); struct iguana_waccount *wacct; struct iguana_txid TX; int32_t height,ind; char scriptstr[8192],asmstr[sizeof(scriptstr)+1024]; cJSON *item; item = cJSON_CreateObject(); jaddbits256(item,"txid",T[up->txidind].txid); jaddnum(item,"vout",up->vout); jaddstr(item,"address",coinaddr); if ( (wacct= iguana_waddressfind(coin,&ind,coinaddr)) != 0 ) jaddstr(item,"account",wacct->account); if ( iguana_scriptget(coin,scriptstr,asmstr,sizeof(scriptstr),hdrsi,unspentind,T[up->txidind].txid,up->vout,rmd160,up->type,pubkey33) != 0 ) jaddstr(item,"scriptPubKey",scriptstr); jaddnum(item,"amount",dstr(up->value)); if ( iguana_txidfind(coin,&height,&TX,T[up->txidind].txid,coin->bundlescount-1) != 0 ) jaddnum(item,"confirmations",coin->longestchain - height); return(item); } int64_t iguana_pkhashbalance(struct iguana_info *coin,cJSON *array,int64_t *spentp,int32_t *nump,struct iguana_ramchain *ramchain,struct iguana_pkhash *p,uint32_t lastunspentind,uint8_t rmd160[20],char *coinaddr,uint8_t *pubkey33,int32_t hdrsi) { struct iguana_unspent *U; uint32_t unspentind; int64_t balance = 0; struct iguana_txid *T; *spentp = *nump = 0; if ( ramchain->Uextras == 0 ) { printf("iguana_pkhashbalance: unexpected null spents\n"); return(0); } unspentind = lastunspentind; U = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Uoffset); T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); while ( unspentind > 0 ) { (*nump)++; printf("%s u.%d %.8f\n",jprint(iguana_unspentjson(coin,hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33),1),unspentind,dstr(U[unspentind].value)); if ( ramchain->Uextras[unspentind].spentflag == 0 ) { balance += U[unspentind].value; if ( array != 0 ) jaddi(array,iguana_unspentjson(coin,hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33)); } else (*spentp) += U[unspentind].value; unspentind = U[unspentind].prevunspentind; } return(balance); } int32_t iguana_pkhasharray(struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,int64_t *totalp,struct iguana_pkhash *P,int32_t max,uint8_t rmd160[20],char *coinaddr,uint8_t *pubkey33) { int32_t i,n,m; int64_t spent,balance,netbalance,total; uint32_t lastunspentind; struct iguana_ramchain *ramchain; for (total=i=n=0; ibundlescount; i++) { if ( iguana_pkhashfind(coin,&ramchain,&balance,&lastunspentind,&P[n],rmd160,i,i) != 0 ) { if ( (netbalance= iguana_pkhashbalance(coin,array,&spent,&m,ramchain,&P[n],lastunspentind,rmd160,coinaddr,pubkey33,i)) != balance-spent ) { printf("pkhash balance mismatch from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",m,dstr(netbalance),dstr(balance),dstr(spent),dstr(balance)-dstr(spent)); } else { //P[n].firstunspentind = lastunspentind; total += netbalance; n++; } } //printf("%d: balance %.8f, lastunspent.%u\n",i,dstr(balance),lastunspentind); } //printf("n.%d max.%d\n",n,max); *totalp = total; return(n); } void iguana_unspents(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,uint8_t *rmdarray,int32_t numrmds) { int64_t total,sum=0; struct iguana_pkhash *P; uint8_t *addrtypes,*pubkeys; int32_t i,flag = 0; char coinaddr[64]; if ( rmdarray == 0 ) rmdarray = iguana_walletrmds(myinfo,coin,&numrmds), flag++; addrtypes = &rmdarray[numrmds * 20], pubkeys = &rmdarray[numrmds * 21]; P = calloc(coin->bundlescount,sizeof(*P)); for (i=0; ibundlescount,&rmdarray[i * 20],coinaddr,&pubkeys[33*i]); printf("%s %.8f\n",coinaddr,dstr(total)); sum += total; } printf("sum %.8f\n",dstr(sum)); free(P); if ( flag != 0 ) free(rmdarray); } uint8_t *iguana_rmdarray(struct iguana_info *coin,int32_t *numrmdsp,cJSON *array,int32_t firsti) { int32_t i,n,j=0; char *coinaddr; uint8_t *addrtypes,*rmdarray = 0; *numrmdsp = 0; if ( array != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { *numrmdsp = n - firsti; rmdarray = calloc(1,(n-firsti) * 21); addrtypes = &rmdarray[(n-firsti) * 20]; for (i=firsti; iramchain; //printf("UTXO gen.%d ramchain data.%p\n",bp->bundleheight,ramchain->H.data); if ( ramchain->H.data == 0 || (n= ramchain->H.data->numspends) < 1 ) return(0); S = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Soffset); nextT = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); numtxid = 1; if ( ramchain->Xspendinds != 0 ) { //printf("iguana_utxogen: already have Xspendinds[%d]\n",ramchain->numXspends); return(0); } ptr = mycalloc('x',sizeof(*ptr),n); total += n; height = bp->bundleheight; //printf("start UTXOGEN.%d max.%d ptr.%p\n",bp->bundleheight,n,ptr); for (spendind=ramchain->H.data->firsti; spendindbundleheight + numtxid; //printf("height.%d firstvin.%d\n",height,nextT[numtxid].firstvin); numtxid++; } u = 0; if ( s->external != 0 && s->prevout >= 0 ) { if ( (spentbp= iguana_spent(coin,&prevhash,&unspentind,ramchain,bp->hdrsi,s)) != 0 ) { if ( (ptr[emit].ind= unspentind) != 0 && spentbp->hdrsi < bp->hdrsi ) { ptr[emit].hdrsi = spentbp->hdrsi; ptr[emit].height = height; //printf("(%d u%d).%d ",spentbp->hdrsi,unspentind,emit); emit++; } else { printf("utxogen: null unspentind for spendind.%d hdrsi.%d [%d]\n",spendind,spentbp->hdrsi,bp->hdrsi); errs++; } if ( spentbp == bp ) { char str[65]; printf("unexpected spendbp: height.%d bp.[%d] U%d <- S%d.[%d] [ext.%d %s prev.%d]\n",height,spentbp->hdrsi,unspentind,spendind,bp->hdrsi,s->external,bits256_str(str,prevhash),s->prevout); errs++; } } else { errs++; printf("utxogen: unresolved spendind.%d hdrsi.%d\n",spendind,bp->hdrsi); } } } if ( numtxid != bp->ramchain.H.data->numtxids ) { printf("numtxid.%d != bp %d\n",numtxid,bp->ramchain.H.data->numtxids); errs++; } if ( errs == 0 && emit >= 0 ) { emitted += emit; memset(zero.bytes,0,sizeof(zero)); sprintf(dirname,"DB/%s/spends",coin->symbol); vcalc_sha256(0,sha256.bytes,(void *)ptr,(int32_t)(sizeof(*ptr) * emit)); if ( iguana_peerfname(coin,&hdrsi,dirname,fname,0,bp->hashes[0],zero,bp->n) >= 0 ) { if ( (fp= fopen(fname,"wb")) != 0 ) { if ( fwrite(sha256.bytes,1,sizeof(sha256),fp) != sizeof(sha256) ) printf("error writing hash for %ld -> (%s)\n",sizeof(*ptr) * emit,fname); else if ( fwrite(ptr,sizeof(*ptr),emit,fp) != emit ) printf("error writing %d of %d -> (%s)\n",emit,n,fname); else retval = 0; fsize = ftell(fp); fclose(fp); if ( iguana_Xspendmap(coin,ramchain,bp) < 0 ) { printf("error mapping Xspendmap.(%s)\n",fname); retval = -1; } //int32_t i; for (i=0; inumXspends; i++) // printf("(%d u%d) ",ramchain->Xspendinds[i].hdrsi,ramchain->Xspendinds[i].ind); //printf("filesize %ld Xspendptr.%p %p num.%d\n",fsize,ramchain->Xspendptr,ramchain->Xspendinds,ramchain->numXspends); } else printf("Error creating.(%s)\n",fname); } else printf("error getting utxo fname\n"); } if ( ptr != 0 ) myfree(ptr,sizeof(*ptr) * n); printf("utxo %d spendinds.[%d] errs.%d [%.2f%%] emitted.%d %s of %d | ",spendind,bp->hdrsi,errs,100.*(double)emitted/(total+1),emit,mbstr(str,sizeof(*ptr) * emit),n); return(-errs); } int32_t iguana_balancegen(struct iguana_info *coin,struct iguana_bundle *bp) { int32_t spendind,n,errs=0,emit=0; uint32_t unspentind,pkind,txidind; struct iguana_account *A2; struct iguana_unspent *u,*spentU; struct iguana_spend *S,*s; struct iguana_ramchain *ramchain; struct iguana_bundle *spentbp; struct iguana_txid *T,*nextT; int32_t hdrsi; uint32_t numtxid,now,h,refheight; struct iguana_utxo *utxo; ramchain = &bp->ramchain; //printf("BALANCEGEN.%d\n",bp->bundleheight); if ( ramchain->H.data == 0 || (n= ramchain->H.data->numspends) < 1 ) return(0); S = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Soffset); nextT = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); numtxid = 1; refheight = bp->bundleheight; if ( ramchain->Xspendinds == 0 ) { printf("iguana_balancegen.%d: no Xspendinds[%d]\n",bp->hdrsi,ramchain->numXspends); return(0); } for (spendind=ramchain->H.data->firsti; spendindbundleheight + numtxid; //printf("height.%d firstvin.%d\n",height,nextT[numtxid].firstvin); numtxid++; } s = &S[spendind]; u = 0; unspentind = 0; hdrsi = -1; spentbp = 0; if ( s->external != 0 && s->prevout >= 0 ) { if ( emit >= ramchain->numXspends ) errs++; else { h = ramchain->Xspendinds[emit].height; unspentind = ramchain->Xspendinds[emit].ind; if ( (hdrsi= ramchain->Xspendinds[emit].hdrsi) >= 0 && hdrsi <= bp->hdrsi ) spentbp = coin->bundles[hdrsi]; else { printf("iguana_balancegen[%d] s.%d illegal hdrsi.%d emit.%d\n",bp->hdrsi,spendind,hdrsi,emit); errs++; } //printf("%d of %d: [%d] X spendind.%d -> (%d u%d)\n",emit,ramchain->numXspends,bp->hdrsi,spendind,hdrsi,unspentind); emit++; } } else if ( s->prevout >= 0 ) { spentbp = bp; hdrsi = bp->hdrsi; h = refheight; if ( (txidind= s->spendtxidind) != 0 && txidind < spentbp->ramchain.H.data->numtxids ) { T = (void *)(long)((long)spentbp->ramchain.H.data + spentbp->ramchain.H.data->Toffset); unspentind = T[txidind].firstvout + s->prevout; if ( unspentind == 0 || unspentind >= spentbp->ramchain.H.data->numunspents ) { printf("iguana_balancegen unspentind overflow %u vs %u\n",unspentind,spentbp->ramchain.H.data->numunspents); errs++; } //printf("txidind.%d 1st.%d prevout.%d\n",txidind,T[txidind].firstvout,s->prevout); } else { printf("iguana_balancegen txidind overflow %u vs %u\n",txidind,spentbp->ramchain.H.data->numtxids); errs++; } //printf("[%d] spendind.%d -> (hdrsi.%d u%d)\n",bp->hdrsi,spendind,hdrsi,unspentind); } else continue; now = (uint32_t)time(NULL); if ( spentbp != 0 && unspentind > 0 && unspentind < spentbp->ramchain.H.data->numunspents ) { if ( spentbp->ramchain.Uextras == 0 ) { spentbp->ramchain.Uextras = calloc(sizeof(*spentbp->ramchain.Uextras),spentbp->ramchain.H.data->numunspents + 16); } if ( spentbp->ramchain.A == 0 ) { spentbp->ramchain.A = calloc(sizeof(*spentbp->ramchain.A),spentbp->ramchain.H.data->numpkinds + 16); } if ( spentbp->ramchain.Uextras == 0 || (A2= spentbp->ramchain.A) == 0 ) { printf("null ptrs %p %p\n",spentbp->ramchain.Uextras,spentbp->ramchain.A); errs++; } else { spentU = (void *)(long)((long)spentbp->ramchain.H.data + spentbp->ramchain.H.data->Uoffset); u = &spentU[unspentind]; if ( (pkind= u->pkind) != 0 && pkind < spentbp->ramchain.H.data->numpkinds ) { utxo = &spentbp->ramchain.Uextras[unspentind]; if ( utxo->spentflag == 0 ) { utxo->prevspendind = A2[pkind].lastind; utxo->spentflag = 1; utxo->height = h; A2[pkind].total += u->value; A2[pkind].lastind = spendind; spentbp->dirty = now; } else { errs++; printf("iguana_balancegen: pkind.%d double spend of hdrsi.%d unspentind.%d prev.%u spentflag.%d height.%d\n",pkind,spentbp->hdrsi,unspentind,utxo->prevspendind,utxo->spentflag,utxo->height); getchar(); } } else { errs++; printf("iguana_balancegen: pkind overflow %d vs %d\n",pkind,spentbp->ramchain.H.data->numpkinds); } } } else { errs++; printf("iguana_balancegen: error with unspentind.%d vs max.%d spentbp.%p\n",unspentind,spentbp!=0?spentbp->ramchain.H.data->numunspents:-1,spentbp); } } if ( numtxid != bp->ramchain.H.data->numtxids ) { printf("iguana_balancegen: numtxid.%d != bp %d\n",numtxid,bp->ramchain.H.data->numtxids); errs++; } if ( emit != ramchain->numXspends ) { printf("iguana_balancegen: emit %d != %d ramchain->numXspends\n",emit,ramchain->numXspends); errs++; } printf(">>>>>>>> balances.%d done errs.%d spendind.%d\n",bp->hdrsi,errs,n); if ( errs == 0 ) bp->validated = (uint32_t)time(NULL); return(-errs); } int32_t iguana_bundlevalidate(struct iguana_info *coin,struct iguana_bundle *bp) { bp->validated = (uint32_t)time(NULL); printf("VALIDATE.%d %u\n",bp->bundleheight,bp->validated); return(0); }