diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index a83393913..d1a85727e 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -172,7 +172,8 @@ struct LP_outpoint { bits256 spendtxid; uint64_t value,interest; int32_t spendvi struct LP_transaction { UT_hash_handle hh; - bits256 txid; int32_t height,numvouts,numvins; //uint32_t timestamp; + bits256 txid; int32_t height,numvouts,numvins,len; //uint32_t timestamp; + uint8_t *serialized; struct LP_outpoint outpoints[]; }; @@ -303,6 +304,8 @@ struct LP_address *_LP_addressfind(struct iguana_info *coin,char *coinaddr); struct LP_address *_LP_addressadd(struct iguana_info *coin,char *coinaddr); int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t wiftaddr,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,struct iguana_msgtx *msgtx,char **signedtxp,bits256 *signedtxidp,struct vin_info *V,int32_t numinputs,char *rawtx,cJSON *vins,cJSON *privkeysjson); //void LP_butxo_swapfields_set(struct LP_utxoinfo *butxo); +struct LP_address_utxo *LP_address_utxofind(struct iguana_info *coin,char *coinaddr,bits256 txid,int32_t vout); +int32_t LP_destaddr(char *destaddr,cJSON *item); int32_t LP_waitmempool(char *symbol,char *coinaddr,bits256 txid,int32_t vout,int32_t duration); struct LP_transaction *LP_transactionfind(struct iguana_info *coin,bits256 txid); cJSON *LP_transactioninit(struct iguana_info *coin,bits256 txid,int32_t iter,cJSON *txobj); @@ -310,10 +313,11 @@ int32_t LP_mempoolscan(char *symbol,bits256 searchtxid); int32_t LP_txheight(struct iguana_info *coin,bits256 txid); int32_t LP_address_utxoadd(struct iguana_info *coin,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t height,int32_t spendheight); cJSON *LP_address_utxos(struct iguana_info *coin,char *coinaddr,int32_t electrumret); -cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout); +cJSON *LP_gettxout(char *symbol,char *coinaddr,bits256 txid,int32_t vout); void LP_postutxos(char *symbol,char *coinaddr); int32_t LP_listunspent_both(char *symbol,char *coinaddr); uint16_t LP_randpeer(char *destip); +cJSON *bitcoin_data2json(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *txidp,struct iguana_msgtx *msgtx,uint8_t *extraspace,int32_t extralen,uint8_t *serialized,int32_t len,cJSON *vins,int32_t suppress_pubkeys); //int32_t LP_butxo_findeither(bits256 txid,int32_t vout); cJSON *LP_listunspent(char *symbol,char *coinaddr); int32_t LP_gettx_presence(char *symbol,bits256 expectedtxid); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 93733a9b0..b7c9e04b0 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -394,10 +394,10 @@ double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,i ptr->price = 0.; printf("LP_pricecache: set %s/%s ptr->price %.8f\n",base,rel,ptr->price); } - printf("found %s/%s %.8f\n",base,rel,ptr->price); + printf(">>>>>>>>>> found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } - char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); + //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); return(0.); } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 3a632d6c1..deffe3bf6 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -243,7 +243,7 @@ cJSON *LP_paxprice(char *fiat) cJSON *LP_gettx(char *symbol,bits256 txid) { - char buf[128],str[65],*hexstr; int32_t len; bits256 checktxid; cJSON *retjson; struct iguana_info *coin; struct iguana_msgtx msgtx; uint8_t *extraspace,*serialized; + struct iguana_info *coin; char buf[512],str[65]; cJSON *retjson; if ( symbol == 0 || symbol[0] == 0 ) return(cJSON_Parse("{\"error\":\"null symbol\"}")); coin = LP_coinfind(symbol); @@ -258,49 +258,38 @@ cJSON *LP_gettx(char *symbol,bits256 txid) } else { - sprintf(buf,"[\"%s\"]",bits256_str(str,txid)); if ( (retjson= electrum_transaction(symbol,coin->electrum,&retjson,txid)) != 0 ) - { - hexstr = jprint(retjson,1); - if ( strlen(hexstr) > 20000 ) - { - static uint32_t counter; - if ( counter++ < 3 ) - printf("rawtransaction too big %d\n",(int32_t)strlen(hexstr)); - free(hexstr); - return(cJSON_Parse("{\"error\":\"transaction too big\"}")); - } - if ( hexstr[0] == '"' && hexstr[strlen(hexstr)-1] == '"' ) - hexstr[strlen(hexstr)-1] = 0; - if ( (len= is_hexstr(hexstr+1,0)) > 2 ) - { - memset(&msgtx,0,sizeof(msgtx)); - len = (int32_t)strlen(hexstr+1) >> 1; - serialized = malloc(len); - decode_hex(serialized,len,hexstr+1); - free(hexstr); - //printf("DATA.(%s)\n",hexstr+1); - extraspace = calloc(1,1000000); - retjson = bitcoin_data2json(coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->height,&checktxid,&msgtx,extraspace,1000000,serialized,len,0,0); - free(serialized); - free(extraspace); - //printf("TX.(%s) match.%d\n",jprint(retjson,0),bits256_cmp(txid,checktxid)); - return(retjson); - } else printf("non-hex tx.(%s)\n",hexstr); - free(hexstr); - return(cJSON_Parse("{\"error\":\"non hex transaction\"}")); - } else printf("failed blockchain.transaction.get %s %s\n",coin->symbol,buf); + return(retjson); + else printf("failed blockchain.transaction.get %s %s\n",coin->symbol,buf); return(cJSON_Parse("{\"error\":\"no transaction bytes\"}")); } } -cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout) +cJSON *LP_gettxout_json(bits256 txid,int32_t vout,int32_t height,char *coinaddr,uint64_t value) +{ + cJSON *retjson,*addresses,*sobj; + retjson = cJSON_CreateObject(); + jaddnum(retjson,"value",dstr(value)); + jaddnum(retjson,"height",height); + jaddbits256(retjson,"txid",txid); + jaddnum(retjson,"vout",vout); + addresses = cJSON_CreateArray(); + jaddistr(addresses,coinaddr); + sobj = cJSON_CreateObject(); + jaddnum(sobj,"reqSigs",1); + jaddstr(sobj,"type","pubkey"); + jadd(sobj,"addresses",addresses); + jadd(retjson,"scriptPubKey",sobj); + printf("GETTXOUT.(%s)\n",jprint(retjson,0)); + return(retjson); +} + +cJSON *LP_gettxout(char *symbol,char *coinaddr,bits256 txid,int32_t vout) { - char buf[128],str[65],coinaddr[64],*hexstr; uint64_t value; uint8_t *serialized; cJSON *sobj,*addresses,*item,*array,*hexobj,*retjson=0; int32_t i,n,v,len; bits256 t; struct iguana_info *coin; + char buf[128],str[65]; cJSON *item,*array,*vouts,*txobj,*retjson=0; int32_t i,v,n; bits256 t; struct iguana_info *coin; struct LP_transaction *tx; struct LP_address_utxo *up; if ( symbol == 0 || symbol[0] == 0 ) return(cJSON_Parse("{\"error\":\"null symbol\"}")); - coin = LP_coinfind(symbol); - if ( coin == 0 ) + if ( (coin= LP_coinfind(symbol)) == 0 ) return(cJSON_Parse("{\"error\":\"no coin\"}")); if ( bits256_nonz(txid) == 0 ) return(cJSON_Parse("{\"error\":\"null txid\"}")); @@ -311,84 +300,52 @@ cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout) } else { - printf("gettxout v%d\n",vout); - sprintf(buf,"[\"%s\"]",bits256_str(str,txid)); - if ( (hexobj= electrum_transaction(symbol,coin->electrum,&hexobj,txid)) != 0 ) + if ( (tx= LP_transactionfind(coin,txid)) != 0 && vout < tx->numvouts ) + { + if ( tx->outpoints[vout].spendheight > 0 ) + return(0); + return(LP_gettxout_json(txid,vout,tx->height,tx->outpoints[vout].coinaddr,tx->outpoints[vout].value)); + } + if ( coinaddr[0] == 0 ) + { + if ( (txobj= electrum_transaction(symbol,coin->electrum,&txobj,txid)) != 0 ) + { + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) + LP_destaddr(coinaddr,jitem(vouts,vout)); + free_json(txobj); + } + } + if ( coinaddr[0] != 0 ) { - hexstr = jprint(hexobj,1); - if ( strlen(hexstr) > 20000 ) + if ( (up= LP_address_utxofind(coin,coinaddr,txid,vout)) != 0 ) { - static uint32_t counter; - if ( counter++ < 3 ) - printf("rawtransaction too big %d\n",(int32_t)strlen(hexstr)); - free(hexstr); - return(cJSON_Parse("{\"error\":\"transaction too big\"}")); + if ( up->spendheight > 0 ) + return(0); + return(LP_gettxout_json(txid,vout,up->U.height,coinaddr,up->U.value)); } - if ( hexstr[0] == '"' && hexstr[strlen(hexstr)-1] == '"' ) - hexstr[strlen(hexstr)-1] = 0; - if ( (len= is_hexstr(hexstr+1,0)) > 2 ) + if ( (array= electrum_address_listunspent(coin->symbol,0,&array,coinaddr)) != 0 ) { - len = (int32_t)strlen(hexstr+1) >> 1; - serialized = malloc(len); - decode_hex(serialized,len,hexstr+1); - LP_swap_coinaddr(coin,coinaddr,&value,serialized,len,vout); - //printf("HEX.(%s) len.%d %s %.8f\n",hexstr+1,len,coinaddr,dstr(value)); - free(hexstr); - if ( (array= electrum_address_listunspent(coin->symbol,0,&array,coinaddr)) != 0 ) + //printf("array.(%s)\n",jprint(array,0)); + if ( array != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { - //printf("array.(%s)\n",jprint(array,0)); - if ( array != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + for (i=0; i<n; i++) { - for (i=0; i<n; i++) + item = jitem(array,i); + t = jbits256(item,"tx_hash"); + v = jint(item,"tx_pos"); + if ( v == vout && bits256_cmp(t,txid) == 0 ) { - item = jitem(array,i); - t = jbits256(item,"tx_hash"); - v = jint(item,"tx_pos"); - if ( v == vout && bits256_cmp(t,txid) == 0 ) - { - retjson = cJSON_CreateObject(); - /*{ - "bestblock": "002f7bbe3973b735f535d472501962e86ce8dbc76c73ac5a310a905931b907fa", - "confirmations": 7, - "value": 2013.10431750, - "scriptPubKey": { - "asm": "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828 OP_CHECKSIG", - "hex": "2103b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828ac", - "reqSigs": 1, - "type": "pubkey", - "addresses": [ - "RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc" - ] - }, - "version": 1, - "coinbase": false - }*/ - if ( value != j64bits(item,"value") ) - printf("LP_gettxout: value %llu != %llu\n",(long long)value,(long long)j64bits(item,"value")); - jaddnum(retjson,"value",dstr(value)); - jaddbits256(retjson,"txid",t); - jaddnum(retjson,"vout",v); - addresses = cJSON_CreateArray(); - jaddistr(addresses,coinaddr); - sobj = cJSON_CreateObject(); - jaddnum(sobj,"reqSigs",1); - jaddstr(sobj,"type","pubkey"); - jadd(sobj,"addresses",addresses); - jadd(retjson,"scriptPubKey",sobj); - printf("GETTXOUT.(%s)\n",jprint(retjson,0)); - break; - } + retjson = LP_gettxout_json(txid,vout,jint(item,"height"),coinaddr,j64bits(item,"value")); + break; } } - free_json(array); } - } else free(hexstr); - if ( retjson == 0 ) - { - + free_json(array); + if ( retjson != 0 ) + return(retjson); } - return(retjson); } + printf("couldnt find %s/v%d\n",bits256_str(str,txid),vout); return(cJSON_Parse("{\"error\":\"couldnt get tx\"}")); } } diff --git a/iguana/exchanges/LP_socket.c b/iguana/exchanges/LP_socket.c index f4809d1f1..1a953c9af 100644 --- a/iguana/exchanges/LP_socket.c +++ b/iguana/exchanges/LP_socket.c @@ -310,7 +310,7 @@ int32_t electrum_process_array(struct iguana_info *coin,struct electrum_info *ep v = jint(item,"vout"); value = LP_value_extract(item,0); ht = LP_txheight(coin,txid); - if ( (retjson= LP_gettxout(coin->symbol,txid,v)) != 0 ) + if ( (retjson= LP_gettxout(coin->symbol,coinaddr,txid,v)) != 0 ) free_json(retjson); else { @@ -527,12 +527,79 @@ cJSON *electrum_estimatefee(char *symbol,struct electrum_info *ep,cJSON **retjso cJSON *electrum_getheader(char *symbol,struct electrum_info *ep,cJSON **retjsonp,int32_t n) { return(electrum_intarg(symbol,ep,retjsonp,"blockchain.block.get_header",n,ELECTRUM_TIMEOUT)); } cJSON *electrum_getchunk(char *symbol,struct electrum_info *ep,cJSON **retjsonp,int32_t n) { return(electrum_intarg(symbol,ep,retjsonp,"blockchain.block.get_chunk",n,ELECTRUM_TIMEOUT)); } +cJSON *LP_transaction_fromdata(struct iguana_info *coin,bits256 txid,uint8_t *serialized,int32_t len) +{ + uint8_t *extraspace; cJSON *txobj; char str[65],str2[65]; struct iguana_msgtx msgtx; bits256 checktxid; + extraspace = calloc(1,1000000); + memset(&msgtx,0,sizeof(msgtx)); + txobj = bitcoin_data2json(coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->height,&checktxid,&msgtx,extraspace,1000000,serialized,len,0,0); + //printf("TX.(%s) match.%d\n",jprint(retjson,0),bits256_cmp(txid,checktxid)); + free(extraspace); + if ( bits256_cmp(txid,checktxid) != 0 ) + { + printf("LP_transaction_fromdata mismatched txid %s vs %s\n",bits256_str(str,txid),bits256_str(str2,checktxid)); + free_json(txobj); + txobj = 0; + } + return(txobj); +} + cJSON *electrum_transaction(char *symbol,struct electrum_info *ep,cJSON **retjsonp,bits256 txid) { - char str[65]; printf("%s add cache here -> TRANSACTION.(%s)\n",symbol,bits256_str(str,txid)); - if ( bits256_nonz(txid) != 0 ) - return(electrum_hasharg(symbol,ep,retjsonp,"blockchain.transaction.get",txid,ELECTRUM_TIMEOUT)); - else return(cJSON_Parse("{\"error\":\"null txid\"}")); + char *hexstr,str[65]; int32_t len; cJSON *hexjson,*txobj=0; struct iguana_info *coin; uint8_t *serialized; struct LP_transaction *tx; + if ( bits256_nonz(txid) != 0 && (coin= LP_coinfind(symbol)) != 0 ) + { + if ( (tx= LP_transactionfind(coin,txid)) != 0 && tx->serialized != 0 ) + { + char str[65]; printf("%s cache hit -> TRANSACTION.(%s)\n",symbol,bits256_str(str,txid)); + if ( (txobj= LP_transaction_fromdata(coin,txid,tx->serialized,tx->len)) != 0 ) + { + *retjsonp = txobj; + return(txobj); + } + } + hexjson = electrum_hasharg(symbol,ep,&hexjson,"blockchain.transaction.get",txid,ELECTRUM_TIMEOUT); + hexstr = jprint(hexjson,1); + if ( strlen(hexstr) > 60000 ) + { + static uint32_t counter; + if ( counter++ < 3 ) + printf("rawtransaction too big %d\n",(int32_t)strlen(hexstr)); + free(hexstr); + *retjsonp = cJSON_Parse("{\"error\":\"transaction too big\"}"); + return(*retjsonp); + } + if ( hexstr[0] == '"' && hexstr[strlen(hexstr)-1] == '"' ) + hexstr[strlen(hexstr)-1] = 0; + if ( (len= is_hexstr(hexstr+1,0)) > 2 ) + { + len = (int32_t)strlen(hexstr+1) >> 1; + serialized = malloc(len); + decode_hex(serialized,len,hexstr+1); + free(hexstr); + //printf("DATA.(%s)\n",hexstr+1); + if ( (tx= LP_transactionfind(coin,txid)) == 0 || tx->serialized == 0 ) + { + txobj = LP_transactioninit(coin,txid,0,0); + LP_transactioninit(coin,txid,1,txobj); + if ( (tx= LP_transactionfind(coin,txid)) != 0 ) + { + tx->serialized = serialized; + tx->len = len; + } + else + { + printf("unexpected couldnt find tx %s %s\n",coin->symbol,bits256_str(str,txid)); + free(serialized); + } + } + *retjsonp = txobj; + return(*retjsonp); + } else printf("non-hex tx.(%s)\n",hexstr); + free(hexstr); + } + *retjsonp = cJSON_Parse("{\"error\":\"null txid\"}"); + return(*retjsonp); } cJSON *electrum_getmerkle(char *symbol,struct electrum_info *ep,cJSON **retjsonp,bits256 txid,int32_t height) diff --git a/iguana/exchanges/LP_utxo.c b/iguana/exchanges/LP_utxo.c index b109e3130..202af4e49 100644 --- a/iguana/exchanges/LP_utxo.c +++ b/iguana/exchanges/LP_utxo.c @@ -332,7 +332,7 @@ int32_t LP_unspents_array(struct iguana_info *coin,char *coinaddr,cJSON *array) val = j64bits(item,"value"); //if ( strcmp(coin->symbol,"LBC") == 0 ) // printf("(%s)\n",jprint(item,0)); - if ( coin->electrum == 0 && (txobj= LP_gettxout(coin->symbol,txid,v)) != 0 ) + if ( coin->electrum == 0 && (txobj= LP_gettxout(coin->symbol,coinaddr,txid,v)) != 0 ) { value = LP_value_extract(txobj,0); if ( value != 0 && value != val ) @@ -475,7 +475,7 @@ uint64_t LP_txinterestvalue(uint64_t *interestp,char *destaddr,struct iguana_inf uint64_t interest,value = 0; cJSON *txobj; *interestp = 0; destaddr[0] = 0; - if ( (txobj= LP_gettxout(coin->symbol,txid,vout)) != 0 ) + if ( (txobj= LP_gettxout(coin->symbol,destaddr,txid,vout)) != 0 ) { if ( (value= LP_value_extract(txobj,0)) == 0 ) { @@ -591,7 +591,7 @@ int32_t LP_numconfirms(char *symbol,char *coinaddr,bits256 txid,int32_t vout,int if ( coin->electrum == 0 ) { numconfirms = -1; - if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) + if ( (txobj= LP_gettxout(symbol,coinaddr,txid,vout)) != 0 ) { numconfirms = jint(txobj,"confirmations"); free_json(txobj); @@ -663,7 +663,7 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) } else { - if ( (txobj= LP_gettxout(coin->symbol,txid,vout)) != 0 ) + if ( (txobj= LP_gettxout(coin->symbol,coinaddr,txid,vout)) != 0 ) { value = LP_value_extract(txobj,0);//SATOSHIDEN * (jdouble(txobj,"value") + jdouble(txobj,"interest")); if ( coinaddr == 0 )