From 222be34db39d7e7230c66ee3864a490269faae47 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 9 Feb 2017 21:52:05 +0200 Subject: [PATCH] kmd_lookup --- basilisk/basilisk.c | 1 + basilisk/basilisk_bitcoin.c | 60 ++--- iguana/dPoW.h | 4 + iguana/iguana_init.c | 1 + iguana/iguana_notary.c | 21 +- iguana/kmd_lookup.h | 426 ++++++++++++++++++++++++++++++++++ includes/iguana_apideclares.h | 2 + includes/iguana_structs.h | 1 + 8 files changed, 476 insertions(+), 40 deletions(-) create mode 100755 iguana/kmd_lookup.h diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 18126ece7..0eaeb4998 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -908,6 +908,7 @@ void basilisks_loop(void *arg) } endmilli = startmilli + 30; } + kmd_bitcoinscan(); } else { diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index 321ba0c50..ee9ae2fb6 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -22,36 +22,6 @@ };*/ #ifdef bitcoincancalculatebalances -int64_t bitcoin_value(struct iguana_info *coin,bits256 txid,int16_t vout,char *coinaddr) -{ - char params[512],str[65]; char *curlstr; cJSON *txobj,*vouts,*item,*sobj,*addrs; int32_t j,m,n; int64_t value = 0; - sprintf(params,"[\"%s\", 1]",bits256_str(str,txid)); - if ( (curlstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"getrawtransaction",params)) != 0 ) - { - if ( (txobj= cJSON_Parse(curlstr)) != 0 ) - { - if ( (vouts= jarray(&n,txobj,"vout")) != 0 && vout < n ) - { - item = jitem(vouts,vout); - if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (addrs= jarray(&m,sobj,"addresses")) != 0 ) - { - for (j=0; jsymbol,coin->chain->serverport,coin->chain->userpass,"getrawtransaction",params)) != 0 ) + { + if ( (txobj= cJSON_Parse(curlstr)) != 0 ) + { + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && vout < n ) + { + item = jitem(vouts,vout); + if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (addrs= jarray(&m,sobj,"addresses")) != 0 ) + { + for (j=0; jsymbol), OS_portable_path(dirname); portable_mutex_init(&coin->RTmutex); + portable_mutex_init(&coin->kmdmutex); portable_mutex_init(&coin->peers_mutex); portable_mutex_init(&coin->blocks_mutex); portable_mutex_init(&coin->special_mutex); diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 85e495c6f..b3689e49d 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -657,16 +657,6 @@ TWO_STRINGS(dex,validateaddress,symbol,address) return(_dex_validateaddress(myinfo,symbol,address)); } -TWO_STRINGS(dex,listunspent,symbol,address) -{ - return(_dex_listunspent(myinfo,symbol,address)); -} - -TWO_STRINGS_AND_TWO_DOUBLES(dex,listtransactions,symbol,address,count,skip) -{ - return(_dex_listtransactions(myinfo,symbol,address,count,skip)); -} - STRING_ARG(dex,getnotaries,symbol) { return(_dex_getnotaries(myinfo,symbol)); @@ -698,6 +688,17 @@ THREE_STRINGS_AND_THREE_INTS(dex,kvupdate,symbol,key,value,flags,unused,unusedb) } else return(clonestr("{\"error\":\"free updates only on KV chain\"}")); } +#include "kmd_lookup.h" + +TWO_STRINGS(dex,listunspent,symbol,address) +{ + return(_dex_listunspent(myinfo,symbol,address)); +} + +TWO_STRINGS_AND_TWO_DOUBLES(dex,listtransactions,symbol,address,count,skip) +{ + return(_dex_listtransactions(myinfo,symbol,address,count,skip)); +} #include "../includes/iguana_apiundefs.h" diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h new file mode 100755 index 000000000..f553b0b2b --- /dev/null +++ b/iguana/kmd_lookup.h @@ -0,0 +1,426 @@ +/****************************************************************************** + * Copyright © 2014-2017 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. * + * * + ******************************************************************************/ + +#ifndef INCLUDE_KMDLOOKUP_H +#define INCLUDE_KMDLOOKUP_H + +struct kmd_voutinfo +{ + bits256 spendtxid; + uint64_t amount; + uint16_t spendvini; + uint8_t type_rmd160[21], pad; +} PACKED; + +struct kmd_transaction +{ + bits256 txid; int32_t height,numvouts; uint32_t timestamp,pad; + struct kmd_voutinfo vouts[]; +}; + +struct kmd_transactionhh +{ + UT_hash_handle hh; + struct kmd_transaction *tx; + int32_t numvouts; + struct kmd_transactionhh *ptrs[]; +}; + +struct kmd_addresshh +{ + UT_hash_handle hh; + uint8_t type_rmd160[21], pad; + struct kmd_transactionhh *prev,*lastprev; +}; + +struct kmd_addresshh *_kmd_address(struct iguana_info *coin,uint8_t type_rmd160[21]) +{ + struct kmd_addresshh *addr; + portable_mutex_lock(&coin->kmdmutex); + HASH_FIND(hh,coin->kmd_addresses,type_rmd160,21,addr); + portable_mutex_unlock(&coin->kmdmutex); + return(addr); +} + +struct kmd_addresshh *_kmd_addressadd(struct iguana_info *coin,uint8_t type_rmd160[21]) +{ + struct kmd_addresshh *addr; + addr = calloc(1,sizeof(*addr)); + memcpy(addr->type_rmd160,type_rmd160,21); + portable_mutex_lock(&coin->kmdmutex); + { + char coinaddr[64]; + bitcoin_address(coinaddr,type_rmd160[0],&type_rmd160[1],20); + printf("%s NEW ADDRESS.(%s)\n",coin->symbol,coinaddr); + } + HASH_ADD_KEYPTR(hh,coin->kmd_addresses,addr->type_rmd160,21,addr); + portable_mutex_unlock(&coin->kmdmutex); + return(addr); +} + +struct kmd_addresshh *kmd_address(struct iguana_info *coin,char *coinaddr) +{ + uint8_t type_rmd160[21]; + bitcoin_addr2rmd160(&type_rmd160[0],&type_rmd160[1],coinaddr); + return(_kmd_address(coin,type_rmd160)); +} + +struct kmd_transactionhh *kmd_transaction(struct iguana_info *coin,bits256 txid) +{ + struct kmd_transactionhh *tx; + portable_mutex_lock(&coin->kmdmutex); + HASH_FIND(hh,coin->kmd_transactions,txid.bytes,sizeof(txid),tx); + portable_mutex_unlock(&coin->kmdmutex); + return(tx); +} + +int32_t kmd_transactionvin(struct iguana_info *coin,bits256 spendtxid,int32_t vini,bits256 txid,int32_t vout) +{ + struct kmd_transactionhh *ptr,*spendptr; + if ( (ptr= kmd_transaction(coin,txid)) != 0 && vout < ptr->numvouts && (spendptr= kmd_transaction(coin,spendtxid)) != 0 ) + { + ptr->ptrs[(vout<<1) + 1] = spendptr; + ptr->tx->vouts[vout].spendtxid = spendtxid; + ptr->tx->vouts[vout].spendvini = vini; + return(0); + } + return(-1); +} + +void kmd_transactionvout(struct iguana_info *coin,struct kmd_transactionhh *ptr,int32_t vout,uint64_t amount,uint8_t type_rmd160[21],bits256 spendtxid,int32_t spendvini) +{ + struct kmd_addresshh *addr; struct kmd_transaction *tx = 0; + if ( vout < ptr->numvouts && (tx= ptr->tx) != 0 ) + { + tx->vouts[vout].spendtxid = spendtxid; + tx->vouts[vout].spendvini = spendvini; + tx->vouts[vout].amount = amount; + memcpy(tx->vouts[vout].type_rmd160,type_rmd160,21); + if ( coin->kmd_didinit != 0 && coin->kmd_txidfp != 0 ) + fwrite(tx,1,sizeof(*tx) + tx->numvouts*sizeof(*tx->vouts),coin->kmd_txidfp); + if ( (addr= _kmd_address(coin,type_rmd160)) == 0 ) + addr = _kmd_addressadd(coin,type_rmd160); + if ( addr != 0 ) + { + if ( addr->prev != ptr ) + { + ptr->ptrs[vout << 1] = addr->prev; + addr->lastprev = addr->prev; + addr->prev = ptr; + } + else + { + printf("tricky case same address in different vouts, make sure backlink is right\n"); + ptr->ptrs[vout<<1] = addr->lastprev; + } + } else printf("kmd_transactionvout unexpected null addr\n"); + } else printf("vout.%d wont fit into numvouts.[%d] or null tx.%p\n",vout,ptr->numvouts,tx); +} + +struct kmd_transactionhh *kmd_transactionadd(struct iguana_info *coin,struct kmd_transaction *tx,int32_t numvouts) +{ + struct kmd_transactionhh *ptr; char str[65]; + if ( (ptr= kmd_transaction(coin,tx->txid)) == 0 ) + { + ptr = calloc(1,sizeof(*ptr) + (sizeof(*ptr->ptrs)*numvouts*2)); + ptr->numvouts = numvouts; + ptr->tx = tx; + portable_mutex_lock(&coin->kmdmutex); + char str[65]; printf("%s ht.%d u.%u NEW TXID.(%s) vouts.[%d]\n",coin->symbol,tx->height,tx->timestamp,bits256_str(str,tx->txid),numvouts); + HASH_ADD_KEYPTR(hh,coin->kmd_transactions,tx->txid.bytes,sizeof(tx->txid),ptr); + portable_mutex_unlock(&coin->kmdmutex); + } else printf("warning adding already existing txid %s\n",bits256_str(str,tx->txid)); + return(ptr); +} + +struct kmd_transaction *kmd_transactionalloc(bits256 txid,int32_t height,uint32_t timestamp,int32_t numvouts) +{ + struct kmd_transaction *tx; + tx = calloc(1,sizeof(*tx) + sizeof(struct kmd_voutinfo)*numvouts); + tx->numvouts = numvouts; + tx->txid = txid; + tx->height = height; + tx->timestamp = timestamp; + return(tx); +} + +void kmd_flushfiles(struct iguana_info *coin) +{ + if ( coin->kmd_txidfp != 0 ) + fflush(coin->kmd_txidfp); +} + +FILE *kmd_txidinit(struct iguana_info *coin) +{ + int32_t i; FILE *fp; char fname[1024]; struct kmd_transactionhh *ptr; struct kmd_transaction T,*tx; struct kmd_voutinfo V; long lastpos=0; + sprintf(fname,"%s/%s/TRANSACTIONS",GLOBAL_DBDIR,coin->symbol); + if ( (fp= fopen(fname,"rb+")) != 0 ) + { + while ( fread(&T,1,sizeof(T),fp) == sizeof(T) ) + { + if ( (tx= kmd_transactionalloc(T.txid,T.height,T.timestamp,T.numvouts)) != 0 ) + { + if ( (ptr= kmd_transactionadd(coin,tx,T.numvouts)) != 0 ) + { + for (i=0; i coin->kmd_height ) + coin->kmd_height = T.height; + } + else break; + } + } else break; + } + fseek(fp,lastpos,SEEK_SET); + } else fp = fopen(fname,"wb"); + return(fp); +} + +cJSON *kmd_transactionjson(struct kmd_transactionhh *ptr,char *typestr) +{ + int32_t i; char coinaddr[64]; cJSON *item,*array,*obj = cJSON_CreateObject(); + array = cJSON_CreateArray(); + jaddstr(obj,"type",typestr); + jaddbits256(obj,"txid",ptr->tx->txid); + jaddnum(obj,"height",ptr->tx->height); + jaddnum(obj,"timestamp",ptr->tx->timestamp); + for (i=0; inumvouts; i++) + { + item = cJSON_CreateObject(); + bitcoin_address(coinaddr,ptr->tx->vouts[i].type_rmd160[0],&ptr->tx->vouts[i].type_rmd160[1],20); + jaddnum(item,coinaddr,dstr(ptr->tx->vouts[i].amount)); + jaddi(array,item); + } + jadd(obj,"vouts",array); + return(obj); +} + +cJSON *kmd_unspentjson(struct kmd_transaction *tx,int32_t vout) +{ + cJSON *item = cJSON_CreateObject(); + jaddbits256(item,"txid",tx->txid); + jaddnum(item,"vout",vout); + jaddnum(item,"amount",dstr(tx->vouts[vout].amount)); + return(item); +} + +int32_t kmd_height(struct iguana_info *coin) +{ + char params[64],*curlstr; cJSON *curljson; int32_t height = 0; + strcpy(params,"[]"); + if ( (curlstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"getinfo",params)) != 0 ) + { + if ( (curljson= cJSON_Parse(curlstr)) != 0 ) + { + height = juint(curljson,"blocks"); + free_json(curljson); + } + free(curlstr); + } + return(height); +} + +cJSON *kmd_listtransactions(struct iguana_info *coin,char *coinaddr) +{ + struct kmd_addresshh *addr; struct kmd_transactionhh *ptr,*spent; uint8_t type_rmd160[21]; int32_t i,height; cJSON *array = cJSON_CreateArray(); + if ( (height= kmd_height(coin)) > coin->kmd_height+3 ) + return(cJSON_Parse("[]")); + bitcoin_addr2rmd160(&type_rmd160[0],&type_rmd160[1],coinaddr); + if ( (addr= _kmd_address(coin,type_rmd160)) != 0 && (ptr= addr->prev) != 0 && ptr->tx != 0 ) + { + jaddi(array,kmd_transactionjson(ptr,"received")); + for (i=0; inumvouts; i++) + { + if ( memcmp(ptr->tx->vouts[i].type_rmd160,type_rmd160,21) == 0 && (spent= ptr->ptrs[(i<<1)+1]) != 0 ) + jaddi(array,kmd_transactionjson(spent,"sent")); + } + } + return(array); +} + +cJSON *kmd_listunspent(struct iguana_info *coin,char *coinaddr) +{ + struct kmd_addresshh *addr; struct kmd_transactionhh *ptr,*spent; uint8_t type_rmd160[21]; int32_t i,height; cJSON *array = cJSON_CreateArray(); + if ( (height= kmd_height(coin)) > coin->kmd_height+3 ) + return(cJSON_Parse("[]")); + bitcoin_addr2rmd160(&type_rmd160[0],&type_rmd160[1],coinaddr); + if ( (addr= _kmd_address(coin,type_rmd160)) != 0 && (ptr= addr->prev) != 0 && ptr->tx != 0 ) + { + for (i=0; inumvouts; i++) + { + if ( memcmp(ptr->tx->vouts[i].type_rmd160,type_rmd160,21) == 0 && (spent= ptr->ptrs[(i<<1)+1]) == 0 ) + jaddi(array,kmd_unspentjson(ptr->tx,i)); + } + } + return(array); +} + +char *kmd_bitcoinblockhashstr(char *coinstr,char *serverport,char *userpass,int32_t height) +{ + char numstr[128],*blockhashstr=0; bits256 hash2; struct iguana_info *coin; + sprintf(numstr,"%d",height); + if ( (blockhashstr= bitcoind_passthru(coinstr,serverport,userpass,"getblockhash",numstr)) == 0 ) + return(0); + hash2 = bits256_conv(blockhashstr); + if ( blockhashstr == 0 || blockhashstr[0] == 0 || bits256_nonz(hash2) == 0 ) + { + printf("couldnt get blockhash for %u, probably curl is disabled\n",height); + if ( blockhashstr != 0 ) + free(blockhashstr); + if ( height == 0 ) + { + if ( (coin= iguana_coinfind(coinstr)) != 0 ) + { + bits256_str(numstr,*(bits256 *)coin->chain->genesis_hashdata); + return(clonestr(numstr)); + } + } + return(0); + } + return(blockhashstr); +} + +cJSON *kmd_blockjson(int32_t *heightp,char *coinstr,char *serverport,char *userpass,char *blockhashstr,int32_t height) +{ + cJSON *json = 0; int32_t flag = 0; char buf[1024],*blocktxt = 0; + if ( blockhashstr == 0 ) + blockhashstr = kmd_bitcoinblockhashstr(coinstr,serverport,userpass,height), flag = 1; + if ( blockhashstr != 0 ) + { + sprintf(buf,"\"%s\"",blockhashstr); + blocktxt = bitcoind_passthru(coinstr,serverport,userpass,"getblock",buf); + //printf("get_blockjson.(%d %s) %s\n",height,blockhashstr,blocktxt); + if ( blocktxt != 0 && blocktxt[0] != 0 && (json= cJSON_Parse(blocktxt)) != 0 && heightp != 0 ) + if ( (*heightp= juint(json,"height")) != height ) + *heightp = -1; + if ( flag != 0 && blockhashstr != 0 ) + free(blockhashstr); + if ( blocktxt != 0 ) + free(blocktxt); + } + return(json); +} + +int32_t _kmd_bitcoinscan(struct iguana_info *coin) +{ + int32_t h,num=0,loadheight,i,n,numtxids,numvins,numvouts,flag=0,height=-1; cJSON *txjson,*vouts,*vins,*blockjson,*txids,*vout,*vin,*sobj,*addresses; bits256 zero,txid; char *curlstr,params[128],str[65]; struct kmd_transactionhh *ptr; struct kmd_transaction *tx; uint8_t type_rmd160[21]; + if ( coin->kmd_didinit == 0 ) + { + if ( (coin->kmd_txidfp= kmd_txidinit(coin)) == 0 ) + printf("error initializing %s.kmd lookups\n",coin->symbol); + coin->kmd_didinit = 1; + } + height = kmd_height(coin); + loadheight = coin->kmd_height; + while ( loadheight < height ) + { + if ( loadheight == 0 ) + { + loadheight++; + continue; + } + flag = 0; + if ( (blockjson= kmd_blockjson(&h,coin->symbol,coin->chain->serverport,coin->chain->userpass,0,loadheight)) != 0 ) + { + if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) + { + for (i=0; isymbol,coin->chain->serverport,coin->chain->userpass,"getrawtransaction",params)) != 0 ) + { + if ( (txjson= cJSON_Parse(curlstr)) != 0 ) + { + txid = jbits256(txjson,"txid"); + if ( kmd_transaction(coin,txid) != 0 ) + { + printf("already have txid.%s\n",bits256_str(str,txid)); + free_json(txjson); + free(curlstr); + continue; + } + vouts = jarray(&numvouts,txjson,"vout"); + vins = jarray(&numvins,txjson,"vin"); + if ( (tx= kmd_transactionalloc(txid,loadheight-jint(txjson,"confirmations"),jint(txjson,"blocktime"),numvouts)) != 0 ) + { + if ( (ptr= kmd_transactionadd(coin,tx,numvouts)) != 0 ) + { + for (i=0; ikmd_height = loadheight++; + if ( flag == 0 || num > 100 ) + break; + } + return(num); +} + +void kmd_bitcoinscan() +{ + char *retstr; cJSON *array; int32_t i,n; struct iguana_info *coin; + if ( (retstr= dpow_notarychains(0,0,0,0)) != 0 ) + { + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; isymbol,"BTC") != 0 ) + _kmd_bitcoinscan(coin); + } + } + free_json(array); + } + free(retstr); + } +} + +#endif diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 8f621e2fb..5fb316041 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -42,6 +42,8 @@ TWO_STRINGS(dex,listunspent,symbol,address); TWO_STRINGS_AND_TWO_DOUBLES(dex,listtransactions,symbol,address,count,skip); TWO_STRINGS(dex,kvsearch,symbol,key); THREE_STRINGS_AND_THREE_INTS(dex,kvupdate,symbol,key,value,flags,unused,unusedb); +TWO_STRINGS(dex,listunspent2,symbol,coinaddr); +TWO_STRINGS(dex,listtransactions2,symbol,coinaddr); TWO_STRINGS(zcash,passthru,function,hex); TWO_STRINGS(komodo,passthru,function,hex); diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index 167aca829..7b5a0b4d0 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -536,6 +536,7 @@ struct iguana_info struct iguana_block *RTblocks[65536]; uint8_t *RTrawdata[65536]; int32_t RTrecvlens[65536],RTnumtx[65536]; struct iguana_RTtxid *RTdataset; struct iguana_RTaddr *RTaddrs; struct hashstr_item *alladdresses; + struct kmd_transactionhh *kmd_transactions; struct kmd_addresshh *kmd_addresses; portable_mutex_t kmdmutex; FILE *kmd_txidfp; int32_t kmd_didinit,kmd_height; }; struct vin_signer { bits256 privkey; char coinaddr[64]; uint8_t siglen,sig[80],rmd160[20],pubkey[66]; };